telepathy-qt-0.9.6~git1/0000775000175000017500000000000012470405666012756 5ustar jrjrtelepathy-qt-0.9.6~git1/doxygen-header.html0000664000175000017500000000165212470405660016545 0ustar jrjr $title
   Home · All Classes · All Namespaces · Modules · Functions · Files
telepathy-qt-0.9.6~git1/COPYING0000664000175000017500000006363712470405660014022 0ustar jrjr GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, 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 St, 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! telepathy-qt-0.9.6~git1/NEWS0000664000175000017500000017606412470405660013465 0ustar jrjrtelepathy-qt 0.9.6 () ================================= The "..." release. telepathy-qt 0.9.5 (2014-09-09) ================================= The "Return of the Akademy Release" release. Enhancements: * Added more service side bindings * Service bindings now enabled by default * Bump Farstream version * Allow subclass of Tp::ReceivedMessage Fixes: * fd.o #77986: Workaround invalid channelRequests when delegating telepathy-qt 0.9.4 (2014-06-14) ================================= The "Back from the dead" release. Enhancements: * fd.o #63098: add method Account::createDbusTubeRoom Fixes: * fd.o #46241: Fixed linking in farstream and farsight * Require tp-glib 0.18 and fix 0.19-ism * fd.o #47647: Fixed storing avatars, so that they are not stored millions of times each. * fd.o #62711: Fixed stack overflow in SimpleObserver::create * Fix compilation and running against release Qt5 Cleanups: * Removed Farsight telepathy-qt 0.9.3 (2012-07-13) ================================= The "We promised, we delivered" release. Enhancements: * Added ClientTypes bindings to Contact. * Fixed deprecation macros, and added TP_QT_EXPORT_DEPRECATED. * Ported SimpleCallObserver to also handle Call1 calls. * Deprecated Farsight and StreamedMedia. Fixes: * Removed occurencies of deprecated tp-glib functions from the DBus tube tests. * Fixed DISABLE_WERROR, which now works as expected. * Fixed linking of the DBus tube tests with strict linkers like gold. * Synced tests/lib/glib/utils.* to remove deprecation warnings. * Removed occurencies of the deprecated tp_connection_new from Farsight/Farstream. telepathy-qt 0.9.2 (2012-07-04) ================================= The "We were at aKademy and we got bored" release. Enhancements: * Introducing Telepathy-Qt-Service, a new static library that contains experimental service-side bindings. For the moment this exposes the required low-level interfaces for writing connection managers, as well as some basic high-level API. * Renamed AccountManager::accountForPath() and AccountManager::accountsForPaths() to accountForObjectPath() and accountsForObjectPaths() respectively, deprecating the old names. * Added bindings for Debug interface. * Enable several options in CMake to allow to selectively build components. In particular, now Farsight, Farstream, examples and tests are optional. Farsight is disabled by default. * fd.o #28366: Added high level bindings for DBus tubes. Fixes: * Fix PkgConfig detection in DBus find files * Fix a race condition in test-account-basics and test-dbus-properties. * Fix compilation with gcc 4.7. * Fix tests compilation with telepathy-glib 0.19. * Fix FindDBus.cmake to find the correct paths. * Pass -fvisibility-inlines-hidden to the compiler if it's supported. telepathy-qt 0.9.1 (2012-03-23) ================================= The "it is call time" release. Enhancements: * fd.o #43025: Tp::Presence now has a setStatusMessage() method which keeps the old status id and status type * Added methods in Tp::AbstractInterface to support PropertiesChanged. This way it is possible for internal classes to monitor any property belonging to their interface * fd.o #46403: Update spec files to spec 0.25.2 and generate low-level bindings for all non-draft interfaces * fd.o #46347: Added high-level bindings for new CaptchaAuthentication interface * fd.o #46484: Add high-level Call bindings * Introducing new Telepathy-Qt-Farstream, a new mini-library with glue code to connect telepathy-farstream to Telepathy-Qt Fixes: * fd.o #45850: Telepathy Qt4 cannot compile against glib 2.31.0 and above * fd.o #39346: telepathy-qt fails to build with clang * fd.o #45755: Inconsistent ordering of pendingMessageRemoved telepathy-qt 0.9.0 (2011-12-20) ================================ The "Merry Christmas" release. This release begins the new 0.9 development series for feature additions following the 0.8 stable release series. Starting with this release the project is renamed to telepathy-qt (TelepathyQt) and Qt5 support is added alongside Qt4 support and for that 0.9 will be API (see changes below) and ABI incompatible with previous versions. API changes: * Everything containing qt4 (with or without caps) was renamed to qt. Eg.: - TP_QT4_DEPRECATED -> TP_QT_DEPRECATED - #include -> #include * Errors and constant macros starting with TELEPATHY_ (const char * versions) were removed, remaining only the versions that expand to QLatin1String. Eg.: - TELEPATHY_ERROR_INVALID_HANDLE <- removed - TP_QT4_ERROR_INVALID_HANDLE -> TP_QT_ERROR_INVALID_HANDLE * All deprecated methods (marked with TP_QT4_DEPRECATED) and signals (those that used to emit warnings at runtime when connecting to them) were removed. * StreamTubeChannel::connections() now returns a QSet instead of an UIntList. * Channel::groupContacts and groupLocal/RemotePendingContacts() gained a "includeSelfContact" param defaulting to true. * KeyFile and ManagerFile classes are now removed from public API. * SharedPtr cannot be constructed from a QWeakPointer anymore as the conversion from a QWeakPointer to a SharedPtr can't be made thread-safe. WeakPtr is reintroduced as a weak pointer class safely promoteable to a SharedPtr. * TelepathyQt-Farsight does not include telepathy-farsight/channel.h directly anymore. * ContactManager::lookupContactByHandle() is removed from public API. Enhancements: * fd.o #35084: The StreamTubeClient and StreamTubeServer classes have been added to allow implementing Telepathy Stream Tube connectivity for applications without having to worry about the channel dispatching details * Contact::refreshInfo() requests are now batched together on D-Bus * fd.o #41356: Implement methods to retrieve available message types on TextChannel. * fd.o #43631: Add CMake config files. Now CMake projects can find Tp-Qt straight away without the need of Find* files. * fd.o #43598 - Add high-level API for Proto.I.Addressing interface * fd.o #43599 - Add high-level API for Conn.I.Addressing interface Fixes: * Our TODO process being completely out of date. Trying to use doxygen \todo annotations from now on * FeatureRoster is set on Tp::Connection even for roster-less accounts. Known issues: * Some tests are failing for some Qt 4.7 configurations, reports on fd.o bug #43551 please. telepathy-qt4 0.7.3 (2011-10-07) ================================ The "a must" release. Enhancements: * Added HandleTypeRoom StreamTubes to ChannelClassSpec * It is now possible to capture and redirect the library debug output via setting a DebugCallback using the Tp::setDebugCallback function * The ChannelClassSpec implementation has been optimized, which yields ChannelFactory setup and consequently application startup speedups * StreamTubeChannel now ensures connectionClosed() is emitted for all connections on a closing tube * Add Presence/PresenceSpec operator== support * Add Presence/PresenceSpec operator!= support (Rohan Garg) * Add Authentication.TLSCertificate to the set of generated interfaces * Improve file transfer examples to properly use the ChannelDispatcher Fixes: * Ensure that the proper Channel Dispatcher methods are being called when creating/ensuring channels. * Prevent PendingContacts crashes in corner cases where contacts are still being built when a Connection is destroyed. Note that this affects which object is returned by PendingContacts::object() - we've now made it explicit that object() shouldn't be used externally as we make no guarantees on what object it returns, by deprecating it. It will be made protected: in the next API break * Passing a non-empty service param to ChannelClassSpec::{incoming,outgoing}StreamTube() messing up the shared instance as used by e.g. ChannelFactory * Connections not being removed from StreamTubeChannel::connections() when they are closed, and newConnection() and connectionClosed() events getting reordered * fd.o# 40655 - ChannelDispatchOperation::claim() cannot be used by Approvers to handle channels * Codegen is now able to utilize types with D-Bus signature aay, aas and aav * Account/Connection/Channel now properly check if FeatureCore is ready on accessors * Readded erroneously removed protected API to StreamTubeChannel, which restores full ABI backwards compatibility. telepathy-qt4 0.7.2 (2011-08-04) ================================ The "Stage 0 Tune Up" release. Enhancements: * Lots of additions and corrections to API documentation * Code generator now produces nicer output for member-ref, dbus-ref and rationale elements in docstrings * The stable D-Bus interfaces Account.Interface.Storage, Channel.Type.DBusTube and Channel.Interface.Destroyable have been added to generated bindings Fixes: * Tp::IncomingStreamTubeChannel always reports an empty socket address to connect to for accepted Tubes - and various other StreamTube fixes thanks to now having unit tests for them telepathy-qt4 0.7.1 (2011-06-09) ================================ The "where is the file?" release. Enhancements: * fd.o #37034: The URI property can now be set when requesting file transfers, and can be read by the Handler (and any Observers) from Tp::FileTransferChannel (Daniele E. Domenichelli) * Improved tests readability by moving common code into helper classes, macros, etc, in preparation for increasing the test coverage Fixes: * Fixed documentation for Contact::publishStateChanged() (Daniele E. Domenichelli) * Properly crosslink our doxygen docs to Qt documentation on fresh builds * Properly generate docs for auto generated classes telepathy-qt4 0.7.0 (2011-06-01) ================================ The "Doctor Love knew this so he made another great invention just for the lonely you!" release. This release begins the new 0.7 development series series for feature additions following the 0.6 stable release series. Both 0.6 and 0.7 will continue to be backwards compatible API and ABI wise with the earlier 0.5 development series. Enhancements: * fd.o #35341: Use the new ContactBlocking D-Bus interface for better performance in Tp::ContactManager (George Kiagiadakis) * ReceivedMessage: Add accessors for retrieving delivery report information, sender nickname and superseded message token * Crosslink our doxygen docs to Qt documentation Fixes: * Do not close channels created using the request and handle API if MC restarts * Pass new value correctly as variant in generated binding setProperty* methods * Properly initialize Connection account balance members * fd.o #36881 - Wrong documentation for Tp::Account::connectionStatusChanged (and a bunch of other parts of the API) * fd.o #31769 - The documentation of TextChannel's features is not very helpful * Skip docs generation for internal OptionalInterfaceCache telepathy-qt4 0.5.16 (2011-05-01) ================================= The "A brown paper bagful of Easter Eggs" release. Enhancements: * fd.o #36526: Tp::Channel has now gained targetID() and targetContact() accessors * fd.o #35421: Update to spec 0.22.0: - Added auto generated class for Conn.ContactBlocking - Added Connection::ErrorDetails accessors for ConnectionError details server-message, user-requested, expected-hostname and certificate-hostname * Add support for Conn.SimplePresence.MaximumStatusMessageLength * Add Features operator|(Features, Feature) * ContactManager state now only advances to Success when both the roster and the roster groups have been downloaded, if requested * New class SimpleObserver that can be used to observe arbitrary channels on a given Account. * fd.o #33525 - Helper class(es) for observing calls - New class SimpleCallObserver class which makes it easy to follow all StreamedMedia communication on a given Account. Fixes: * fd.o #35633: Contact features being erased after further contact upgrades, e.g. from ContactFactory used together with Connection::FeatureRosterGroups * Contact::groups() and ContactManager::groupContacts() not populated correctly when using CMs with new-style ContactGroups D-Bus API * Timeout in some CMs when introspecting contact list channels * Crashes with Connection::FeatureSelfContact enabled (Manifested as an assert for inFlightFeatures or pendingFeatures being hit) * Crashes if a connection disconnects while FeatureRosterGroups is being introspected (SIGSEGV in PendingOperation from ContactManager::Roster) * Added correctly named pretty headers for the Conn.ClientTypes/ContactGroups/ContactList/Saving interfaces * Odd build system failures from feature checks which were anyway redundant due to our recently bumped Qt 4.6+ dependency - checks now removed telepathy-qt4 0.5.15 (2011-04-12) ================================= The "How to remove a hole from a set of holes" release. Enhancements: * Performance improvements for introspection (becomeReady() latency) * Some documentation improvements. Fixes: * Incorrect scoping for Initial{Audio,Video} properties in Account channel request methods * Possible deadlock on connection status changes when FeatureConnected is requested on a Connection * Crash opportunities when introspecting a Connection which disappears in the process (e.g. due to a network error or a CM crash) telepathy-qt4 0.5.14 (2011-04-05) ================================= The "Now succeeds at failing!" release. The Qt dependency has been bumped to >= 4.6.0 for all future releases. Enhancements: * AccountManager will now retry introspection 5 times with a 3 seconds interval (or immediately if error is Timeout) if the introspection failed and becomeReady() will fail if there is still an error after all tries. * AccountManager will no more signal newAccount if the initial introspection failed. * ConnectionCapabilities and ContactCapabilities are now subclassable Fixes: * Regression in 0.5.13 causing PendingReadys to not fail even if the object being made ready disappears * Discrepancy between the spec and implementation on initially assumed non-locally-requested StreamedMediaChannel stream direction * Reporting capabilities of offline accounts incorrectly because of a .manager file parsing bug telepathy-qt4 0.5.13 (2011-03-23) ================================= The "what is my id?" release. Enhancements: * Added example to send messages using ContactMessenger. Fixes: * ContactMessenger: Do not crash if an error occurred normalizing the contact identifier but the ContactManager::contactsForIdentifiers() succeeded. * Multiple parallel invalidated() signal connections created between DBusProxy and ReadinessHelper telepathy-qt4 0.5.12 (2011-03-18) ================================= The "Can I use the IM framework for, like, sending and receiving messages" release. Enhancements: * fd.o #28753: Added SimpleTextObserver class which makes it easy to follow all text communication on a given Account * fd.o #35321: Added ContactMessenger class for easily sending and receiving text messages with a particular contact Fixes: * The Request & Handle API spuriously failing with SERVICE_CONFUSED because of a race condition with introspecting the proxies telepathy-qt4 0.5.11 (2011-03-09) ================================= The "more contacts?" release. Enhancements: * fd.o#33121 - Bind Connection.ContactList.ContactsChangedWithID. Fixes: * ContactManager will now create contact objects even if everything fails but we have the contact handle/id and the connection has ImmortalHandles. * Ensure FeatureRoster is ready before setting ContactManager state to success even in fallback mode. telepathy-qt4 0.5.10 (2011-03-09) ================================= The "am I connected?" release. Enhancements: * Added Connection::FeatureConnected to help applications that only care about connected connections. Setting this feature on the ConnectionFactory used will make sure all connections signalled by the library are connected. Fixes: * Ensure FeatureRoster is ready before setting ContactManager state to success. telepathy-qt4 0.5.9 (2011-03-07) ================================= The "planned engineering works for the last year" release. Enhancements: * fd.o#28367 - Added High-level API for StreamTube channels * fd.o#34228 - Added API on Account for requesting Channels and handling them yourself, implemented properly using the Channel Dispatcher service * Account::allowedPresenceStatuses() now has fallbacks to include "available" and "offline" when that makes sense * Removed some more private symbols from the shared library, resulting in slightly faster load times * Deprecated ConnectionCapabilities contact search related methods with singular names and added plural versions of them, for API consistency. * Contacts publish/subscription state updates for removed contacts are only signalled after the ContactManager::allKnownContactsChanged signal is emitted. Fixes: * Redundant Contact::avatarDataChanged() emissions * Connection::becomeReady() never finishing in state Connecting, which for example prevents handling ServerAuthentication channels. NOTE: any code incorrectly relying on the old buggy behavior of becomeReady() only finishing once the connection goes Connected or Disconnected may need adjustment. * Linking errors referencing the QtXml library * Spec-incompliant building of Client names when uniquifying is requested from ClientRegistrar * Sensitive data in Account parameters being included in debug logs telepathy-qt4 0.5.8 (2011-02-22) ================================= The "where are my contacts?" release. Enhancements: * Account won't try to build a Connection object anymore if the connection object path hasn't changed. * Connection::FeatureRoster will now fail introspection if ContactList interface is not supported, neither fallback roster channels. * ContactManager now has a state() accessor and a corresponding stateChanged() signal to keep track of the progress made in retrieving the contact list. * Made Profile/Account/ContactManager debug output a bit cleaner. * Cleaned up debug classes by removing unused code. Fixes: * Properly replace "_" with "-" on Account::protocolName(). telepathy-qt4 0.5.7 (2011-02-15) ================================= The "fit for galoshes" release. Enhancements: * Make the debug subsystem as no-op as possible when debugging is disabled at runtime with Tp::enableDebug(false) and Tp::enableWarnings(false). * fd.o#33123 - Bind Protocol.Avatars. * fd.o#33124 - Bind Protocol.Presence. * fd.o#33116 - Added support for passing hints to channel requests, also making channel requests marginally more efficient CPU and memory wise in the process. * fd.o#33117 - Added support for extracting hints from ChannelRequests. * fd.o#33117 - Added support for ChannelRequests reporting the channel created for them on success, for further observation. Fixes: * fd.o#34131 - Writing avatar cache into $HOME with scratchbox. * Unstable generated future-* headers being installed (although nothing declared in them was ever exported in the library). * Possible crashes in Channel internal updateContacts function when just the self handle changed. telepathy-qt4 0.5.6 (2011-01-27) ================================= The "accept/decline" release. Enhancements: * Update to spec 0.21.8. - Added auto generated classes for Account.Addressing, Channel.ServerAuthentication, Channel.SASLAuthentication, Channel.Securable and Conn.MainNotification. Fixes: * Properly ignore protocol with invalid names. * Properly escape protocol name with "-" when constructing protocol object path. * Properly link against QtXml. * Properly emit presencePublicationRequested if the contact current publish state changes to PresenceStateAsk. * Added missing fancy-headers for generated classes. telepathy-qt4 0.5.5 (2011-01-25) ================================= The "I wish I had less contacts" release. Enhancements: * CapabilitiesBase: Added method to check if file transfer is supported. Fixes: * Contact list contacts are now guaranteed to contain the features set on ContactFactory. * Contact list groups are now automatically reintrospected when needed. * Another attempt to fix a crash when contacts are removed from contact list while the introspection is still running. * fd.o#33457 - tp-qt4 uses non-atomic file write in avatar cache. telepathy-qt4 0.5.4 (2011-01-20) ================================= The "the shower of golden paper bags" release. Enhancements: * Presence publication requests are now reported more sensibly by the ContactManager::presencePublicationRequested(Contacts) signal, with the per-contact request message, if any, being in Contact::publishStateMessage() Fixes: * ContactManager not emitting presencePublicationRequested if the request message is empty. * ContactManager sometimes crashing when contacts are removed using the new ContactList interface. telepathy-qt4 0.5.3 (2011-01-17) ================================= The "contact factorization" release. Enhancements: * Added Tp::Contact::requestAvatarData() * Added Tp::Contact::isContactInfoKnown() * fd.o#32999 - operator< and qHash are not implemented for Tp::ProtocolParameter. * fd.o#33119 - Bind Connection.HasImmortalHandles. * ContactFactory is no more a stub class. The features set in the ContactFactory will be enabled in all contacts created by ContactManager and the classes using it (Connection, Channel, etc). Fixes: * Build failures on systems using GNU gold or the --no-add-needed/--no-copy-dt-needed-entries linker flags telepathy-qt4 0.5.2 (2011-01-03) ================================= The "I'm not subscribed now, right? WRONG" release. Enhancements: * Added Or/NotFilter classes making it more flexible to use the Filter API. * Channel invalidation reasons now more accurately describe what happened, including a new error TP_QT4_ERROR_ORPHANED for the corresponding Connection getting invalidated from whichever reason. * Added support for ContactList and ContactGroups interfaces improving performance of Connection::FeatureRoster/Groups when the CM supports the new interfaces. * ContactManager PendingOperations finish at consistent times wrt actual state changes when used with a CM sporting the new ContactList/ContactGroups interfaces * Deprecated Contact/ContactManager signals carrying a Channel::GroupMemberChangeDetails param for publish/subscription/block state changes and added new signals that should be used in new code. * fd.o #31464 - Added Channel::requestLeave() for leaving channels more gracefully than closing them; StreamedMediaChannel::hangupCall now uses that Fixes: * Properly install TelepathyQt4/ConnectionManagerLowLevel. * A race condition causing proxies to be needlessly dropped from the factory cache and hence new proxies built for a future request, and eventually hitting an assert in onProxyInvalidated as a result * Memory leaks when using Connection::FeatureRoster/RosterGroups where the connection and roster channels were leaking. * fd.o#29728 - ContactManager::addGroup and removeGroup are confusing/broken. * fd.o#29735 - Roster API semantics are error / race condition prone. telepathy-qt4 0.5.1 (2010-12-08) ================================= The "lazily evaluated birth" release. Fixes: * fd.o #29731: Memory leaks reported by make check-valgrind * Crash using a dangling (const!) iterator when a channel is removed from a conference * Crash when the an object path for an Account in an account set is quickly reused after it's removed * Emitting redundant {local,remote}SendingStateChanged signals from StreamedMediaChannel * ChannelDispatchOperation::channelLost failing to include Tp:: in the signal arg type names, making it a tad hard to connect to telepathy-qt4 0.5.0 (2010-11-16) ================================= The "new era of breakage" release. This release IS NOT API/ABI COMPATIBLE WITH EARLIER RELEASES. Further releases in the 0.5 development series will however be compatible with this release, as will any releases in a 0.6 stable series. For enhanced compatibility versions from 0.5 and earlier series can be parallel installed, with 0.5 bumping the .so major version to .so.1. However, the development headers and pkgconfig file can't be parallel installed. Enhancements: * fd.o #28793 - It is no longer necessary to keep the proxy / other object you get a PendingOperation from manually referenced until the operation is finished * fd.o #28797 - generated client code (AbstractInterface subclasses) now allows setting a non-default timeout for D-Bus method calls * fd.o #29486 - Bare variant maps and string lists are no longer exposed in the API unless absolutely necessary; instead they have wrapper classes with easy access to well-known keys and values. Among other consequences, this means AbstractClient implementations NEED TO CHANGE their method implementation signatures to accept the wrapper classes instead of bare QVariantMaps. * Setting automatic/requested presence in Account now uses Tp::Presence * Cleaned up the API and internal code by removing all deprecated classes, methods and signals. * Added Tp::Object intermediate base class for uniform QObject property change notification. Connection, Channel and Contact will be propertified using it in the future. * Enumeration and flag types generated from the specification can now be used in API without endangering ABI stability due to added padding members, enhancing type safety in numerous instances where bare uints used to be returned / taken as a parameter. * Moved low-level functionality which shouldn't be used when using a full Telepathy setup with a Mission Control service (Account Manager + Channel Dispatcher) available from Connection and ConnectionManager to Lowlevel classes, which can be accessed only if TP_QT4_ENABLE_LOWLEVEL_API is #defined through a lowlevel() accessor on them * Bare pointers are no longer returned from the API, instead either SharedPtr or Qt implicitly shared handle classes are used (applicable to Connection/ContactCapabilities, ProtocolInfo, etc) * Tp::Contact is now a RefCounted and uses Tp::Feature like the rest of the library. * ClientRegistrar no longer guarantees that a singleton instance is returned for create(). In particular, this relaxation allows us to implement an API in the future which constructs a ClientRegistrar behind the scenes to be able to request and handle channels without manually implementing an AbstractClientHandler. * The Filter API is now more future-proof, with the assumption that the filter chain is ANDed together dropped. It will be possible to combine filters using And/Or/Not filter combiners in the future, of which And is included now. * The SharedPtr API has been improved. In particular, it's now safe to use it as a QMap/QHash key and more difficult to use it incorrectly as a boolean or an integer. The redundant WeakPtr class has been removed - use QWeakPointer instead (which works with SharedPtr for all QObject classes). * Tp::Contact friend list state change signals now have a details argument (which will contain e.g. the request message for publishState() == Ask when somebody adds you to their contact list, for example). This means that code connecting to them NEEDS TO BE CHANGED. * Account::haveConnection(Changed) and friends is now the less confusing Account::connection(Changed) pair * AccountManager filtering methods returning an AccountSet now have more descriptive names without the Set suffix * Account/Connection/Channel subclasses now can override the "core" feature implied by isReady() and becomeReady(). In particular, this means that e.g. ContactSearchChannel::isReady() with no arguments will only return true if ContactSearchChannel::FeatureCore is ready in addition to Channel::FeatureCore. * StreamedMediaChannel is once again just for Channel.Type.StreamedMedia channels, with the intermediate Call.DRAFT support and API removed. When Call is undrafted, a new CallChannel will be added and StreamedMediaChannel deprecated. * Similarly, hacky Conference.DRAFT support IS REMOVED. Only the final Conference interface is supported from now on. * Everything that used to be called just Audio/Video/MediaCall etc now has StreamedMedia in the name, to not conflict with future Call API. Fixes: * fd.o #27204 - Codegen erroneously uses enums' value-prefix as the name for the C++ enum * fd.o #29998 - Connecting to signal Tp::TextChannel::chatStateChanged needs typedef if not done in Tp namespace * fd.o #27795 - Problems using Tp::SharedPtr as a key in QMap * ChannelRequest not becoming ready successfully when there is no Account specified * ContactSearchChannel not initializing its private members correctly * Compile errors with QT_STRICT_ITERATORS * Some MSVC++ compilation issues (though there still are likely some remaining) * ContactManager::allKnownContacts not picking up changes from the "stored" list telepathy-qt4 0.3.14 (2010-11-05) ================================= The "O HAI MY NAME IS CONFERENCE" release. Enhancements: * fd.o #30098 - Added an asynchronous property request API for generated low-level proxies * Added high-level class for SimplePresence and changed Contact to use it, deprecating the old methods using SimplePresence directly. * Added signals deprecation support to Contact. * Deprecated StreamedMediaChannel methods that only make sense when used with Call.DRAFT channels (we're going to drop support for that particular draft in 0.5.0) * Deprecated all optional interface convenience methods. The methods inherited from OptionalInterfaceFactory should be used directly instead if access to low-level proxies is needed. * Add unnamed (anonymous, TargetHandleType == None) variants for text chats and calls to ChannelClassSpec * Register all non-QObject public classes with the Qt meta-object system, so they can e.g. be stored in QVariants. Fixes: * Unnamed text and StreamedMedia calls not included in the ChannelFactory (channel class) -> (subclass, features) mapping * Some RequestableChannelClassSpec and ConnectionCapabilities methods having a notion of "text chat with a person WHO is a conference", which doesn't exist telepathy-qt4 0.3.13 (2010-11-01) ================================= The "sickness won't slow us down" release. Enhancements: * Added TP_QT4_ prefixed versions of all generated string constants marked as QLatin1String for less verbose usage with Q_NO_CAST_FROM_ASCII * Added signals deprecation mechanism to warn when a deprecated signal is used. * fd.o #29451 - Make it possible to specify subclasses to use and features to make ready on them in ChannelFactory * fd.o #29484 - RequestableChannelClass should have high-level API * fd.o #29486 - Add a ChannelClassSpec class for easily specifying Client channel filters (and building Channel requests and ChannelFactory filters for advanced usage) * Added more deprecated methods and remove some methods that should not be deprecated. Now the library together with examples builds itself with deprecation warnings enabled, to make sure no deprecate method is used internally. * Deprecated autogenerated synchronous properties accessors/setters. Fixes: * fd.o #30223 - telepathy-qt4's codegen doesn't deal with tp:external-type properly * fd.o #30923 - Fix compilation errors in 0.3.12 - The tp-glib version requirement in 0.3.12 was too old - Compile error in the tp-glib based test library * fd.o #31087 - ChannelRequest immutable property extraction relying on undefined method argument evaluation order -> failing on some toolchains * TextChannel never finishing introspection of FeatureMessageQueue with some older services * Properly document ContactSearchChannel signals. * AccountManager and AccountSet getting confused and hitting asserts with certain sequences of introspecting and adding/removing accounts, most prominently when removing and readding an account * Useless PendingReady code having potential for crashes in corner-cases but serving no useful purpose (now removed) * Code generator changes not always triggering rebuilds properly telepathy-qt4 0.3.12 (2010-10-15) ================================= The "break is coming" release. New API: * Added ContactSearch high-level class. * Added constructors/accessors for using Channel/ContactFactory in Connection. * Added high-level class for ContactInfoFieldList. Enhancements: * Updated to spec 0.21.1: - Added auto generated classes for Conn.ClientTypes/ContactGroups/ContactList/ PowerSaving and Chan.ServerTLSConnection. - Make use of Observer.ObserverInfo.request-properties map, making ChannelRequest use the immutable properties defined in the map if available, avoiding unneeded introspection. - Added support for Conference interface alongside Conference.DRAFT support. - Added ConnectionCapabilities methods to check conference support. * Improved Account::capabilities() to take Profile::unsupportedChannelClasses into account. * Improved StreamedMediaChannel test coverage to yellow (> 80%). Fixes: * Properly install TelepathyQt4/Farsight/global.h. * fd.o#30386 - Regression: StreamedMediaChannel::streamAdded is not emitted when one requests a new stream using a StreamedMedia channel type. * Fixed MediaStream::requestDirection when using a Call channel type. * Un-deprecate AccountManager methods to retrieve accounts given the account paths. * Some small documentation fixes. telepathy-qt4 0.3.11 (2010-10-04) ================================= The "farewell hated friend" release. Enhancements: * fd.o #24648 - Port Telepathy-Qt4's build system from autotools to cmake, resulting in faster builds. All targets supported by the previous build system are still supported, and some new were added, notably individual targets for unit tests and callgrind support. * fd.o #29672 - Support for Profiles - a way to describe different IM/VoIP services by data files (e.g. Google Talk for the XMPP/Jabber protocol) * fd.o #29699 - ChannelRequest immutable data is now accessible even before it's fully ready - this is useful for e.g. early initialization of channel context in applications with the AbstractClientHandler requestNotification API * Some performance optimizations in ReadyObject, ReadinessHelper and Channel Fixes: * Race conditions uncovered by Qt 4.7 in TestAccountBasics and TestConnRoster telepathy-qt4 0.3.10 (2010-09-16) ================================= The {bool b; if (b == false || b == true || b == 99) { /*...*/ }} release. Enhancements: * fd.o #29609 - ClientRegistrar and all related classes now use Factories too, which means if you use the factory-enabled create() variants such as create(AccountManagerPtr), you can share account and connection proxies with the rest of your application, and/or make them be ready by the time your addDispatchOperation/handleChannels/observeChannels implementation is called * fd.o #29090 - Added support to filter accounts by their capabilities (whether you can do room chats, voice calls, etc, using a given account) * Added Account::capabilities(), which automatically gets the capabilities from a connected Connection if there's one, or the protocol object if there isn't * Generic Filter framework, currently only used for Account filtering, but in the future also for filtering Contacts * ChannelRequest is now also using the same Account/Connection etc objects than the rest of the application * PendingChannelRequest now holds a reference to its Account, so you don't have to keep a reference to the Account in your application's scope for the channel request to succeed * There are now variants of the ContactManager signals presencePublicationRequested, groupMembersChanged and allKnownContactsChanged which carry the details parameter (contains things like the message and the reason) Fixes: * Memory leak when using PendingComposite * Memory leak in QDBus triggered by ClientHandlerRequestsAdaptor code (there's a workaround, and the actual bug is reported as QTBUG-13562) * The PendingOperation returned by Connection::requestConnect() finishing even if the connection wasn't connected yet * Hitting an assert in cornercases for calling setIntrospectedCalled twice in Account Avatar introspection * Account::changingPresence() not being initialized correctly telepathy-qt4 0.3.9 (2010-09-10) ================================ The "THE ORIGINAL SWEAT FACTORY^W^WSAUNA MASTER" release. Enhancements: * fd.o #29451 - Add Factory infrastructure, enabling: - sharing accounts/connections between different parts of the library better (this will soon enable us to eliminate duplicate objects between AbstractClient implementations and the AM) - requesting that all accounts/connections/channels/contacts are always ready with given features - automatically constructing application-defined subclasses whenever eg. an Account is constructed * Add finished and usable AccountFactory and ConnectionFactory APIs, and also added API/ABI placeholder ChannelFactory and ContactFactory APIs which will be more useful soon * fd.o #29606 - Use factories in AccountManager and Account for constructing Accounts and Connections -> if desired features are enabled, one no longer needs to make any Account::becomeReady and Connection::becomeReady calls when using an AccountManager * fd.o #29409 - Use QDBusServiceWatcher if available, reducing wakeups * fd.o #20034 - Add avatar cache implementation and featureAvatarData on Tp::Contact using it. * Made Channel::groupSelfContact() always have some contact for the user as long as the channel is ready (if the group has none, the Connection one is used) * (Side-effect from other work) Add fallbacks to channel requests in case the service doesn't provide the InitiatorHandle or the Requested property * Made Channel debug output a bit cleaner * Added Connection::ErrorDetails to represent additional information about error conditions causing Connection invalidation * Made the Connection API guide the applications better to correct error handling practices (all error handling should be done in invalidated() slots) * Add SharedPtr::qobjectCast(), an upcasting constructor and pointer to const support Fixes: * A race condition which could result in Channel ignoring a member change (only applicable to services with Group.MembersChangedDetailed) * A bug where Channel::groupMembersChanged(only removed members) isn't always emitted if the local user is not a member of the group - probably means signaling contacts being removed from roster groups didn't work either * Yet another TestConnRosterGroup race condition (freq: 6 in 20000 runs) * fd.o#29930 - Build error with glib 2.25 * ReadyObjects incorrectly handling feature dependencies * Account/Connection/Channel readifying themselves even if not asked to * Handle reference management screwing up if there are multiple connections online on a single CM * Lots of crash opportunities when a PendingOperation is underway when its parent-ish object is unreferenced in an application telepathy-qt4 0.3.8 (2010-08-24) ================================ The "a weekend (and quite a bit of the Monday early hours) well spent" release. Enhancements: * fd.o#29395 - Update to spec 0.19.10 * fd.o#29461 - Update to spec 0.19.11 * fd.o#28948 - Added docs/tests/missing Qt properties to AccountSet * fd.o#29357 - Account::iconName() and icon() now always return sensible non-empty values * fd.o#28819 - {Account,ConnectionManager}::protocolInfo() has been improved - Recent CMs are now introspected with less D-Bus calls - New API capabilities(), vcardField(), englishName(), iconName() on ProtocolInfo and ManagerFile * fd.o#25126 - Some redundant debug output has been removed * fd.o#27460 - Connection now introspects recent CMs with less D-Bus traffic * Connection::contactManager and ::capabilities are now less of a death-trap - now always are non-NULL - operations fail with descriptive errors if the Connection isn't valid - they used to go NULL at an indeterminate time when eg. disconnecting * Account::connection() object path parsing has been optimized Fixes: * fd.o#28947 - Account::filterAccounts doc does not properly format the example code * fd.o#28651 - Cannot receive files using gabble 0.9 * fd.o#29145 - AccountSet::accountRemoved is emitted for newly-created non-matching accounts * fd.o#29699 - ChannelRequest incorrectly checks immutable properties * Broken iteration code in MediaStream which often led to busy-looping forever * (Harmless) uninitialized memory use reported by valgrind in Account internals Test suite improvements: * fd.o#29702 - Unit tests now execute reliably, and 10-30x faster * Added the script repeat-tests.sh for repeating tests to detect race conditions * Added a conservative 10 minute per test watchdog to detect hung-up test logic - Should be plenty even for heavily loaded VM build bots, as the whole test suite now executes in 2.4-2.5 seconds on my laptop * The StreamedMedia legacy and Future.Call tests now actually have different names to be able to distinguish between them in the test logs * Test coverage reporting now works again; turns out we need to disable building the shared library when it is enabled * amd64 memory use errors (pointer size != int size) calling g_object_new() in tests have been fixed telepathy-qt4 0.3.7 (2010-07-12) ================================ The “not as bad as Pepsi Max” release. Enhancements: * fd.o#28927 - Generate code for Channel.Interface.{Anonymity,ServicePoint} (wjt) * fd.o#28942 - Refresh HACKING and README (wjt) * Update to spec version 0.19.9, adding Read and Deleted members to MessageSendingFlagReport, DeliveryReportingSupportFlagReceive, and DeliveryStatus (wjt) Fixes: * fd.o#28945 - AccountManager::accountsByProtocol() returns an empty set * fd.o#28946 - AccountSet should indicate whether the filter used is valid telepathy-qt4 0.3.6 (2010-07-01) ================================ The "I've been thinkin' a lot today" release. New API: * Added Qt properties to Account. * Added filter API to AccountManager to filter accounts based on Qt properties. Includes a new class AccountSet that represents a set of accounts that match a certain filter and that updates automatically based on accounts Qt properties changes. * fd.o#25035 - Add API to AccountManager to get a list of Account objects, all ready. * fd.o#28825 - Bind Account.Service * fd.o#28828 - Add Qt properties to ConnectionManager * fd.o#28861 - Add auto generated interface and Connection accessor for Connection.Cellular interface Enhancements: * fd.o#28302 - Sync test CM with telepathy-glib * fd.o#28827 - Add valgrind support to tests * fd.o#28850 - Update to spec 0.19.8 Fixes: * fd.o#28489 - manager-file.py missing in tp-qt4 0.3.4 tarball * fd.o#28826 - KeyFile should support spaces in key names and string list params that don't terminate with ; * fd.o#28829 - Contact should not fail if /capabilities attr is empty * fd.o#28830 - Channel does not parse immutable properties correctly * fd.o#28831 - Connection FeatureRosterGroups does not work after FeatureAccountBalance support was added telepathy-qt4 0.3.5 (2010-06-21) ================================ The "Think I'll get it done yesterday" release. New API: * fd.o#28018: Bind Account.ChangingPresence. * fd.o#28552: Bind Account.ConnectionError/Details. Enhancements: * fd.o#28536: update to spec 0.19.7 (ConnectionError, Anonymity, ServicePoint, ChatStates). Fixes: * Update with-session-bus.sh from telepathy-glib, fixing a bashism. (smcv) * Fixed coverity issues with call example. * Fixed AbstractClient documentation. (albanc) * telepathy-qt4-farsight telepathy-glib dependency is now >= 0.8.1. (albanc) telepathy-qt4 0.3.4 (2010-05-23) ================================ The "Cause time takes time, ya know" release. New API: * fd.o#28143: Implement Connection.Balance interface support. Fixes: * Fix strict QtDBus demarshalling which was causing crashes when using qdbus_cast from a SocketAddressIP*. (drf) telepathy-qt4 0.3.3 (2010-05-09) ================================ The "generic fun" release. New API: * fd.o#27671: ContactInfo high-level API. Enhancements: - Added Call.Content.Remove support to StreamedMediaChannel. Fixes: - Fixed a leak in Connection::gotCapabilities, - Correctly remove object path from Account::uniqueIdentifier. telepathy-qt4 0.3.2 (2010-04-23) ================================ The "poisoned with anti-coffee" release. New API: * fd.o#27379: Add a new signal, allKnownContactsChanged. (drf) * fd.o#27677: Add Observer.Recover support. * Added support for retrieving contacts location. Enhancements: * Added example application to list all supported protocols. * fd.o#27670: Updated to spec 0.19.5. Fixes: * Fixed compilation (more specific, moc generation). The code was triggering QTBUG #2151. (drf) * Correctly handle UTF-8 in code generator. (wjt) * Fixed text-chan test race condition. (drf) telepathy-qt4 0.3.1 (2010-03-30) ================================ The "it's all about coffee" release. Enhancements: * Added/Improved documentation for various classes and some minor documentation style fixes. Fixes: * Fixed bug where StreamedMediaChannel::requestStream returned PendingOperation was never finishing. telepathy-qt4 0.3.0 (2010-03-18) ================================ The "With My Own Two Hands" release. Dependencies: * Full regression tests now require telepathy-glib >= 0.10.0 (telepathy-glib is still optional) New API: * Channel: Added Conference/MergeableConference/Spplitabble interfaces support. * StreamedMediaChannel: Added Call interface support. Enhancements: * Updated to 0.19.1 spec. * Better tests directories organization (complete separation of glib/python specific code). Fixes: * fd.o#25422: generate code for Call draft API. * fd.o#26117: Add Call interface support to StreamedMediaChannel. * fd.o#26881: Remove the usage of QString::fromAscii. * fd.o#27124: Missing docs for some classes. * fd.o#27125: Add support to QT_NO_CAST_FROM_ASCII. * Fixed bug when Channel was never getting ready. telepathy-qt4 0.2.2 (2010-02-22) ================================ The "no pain, no gain" release. New API: * AbstractClientHandler: Added support to set Handler Capabilities property. Fixes: * fd.o #25659: ObserveChannels implementation might actually return immediately. telepathy-qt4 0.2.1 (2009-12-04) ================================ The "all you want, only better" release. Fixes: * fd.o #25058: reduce the scope of our workaround for Qt 4.5 bug , fixing compilation against Qt versions >= 4.6 beta, where this bug has been fixed (smcv) * Avoid the installed AccountManager (if any) being service-activated during distcheck under some circumstances (smcv) * Compile with symbols hidden by default, explicitly export a few symbols that were mistakenly not exported, and improve the code generation tools to be more correct about their exports (smcv) * Improve the code-generation tools to cope with UTF-8 in the spec (wjt, smcv) * Enable Automake 1.11 silent building (./configure --enable-silent-rules to enable this) (wjt) Code generation release notes: * qt4-types-gen.py and qt4-client-gen.py previously forced the generated classes to be exported, in a way that's not actually correct for code outside telepathy-qt4 (the TELEPATHY_QT4_EXPORT macro). They now use a macro set by --visibility, defaulting to nothing; if you're building a shared library with -fvisibility=hidden, or supporting Windows, you may need to use --visibility=YOUR_LIB_EXPORT when running these scripts. See TelepathyQt4/global.h or QtDBus/qdbusmacros.h for an example of setting up such a macro (unfortunately, the only correct way to do this seems to be for each shared library to define its own). telepathy-qt4 0.2.0 (2009-11-10) ================================ The "I Shot the Sheriff" release. API changes: * Connection: Changed status/statusReason/statusChanged to use enums Tp::Connection::Status and ConnectionStatusReason. * Connection: Renamed getContactAttributes method to contactAttributes. Fixes: * fd.o#23370: Make better use of telepathy-spec 0.17.27 errors. * fd.o#24422: Account removal should be represented by TELEPATHY_QT4_ERROR_OBJECT_REMOVED. telepathy-qt4 0.1.12 (2009-11-05) ================================ The "an enzyme that breaks down tigers" release. New API: * TextChannel: Added ChatState interface support. API changes: * TextChannel: send() methods now receive a flags parameter, so we proper support delivery reports. Fixes: * pkgconfig: Added missing QtNetwork dependency. telepathy-qt4 0.1.11 (2009-10-08) ================================ The "on more to go" release. New API: * FileTransferChannel: Added methods to access FileTransfer interface properties. * IncomingFileTransferChannel: Added specialized class for handling incoming file transfers. * OutgoingFileTransferChannel: Added specialized class for handling outgoing file transfers. * CapabilitiesBase: Added base class to represent contact/connection capabilities. * ContactCapabilities: Added specialized class that inherits CapabilitiesBase to represent contact capabilities. * ConnectionCapabilities: Added specialized class that inherits CapabilitiesBase to represent connection capabilities. * Contact: Added ContactCapabilities interface support. * Connection: Added capabilities (RequestableChannelClasses) support. * Account: Added ensureAudio/VideoCall methods that make use of InitialAudio/Video properties when creating StreamedMedia channels. * Channel: Added streamTubeInterface/tubeInterface methods. (Patch from Abner Silva ). * PendingVariant: Added pending operation helper class for D-Bus methods that return a variant as result. API changes: * Renamed PendingVoidMethodCall to PendingVoid. * Changed PendingVoid/Success/Failure constructor to receive parent as last parameter. Enhancements: * Added examples for handling incoming/outgoing file transfers, examples/file-transfer/ * Added C++ visibility support. * Updated to 0.18.0 spec. Fixes: * fd.o #24324: Account::create/ensureXXX should receive a const QDateTime & for userActionTime * Explicitly use uint for TargetHandleType. telepathy-qt4 0.1.10 (2009-08-25) ================================ The "not yet stable" release. New API: * StreamedMediaChannel: Added Hold and DTMF interface support. Enhancements: * Moved OptionalInterfaceFactory::InterfaceSupportedChecking docs from DBusProxy to OptionalInterfaceFactory. * Use struct Private instead of class Private for consistence. * Removed cli/Client from header guards. Fixes: * fd.o #20269: Channel's Contact objects should initially have no features. * fd.o #21335: Implement Group self-handle removal reasons. * fd.o #23040: Running connection managers appear twice in ConnectionManager::listNames result. * fd.o #23282: Channel should update ReadinessHelper with the supported interfaces. telepathy-qt4 0.1.9 (2009-07-23) ================================ The "never too late" release. New API: * OptionalInterfaceFactory: Added methods interfaces and optionalInterface and removed duplicated code in all OptionalInterfaceFactory subclasses. * Added ContactManager allKnownGroups, addGroup, removeGroup, groupContacts, addContactsToGroup and removeContactsFromGroup methods. * Added ContactManager groupAdded, groupRemoved and groupMembersChanged signals. * Added Contact groups, addToGroup and removeFromGroup methods. * Added Contact addedToGroup and removedFromGroup signals. API changes: * Changed ProtocolParameter requiredForRegistration method to isRequiredForRegistration to make it consistent with other bool returning getters. Enhancements: * Changed all classes to follow coding-style. * Moved documentation to source file for all classes. * Standardize class definition in all classes: * Moved public xxxInterface methods definition to the end of the public methods declaration. * Added friend struct Private declaration. * Added Q_DISABLE_COPY(xxx) to all classes that can not be copied. * Moved Q_DISABLE_COPY(xxx) declaration to the top of the class definition, before the public keyword. * Reorder public, protected, SIGNALS declaration as follows: public public Q_SLOTS Q_SIGNALS protected protected Q_SLOTS private Q_SLOTS private * Moved friend class xxx definitions to be placed right below private keyword * ChannelDispatchOperation: Emit invalidated with TELEPATHY_QT4_ERROR_OBJECT_REMOVED when ChannelDispatchOperation.Finished is received. * Added/Improved some documentation. Fixes: * ClientApproverAdaptor: Use the dbus fully qualified name to get the connection property (Patch from George Kiagiadakis ). * Fixed bug 20268: Connection's selfContact object should initially have no features. * Fixed bug 20080: KeyFile: ";" as a list may be mis-parsed. * Fixed bug 20082: KeyFile: double (and other types?) not correctly tested. * Fixed bug 20353: No d-pointer in Channel::GroupMemberChangeDetails. * Fixed bug 20033: Contact / ContactList Group integration. telepathy-qt4 0.1.8 (2009-06-16) ================================ The "Every Good Boy Deserves Frontalot" release. New API: * Added PendingChannelRequest class to be used when requesting channels using ChannelDispatcher through Account. * Added Account methods to request/create channels using ChannelDispatcher (ensureTextChat, ensureTextChatroom, ensureMediaCall, createChannel and ensureChannel) Enhancements: * Updated to telepathy-spec 0.17.26 Fixes: * ChannelDispatchOperation: Read Channels property instead of incorrectly reading ChannelDetailsList (Patch from George Kiagiadakis ). telepathy-qt4 0.1.7 (2009-06-02) ================================ The "approver" release. New API: * Added Client Approver support. * Added ChannelDispatchOperation high-level class. Bugfixes: * Fixed bug 21988: Channel does not work properly if the parent connection object is not ready * Fixed bug 21993: TextChannel does not become ready until first message is received if FeatureMessageQueue is enabled. telepathy-qt4 0.1.6 (2009-05-28) ================================ The "So hot, I have a fever" release. New API: * Added Channel::immutableProperties public method. Enhancements: * Added ChannelFactory, internal class to create channels based on their types. * PendingChannel: Use ChannelFactory to create channels. Bugfixes: * Proper define AbstractClientPtr. * ClientRegistrar: Fixed Observer adaptor introspection data. * ClientRegistrar: Use ChannelFactory to create Channels. telepathy-qt4 0.1.5 (2009-05-19) ================================ The "do not look at the conductor" release. New API: * Added Client support (Handler, Observer). * Added ClientRegistrar, class responsible for registering clients and proper exporting their D-Bus interfaces. * Added AbstractClientObserver, AbstractClientApprover (skeleton) and AbstractClientHandler. Clients should inherit one or some combination of these, by using multiple inheritance, and register themselves using ClientRegistrar::registerClient() in order to become a Client. * Added ChannelRequest high-level class. telepathy-qt4 0.1.4 (2009-05-08) ================================ The "global military-industrial complex is subsidising your iPod" release. Dependencies: * Creating accounts, and possibly updating their parameters, now requires an AccountManager implementing telepathy-spec 0.17.24, such as telepathy-mission-control >= 5.0.beta70 (in particular, beta 69 won't work, and the KWallet-based account manager will also need updating) API changes: * Renamed SharedData header file to RefCounted to follow class name. New API: * Update to telepathy-spec 0.17.24, breaking some D-Bus APIs: * fd.o #21619: Account::updateParameters() returns a PendingStringList of the parameters that won't be changed until reconnection takes place * Account::reconnect() added (newer MC versions don't violate telepathy-spec by reconnecting automatically when parameters are changed) * AccountManager::supportedAccountProperties() added * AccountManager::createAccount() takes an optional dict of properties (the valid keys are in supportedAccountProperties()) * Enhance PendingStringList to have a constructor from a QDBusPendingCall Bugfixes: * Don't try to run Python tests unless we have the gobject module (the tests use it) telepathy-qt4 0.1.3 (2009-04-22) ================================ The "what are you scared of?" release. Dependencies: * Full regression tests now require telepathy-glib >= 0.7.28 (telepathy-glib is still optional) API changes: * Namespace simplification: Telepathy::Client::Channel (etc.) are now Tp::Channel, similar to telepathy-glib's TpChannel. Auto-generated client classes like Telepathy::Client::ChannelInterface are now Tp::Client::ChannelInterface. * AccountManager, Account, ConnectionManager, Connection, Channel and Channel subclasses now inherit from Tp::RefCounted and are used together with Tp::SharedPtr/Tp::WeakPtr, shared and weak pointer classes using ideas from Qt, glibmm, Boost and WebKit. The constructor is now protected (in order to support custom classes) and a public create method that returns a SharedPtr was added. This is an attempt to avoid memory leaks as much as possible, see http://lists.freedesktop.org/archives/telepathy/2009-March/003218.html for more details. * Instead of forward-declaring Telepathy::Client::Channel and using a variable of type Telepathy::Client::Channel *, you should now include and use either Tp::ChannelPtr, which is a reference-counted shared pointer, or Tp::WeakPtr, which is the weak counterpart. * Header simplification: the public headers now look like , i.e. without the Client subdirectory. * PendingHandles now finish successfully on non fatal errors (InvalidArgument, InvalidHandle, NotAvailable). PendingHandles::invalidNames/invalidHandles should be used to check if a non-fatal error occurred and some handle could not be acquired. Enhancements: * Updated to telepathy-spec 0.17.23 * TelepathyQt4Farsight is a new mini-library with glue code to connect telepathy-farsight to Telepathy-Qt4. Handlers for streamed media channels with media signalling can #include and pass their Tp::StreamedMediaChannel to Tp::createFarsightChannel, then hook up the resulting TfChannel to a GStreamer pipeline of their choice. * StreamedMediaChannel has a new handlerStreamingRequired method so you can check whether the handler needs to carry out the streaming * fd.o #21336: Channels now indicate whether a message is expected when doing various Group operations * fd.o #21337: Account supports the new HasBeenOnline property Fixes: * fd.o #20583: Contact objects don't work without the Contacts interface. * fd.o #20584: Contact object creation doesn't survive bad IDs or handles. telepathy-qt4 0.1.2 (2009-03-23) ================================ The "robotic automatic hoover" release. Dependencies: * Full regression tests now require telepathy-glib >= 0.7.27 (telepathy-glib is still optional) * telepathy-farsight >= 0.0.4 is a new optional dependency API changes: * AccountManager, Account, ConnectionManager, Connection, Channel now inherit QSharedData and are used together with QExplicitlySharedDataPointer. This is needed so we can create shared pointers based on the object itself, instead of doing hacks to find the shared pointer related to a given object. See http://lists.freedesktop.org/archives/telepathy/2009-March/003168.html for more details. * Channel Features are now Feature objects, not integers * The Feature class is now in its own header, Enhancements: * The skeletal StreamedMediaChannel class from 0.1.0 has been expanded to cover all the functionality of the Telepathy StreamedMedia interface * PendingConnection, PendingAccount etc. have busName and objectPath methods where necessary, so that objects of custom classes can be constructed * Features can now be considered critical, meaning that failure to set them up leads to failure of becomeReady() - this should only be used for features that should never fail unless the service is buggy, like Connection and Channel core functionality * examples/call/ is an example of how to use StreamedMediaChannel, which can make and receive XMPP Jingle calls using telepathy-gabble (this feature requires telepathy-farsight and GStreamer) Fixes: * When introspection of a Feature fails, the D-Bus error is propagated as the failure reason of becomeReady() * Fix a memory leak in TextChannel telepathy-qt4 0.1.1 (2009-03-05) ================================ The "PresencePublicationAuthorizationRequestRejection" release. API changes: * PendingReadyAccount, PendingReadyAccountManager, PendingReadyConnection, PendingReadyConnectionManager have all been replaced by the PendingReady class * Account, AccountManager, Connection and ConnectionManager features are now QSet, not bitfields * Plural contacts are generally represented by a QSet > instead of a QList > (with a new typedef, Telepathy::Client::Contacts, which must be used in signal/slot connections) Enhancements: * Added Connection::FeatureRoster, which, when enabled, adds contact list (a.k.a. roster/buddy list) functionality to the ContactManager and Contact objects * Improved maintainability of Account, AccountManager, Connection and ConnectionManager becoming ready * A QSharedPointer is now hashable with qHash, meaning contacts can be QSet or QHash members * Added a trivial contact list user interface, examples/roster/roster Fixes: * The client library no longer attempts to enforce group add/remove flags: whatever change the user requests is passed on to the connection manager (which might reject it) * PendingReady objects returned by Connection::becomeReady() have the Connection as parent, rather than an internal object that isn't useful to library users telepathy-qt4 0.1.0 (2009-02-26) ================================ The "pending operation" release. This first release of telepathy-qt4 features high-level API for the following: * Manipulating accounts on a Telepathy AccountManager implementation as described by telepathy-spec 0.17.x, such as Mission Control 5 (beta versions currently available) * Manipulating Telepathy connection managers via the ConnectionManager and Connection core API * Setting your own presence on a connection manager supporting the SimplePresence interface * Requesting channels from a connection manager supporting the Requests interface * Reading contacts' aliases etc. on a connection manager supporting the Contacts interface * Sending and receiving messages on Text channels, with or without the Messages interface In addition, lower-level auto-generated accessors are provided for all the functionality of telepathy-spec version 0.17.19. Notable functionality that is currently missing, but will be added soon, includes: * Manipulating a server-stored contact list * Controlling VoIP calls in StreamedMedia channels /* ex: set textwidth=80: */ telepathy-qt-0.9.6~git1/AUTHORS0000664000175000017500000000025412470405660014021 0ustar jrjrAndre Moreira Magalhaes (andrunko) Olli Salli (oggis) Simon McVittie (smcv) telepathy-qt-0.9.6~git1/config-version.h.in0000664000175000017500000000005412470405660016455 0ustar jrjr#define PACKAGE_VERSION "@PACKAGE_VERSION@" telepathy-qt-0.9.6~git1/tools/0000775000175000017500000000000012470405660014110 5ustar jrjrtelepathy-qt-0.9.6~git1/tools/git-which-branch.sh0000664000175000017500000000125312470405660017563 0ustar jrjr#!/bin/sh # git-which-branch.sh - output the name of the current git branch # # The canonical location of this program is the telepathy-spec tools/ # directory, please synchronize any changes with that copy. # # Copyright (C) 2008 Collabora Ltd. # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. default="$1" if { ref="`git symbolic-ref HEAD 2>/dev/null`"; }; then echo ${ref#refs/heads/} exit 0 fi if test -n "$default"; then echo "$default" >/dev/null exit 0 fi echo "no git branch found" >&2 exit 1 telepathy-qt-0.9.6~git1/tools/qt-client-gen.py0000664000175000017500000004205412470405660017136 0ustar jrjr#!/usr/bin/python # # Copyright (C) 2008 Collabora Limited # Copyright (C) 2008 Nokia Corporation # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA from sys import argv import xml.dom.minidom import codecs from getopt import gnu_getopt from libtpcodegen import NS_TP, get_descendant_text, get_by_path from libqtcodegen import binding_from_usage, extract_arg_or_member_info, format_docstring, gather_externals, gather_custom_lists, get_headerfile_cmd, get_qt_name, qt_identifier_escape, RefRegistry class Generator(object): def __init__(self, opts): try: self.group = opts.get('--group', '') self.headerfile = opts['--headerfile'] self.implfile = opts['--implfile'] self.namespace = opts['--namespace'] self.typesnamespace = opts['--typesnamespace'] self.realinclude = opts['--realinclude'] self.prettyinclude = opts.get('--prettyinclude') self.extraincludes = opts.get('--extraincludes', None) self.mainiface = opts.get('--mainiface', None) self.must_define = opts.get('--must-define', None) self.dbus_proxy = opts.get('--dbus-proxy', 'Tp::DBusProxy') self.visibility = opts.get('--visibility', '') ifacedom = xml.dom.minidom.parse(opts['--ifacexml']) specdom = xml.dom.minidom.parse(opts['--specxml']) except KeyError, k: assert False, 'Missing required parameter %s' % k.args[0] self.hs = [] self.bs = [] self.ifacenodes = ifacedom.getElementsByTagName('node') self.spec, = get_by_path(specdom, "spec") self.custom_lists = gather_custom_lists(self.spec, self.typesnamespace) self.externals = gather_externals(self.spec) self.refs = RefRegistry(self.spec) def __call__(self): # Output info header and includes self.h("""\ /* * This file contains D-Bus client proxy classes generated by qt-client-gen.py. * * This file can be distributed under the same terms as the specification from * which it was generated. */ """) if self.must_define: self.h('\n') self.h('#ifndef %s\n' % self.must_define) self.h('#error %s\n' % self.must_define) self.h('#endif\n') self.h('\n') if self.extraincludes: for include in self.extraincludes.split(','): self.h('#include %s\n' % include) self.h(""" #include #include #include #include #include #include #include #include namespace Tp { class PendingVariant; class PendingOperation; } """) if self.must_define: self.b("""#define %s\n""" % (self.must_define)) self.b("""#include "%s" """ % self.realinclude) # Begin namespace for ns in self.namespace.split('::'): self.hb("""\ namespace %s { """ % ns) # Output interface proxies def ifacenodecmp(x, y): xname, yname = [self.namespace + '::' + node.getAttribute('name').replace('/', '').replace('_', '') + 'Interface' for node in x, y] if xname == self.mainiface: return -1 elif yname == self.mainiface: return 1 else: return cmp(xname, yname) self.ifacenodes.sort(cmp=ifacenodecmp) for ifacenode in self.ifacenodes: self.do_ifacenode(ifacenode) # End namespace self.hb(''.join(['}\n' for ns in self.namespace.split('::')])) # Add metatype declaration - otherwise QTBUG #2151 might be triggered for ifacenode in self.ifacenodes: classname = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Interface' self.h("Q_DECLARE_METATYPE(" + self.namespace + "::" + classname + "*)\n") # Write output to files (codecs.getwriter('utf-8')(open(self.headerfile, 'w'))).write(''.join(self.hs)) (codecs.getwriter('utf-8')(open(self.implfile, 'w'))).write(''.join(self.bs)) def do_ifacenode(self, ifacenode): # Extract info name = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Interface' iface, = get_by_path(ifacenode, 'interface') dbusname = iface.getAttribute('name') # Begin class, constructors self.h(""" /** * \\class %(name)s %(headercmd)s\ %(groupcmd)s\ * * Proxy class providing a 1:1 mapping of the D-Bus interface "%(dbusname)s". */ class %(visibility)s %(name)s : public Tp::AbstractInterface { Q_OBJECT public: /** * Returns the name of the interface "%(dbusname)s", which this class * represents. * * \\return The D-Bus interface name. */ static inline QLatin1String staticInterfaceName() { return QLatin1String("%(dbusname)s"); } /** * Creates a %(name)s associated with the given object on the session bus. * * \\param busName Name of the service the object is on. * \\param objectPath Path to the object on the service. * \\param parent Passed to the parent class constructor. */ %(name)s( const QString& busName, const QString& objectPath, QObject* parent = 0 ); /** * Creates a %(name)s associated with the given object on the given bus. * * \\param connection The bus via which the object can be reached. * \\param busName Name of the service the object is on. * \\param objectPath Path to the object on the service. * \\param parent Passed to the parent class constructor. */ %(name)s( const QDBusConnection& connection, const QString& busName, const QString& objectPath, QObject* parent = 0 ); """ % {'name' : name, 'headercmd' : get_headerfile_cmd(self.realinclude, self.prettyinclude), 'groupcmd' : self.group and (' * \\ingroup %s\n' % self.group), 'dbusname' : dbusname, 'visibility': self.visibility, }) self.b(""" %(name)s::%(name)s(const QString& busName, const QString& objectPath, QObject *parent) : Tp::AbstractInterface(busName, objectPath, staticInterfaceName(), QDBusConnection::sessionBus(), parent) { } %(name)s::%(name)s(const QDBusConnection& connection, const QString& busName, const QString& objectPath, QObject *parent) : Tp::AbstractInterface(busName, objectPath, staticInterfaceName(), connection, parent) { } """ % {'name' : name}) # Construct from DBusProxy subclass self.h(""" /** * Creates a %(name)s associated with the same object as the given proxy. * * \\param proxy The proxy to use. It will also be the QObject::parent() * for this object. */ %(name)s(%(dbus_proxy)s *proxy); """ % {'name' : name, 'dbus_proxy' : self.dbus_proxy}) self.b(""" %(name)s::%(name)s(%(dbus_proxy)s *proxy) : Tp::AbstractInterface(proxy, staticInterfaceName()) { } """ % {'name' : name, 'dbus_proxy' : self.dbus_proxy}) # Main interface mainiface = self.mainiface or 'Tp::AbstractInterface' if mainiface != self.namespace + '::' + name: self.h(""" /** * Creates a %(name)s associated with the same object as the given proxy. * Additionally, the created proxy will have the same parent as the given * proxy. * * \\param mainInterface The proxy to use. */ explicit %(name)s(const %(mainiface)s& mainInterface); /** * Creates a %(name)s associated with the same object as the given proxy. * However, a different parent object can be specified. * * \\param mainInterface The proxy to use. * \\param parent Passed to the parent class constructor. */ %(name)s(const %(mainiface)s& mainInterface, QObject* parent); """ % {'name' : name, 'mainiface' : mainiface}) self.b(""" %(name)s::%(name)s(const %(mainiface)s& mainInterface) : Tp::AbstractInterface(mainInterface.service(), mainInterface.path(), staticInterfaceName(), mainInterface.connection(), mainInterface.parent()) { } %(name)s::%(name)s(const %(mainiface)s& mainInterface, QObject *parent) : Tp::AbstractInterface(mainInterface.service(), mainInterface.path(), staticInterfaceName(), mainInterface.connection(), parent) { } """ % {'name' : name, 'mainiface' : mainiface}) # Properties has_props = False for prop in get_by_path(iface, 'property'): # Skip tp:properties if not prop.namespaceURI: self.do_prop(prop) has_props = True self.h(""" /** * Request all of the DBus properties on the interface. * * \\return A pending variant map which will emit finished when the properties have * been retrieved. */ Tp::PendingVariantMap *requestAllProperties() const { return internalRequestAllProperties(); } """) # Methods methods = get_by_path(iface, 'method') if methods: self.h(""" public Q_SLOTS:\ """) for method in methods: self.do_method(method) # Signals signals = get_by_path(iface, 'signal') if signals: self.h(""" Q_SIGNALS:\ """) for signal in signals: self.do_signal(signal) # invalidated handler (already a slot in the superclass) # we can't just use disconnect(this, NULL, NULL, NULL) because # (a) that would disconnect QObject::destroyed() and other non-D-Bus # signals, and (b) QtDBus doesn't support that usage anyway (it needs # specific signals in order to remove its signal match rules) self.h(""" protected: virtual void invalidate(Tp::DBusProxy *, const QString &, const QString &); """) self.b(""" void %(name)s::invalidate(Tp::DBusProxy *proxy, const QString &error, const QString &message) { """ % {'name' : name}) for signal in signals: self.do_signal_disconnect(signal) self.b(""" Tp::AbstractInterface::invalidate(proxy, error, message); } """) # Close class self.h("""\ }; """) def do_prop(self, prop): name = prop.getAttribute('name') access = prop.getAttribute('access') gettername = name settername = None docstring = format_docstring(prop, self.refs, ' * ').replace('*/', '*/') sig = prop.getAttribute('type') tptype = prop.getAttributeNS(NS_TP, 'type') binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace) if 'write' in access: settername = 'set' + name if 'read' in access: self.h(""" /** * Asynchronous getter for the remote object property \\c %(name)s of type \\c %(val)s. * %(docstring)s\ * * \\return A pending variant which will emit finished when the property has been * retrieved. */ inline Tp::PendingVariant *%(gettername)s() const { return internalRequestProperty(QLatin1String("%(name)s")); } """ % {'name' : name, 'docstring' : docstring, 'val' : binding.val, 'gettername' : 'requestProperty' + name}) if 'write' in access: self.h(""" /** * Asynchronous setter for the remote object property \\c %(name)s of type \\c %(type)s. * %(docstring)s\ * * \\return A pending operation which will emit finished when the property has been * set. */ inline Tp::PendingOperation *%(settername)s(%(type)s newValue) { return internalSetProperty(QLatin1String("%(name)s"), QVariant::fromValue(newValue)); } """ % {'name' : name, 'docstring' : docstring, 'type' : binding.val, 'name' : name, 'settername' : 'setProperty' + name}) def do_method(self, method): name = method.getAttribute('name') args = get_by_path(method, 'arg') argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') inargs = [] outargs = [] for i in xrange(len(args)): if args[i].getAttribute('direction') == 'out': outargs.append(i) else: inargs.append(i) assert argnames[i] != None, 'No argument name for input argument at index %d for method %s' % (i, name) rettypes = ', '.join([argbindings[i].val for i in outargs]) params = ', '.join([argbindings[i].inarg + ' ' + argnames[i] for i in inargs]) if params: params += ', int timeout = -1' else: params = 'int timeout = -1' self.h(""" /** * Begins a call to the D-Bus method \\c %s on the remote object. %s\ * * Note that \\a timeout is ignored as of now. It will be used once * http://bugreports.qt.nokia.com/browse/QTBUG-11775 is fixed. * """ % (name, format_docstring(method, self.refs, ' * '))) for i in inargs: if argdocstrings[i]: self.h("""\ * * \\param %s %s\ """ % (argnames[i], argdocstrings[i])) self.h("""\ * \\param timeout The timeout in milliseconds. """) for i in outargs: if argdocstrings[i]: self.h("""\ * * \\return %s\ """ % argdocstrings[i]) self.h("""\ */ inline QDBusPendingReply<%(rettypes)s> %(name)s(%(params)s) { if (!invalidationReason().isEmpty()) { return QDBusPendingReply<%(rettypes)s>(QDBusMessage::createError( invalidationReason(), invalidationMessage() )); } """ % {'rettypes' : rettypes, 'name' : name, 'params' : params}) if inargs: self.h(""" QDBusMessage callMessage = QDBusMessage::createMethodCall(this->service(), this->path(), this->staticInterfaceName(), QLatin1String("%s")); callMessage << %s; return this->connection().asyncCall(callMessage, timeout); } """ % (name, ' << '.join(['QVariant::fromValue(%s)' % argnames[i] for i in inargs]))) else: self.h(""" QDBusMessage callMessage = QDBusMessage::createMethodCall(this->service(), this->path(), this->staticInterfaceName(), QLatin1String("%s")); return this->connection().asyncCall(callMessage, timeout); } """ % name) def do_signal(self, signal): name = signal.getAttribute('name') argnames, argdocstrings, argbindings = extract_arg_or_member_info(get_by_path(signal, 'arg'), self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') self.h(""" /** * Represents the signal \\c %s on the remote object. %s\ """ % (name, format_docstring(signal, self.refs, ' * '))) for i in xrange(len(argnames)): assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name) if argdocstrings[i]: self.h("""\ * * \\param %s %s\ """ % (argnames[i], argdocstrings[i])) self.h("""\ */ void %s(%s); """ % (name, ', '.join(['%s %s' % (binding.inarg, name) for binding, name in zip(argbindings, argnames)]))) def do_signal_disconnect(self, signal): name = signal.getAttribute('name') _, _, argbindings = extract_arg_or_member_info(get_by_path(signal, 'arg'), self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') self.b("""\ disconnect(this, SIGNAL(%s(%s)), NULL, NULL); """ % (name, ', '.join([binding.inarg for binding in argbindings]))) def h(self, str): self.hs.append(str) def b(self, str): self.bs.append(str) def hb(self, str): self.h(str) self.b(str) if __name__ == '__main__': options, argv = gnu_getopt(argv[1:], '', ['group=', 'namespace=', 'typesnamespace=', 'headerfile=', 'implfile=', 'ifacexml=', 'specxml=', 'realinclude=', 'prettyinclude=', 'extraincludes=', 'mainiface=', 'must-define=', 'dbus-proxy=', 'visibility=']) Generator(dict(options))() telepathy-qt-0.9.6~git1/tools/telepathy-glib.supp0000664000175000017500000001451312470405660017737 0ustar jrjr# Valgrind error suppression file # ============================= libc ================================== { ld.so initialization + selinux Memcheck:Leak ... fun:_dl_init obj:/lib/ld-*.so } { dlopen initialization, triggered by handle-leak-debug code Memcheck:Leak ... fun:__libc_dlopen_mode fun:init fun:backtrace fun:handle_leak_debug_bt fun:dynamic_ensure_handle fun:tp_handle_ensure } # default.supp has these for 2.10, but they're too specific { Debian libc6 (2.10.x, 2.11.x) stripped dynamic linker Memcheck:Cond fun:index fun:expand_dynamic_string_token fun:_dl_map_object fun:map_doit fun:_dl_catch_error fun:do_preload fun:dl_main fun:_dl_sysdep_start fun:_dl_start obj:/lib/ld-*.so } { Debian libc6 (2.9.x - 2.11.x) stripped dynamic linker Memcheck:Cond fun:_dl_relocate_object fun:dl_main fun:_dl_sysdep_start fun:_dl_start obj:/lib/ld-*.so } { ld.so initialization on glibc 2.9 Memcheck:Cond fun:strlen fun:_dl_init_paths fun:dl_main fun:_dl_sysdep_start fun:_dl_start obj:/lib/ld-2.9.so } # ======================= libselinux on Debian amd64 ===================== { I have no idea what SELinux is doing but it's not my problem Memcheck:Cond ... obj:/lib/libselinux.so.1 obj:/lib/libselinux.so.1 obj:/lib/libselinux.so.1 } { I have no idea what SELinux is doing but it's not my problem Memcheck:Value8 ... obj:/lib/libselinux.so.1 obj:/lib/libselinux.so.1 obj:/lib/libselinux.so.1 } { I have no idea what SELinux is doing but it's not my problem Memcheck:Leak ... obj:/lib/libselinux.so.1 obj:/lib/libselinux.so.1 obj:/lib/libselinux.so.1 } # ============================= GLib ================================== { g_set_prgname copies its argument Memcheck:Leak ... fun:g_set_prgname } { one g_get_charset per child^Wprocess Memcheck:Leak ... fun:g_get_charset } { one g_get_home_dir per process Memcheck:Leak ... fun:g_get_home_dir } { GQuarks can't be freed Memcheck:Leak ... fun:g_quark_from_static_string } { GQuarks can't be freed Memcheck:Leak ... fun:g_quark_from_string } { interned strings can't be freed Memcheck:Leak ... fun:g_intern_string } { interned strings can't be freed Memcheck:Leak ... fun:g_intern_static_string } { shared global default g_main_context Memcheck:Leak ... fun:g_main_context_new fun:g_main_context_default } { GTest initialization Memcheck:Leak ... fun:g_test_init fun:main } { GTest admin Memcheck:Leak ... fun:g_test_add_vtable } { GTest pseudorandomness Memcheck:Leak ... fun:g_rand_new_with_seed_array fun:test_run_seed ... fun:g_test_run } { GSLice initialization Memcheck:Leak ... fun:g_malloc0 fun:g_slice_init_nomessage fun:g_slice_alloc } # ============================= GObject =============================== { g_type_init Memcheck:Leak ... fun:g_type_init } { g_type_init_with_debug_flags Memcheck:Leak ... fun:g_type_init_with_debug_flags } { g_type_register_static Memcheck:Leak ... fun:g_type_register_static } { g_type_add_interface_static Memcheck:Leak ... fun:g_type_add_interface_static } { initialization of interfaces Memcheck:Leak ... fun:type_iface_vtable_base_init_Wm fun:g_type_class_ref } # ============================= GIO =================================== { GIO init Memcheck:Leak ... fun:g_inet_address_class_intern_init } { g_simple_async_result class Memcheck:Leak ... fun:g_type_class_ref ... fun:g_simple_async_result_new } # ============================= dbus-glib ============================= { registering marshallers is permanent Memcheck:Leak ... fun:dbus_g_object_register_marshaller_array fun:dbus_g_object_register_marshaller } { dbus-glib specialized GTypes are permanent Memcheck:Leak ... fun:dbus_g_type_specialized_init } { libdbus shared connection Memcheck:Leak ... fun:dbus_g_bus_get } { dbus-gobject registrations aren't freed unless we fall off the bus Memcheck:Leak ... fun:g_slist_append fun:dbus_g_connection_register_g_object } { DBusGProxy slots aren't freed unless we fall off the bus Memcheck:Leak ... fun:dbus_connection_allocate_data_slot ... fun:dbus_g_proxy_constructor } { error registrations are for life, not just for Christmas Memcheck:Leak ... fun:dbus_g_error_domain_register } { DBusGProxy class init Memcheck:Leak ... fun:dbus_g_proxy_class_init } # ============================= telepathy-glib ======================== { tp_dbus_daemon_constructor @daemons once per DBusConnection Memcheck:Leak ... fun:g_slice_alloc fun:tp_dbus_daemon_constructor } { tp_proxy_subclass_add_error_mapping refs the enum Memcheck:Leak ... fun:g_type_class_ref fun:tp_proxy_subclass_add_error_mapping } { tp_proxy_or_subclass_hook_on_interface_add never frees its list Memcheck:Leak ... fun:tp_proxy_or_subclass_hook_on_interface_add } { tp_dbus_daemon_constructor filter not freed til we fall off the bus Memcheck:Leak ... fun:dbus_connection_add_filter fun:tp_dbus_daemon_constructor } { tp_g_socket_address_from_variant reffing GNIO types Memcheck:Leak ... fun:g_type_class_ref ... fun:tp_g_socket_address_from_variant } { creating classes for DBusGProxy Memcheck:Leak ... fun:g_type_class_ref ... fun:g_object_new ... fun:tp_proxy_borrow_interface_by_id } { creating classes for tp_dbus_daemon_new Memcheck:Leak ... fun:g_type_class_ref ... fun:g_object_new ... fun:tp_dbus_daemon_new } { creating classes for TpCHannel Memcheck:Leak ... fun:g_type_class_ref ... fun:g_object_new ... fun:tp_channel_new } { creating a boxed type to use in TpCapabilities Memcheck:Leak ... fun:g_type_class_ref ... fun:g_param_spec_boxed fun:tp_capabilities_class_intern_init } # ============================= questionable ========================== { creating classes for instances (this is a pretty big hammer) Memcheck:Leak ... fun:g_type_class_ref ... fun:g_type_create_instance ... fun:g_param_spec_string } telepathy-qt-0.9.6~git1/tools/check-misc.sh0000664000175000017500000000036012470405660016451 0ustar jrjr#!/bin/sh fail=0 ( . "${tools_dir}"/check-whitespace.sh ) || fail=$? if egrep '(Free\s*Software\s*Foundation.*02139|02111-1307)' "$@" then echo "^^^ The above files contain the FSF's old address in GPL headers" fail=1 fi exit $fail telepathy-qt-0.9.6~git1/tools/glib-gtypes-generator.py0000664000175000017500000003013312470405660020674 0ustar jrjr#!/usr/bin/python # Generate GLib GInterfaces from the Telepathy specification. # The master copy of this program is in the telepathy-glib repository - # please make any changes there. # # Copyright (C) 2006, 2007 Collabora Limited # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA import sys import xml.dom.minidom from libglibcodegen import escape_as_identifier, \ get_docstring, \ NS_TP, \ Signature, \ type_to_gtype, \ xml_escape def types_to_gtypes(types): return [type_to_gtype(t)[1] for t in types] class GTypesGenerator(object): def __init__(self, dom, output, mixed_case_prefix): self.dom = dom self.Prefix = mixed_case_prefix self.PREFIX_ = self.Prefix.upper() + '_' self.prefix_ = self.Prefix.lower() + '_' self.header = open(output + '.h', 'w') self.body = open(output + '-body.h', 'w') for f in (self.header, self.body): f.write('/* Auto-generated, do not edit.\n *\n' ' * This file may be distributed under the same terms\n' ' * as the specification from which it was generated.\n' ' */\n\n') # keys are e.g. 'sv', values are the key escaped self.need_mappings = {} # keys are the contents of the struct (e.g. 'sssu'), values are the # key escaped self.need_structs = {} # keys are the contents of the struct (e.g. 'sssu'), values are the # key escaped self.need_struct_arrays = {} # keys are the contents of the array (unlike need_struct_arrays!), # values are the key escaped self.need_other_arrays = {} def h(self, code): self.header.write(code.encode("utf-8")) def c(self, code): self.body.write(code.encode("utf-8")) def do_mapping_header(self, mapping): members = mapping.getElementsByTagNameNS(NS_TP, 'member') assert len(members) == 2 impl_sig = ''.join([elt.getAttribute('type') for elt in members]) esc_impl_sig = escape_as_identifier(impl_sig) name = (self.PREFIX_ + 'HASH_TYPE_' + mapping.getAttribute('name').upper()) impl = self.prefix_ + 'type_dbus_hash_' + esc_impl_sig docstring = get_docstring(mapping) or '(Undocumented)' self.h('/**\n * %s:\n *\n' % name) self.h(' * %s\n' % xml_escape(docstring)) self.h(' *\n') self.h(' * This macro expands to a call to a function\n') self.h(' * that returns the #GType of a #GHashTable\n') self.h(' * appropriate for representing a D-Bus\n') self.h(' * dictionary of signature\n') self.h(' * a{%s}.\n' % impl_sig) self.h(' *\n') key, value = members self.h(' * Keys (D-Bus type %s,\n' % key.getAttribute('type')) tp_type = key.getAttributeNS(NS_TP, 'type') if tp_type: self.h(' * type %s,\n' % tp_type) self.h(' * named %s):\n' % key.getAttribute('name')) docstring = get_docstring(key) or '(Undocumented)' self.h(' * %s\n' % xml_escape(docstring)) self.h(' *\n') self.h(' * Values (D-Bus type %s,\n' % value.getAttribute('type')) tp_type = value.getAttributeNS(NS_TP, 'type') if tp_type: self.h(' * type %s,\n' % tp_type) self.h(' * named %s):\n' % value.getAttribute('name')) docstring = get_docstring(value) or '(Undocumented)' self.h(' * %s\n' % xml_escape(docstring)) self.h(' *\n') self.h(' */\n') self.h('#define %s (%s ())\n\n' % (name, impl)) self.need_mappings[impl_sig] = esc_impl_sig array_name = mapping.getAttribute('array-name') if array_name: gtype_name = self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper() contents_sig = 'a{' + impl_sig + '}' esc_contents_sig = escape_as_identifier(contents_sig) impl = self.prefix_ + 'type_dbus_array_of_' + esc_contents_sig self.h('/**\n * %s:\n\n' % gtype_name) self.h(' * Expands to a call to a function\n') self.h(' * that returns the #GType of a #GPtrArray\n') self.h(' * of #%s.\n' % name) self.h(' */\n') self.h('#define %s (%s ())\n\n' % (gtype_name, impl)) self.need_other_arrays[contents_sig] = esc_contents_sig def do_struct_header(self, struct): members = struct.getElementsByTagNameNS(NS_TP, 'member') impl_sig = ''.join([elt.getAttribute('type') for elt in members]) esc_impl_sig = escape_as_identifier(impl_sig) name = (self.PREFIX_ + 'STRUCT_TYPE_' + struct.getAttribute('name').upper()) impl = self.prefix_ + 'type_dbus_struct_' + esc_impl_sig docstring = struct.getElementsByTagNameNS(NS_TP, 'docstring') if docstring: docstring = docstring[0].toprettyxml() if docstring.startswith(''): docstring = docstring[14:] if docstring.endswith('\n'): docstring = docstring[:-16] if docstring.strip() in ('', ''): docstring = '(Undocumented)' else: docstring = '(Undocumented)' self.h('/**\n * %s:\n\n' % name) self.h(' * %s\n' % xml_escape(docstring)) self.h(' *\n') self.h(' * This macro expands to a call to a function\n') self.h(' * that returns the #GType of a #GValueArray\n') self.h(' * appropriate for representing a D-Bus struct\n') self.h(' * with signature (%s).\n' % impl_sig) self.h(' *\n') for i, member in enumerate(members): self.h(' * Member %d (D-Bus type ' '%s,\n' % (i, member.getAttribute('type'))) tp_type = member.getAttributeNS(NS_TP, 'type') if tp_type: self.h(' * type %s,\n' % tp_type) self.h(' * named %s):\n' % member.getAttribute('name')) docstring = get_docstring(member) or '(Undocumented)' self.h(' * %s\n' % xml_escape(docstring)) self.h(' *\n') self.h(' */\n') self.h('#define %s (%s ())\n\n' % (name, impl)) array_name = struct.getAttribute('array-name') if array_name != '': array_name = (self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper()) impl = self.prefix_ + 'type_dbus_array_' + esc_impl_sig self.h('/**\n * %s:\n\n' % array_name) self.h(' * Expands to a call to a function\n') self.h(' * that returns the #GType of a #GPtrArray\n') self.h(' * of #%s.\n' % name) self.h(' */\n') self.h('#define %s (%s ())\n\n' % (array_name, impl)) self.need_struct_arrays[impl_sig] = esc_impl_sig self.need_structs[impl_sig] = esc_impl_sig def __call__(self): mappings = self.dom.getElementsByTagNameNS(NS_TP, 'mapping') structs = self.dom.getElementsByTagNameNS(NS_TP, 'struct') for mapping in mappings: self.do_mapping_header(mapping) for sig in self.need_mappings: self.h('GType %stype_dbus_hash_%s (void);\n\n' % (self.prefix_, self.need_mappings[sig])) self.c('GType\n%stype_dbus_hash_%s (void)\n{\n' % (self.prefix_, self.need_mappings[sig])) self.c(' static GType t = 0;\n\n') self.c(' if (G_UNLIKELY (t == 0))\n') # FIXME: translate sig into two GTypes items = tuple(Signature(sig)) gtypes = types_to_gtypes(items) self.c(' t = dbus_g_type_get_map ("GHashTable", ' '%s, %s);\n' % (gtypes[0], gtypes[1])) self.c(' return t;\n') self.c('}\n\n') for struct in structs: self.do_struct_header(struct) for sig in self.need_structs: self.h('GType %stype_dbus_struct_%s (void);\n\n' % (self.prefix_, self.need_structs[sig])) self.c('GType\n%stype_dbus_struct_%s (void)\n{\n' % (self.prefix_, self.need_structs[sig])) self.c(' static GType t = 0;\n\n') self.c(' if (G_UNLIKELY (t == 0))\n') self.c(' t = dbus_g_type_get_struct ("GValueArray",\n') items = tuple(Signature(sig)) gtypes = types_to_gtypes(items) for gtype in gtypes: self.c(' %s,\n' % gtype) self.c(' G_TYPE_INVALID);\n') self.c(' return t;\n') self.c('}\n\n') for sig in self.need_struct_arrays: self.h('GType %stype_dbus_array_%s (void);\n\n' % (self.prefix_, self.need_struct_arrays[sig])) self.c('GType\n%stype_dbus_array_%s (void)\n{\n' % (self.prefix_, self.need_struct_arrays[sig])) self.c(' static GType t = 0;\n\n') self.c(' if (G_UNLIKELY (t == 0))\n') self.c(' t = dbus_g_type_get_collection ("GPtrArray", ' '%stype_dbus_struct_%s ());\n' % (self.prefix_, self.need_struct_arrays[sig])) self.c(' return t;\n') self.c('}\n\n') for sig in self.need_other_arrays: self.h('GType %stype_dbus_array_of_%s (void);\n\n' % (self.prefix_, self.need_other_arrays[sig])) self.c('GType\n%stype_dbus_array_of_%s (void)\n{\n' % (self.prefix_, self.need_other_arrays[sig])) self.c(' static GType t = 0;\n\n') self.c(' if (G_UNLIKELY (t == 0))\n') if sig[:2] == 'a{' and sig[-1:] == '}': # array of mappings self.c(' t = dbus_g_type_get_collection (' '"GPtrArray", ' '%stype_dbus_hash_%s ());\n' % (self.prefix_, escape_as_identifier(sig[2:-1]))) elif sig[:2] == 'a(' and sig[-1:] == ')': # array of arrays of struct self.c(' t = dbus_g_type_get_collection (' '"GPtrArray", ' '%stype_dbus_array_%s ());\n' % (self.prefix_, escape_as_identifier(sig[2:-1]))) elif sig[:1] == 'a': # array of arrays of non-struct self.c(' t = dbus_g_type_get_collection (' '"GPtrArray", ' '%stype_dbus_array_of_%s ());\n' % (self.prefix_, escape_as_identifier(sig[1:]))) else: raise AssertionError("array of '%s' not supported" % sig) self.c(' return t;\n') self.c('}\n\n') if __name__ == '__main__': argv = sys.argv[1:] dom = xml.dom.minidom.parse(argv[0]) GTypesGenerator(dom, argv[1], argv[2])() telepathy-qt-0.9.6~git1/tools/repeat-tests.sh0000775000175000017500000000070412470405660017070 0ustar jrjr#!/bin/sh if [ $# -ne 2 ] then echo "usage: $0 " echo "example: $0 \"make check-valgrind\" 100" echo " or: $0 \"make -j4 check\" 100" exit 1 fi for i in `seq 1 $2` do echo -n "Running test iteration ${i}... " log="test-round-${i}.log" $1 > ${log} 2>&1 if grep -q "FAIL" $log then echo "FAILED (log in $log)" else echo "PASSED" rm ${log} fi done telepathy-qt-0.9.6~git1/tools/check-whitespace.sh0000664000175000017500000000032312470405660017651 0ustar jrjr#!/bin/sh fail=0 if grep -n ' $' "$@" then echo "^^^ The above files contain unwanted trailing spaces" fail=1 fi if grep -n ' ' "$@" then echo "^^^ The above files contain tabs" fail=1 fi exit $fail telepathy-qt-0.9.6~git1/tools/libglibcodegen.py0000664000175000017500000001456312470405660017424 0ustar jrjr"""Library code for GLib/D-Bus-related code generation. The master copy of this library is in the telepathy-glib repository - please make any changes there. """ # Copyright (C) 2006-2008 Collabora Limited # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA from libtpcodegen import NS_TP, \ Signature, \ cmp_by_name, \ escape_as_identifier, \ get_by_path, \ get_descendant_text, \ get_docstring, \ xml_escape, \ get_deprecated def dbus_gutils_wincaps_to_uscore(s): """Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore which gets sequences of capital letters wrong in the same way. (e.g. in Telepathy, SendDTMF -> send_dt_mf) """ ret = '' for c in s: if c >= 'A' and c <= 'Z': length = len(ret) if length > 0 and (length < 2 or ret[length-2] != '_'): ret += '_' ret += c.lower() else: ret += c return ret def signal_to_marshal_type(signal): """ return a list of strings indicating the marshalling type for this signal. """ mtype=[] for i in signal.getElementsByTagName("arg"): name =i.getAttribute("name") type = i.getAttribute("type") mtype.append(type_to_gtype(type)[2]) return mtype _glib_marshallers = ['VOID', 'BOOLEAN', 'CHAR', 'UCHAR', 'INT', 'STRING', 'UINT', 'LONG', 'ULONG', 'ENUM', 'FLAGS', 'FLOAT', 'DOUBLE', 'STRING', 'PARAM', 'BOXED', 'POINTER', 'OBJECT', 'UINT_POINTER'] def signal_to_marshal_name(signal, prefix): mtype = signal_to_marshal_type(signal) if len(mtype): name = '_'.join(mtype) else: name = 'VOID' if name in _glib_marshallers: return 'g_cclosure_marshal_VOID__' + name else: return prefix + '_marshal_VOID__' + name def method_to_glue_marshal_name(method, prefix): mtype = [] for i in method.getElementsByTagName("arg"): if i.getAttribute("direction") != "out": type = i.getAttribute("type") mtype.append(type_to_gtype(type)[2]) mtype.append('POINTER') name = '_'.join(mtype) if name in _glib_marshallers: return 'g_cclosure_marshal_VOID__' + name else: return prefix + '_marshal_VOID__' + name def type_to_gtype(s): if s == 'y': #byte return ("guchar ", "G_TYPE_UCHAR","UCHAR", False) elif s == 'b': #boolean return ("gboolean ", "G_TYPE_BOOLEAN","BOOLEAN", False) elif s == 'n': #int16 return ("gint ", "G_TYPE_INT","INT", False) elif s == 'q': #uint16 return ("guint ", "G_TYPE_UINT","UINT", False) elif s == 'i': #int32 return ("gint ", "G_TYPE_INT","INT", False) elif s == 'u': #uint32 return ("guint ", "G_TYPE_UINT","UINT", False) elif s == 'x': #int64 return ("gint64 ", "G_TYPE_INT64","INT64", False) elif s == 't': #uint64 return ("guint64 ", "G_TYPE_UINT64","UINT64", False) elif s == 'd': #double return ("gdouble ", "G_TYPE_DOUBLE","DOUBLE", False) elif s == 's': #string return ("gchar *", "G_TYPE_STRING", "STRING", True) elif s == 'g': #signature - FIXME return ("gchar *", "DBUS_TYPE_G_SIGNATURE", "STRING", True) elif s == 'o': #object path return ("gchar *", "DBUS_TYPE_G_OBJECT_PATH", "BOXED", True) elif s == 'v': #variant return ("GValue *", "G_TYPE_VALUE", "BOXED", True) elif s == 'as': #array of strings return ("gchar **", "G_TYPE_STRV", "BOXED", True) elif s == 'ay': #byte array return ("GArray *", "dbus_g_type_get_collection (\"GArray\", G_TYPE_UCHAR)", "BOXED", True) elif s == 'au': #uint array return ("GArray *", "DBUS_TYPE_G_UINT_ARRAY", "BOXED", True) elif s == 'ai': #int array return ("GArray *", "DBUS_TYPE_G_INT_ARRAY", "BOXED", True) elif s == 'ax': #int64 array return ("GArray *", "DBUS_TYPE_G_INT64_ARRAY", "BOXED", True) elif s == 'at': #uint64 array return ("GArray *", "DBUS_TYPE_G_UINT64_ARRAY", "BOXED", True) elif s == 'ad': #double array return ("GArray *", "DBUS_TYPE_G_DOUBLE_ARRAY", "BOXED", True) elif s == 'ab': #boolean array return ("GArray *", "DBUS_TYPE_G_BOOLEAN_ARRAY", "BOXED", True) elif s == 'ao': #object path array return ("GPtrArray *", 'dbus_g_type_get_collection ("GPtrArray",' ' DBUS_TYPE_G_OBJECT_PATH)', "BOXED", True) elif s == 'a{ss}': #hash table of string to string return ("GHashTable *", "DBUS_TYPE_G_STRING_STRING_HASHTABLE", "BOXED", False) elif s[:2] == 'a{': #some arbitrary hash tables if s[2] not in ('y', 'b', 'n', 'q', 'i', 'u', 's', 'o', 'g'): raise Exception, "can't index a hashtable off non-basic type " + s first = type_to_gtype(s[2]) second = type_to_gtype(s[3:-1]) return ("GHashTable *", "(dbus_g_type_get_map (\"GHashTable\", " + first[1] + ", " + second[1] + "))", "BOXED", False) elif s[:2] in ('a(', 'aa'): # array of structs or arrays, recurse gtype = type_to_gtype(s[1:])[1] return ("GPtrArray *", "(dbus_g_type_get_collection (\"GPtrArray\", "+gtype+"))", "BOXED", True) elif s[:1] == '(': #struct gtype = "(dbus_g_type_get_struct (\"GValueArray\", " for subsig in Signature(s[1:-1]): gtype = gtype + type_to_gtype(subsig)[1] + ", " gtype = gtype + "G_TYPE_INVALID))" return ("GValueArray *", gtype, "BOXED", True) # we just don't know .. raise Exception, "don't know the GType for " + s telepathy-qt-0.9.6~git1/tools/CMakeLists.txt0000664000175000017500000001127112470405660016652 0ustar jrjr# Some useful commands add_custom_command(OUTPUT FIXME.out COMMAND egrep ARGS -A 5 '[F]IXME|[T]ODO|[X]XX' ${CMAKE_SOURCE_DIR}/TelepathyQt/*.[ch]* ${CMAKE_SOURCE_DIR}/TelepathyQt/*.[ch]* > FIXME.out || true) add_custom_target(check-local DEPENDS FIXME.out) execute_process(COMMAND ${SH} tools/git-which-branch.sh misc | tr -d '\n' | tr -C "[:alnum:]" _ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_BRANCH_CURRENT) if (GIT_BRANCH_CURRENT) string(LENGTH ${GIT_BRANCH_CURRENT} HAVE_GIT_BRANCH) if (HAVE_GIT_BRANCH) string(REPLACE "\n" "" GIT_BRANCH_CURRENT ${GIT_BRANCH_CURRENT}) set(UPLOAD_BRANCH_TO people.freedesktop.org:public_html/telepathy-qt) add_custom_target(upload-branch-docs rsync -rtzvPp --chmod=a+rX doc/html/ ${UPLOAD_BRANCH_TO}-${GIT_BRANCH_CURRENT} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_dependencies(upload-branch-docs doxygen-doc) endif (HAVE_GIT_BRANCH) endif (GIT_BRANCH_CURRENT) if (PERL_FOUND) add_custom_target(maintainer-fix-qt-links-in-docs ${PERL_EXECUTABLE} doc/html/installdox -l qt.tags@http://doc.qt.nokia.com/latest/ doc/html/*.html WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_dependencies(maintainer-fix-qt-links-in-docs doxygen-doc _maintainer-upload-release-check) endif (PERL_FOUND) add_custom_target(maintainer-upload-release-docs rsync -rtOvzPp --chmod=Dg+s,ug+rwX,o=rX doc/html/ telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/doc/telepathy-qt/ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) if (PERL_FOUND) add_dependencies(maintainer-upload-release-docs maintainer-fix-qt-links-in-docs) else (PERL_FOUND) add_dependencies(maintainer-upload-release-docs doxygen-doc _maintainer-upload-release-check) endif (PERL_FOUND) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/maintainer-upload-release-check.sh " #!/bin/sh case ${PACKAGE_VERSION} in (*.*.*.*) echo \"${PACKAGE_VERSION} is not a release\" >&2; exit 2; ;; esac test -f ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz if ! test -f ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc; then gpg --detach-sign -a ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz; fi; gpg --verify ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc ") add_custom_target(_maintainer-upload-release-check ${SH} ${CMAKE_CURRENT_BINARY_DIR}/maintainer-upload-release-check.sh) add_custom_target(maintainer-upload-release rsync -vzP ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/${PACKAGE_NAME}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz COMMAND rsync -vzP ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/${PACKAGE_NAME}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz.asc WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_dependencies(maintainer-upload-release _maintainer-upload-release-check maintainer-upload-release-docs) set(toolchain_files c-constants-gen.py check-misc.sh check-whitespace.sh git-which-branch.sh glib-ginterface-gen.py glib-gtypes-generator.py glib-interfaces-gen.py glib-signals-marshal-gen.py libtpcodegen.py libglibcodegen.py libqtcodegen.py qt-client-gen.py qt-constants-gen.py qt-types-gen.py manager-file.py with-session-bus.sh xincludator.py ) string(REPLACE "." " " sh_toolchain_files ${toolchain_files}) set(TELEPATHY_SPEC_SRCDIR ${CMAKE_SOURCE_DIR}/../telepathy-spec) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-spec.sh " #!/bin/sh set -e cd ${CMAKE_SOURCE_DIR} for x in ${sh_toolchain_files}; do if test -f ${TELEPATHY_SPEC_SRCDIR}/tools/$$x; then cp ${TELEPATHY_SPEC_SRCDIR}/tools/$$x $$x; fi; done ") add_custom_target(maintainer-update-from-telepathy-spec ${SH} ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-spec.sh WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) set(TELEPATHY_GLIB_SRCDIR ${CMAKE_SOURCE_DIR}/../telepathy-glib) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-glib.sh " #!/bin/sh set -e cd ${CMAKE_SOURCE_DIR} for x in ${sh_toolchain_files}; do if test -f ${TELEPATHY_GLIB_SRCDIR}/tools/$$x; then cp ${TELEPATHY_GLIB_SRCDIR}/tools/$$x $$x; fi; done ") add_custom_target(maintainer-update-from-telepathy-glib ${SH} ${CMAKE_CURRENT_BINARY_DIR}/maintainer-update-from-telepathy-glib.sh WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) telepathy-qt-0.9.6~git1/tools/manager-file.py0000664000175000017500000001361612470405660017020 0ustar jrjr#!/usr/bin/python # manager-file.py: generate .manager files and TpCMParamSpec arrays from the # same data (should be suitable for all connection managers that don't have # plugins) # # The master copy of this program is in the telepathy-glib repository - # please make any changes there. # # Copyright (c) Collabora Ltd. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA import re import sys import os _NOT_C_STR = re.compile(r'[^A-Za-z0-9_-]') def c_string(x): # whitelist-based brute force and ignorance - escape nearly all punctuation return '"' + _NOT_C_STR.sub(lambda c: r'\x%02x' % ord(c), x) + '"' def desktop_string(x): return x.replace(' ', r'\s').replace('\n', r'\n').replace('\r', r'\r').replace('\t', r'\t') supported = list('sbuiqn') fdefaultencoders = { 's': desktop_string, 'b': (lambda b: b and '1' or '0'), 'u': (lambda n: '%u' % n), 'i': (lambda n: '%d' % n), 'q': (lambda n: '%u' % n), 'n': (lambda n: '%d' % n), } for x in supported: assert x in fdefaultencoders gtypes = { 's': 'G_TYPE_STRING', 'b': 'G_TYPE_BOOLEAN', 'u': 'G_TYPE_UINT', 'i': 'G_TYPE_INT', 'q': 'G_TYPE_UINT', 'n': 'G_TYPE_INT', } for x in supported: assert x in gtypes gdefaultencoders = { 's': c_string, 'b': (lambda b: b and 'GINT_TO_POINTER (TRUE)' or 'GINT_TO_POINTER (FALSE)'), 'u': (lambda n: 'GUINT_TO_POINTER (%u)' % n), 'i': (lambda n: 'GINT_TO_POINTER (%d)' % n), 'q': (lambda n: 'GUINT_TO_POINTER (%u)' % n), 'n': (lambda n: 'GINT_TO_POINTER (%d)' % n), } for x in supported: assert x in gdefaultencoders gdefaultdefaults = { 's': 'NULL', 'b': 'GINT_TO_POINTER (FALSE)', 'u': 'GUINT_TO_POINTER (0)', 'i': 'GINT_TO_POINTER (0)', 'q': 'GUINT_TO_POINTER (0)', 'n': 'GINT_TO_POINTER (0)', } for x in supported: assert x in gdefaultdefaults gflags = { 'has-default': 'TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT', 'register': 'TP_CONN_MGR_PARAM_FLAG_REGISTER', 'required': 'TP_CONN_MGR_PARAM_FLAG_REQUIRED', 'secret': 'TP_CONN_MGR_PARAM_FLAG_SECRET', 'dbus-property': 'TP_CONN_MGR_PARAM_FLAG_DBUS_PROPERTY', } def write_manager(f, manager, protos): # pointless backwards compat section print >> f, '[ConnectionManager]' print >> f, 'BusName=org.freedesktop.Telepathy.ConnectionManager.' + manager print >> f, 'ObjectPath=/org/freedesktop/Telepathy/ConnectionManager/' + manager # protocols for proto, params in protos.iteritems(): print >> f print >> f, '[Protocol %s]' % proto defaults = {} for param, info in params.iteritems(): dtype = info['dtype'] flags = info.get('flags', '').split() struct_field = info.get('struct_field', param.replace('-', '_')) filter = info.get('filter', 'NULL') filter_data = info.get('filter_data', 'NULL') setter_data = 'NULL' if 'default' in info: default = fdefaultencoders[dtype](info['default']) defaults[param] = default if flags: flags = ' ' + ' '.join(flags) else: flags = '' print >> f, 'param-%s=%s%s' % (param, desktop_string(dtype), flags) for param, default in defaults.iteritems(): print >> f, 'default-%s=%s' % (param, default) def write_c_params(f, manager, proto, struct, params): print >> f, "static const TpCMParamSpec %s_%s_params[] = {" % (manager, proto) for param, info in params.iteritems(): dtype = info['dtype'] flags = info.get('flags', '').split() struct_field = info.get('struct_field', param.replace('-', '_')) filter = info.get('filter', 'NULL') filter_data = info.get('filter_data', 'NULL') setter_data = 'NULL' if 'default' in info: default = gdefaultencoders[dtype](info['default']) else: default = gdefaultdefaults[dtype] if flags: flags = ' | '.join([gflags[flag] for flag in flags]) else: flags = '0' if struct is None or struct_field is None: struct_offset = '0' else: struct_offset = 'G_STRUCT_OFFSET (%s, %s)' % (struct, struct_field) print >> f, (''' { %s, %s, %s, %s, %s, /* default */ %s, /* struct offset */ %s, /* filter */ %s, /* filter data */ %s /* setter data */ },''' % (c_string(param), c_string(dtype), gtypes[dtype], flags, default, struct_offset, filter, filter_data, setter_data)) print >> f, " { NULL }" print >> f, "};" if __name__ == '__main__': environment = {} execfile(sys.argv[1], environment) f = open('%s/%s.manager' % (sys.argv[2], environment['MANAGER']), 'w') write_manager(f, environment['MANAGER'], environment['PARAMS']) f.close() f = open('%s/param-spec-struct.h' % sys.argv[2], 'w') for protocol in environment['PARAMS']: write_c_params(f, environment['MANAGER'], protocol, environment['STRUCTS'][protocol], environment['PARAMS'][protocol]) f.close() telepathy-qt-0.9.6~git1/tools/qt-types-gen.py0000664000175000017500000004120312470405660017017 0ustar jrjr#!/usr/bin/python # # Copyright (C) 2008 Collabora Limited # Copyright (C) 2008 Nokia Corporation # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA import sys import xml.dom.minidom from getopt import gnu_getopt from libtpcodegen import NS_TP, get_descendant_text, get_by_path from libqtcodegen import binding_from_usage, binding_from_decl, extract_arg_or_member_info, format_docstring, gather_externals, gather_custom_lists, get_qt_name, get_headerfile_cmd, RefRegistry class BrokenSpecException(Exception): pass class MissingTypes(BrokenSpecException): def __init__(self, types): super(MissingTypes, self).__init__(self) self.types = types def __str__(self): typelist = ''.join([' %s' % t for t in self.types]) return "The following types were used, but not provided by the spec " \ "or by declarations in all.xml:\n%s" % typelist class UnresolvedDependency(BrokenSpecException): def __init__(self, child, parent): super(UnresolvedDependency, self).__init__(self) self.child = child self.parent = parent def __str__(self): return 'Type %s has unresolved dependency on %s' % ( self.child, self.parent) class EmptyStruct(BrokenSpecException): def __init__(self, struct_name): super(EmptyStruct, self).__init__(self) self.struct_name = struct_name def __str__(self): return 'tp:struct %s should have some members' % self.struct_name class MalformedMapping(BrokenSpecException): def __init__(self, mapping_name, members): super(MalformedMapping, self).__init__(self) self.mapping_name = mapping_name self.members = members def __str__(self): return 'tp:mapping %s should have 2 members, not %u' % ( self.mapping_name, self.members) class WTF(BrokenSpecException): def __init__(self, element_name): super(BrokenSpecException, self).__init__(self) self.element_name = element_name def __str__(self): return 'What the hell is a tp:%s?' % self.element_name class DepInfo: def __init__(self, el, externals, custom_lists): self.el = el name = get_by_path(el, '@name') array_name = get_by_path(el, '@array-name') array_depth = get_by_path(el, '@array-depth') if array_depth: array_depth = int(array_depth) else: array_depth = None self.binding = binding_from_decl(name, array_name, array_depth) self.deps = [] for member in get_by_path(el, 'member'): sig = member.getAttribute('type') tptype = member.getAttributeNS(NS_TP, 'type') if (sig, tptype) in externals: continue if tptype.endswith('[]'): tptype = tptype[:-2] binding = binding_from_usage(sig, tptype, custom_lists) if binding.custom_type: self.deps.append(binding.val) self.revdeps = [] class Generator(object): def __init__(self, opts): try: self.namespace = opts['--namespace'] self.declfile = opts['--declfile'] self.implfile = opts['--implfile'] self.realinclude = opts['--realinclude'] self.prettyinclude = opts.get('--prettyinclude', self.realinclude) self.extraincludes = opts.get('--extraincludes', None) self.must_define = opts.get('--must-define', None) self.visibility = opts.get('--visibility', '') dom = xml.dom.minidom.parse(opts['--specxml']) except KeyError, k: assert False, 'Missing required parameter %s' % k.args[0] self.decls = [] self.impls = [] self.spec = get_by_path(dom, "spec")[0] self.externals = gather_externals(self.spec) self.custom_lists = gather_custom_lists(self.spec, self.namespace) self.required_custom = [] self.required_arrays = [] self.to_declare = [] self.depinfos = {} self.refs = RefRegistry(self.spec) def __call__(self): # Emit comment header self.both('/* Generated from ') self.both(get_descendant_text(get_by_path(self.spec, 'title'))) version = get_by_path(self.spec, "version") if version: self.both(', version ' + get_descendant_text(version)) self.both(' */\n') # Gather info on available and required types self.gather_required() if self.must_define: self.decl('\n') self.decl('#ifndef %s\n' % self.must_define) self.decl('#error %s\n' % self.must_define) self.decl('#endif') self.decl('\n') if self.extraincludes: for include in self.extraincludes.split(','): self.decl('#include %s\n' % include) self.decl(""" #include #include #include #include #include #include #include #include #include #include #include #include /** * \\addtogroup typesconstants Types and constants * * Enumerated, flag, structure, list and mapping types and utility constants. */ /** * \\defgroup struct Structure types * \\ingroup typesconstants * * Structure types generated from the specification. */ /** * \\defgroup list List types * \\ingroup typesconstants * * List types generated from the specification. */ /** * \\defgroup mapping Mapping types * \\ingroup typesconstants * * Mapping types generated from the specification. */ """) if self.must_define: self.impl(""" #define %s""" % self.must_define) self.impl(""" #include "%s" """ % self.realinclude) self.both(""" namespace %s { """ % self.namespace) # Emit type definitions for types provided in the spec self.provide_all() # Emit type registration function self.decl(""" } // namespace %s """ % self.namespace) self.impl("""\ TP_QT_NO_EXPORT void _registerTypes() { static bool registered = false; if (registered) return; registered = true; """) # Emit Qt metatype declarations self.to_declare.sort() for metatype in self.to_declare: self.decl('Q_DECLARE_METATYPE(%s)\n' % metatype) self.impl(' qDBusRegisterMetaType<%s>();\n' % ((metatype.endswith('>') and metatype + ' ') or metatype)) self.impl("""\ } } // namespace %s """ % self.namespace) # Write output to files open(self.declfile, 'w').write(''.join(self.decls).encode("utf-8")) open(self.implfile, 'w').write(''.join(self.impls).encode("utf-8")) def decl(self, str): self.decls.append(str) def impl(self, str): self.impls.append(str) def both(self, str): self.decl(str) self.impl(str) def gather_required(self): members = self.spec.getElementsByTagNameNS(NS_TP, 'member') args = self.spec.getElementsByTagName('arg') props = self.spec.getElementsByTagName('property') tp_props = self.spec.getElementsByTagNameNS(NS_TP, 'property') for requirer in members + args + props + tp_props: sig = requirer.getAttribute('type') tptype = requirer.getAttributeNS(NS_TP, 'type') external = (sig, tptype) in self.externals binding = binding_from_usage(sig, tptype, self.custom_lists, external) if binding.custom_type and binding.val not in self.required_custom: self.required_custom.append(binding.val) if not binding.custom_type and binding.array_of and (binding.val, binding.array_of) not in self.required_arrays: self.required_arrays.append((binding.val, binding.array_of)) def provide_all(self): self.required_arrays.sort() for (val, array_of) in self.required_arrays: real = 'QList<%s>' % array_of self.decl("""\ /** * \\struct %s * \\ingroup list %s\ * * Generic list type with %s elements. Convertible with * %s, but needed to have a discrete type in the Qt type system. */ """ % (val, get_headerfile_cmd(self.realinclude, self.prettyinclude), array_of, real)) self.decl(self.faketype(val, real)) self.to_declare.append(self.namespace + '::' + val) structs = self.spec.getElementsByTagNameNS(NS_TP, 'struct') mappings = self.spec.getElementsByTagNameNS(NS_TP, 'mapping') exts = self.spec.getElementsByTagNameNS(NS_TP, 'external-type') for deptype in structs + mappings: info = DepInfo(deptype, self.externals, self.custom_lists) self.depinfos[info.binding.val] = info leaves = [] next_leaves = [] for val, depinfo in self.depinfos.iteritems(): leaf = True for dep in depinfo.deps: if not self.depinfos.has_key(dep): raise UnresolvedDependency(val, dep) leaf = False self.depinfos[dep].revdeps.append(val) if leaf: next_leaves.append(val) while leaves or next_leaves: if not leaves: leaves = next_leaves leaves.sort() next_leaves = [] val = leaves.pop(0) depinfo = self.depinfos[val] self.output_by_depinfo(depinfo) for revdep in depinfo.revdeps: revdepinfo = self.depinfos[revdep] revdepinfo.deps.remove(val) if not revdepinfo.deps: next_leaves.append(revdep) del self.depinfos[val] for provider in structs + mappings + exts: name = get_by_path(provider, '@name') array_name = get_by_path(provider, '@array-name') array_depth = get_by_path(provider, '@array-depth') if array_depth: array_depth = int(array_depth) else: array_depth = None sig = provider.getAttribute('type') tptype = provider.getAttribute('name') external = (sig, tptype) in self.externals binding = binding_from_decl(name, array_name, array_depth, external) self.provide(binding.val) if binding.array_val: self.provide(binding.array_val) d = binding.array_depth while d > 1: d -= 1 self.provide(binding.array_val + ('List' * d)) if self.required_custom: raise MissingTypes(self.required_custom) def provide(self, type): if type in self.required_custom: self.required_custom.remove(type) def output_by_depinfo(self, depinfo): names, docstrings, bindings = extract_arg_or_member_info(get_by_path(depinfo.el, 'member'), self.custom_lists, self.externals, None, self.refs, ' * ', (' /**', ' */')) members = len(names) if depinfo.el.localName == 'struct': if members == 0: raise EmptyStruct(depinfo.binding.val) self.decl("""\ /** * \\struct %(name)s * \\ingroup struct %(headercmd)s\ * * Structure type generated from the specification. %(docstring)s\ */ struct %(visibility)s %(name)s { """ % { 'name' : depinfo.binding.val, 'headercmd': get_headerfile_cmd(self.realinclude, self.prettyinclude), 'docstring' : format_docstring(depinfo.el, self.refs), 'visibility': self.visibility, }) for i in xrange(members): self.decl("""\ %s\ %s %s; """ % (docstrings[i], bindings[i].val, names[i])) self.decl("""\ }; """) self.both('%s bool operator==(%s v1, %s v2)' % (self.visibility, depinfo.binding.inarg, depinfo.binding.inarg)) self.decl(';\n') self.impl(""" {""") if (bindings[0].val != 'QDBusVariant'): self.impl(""" return ((v1.%s == v2.%s)""" % (names[0], names[0])) else: self.impl(""" return ((v1.%s.variant() == v2.%s.variant())""" % (names[0], names[0])) for i in xrange(1, members): if (bindings[i].val != 'QDBusVariant'): self.impl(""" && (v1.%s == v2.%s)""" % (names[i], names[i])) else: self.impl(""" && (v1.%s.variant() == v2.%s.variant())""" % (names[i], names[i])) self.impl(""" ); } """) self.decl('inline bool operator!=(%s v1, %s v2)' % (depinfo.binding.inarg, depinfo.binding.inarg)) self.decl(""" { return !operator==(v1, v2); } """) self.both('%s QDBusArgument& operator<<(QDBusArgument& arg, %s val)' % (self.visibility, depinfo.binding.inarg)) self.decl(';\n') self.impl(""" { arg.beginStructure(); arg << %s; arg.endStructure(); return arg; } """ % ' << '.join(['val.' + name for name in names])) self.both('%s const QDBusArgument& operator>>(const QDBusArgument& arg, %s val)' % (self.visibility, depinfo.binding.outarg)) self.decl(';\n\n') self.impl(""" { arg.beginStructure(); arg >> %s; arg.endStructure(); return arg; } """ % ' >> '.join(['val.' + name for name in names])) elif depinfo.el.localName == 'mapping': if members != 2: raise MalformedMapping(depinfo.binding.val, members) realtype = 'QMap<%s, %s>' % (bindings[0].val, (bindings[1].val.endswith('>') and bindings[1].val + ' ') or bindings[1].val) self.decl("""\ /** * \\struct %s * \\ingroup mapping %s\ * * Mapping type generated from the specification. Convertible with * %s, but needed to have a discrete type in the Qt type system. %s\ */ """ % (depinfo.binding.val, get_headerfile_cmd(self.realinclude, self.prettyinclude), realtype, format_docstring(depinfo.el, self.refs))) self.decl(self.faketype(depinfo.binding.val, realtype)) else: raise WTF(depinfo.el.localName) self.to_declare.append(self.namespace + '::' + depinfo.binding.val) if depinfo.binding.array_val: self.to_declare.append('%s::%s' % (self.namespace, depinfo.binding.array_val)) self.decl("""\ /** * \\ingroup list %s\ * * Array of %s values. */ typedef %s %s; """ % (get_headerfile_cmd(self.realinclude, self.prettyinclude), depinfo.binding.val, 'QList<%s>' % depinfo.binding.val, depinfo.binding.array_val)) i = depinfo.binding.array_depth while i > 1: i -= 1 self.to_declare.append('%s::%s%s' % (self.namespace, depinfo.binding.array_val, ('List' * i))) list_of = depinfo.binding.array_val + ('List' * (i-1)) self.decl("""\ /** * \\ingroup list %s\ * * Array of %s values. */ typedef QList<%s> %sList; """ % (get_headerfile_cmd(self.realinclude, self.prettyinclude), list_of, list_of, list_of)) def faketype(self, fake, real): return """\ struct %(visibility)s %(fake)s : public %(real)s { inline %(fake)s() : %(real)s() {} inline %(fake)s(const %(real)s& a) : %(real)s(a) {} inline %(fake)s& operator=(const %(real)s& a) { *(static_cast<%(real)s*>(this)) = a; return *this; } }; """ % {'fake' : fake, 'real' : real, 'visibility': self.visibility} if __name__ == '__main__': options, argv = gnu_getopt(sys.argv[1:], '', ['declfile=', 'implfile=', 'realinclude=', 'prettyinclude=', 'extraincludes=', 'must-define=', 'namespace=', 'specxml=', 'visibility=', ]) try: Generator(dict(options))() except BrokenSpecException as e: print >> sys.stderr, 'Your spec is broken, dear developer! %s' % e sys.exit(42) telepathy-qt-0.9.6~git1/tools/qt-constants-gen.py0000664000175000017500000002121112470405660017664 0ustar jrjr#!/usr/bin/python # # Copyright (C) 2008 Collabora Limited # Copyright (C) 2008 Nokia Corporation # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA from sys import argv, stdout, stderr import codecs import xml.dom.minidom from getopt import gnu_getopt from libtpcodegen import NS_TP, get_descendant_text, get_by_path from libqtcodegen import format_docstring, RefRegistry class Generator(object): def __init__(self, opts): try: self.namespace = opts['--namespace'] self.must_define = opts.get('--must-define', None) dom = xml.dom.minidom.parse(opts['--specxml']) except KeyError, k: assert False, 'Missing required parameter %s' % k.args[0] self.define_prefix = None if '--define-prefix' in opts: self.define_prefix = opts['--define-prefix'] self.old_prefix = None if '--str-constant-prefix' in opts: self.old_prefix = opts['--str-constant-prefix'] self.spec = get_by_path(dom, "spec")[0] self.out = codecs.getwriter('utf-8')(stdout) self.refs = RefRegistry(self.spec) def h(self, code): self.out.write(code) def __call__(self): # Header self.h('/* Generated from ') self.h(get_descendant_text(get_by_path(self.spec, 'title'))) version = get_by_path(self.spec, "version") if version: self.h(', version ' + get_descendant_text(version)) self.h(""" */ """) if self.must_define: self.h(""" #ifndef %s #error %s #endif """ % (self.must_define, self.must_define)) self.h(""" #include /** * \\addtogroup typesconstants Types and constants * * Enumerated, flag, structure, list and mapping types and utility constants. */ /** * \\defgroup flagtypeconsts Flag type constants * \\ingroup typesconstants * * Types generated from the specification representing bit flag constants and * combinations of them (bitfields). */ /** * \\defgroup enumtypeconsts Enumerated type constants * \\ingroup typesconstants * * Types generated from the specification representing enumerated types ie. * types the values of which are mutually exclusive integral constants. */ /** * \\defgroup ifacestrconsts Interface string constants * \\ingroup typesconstants * * D-Bus interface names of the interfaces in the specification. */ /** * \\defgroup errorstrconsts Error string constants * \\ingroup typesconstants * * Names of the D-Bus errors in the specification. */ """) # Begin namespace self.h(""" namespace %s { """ % self.namespace) # Flags for flags in self.spec.getElementsByTagNameNS(NS_TP, 'flags'): self.do_flags(flags) # Enums for enum in self.spec.getElementsByTagNameNS(NS_TP, 'enum'): self.do_enum(enum) # End namespace self.h("""\ } """) # Interface names for iface in self.spec.getElementsByTagName('interface'): if self.old_prefix: self.h("""\ /** * \\ingroup ifacestrconsts * * The interface name "%(name)s". */ #define %(DEFINE)s "%(name)s" """ % {'name' : iface.getAttribute('name'), 'DEFINE' : self.old_prefix + 'INTERFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')}) if self.define_prefix: self.h("""\ /** * \\ingroup ifacestrconsts * * The interface name "%(name)s" as a QLatin1String, usable in QString requiring contexts even when * building with Q_NO_CAST_FROM_ASCII defined. */ #define %(DEFINE)s (QLatin1String("%(name)s")) """ % {'name' : iface.getAttribute('name'), 'DEFINE' : self.define_prefix + 'IFACE_' + get_by_path(iface, '../@name').upper().replace('/', '')}) # Error names for error in get_by_path(self.spec, 'errors/error'): name = error.getAttribute('name') fullname = get_by_path(error, '../@namespace') + '.' + name.replace(' ', '') if self.old_prefix: define = self.old_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper() self.h("""\ /** * \\ingroup errorstrconsts * * The error name "%(fullname)s". %(docstring)s\ */ #define %(DEFINE)s "%(fullname)s" """ % {'fullname' : fullname, 'docstring': format_docstring(error, self.refs), 'DEFINE' : define}) if self.define_prefix: define = self.define_prefix + 'ERROR_' + name.replace(' ', '_').replace('.', '_').upper() self.h("""\ /** * \\ingroup errorstrconsts * * The error name "%(fullname)s" as a QLatin1String, usable in QString requiring contexts even when * building with Q_NO_CAST_FROM_ASCII defined. %(docstring)s\ */ #define %(DEFINE)s QLatin1String("%(fullname)s") """ % {'fullname' : fullname, 'docstring': format_docstring(error, self.refs), 'DEFINE' : define}) def do_flags(self, flags): singular = flags.getAttribute('singular') or \ flags.getAttribute('value-prefix') using_name = False if not singular: using_name = True singular = flags.getAttribute('name') if singular.endswith('lags'): singular = singular[:-1] if using_name and singular.endswith('s'): singular = singular[:-1] singular = singular.replace('_', '') plural = (flags.getAttribute('plural') or flags.getAttribute('name') or singular + 's').replace('_', '') self.h("""\ /** * \\ingroup flagtypeconsts * * Flag type generated from the specification. */ enum %(singular)s { """ % {'singular' : singular}) flagvalues = get_by_path(flags, 'flag') for flag in flagvalues: self.do_val(flag, singular, flag == flagvalues[-1]) self.h("""\ %s = 0xffffffffU """ % ("_" + singular + "Padding")) self.h("""\ }; /** * \\typedef QFlags<%(singular)s> %(plural)s * \\ingroup flagtypeconsts * * Type representing combinations of #%(singular)s values. %(docstring)s\ */ typedef QFlags<%(singular)s> %(plural)s; Q_DECLARE_OPERATORS_FOR_FLAGS(%(plural)s) """ % {'singular' : singular, 'plural' : plural, 'docstring' : format_docstring(flags, self.refs)}) def do_enum(self, enum): singular = enum.getAttribute('singular') or \ enum.getAttribute('name') value_prefix = enum.getAttribute('singular') or \ enum.getAttribute('value-prefix') or \ enum.getAttribute('name') if singular.endswith('lags'): singular = singular[:-1] plural = enum.getAttribute('plural') or singular + 's' singular = singular.replace('_', '') value_prefix = value_prefix.replace('_', '') vals = get_by_path(enum, 'enumvalue') self.h("""\ /** * \\enum %(singular)s * \\ingroup enumtypeconsts * * Enumerated type generated from the specification. %(docstring)s\ */ enum %(singular)s { """ % {'singular' : singular, 'docstring' : format_docstring(enum, self.refs)}) for val in vals: self.do_val(val, value_prefix, val == vals[-1]) self.h("""\ %s = 0xffffffffU }; """ % ("_" + singular + "Padding")) self.h("""\ /** * \\ingroup enumtypeconsts * * 1 higher than the highest valid value of %(singular)s. */ const int NUM_%(upper-plural)s = (%(last-val)s+1); """ % {'singular' : singular, 'upper-plural' : plural.upper(), 'last-val' : vals[-1].getAttribute('value')}) def do_val(self, val, prefix, last): name = (val.getAttribute('suffix') or val.getAttribute('name')).replace('_', '') self.h("""\ %s\ %s = %s, """ % (format_docstring(val, self.refs, indent=' * ', brackets=(' /**', ' */')), prefix + name, val.getAttribute('value'))) if __name__ == '__main__': options, argv = gnu_getopt(argv[1:], '', ['namespace=', 'str-constant-prefix=', 'define-prefix=', 'must-define=', 'specxml=']) Generator(dict(options))() telepathy-qt-0.9.6~git1/tools/tp-qt-tests.supp0000664000175000017500000000266312470405660017235 0ustar jrjr# QDBus doesn't call dbus_shutdown, so some D-Bus internal data structures are leaked. # We never call any low-level dbus message creation functions ourselves - if there are leaks, # they're either caused by not calling dbus_shutdown, QDBus bugs or libdbus bugs - neither of which # are our problem. { Initial session bus registration message Memcheck:Leak fun:malloc fun:dbus_message_new_empty_header } # The conference test CM channel object leaks some crazy GValue boxed data which I don't have the # energy to investigate how to properly free now - it's not production code anyway. { Conference test CM channel boxed GValue data Memcheck:Leak ... fun:g_boxed_copy ... fun:_ZN18TestConferenceChan12initTestCaseEv } # Reported as https://bugs.freedesktop.org/show_bug.cgi?id=32116 { TpBaseConnectionManager legacy protocol objects Memcheck:Leak ... fun:g_object_new ... fun:tp_base_connection_manager_register } # O(number of error domains) leak from dbus_g_method_return_error { dbus_g_method_return_error error domain enum class Memcheck:Leak ... fun:g_type_class_ref ... fun:dbus_g_method_return_error } # O(1) leak from tp_base_connection_manager installing the param spec for the dbus-daemon param { tp_base_connection_manager dbus-daemon param spec Memcheck:Leak ... fun:g_param_spec_object fun:tp_base_connection_manager_class_intern_init } telepathy-qt-0.9.6~git1/tools/glib-interfaces-gen.py0000664000175000017500000000636612470405660020302 0ustar jrjr#!/usr/bin/python from sys import argv, stdout, stderr import xml.dom.minidom from libglibcodegen import NS_TP, get_docstring, \ get_descendant_text, get_by_path class Generator(object): def __init__(self, prefix, implfile, declfile, dom): self.prefix = prefix + '_' self.impls = open(implfile, 'w') self.decls = open(declfile, 'w') self.spec = get_by_path(dom, "spec")[0] def h(self, code): self.decls.write(code.encode('utf-8')) def c(self, code): self.impls.write(code.encode('utf-8')) def __call__(self): for f in self.h, self.c: self.do_header(f) self.do_body() # Header def do_header(self, f): f('/* Generated from: ') f(get_descendant_text(get_by_path(self.spec, 'title'))) version = get_by_path(self.spec, "version") if version: f(' version ' + get_descendant_text(version)) f('\n\n') for copyright in get_by_path(self.spec, 'copyright'): f(get_descendant_text(copyright)) f('\n') f('\n') f(get_descendant_text(get_by_path(self.spec, 'license'))) f(get_descendant_text(get_by_path(self.spec, 'docstring'))) f(""" */ """) # Body def do_body(self): for iface in self.spec.getElementsByTagName('interface'): self.do_iface(iface) def do_iface(self, iface): parent_name = get_by_path(iface, '../@name') self.h("""\ /** * %(IFACE_DEFINE)s: * * The interface name "%(name)s" */ #define %(IFACE_DEFINE)s \\ "%(name)s" """ % {'IFACE_DEFINE' : (self.prefix + 'IFACE_' + \ parent_name).upper().replace('/', ''), 'name' : iface.getAttribute('name')}) self.h(""" /** * %(IFACE_QUARK_DEFINE)s: * * Expands to a call to a function that returns a quark for the interface \ name "%(name)s" */ #define %(IFACE_QUARK_DEFINE)s \\ (%(iface_quark_func)s ()) GQuark %(iface_quark_func)s (void); """ % {'IFACE_QUARK_DEFINE' : (self.prefix + 'IFACE_QUARK_' + \ parent_name).upper().replace('/', ''), 'iface_quark_func' : (self.prefix + 'iface_quark_' + \ parent_name).lower().replace('/', ''), 'name' : iface.getAttribute('name')}) self.c("""\ GQuark %(iface_quark_func)s (void) { static GQuark quark = 0; if (G_UNLIKELY (quark == 0)) { quark = g_quark_from_static_string ("%(name)s"); } return quark; } """ % {'iface_quark_func' : (self.prefix + 'iface_quark_' + \ parent_name).lower().replace('/', ''), 'name' : iface.getAttribute('name')}) for prop in iface.getElementsByTagNameNS(None, 'property'): self.decls.write(""" /** * %(IFACE_PREFIX)s_%(PROP_UC)s: * * The fully-qualified property name "%(name)s.%(prop)s" */ #define %(IFACE_PREFIX)s_%(PROP_UC)s \\ "%(name)s.%(prop)s" """ % {'IFACE_PREFIX' : (self.prefix + 'PROP_' + \ parent_name).upper().replace('/', ''), 'PROP_UC': prop.getAttributeNS(NS_TP, "name-for-bindings").upper(), 'name' : iface.getAttribute('name'), 'prop' : prop.getAttribute('name'), }) if __name__ == '__main__': argv = argv[1:] Generator(argv[0], argv[1], argv[2], xml.dom.minidom.parse(argv[3]))() telepathy-qt-0.9.6~git1/tools/c-constants-gen.py0000664000175000017500000001120012470405660017457 0ustar jrjr#!/usr/bin/python from sys import argv, stdout, stderr import xml.dom.minidom from libglibcodegen import NS_TP, get_docstring, \ get_descendant_text, get_by_path class Generator(object): def __init__(self, prefix, dom): self.prefix = prefix + '_' self.spec = get_by_path(dom, "spec")[0] def __call__(self): self.do_header() self.do_body() self.do_footer() def write(self, code): stdout.write(code.encode('utf-8')) # Header def do_header(self): self.write('/* Generated from ') self.write(get_descendant_text(get_by_path(self.spec, 'title'))) version = get_by_path(self.spec, "version") if version: self.write(', version ' + get_descendant_text(version)) self.write('\n\n') for copyright in get_by_path(self.spec, 'copyright'): self.write(get_descendant_text(copyright)) self.write('\n') self.write(get_descendant_text(get_by_path(self.spec, 'license'))) self.write('\n') self.write(get_descendant_text(get_by_path(self.spec, 'docstring'))) self.write(""" */ #ifdef __cplusplus extern "C" { #endif \n""") # Body def do_body(self): for elem in self.spec.getElementsByTagNameNS(NS_TP, '*'): if elem.localName == 'flags': self.do_flags(elem) elif elem.localName == 'enum': self.do_enum(elem) def do_flags(self, flags): name = flags.getAttribute('plural') or flags.getAttribute('name') value_prefix = flags.getAttribute('singular') or \ flags.getAttribute('value-prefix') or \ flags.getAttribute('name') self.write("""\ /** * %s: """ % (self.prefix + name).replace('_', '')) for flag in get_by_path(flags, 'flag'): self.do_gtkdoc(flag, value_prefix) self.write(' *\n') docstrings = get_by_path(flags, 'docstring') if docstrings: self.write("""\ * * """ % get_descendant_text(docstrings).replace('\n', ' ')) self.write("""\ * Bitfield/set of flags generated from the Telepathy specification. */ typedef enum { """) for flag in get_by_path(flags, 'flag'): self.do_val(flag, value_prefix) self.write("""\ } %s; """ % (self.prefix + name).replace('_', '')) def do_enum(self, enum): name = enum.getAttribute('singular') or enum.getAttribute('name') value_prefix = enum.getAttribute('singular') or \ enum.getAttribute('value-prefix') or \ enum.getAttribute('name') name_plural = enum.getAttribute('plural') or \ enum.getAttribute('name') + 's' self.write("""\ /** * %s: """ % (self.prefix + name).replace('_', '')) vals = get_by_path(enum, 'enumvalue') for val in vals: self.do_gtkdoc(val, value_prefix) self.write(' *\n') docstrings = get_by_path(enum, 'docstring') if docstrings: self.write("""\ * * """ % get_descendant_text(docstrings).replace('\n', ' ')) self.write("""\ * Bitfield/set of flags generated from the Telepathy specification. */ typedef enum { """) for val in vals: self.do_val(val, value_prefix) self.write("""\ } %(mixed-name)s; /** * NUM_%(upper-plural)s: * * 1 higher than the highest valid value of #%(mixed-name)s. */ #define NUM_%(upper-plural)s (%(last-val)s+1) """ % {'mixed-name' : (self.prefix + name).replace('_', ''), 'upper-plural' : (self.prefix + name_plural).upper(), 'last-val' : vals[-1].getAttribute('value')}) def do_val(self, val, value_prefix): name = val.getAttribute('name') suffix = val.getAttribute('suffix') use_name = (self.prefix + value_prefix + '_' + \ (suffix or name)).upper() assert not (name and suffix) or name == suffix, \ 'Flag/enumvalue name %s != suffix %s' % (name, suffix) self.write(' %s = %s,\n' % (use_name, val.getAttribute('value'))) def do_gtkdoc(self, node, value_prefix): self.write(' * @') self.write((self.prefix + value_prefix + '_' + node.getAttribute('suffix')).upper()) self.write(': \n') # Footer def do_footer(self): self.write(""" #ifdef __cplusplus } #endif """) if __name__ == '__main__': argv = argv[1:] Generator(argv[0], xml.dom.minidom.parse(argv[1]))() telepathy-qt-0.9.6~git1/tools/qt-svc-gen.py0000664000175000017500000005636612470405660016466 0ustar jrjr#!/usr/bin/python # # Copyright (C) 2012 Collabora Limited # Copyright (C) 2012 Nokia Corporation # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA from sys import argv import xml.dom.minidom import codecs from getopt import gnu_getopt from libtpcodegen import NS_TP, get_descendant_text, get_by_path from libqtcodegen import binding_from_usage, extract_arg_or_member_info, format_docstring, gather_externals, gather_custom_lists, get_headerfile_cmd, get_qt_name, qt_identifier_escape, RefRegistry # TODO generate docstrings def to_lower_camel_case(s): if len(s) <= 1: return s.lower() i = 0 for c in s: if c == '_': break i += 1 ret = s if i == len(s): return s.lower() else: ret = s[0:i].lower() + s[i:] ret = ret.replace('_', '') return ret class Generator(object): def __init__(self, opts): try: self.group = opts.get('--group', '') self.headerfile = opts['--headerfile'] self.implfile = opts['--implfile'] self.namespace = opts['--namespace'] self.typesnamespace = opts['--typesnamespace'] self.realinclude = opts.get('--realinclude', None) self.mocinclude = opts.get('--mocinclude', None) self.prettyinclude = opts.get('--prettyinclude') self.extraincludes = opts.get('--extraincludes', None) self.must_define = opts.get('--must-define', None) self.visibility = opts.get('--visibility', '') ifacedom = xml.dom.minidom.parse(opts['--ifacexml']) specdom = xml.dom.minidom.parse(opts['--specxml']) except KeyError, k: assert False, 'Missing required parameter %s' % k.args[0] if not self.realinclude: self.realinclude = self.headerfile self.hs = [] self.bs = [] self.ifacenodes = ifacedom.getElementsByTagName('node') self.spec, = get_by_path(specdom, "spec") self.custom_lists = gather_custom_lists(self.spec, self.typesnamespace) self.externals = gather_externals(self.spec) self.refs = RefRegistry(self.spec) def __call__(self): # Output info header and includes self.h("""\ /* * This file contains D-Bus adaptor classes generated by qt-svc-gen.py. * * This file can be distributed under the same terms as the specification from * which it was generated. */ """) if self.must_define: self.h('\n') self.h('#ifndef %s\n' % self.must_define) self.h('#error %s\n' % self.must_define) self.h('#endif\n') self.h('\n') if self.extraincludes: for include in self.extraincludes.split(','): self.h('#include %s\n' % include) self.h("""\ #include #include #include #include #include """) if self.must_define: self.b("""#define %s\n""" % (self.must_define)) self.b("""#include "%s" """ % self.realinclude) if self.mocinclude: self.b("""#include "%s" """ % self.mocinclude) self.b("""\ #include #include """) # Begin namespace for ns in self.namespace.split('::'): self.hb("""\ namespace %s { """ % ns) # Output interface proxies def ifacenodecmp(x, y): xname, yname = [self.namespace + '::' + node.getAttribute('name').replace('/', '').replace('_', '') + 'Adaptor' for node in x, y] return cmp(xname, yname) self.ifacenodes.sort(cmp=ifacenodecmp) for ifacenode in self.ifacenodes: self.do_ifacenode(ifacenode) # End namespace self.hb(''.join(['\n}' for ns in self.namespace.split('::')])) # Write output to files (codecs.getwriter('utf-8')(open(self.headerfile, 'w'))).write(''.join(self.hs)) (codecs.getwriter('utf-8')(open(self.implfile, 'w'))).write(''.join(self.bs)) def do_ifacenode(self, ifacenode): # Extract info name = ifacenode.getAttribute('name').replace('/', '').replace('_', '') + 'Adaptor' iface, = get_by_path(ifacenode, 'interface') dbusname = iface.getAttribute('name') props = get_by_path(iface, 'property') methods = get_by_path(iface, 'method') signals = get_by_path(iface, 'signal') # Begin class, constructors self.h(""" /** * \\class %(name)s %(headercmd)s\ %(groupcmd)s\ * * Adaptor class providing a 1:1 mapping of the D-Bus interface "%(dbusname)s". */ class %(visibility)s %(name)s : public Tp::AbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "%(dbusname)s") Q_CLASSINFO("D-Bus Introspection", "" " \\n" """ % {'name': name, 'headercmd': get_headerfile_cmd(self.realinclude, self.prettyinclude), 'groupcmd': self.group and (' * \\ingroup %s\n' % self.group), 'dbusname': dbusname, 'visibility': self.visibility, }) self.do_introspection(props, methods, signals) self.h("""\ " \\n" "") """) self.do_qprops(props) self.h(""" public: %(name)s(const QDBusConnection& dbusConnection, QObject* adaptee, QObject* parent); virtual ~%(name)s(); """ % {'name': name}) self.do_mic_typedefs(methods) self.b(""" %(name)s::%(name)s(const QDBusConnection& bus, QObject* adaptee, QObject* parent) : Tp::AbstractAdaptor(bus, adaptee, parent) { """ % {'name': name}) self.do_signals_connect(signals) self.b("""\ } %(name)s::~%(name)s() { } """ % {'name': name}) # Properties has_props = False if props: self.h(""" public: // PROPERTIES """) for prop in props: # Skip tp:properties if not prop.namespaceURI: self.do_prop(name, prop) has_props = True # Methods if methods: self.h(""" public Q_SLOTS: // METHODS """) for method in methods: self.do_method(name, method) # Signals if signals: self.h(""" Q_SIGNALS: // SIGNALS """) for signal in signals: self.do_signal(signal) # Close class self.h("""\ }; """) def do_introspection(self, props, methods, signals): self.do_prop_introspection(props) self.do_method_introspection(methods) self.do_signal_introspection(signals) def do_prop_introspection(self, props): for prop in props: if prop.namespaceURI: continue name = prop.getAttribute('name') access = prop.getAttribute('access') sig = prop.getAttribute('type') tptype = prop.getAttributeNS(NS_TP, 'type') binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace) if not binding.custom_type: self.h("""\ " \\n" """ % {'access': access, 'sig': sig, 'name': name, }) else: self.h("""\ " \\n" " \\n" " \\n" """ % {'access': access, 'sig': sig, 'name': name, 'type': binding.val, }) def do_method_introspection(self, methods): for method in methods: name = method.getAttribute('name') args = get_by_path(method, 'arg') argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') if not argnames: self.h("""\ " \\n" """ % {'name': name}) else: self.h("""\ " \\n" """ % {'name': name}) outindex = 0 inindex = 0 for i in xrange(len(argnames)): assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name) argbinding = argbindings[i] argname = argnames[i] argsig = args[i].getAttribute('type') argdirection = args[i].getAttribute('direction') # QtDBus requires annotating a{sv} if argsig == 'a{sv}': argbinding.custom_type = True if not argbinding.custom_type: self.h("""\ " \\n" """ % {'direction': argdirection, 'sig': argsig, 'name': argname}) else: self.h("""\ " \\n" " \\n" " \\n" """ % {'direction': argdirection, 'sig': argsig, 'name': argname, 'type': argbinding.val, 'index': 'In' + str(inindex) if argdirection == 'in' else 'Out' + str(outindex), }) if argdirection == 'out': outindex += 1 else: inindex += 1 self.h("""\ " \\n" """) def do_signal_introspection(self, signals): for signal in signals: name = signal.getAttribute('name') args = get_by_path(signal, 'arg') argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') if not argnames: self.h("""\ " \\n" """ % {'name': name}) else: self.h("""\ " \\n" """ % {'name': name}) for i in xrange(len(argnames)): assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name) argbinding = argbindings[i] argname = argnames[i] argsig = args[i].getAttribute('type') if not argbinding.custom_type: self.h("""\ " \\n" """ % {'sig': argsig, 'name': argname}) else: self.h("""\ " \\n" " \\n" " \\n" """ % {'sig': argsig, 'name': argname, 'type': argbinding.val, 'index': i, }) self.h("""\ " \\n" """) def do_mic_typedefs(self, methods): for method in methods: name = method.getAttribute('name') args = get_by_path(method, 'arg') argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') outargs = [] for i in xrange(len(args)): if args[i].getAttribute('direction') == 'out': outargs.append(i) if outargs: outargtypes = ', '.join([argbindings[i].val for i in outargs]) else: outargtypes = '' self.h("""\ typedef Tp::MethodInvocationContextPtr< %(outargtypes)s > %(name)sContextPtr; """ % {'name': name, 'outargtypes': outargtypes, }) def do_qprops(self, props): for prop in props: # Skip tp:properties if not prop.namespaceURI: self.do_qprop(prop) def do_qprop(self, prop): name = prop.getAttribute('name') access = prop.getAttribute('access') gettername = name settername = None if 'write' in access: settername = 'Set' + name sig = prop.getAttribute('type') tptype = prop.getAttributeNS(NS_TP, 'type') binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace) self.h("""\ Q_PROPERTY(%(type)s %(name)s %(getter)s %(setter)s) """ % {'type': binding.val, 'name': name, 'getter': 'READ ' + gettername if ('read' in access) else '', 'setter': 'WRITE ' + settername if ('write' in access) else '', }) def do_prop(self, ifacename, prop): name = prop.getAttribute('name') adaptee_name = to_lower_camel_case(prop.getAttribute('tp:name-for-bindings')) access = prop.getAttribute('access') gettername = name settername = None if 'write' in access: settername = 'Set' + name docstring = format_docstring(prop, self.refs, ' * ').replace('*/', '*/') sig = prop.getAttribute('type') tptype = prop.getAttributeNS(NS_TP, 'type') binding = binding_from_usage(sig, tptype, self.custom_lists, (sig, tptype) in self.externals, self.typesnamespace) if 'read' in access: self.h("""\ /** * Return the value of the exported D-Bus object property \\c %(name)s of type \\c %(type)s. * * Adaptees should export this property as a Qt property named * '%(adaptee_name)s' with type %(type)s. * %(docstring)s\ * * \\return The value of exported property \\c %(name)s. */ %(type)s %(gettername)s() const; """ % {'name': name, 'adaptee_name': adaptee_name, 'docstring': docstring, 'type': binding.val, 'gettername': gettername, }) self.b(""" %(type)s %(ifacename)s::%(gettername)s() const { return qvariant_cast< %(type)s >(adaptee()->property("%(adaptee_name)s")); } """ % {'type': binding.val, 'ifacename': ifacename, 'gettername': gettername, 'adaptee_name': adaptee_name, }) if 'write' in access: self.h("""\ /** * Set the value of the exported D-Bus object property \\c %(name)s of type \\c %(type)s. * * Adaptees should export this property as a writable Qt property named * '%(adaptee_name)s' with type %(type)s. * %(docstring)s\ */ void %(settername)s(const %(type)s &newValue); """ % {'name': name, 'adaptee_name': adaptee_name, 'docstring': docstring, 'settername': settername, 'type': binding.val, }) self.b(""" void %(ifacename)s::%(settername)s(const %(type)s &newValue) { adaptee()->setProperty("%(adaptee_name)s", qVariantFromValue(newValue)); } """ % {'ifacename': ifacename, 'settername': settername, 'type': binding.val, 'adaptee_name': adaptee_name, }) def do_method(self, ifacename, method): name = method.getAttribute('name') adaptee_name = to_lower_camel_case(method.getAttribute('tp:name-for-bindings')) args = get_by_path(method, 'arg') argnames, argdocstrings, argbindings = extract_arg_or_member_info(args, self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') docstring = format_docstring(method, self.refs, ' * ').replace('*/', '*/') inargs = [] outargs = [] for i in xrange(len(args)): if args[i].getAttribute('direction') == 'out': outargs.append(i) else: inargs.append(i) assert argnames[i] != None, 'No argument name for input argument at index %d for method %s' % (i, name) if outargs: rettype = argbindings[outargs[0]].val else: rettype = 'void' params = [argbindings[i].inarg + ' ' + argnames[i] for i in inargs] params.append('const QDBusMessage& dbusMessage') params += [argbindings[i].outarg + ' ' + argnames[i] for i in outargs[1:]] params = ', '.join(params) if outargs: outargtypes = ', '.join([argbindings[i].val for i in outargs]) else: outargtypes = '' invokemethodargs = ', '.join(['Q_ARG(' + argbindings[i].val + ', ' + argnames[i] + ')' for i in inargs]) inparams = [argbindings[i].val for i in inargs] inparams.append("%s::%s::%sContextPtr" % (self.namespace, ifacename, name)) normalized_adaptee_params = ','.join(inparams) adaptee_params = [argbindings[i].inarg + ' ' + argnames[i] for i in inargs] adaptee_params.append('const %(namespace)s::%(ifacename)s::%(name)sContextPtr &context' % {'namespace': self.namespace, 'ifacename': ifacename, 'name': name}) adaptee_params = ', '.join(adaptee_params) self.h("""\ /** * Begins a call to the exported D-Bus method \\c %(name)s on this object. * * Adaptees should export this method as a Qt slot with the following signature: * void %(adaptee_name)s(%(adaptee_params)s); * * Implementations should call MethodInvocationContext::setFinished (or setFinishedWithError * accordingly) on the received \\a context object once the method has finished processing. * %(docstring)s\ * """ % {'name': name, 'adaptee_name': adaptee_name, 'adaptee_params': adaptee_params, 'rettype': rettype, 'docstring': docstring }) for i in inargs: if argdocstrings[i]: self.h("""\ * \\param %s %s\ """ % (argnames[i], argdocstrings[i])) for i in outargs[1:]: if argdocstrings[i]: self.h("""\ * \\param %s Output parameter %s\ """ % (argnames[i], argdocstrings[i])) if outargs: self.h("""\ * \\return %s\ """ % argdocstrings[outargs[0]]) self.h("""\ */ %(rettype)s %(name)s(%(params)s); """ % {'rettype': rettype, 'name': name, 'params': params }) self.b(""" %(rettype)s %(ifacename)s::%(name)s(%(params)s) { if (!adaptee()->metaObject()->indexOfMethod("%(adaptee_name)s(%(normalized_adaptee_params)s)") == -1) { dbusConnection().send(dbusMessage.createErrorReply(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented"))); """ % {'rettype': rettype, 'ifacename': ifacename, 'name': name, 'adaptee_name': adaptee_name, 'normalized_adaptee_params': normalized_adaptee_params, 'params': params, }) if rettype != 'void': self.b("""\ return %(rettype)s(); """ % {'rettype': rettype}) else: self.b("""\ return; """) self.b("""\ } %(name)sContextPtr ctx = %(name)sContextPtr( new Tp::MethodInvocationContext< %(outargtypes)s >(dbusConnection(), dbusMessage)); """ % {'name': name, 'outargtypes': outargtypes, }) if invokemethodargs: self.b("""\ QMetaObject::invokeMethod(adaptee(), "%(adaptee_name)s", %(invokemethodargs)s, Q_ARG(%(namespace)s::%(ifacename)s::%(name)sContextPtr, ctx)); """ % {'namespace': self.namespace, 'ifacename': ifacename, 'name': name, 'adaptee_name': adaptee_name, 'invokemethodargs': invokemethodargs, }) else: self.b("""\ QMetaObject::invokeMethod(adaptee(), "%(lname)s", Q_ARG(%(namespace)s::%(ifacename)s::%(name)sContextPtr, ctx)); """ % {'namespace': self.namespace, 'ifacename': ifacename, 'name': name, 'lname': (name[0].lower() + name[1:]), }) if rettype != 'void': self.b("""\ return %(rettype)s(); """ % {'rettype': rettype}) self.b("}\n") def do_signal(self, signal): name = signal.getAttribute('name') adaptee_name = to_lower_camel_case(signal.getAttribute('tp:name-for-bindings')) argnames, argdocstrings, argbindings = extract_arg_or_member_info(get_by_path(signal, 'arg'), self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') params = ', '.join(['%s %s' % (binding.inarg, param_name) for binding, param_name in zip(argbindings, argnames)]) for i in xrange(len(argnames)): assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name) self.h("""\ /** * Represents the exported D-Bus signal \\c %(name)s on this object. * * Adaptees should export this signal as a Qt signal with the following signature: * void %(adaptee_name)s(%(params)s); * * The adaptee signal will be automatically relayed as a D-Bus signal once emitted. * """ % {'name': name, 'adaptee_name': adaptee_name, 'params': params }) for i in xrange(len(argnames)): assert argnames[i] != None, 'Name missing from argument at index %d for signal %s' % (i, name) if argdocstrings[i]: self.h("""\ * \\param %s %s\ """ % (argnames[i], argdocstrings[i])) self.h("""\ */ void %(name)s(%(params)s); """ % {'name': name, 'params': params }) def do_signals_connect(self, signals): for signal in signals: name = signal.getAttribute('name') adaptee_name = to_lower_camel_case(signal.getAttribute('tp:name-for-bindings')) _, _, argbindings = extract_arg_or_member_info(get_by_path(signal, 'arg'), self.custom_lists, self.externals, self.typesnamespace, self.refs, ' * ') self.b("""\ connect(adaptee, SIGNAL(%(adaptee_name)s(%(params)s)), SIGNAL(%(name)s(%(params)s))); """ % {'name': name, 'adaptee_name': adaptee_name, 'params': ', '.join([binding.inarg for binding in argbindings]) }) def h(self, str): self.hs.append(str) def b(self, str): self.bs.append(str) def hb(self, str): self.h(str) self.b(str) if __name__ == '__main__': options, argv = gnu_getopt(argv[1:], '', ['group=', 'headerfile=', 'implfile=', 'namespace=', 'typesnamespace=', 'realinclude=', 'mocinclude=', 'prettyinclude=', 'extraincludes=', 'must-define=', 'visibility=', 'ifacexml=', 'specxml=']) Generator(dict(options))() telepathy-qt-0.9.6~git1/tools/libtpcodegen.py0000664000175000017500000001472212470405660017127 0ustar jrjr"""Library code for language-independent D-Bus-related code generation. The master copy of this library is in the telepathy-glib repository - please make any changes there. """ # Copyright (C) 2006-2008 Collabora Limited # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA from string import ascii_letters, digits NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" _ASCII_ALNUM = ascii_letters + digits def cmp_by_name(node1, node2): return cmp(node1.getAttributeNode("name").nodeValue, node2.getAttributeNode("name").nodeValue) def escape_as_identifier(identifier): """Escape the given string to be a valid D-Bus object path or service name component, using a reversible encoding to ensure uniqueness. The reversible encoding is as follows: * The empty string becomes '_' * Otherwise, each non-alphanumeric character is replaced by '_' plus two lower-case hex digits; the same replacement is carried out on the first character, if it's a digit """ # '' -> '_' if not identifier: return '_' # A bit of a fast path for strings which are already OK. # We deliberately omit '_' because, for reversibility, that must also # be escaped. if (identifier.strip(_ASCII_ALNUM) == '' and identifier[0] in ascii_letters): return identifier # The first character may not be a digit if identifier[0] not in ascii_letters: ret = ['_%02x' % ord(identifier[0])] else: ret = [identifier[0]] # Subsequent characters may be digits or ASCII letters for c in identifier[1:]: if c in _ASCII_ALNUM: ret.append(c) else: ret.append('_%02x' % ord(c)) return ''.join(ret) def get_by_path(element, path): branches = path.split('/') branch = branches[0] # Is the current branch an attribute, if so, return the attribute value if branch[0] == '@': return element.getAttribute(branch[1:]) # Find matching children for the branch children = [] if branch == '..': children.append(element.parentNode) else: for x in element.childNodes: if x.localName == branch: children.append(x) ret = [] # If this is not the last path element, recursively gather results from # children if len(branches) > 1: for x in children: add = get_by_path(x, '/'.join(branches[1:])) if isinstance(add, list): ret += add else: return add else: ret = children return ret def get_docstring(element): docstring = None for x in element.childNodes: if x.namespaceURI == NS_TP and x.localName == 'docstring': docstring = x if docstring is not None: docstring = docstring.toxml().replace('\n', ' ').strip() if docstring.startswith(''): docstring = docstring[14:].lstrip() if docstring.endswith(''): docstring = docstring[:-15].rstrip() if docstring in ('', ''): docstring = '' return docstring def get_deprecated(element): text = [] for x in element.childNodes: if hasattr(x, 'data'): text.append(x.data.replace('\n', ' ').strip()) else: # This caters for tp:dbus-ref elements, but little else. if x.childNodes and hasattr(x.childNodes[0], 'data'): text.append(x.childNodes[0].data.replace('\n', ' ').strip()) return ' '.join(text) def get_descendant_text(element_or_elements): if not element_or_elements: return '' if isinstance(element_or_elements, list): return ''.join(map(get_descendant_text, element_or_elements)) parts = [] for x in element_or_elements.childNodes: if x.nodeType == x.TEXT_NODE: parts.append(x.nodeValue) elif x.nodeType == x.ELEMENT_NODE: parts.append(get_descendant_text(x)) else: pass return ''.join(parts) class _SignatureIter: """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we can run genginterface in a limited environment with only Python (like Scratchbox). """ def __init__(self, string): self.remaining = string def next(self): if self.remaining == '': raise StopIteration signature = self.remaining block_depth = 0 block_type = None end = len(signature) for marker in range(0, end): cur_sig = signature[marker] if cur_sig == 'a': pass elif cur_sig == '{' or cur_sig == '(': if block_type == None: block_type = cur_sig if block_type == cur_sig: block_depth = block_depth + 1 elif cur_sig == '}': if block_type == '{': block_depth = block_depth - 1 if block_depth == 0: end = marker break elif cur_sig == ')': if block_type == '(': block_depth = block_depth - 1 if block_depth == 0: end = marker break else: if block_depth == 0: end = marker break end = end + 1 self.remaining = signature[end:] return Signature(signature[0:end]) class Signature(str): """A string, iteration over which is by D-Bus single complete types rather than characters. """ def __iter__(self): return _SignatureIter(self) def xml_escape(s): s = s.replace('&', '&').replace("'", ''').replace('"', '"') return s.replace('<', '<').replace('>', '>') telepathy-qt-0.9.6~git1/tools/libqtcodegen.py0000664000175000017500000004126612470405660017133 0ustar jrjr"""Library code for Qt D-Bus-related code generation. The master copy of this library is in the telepathy-qt repository - please make any changes there. """ # Copyright (C) 2008 Collabora Limited # Copyright (C) 2008 Nokia Corporation # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA from sys import maxint, stderr import re from libtpcodegen import get_by_path, get_descendant_text, NS_TP, xml_escape class Xzibit(Exception): def __init__(self, parent, child): self.parent = parent self.child = child def __str__(self): print """ Nested <%s>s are forbidden. Parent: %s... Child: %s... """ % (self.parent.nodeName, self.parent.toxml()[:100], self.child.toxml()[:100]) class _QtTypeBinding: def __init__(self, val, inarg, outarg, array_val, custom_type, array_of, array_depth=None): self.val = val self.inarg = inarg self.outarg = outarg self.array_val = array_val self.custom_type = custom_type self.array_of = array_of self.array_depth = array_depth if array_depth is None: self.array_depth = int(bool(array_val)) elif array_depth >= 1: assert array_val else: assert not array_val class RefTarget(object): KIND_INTERFACE, KIND_METHOD, KIND_SIGNAL, KIND_PROPERTY = 'node', 'method', 'signal', 'property' def __init__(self, el): self.kind = el.localName assert self.kind in (self.KIND_INTERFACE, self.KIND_METHOD, self.KIND_SIGNAL, self.KIND_PROPERTY) if self.kind == self.KIND_INTERFACE: self.dbus_text = el.getAttribute('name').lstrip('/').replace('_', '') + 'Interface' else: self.member_text = el.getAttribute('name') assert el.parentNode.parentNode.localName == self.KIND_INTERFACE host_class = el.parentNode.parentNode.getAttribute('name').lstrip('/').replace('_', '') + 'Interface' if self.kind == self.KIND_PROPERTY: self.member_link = 'requestProperty%s()' % (self.member_text) self.dbus_link = '%s::%s' % (host_class, self.member_link) else: self.member_text = '%s()' % self.member_text self.dbus_text = '%s::%s' % (host_class, self.member_text) class RefRegistry(object): def __init__(self, spec): self.targets = {} for node in spec.getElementsByTagName('node'): iface, = get_by_path(node, 'interface') iface_name = iface.getAttribute('name') self.targets[iface_name] = RefTarget(node) for method in iface.getElementsByTagName(RefTarget.KIND_METHOD): self.targets[iface_name + '.' + method.getAttribute('name')] = RefTarget(method) for signal in iface.getElementsByTagName(RefTarget.KIND_SIGNAL): self.targets[iface_name + '.' + signal.getAttribute('name')] = RefTarget(signal) for prop in iface.getElementsByTagName(RefTarget.KIND_PROPERTY): self.targets[iface_name + '.' + prop.getAttribute('name')] = RefTarget(prop) def process(self, ref): assert ref.namespaceURI == NS_TP def get_closest_parent(el, needle): node = el while node is not None and node.localName != needle: node = node.parentNode return node local = get_descendant_text(ref).strip() if ref.localName == 'member-ref': ns = get_closest_parent(ref, 'interface').getAttribute('name') path = ns + '.' + local.strip() else: if ref.hasAttribute('namespace'): ns = ref.getAttribute('namespace').replace('ofdT', 'org.freedesktop.Telepathy') path = ns + '.' + local.strip() else: path = local target = self.targets.get(path) if target is None: parent = get_closest_parent(ref, 'interface') or get_closest_parent(ref, 'error') parent_name = parent.getAttribute('name') if (path + parent_name).find('.DRAFT') == -1 and (path + parent_name).find('.FUTURE') == -1: print >> stderr, 'WARNING: Failed to resolve %s to "%s" in "%s"' % ( ref.localName, path, parent_name) return path if ref.localName == 'member-ref': if target.kind == target.KIND_PROPERTY: return '\\link %s %s \\endlink' % (target.member_link, target.member_text) else: return target.member_text else: if target.kind == target.KIND_PROPERTY: return '\\link %s %s \\endlink' % (target.dbus_link, target.dbus_text) else: return target.dbus_text def binding_from_usage(sig, tptype, custom_lists, external=False, explicit_own_ns=None): # 'signature' : ('qt-type', 'pass-by-reference', 'array-type') natives = { 'y' : ('uchar', False, None), 'b' : ('bool', False, 'BoolList'), 'n' : ('short', False, 'ShortList'), 'q' : ('ushort', False, 'UShortList'), 'i' : ('int', False, 'IntList'), 'u' : ('uint', False, 'UIntList'), 'x' : ('qlonglong', False, 'LongLongList'), 't' : ('qulonglong', False, 'ULongLongList'), 'd' : ('double', False, 'DoubleList'), 's' : ('QString', True, None), 'v' : ('QDBusVariant', True, None), 'o' : ('QDBusObjectPath', True, 'ObjectPathList'), 'g' : ('QDBusSignature', True, 'SignatureList'), 'as' : ('QStringList', True, "StringListList"), 'ay' : ('QByteArray', True, "ByteArrayList"), 'av' : ('QVariantList', True, "VariantListList"), 'a{sv}' : ('QVariantMap', True, None) } val, inarg = None, None custom_type = False array_of = None if natives.has_key(sig): typename, pass_by_ref, array_name = natives[sig] val = typename inarg = (pass_by_ref and ('const %s&' % val)) or val elif sig[0] == 'a' and natives.has_key(sig[1:]) and natives[sig[1:]][2]: val = natives[sig[1:]][2] if explicit_own_ns: val = explicit_own_ns + '::' + val inarg = 'const %s&' % val array_of = natives[sig[1:]][0] elif tptype: tptype = tptype.replace('_', '') custom_type = True if external: tptype = 'Tp::' + tptype elif explicit_own_ns: tptype = explicit_own_ns + '::' + tptype if tptype.endswith('[]'): tptype = tptype[:-2] extra_list_nesting = 0 while tptype.endswith('[]'): extra_list_nesting += 1 tptype = tptype[:-2] assert custom_lists.has_key(tptype), ('No array version of custom type %s in the spec, but array version used' % tptype) val = custom_lists[tptype] + 'List' * extra_list_nesting else: val = tptype inarg = 'const %s&' % val else: assert False, 'Don\'t know how to map type (%s, %s)' % (sig, tptype) outarg = val + '&' return _QtTypeBinding(val, inarg, outarg, None, custom_type, array_of) def binding_from_decl(name, array_name, array_depth=None, external=False, explicit_own_ns=''): val = name.replace('_', '') if external: val = 'Tp::' + val elif explicit_own_ns: val = explicit_own_ns + '::' + val inarg = 'const %s&' % val outarg = '%s&' % val return _QtTypeBinding(val, inarg, outarg, array_name.replace('_', ''), True, None, array_depth) def extract_arg_or_member_info(els, custom_lists, externals, typesns, refs, docstring_indent=' * ', docstring_brackets=None, docstring_maxwidth=80): names = [] docstrings = [] bindings = [] for el in els: names.append(get_qt_name(el)) docstrings.append(format_docstring(el, refs, docstring_indent, docstring_brackets, docstring_maxwidth)) sig = el.getAttribute('type') tptype = el.getAttributeNS(NS_TP, 'type') bindings.append(binding_from_usage(sig, tptype, custom_lists, (sig, tptype) in externals, typesns)) return names, docstrings, bindings def format_docstring(el, refs, indent=' * ', brackets=None, maxwidth=80): docstring_el = None for x in el.childNodes: if x.namespaceURI == NS_TP and x.localName == 'docstring': docstring_el = x if not docstring_el: return '' lines = [] # escape backslashes, so they won't be interpreted starting doxygen commands and we can later # insert doxygen commands we actually want def escape_slashes(x): if x.nodeType == x.TEXT_NODE: x.data = x.data.replace('\\', '\\\\') elif x.nodeType == x.ELEMENT_NODE: for y in x.childNodes: escape_slashes(y) else: return escape_slashes(docstring_el) doc = docstring_el.ownerDocument for n in docstring_el.getElementsByTagNameNS(NS_TP, 'rationale'): nested = n.getElementsByTagNameNS(NS_TP, 'rationale') if nested: raise Xzibit(n, nested[0]) div = doc.createElement('div') div.setAttribute('class', 'rationale') for rationale_body in n.childNodes: div.appendChild(rationale_body.cloneNode(True)) n.parentNode.replaceChild(div, n) if docstring_el.getAttribute('xmlns') == 'http://www.w3.org/1999/xhtml': for ref in docstring_el.getElementsByTagNameNS(NS_TP, 'member-ref') + docstring_el.getElementsByTagNameNS(NS_TP, 'dbus-ref'): nested = ref.getElementsByTagNameNS(NS_TP, 'member-ref') + ref.getElementsByTagNameNS(NS_TP, 'dbus-ref') if nested: raise Xzibit(n, nested[0]) text = doc.createTextNode(' \\endhtmlonly ') text.data += refs.process(ref) text.data += ' \\htmlonly ' ref.parentNode.replaceChild(text, ref) splitted = ''.join([el.toxml() for el in docstring_el.childNodes]).strip(' ').strip('\n').split('\n') level = min([not match and maxint or match.end() - 1 for match in [re.match('^ *[^ ]', line) for line in splitted]]) assert level != maxint lines = ['\\htmlonly'] + [line[level:] for line in splitted] + ['\\endhtmlonly'] else: content = xml_escape(get_descendant_text(docstring_el).replace('\n', ' ').strip()) while content.find(' ') != -1: content = content.replace(' ', ' ') left = maxwidth - len(indent) - 1 line = '' while content: step = (content.find(' ') + 1) or len(content) if step > left: lines.append(line) line = '' left = maxwidth - len(indent) - 1 left = left - step line = line + content[:step] content = content[step:] if line: lines.append(line) output = [] if lines: if brackets: output.append(brackets[0]) else: output.append(indent) output.append('\n') for line in lines: output.append(indent) output.append(line) output.append('\n') if lines and brackets: output.append(brackets[1]) output.append('\n') return ''.join(output) def gather_externals(spec): externals = [] for ext in spec.getElementsByTagNameNS(NS_TP, 'external-type'): sig = ext.getAttribute('type') tptype = ext.getAttribute('name') externals.append((sig, tptype)) return externals def gather_custom_lists(spec, typesns): custom_lists = {} structs = [(provider, typesns) for provider in spec.getElementsByTagNameNS(NS_TP, 'struct')] mappings = [(provider, typesns) for provider in spec.getElementsByTagNameNS(NS_TP, 'mapping')] exts = [(provider, 'Telepathy') for provider in spec.getElementsByTagNameNS(NS_TP, 'external-type')] for (provider, ns) in structs + mappings + exts: tptype = provider.getAttribute('name').replace('_', '') array_val = provider.getAttribute('array-name').replace('_', '') array_depth = provider.getAttribute('array-depth') if array_depth: array_depth = int(array_depth) else: array_depth = None if array_val: custom_lists[tptype] = array_val custom_lists[ns + '::' + tptype] = ns + '::' + array_val if array_depth >= 2: for i in xrange(array_depth): custom_lists[tptype + ('[]' * (i+1))] = ( array_val + ('List' * i)) custom_lists[ns + '::' + tptype + ('[]' * (i+1))] = ( ns + '::' + array_val + ('List' * i)) return custom_lists def get_headerfile_cmd(realinclude, prettyinclude, indent=' * '): prettyinclude = prettyinclude or realinclude if realinclude: if prettyinclude: return indent + ('\\headerfile %s <%s>\n' % (realinclude, prettyinclude)) else: return indent + ('\\headerfile %s <%s>\n' % (realinclude)) else: return '' def get_qt_name(el): name = el.getAttribute('name') if el.localName in ('method', 'signal', 'property'): bname = el.getAttributeNS(NS_TP, 'name-for-bindings') if bname: name = bname if not name: return None if name[0].isupper() and name[1].islower(): name = name[0].lower() + name[1:] return qt_identifier_escape(name.replace('_', '')) def qt_identifier_escape(str): built = (str[0].isdigit() and ['_']) or [] for c in str: if c.isalnum(): built.append(c) else: built.append('_') str = ''.join(built) # List of reserved identifiers # Initial list from http://cs.smu.ca/~porter/csc/ref/cpp_keywords.html # Keywords inherited from C90 reserved = ['auto', 'const', 'double', 'float', 'int', 'short', 'struct', 'unsigned', 'break', 'continue', 'else', 'for', 'long', 'signed', 'switch', 'void', 'case', 'default', 'enum', 'goto', 'register', 'sizeof', 'typedef', 'volatile', 'char', 'do', 'extern', 'if', 'return', 'static', 'union', 'while', # C++-only keywords 'asm', 'dynamic_cast', 'namespace', 'reinterpret_cast', 'try', 'bool', 'explicit', 'new', 'static_cast', 'typeid', 'catch', 'false', 'operator', 'template', 'typename', 'class', 'friend', 'private', 'this', 'using', 'const_cast', 'inline', 'public', 'throw', 'virtual', 'delete', 'mutable', 'protected', 'true', 'wchar_t', # Operator replacements 'and', 'bitand', 'compl', 'not_eq', 'or_eq', 'xor_eq', 'and_eq', 'bitor', 'not', 'or', 'xor', # Predefined identifiers 'INT_MIN', 'INT_MAX', 'MAX_RAND', 'NULL', # Qt 'SIGNAL', 'SLOT', 'signals', 'slots'] while str in reserved: str = str + '_' return str telepathy-qt-0.9.6~git1/tools/glib-signals-marshal-gen.py0000664000175000017500000000254112470405660021233 0ustar jrjr#!/usr/bin/python import sys import xml.dom.minidom from string import ascii_letters, digits from libglibcodegen import signal_to_marshal_name, method_to_glue_marshal_name class Generator(object): def __init__(self, dom): self.dom = dom self.marshallers = {} def do_method(self, method): marshaller = method_to_glue_marshal_name(method, 'PREFIX') assert '__' in marshaller rhs = marshaller.split('__', 1)[1].split('_') self.marshallers[marshaller] = rhs def do_signal(self, signal): marshaller = signal_to_marshal_name(signal, 'PREFIX') assert '__' in marshaller rhs = marshaller.split('__', 1)[1].split('_') self.marshallers[marshaller] = rhs def __call__(self): methods = self.dom.getElementsByTagName('method') for method in methods: self.do_method(method) signals = self.dom.getElementsByTagName('signal') for signal in signals: self.do_signal(signal) all = self.marshallers.keys() all.sort() for marshaller in all: rhs = self.marshallers[marshaller] if not marshaller.startswith('g_cclosure'): print 'VOID:' + ','.join(rhs) if __name__ == '__main__': argv = sys.argv[1:] dom = xml.dom.minidom.parse(argv[0]) Generator(dom)() telepathy-qt-0.9.6~git1/tools/glib-ginterface-gen.py0000664000175000017500000007250112470405660020260 0ustar jrjr#!/usr/bin/python # glib-ginterface-gen.py: service-side interface generator # # Generate dbus-glib 0.x service GInterfaces from the Telepathy specification. # The master copy of this program is in the telepathy-glib repository - # please make any changes there. # # Copyright (C) 2006, 2007 Collabora Limited # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA import sys import os.path import xml.dom.minidom from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \ NS_TP, dbus_gutils_wincaps_to_uscore, \ signal_to_marshal_name, method_to_glue_marshal_name NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" class Generator(object): def __init__(self, dom, prefix, basename, signal_marshal_prefix, headers, end_headers, not_implemented_func, allow_havoc): self.dom = dom self.__header = [] self.__body = [] assert prefix.endswith('_') assert not signal_marshal_prefix.endswith('_') # The main_prefix, sub_prefix thing is to get: # FOO_ -> (FOO_, _) # FOO_SVC_ -> (FOO_, _SVC_) # but # FOO_BAR/ -> (FOO_BAR_, _) # FOO_BAR/SVC_ -> (FOO_BAR_, _SVC_) if '/' in prefix: main_prefix, sub_prefix = prefix.upper().split('/', 1) prefix = prefix.replace('/', '_') else: main_prefix, sub_prefix = prefix.upper().split('_', 1) self.MAIN_PREFIX_ = main_prefix + '_' self._SUB_PREFIX_ = '_' + sub_prefix self.Prefix_ = prefix self.Prefix = prefix.replace('_', '') self.prefix_ = prefix.lower() self.PREFIX_ = prefix.upper() self.basename = basename self.signal_marshal_prefix = signal_marshal_prefix self.headers = headers self.end_headers = end_headers self.not_implemented_func = not_implemented_func self.allow_havoc = allow_havoc def h(self, s): self.__header.append(s) def b(self, s): self.__body.append(s) def do_node(self, node): node_name = node.getAttribute('name').replace('/', '') node_name_mixed = self.node_name_mixed = node_name.replace('_', '') node_name_lc = self.node_name_lc = node_name.lower() node_name_uc = self.node_name_uc = node_name.upper() interfaces = node.getElementsByTagName('interface') assert len(interfaces) == 1, interfaces interface = interfaces[0] self.iface_name = interface.getAttribute('name') tmp = interface.getAttribute('tp:implement-service') if tmp == "no": return tmp = interface.getAttribute('tp:causes-havoc') if tmp and not self.allow_havoc: raise AssertionError('%s is %s' % (self.iface_name, tmp)) self.b('static const DBusGObjectInfo _%s%s_object_info;' % (self.prefix_, node_name_lc)) self.b('') methods = interface.getElementsByTagName('method') signals = interface.getElementsByTagName('signal') properties = interface.getElementsByTagName('property') # Don't put properties in dbus-glib glue glue_properties = [] self.b('struct _%s%sClass {' % (self.Prefix, node_name_mixed)) self.b(' GTypeInterface parent_class;') for method in methods: self.b(' %s %s;' % self.get_method_impl_names(method)) self.b('};') self.b('') if signals: self.b('enum {') for signal in signals: self.b(' %s,' % self.get_signal_const_entry(signal)) self.b(' N_%s_SIGNALS' % node_name_uc) self.b('};') self.b('static guint %s_signals[N_%s_SIGNALS] = {0};' % (node_name_lc, node_name_uc)) self.b('') self.b('static void %s%s_base_init (gpointer klass);' % (self.prefix_, node_name_lc)) self.b('') self.b('GType') self.b('%s%s_get_type (void)' % (self.prefix_, node_name_lc)) self.b('{') self.b(' static GType type = 0;') self.b('') self.b(' if (G_UNLIKELY (type == 0))') self.b(' {') self.b(' static const GTypeInfo info = {') self.b(' sizeof (%s%sClass),' % (self.Prefix, node_name_mixed)) self.b(' %s%s_base_init, /* base_init */' % (self.prefix_, node_name_lc)) self.b(' NULL, /* base_finalize */') self.b(' NULL, /* class_init */') self.b(' NULL, /* class_finalize */') self.b(' NULL, /* class_data */') self.b(' 0,') self.b(' 0, /* n_preallocs */') self.b(' NULL /* instance_init */') self.b(' };') self.b('') self.b(' type = g_type_register_static (G_TYPE_INTERFACE,') self.b(' "%s%s", &info, 0);' % (self.Prefix, node_name_mixed)) self.b(' }') self.b('') self.b(' return type;') self.b('}') self.b('') self.h('/**') self.h(' * %s%s:' % (self.Prefix, node_name_mixed)) self.h(' *') self.h(' * Dummy typedef representing any implementation of this ' 'interface.') self.h(' */') self.h('typedef struct _%s%s %s%s;' % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed)) self.h('') self.h('/**') self.h(' * %s%sClass:' % (self.Prefix, node_name_mixed)) self.h(' *') self.h(' * The class of %s%s.' % (self.Prefix, node_name_mixed)) if methods: self.h(' *') self.h(' * In a full implementation of this interface (i.e. all') self.h(' * methods implemented), the interface initialization') self.h(' * function used in G_IMPLEMENT_INTERFACE() would') self.h(' * typically look like this:') self.h(' *') self.h(' * ') self.h(' * static void') self.h(' * implement_%s (gpointer klass,' % self.node_name_lc) self.h(' * gpointer unused G_GNUC_UNUSED)') self.h(' * {') # "#" is special to gtkdoc under some circumstances; it appears # that escaping "##" as "##" or "##" doesn't work, # but adding an extra hash symbol does. Thanks, gtkdoc :-( self.h(' * #define IMPLEMENT(x) %s%s_implement_###x (\\' % (self.prefix_, self.node_name_lc)) self.h(' * klass, my_object_###x)') for method in methods: class_member_name = method.getAttribute('tp:name-for-bindings') class_member_name = class_member_name.lower() self.h(' * IMPLEMENT (%s);' % class_member_name) self.h(' * #undef IMPLEMENT') self.h(' * }') self.h(' * ') else: self.h(' * This interface has no D-Bus methods, so an') self.h(' * implementation can typically pass %NULL to') self.h(' * G_IMPLEMENT_INTERFACE() as the interface') self.h(' * initialization function.') self.h(' */') self.h('typedef struct _%s%sClass %s%sClass;' % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed)) self.h('') self.h('GType %s%s_get_type (void);' % (self.prefix_, node_name_lc)) gtype = self.current_gtype = \ self.MAIN_PREFIX_ + 'TYPE' + self._SUB_PREFIX_ + node_name_uc classname = self.Prefix + node_name_mixed self.h('#define %s \\\n (%s%s_get_type ())' % (gtype, self.prefix_, node_name_lc)) self.h('#define %s%s(obj) \\\n' ' (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))' % (self.PREFIX_, node_name_uc, gtype, classname)) self.h('#define %sIS%s%s(obj) \\\n' ' (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))' % (self.MAIN_PREFIX_, self._SUB_PREFIX_, node_name_uc, gtype)) self.h('#define %s%s_GET_CLASS(obj) \\\n' ' (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))' % (self.PREFIX_, node_name_uc, gtype, classname)) self.h('') self.h('') base_init_code = [] for method in methods: self.do_method(method) for signal in signals: base_init_code.extend(self.do_signal(signal)) self.b('static inline void') self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)' % (self.prefix_, node_name_lc)) self.b('{') if properties: self.b(' static TpDBusPropertiesMixinPropInfo properties[%d] = {' % (len(properties) + 1)) for m in properties: access = m.getAttribute('access') assert access in ('read', 'write', 'readwrite') if access == 'read': flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_READ' elif access == 'write': flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE' else: flags = ('TP_DBUS_PROPERTIES_MIXIN_FLAG_READ | ' 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE') self.b(' { 0, %s, "%s", 0, NULL, NULL }, /* %s */' % (flags, m.getAttribute('type'), m.getAttribute('name'))) self.b(' { 0, 0, NULL, 0, NULL, NULL }') self.b(' };') self.b(' static TpDBusPropertiesMixinIfaceInfo interface =') self.b(' { 0, properties, NULL, NULL };') self.b('') self.b(' dbus_g_object_type_install_info (%s%s_get_type (),' % (self.prefix_, node_name_lc)) self.b(' &_%s%s_object_info);' % (self.prefix_, node_name_lc)) self.b('') if properties: self.b(' interface.dbus_interface = g_quark_from_static_string ' '("%s");' % self.iface_name) for i, m in enumerate(properties): self.b(' properties[%d].name = g_quark_from_static_string ("%s");' % (i, m.getAttribute('name'))) self.b(' properties[%d].type = %s;' % (i, type_to_gtype(m.getAttribute('type'))[1])) self.b(' tp_svc_interface_set_dbus_properties_info (%s, &interface);' % self.current_gtype) self.b('') for s in base_init_code: self.b(s) self.b('}') self.b('static void') self.b('%s%s_base_init (gpointer klass)' % (self.prefix_, node_name_lc)) self.b('{') self.b(' static gboolean initialized = FALSE;') self.b('') self.b(' if (!initialized)') self.b(' {') self.b(' initialized = TRUE;') self.b(' %s%s_base_init_once (klass);' % (self.prefix_, node_name_lc)) self.b(' }') # insert anything we need to do per implementation here self.b('}') self.h('') self.b('static const DBusGMethodInfo _%s%s_methods[] = {' % (self.prefix_, node_name_lc)) method_blob, offsets = self.get_method_glue(methods) for method, offset in zip(methods, offsets): self.do_method_glue(method, offset) if len(methods) == 0: # empty arrays are a gcc extension, so put in a dummy member self.b(" { NULL, NULL, 0 }") self.b('};') self.b('') self.b('static const DBusGObjectInfo _%s%s_object_info = {' % (self.prefix_, node_name_lc)) self.b(' 0,') # version self.b(' _%s%s_methods,' % (self.prefix_, node_name_lc)) self.b(' %d,' % len(methods)) self.b('"' + method_blob.replace('\0', '\\0') + '",') self.b('"' + self.get_signal_glue(signals).replace('\0', '\\0') + '",') self.b('"' + self.get_property_glue(glue_properties).replace('\0', '\\0') + '",') self.b('};') self.b('') self.node_name_mixed = None self.node_name_lc = None self.node_name_uc = None def get_method_glue(self, methods): info = [] offsets = [] for method in methods: offsets.append(len(''.join(info))) info.append(self.iface_name + '\0') info.append(method.getAttribute('name') + '\0') info.append('A\0') # async counter = 0 for arg in method.getElementsByTagName('arg'): out = arg.getAttribute('direction') == 'out' name = arg.getAttribute('name') if not name: assert out name = 'arg%u' % counter counter += 1 info.append(name + '\0') if out: info.append('O\0') else: info.append('I\0') if out: info.append('F\0') # not const info.append('N\0') # not error or return info.append(arg.getAttribute('type') + '\0') info.append('\0') return ''.join(info) + '\0', offsets def do_method_glue(self, method, offset): lc_name = method.getAttribute('tp:name-for-bindings') if method.getAttribute('name') != lc_name.replace('_', ''): raise AssertionError('Method %s tp:name-for-bindings (%s) does ' 'not match' % (method.getAttribute('name'), lc_name)) lc_name = lc_name.lower() marshaller = method_to_glue_marshal_name(method, self.signal_marshal_prefix) wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name self.b(" { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset)) def get_signal_glue(self, signals): info = [] for signal in signals: info.append(self.iface_name) info.append(signal.getAttribute('name')) return '\0'.join(info) + '\0\0' # the implementation can be the same get_property_glue = get_signal_glue def get_method_impl_names(self, method): dbus_method_name = method.getAttribute('name') class_member_name = method.getAttribute('tp:name-for-bindings') if dbus_method_name != class_member_name.replace('_', ''): raise AssertionError('Method %s tp:name-for-bindings (%s) does ' 'not match' % (dbus_method_name, class_member_name)) class_member_name = class_member_name.lower() stub_name = (self.prefix_ + self.node_name_lc + '_' + class_member_name) return (stub_name + '_impl', class_member_name) def do_method(self, method): assert self.node_name_mixed is not None in_class = [] # Examples refer to Thing.DoStuff (su) -> ii # DoStuff dbus_method_name = method.getAttribute('name') # do_stuff class_member_name = method.getAttribute('tp:name-for-bindings') if dbus_method_name != class_member_name.replace('_', ''): raise AssertionError('Method %s tp:name-for-bindings (%s) does ' 'not match' % (dbus_method_name, class_member_name)) class_member_name = class_member_name.lower() # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint, # DBusGMethodInvocation *); stub_name = (self.prefix_ + self.node_name_lc + '_' + class_member_name) # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *, # const char *, guint, DBusGMethodInvocation); impl_name = stub_name + '_impl' # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *, # gint, gint); ret_name = (self.prefix_ + self.node_name_lc + '_return_from_' + class_member_name) # Gather arguments in_args = [] out_args = [] for i in method.getElementsByTagName('arg'): name = i.getAttribute('name') direction = i.getAttribute('direction') or 'in' dtype = i.getAttribute('type') assert direction in ('in', 'out') if name: name = direction + '_' + name elif direction == 'in': name = direction + str(len(in_args)) else: name = direction + str(len(out_args)) ctype, gtype, marshaller, pointer = type_to_gtype(dtype) if pointer: ctype = 'const ' + ctype struct = (ctype, name) if direction == 'in': in_args.append(struct) else: out_args.append(struct) # Implementation type declaration (in header, docs in body) self.b('/**') self.b(' * %s:' % impl_name) self.b(' * @self: The object implementing this interface') for (ctype, name) in in_args: self.b(' * @%s: %s (FIXME, generate documentation)' % (name, ctype)) self.b(' * @context: Used to return values or throw an error') self.b(' *') self.b(' * The signature of an implementation of the D-Bus method') self.b(' * %s on interface %s.' % (dbus_method_name, self.iface_name)) self.b(' */') self.h('typedef void (*%s) (%s%s *self,' % (impl_name, self.Prefix, self.node_name_mixed)) for (ctype, name) in in_args: self.h(' %s%s,' % (ctype, name)) self.h(' DBusGMethodInvocation *context);') # Class member (in class definition) in_class.append(' %s %s;' % (impl_name, class_member_name)) # Stub definition (in body only - it's static) self.b('static void') self.b('%s (%s%s *self,' % (stub_name, self.Prefix, self.node_name_mixed)) for (ctype, name) in in_args: self.b(' %s%s,' % (ctype, name)) self.b(' DBusGMethodInvocation *context)') self.b('{') self.b(' %s impl = (%s%s_GET_CLASS (self)->%s);' % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name)) self.b('') self.b(' if (impl != NULL)') tmp = ['self'] + [name for (ctype, name) in in_args] + ['context'] self.b(' {') self.b(' (impl) (%s);' % ',\n '.join(tmp)) self.b(' }') self.b(' else') self.b(' {') if self.not_implemented_func: self.b(' %s (context);' % self.not_implemented_func) else: self.b(' GError e = { DBUS_GERROR, ') self.b(' DBUS_GERROR_UNKNOWN_METHOD,') self.b(' "Method not implemented" };') self.b('') self.b(' dbus_g_method_return_error (context, &e);') self.b(' }') self.b('}') self.b('') # Implementation registration (in both header and body) self.h('void %s%s_implement_%s (%s%sClass *klass, %s impl);' % (self.prefix_, self.node_name_lc, class_member_name, self.Prefix, self.node_name_mixed, impl_name)) self.b('/**') self.b(' * %s%s_implement_%s:' % (self.prefix_, self.node_name_lc, class_member_name)) self.b(' * @klass: A class whose instances implement this interface') self.b(' * @impl: A callback used to implement the %s D-Bus method' % dbus_method_name) self.b(' *') self.b(' * Register an implementation for the %s method in the vtable' % dbus_method_name) self.b(' * of an implementation of this interface. To be called from') self.b(' * the interface init function.') self.b(' */') self.b('void') self.b('%s%s_implement_%s (%s%sClass *klass, %s impl)' % (self.prefix_, self.node_name_lc, class_member_name, self.Prefix, self.node_name_mixed, impl_name)) self.b('{') self.b(' klass->%s = impl;' % class_member_name) self.b('}') self.b('') # Return convenience function (static inline, in header) self.h('/**') self.h(' * %s:' % ret_name) self.h(' * @context: The D-Bus method invocation context') for (ctype, name) in out_args: self.h(' * @%s: %s (FIXME, generate documentation)' % (name, ctype)) self.h(' *') self.h(' * Return successfully by calling dbus_g_method_return().') self.h(' * This inline function exists only to provide type-safety.') self.h(' */') tmp = (['DBusGMethodInvocation *context'] + [ctype + name for (ctype, name) in out_args]) self.h('static inline') self.h('/* this comment is to stop gtkdoc realising this is static */') self.h(('void %s (' % ret_name) + (',\n '.join(tmp)) + ');') self.h('static inline void') self.h(('%s (' % ret_name) + (',\n '.join(tmp)) + ')') self.h('{') tmp = ['context'] + [name for (ctype, name) in out_args] self.h(' dbus_g_method_return (' + ',\n '.join(tmp) + ');') self.h('}') self.h('') return in_class def get_signal_const_entry(self, signal): assert self.node_name_uc is not None return ('SIGNAL_%s_%s' % (self.node_name_uc, signal.getAttribute('name'))) def do_signal(self, signal): assert self.node_name_mixed is not None in_base_init = [] # for signal: Thing::StuffHappened (s, u) # we want to emit: # void tp_svc_thing_emit_stuff_happened (gpointer instance, # const char *arg0, guint arg1); dbus_name = signal.getAttribute('name') ugly_name = signal.getAttribute('tp:name-for-bindings') if dbus_name != ugly_name.replace('_', ''): raise AssertionError('Signal %s tp:name-for-bindings (%s) does ' 'not match' % (dbus_name, ugly_name)) stub_name = (self.prefix_ + self.node_name_lc + '_emit_' + ugly_name.lower()) const_name = self.get_signal_const_entry(signal) # Gather arguments args = [] for i in signal.getElementsByTagName('arg'): name = i.getAttribute('name') dtype = i.getAttribute('type') tp_type = i.getAttribute('tp:type') if name: name = 'arg_' + name else: name = 'arg' + str(len(args)) ctype, gtype, marshaller, pointer = type_to_gtype(dtype) if pointer: ctype = 'const ' + ctype struct = (ctype, name, gtype) args.append(struct) tmp = (['gpointer instance'] + [ctype + name for (ctype, name, gtype) in args]) self.h(('void %s (' % stub_name) + (',\n '.join(tmp)) + ');') # FIXME: emit docs self.b('/**') self.b(' * %s:' % stub_name) self.b(' * @instance: The object implementing this interface') for (ctype, name, gtype) in args: self.b(' * @%s: %s (FIXME, generate documentation)' % (name, ctype)) self.b(' *') self.b(' * Type-safe wrapper around g_signal_emit to emit the') self.b(' * %s signal on interface %s.' % (dbus_name, self.iface_name)) self.b(' */') self.b('void') self.b(('%s (' % stub_name) + (',\n '.join(tmp)) + ')') self.b('{') self.b(' g_assert (instance != NULL);') self.b(' g_assert (G_TYPE_CHECK_INSTANCE_TYPE (instance, %s));' % (self.current_gtype)) tmp = (['instance', '%s_signals[%s]' % (self.node_name_lc, const_name), '0'] + [name for (ctype, name, gtype) in args]) self.b(' g_signal_emit (' + ',\n '.join(tmp) + ');') self.b('}') self.b('') signal_name = dbus_gutils_wincaps_to_uscore(dbus_name).replace('_', '-') in_base_init.append(' /**') in_base_init.append(' * %s%s::%s:' % (self.Prefix, self.node_name_mixed, signal_name)) for (ctype, name, gtype) in args: in_base_init.append(' * @%s: %s (FIXME, generate documentation)' % (name, ctype)) in_base_init.append(' *') in_base_init.append(' * The %s D-Bus signal is emitted whenever ' 'this GObject signal is.' % dbus_name) in_base_init.append(' */') in_base_init.append(' %s_signals[%s] =' % (self.node_name_lc, const_name)) in_base_init.append(' g_signal_new ("%s",' % signal_name) in_base_init.append(' G_OBJECT_CLASS_TYPE (klass),') in_base_init.append(' G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,') in_base_init.append(' 0,') in_base_init.append(' NULL, NULL,') in_base_init.append(' %s,' % signal_to_marshal_name(signal, self.signal_marshal_prefix)) in_base_init.append(' G_TYPE_NONE,') tmp = ['%d' % len(args)] + [gtype for (ctype, name, gtype) in args] in_base_init.append(' %s);' % ',\n '.join(tmp)) in_base_init.append('') return in_base_init def have_properties(self, nodes): for node in nodes: interface = node.getElementsByTagName('interface')[0] if interface.getElementsByTagName('property'): return True return False def __call__(self): nodes = self.dom.getElementsByTagName('node') nodes.sort(cmp_by_name) self.h('#include ') self.h('#include ') if self.have_properties(nodes): self.h('#include ') self.h('') self.h('G_BEGIN_DECLS') self.h('') self.b('#include "%s.h"' % self.basename) self.b('') for header in self.headers: self.b('#include %s' % header) self.b('') for node in nodes: self.do_node(node) self.h('') self.h('G_END_DECLS') self.b('') for header in self.end_headers: self.b('#include %s' % header) self.h('') self.b('') open(self.basename + '.h', 'w').write('\n'.join(self.__header)) open(self.basename + '.c', 'w').write('\n'.join(self.__body)) def cmdline_error(): print """\ usage: gen-ginterface [OPTIONS] xmlfile Prefix_ options: --include='' (may be repeated) --include='"header.h"' (ditto) --include-end='"header.h"' (ditto) Include extra headers in the generated .c file --signal-marshal-prefix='prefix' Use the given prefix on generated signal marshallers (default is prefix.lower()). --filename='BASENAME' Set the basename for the output files (default is prefix.lower() + 'ginterfaces') --not-implemented-func='symbol' Set action when methods not implemented in the interface vtable are called. symbol must have signature void symbol (DBusGMethodInvocation *context) and return some sort of "not implemented" error via dbus_g_method_return_error (context, ...) """ sys.exit(1) if __name__ == '__main__': from getopt import gnu_getopt options, argv = gnu_getopt(sys.argv[1:], '', ['filename=', 'signal-marshal-prefix=', 'include=', 'include-end=', 'allow-unstable', 'not-implemented-func=']) try: prefix = argv[1] except IndexError: cmdline_error() basename = prefix.lower() + 'ginterfaces' signal_marshal_prefix = prefix.lower().rstrip('_') headers = [] end_headers = [] not_implemented_func = '' allow_havoc = False for option, value in options: if option == '--filename': basename = value elif option == '--signal-marshal-prefix': signal_marshal_prefix = value elif option == '--include': if value[0] not in '<"': value = '"%s"' % value headers.append(value) elif option == '--include-end': if value[0] not in '<"': value = '"%s"' % value end_headers.append(value) elif option == '--not-implemented-func': not_implemented_func = value elif option == '--allow-unstable': allow_havoc = True try: dom = xml.dom.minidom.parse(argv[0]) except IndexError: cmdline_error() Generator(dom, prefix, basename, signal_marshal_prefix, headers, end_headers, not_implemented_func, allow_havoc)() telepathy-qt-0.9.6~git1/tools/with-session-bus.sh0000664000175000017500000000427412470405660017676 0ustar jrjr#!/bin/sh # with-session-bus.sh - run a program with a temporary D-Bus session daemon # # The canonical location of this program is the telepathy-glib tools/ # directory, please synchronize any changes with that copy. # # Copyright (C) 2007-2008 Collabora Ltd. # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. set -e me=with-session-bus dbus_daemon_args="--print-address=5 --print-pid=6 --fork" sleep=0 usage () { echo "usage: $me [options] -- program [program_options]" >&2 echo "Requires write access to the current directory." >&2 echo "" >&2 echo "If \$WITH_SESSION_BUS_FORK_DBUS_MONITOR is set, fork dbus-monitor" >&2 echo "with the arguments in \$WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT." >&2 echo "The output of dbus-monitor is saved in $me-.dbus-monitor-logs" >&2 exit 2 } while test "z$1" != "z--"; do case "$1" in --sleep=*) sleep="$1" sleep="${sleep#--sleep=}" shift ;; --session) dbus_daemon_args="$dbus_daemon_args --session" shift ;; --config-file=*) # FIXME: assumes config file doesn't contain any special characters dbus_daemon_args="$dbus_daemon_args $1" shift ;; *) usage ;; esac done shift if test "z$1" = "z"; then usage; fi exec 5> $me-$$.address exec 6> $me-$$.pid cleanup () { pid=`head -n1 $me-$$.pid` if test -n "$pid" ; then echo "Killing temporary bus daemon: $pid" >&2 kill -INT "$pid" fi rm -f $me-$$.address rm -f $me-$$.pid } trap cleanup INT HUP TERM dbus-daemon $dbus_daemon_args { echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2 { echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2 e=0 DBUS_SESSION_BUS_ADDRESS="`cat $me-$$.address`" export DBUS_SESSION_BUS_ADDRESS if [ -n "$WITH_SESSION_BUS_FORK_DBUS_MONITOR" ] ; then echo -n "Forking dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT" >&2 dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT \ > $me-$$.dbus-monitor-logs 2>&1 & fi "$@" || e=$? if test $sleep != 0; then sleep $sleep fi trap - INT HUP TERM cleanup exit $e telepathy-qt-0.9.6~git1/tools/xincludator.py0000664000175000017500000000241312470405660017016 0ustar jrjr#!/usr/bin/python from sys import argv, stdout, stderr import codecs, locale import os import xml.dom.minidom stdout = codecs.getwriter('utf-8')(stdout) NS_XI = 'http://www.w3.org/2001/XInclude' def xincludate(dom, base, dropns = []): remove_attrs = [] for i in xrange(dom.documentElement.attributes.length): attr = dom.documentElement.attributes.item(i) if attr.prefix == 'xmlns': if attr.localName in dropns: remove_attrs.append(attr) else: dropns.append(attr.localName) for attr in remove_attrs: dom.documentElement.removeAttributeNode(attr) for include in dom.getElementsByTagNameNS(NS_XI, 'include'): href = include.getAttribute('href') # FIXME: assumes Unixy paths filename = os.path.join(os.path.dirname(base), href) subdom = xml.dom.minidom.parse(filename) xincludate(subdom, filename, dropns) if './' in href: subdom.documentElement.setAttribute('xml:base', href) include.parentNode.replaceChild(subdom.documentElement, include) if __name__ == '__main__': argv = argv[1:] dom = xml.dom.minidom.parse(argv[0]) xincludate(dom, argv[0]) xml = dom.toxml() stdout.write(xml) stdout.write('\n') telepathy-qt-0.9.6~git1/cmake/0000775000175000017500000000000012470405660014030 5ustar jrjrtelepathy-qt-0.9.6~git1/cmake/modules/0000775000175000017500000000000012470405660015500 5ustar jrjrtelepathy-qt-0.9.6~git1/cmake/modules/FindGObject.cmake0000664000175000017500000000427112470405660020624 0ustar jrjr# - Try to find GObject # Once done this will define # # GOBJECT_FOUND - system has GObject # GOBJECT_INCLUDE_DIR - the GObject include directory # GOBJECT_LIBRARIES - the libraries needed to use GObject # GOBJECT_DEFINITIONS - Compiler switches required for using GObject # Copyright (c) 2008 Helio Chissini de Castro, # (c)2006, Tim Beaulen IF (GOBJECT_INCLUDE_DIR AND GOBJECT_LIBRARIES) # in cache already SET(GObject_FIND_QUIETLY TRUE) ELSE (GOBJECT_INCLUDE_DIR AND GOBJECT_LIBRARIES) SET(GObject_FIND_QUIETLY FALSE) ENDIF (GOBJECT_INCLUDE_DIR AND GOBJECT_LIBRARIES) IF (NOT WIN32) FIND_PACKAGE(PkgConfig REQUIRED) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls PKG_CHECK_MODULES(PKG_GOBJECT2 REQUIRED gobject-2.0) SET(GOBJECT_DEFINITIONS ${PKG_GOBJECT2_CFLAGS}) ENDIF (NOT WIN32) FIND_PATH(GOBJECT_INCLUDE_DIR gobject/gobject.h PATHS ${PKG_GOBJECT2_INCLUDE_DIRS} /usr/include/glib-2.0/ PATH_SUFFIXES glib-2.0 ) FIND_LIBRARY(_GObjectLibs NAMES gobject-2.0 PATHS ${PKG_GOBJECT2_LIBRARY_DIRS} ) FIND_LIBRARY(_GModuleLibs NAMES gmodule-2.0 PATHS ${PKG_GOBJECT2_LIBRARY_DIRS} ) FIND_LIBRARY(_GThreadLibs NAMES gthread-2.0 PATHS ${PKG_GOBJECT2_LIBRARY_DIRS} ) FIND_LIBRARY(_GLibs NAMES glib-2.0 PATHS ${PKG_GOBJECT2_LIBRARY_DIRS} ) IF (WIN32) SET (GOBJECT_LIBRARIES ${_GObjectLibs} ${_GModuleLibs} ${_GThreadLibs} ${_GLibs}) ELSE (WIN32) SET (GOBJECT_LIBRARIES ${PKG_GOBJECT2_LIBRARIES}) ENDIF (WIN32) IF (GOBJECT_INCLUDE_DIR AND GOBJECT_LIBRARIES) SET(GOBJECT_FOUND TRUE) ELSE (GOBJECT_INCLUDE_DIR AND GOBJECT_LIBRARIES) SET(GOBJECT_FOUND FALSE) ENDIF (GOBJECT_INCLUDE_DIR AND GOBJECT_LIBRARIES) IF (GOBJECT_FOUND) IF (NOT GObject_FIND_QUIETLY) MESSAGE(STATUS "Found GObject libraries: ${GOBJECT_LIBRARIES}") MESSAGE(STATUS "Found GObject includes : ${GOBJECT_INCLUDE_DIR}") ENDIF (NOT GObject_FIND_QUIETLY) ELSE (GOBJECT_FOUND) IF (GObject_FIND_REQUIRED) MESSAGE(STATUS "Could NOT find GObject") ENDIF(GObject_FIND_REQUIRED) ENDIF (GOBJECT_FOUND) MARK_AS_ADVANCED(GOBJECT_INCLUDE_DIR GOBJECT_LIBRARIES) telepathy-qt-0.9.6~git1/cmake/modules/FindDBusGLib.cmake0000664000175000017500000000405412470405660020701 0ustar jrjr# Try to find the GLib binding of the DBus library # DBUS_GLIB_FOUND - system has dbus-glib # DBUS_GLIB_INCLUDE_DIR - the dbus-glib include directory # DBUS_GLIB_LIBRARIES - Link these to use dbus-glib # Copyright (c) 2008, Allen Winter # Copyright (c) 2009, Andre Moreira Magalhaes # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. set(DBUS_GLIB_FIND_REQUIRED ${DBusGLib_FIND_REQUIRED}) if(DBUS_GLIB_INCLUDE_DIR AND DBUS_GLIB_LIBRARIES) # Already in cache, be silent set(DBUS_GLIB_FIND_QUIETLY TRUE) endif(DBUS_GLIB_INCLUDE_DIR AND DBUS_GLIB_LIBRARIES) if(NOT WIN32) find_package(PkgConfig) if (DBusGLib_FIND_VERSION_EXACT) pkg_check_modules(PC_DBUS_GLIB QUIET dbus-glib-1=${DBusGLib_FIND_VERSION}) else (DBusGLib_FIND_VERSION_EXACT) if (DBusGLib_FIND_VERSION) pkg_check_modules(PC_DBUS_GLIB REQUIRED dbus-glib-1>=${DBusGLib_FIND_VERSION}) else (DBusGLib_FIND_VERSION) pkg_check_modules(PC_DBUS_GLIB REQUIRED dbus-glib-1) endif (DBusGLib_FIND_VERSION) endif (DBusGLib_FIND_VERSION_EXACT) endif(NOT WIN32) find_path(DBUS_GLIB_INCLUDE_DIR NAMES dbus-1.0/dbus/dbus-glib.h HINTS ${PC_DBUS_GLIB_INCLUDEDIR} ${PC_DBUS_GLIB_INCLUDE_DIRS} ) find_path(DBUS_GLIB_LOWLEVEL_INCLUDE_DIR NAMES dbus/dbus-arch-deps.h HINTS ${PC_DBUS_GLIB_INCLUDEDIR} ${PC_DBUS_GLIB_INCLUDE_DIRS} ) # HACK! Workaround appending "/dbus-1.0" to the HINTS above not working for some reason. set(DBUS_GLIB_INCLUDE_DIRS "${DBUS_GLIB_INCLUDE_DIR}/dbus-1.0" "${DBUS_GLIB_LOWLEVEL_INCLUDE_DIR}" ) find_library(DBUS_GLIB_LIBRARIES NAMES dbus-glib-1 HINTS ${PC_DBUS_GLIB_LIBDIR} ${PC_DBUS_GLIB_LIBRARY_DIRS} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DBUS_GLIB DEFAULT_MSG DBUS_GLIB_LIBRARIES DBUS_GLIB_INCLUDE_DIR) telepathy-qt-0.9.6~git1/cmake/modules/Qt5Macros.cmake0000664000175000017500000000524712470405660020330 0ustar jrjr# This file is included by FindQt5.cmake, don't include it directly. # Copyright (C) 2001-2009 Kitware, Inc. # Copyright (C) 2011 Collabora Ltd. # Copyright (C) 2011 Nokia Corporation # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. MACRO (QT5_GET_MOC_FLAGS _moc_flags) SET(${_moc_flags}) GET_DIRECTORY_PROPERTY(_inc_DIRS INCLUDE_DIRECTORIES) FOREACH(_current ${_inc_DIRS}) IF("${_current}" MATCHES "\\.framework/?$") STRING(REGEX REPLACE "/[^/]+\\.framework" "" framework_path "${_current}") SET(${_moc_flags} ${${_moc_flags}} "-F${framework_path}") ELSE("${_current}" MATCHES "\\.framework/?$") SET(${_moc_flags} ${${_moc_flags}} "-I${_current}") ENDIF("${_current}" MATCHES "\\.framework/?$") ENDFOREACH(_current ${_inc_DIRS}) GET_DIRECTORY_PROPERTY(_defines COMPILE_DEFINITIONS) FOREACH(_current ${_defines}) SET(${_moc_flags} ${${_moc_flags}} "-D${_current}") ENDFOREACH(_current ${_defines}) IF(Q_WS_WIN) SET(${_moc_flags} ${${_moc_flags}} -DWIN32) ENDIF(Q_WS_WIN) ENDMACRO (QT5_GET_MOC_FLAGS) # helper macro to set up a moc rule MACRO (QT5_CREATE_MOC_COMMAND infile outfile moc_flags moc_options) # For Windows, create a parameters file to work around command line length limit IF (WIN32) # Pass the parameters in a file. Set the working directory to # be that containing the parameters file and reference it by # just the file name. This is necessary because the moc tool on # MinGW builds does not seem to handle spaces in the path to the # file given with the @ syntax. GET_FILENAME_COMPONENT(_moc_outfile_name "${outfile}" NAME) GET_FILENAME_COMPONENT(_moc_outfile_dir "${outfile}" PATH) IF(_moc_outfile_dir) SET(_moc_working_dir WORKING_DIRECTORY ${_moc_outfile_dir}) ENDIF(_moc_outfile_dir) SET (_moc_parameters_file ${outfile}_parameters) SET (_moc_parameters ${moc_flags} ${moc_options} -o "${outfile}" "${infile}") STRING (REPLACE ";" "\n" _moc_parameters "${_moc_parameters}") FILE (WRITE ${_moc_parameters_file} "${_moc_parameters}") ADD_CUSTOM_COMMAND(OUTPUT ${outfile} COMMAND ${QT_MOC_EXECUTABLE} @${_moc_outfile_name}_parameters DEPENDS ${infile} ${_moc_working_dir} VERBATIM) ELSE (WIN32) ADD_CUSTOM_COMMAND(OUTPUT ${outfile} COMMAND ${QT_MOC_EXECUTABLE} ARGS ${moc_flags} ${moc_options} -o ${outfile} ${infile} DEPENDS ${infile}) ENDIF (WIN32) ENDMACRO (QT5_CREATE_MOC_COMMAND) telepathy-qt-0.9.6~git1/cmake/modules/BasicFindPackageVersion.cmake.in0000664000175000017500000000262412470405660023557 0ustar jrjr# This is a very basic file for the new style find_package() search mode, # i.e. Config-mode. It is used by MACRO_WRITE_BASIC_CMAKE_VERSION_FILE() from # MacroWriteBasicCMakeVersionFile.cmake. # In this mode find_package() searches for a Config.cmake # file and an associated Version.cmake file, which it loads to check # the version number. # This file can be used with configure_file() to generate such a file for a project # with very basic logic. # It sets PACKAGE_VERSION_EXACT if the current version string and the requested # version string are exactly the same and it sets PACKAGE_VERSION_COMPATIBLE # if the current version is >= requested version. # If this is not good enough for your project, you need to write your own # improved Version.cmake file. # This file requires the following three variables to be set: # PROJECT_VERSION_MAJOR # PROJECT_VERSION_MINOR # PROJECT_VERSION_PATCH set(PACKAGE_VERSION @PROJECT_VERSION_FULL@) if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) set(PACKAGE_VERSION_COMPATIBLE FALSE) else("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) set(PACKAGE_VERSION_COMPATIBLE TRUE) if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") set(PACKAGE_VERSION_EXACT TRUE) endif( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") endif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) telepathy-qt-0.9.6~git1/cmake/modules/FindQt5.cmake0000664000175000017500000001312312470405660017754 0ustar jrjr# - Find Qt5 # This module can be used to find Qt5. # The most important issues are that Qt5 pkgconfig files are installed with PKG_CONFIG_PATH properly # set, and that Qt5 qmake is available via the system path. # This module defines a number of key variables and macros. # # Below is a detailed list of variables that FindQt5.cmake sets. # QT_FOUND If false, don't try to use Qt. # QT5_FOUND If false, don't try to use Qt5. # # QT_VERSION_MAJOR The major version of Qt found. # QT_VERSION_MINOR The minor version of Qt found. # QT_VERSION_PATCH The patch version of Qt found. # # QT_BINARY_DIR Path to "bin" of Qt5 # QT_DOC_DIR Path to "doc" of Qt5 # # QT_INCLUDES List of paths to all include directories of Qt5. # # QT_LIBRARIES List of paths to all libraries of Qt5. # QT_QTCORE_LIBRARY The QtCore library # QT_QTDBUS_LIBRARY The QtDBus library # QT_QTGUI_LIBRARY The QtGui library # QT_QTNETWORK_LIBRARY The QtNetwork library # QT_QTTEST_LIBRARY The QtTest library # QT_QTWIDGETS_LIBRARY The QtWidgets library # QT_QTXML_LIBRARY The QtXml library # # also defined, but NOT for general use are # QT_MOC_EXECUTABLE Where to find the moc tool # QT_CONFIG_FLAGS Flags used when building Qt # Copyright (C) 2001-2009 Kitware, Inc. # Copyright (C) 2011 Collabora Ltd. # Copyright (C) 2011 Nokia Corporation # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF(QT_INCLUDES AND QT_LIBRARIES AND QT_MAJOR_VERSION MATCHES 5) # Already in cache, be silent SET(QT_FOUND TRUE) SET(QT5_FOUND TRUE) RETURN() ENDIF(QT_INCLUDES AND QT_LIBRARIES AND QT_MAJOR_VERSION MATCHES 5) IF(NOT Qt5Core_DIR ) IF(NOT QT_QMAKE_EXECUTABLE) FIND_PROGRAM(QT_QMAKE_EXECUTABLE_FINDQT NAMES qmake qmake5 qmake-qt5 PATHS "${QT_SEARCH_PATH}/bin" "$ENV{QTDIR}/bin") SET(QT_QMAKE_EXECUTABLE ${QT_QMAKE_EXECUTABLE_FINDQT} CACHE PATH "Qt qmake program.") ENDIF(NOT QT_QMAKE_EXECUTABLE) EXEC_PROGRAM(${QT_QMAKE_EXECUTABLE} ARGS "-query QT_VERSION" OUTPUT_VARIABLE QTVERSION) IF(NOT QTVERSION MATCHES "5.*") SET(QT_FOUND FALSE) SET(QT5_FOUND FALSE) IF(Qt5_FIND_REQUIRED) MESSAGE(FATAL_ERROR "CMake was unable to find Qt5, put qmake in your path or set QTDIR/QT_QMAKE_EXECUTABLE.") ENDIF(Qt5_FIND_REQUIRED) RETURN() ENDIF(NOT QTVERSION MATCHES "5.*") ENDIF(NOT Qt5Core_DIR ) find_package(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt5DBus ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt5Test ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt5Network ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt5Xml ${REQUIRED_QT_VERSION} REQUIRED) # Copy includes and library names into the same style as pkgconfig used for Qt4 set(QT_INCLUDES ${Qt5Core_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Test_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS}) set(QT_QTCORE_LIBRARY ${Qt5Core_LIBRARIES}) set(QT_QTDBUS_LIBRARY ${Qt5DBus_LIBRARIES}) set(QT_QTGUI_LIBRARY ${Qt5Gui_LIBRARIES}) set(QT_QTNETWORK_LIBRARY ${Qt5Network_LIBRARIES}) set(QT_QTTEST_LIBRARY ${Qt5Test_LIBRARIES}) set(QT_QTWIDGETS_LIBRARY ${Qt5Widgets_LIBRARIES}) set(QT_QTXML_LIBRARY ${Qt5Xml_LIBRARIES}) set(QT_LIBRARIES ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTTEST_LIBRARY} ${QT_QTWIDGETS_LIBRARY} ${QT_QTXML_LIBRARY}) SET(QT_VERSION_MAJOR ${Qt5Core_VERSION_MAJOR}) SET(QT_VERSION_MINOR ${Qt5Core_VERSION_MINOR}) SET(QT_VERSION_PATCH ${Qt5Core_VERSION_PATCH}) SET(QT_VERSION ${Qt5Core_VERSION}) GET_PROPERTY(QT_QMAKE_EXECUTABLE TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORTED_LOCATION) IF(NOT QT_INCLUDE_DIR) EXEC_PROGRAM(${QT_QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_HEADERS" OUTPUT_VARIABLE QTHEADERS) SET(QT_INCLUDE_DIR ${QTHEADERS} CACHE INTERNAL "" FORCE) ENDIF(NOT QT_INCLUDE_DIR) IF(NOT QT_LIBRARY_DIR) EXEC_PROGRAM(${QT_QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_LIBS" OUTPUT_VARIABLE QTLIBS) SET(QT_LIBRARY_DIR ${QTLIBS} CACHE INTERNAL "" FORCE) ENDIF(NOT QT_LIBRARY_DIR) IF(NOT QT_BINARY_DIR) EXEC_PROGRAM(${QT_QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_BINS" OUTPUT_VARIABLE QTBINS) SET(QT_BINARY_DIR ${QTBINS} CACHE INTERNAL "" FORCE) ENDIF(NOT QT_BINARY_DIR) IF(NOT QT_DOC_DIR) EXEC_PROGRAM(${QT_QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_DOCS" OUTPUT_VARIABLE QTDOCS) SET(QT_DOC_DIR ${QTDOCS} CACHE INTERNAL "" FORCE) ENDIF(NOT QT_DOC_DIR) IF(NOT QT_MOC_EXECUTABLE) FIND_PROGRAM(QT_MOC_EXECUTABLE NAMES moc moc5 moc-qt5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) ENDIF(NOT QT_MOC_EXECUTABLE) MARK_AS_ADVANCED(QT_INCLUDES QT_INCLUDE_DIR QT_LIBRARIES QT_LIBRARY_DIR QT_BINARY_DIR QT_DOC_DIR QT_QMAKE_EXECUTABLE_FINDQT QT_QMAKE_EXECUTABLE QT_MOC_EXECUTABLE) # Invokes pkgconfig, cleans up the result and sets variables EXECUTE_PROCESS(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable qt_config QtCore OUTPUT_VARIABLE _pkgconfig_flags RESULT_VARIABLE _pkgconfig_failed) STRING(REPLACE " " ";" QT_CONFIG_FLAGS "${_pkgconfig_flags}") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") INCLUDE(Qt5Macros) SET(QT_FOUND TRUE) SET(QT5_FOUND TRUE) telepathy-qt-0.9.6~git1/cmake/modules/FindLibPython.py0000664000175000017500000000101212470405660020555 0ustar jrjr# Copyright (c) 2007, Simon Edwards # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. import sys import distutils.sysconfig print("exec_prefix:%s" % sys.exec_prefix) print("short_version:%s" % sys.version[:3]) print("long_version:%s" % sys.version.split()[0]) print("py_inc_dir:%s" % distutils.sysconfig.get_python_inc()) print("site_packages_dir:%s" % distutils.sysconfig.get_python_lib(plat_specific=1)) telepathy-qt-0.9.6~git1/cmake/modules/FindGStreamer.cmake0000664000175000017500000000515012470405660021175 0ustar jrjr# - Try to find GStreamer # Once done this will define # # GSTREAMER_FOUND - system has GStreamer # GSTREAMER_INCLUDE_DIR - the GStreamer include directory # GSTREAMER_LIBRARIES - the libraries needed to use GStreamer # GSTREAMER_DEFINITIONS - Compiler switches required for using GStreamer # Copyright (c) 2006, Tim Beaulen # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # TODO: Other versions --> GSTREAMER_X_Y_FOUND (Example: GSTREAMER_0_8_FOUND and GSTREAMER_0_10_FOUND etc) IF (GSTREAMER_INCLUDE_DIR AND GSTREAMER_LIBRARIES AND GSTREAMER_BASE_LIBRARY AND GSTREAMER_INTERFACE_LIBRARY) # in cache already SET(GSTREAMER_FIND_QUIETLY TRUE) ELSE (GSTREAMER_INCLUDE_DIR AND GSTREAMER_LIBRARIES AND GSTREAMER_BASE_LIBRARY AND GSTREAMER_INTERFACE_LIBRARY) SET(GSTREAMER_FIND_QUIETLY FALSE) ENDIF (GSTREAMER_INCLUDE_DIR AND GSTREAMER_LIBRARIES AND GSTREAMER_BASE_LIBRARY AND GSTREAMER_INTERFACE_LIBRARY) IF (NOT WIN32) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls FIND_PACKAGE(PkgConfig) PKG_CHECK_MODULES(PC_GSTREAMER gstreamer-1.0) #MESSAGE(STATUS "DEBUG: GStreamer include directory = ${GSTREAMER_INCLUDE_DIRS}") #MESSAGE(STATUS "DEBUG: GStreamer link directory = ${GSTREAMER_LIBRARY_DIRS}") #MESSAGE(STATUS "DEBUG: GStreamer CFlags = ${GSTREAMER_CFLAGS_OTHER}") SET(GSTREAMER_DEFINITIONS ${PC_GSTREAMER_CFLAGS_OTHER}) ENDIF (NOT WIN32) FIND_PATH(GSTREAMER_INCLUDE_DIR gst/gst.h PATHS ${PC_GSTREAMER_INCLUDEDIR} ${PC_GSTREAMER_INCLUDE_DIRS} PATH_SUFFIXES gstreamer-1.0 ) FIND_LIBRARY(GSTREAMER_LIBRARIES NAMES gstreamer-1.0 PATHS ${PC_GSTREAMER_LIBDIR} ${PC_GSTREAMER_LIBRARY_DIRS} ) FIND_LIBRARY(GSTREAMER_BASE_LIBRARY NAMES gstbase-1.0 PATHS ${PC_GSTREAMER_LIBDIR} ${PC_GSTREAMER_LIBRARY_DIRS} ) IF (GSTREAMER_INCLUDE_DIR) #MESSAGE(STATUS "DEBUG: Found GStreamer include dir: ${GSTREAMER_INCLUDE_DIR}") ELSE (GSTREAMER_INCLUDE_DIR) MESSAGE(STATUS "GStreamer: WARNING: include dir not found") ENDIF (GSTREAMER_INCLUDE_DIR) IF (GSTREAMER_LIBRARIES) #MESSAGE(STATUS "DEBUG: Found GStreamer library: ${GSTREAMER_LIBRARIES}") ELSE (GSTREAMER_LIBRARIES) MESSAGE(STATUS "GStreamer: WARNING: library not found") ENDIF (GSTREAMER_LIBRARIES) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(GStreamer DEFAULT_MSG GSTREAMER_LIBRARIES GSTREAMER_INCLUDE_DIR GSTREAMER_BASE_LIBRARY) MARK_AS_ADVANCED(GSTREAMER_INCLUDE_DIR GSTREAMER_LIBRARIES GSTREAMER_BASE_LIBRARY) telepathy-qt-0.9.6~git1/cmake/modules/Doxygen.cmake0000664000175000017500000000260212470405660020117 0ustar jrjr# generate documentation on 'make doxygen-doc' file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/doc) find_package(Doxygen) if(DOXYGEN_FOUND) find_program(QHELPGENERATOR_EXECUTABLE qhelpgenerator) mark_as_advanced(QHELPGENERATOR_EXECUTABLE) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(QHELPGENERATOR DEFAULT_MSG QHELPGENERATOR_EXECUTABLE) set(QT_TAGS_FILE ${QT_DOC_DIR}/html/qt.tags) if(EXISTS ${QT_TAGS_FILE}) find_package(Perl) if (NOT PERL_FOUND) message(WARNING "Perl was not found. Qt crosslinks in uploaded docs won't be valid.") endif (NOT PERL_FOUND) else(EXISTS ${QT_TAGS_FILE}) message(WARNING "html/qt.tags not found in ${QT_DOC_DIR}. Set the QT_DOC_DIR variable to point to its location to enable crosslinking.") unset(QT_TAGS_FILE) endif(EXISTS ${QT_TAGS_FILE}) set(abs_top_builddir ${CMAKE_BINARY_DIR}) set(abs_top_srcdir ${CMAKE_SOURCE_DIR}) set(GENERATE_HTML YES) set(GENERATE_RTF NO) set(GENERATE_CHM NO) set(GENERATE_CHI NO) set(GENERATE_LATEX NO) set(GENERATE_MAN NO) set(GENERATE_XML NO) set(GENERATE_QHP ${QHELPGENERATOR_FOUND}) configure_file(doxygen.cfg.in ${CMAKE_BINARY_DIR}/doxygen.cfg) add_custom_target(doxygen-doc ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/doxygen.cfg) endif(DOXYGEN_FOUND) telepathy-qt-0.9.6~git1/cmake/modules/MacroWriteBasicCMakeVersionFile.cmake0000664000175000017500000000215312470405660024570 0ustar jrjr# MACRO_WRITE_BASIC_CMAKE_VERSION_FILE( _filename _major _minor _patch) # Writes a file for use as ConfigVersion.cmake file to <_filename>. # See the documentation of FIND_PACKAGE() for details on this. # _filename is the output filename, it should be in the build tree. # _major is the major version number of the project to be installed # _minor is the minor version number of the project to be installed # _patch is the patch version number of the project to be installed # # Copyright (c) 2008, Alexander Neundorf, # Copyright (c) 2010, Collabora Ltd., # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. get_filename_component(_currentListFileDir ${CMAKE_CURRENT_LIST_FILE} PATH) function(MACRO_WRITE_BASIC_CMAKE_VERSION_FILE _filename _version) set(PROJECT_VERSION_FULL ${_version}) configure_file(${_currentListFileDir}/BasicFindPackageVersion.cmake.in "${_filename}" @ONLY) endfunction(MACRO_WRITE_BASIC_CMAKE_VERSION_FILE _major _minor _patch) telepathy-qt-0.9.6~git1/cmake/modules/TelepathyDist.cmake0000664000175000017500000001236512470405660021274 0ustar jrjr# setup make dist add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz COMMAND git archive --format=tar --prefix=${PACKAGE_NAME}-${PACKAGE_VERSION}/ HEAD | gzip > ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) add_custom_target(create-source-working-dir rm -rf ${PACKAGE_NAME}-${PACKAGE_VERSION} && gzip -df ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz && tar -xf ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar && rm ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar* && cd ${PACKAGE_NAME}-${PACKAGE_VERSION}/ && rm -rf doc && mkdir doc && cp -R ${CMAKE_BINARY_DIR}/doc/html doc/ WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz COMMENT "Generating working source dir for the dist tarball") add_dependencies(create-source-working-dir doxygen-doc) add_custom_target(dist-hook chmod u+w ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}/ChangeLog && git log --stat > ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}/ChangeLog || git log > ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}/ChangeLog WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMENT "Updating Changelog") add_dependencies(dist-hook create-source-working-dir) add_custom_target(dist tar --format=ustar -chf - ${PACKAGE_NAME}-${PACKAGE_VERSION} | GZIP=--best gzip -c > ${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Generating dist tarball") add_dependencies(dist dist-hook) # setup make distcheck add_custom_target(distcheck rm -rf build && mkdir build && cd build && cmake .. && make && make check WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}/ COMMENT "Testing successful tarball build") add_dependencies(distcheck dist) # CPack set(ENABLE_CPACK OFF CACHE BOOL "Enables CPack targets generation") if (ENABLE_CPACK) include(InstallRequiredSystemLibraries) SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A high-level binding for Telepathy in Qt") SET(CPACK_PACKAGE_VENDOR "Collabora Ltd.") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING") SET(CPACK_PACKAGE_VERSION_MAJOR ${TP_QT_MAJOR_VERSION}) SET(CPACK_PACKAGE_VERSION_MINOR ${TP_QT_MINOR_VERSION}) SET(CPACK_PACKAGE_VERSION_PATCH ${TP_QT_MICRO_VERSION}) SET(CPACK_PACKAGE_INSTALL_DIRECTORY "TelepathyQt") SET(CPACK_PACKAGE_CONTACT "telepathy@lists.freedesktop.org") set(CPACK_SOURCE_IGNORE_FILES "/build/;/.bzr/;~$;/.git/;/.kdev4/;${CPACK_SOURCE_IGNORE_FILES}") IF(WIN32 AND NOT UNIX) # There is a bug in NSI that does not handle full unix paths properly. Make # sure there is at least one set of four (4) backlasshes. #SET(CPACK_PACKAGE_ICON "${CMake_SOURCE_DIR}/Utilities/Release\\\\InstallIcon.bmp") #SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\MyExecutable.exe") SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} TelepathyQt") #SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.github.com") #SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.my-personal-home-page.com") #SET(CPACK_NSIS_CONTACT "me@my-personal-home-page.com") SET(CPACK_NSIS_MODIFY_PATH ON) ELSE(WIN32 AND NOT UNIX) #SET(CPACK_STRIP_FILES "bin/MyExecutable") SET(CPACK_SOURCE_STRIP_FILES "") ENDIF(WIN32 AND NOT UNIX) #SET(CPACK_PACKAGE_EXECUTABLES "MyExecutable" "My Executable") if (APPLE) set(CPACK_SET_DESTDIR ON) set(CPACK_PACKAGE_RELOCATABLE OFF) endif (APPLE) #name components set(CPACK_COMPONENT_MAINLIBRARY_DISPLAY_NAME "TelepathyQt main components") set(CPACK_COMPONENT_FARSTREAM_DISPLAY_NAME "TelepathyQt Farstream support") set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "Development files for TelepathyQt") set(CPACK_COMPONENT_FARSTREAM_HEADERS_DISPLAY_NAME "Development files for TelepathyQt-Farstream") #components description set(CPACK_COMPONENT_MAINLIBRARY_DESCRIPTION "The main TelepathyQt library") set(CPACK_COMPONENT_FARSTREAM_DESCRIPTION "The TelepathyQt-Farstream library") set(CPACK_COMPONENT_HEADERS_DESCRIPTION "Development files for TelepathyQt") set(CPACK_COMPONENT_FARSTREAM_HEADERS_DESCRIPTION "Development files for TelepathyQt-Farstream") set(CPACK_COMPONENT_HEADERS_DEPENDS mainlibrary) set(CPACK_COMPONENT_FARSTREAM_DEPENDS mainlibrary) set(CPACK_COMPONENT_FARSTREAM_HEADERS_DEPENDS mainlibrary farstream) #installation types set(CPACK_ALL_INSTALL_TYPES User Developer Minimal) set(CPACK_COMPONENT_MAINLIBRARY_INSTALL_TYPES User Developer Minimal) set(CPACK_COMPONENT_FARSTREAM_INSTALL_TYPES User Developer) set(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer) set(CPACK_COMPONENT_FARSTREAM_HEADERS_INSTALL_TYPES Developer) # Leave this as the last declaration, always!!! include(CPack) endif (ENABLE_CPACK) telepathy-qt-0.9.6~git1/cmake/modules/TelepathyDefaults.cmake0000664000175000017500000001572012470405660022136 0ustar jrjr# Enable testing using CTest enable_testing() # Always include srcdir and builddir in include path # This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} in about every subdir set(CMAKE_INCLUDE_CURRENT_DIR ON) # put the include dirs which are in the source or build tree # before all other include dirs, so the headers in the sources # are prefered over the already installed ones set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) # Use colored output set(CMAKE_COLOR_MAKEFILE ON) # Add an option to decide where to install the config files if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} VERSION_GREATER 2.6.2) option(USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR "Prefer to install the Config.cmake files to lib/cmake/ instead of lib//cmake" TRUE) endif (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} VERSION_GREATER 2.6.2) # Set compiler flags if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -ggdb") set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O2 -fno-reorder-blocks -fno-schedule-insns -fno-inline") set(CMAKE_CXX_FLAGS_DEBUGFULL "-O0 -g3 -ggdb -fno-inline") set(CMAKE_CXX_FLAGS_PROFILE "-pg -g3 -ggdb -DNDEBUG") set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -ggdb") set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") set(CMAKE_C_FLAGS_DEBUG "-ggdb -O2 -fno-reorder-blocks -fno-schedule-insns -fno-inline") set(CMAKE_C_FLAGS_DEBUGFULL "-O0 -g3 -ggdb -fno-inline") set(CMAKE_C_FLAGS_PROFILE "-pg -g3 -ggdb -DNDEBUG") set(CMAKE_EXE_LINKER_FLAGS_PROFILE "-pg -ggdb") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "-pg -ggdb") set(DISABLE_WERROR 0 CACHE BOOL "compile without -Werror (normally enabled in development builds)") include(CompilerWarnings) include(TestCXXAcceptsFlag) CHECK_CXX_ACCEPTS_FLAG("-fvisibility=hidden" CXX_FVISIBILITY_HIDDEN) if (CXX_FVISIBILITY_HIDDEN) set(VISIBILITY_HIDDEN_FLAGS "-fvisibility=hidden") else (CXX_FVISIBILITY_HIDDEN) set(VISIBILITY_HIDDEN_FLAGS) endif (CXX_FVISIBILITY_HIDDEN) CHECK_CXX_ACCEPTS_FLAG("-fvisibility-inlines-hidden" CXX_FVISIBILITY_INLINES_HIDDEN) if (CXX_FVISIBILITY_INLINES_HIDDEN) set(VISIBILITY_HIDDEN_FLAGS "${VISIBILITY_HIDDEN_FLAGS} -fvisibility-inlines-hidden") endif (CXX_FVISIBILITY_INLINES_HIDDEN) CHECK_CXX_ACCEPTS_FLAG("-Wdeprecated-declarations" CXX_DEPRECATED_DECLARATIONS) if (CXX_DEPRECATED_DECLARATIONS) set(DEPRECATED_DECLARATIONS_FLAGS "-Wdeprecated-declarations -DTP_QT_DEPRECATED_WARNINGS") else (CXX_DEPRECATED_DECLARATIONS) set(DEPRECATED_DECLARATIONS_FLAGS) endif (CXX_DEPRECATED_DECLARATIONS) if(${TP_QT_NANO_VERSION} EQUAL 0) set(NOT_RELEASE 0) else(${TP_QT_NANO_VERSION} EQUAL 0) set(NOT_RELEASE 1) endif(${TP_QT_NANO_VERSION} EQUAL 0) set(desired all extra sign-compare pointer-arith format-security init-self non-virtual-dtor) set(undesired missing-field-initializers unused-parameter unused-local-typedefs) compiler_warnings(CMAKE_CXX_FLAGS_WARNINGS cxx ${NOT_RELEASE} "${desired}" "${undesired}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_WARNINGS}") set(desired_c all extra declaration-after-statement shadow strict-prototypes missing-prototypes sign-compare nested-externs pointer-arith format-security init-self) set(undesired_c missing-field-initializers unused-parameter unused-local-typedefs) compiler_warnings(CMAKE_C_FLAGS_WARNINGS c ${NOT_RELEASE} "${desired_c}" "${undesired_c}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_WARNINGS}") # Link development builds with -Wl,--no-add-needed # TODO: binutils 2.21 renames the flag to --no-copy-dt-needed-entries, though it keeps the old # one as a deprecated alias. if(${NOT_RELEASE} EQUAL 1) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-add-needed") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-add-needed") endif(${NOT_RELEASE} EQUAL 1) if(CMAKE_SYSTEM_NAME MATCHES Linux) add_definitions(-D_BSD_SOURCE) endif(CMAKE_SYSTEM_NAME MATCHES Linux) # Compiler coverage set(ENABLE_COMPILER_COVERAGE OFF CACHE BOOL "Enables compiler coverage tests through lcov. Enabling this option will build Telepathy-Qt as a static library.") if (ENABLE_COMPILER_COVERAGE) check_cxx_accepts_flag("-fprofile-arcs -ftest-coverage" CXX_FPROFILE_ARCS) check_cxx_accepts_flag("-ftest-coverage" CXX_FTEST_COVERAGE) if (CXX_FPROFILE_ARCS AND CXX_FTEST_COVERAGE) find_program(LCOV lcov) find_program(LCOV_GENHTML genhtml) if (NOT LCOV OR NOT LCOV_GENHTML) message(FATAL_ERROR "You chose to use compiler coverage tests, but lcov or genhtml could not be found in your PATH.") else (NOT LCOV OR NOT LCOV_GENHTML) message(STATUS "Compiler coverage tests enabled - Telepathy-Qt will be compiled as a static library") set(COMPILER_COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage") endif (NOT LCOV OR NOT LCOV_GENHTML) else (CXX_FPROFILE_ARCS AND CXX_FTEST_COVERAGE) message(FATAL_ERROR "You chose to use compiler coverage tests, but it appears your compiler is not able to support them.") endif (CXX_FPROFILE_ARCS AND CXX_FTEST_COVERAGE) else (ENABLE_COMPILER_COVERAGE) set(COMPILER_COVERAGE_FLAGS) endif (ENABLE_COMPILER_COVERAGE) # gcc under Windows if(MINGW) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--export-all-symbols -Wl,--disable-auto-import") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--export-all-symbols -Wl,--disable-auto-import") # we always link against the release version of QT with mingw # (even for debug builds). So we need to define QT_NO_DEBUG # or else QPluginLoader rejects plugins because it thinks # they're built against the wrong QT. add_definitions(-DQT_NO_DEBUG) endif(MINGW) endif(CMAKE_COMPILER_IS_GNUCXX) if(MSVC) set(ESCAPE_CHAR ^) endif(MSVC) set(LIB_SUFFIX "" CACHE STRING "Define suffix of library directory name (32/64)" ) set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The subdirectory where libraries will be installed (default is ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX})" FORCE) set(INCLUDE_INSTALL_DIR "include" CACHE PATH "The subdirectory where header files will be installed (default is ${CMAKE_INSTALL_PREFIX}/include)" FORCE) set(DATA_INSTALL_DIR "share/telepathy" CACHE PATH "The subdirectory where data files will be installed (default is ${CMAKE_INSTALL_PREFIX}/share/telepathy)" FORCE) telepathy-qt-0.9.6~git1/cmake/modules/MacroLogFeature.cmake0000664000175000017500000001311012470405660021515 0ustar jrjr# This file defines the Feature Logging macros. # # MACRO_LOG_FEATURE(VAR FEATURE DESCRIPTION URL [REQUIRED [MIN_VERSION [COMMENTS]]]) # Logs the information so that it can be displayed at the end # of the configure run # VAR : TRUE or FALSE, indicating whether the feature is supported # FEATURE: name of the feature, e.g. "libjpeg" # DESCRIPTION: description what this feature provides # URL: home page # REQUIRED: TRUE or FALSE, indicating whether the featue is required # MIN_VERSION: minimum version number. empty string if unneeded # COMMENTS: More info you may want to provide. empty string if unnecessary # # MACRO_DISPLAY_FEATURE_LOG() # Call this to display the collected results. # Exits CMake with a FATAL error message if a required feature is missing # # Example: # # INCLUDE(MacroLogFeature) # # FIND_PACKAGE(JPEG) # MACRO_LOG_FEATURE(JPEG_FOUND "libjpeg" "Support JPEG images" "http://www.ijg.org" TRUE "3.2a" "") # ... # MACRO_DISPLAY_FEATURE_LOG() # Copyright (c) 2006, Alexander Neundorf, # Copyright (c) 2006, Allen Winter, # Copyright (c) 2009, Sebastian Trueg, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF (NOT _macroLogFeatureAlreadyIncluded) SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_macroLogFeatureAlreadyIncluded TRUE) ENDIF (NOT _macroLogFeatureAlreadyIncluded) MACRO(MACRO_LOG_FEATURE _var _package _description _url ) # _required _minvers _comments) STRING(TOUPPER "${ARGV4}" _required) SET(_minvers "${ARGV5}") SET(_comments "${ARGV6}") IF (${_var}) SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) ELSE (${_var}) IF ("${_required}" STREQUAL "TRUE") SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/MissingRequirements.txt) ELSE ("${_required}" STREQUAL "TRUE") SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) ENDIF ("${_required}" STREQUAL "TRUE") ENDIF (${_var}) SET(_logtext " * ${_package}") IF (NOT ${_var}) IF (${_minvers} MATCHES ".*") SET(_logtext "${_logtext} (${_minvers} or higher)") ENDIF (${_minvers} MATCHES ".*") SET(_logtext "${_logtext} <${_url}>\n ") ELSE (NOT ${_var}) SET(_logtext "${_logtext} - ") ENDIF (NOT ${_var}) SET(_logtext "${_logtext}${_description}") IF (NOT ${_var}) IF (${_comments} MATCHES ".*") SET(_logtext "${_logtext}\n ${_comments}") ENDIF (${_comments} MATCHES ".*") # SET(_logtext "${_logtext}\n") #double-space missing features? ENDIF (NOT ${_var}) FILE(APPEND "${_LOGFILENAME}" "${_logtext}\n") ENDMACRO(MACRO_LOG_FEATURE) MACRO(MACRO_DISPLAY_FEATURE_LOG) SET(_missingFile ${CMAKE_BINARY_DIR}/MissingRequirements.txt) SET(_enabledFile ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) SET(_disabledFile ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) IF (EXISTS ${_missingFile} OR EXISTS ${_enabledFile} OR EXISTS ${_disabledFile}) SET(_printSummary TRUE) ENDIF (EXISTS ${_missingFile} OR EXISTS ${_enabledFile} OR EXISTS ${_disabledFile}) IF(_printSummary) SET(_missingDeps 0) IF (EXISTS ${_enabledFile}) FILE(READ ${_enabledFile} _enabled) FILE(REMOVE ${_enabledFile}) SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following external packages were located on your system.\n-- This installation will have the extra features provided by these packages.\n-----------------------------------------------------------------------------\n${_enabled}") ENDIF (EXISTS ${_enabledFile}) IF (EXISTS ${_disabledFile}) SET(_missingDeps 1) FILE(READ ${_disabledFile} _disabled) FILE(REMOVE ${_disabledFile}) SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following OPTIONAL packages could NOT be located on your system.\n-- Consider installing them to enable more features from this software.\n-----------------------------------------------------------------------------\n${_disabled}") ENDIF (EXISTS ${_disabledFile}) IF (EXISTS ${_missingFile}) SET(_missingDeps 1) FILE(READ ${_missingFile} _requirements) SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following REQUIRED packages could NOT be located on your system.\n-- You must install these packages before continuing.\n-----------------------------------------------------------------------------\n${_requirements}") FILE(REMOVE ${_missingFile}) SET(_haveMissingReq 1) ENDIF (EXISTS ${_missingFile}) IF (NOT ${_missingDeps}) SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- Congratulations! All external packages have been found.") ENDIF (NOT ${_missingDeps}) MESSAGE(${_summary}) MESSAGE("-----------------------------------------------------------------------------\n") IF(_haveMissingReq) MESSAGE(FATAL_ERROR "Exiting: Missing Requirements") ENDIF(_haveMissingReq) ENDIF(_printSummary) ENDMACRO(MACRO_DISPLAY_FEATURE_LOG) telepathy-qt-0.9.6~git1/cmake/modules/FindFarstream.cmake0000664000175000017500000000340512470405660021231 0ustar jrjr# - Try to find Farstream # Once done this will define # # FARSTREAM_FOUND - system has Farstream # FARSTREAM_INCLUDE_DIR - the Farstream include directory # FARSTREAM_LIBRARIES - the libraries needed to use Farstream # FARSTREAM_DEFINITIONS - Compiler switches required for using Farstream # Copyright (c) 2010, Dario Freddi # Copyright (c) 2012, George Kiagiadakis # # Redistribution and use is allowed according to the terms of the BSD license. if (FARSTREAM_INCLUDE_DIR AND FARSTREAM_LIBRARIES) # in cache already set(Farstream_FIND_QUIETLY TRUE) else (FARSTREAM_INCLUDE_DIR AND FARSTREAM_LIBRARIES) set(Farstream_FIND_QUIETLY FALSE) endif (FARSTREAM_INCLUDE_DIR AND FARSTREAM_LIBRARIES) if (NOT WIN32) # use pkg-config to get the directories and then use these values # in the find_path() and find_library() calls find_package(PkgConfig) if (FARSTREAM_MIN_VERSION) PKG_CHECK_MODULES(PC_FARSTREAM farstream-0.2>=${FARSTREAM_MIN_VERSION}) else (FARSTREAM_MIN_VERSION) PKG_CHECK_MODULES(PC_FARSTREAM farstream-0.2) endif (FARSTREAM_MIN_VERSION) set(FARSTREAM_DEFINITIONS ${PC_FARSTREAM_CFLAGS_OTHER}) endif (NOT WIN32) find_path(FARSTREAM_INCLUDE_DIR farstream/fs-conference.h PATHS ${PC_FARSTREAM_INCLUDEDIR} ${PC_FARSTREAM_INCLUDE_DIRS} PATH_SUFFIXES farstream-0.2 ) find_library(FARSTREAM_LIBRARIES NAMES farstream-0.2 PATHS ${PC_FARSTREAM_LIBDIR} ${PC_FARSTREAM_LIBRARY_DIRS} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Farstream DEFAULT_MSG FARSTREAM_LIBRARIES FARSTREAM_INCLUDE_DIR) mark_as_advanced(FARSTREAM_INCLUDE_DIR FARSTREAM_LIBRARIES) telepathy-qt-0.9.6~git1/cmake/modules/FindPythonLibrary.cmake0000664000175000017500000000703112470405660022112 0ustar jrjr# FindPythonLibrary.cmake # ~~~~~~~~~~~~~~~~~~~~~~~ # Find the Python interpreter and related Python directories. # # This file defines the following variables: # # PYTHON_EXECUTABLE - The path and filename of the Python interpreter. # # PYTHON_SHORT_VERSION - The version of the Python interpreter found, # excluding the patch version number. (e.g. 2.5 and not 2.5.1)) # # PYTHON_LONG_VERSION - The version of the Python interpreter found as a human # readable string. # # PYTHON_SITE_PACKAGES_DIR - Location of the Python site-packages directory. # # PYTHON_INCLUDE_PATH - Directory holding the python.h include file. # # PYTHON_LIBRARY, PYTHON_LIBRARIES- Location of the Python library. # Copyright (c) 2007, Simon Edwards # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. INCLUDE(CMakeFindFrameworks) if(EXISTS PYTHON_LIBRARY) # Already in cache, be silent set(PYTHONLIBRARY_FOUND TRUE) else(EXISTS PYTHON_LIBRARY) FIND_PACKAGE(PythonInterp) if(PYTHONINTERP_FOUND) FIND_FILE(_find_lib_python_py FindLibPython.py PATHS ${CMAKE_MODULE_PATH}) EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_lib_python_py} OUTPUT_VARIABLE python_config) if(python_config) STRING(REGEX REPLACE ".*exec_prefix:([^\n]+).*$" "\\1" PYTHON_PREFIX ${python_config}) STRING(REGEX REPLACE ".*\nshort_version:([^\n]+).*$" "\\1" PYTHON_SHORT_VERSION ${python_config}) STRING(REGEX REPLACE ".*\nlong_version:([^\n]+).*$" "\\1" PYTHON_LONG_VERSION ${python_config}) STRING(REGEX REPLACE ".*\npy_inc_dir:([^\n]+).*$" "\\1" PYTHON_INCLUDE_PATH ${python_config}) STRING(REGEX REPLACE ".*\nsite_packages_dir:([^\n]+).*$" "\\1" PYTHON_SITE_PACKAGES_DIR ${python_config}) STRING(REGEX REPLACE "([0-9]+).([0-9]+)" "\\1\\2" PYTHON_SHORT_VERSION_NO_DOT ${PYTHON_SHORT_VERSION}) set(PYTHON_LIBRARY_NAMES python${PYTHON_SHORT_VERSION} python${PYTHON_SHORT_VERSION_NO_DOT}) if(WIN32) STRING(REPLACE "\\" "/" PYTHON_SITE_PACKAGES_DIR ${PYTHON_SITE_PACKAGES_DIR}) endif(WIN32) FIND_LIBRARY(PYTHON_LIBRARY NAMES ${PYTHON_LIBRARY_NAMES} PATHS ${PYTHON_PREFIX}/lib ${PYTHON_PREFIX}/libs NO_DEFAULT_PATH) set(PYTHONLIBRARY_FOUND TRUE) endif(python_config) # adapted from cmake's builtin FindPythonLibs if(APPLE) CMAKE_FIND_FRAMEWORKS(Python) set(PYTHON_FRAMEWORK_INCLUDES) if(Python_FRAMEWORKS) # If a framework has been selected for the include path, # make sure "-framework" is used to link it. if("${PYTHON_INCLUDE_PATH}" MATCHES "Python\\.framework") set(PYTHON_LIBRARY "") set(PYTHON_DEBUG_LIBRARY "") endif("${PYTHON_INCLUDE_PATH}" MATCHES "Python\\.framework") if(NOT PYTHON_LIBRARY) set (PYTHON_LIBRARY "-framework Python" CACHE FILEPATH "Python Framework" FORCE) endif(NOT PYTHON_LIBRARY) set(PYTHONLIBRARY_FOUND TRUE) endif(Python_FRAMEWORKS) endif(APPLE) endif(PYTHONINTERP_FOUND) if(PYTHONLIBRARY_FOUND) set(PYTHON_LIBRARIES ${PYTHON_LIBRARY}) if(NOT PYTHONLIBRARY_FIND_QUIETLY) message(STATUS "Found Python executable: ${PYTHON_EXECUTABLE}") message(STATUS "Found Python version: ${PYTHON_LONG_VERSION}") endif(NOT PYTHONLIBRARY_FIND_QUIETLY) else(PYTHONLIBRARY_FOUND) if(PYTHONLIBRARY_FIND_REQUIRED) message(FATAL_ERROR "Could not find Python") endif(PYTHONLIBRARY_FIND_REQUIRED) endif(PYTHONLIBRARY_FOUND) endif (EXISTS PYTHON_LIBRARY) telepathy-qt-0.9.6~git1/cmake/modules/FindTelepathyGlib.cmake0000664000175000017500000000431212470405660022040 0ustar jrjr# - Try to find Telepathy-Glib # Once done this will define # # TELEPATHY_GLIB_FOUND - system has Telepathy-Glib # TELEPATHY_GLIB_INCLUDE_DIR - the Telepathy-Glib include directory # TELEPATHY_GLIB_LIBRARIES - the libraries needed to use Telepathy-Glib # TELEPATHY_GLIB_DEFINITIONS - Compiler switches required for using Telepathy-Glib # Copyright (c) 2010, Dario Freddi # # Redistribution and use is allowed according to the terms of the BSD license. if (TELEPATHY_GLIB_INCLUDE_DIR AND TELEPATHY_GLIB_LIBRARIES) # in cache already set(TELEPATHYGLIB_FIND_QUIETLY TRUE) else (TELEPATHY_GLIB_INCLUDE_DIR AND TELEPATHY_GLIB_LIBRARIES) set(TELEPATHYGLIB_FIND_QUIETLY FALSE) endif (TELEPATHY_GLIB_INCLUDE_DIR AND TELEPATHY_GLIB_LIBRARIES) if (NOT WIN32) # use pkg-config to get the directories and then use these values # in the find_path() and find_library() calls find_package(PkgConfig) if (TELEPATHY_GLIB_MIN_VERSION) PKG_CHECK_MODULES(PC_TELEPATHY_GLIB telepathy-glib>=${TELEPATHY_GLIB_MIN_VERSION}) else (TELEPATHY_GLIB_MIN_VERSION) PKG_CHECK_MODULES(PC_TELEPATHY_GLIB telepathy-glib) endif (TELEPATHY_GLIB_MIN_VERSION) set(TELEPATHY_GLIB_DEFINITIONS ${PC_TELEPATHY_GLIB_CFLAGS_OTHER}) endif (NOT WIN32) if (TELEPATHY_GLIB_MIN_VERSION AND NOT PC_TELEPATHY_GLIB_FOUND) message(STATUS "Telepathy-glib not found or its version is < ${TELEPATHY_GLIB_MIN_VERSION}") else (TELEPATHY_GLIB_MIN_VERSION AND NOT PC_TELEPATHY_GLIB_FOUND) find_path(TELEPATHY_GLIB_INCLUDE_DIR telepathy-glib/client.h PATHS ${PC_TELEPATHY_GLIB_INCLUDEDIR} ${PC_TELEPATHY_GLIB_INCLUDE_DIRS} PATH_SUFFIXES telepathy-1.0 ) find_library(TELEPATHY_GLIB_LIBRARIES NAMES telepathy-glib PATHS ${PC_TELEPATHY_GLIB_LIBDIR} ${PC_TELEPATHY_GLIB_LIBRARY_DIRS} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(TelepathyGlib DEFAULT_MSG TELEPATHY_GLIB_LIBRARIES TELEPATHY_GLIB_INCLUDE_DIR) mark_as_advanced(TELEPATHY_GLIB_INCLUDE_DIR TELEPATHY_GLIB_LIBRARIES) endif (TELEPATHY_GLIB_MIN_VERSION AND NOT PC_TELEPATHY_GLIB_FOUND) telepathy-qt-0.9.6~git1/cmake/modules/CompilerWarnings.cmake0000664000175000017500000000431512470405660021770 0ustar jrjrinclude(CheckCXXCompilerFlag) include(CheckCCompilerFlag) macro(check_lang_compiler_flag lang flag variable) if(${lang} STREQUAL c) check_c_compiler_flag(${flag} ${variable}) endif(${lang} STREQUAL c) if(${lang} STREQUAL cxx) check_cxx_compiler_flag(${flag} ${variable}) endif(${lang} STREQUAL cxx) endmacro(check_lang_compiler_flag flag variable) macro(compiler_warnings ret lang werror_by_default desirable_flags undesirable_flags) set(warning_flags "") foreach(flag ${desirable_flags}) check_lang_compiler_flag(${lang} -W${flag} ${flag}_${lang}_result) if(${${flag}_${lang}_result}) set(warning_flags "${warning_flags} -W${flag}") endif( ${${flag}_${lang}_result} ) endforeach(flag ${desirable_flags}) check_lang_compiler_flag(${lang} -Werror error_${lang}_result) if(${error_${lang}_result}) set(error_flags "-Werror") endif(${error_${lang}_result}) set(all_nowarning_flags_supported 1) foreach(flag ${undesirable_flags}) check_lang_compiler_flag(${lang} -Wno-${flag} ${flag}_${lang}_result) if(${${flag}_${lang}_result}) set(warning_flags "${warning_flags} -Wno-${flag}") else(${${flag}_${lang}_result}) set(all_nowarning_flags_supported 0) break() endif(${${flag}_${lang}_result}) check_lang_compiler_flag(${lang} -Wno-error=${flag} noerror_${flag}_${lang}_result) if(${noerror_${flag}_${lang}_result}) set(error_flags "${error_flags} -Wno-error=${flag}") endif(${noerror_${flag}_${lang}_result}) endforeach(flag ${undesirable_flags}) if(DISABLE_WERROR) set(enable_werror 0) else(DISABLE_WERROR) set(enable_werror 1) endif(DISABLE_WERROR) if(${werror_by_default} AND ${enable_werror} AND ${all_nowarning_flags_supported}) set(${ret} "${warning_flags} ${error_flags}") else(${werror_by_default} AND ${enable_werror} AND ${all_nowarning_flags_supported}) set(${ret} "${warning_flags}") endif(${werror_by_default} AND ${enable_werror} AND ${all_nowarning_flags_supported}) endmacro(compiler_warnings ret lang werror_by_default desirable_flags undesirable_flags) telepathy-qt-0.9.6~git1/cmake/modules/FindDBus.cmake0000664000175000017500000000267412470405660020151 0ustar jrjr# - Try to find the low-level D-Bus library # Once done this will define # # DBUS_FOUND - system has D-Bus # DBUS_INCLUDE_DIRS - the D-Bus include directories # DBUS_INCLUDE_DIR - the D-Bus include directory # DBUS_ARCH_INCLUDE_DIR - the D-Bus architecture-specific include directory # DBUS_LIBRARIES - the libraries needed to use D-Bus # Copyright (c) 2012, George Kiagiadakis # Copyright (c) 2008, Kevin Kofler, # modeled after FindLibArt.cmake: # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (NOT WIN32) find_package(PkgConfig) pkg_check_modules(PC_DBUS dbus-1) endif (NOT WIN32) find_path(DBUS_INCLUDE_DIR dbus/dbus.h PATHS ${PC_DBUS_INCLUDE_DIRS} PATH_SUFFIXES dbus-1.0 ) find_path(DBUS_ARCH_INCLUDE_DIR dbus/dbus-arch-deps.h PATHS ${PC_DBUS_INCLUDE_DIRS} HINTS ${CMAKE_LIBRARY_PATH}/dbus-1.0/include ${CMAKE_SYSTEM_LIBRARY_PATH}/dbus-1.0/include ) find_library(DBUS_LIBRARIES NAMES dbus-1 PATHS ${PC_DBUS_LIBRARY_DIRS} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DBus DBUS_INCLUDE_DIR DBUS_ARCH_INCLUDE_DIR DBUS_LIBRARIES) set(DBUS_INCLUDE_DIRS ${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR}) mark_as_advanced(DBUS_INCLUDE_DIR DBUS_ARCH_INCLUDE_DIR DBUS_LIBRARIES) telepathy-qt-0.9.6~git1/cmake/modules/FindGIOUnix.cmake0000664000175000017500000000172112470405660020566 0ustar jrjr# - Try to find the GIO unix libraries # Once done this will define # # GIOUNIX_FOUND - system has GIO unix # GIOUNIX_INCLUDE_DIR - the GIO unix include directory # # Copyright (C) 2011 Collabora Ltd. # Copyright (C) 2011 Nokia Corporation # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if(GIOUNIX_INCLUDE_DIR) # Already in cache, be silent set(GIOUNIX_FIND_QUIETLY TRUE) endif(GIOUNIX_INCLUDE_DIR) include(UsePkgConfig) pkg_check_modules(PC_LibGIOUnix gio-unix-2.0) find_path(GIOUNIX_MAIN_INCLUDE_DIR NAMES gio/gunixconnection.h HINTS ${PC_LibGIOUnix_INCLUDEDIR} PATH_SUFFIXES gio-unix-2.0) set(GIOUNIX_INCLUDE_DIR "${GIOUNIX_MAIN_INCLUDE_DIR}") include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GIOUNIX DEFAULT_MSG GIOUNIX_MAIN_INCLUDE_DIR) mark_as_advanced(GIOUNIX_INCLUDE_DIR) telepathy-qt-0.9.6~git1/cmake/modules/FindGIO.cmake0000664000175000017500000000213112470405660017716 0ustar jrjr# - Try to find the GIO libraries # Once done this will define # # GIO_FOUND - system has GIO # GIO_INCLUDE_DIR - the GIO include directory # GIO_LIBRARIES - GIO library # # Copyright (C) 2011 Collabora Ltd. # Copyright (C) 2011 Nokia Corporation # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if(GIO_INCLUDE_DIR AND GIO_LIBRARIES) # Already in cache, be silent set(GIO_FIND_QUIETLY TRUE) endif(GIO_INCLUDE_DIR AND GIO_LIBRARIES) include(UsePkgConfig) pkg_check_modules(PC_LibGIO gio-2.0) find_path(GIO_MAIN_INCLUDE_DIR NAMES gio/gio.h HINTS ${PC_LibGIO_INCLUDEDIR} PATH_SUFFIXES glib-2.0) find_library(GIO_LIBRARY NAMES gio-2.0 HINTS ${PC_LibGIO_LIBDIR}) set(GIO_INCLUDE_DIR "${GIO_MAIN_INCLUDE_DIR}") set(GIO_LIBRARIES "${GIO_LIBRARY}") include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GIO DEFAULT_MSG GIO_LIBRARIES GIO_MAIN_INCLUDE_DIR) mark_as_advanced(GIO_INCLUDE_DIR GIO_LIBRARIES) telepathy-qt-0.9.6~git1/cmake/modules/FindTelepathyFarstream.cmake0000664000175000017500000000420312470405660023106 0ustar jrjr# - Try to find Telepathy-Farstream # Once done this will define # # TELEPATHY_FARSTREAM_FOUND - system has TelepathyFarstream # TELEPATHY_FARSTREAM_INCLUDE_DIR - the TelepathyFarstream include directory # TELEPATHY_FARSTREAM_LIBRARIES - the libraries needed to use TelepathyFarstream # TELEPATHY_FARSTREAM_DEFINITIONS - Compiler switches required for using TelepathyFarstream # Copyright (c) 2010, Dario Freddi # Copyright (c) 2011, Mateu Batle # # Redistribution and use is allowed according to the terms of the BSD license. if (TELEPATHY_FARSTREAM_INCLUDE_DIR AND TELEPATHY_FARSTREAM_LIBRARIES) # in cache already set(TelepathyFarstream_FIND_QUIETLY TRUE) else (TELEPATHY_FARSTREAM_INCLUDE_DIR AND TELEPATHY_FARSTREAM_LIBRARIES) set(TelepathyFarstream_FIND_QUIETLY FALSE) endif (TELEPATHY_FARSTREAM_INCLUDE_DIR AND TELEPATHY_FARSTREAM_LIBRARIES) if (NOT WIN32) # use pkg-config to get the directories and then use these values # in the find_path() and find_library() calls find_package(PkgConfig) if (TELEPATHY_FARSTREAM_MIN_VERSION) PKG_CHECK_MODULES(PC_TELEPATHY_FARSTREAM telepathy-farstream>=${TELEPATHY_FARSTREAM_MIN_VERSION}) else (TELEPATHY_FARSTREAM_MIN_VERSION) PKG_CHECK_MODULES(PC_TELEPATHY_FARSTREAM telepathy-farstream) endif (TELEPATHY_FARSTREAM_MIN_VERSION) set(TELEPATHY_FARSTREAM_DEFINITIONS ${PC_TELEPATHY_FARSTREAM_CFLAGS_OTHER}) endif (NOT WIN32) find_path(TELEPATHY_FARSTREAM_INCLUDE_DIR telepathy-farstream/telepathy-farstream.h PATHS ${PC_TELEPATHY_FARSTREAM_INCLUDEDIR} ${PC_TELEPATHY_FARSTREAM_INCLUDE_DIRS} PATH_SUFFIXES telepathy-1.0 ) find_library(TELEPATHY_FARSTREAM_LIBRARIES NAMES telepathy-farstream PATHS ${PC_TELEPATHY_FARSTREAM_LIBDIR} ${PC_TELEPATHY_FARSTREAM_LIBRARY_DIRS} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(TelepathyFarstream DEFAULT_MSG TELEPATHY_FARSTREAM_LIBRARIES TELEPATHY_FARSTREAM_INCLUDE_DIR) mark_as_advanced(TELEPATHY_FARSTREAM_INCLUDE_DIR TELEPATHY_FARSTREAM_LIBRARIES) telepathy-qt-0.9.6~git1/cmake/modules/FindQt.cmake0000664000175000017500000001012512470405660017666 0ustar jrjr# - Searches for Qt4 or Qt5. # Copyright (C) 2001-2009 Kitware, Inc. # Copyright (C) 2011 Collabora Ltd. # Copyright (C) 2011 Nokia Corporation # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF(DESIRED_QT_VERSION MATCHES 5) # Qt5 was explicitly requested, so use its CMakeConfig instead of qmake which may not be at a global location find_package(Qt5Core QUIET) IF( Qt5Core_DIR ) SET(QT5_INSTALLED TRUE) ENDIF( Qt5Core_DIR ) ENDIF(DESIRED_QT_VERSION MATCHES 5) #Otherwise search for installed qmakes IF(NOT QT5_INSTALLED) IF(NOT QT_QMAKE_EXECUTABLE) FIND_PROGRAM(QT_QMAKE_EXECUTABLE_FINDQT NAMES qmake qmake4 qmake-qt4 qmake5 qmake-qt5 PATHS "${QT_SEARCH_PATH}/bin" "$ENV{QTDIR}/bin") SET(QT_QMAKE_EXECUTABLE ${QT_QMAKE_EXECUTABLE_FINDQT} CACHE PATH "Qt qmake program.") ENDIF(NOT QT_QMAKE_EXECUTABLE) # now find qmake IF(QT_QMAKE_EXECUTABLE) EXEC_PROGRAM(${QT_QMAKE_EXECUTABLE} ARGS "-query QT_VERSION" OUTPUT_VARIABLE QTVERSION) IF(QTVERSION MATCHES "4.*") SET(QT4_INSTALLED TRUE) ENDIF(QTVERSION MATCHES "4.*") IF(QTVERSION MATCHES "5.*") SET(QT5_INSTALLED TRUE) ENDIF(QTVERSION MATCHES "5.*") ENDIF(QT_QMAKE_EXECUTABLE) ENDIF(NOT QT5_INSTALLED) IF(NOT DESIRED_QT_VERSION) IF(QT4_INSTALLED) SET(DESIRED_QT_VERSION 4 CACHE STRING "Pick a version of Qt to use: 4 or 5") ENDIF(QT4_INSTALLED) IF(QT5_INSTALLED) SET(DESIRED_QT_VERSION 5 CACHE STRING "Pick a version of Qt to use: 4 or 5") ENDIF(QT5_INSTALLED) ENDIF(NOT DESIRED_QT_VERSION) IF(DESIRED_QT_VERSION MATCHES 4) SET(Qt4_FIND_REQUIRED ${Qt_FIND_REQUIRED}) SET(Qt4_FIND_QUIETLY ${Qt_FIND_QUIETLY}) SET(QT_MIN_VERSION ${QT4_MIN_VERSION}) SET(QT_MAX_VERSION ${QT4_MAX_VERSION}) INCLUDE(FindQt4) ENDIF(DESIRED_QT_VERSION MATCHES 4) IF(DESIRED_QT_VERSION MATCHES 5) SET(Qt5_FIND_REQUIRED ${Qt_FIND_REQUIRED}) SET(Qt5_FIND_QUIETLY ${Qt_FIND_QUIETLY}) SET(QT_MIN_VERSION ${QT5_MIN_VERSION}) SET(QT_MAX_VERSION ${QT5_MAX_VERSION}) INCLUDE(FindQt5) ENDIF(DESIRED_QT_VERSION MATCHES 5) IF(NOT QT4_INSTALLED AND NOT QT5_INSTALLED) IF(Qt_FIND_REQUIRED) MESSAGE(SEND_ERROR "CMake was unable to find any Qt versions, put qmake in your path, or set QTDIR/QT_QMAKE_EXECUTABLE.") ENDIF(Qt_FIND_REQUIRED) ELSE(NOT QT4_INSTALLED AND NOT QT5_INSTALLED) IF(NOT QT_FOUND) IF(Qt_FIND_REQUIRED) MESSAGE(FATAL_ERROR "CMake was unable to find Qt version: ${DESIRED_QT_VERSION}, put qmake in your path or set QTDIR/QT_QMAKE_EXECUTABLE.") ELSE(Qt_FIND_REQUIRED) MESSAGE("CMake was unable to find Qt version: ${DESIRED_QT_VERSION}, put qmake in your path or set QTDIR/QT_QMAKE_EXECUTABLE.") ENDIF(Qt_FIND_REQUIRED) ENDIF(NOT QT_FOUND) ENDIF(NOT QT4_INSTALLED AND NOT QT5_INSTALLED) MACRO(QT_GET_MOC_FLAGS moc_flags) IF(QT_VERSION_MAJOR MATCHES 4) QT4_GET_MOC_FLAGS(${moc_flags}) ELSE(QT_VERSION_MAJOR MATCHES 4) IF(QT_VERSION_MAJOR MATCHES 5) QT5_GET_MOC_FLAGS(${moc_flags}) ENDIF(QT_VERSION_MAJOR MATCHES 5) ENDIF(QT_VERSION_MAJOR MATCHES 4) ENDMACRO(QT_GET_MOC_FLAGS) MACRO(QT_CREATE_MOC_COMMAND infile outfile moc_flags moc_options) IF(QT_VERSION_MAJOR MATCHES 4) IF(CMAKE_VERSION VERSION_GREATER 2.8.11.20130607) QT4_CREATE_MOC_COMMAND(${infile} ${outfile} "${moc_flags}" "${moc_options}" "") ELSE(CMAKE_VERSION VERSION_GREATER 2.8.11.20130607) QT4_CREATE_MOC_COMMAND(${infile} ${outfile} "${moc_flags}" "${moc_options}") ENDIF(CMAKE_VERSION VERSION_GREATER 2.8.11.20130607) ELSE(QT_VERSION_MAJOR MATCHES 4) IF(QT_VERSION_MAJOR MATCHES 5) IF(QTVERSION VERSION_GREATER 5.1.99) QT5_CREATE_MOC_COMMAND(${infile} ${outfile} "${moc_flags}" "${moc_options}" "") ELSE() QT5_CREATE_MOC_COMMAND(${infile} ${outfile} "${moc_flags}" "${moc_options}") ENDIF() ENDIF(QT_VERSION_MAJOR MATCHES 5) ENDIF(QT_VERSION_MAJOR MATCHES 4) ENDMACRO(QT_CREATE_MOC_COMMAND) MARK_AS_ADVANCED(QT_QMAKE_EXECUTABLE_FINDQT) telepathy-qt-0.9.6~git1/cmake/modules/FindGLIB2.cmake0000664000175000017500000000321012470405660020076 0ustar jrjr# - Try to find the GLIB2 libraries # Once done this will define # # GLIB2_FOUND - system has glib2 # GLIB2_INCLUDE_DIR - the glib2 include directory # GLIB2_LIBRARIES - glib2 library # Copyright (c) 2008 Laurent Montel, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if(GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) # Already in cache, be silent set(GLIB2_FIND_QUIETLY TRUE) endif(GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) find_package(PkgConfig) pkg_check_modules(PC_LibGLIB2 glib-2.0) find_path(GLIB2_MAIN_INCLUDE_DIR NAMES glib.h HINTS ${PC_LibGLIB2_INCLUDEDIR} PATH_SUFFIXES glib-2.0) find_library(GLIB2_LIBRARY NAMES glib-2.0 HINTS ${PC_LibGLIB2_LIBDIR} ) set(GLIB2_LIBRARIES ${GLIB2_LIBRARY}) # search the glibconfig.h include dir under the same root where the library is found get_filename_component(glib2LibDir "${GLIB2_LIBRARIES}" PATH) find_path(GLIB2_INTERNAL_INCLUDE_DIR glibconfig.h PATH_SUFFIXES glib-2.0/include HINTS ${PC_LibGLIB2_INCLUDEDIR} "${glib2LibDir}" ${CMAKE_SYSTEM_LIBRARY_PATH}) set(GLIB2_INCLUDE_DIR "${GLIB2_MAIN_INCLUDE_DIR}") # not sure if this include dir is optional or required # for now it is optional if(GLIB2_INTERNAL_INCLUDE_DIR) set(GLIB2_INCLUDE_DIR ${GLIB2_INCLUDE_DIR} "${GLIB2_INTERNAL_INCLUDE_DIR}") endif(GLIB2_INTERNAL_INCLUDE_DIR) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GLIB2 DEFAULT_MSG GLIB2_LIBRARIES GLIB2_MAIN_INCLUDE_DIR) mark_as_advanced(GLIB2_INCLUDE_DIR GLIB2_LIBRARIES) telepathy-qt-0.9.6~git1/cmake/modules/TpQtMacros.cmake0000664000175000017500000006703412470405660020551 0ustar jrjr# - Common macros for Tp-Qt # Copyright (c) 2010, Collabora Ltd. # # Redistribution and use is allowed according to the terms of the BSD license. # # These macros/functions are not exported - they are meant for internal usage into Telepathy-Qt's build system. # # Preamble: How dynamic generators are handled with the CMake build system. # Telepathy-Qt strongly relies upon lots of files generated at build time through some python programs, found # in tools/. To avoid developers the struggle of handling those manually, a set of convenience macros have been # created to handle them with the correct dependencies. Each of those macros takes a target name as a first argument # and creates a target with that exact name. In a similar fashion, in the last argument you can specify a list # of targets the generated target will depend on. This way, you can handle transparently dependencies between # generated files, while the dirty stuff is done for you in the background. # # macro TPQT_EXTRACT_DEPENDS (tpqt_other tpqt_depends) # Internal macro used to extract arguments from ARGN # # function TPQT_CREATE_MOC_COMMAND_TARGET_DEPS(inputfile outputfile moc_flags moc_options target_dependencies ...) # This function behaves exactly like qt_create_moc_command, but creates a custom target for the # moc file generation, allowing to specify a list of targets the generated moc target will depend on. # Just like qt_create_moc_command, it is an internal macro and it's not meant to be used explicitely. # # function TPQT_GENERATE_MOC_I(inputfile outputfile) # This function behaves exactly like qt_generate_moc, but it generates moc files with the -i option, # which disables the generation of an #include directive. This macro has to be used always when building # Tp-Qt internals due to the internal header files restrictions. # # function TPQT_GENERATE_MOC_I_TARGET_DEPS(inputfile outputfile target_dependencies ...) # This function acts as an overload to QT_GENERATE_MOC_I: it does exactly the same thing, but creates a # custom target for the moc file generation, and adds target_dependencies to it as dependencies. # # function TPQT_GENERATE_MOCS(sourcefile ...) # Generates mocs from a list of header files. You usually want to use this function when building tests # or examples. Please remember the list of the header files passed to this function MUST be added to the # target's sources. # # function TPQT_CLIENT_GENERATOR(spec group pretty_include namespace [arguments] [DEPENDS dependencies ...]) # This function takes care of invoking qt-client-gen.py with the correct arguments, which generates # headers out of specs. spec is the name of the spec headers will be generated from, group represents # the spec's group, pretty_include is the name of the capitalized header (for example ClientGenerator), # namespace is the C++ namespace the generated header will belong to. This function also accepts # as an optional last argument a list of additional command line arguments which will be passed to # qt-client-gen.py upon execution. After issuing DEPENDS in the last argument you can pass a list of targets # the generated target will depend on. # # function TPQT_FUTURE_CLIENT_GENERATOR(spec namespace [arguments] [DEPENDS dependencies ...]) # Same as tpqt_client_generator, but for future interfaces # # function TPQT_SERVICE_GENERATOR(spec group pretty_include namespace [arguments] [DEPENDS dependencies ...]) # This function takes care of invoking qt-svc-gen.py with the correct arguments, which generates # headers out of specs. spec is the name of the spec headers will be generated from, group represents # the spec's group, pretty_include is the name of the capitalized header (for example ServiceGenerator), # namespace is the C++ namespace the generated header will belong to. This function also accepts # as an optional last argument a list of additional command line arguments which will be passed to # qt-svc-gen.py upon execution. After issuing DEPENDS in the last argument you can pass a list of targets # the generated target will depend on. # # function TPQT_GENERATE_MANAGER_FILE(MANAGER_FILE OUTPUT_FILENAME DEPEND_FILENAME) # This function takes care of invoking manager-file.py with the correct arguments. The first argument is the # path to the manager-file.py file which should be used, the second is the output filename of the manager, # and the third is the path to the file which depends on the generated manager file. # # function TPQT_XINCLUDATOR (TARGET_NAME INPUT_FILE OUTPUT_FILE [additional_arguments ...] [DEPENDS dependencies ...]) # This function takes care of invoking xincludator.py with the correct arguments. TARGET_NAME is the name of # the generated target (see preamble), INPUT_FILE is the input spec file, OUTPUT_FILE is the filename # the generated file will be saved to. This function also accepts as an optional last argument a list of # additional command line arguments which will be passed to xincludator upon execution. # After issuing DEPENDS in the last argument you can pass a list of targets the generated target will depend on. # # function TPQT_CONSTANTS_GEN (TARGET_NAME SPEC_XML OUTPUT_FILE [additional_arguments ...] [DEPENDS dependencies ...]) # This function takes care of invoking qt-constants-gen.py with the correct arguments. TARGET_NAME is the name of # the generated target (see preamble), SPEC_XML is the spec input file, OUTPUT_FILE is the filename # the generated file will be saved to. This function also accepts as an optional last argument a list of # additional command line arguments which will be passed to qt-constants-gen.py upon execution. # After issuing DEPENDS in the last argument you can pass a list of targets the generated target will depend on. # # function TPQT_TYPES_GEN (TARGET_NAME SPEC_XML OUTFILE_DECL OUTFILE_IMPL NAMESPACE # REAL_INCLUDE PRETTY_INCLUDE [additional_arguments ...] [DEPENDS dependencies ...]) # This function takes care of invoking qt-types-gen.py with the correct arguments. TARGET_NAME is the name of # the generated target (see preamble), SPEC_XML is the input spec file, OUTFILE_DECL is the filename # the header of the generated file will be saved to, OUTFILE_IMPL is the filename the implementation of the # generated file will be saved to, NAMESPACE is the C++ namespace the generated header will belong to, # REAL_INCLUDE is the real include file you want to use, PRETTY_INCLUDE is the name of the capitalized header # (for example ClientGenerator). # This function also accepts as an optional last argument a list of additional command line arguments # which will be passed to qt-constants-gen.py upon execution. # After issuing DEPENDS in the last argument you can pass a list of targets the generated target will depend on. # # macro TPQT_ADD_GENERIC_UNIT_TEST (fancyName name [libraries ...]) # This macro takes care of building and adding a generic unit test to the automatic CTest suite. The requirement # for using this macro is to have the unit test contained in a single source file named ${name}.cpp. fancyName will # be used as the test and target's name, and you can specify as a third and optional argument a set of additional # libraries the target will link to. # # macro TPQT_ADD_DBUS_UNIT_TEST (fancyName name [libraries ...]) # This macro takes care of building and adding an unit test requiring DBus emulation to the automatic # CTest suite. The requirement for using this macro is to have the unit test contained in a single # source file named ${name}.cpp. fancyName will be used as the test and target's name, and you can specify as a third # and optional argument a set of additional libraries the target will link to. Please remember that you need to # set up the DBus environment by calling TPQT_SETUP_DBUS_TEST_ENVIRONMENT BEFORE you call this macro. # # macro _TPQT_ADD_CHECK_TARGETS (fancyName name command [args]) # This is an internal macro which is meant to be used by TPQT_ADD_DBUS_UNIT_TEST and TPQT_ADD_GENERIC_UNIT_TEST. # It takes care of generating a check target for each test method available (currently normal execution, valgrind and # callgrind). This macro accepts the same arguments as the add test macros, but accepts a command and a list of # arguments for running the test instead of the link libraries. However, you are not meant to call this macro from # your CMakeLists.txt files. # # function TPQT_SETUP_DBUS_TEST_ENVIRONMENT () # This function MUST be called before calling TPQT_ADD_DBUS_UNIT_TEST. It takes care of preparing the test # environment for DBus tests and generating the needed files. # # macro MAKE_INSTALL_PATH_ABSOLUTE (out in) # This macro makes the path given in the "in" variable absolute (or leaves it unchanged # if it's absolute already) by prefixing it with TELEPATHY_QT_INSTALL_DIR, # and returns the absolute path in the "out" variable. This macro is mainly used for # generating *Config.cmake files. # # MACRO (TPQT_EXTRACT_DEPENDS _tpqt_other _tpqt_depends) SET(${_tpqt_other}) SET(${_tpqt_depends}) SET(_TPQT_DOING_DEPENDS FALSE) FOREACH(_currentArg ${ARGN}) IF ("${_currentArg}" STREQUAL "DEPENDS") SET(_TPQT_DOING_DEPENDS TRUE) ELSE ("${_currentArg}" STREQUAL "DEPENDS") IF(_TPQT_DOING_DEPENDS) LIST(APPEND ${_tpqt_depends} "${_currentArg}") ELSE(_TPQT_DOING_DEPENDS) LIST(APPEND ${_tpqt_other} "${_currentArg}") ENDIF(_TPQT_DOING_DEPENDS) ENDIF ("${_currentArg}" STREQUAL "DEPENDS") ENDFOREACH(_currentArg) ENDMACRO (TPQT_EXTRACT_DEPENDS) # helper function to set up a moc rule FUNCTION (TPQT_CREATE_MOC_COMMAND_TARGET_DEPS infile outfile moc_flags moc_options) # For Windows, create a parameters file to work around command line length limit GET_FILENAME_COMPONENT(_moc_outfile_name "${outfile}" NAME) IF (WIN32) # Pass the parameters in a file. Set the working directory to # be that containing the parameters file and reference it by # just the file name. This is necessary because the moc tool on # MinGW builds does not seem to handle spaces in the path to the # file given with the @ syntax. GET_FILENAME_COMPONENT(_moc_outfile_dir "${outfile}" PATH) IF(_moc_outfile_dir) SET(_moc_working_dir WORKING_DIRECTORY ${_moc_outfile_dir}) ENDIF(_moc_outfile_dir) SET (_moc_parameters_file ${outfile}_parameters) SET (_moc_parameters ${moc_flags} ${moc_options} -o "${outfile}" "${infile}") FILE (REMOVE ${_moc_parameters_file}) FOREACH(arg ${_moc_parameters}) FILE (APPEND ${_moc_parameters_file} "${arg}\n") ENDFOREACH(arg) ADD_CUSTOM_COMMAND(OUTPUT ${outfile} COMMAND ${QT_MOC_EXECUTABLE} @${_moc_outfile_name}_parameters DEPENDS ${infile} ${_moc_working_dir} VERBATIM) ELSE (WIN32) ADD_CUSTOM_COMMAND(OUTPUT ${outfile} COMMAND ${QT_MOC_EXECUTABLE} ARGS ${moc_flags} ${moc_options} -o ${outfile} ${infile} DEPENDS ${infile}) ENDIF (WIN32) add_custom_target(moc-${_moc_outfile_name} DEPENDS ${outfile}) add_dependencies(moc-${_moc_outfile_name} ${ARGN}) ENDFUNCTION (TPQT_CREATE_MOC_COMMAND_TARGET_DEPS) # add the -i option to QT_GENERATE_MOC function(TPQT_GENERATE_MOC_I infile outfile) qt_get_moc_flags(moc_flags) get_filename_component(abs_infile ${infile} ABSOLUTE) qt_create_moc_command(${abs_infile} ${outfile} "${moc_flags}" "-i") set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOMOC TRUE) # dont run automoc on this file endfunction(TPQT_GENERATE_MOC_I) # same as tpqt_generate_moc_i, but lets the caller specify a list of targets which the mocs should depend on function(TPQT_GENERATE_MOC_I_TARGET_DEPS infile outfile) qt_get_moc_flags(moc_flags) get_filename_component(abs_infile ${infile} ABSOLUTE) tpqt_create_moc_command_target_deps(${abs_infile} ${outfile} "${moc_flags}" "-i" ${ARGN}) set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOMOC TRUE) # dont run automoc on this file endfunction(TPQT_GENERATE_MOC_I_TARGET_DEPS) # generates mocs for the passed list. The list should be added to the target's sources function(tpqt_generate_mocs) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_gen" ) foreach(moc_src ${ARGN}) string(REPLACE ".h" ".moc.hpp" generated_file ${moc_src}) tpqt_generate_moc_i(${CMAKE_CURRENT_SOURCE_DIR}/${moc_src} ${CMAKE_CURRENT_BINARY_DIR}/_gen/${generated_file}) set_property(SOURCE ${moc_src} APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_gen/${generated_file}) endforeach(moc_src ${ARGN}) endfunction(tpqt_generate_mocs) function(tpqt_client_generator spec group pretty_include namespace) tpqt_extract_depends(client_generator_args client_generator_depends ${ARGN}) set(ARGS ${CMAKE_SOURCE_DIR}/tools/qt-client-gen.py --group=${group} --namespace=${namespace} --typesnamespace=Tp --headerfile=${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-${spec}.h --implfile=${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-${spec}-body.hpp --realinclude=TelepathyQt/${spec}.h --prettyinclude=TelepathyQt/${pretty_include} --specxml=${CMAKE_CURRENT_BINARY_DIR}/_gen/stable-spec.xml --ifacexml=${CMAKE_CURRENT_BINARY_DIR}/_gen/spec-${spec}.xml --extraincludes=${TYPES_INCLUDE} --must-define=IN_TP_QT_HEADER --visibility=TP_QT_EXPORT ${client_generator_args}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-${spec}.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-${spec}-body.hpp COMMAND ${PYTHON_EXECUTABLE} ARGS ${ARGS} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${CMAKE_SOURCE_DIR}/tools/libqtcodegen.py ${CMAKE_SOURCE_DIR}/tools/qt-client-gen.py) add_custom_target(generate_cli-${spec}-body DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-${spec}-body.hpp) add_dependencies(all-generated-sources generate_cli-${spec}-body) if (client_generator_depends) add_dependencies(generate_cli-${spec}-body ${client_generator_depends}) endif (client_generator_depends) tpqt_generate_moc_i_target_deps(${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-${spec}.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-${spec}.moc.hpp "generate_cli-${spec}-body") endfunction(tpqt_client_generator spec group pretty_include namespace) function(tpqt_future_client_generator spec namespace) tpqt_extract_depends(future_client_generator_args future_client_generator_depends ${ARGN}) set(ARGS ${CMAKE_SOURCE_DIR}/tools/qt-client-gen.py --namespace=${namespace} --typesnamespace=TpFuture --headerfile=${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}.h --implfile=${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}-body.hpp --realinclude=TelepathyQt/future-internal.h --prettyinclude=TelepathyQt/future-internal.h --specxml=${CMAKE_CURRENT_BINARY_DIR}/_gen/future-spec.xml --ifacexml=${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}.xml --extraincludes=${TYPES_INCLUDE} --extraincludes='' --extraincludes='' --visibility=TP_QT_NO_EXPORT ${future_client_generator_args}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}-body.hpp COMMAND ${PYTHON_EXECUTABLE} ARGS ${ARGS} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${CMAKE_SOURCE_DIR}/tools/libqtcodegen.py ${CMAKE_SOURCE_DIR}/tools/qt-client-gen.py) add_custom_target(generate_future-${spec}-body DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}-body.hpp) add_dependencies(all-generated-sources generate_future-${spec}-body) if (future_client_generator_depends) add_dependencies(generate_future-${spec}-body ${future_client_generator_depends}) endif (future_client_generator_depends) tpqt_generate_moc_i_target_deps(${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}.moc.hpp "generate_future-${spec}-body") endfunction(tpqt_future_client_generator spec namespace) function(tpqt_service_generator spec group pretty_include namespace) tpqt_extract_depends(service_generator_args service_generator_depends ${ARGN}) string(REPLACE "svc-" "" spec ${spec}) set(ARGS ${CMAKE_SOURCE_DIR}/tools/qt-svc-gen.py --group=${group} --namespace=${namespace} --typesnamespace=Tp --headerfile=${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-${spec}.h --implfile=${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-${spec}.cpp --realinclude=TelepathyQt/_gen/svc-${spec}.h --mocinclude=TelepathyQt/_gen/svc-${spec}.moc.hpp --specxml=${CMAKE_CURRENT_BINARY_DIR}/_gen/stable-spec.xml --ifacexml=${CMAKE_CURRENT_BINARY_DIR}/_gen/spec-svc-${spec}.xml --visibility=TP_QT_EXPORT ${service_generator_args}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-${spec}.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-${spec}.cpp COMMAND ${PYTHON_EXECUTABLE} ARGS ${ARGS} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${CMAKE_SOURCE_DIR}/tools/libqtcodegen.py ${CMAKE_SOURCE_DIR}/tools/qt-svc-gen.py) add_custom_target(generate_service-${spec}-body DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-${spec}.cpp) add_dependencies(all-generated-service-sources generate_service-${spec}-body) if (service_generator_depends) add_dependencies(generate_service-${spec}-body ${service_generator_depends}) endif (service_generator_depends) tpqt_generate_moc_i_target_deps(${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-${spec}.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-${spec}.moc.hpp "generate_service-${spec}-body") endfunction(tpqt_service_generator spec group pretty_include namespace) # This function is used for generating CM in various examples function(tpqt_generate_manager_file MANAGER_FILE OUTPUT_FILENAME DEPEND_FILENAME) # make_directory is required, otherwise the command won't work!! make_directory(${CMAKE_CURRENT_BINARY_DIR}/_gen) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/param-spec-struct.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/${OUTPUT_FILENAME} COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/manager-file.py ${MANAGER_FILE} _gen DEPENDS ${CMAKE_SOURCE_DIR}/tools/manager-file.py) set_source_files_properties(${DEPEND_FILENAME} PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_gen/param-spec-struct.h) endfunction(tpqt_generate_manager_file MANAGER_FILE) function(tpqt_xincludator _TARGET_NAME _INPUT_FILE _OUTPUT_FILE) tpqt_extract_depends(xincludator_gen_args xincludator_gen_depends ${ARGN}) # Gather all .xml files in TelepathyQt and spec/ and make this target depend on those file(GLOB depends_xml_files ${CMAKE_SOURCE_DIR}/TelepathyQt/*.xml ${CMAKE_SOURCE_DIR}/spec/*.xml) add_custom_command(OUTPUT ${_OUTPUT_FILE} COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/xincludator.py ${_INPUT_FILE} ${xincludator_gen_args} > ${_OUTPUT_FILE} DEPENDS ${CMAKE_SOURCE_DIR}/tools/xincludator.py ${_INPUT_FILE} ${depends_xml_files}) add_custom_target(${_TARGET_NAME} DEPENDS ${_OUTPUT_FILE}) if (xincludator_gen_depends) add_dependencies(${_TARGET_NAME} ${xincludator_gen_depends}) endif (xincludator_gen_depends) endfunction(tpqt_xincludator _TARGET_NAME _INPUT_FILE _OUTPUT_FILE) function(tpqt_constants_gen _TARGET_NAME _SPEC_XML _OUTFILE) tpqt_extract_depends(constants_gen_args constants_gen_depends ${ARGN}) # Gather all .xml files in TelepathyQt and spec/ and make this target depend on those file(GLOB depends_xml_files ${CMAKE_SOURCE_DIR}/TelepathyQt/*.xml ${CMAKE_SOURCE_DIR}/spec/*.xml) add_custom_command(OUTPUT ${_OUTFILE} COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/qt-constants-gen.py ${constants_gen_args} --specxml=${_SPEC_XML} > ${_OUTFILE} DEPENDS ${CMAKE_SOURCE_DIR}/tools/libqtcodegen.py ${CMAKE_SOURCE_DIR}/tools/qt-constants-gen.py ${_SPEC_XML} ${depends_xml_files}) add_custom_target(${_TARGET_NAME} DEPENDS ${_OUTFILE}) add_dependencies(all-generated-sources ${_TARGET_NAME}) if (constants_gen_depends) add_dependencies(${_TARGET_NAME} ${constants_gen_depends}) endif (constants_gen_depends) endfunction (tpqt_constants_gen _TARGET_NAME _SPEC_XML _OUTFILE) function(tpqt_types_gen _TARGET_NAME _SPEC_XML _OUTFILE_DECL _OUTFILE_IMPL _NAMESPACE _REALINCLUDE _PRETTYINCLUDE) tpqt_extract_depends(types_gen_args types_gen_depends ${ARGN}) # Gather all .xml files in TelepathyQt and spec/ and make this target depend on those file(GLOB depends_xml_files ${CMAKE_SOURCE_DIR}/TelepathyQt/*.xml ${CMAKE_SOURCE_DIR}/spec/*.xml) add_custom_command(OUTPUT ${_OUTFILE_DECL} ${_OUTFILE_IMPL} COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/qt-types-gen.py --namespace=${_NAMESPACE} --declfile=${_OUTFILE_DECL} --implfile=${_OUTFILE_IMPL} --realinclude=${_REALINCLUDE} --prettyinclude=${_PRETTYINCLUDE} ${types_gen_args} --specxml=${_SPEC_XML} DEPENDS ${CMAKE_SOURCE_DIR}/tools/libqtcodegen.py ${CMAKE_SOURCE_DIR}/tools/qt-types-gen.py ${_SPEC_XML} ${depends_xml_files}) add_custom_target(${_TARGET_NAME} DEPENDS ${_OUTFILE_IMPL}) add_dependencies(all-generated-sources ${_TARGET_NAME}) if (types_gen_depends) add_dependencies(${_TARGET_NAME} ${types_gen_depends}) endif (types_gen_depends) endfunction(tpqt_types_gen _TARGET_NAME _SPEC_XML _OUTFILE_DECL _OUTFILE_IMPL _NAMESPACE _REALINCLUDE _PRETTYINCLUDE) macro(tpqt_add_generic_unit_test _fancyName _name) tpqt_generate_moc_i(${_name}.cpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/${_name}.cpp.moc.hpp) add_executable(test-${_name} ${_name}.cpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/${_name}.cpp.moc.hpp) target_link_libraries(test-${_name} ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTTEST_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} tp-qt-tests ${TP_QT_EXECUTABLE_LINKER_FLAGS} ${ARGN}) add_test(${_fancyName} ${SH} ${CMAKE_CURRENT_BINARY_DIR}/runGenericTest.sh ${CMAKE_CURRENT_BINARY_DIR}/test-${_name}) list(APPEND _telepathy_qt_test_cases test-${_name}) # Valgrind and Callgrind targets _tpqt_add_check_targets(${_fancyName} ${_name} ${CMAKE_CURRENT_BINARY_DIR}/runGenericTest.sh ${CMAKE_CURRENT_BINARY_DIR}/test-${_name}) endmacro(tpqt_add_generic_unit_test _fancyName _name) macro(tpqt_add_dbus_unit_test _fancyName _name) tpqt_generate_moc_i(${_name}.cpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/${_name}.cpp.moc.hpp) add_executable(test-${_name} ${_name}.cpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/${_name}.cpp.moc.hpp) target_link_libraries(test-${_name} ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTTEST_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} tp-qt-tests ${TP_QT_EXECUTABLE_LINKER_FLAGS} ${ARGN}) set(with_session_bus ${CMAKE_CURRENT_BINARY_DIR}/runDbusTest.sh) add_test(${_fancyName} ${SH} ${with_session_bus} ${CMAKE_CURRENT_BINARY_DIR}/test-${_name}) list(APPEND _telepathy_qt_test_cases test-${_name}) # Valgrind and Callgrind targets _tpqt_add_check_targets(${_fancyName} ${_name} ${with_session_bus} ${CMAKE_CURRENT_BINARY_DIR}/test-${_name}) endmacro(tpqt_add_dbus_unit_test _fancyName _name) macro(_tpqt_add_check_targets _fancyName _name _runnerScript) set_tests_properties(${_fancyName} PROPERTIES FAIL_REGULAR_EXPRESSION "^FAIL!") # Standard check target add_custom_target(check-${_fancyName} ${SH} ${_runnerScript} ${ARGN}) add_dependencies(check-${_fancyName} test-${_name}) # Lcov target add_dependencies(lcov-check test-${_name}) # Valgrind target add_custom_target(check-valgrind-${_fancyName}) add_dependencies(check-valgrind-${_fancyName} test-${_name}) add_custom_command( TARGET check-valgrind-${_fancyName} COMMAND G_SLICE=always-malloc ${SH} ${_runnerScript} /usr/bin/valgrind --tool=memcheck --leak-check=full --leak-resolution=high --child-silent-after-fork=yes --num-callers=20 --gen-suppressions=all --log-file=${CMAKE_CURRENT_BINARY_DIR}/test-${_fancyName}.memcheck.log --suppressions=${CMAKE_SOURCE_DIR}/tools/tp-qt-tests.supp --suppressions=${CMAKE_SOURCE_DIR}/tools/telepathy-glib.supp ${ARGN} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Running valgrind on test \"${_fancyName}\"") add_dependencies(check-valgrind check-valgrind-${_fancyName}) # Callgrind target add_custom_target(check-callgrind-${_fancyName}) add_dependencies(check-callgrind-${_fancyName} test-${_name}) add_custom_command( TARGET check-callgrind-${_fancyName} COMMAND ${SH} ${_runnerScript} /usr/bin/valgrind --tool=callgrind --dump-instr=yes --log-file=${CMAKE_CURRENT_BINARY_DIR}/test-${_fancyName}.callgrind.log --callgrind-out-file=${CMAKE_CURRENT_BINARY_DIR}/test-${_fancyName}.callgrind.out ${ARGN} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Running callgrind on test \"${_fancyName}\"") add_dependencies(check-callgrind check-callgrind-${_fancyName}) endmacro(_tpqt_add_check_targets _fancyName _name) function(tpqt_setup_dbus_test_environment) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/runDbusTest.sh " ${test_environment} sh ${CMAKE_SOURCE_DIR}/tools/with-session-bus.sh \\ --config-file=${CMAKE_BINARY_DIR}/tests/dbus-1/session.conf -- $@ ") endfunction(tpqt_setup_dbus_test_environment) macro(make_install_path_absolute out in) if (IS_ABSOLUTE "${in}") set(${out} "${in}") else (IS_ABSOLUTE "${in}") set(${out} "\${TELEPATHY_QT${QT_VERSION_MAJOR}_INSTALL_DIR}/${in}") endif (IS_ABSOLUTE "${in}") endmacro(make_install_path_absolute out in) telepathy-qt-0.9.6~git1/cmake/modules/FindLibXml2.cmake0000664000175000017500000000356112470405660020561 0ustar jrjr# - Try to find LibXml2 # Once done this will define # # LIBXML2_FOUND - System has LibXml2 # LIBXML2_INCLUDE_DIR - The LibXml2 include directory # LIBXML2_LIBRARIES - The libraries needed to use LibXml2 # LIBXML2_DEFINITIONS - Compiler switches required for using LibXml2 # LIBXML2_XMLLINT_EXECUTABLE - The XML checking tool xmllint coming with LibXml2 # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF (LIBXML2_INCLUDE_DIR AND LIBXML2_LIBRARIES) # in cache already SET(LibXml2_FIND_QUIETLY TRUE) ENDIF (LIBXML2_INCLUDE_DIR AND LIBXML2_LIBRARIES) IF (NOT WIN32) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls FIND_PACKAGE(PkgConfig) PKG_CHECK_MODULES(PC_LIBXML libxml-2.0) SET(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER}) ENDIF (NOT WIN32) FIND_PATH(LIBXML2_INCLUDE_DIR libxml/xpath.h HINTS ${PC_LIBXML_INCLUDEDIR} ${PC_LIBXML_INCLUDE_DIRS} PATH_SUFFIXES libxml2 ) FIND_LIBRARY(LIBXML2_LIBRARIES NAMES xml2 libxml2 HINTS ${PC_LIBXML_LIBDIR} ${PC_LIBXML_LIBRARY_DIRS} ) FIND_PROGRAM(LIBXML2_XMLLINT_EXECUTABLE xmllint) # for backwards compat. with KDE 4.0.x: SET(XMLLINT_EXECUTABLE "${LIBXML2_XMLLINT_EXECUTABLE}") IF( NOT LIBXML2_XMLLINT_EXECUTABLE ) MESSAGE(STATUS "xmllint program not found. Install it if you want validate generated doc file.") ENDIF(NOT LIBXML2_XMLLINT_EXECUTABLE ) INCLUDE(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LIBXML2_FOUND to TRUE if # all listed variables are TRUE FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARIES LIBXML2_INCLUDE_DIR) MARK_AS_ADVANCED(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARIES LIBXML2_XMLLINT_EXECUTABLE) telepathy-qt-0.9.6~git1/HACKING0000664000175000017500000001136412470405660013744 0ustar jrjrContents: • Version control • Coding style... › ...for C++ code › ...for C and Python code • Submitting patches =============================================================================== Version control =============================================================================== The current development version of telepathy-qt is available from the 'master' branch in the git repository: (for committers) (cgit) Stable branches are available from branches with names like 'telepathy-qt-0.2' in the same repository. =============================================================================== Coding style =============================================================================== For C++ code: ------------- TelepathyQt uses the standard Qt coding style for the Qt/C++ code, as also followed by eg. KDELibs. The coding style is described in more detail in the KDE TechBase at ; in short, it amounts to: * 4 spaces for indentation (no tabs, anywhere) * javaCase for variables and functions (incl. members), FullCamelCase for types * No abbreviations, except for 100% standard ones like regex, refcount, etc. * Type &var and Type *var, not Type& var and Type* var for pointers and refs * Use only one empty line to separate both groups of related statements AND function & class bodies * Use a space after each keyword but none after opening parens (if (true)) * No spaces between the function name and the parens for the parameter list * Surround binary operators with spaces, but don't put spaces between a unary operator and their operand * For function bodies, put the opening curly brace on its own line. For everything else, put the opening curly brace in the same line as the statement (if, for, etc.) associated with it. * Use curly braces even for single-line bodies of conditional statements and loops * Prefer static_cast, const_cast etc over C-style casts * Wrap long lines to 100 characters at most * Use foreach, emit instead of Q_FOREACH/Q_EMIT * Don't write long (> ~5 lines) inline methods unless they are needed because of eg. template * Don't use references to QObjects * Destroy transient objects such as method call watchers as soon as possible rather than accumulating them to long-lived parent objects * Documentation should be in the source file instead of the header file * Public xxxInterface methods' definitions should be added to the end of the public methods declaration. * Always add friend struct Private declaration on classes that have Private structure. * Always add Q_DISABLE_COPY(xxx) to classes that cannot be copied. * Q_DISABLE_COPY(xxx) declaration must be placed on the top of the class definition, before the public keyword. * Methods should be ordered as follows: public public Q_SLOTS Q_SIGNALS protected protected Q_SLOTS private Q_SLOTS private * friend class xxx definitions must be placed right below the private keyword. * All exported classes should use TP_QT_EXPORT macro as following: class TP_QT_EXPORT xxx { ... }; * Every issue in APIs which can (or will) only be fixed later should be marked with a doxygen \todo and have a corresponding fd.o bug filed and mentioned in the \todo annotation For C and Python code: ---------------------- Parts of the regression tests — namely, those parts in tests/lib/glib/ — are taken from telepathy-glib, and are written in C; the majority of the code generation tools — in tools/ — are written in Python. Please follow for these. =============================================================================== Submitting patches =============================================================================== Patches should be made as (preferably) git branches or (last resort) -uNr diffs against upstream git master, as found at: git://anongit.freedesktop.org/telepathy/telepathy-qt ssh://git.freedesktop.org/git/telepathy/telepathy-qt (for committers) http://cgit.freedesktop.org/telepathy/telepathy-qt/ (cgit) Patches can be announced at the freedesktop.org bugzilla, using the product "Telepathy" and component "tp-qt": https://bugs.freedesktop.org/enter_bug.cgi?product=Telepathy&component=tp-qt If submitting a Git branch, please set the URL field of the bug to point to your Git branch. Regardless of whether you are referring to a Git branch or attaching patches, please specify the "patch" keyword on the bug. For details on the code review procedure, see: http://telepathy.freedesktop.org/wiki/Review%20Procedure telepathy-qt-0.9.6~git1/doxygen.css0000664000175000017500000001317012470405660015141 0ustar jrjrbody, table, div, p, dl { font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; font-size: 12px; } /* @group Heading Levels */ h1 { text-align: center; font-size: 150%; } h2 { font-size: 110%; font-weight: bold; } h3 { font-size: 100%; } h3.version { font-size: 100%; text-align: center; } /* @end */ caption { font-weight: bold; } div.title{ font-size: 150%; text-align: center; margin: 2px; padding: 2px; } div.qindex, div.navtab{ background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; padding: 2px; } div.qindex, div.navpath { width: 100%; line-height: 140%; } div.navtab { margin-right: 15px; } /* @group Link Styling */ a { color: #153788; font-weight: normal; text-decoration: none; } .contents a:visited { color: #1b77c5; } a:hover { text-decoration: underline; } a.qindex { font-weight: bold; } a.qindexHL { font-weight: bold; background-color: #6666cc; color: #ffffff; border: 1px double #9295C2; } .contents a.qindexHL:visited { color: #ffffff; } a.el { } a.elRef { } a.code { } a.codeRef { } /* @end */ dl.el { margin-left: -1cm; } .fragment { font-family: monospace, fixed; font-size: 100%; } pre.fragment { border: 1px solid #CCCCCC; background-color: #f5f5f5; padding: 4px 6px; margin: 4px 8px 4px 2px; } div.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } div.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold; } div.groupText { margin-left: 16px; font-style: italic; } body { background: white; color: black; margin-right: 20px; margin-left: 20px; } td.indexkey { background-color: #e8eef2; font-weight: bold; border: 1px solid #CCCCCC; margin: 2px 0px 2px 0; padding: 2px 10px; } td.indexvalue { background-color: #e8eef2; border: 1px solid #CCCCCC; padding: 2px 10px; margin: 2px 0px; } tr.memlist { background-color: #f0f0f0; } p.formulaDsp { text-align: center; } img.formulaDsp { } img.formulaInl { vertical-align: middle; } /* @group Code Colorization */ span.keyword { color: #008000 } span.keywordtype { color: #604020 } span.keywordflow { color: #e08000 } span.comment { color: #800000 } span.preprocessor { color: #806020 } span.stringliteral { color: #002080 } span.charliteral { color: #008080 } span.vhdldigit { color: #ff00ff } span.vhdlchar { color: #000000 } span.vhdlkeyword { color: #700070 } span.vhdllogic { color: #ff0000 } /* @end */ .search { color: #003399; font-weight: bold; } form.search { margin-bottom: 0px; margin-top: 0px; } input.search { font-size: 75%; color: #000080; font-weight: normal; background-color: #e8eef2; } td.tiny { font-size: 75%; } .dirtab { padding: 4px; border-collapse: collapse; border: 1px solid #84b0c7; } th.dirtab { background: #e8eef2; font-weight: bold; } hr { height: 0; border: none; border-top: 1px solid #666; } /* @group Member Descriptions */ .mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams { background-color: #FAFAFA; border: none; margin: 4px; padding: 1px 0 0 8px; } .mdescLeft, .mdescRight { padding: 0px 8px 4px 8px; color: #555; } .memItemLeft, .memItemRight, .memTemplParams { border-top: 1px solid #ccc; } .memTemplParams { color: #606060; } /* @end */ /* @group Member Details */ /* Styles for detailed member documentation */ .memtemplate { font-size: 80%; color: #606060; font-weight: normal; margin-left: 3px; } .memnav { background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } .memitem { padding: 0; } .memname { white-space: nowrap; font-weight: bold; } .memproto { padding: 0; background-color: #d5e1e8; font-weight: bold; border: 1px solid #84b0c7; } .memdoc { padding: 2px 5px; border-top-width: 0; } .paramkey { text-align: right; } .paramtype { white-space: nowrap; } .paramname { color: #602020; white-space: nowrap; } .paramname em { font-style: normal; } /* @end */ /* @group Directory (tree) */ /* for the tree view */ .ftvtree { font-family: sans-serif; margin: 0.5em; } /* these are for tree view when used as main index */ .directory { font-size: 9pt; font-weight: bold; } .directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } /* The following two styles can be used to replace the root node title with an image of your choice. Simply uncomment the next two styles, specify the name of your image and be sure to set 'height' to the proper pixel height of your image. */ /* .directory h3.swap { height: 61px; background-repeat: no-repeat; background-image: url("yourimage.gif"); } .directory h3.swap span { display: none; } */ .directory > h3 { margin-top: 0; } .directory p { margin: 0px; white-space: nowrap; } .directory div { display: none; margin: 0px; } .directory img { vertical-align: -30%; } /* these are for tree view when not used as main index */ .directory-alt { font-size: 100%; font-weight: bold; } .directory-alt h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } .directory-alt > h3 { margin-top: 0; } .directory-alt p { margin: 0px; white-space: nowrap; } .directory-alt div { display: none; margin: 0px; } .directory-alt img { vertical-align: -30%; } /* @end */ address { font-style: normal; color: #333; } div.rationale:before { content: "Rationale:"; display: block; font-weight: bold; font-size: 0.85em; } div.rationale { font-style: italic; border-left: 0.25em solid #808080; padding-left: 0.5em; } div.rationale p { font-size: 0.85em; } telepathy-qt-0.9.6~git1/tests/0000775000175000017500000000000012470405660014112 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/0000775000175000017500000000000012470405660014660 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/test.cpp0000664000175000017500000000575212470405660016354 0ustar jrjr#include "tests/lib/test.h" #include #include #include #include #include #include #include #include using Tp::PendingOperation; using Tp::PendingVoid; using Tp::Client::DBus::PeerInterface; Test::Test(QObject *parent) : QObject(parent), mLoop(new QEventLoop(this)) { QTimer::singleShot(10 * 60 * 1000, this, SLOT(onWatchdog())); } Test::~Test() { delete mLoop; } void Test::initTestCaseImpl() { Tp::registerTypes(); Tp::enableDebug(true); Tp::enableWarnings(true); QVERIFY(QDBusConnection::sessionBus().isConnected()); } void Test::initImpl() { } void Test::cleanupImpl() { } void Test::cleanupTestCaseImpl() { // To allow for cleanup code to run (e.g. PendingOperation cleanup after they finish) mLoop->processEvents(); } void Test::expectSuccessfulCall(PendingOperation *op) { if (op->isError()) { qWarning().nospace() << op->errorName() << ": " << op->errorMessage(); mLoop->exit(1); return; } mLoop->exit(0); } void Test::expectSuccessfulCall(QDBusPendingCallWatcher *watcher) { if (watcher->isError()) { qWarning().nospace() << watcher->error().name() << ": " << watcher->error().message(); mLoop->exit(1); return; } mLoop->exit(0); } void Test::expectFailure(PendingOperation *op) { if (!op->isError()) { qWarning() << "expectFailure(): should have been an error, but wasn't"; mLastError = QString(); mLastErrorMessage = QString(); mLoop->exit(1); return; } mLastError = op->errorName(); mLastErrorMessage = op->errorMessage(); mLoop->exit(0); } void Test::expectSuccessfulProperty(PendingOperation *op) { if (op->isError()) { qWarning().nospace() << op->errorName() << ": " << op->errorMessage(); mPropertyValue = QVariant(); mLoop->exit(1001); } else { Tp::PendingVariant *pv = qobject_cast(op); mPropertyValue = pv->result(); mLoop->exit(1000); } } void Test::processDBusQueue(Tp::DBusProxy *proxy) { // Call method Ping on the D-Bus Peer interface PeerInterface peer(proxy); PendingVoid *call = new PendingVoid(peer.Ping(), Tp::SharedPtr()); // Wait for the reply to the Ping call while (!call->isFinished()) { mLoop->processEvents(); } QVERIFY(call->isFinished()); QVERIFY(call->isValid()); // Do one more processEvents so the PendingVoid is always freed mLoop->processEvents(); } void Test::onWatchdog() { // We can't use QFAIL because the test would then go to cleanup() and/or cleanupTestCase(), // which would often hang too - so let's just use abort qWarning() << "Test took over 10 minutes to finish, it's probably hung up - aborting"; std::abort(); } #include "_gen/test.h.moc.hpp" telepathy-qt-0.9.6~git1/tests/lib/CMakeLists.txt0000664000175000017500000000163112470405660017421 0ustar jrjrinclude_directories( ${CMAKE_CURRENT_BINARY_DIR}) set(tp_qt_tests_SRCS test.cpp test-thread-helper.cpp ) set(tp_qt_tests_MOC_SRCS test.h test-thread-helper.h ) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_gen") foreach(moc_src ${tp_qt_tests_MOC_SRCS}) set(generated_file _gen/${moc_src}) string(REPLACE ".h" ".h.moc.hpp" generated_file ${generated_file}) tpqt_generate_moc_i(${CMAKE_CURRENT_SOURCE_DIR}/${moc_src} ${CMAKE_CURRENT_BINARY_DIR}/${generated_file}) list(APPEND tp_qt_tests_SRCS ${CMAKE_CURRENT_BINARY_DIR}/${generated_file}) endforeach(moc_src ${tp_qt_tests_MOC_SRCS}) add_library(tp-qt-tests ${tp_qt_tests_SRCS}) target_link_libraries(tp-qt-tests ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} telepathy-qt${QT_VERSION_MAJOR}) if(ENABLE_TP_GLIB_TESTS) add_subdirectory(glib) add_subdirectory(glib-helpers) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/python/0000775000175000017500000000000012470405660016201 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/python/account-manager.py0000775000175000017500000003724312470405660021633 0ustar jrjr#!/usr/bin/python # # A small implementation of a Telepathy AccountManager. import sys import re import dbus from dbus.bus import NAME_FLAG_DO_NOT_QUEUE, REQUEST_NAME_REPLY_EXISTS from dbus.mainloop.glib import DBusGMainLoop from dbus.service import Object, method, signal from gobject import MainLoop TP = 'org.freedesktop.Telepathy' AM_IFACE = TP + '.AccountManager' AM_BUS_NAME = AM_IFACE AM_OBJECT_PATH = '/' + AM_IFACE.replace('.', '/') ACCOUNT_IFACE = TP + '.Account' ACCOUNT_IFACE_AVATAR_IFACE = ACCOUNT_IFACE + '.Interface.Avatar' ACCOUNT_OBJECT_PATH_BASE = '/' + ACCOUNT_IFACE.replace('.', '/') + '/' Connection_Status_Connected = dbus.UInt32(0) Connection_Status_Connecting = dbus.UInt32(1) Connection_Status_Disconnected = dbus.UInt32(2) Connection_Status_Reason_None_Specified = dbus.UInt32(0) Connection_Status_Reason_Requested = dbus.UInt32(1) Connection_Status_Reason_Network_Error = dbus.UInt32(2) Connection_Presence_Type_Offline = dbus.UInt32(1) Connection_Presence_Type_Available = dbus.UInt32(2) VALID_CONNECTION_MANAGER_NAME = re.compile(r'^[A-Za-z0-9][_A-Za-z0-9]+$') VALID_PROTOCOL_NAME = re.compile(r'^[A-Za-z0-9][-A-Za-z0-9]+$') TELEPATHY_ERROR = "org.freedesktop.Telepathy.Error" TELEPATHY_ERROR_DISCONNECTED = TELEPATHY_ERROR + ".Disconnected" TELEPATHY_ERROR_CANCELLED = TELEPATHY_ERROR + ".Cancelled" TELEPATHY_ERROR_NETWORK_ERROR = TELEPATHY_ERROR + ".NetworkError" class AccountManager(Object): def __init__(self, bus=None): #: map from object path to Account self._valid_accounts = {} #: map from object path to Account self._invalid_accounts = {} if bus is None: bus = dbus.SessionBus() ret = bus.request_name(AM_BUS_NAME, NAME_FLAG_DO_NOT_QUEUE) if ret == REQUEST_NAME_REPLY_EXISTS: raise dbus.NameExistsException(AM_BUS_NAME) Object.__init__(self, bus, AM_OBJECT_PATH) def _am_props(self): return dbus.Dictionary({ 'Interfaces': dbus.Array([], signature='s'), 'ValidAccounts': dbus.Array(self._valid_accounts.keys(), signature='o'), 'InvalidAccounts': dbus.Array(self._invalid_accounts.keys(), signature='o'), 'SupportedAccountProperties': dbus.Array([ACCOUNT_IFACE + '.Enabled'], signature='s'), }, signature='sv') @method(dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}') def GetAll(self, iface): if iface == AM_IFACE: return self._am_props() else: raise ValueError('No such interface') @method(dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v') def Get(self, iface, prop): if iface == AM_IFACE: props = self._am_props() else: raise ValueError('No such interface') if prop in props: return props[prop] else: raise ValueError('No such property') @method(dbus.PROPERTIES_IFACE, in_signature='ssv') def Set(self, iface, prop, value): raise NotImplementedError('No mutable properties') @signal(AM_IFACE, signature='ob') def AccountValidityChanged(self, path, valid): if valid: assert path in self._invalid_accounts assert path not in self._valid_accounts self._valid_accounts[path] = self._invalid_accounts.pop(path) else: assert path in self._valid_accounts assert path not in self._invalid_accounts self._invalid_accounts[path] = self._valid_accounts.pop(path) print "Emitting AccountValidityChanged(%s, %s)" % (path, valid) @signal(AM_IFACE, signature='o') def AccountRemoved(self, path): assert path in self._valid_accounts or path in self._invalid_accounts self._valid_accounts.pop(path, None) self._invalid_accounts.pop(path, None) print "Emitting AccountRemoved(%s)" % path @method(AM_IFACE, in_signature='sssa{sv}a{sv}', out_signature='o') def CreateAccount(self, cm, protocol, display_name, parameters, properties): if not VALID_CONNECTION_MANAGER_NAME.match(cm): raise ValueError('Invalid CM name') if not VALID_PROTOCOL_NAME.match(protocol): raise ValueError('Invalid protocol name') if properties: raise ValueError('This AM does not support setting properties at' 'account creation') base = ACCOUNT_OBJECT_PATH_BASE + cm + '/' + protocol.replace('-', '_') # FIXME: This is a stupid way to generate the paths - we should # incorporate the display name somehow. However, it's spec-compliant i = 0 while 1: path = '%s/Account%d' % (base, i) if (path not in self._valid_accounts and path not in self._invalid_accounts): account = Account(self, path, '%s (account %d)' % (display_name, i), parameters) # put it in the wrong set and move it to the right one - # that's probably the simplest implementation if account._is_valid(): self._invalid_accounts[path] = account self.AccountValidityChanged(path, True) assert path not in self._invalid_accounts assert path in self._valid_accounts else: self._valid_accounts[path] = account self.AccountValidityChanged(path, False) assert path not in self._valid_accounts assert path in self._invalid_accounts return path i += 1 raise AssertionError('Not reached') class Account(Object): def __init__(self, am, path, display_name, parameters): Object.__init__(self, am.connection, path) self._am = am self._connection = dbus.ObjectPath('/') self._connection_status = Connection_Status_Disconnected self._connection_status_reason = Connection_Status_Reason_None_Specified self._connection_error = u'' self._connection_error_details = dbus.Dictionary({}, signature='sv') self._service = u'' self._display_name = display_name self._icon = u'bob.png' self._enabled = True self._nickname = u'Bob' self._parameters = parameters self._has_been_online = False self._connect_automatically = False self._normalized_name = u'bob' self._automatic_presence = dbus.Struct( (Connection_Presence_Type_Available, 'available', ''), signature='uss') self._current_presence = dbus.Struct( (Connection_Presence_Type_Offline, 'offline', ''), signature='uss') self._requested_presence = dbus.Struct( (Connection_Presence_Type_Offline, 'offline', ''), signature='uss') self._avatar = dbus.Struct( (dbus.ByteArray(''), 'image/png'), signature='ays') self._interfaces = [ACCOUNT_IFACE_AVATAR_IFACE,] def _is_valid(self): return True @method(ACCOUNT_IFACE, in_signature='a{sv}as', out_signature='as') def UpdateParameters(self, set_, unset): print ("%s: entering UpdateParameters(\n %r,\n %r \n)" % (self.__dbus_object_path__, set_, unset)) for (key, value) in set_.iteritems(): self._parameters[key] = value for key in unset: self._parameters.pop(key, None) print ("%s: UpdateParameters(...) -> success" % self.__dbus_object_path__) self.AccountPropertyChanged({'Parameters': self._parameters}) return [] @signal(ACCOUNT_IFACE, signature='a{sv}') def AccountPropertyChanged(self, delta): print ("%s: emitting AccountPropertyChanged(\n %r \n)" % (self.__dbus_object_path__, delta)) @signal(ACCOUNT_IFACE_AVATAR_IFACE, signature='') def AvatarChanged(self): print ("%s: emitting AvatarChanged" % (self.__dbus_object_path__)) @method(ACCOUNT_IFACE, in_signature='', out_signature='') def Remove(self): print "%s: entering Remove()" % self.__dbus_object_path__ self.Removed() self.remove_from_connection() print "%s: Remove() -> success" % self.__dbus_object_path__ @signal(ACCOUNT_IFACE, signature='') def Removed(self): self._am.AccountRemoved(self.__dbus_object_path__) print "%s: Emitting Removed()" % self.__dbus_object_path__ def _account_props(self): return dbus.Dictionary({ 'Interfaces': dbus.Array(self._interfaces, signature='s'), 'Service': self._service, 'DisplayName': self._display_name, 'Icon': self._icon, 'Valid': self._is_valid(), 'Enabled': self._enabled, 'Nickname': self._nickname, 'Parameters': self._parameters, 'AutomaticPresence': self._automatic_presence, 'CurrentPresence': self._current_presence, 'RequestedPresence': self._requested_presence, 'HasBeenOnline': self._has_been_online, 'ConnectAutomatically': self._connect_automatically, 'Connection': self._connection, 'ConnectionStatus': self._connection_status, 'ConnectionStatusReason': self._connection_status_reason, 'ConnectionError': self._connection_error, 'ConnectionErrorDetails': self._connection_error_details, 'NormalizedName': self._normalized_name, }, signature='sv') def _account_avatar_props(self): return dbus.Dictionary({ 'Avatar': self._avatar }, signature='sv') @method(dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}') def GetAll(self, iface): if iface == ACCOUNT_IFACE: return self._account_props() elif iface == ACCOUNT_IFACE_AVATAR_IFACE: return self._account_avatar_props() else: raise ValueError('No such interface') @method(dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v') def Get(self, iface, prop): if iface == ACCOUNT_IFACE: props = self._account_props() elif iface == ACCOUNT_IFACE_AVATAR_IFACE: props = self._account_avatar_props() else: raise ValueError('No such interface') if prop in props: return props[prop] else: raise ValueError('No such property') @method(dbus.PROPERTIES_IFACE, in_signature='ssv', byte_arrays=True) def Set(self, iface, prop, value): if iface == ACCOUNT_IFACE: props = {} if prop == 'Service': self._service = unicode(value) elif prop == 'DisplayName': self._display_name = unicode(value) elif prop == 'Icon': self._icon = unicode(value) elif prop == 'Enabled': self._enabled = bool(value) elif prop == 'Nickname': self._nickname = unicode(value) elif prop == 'AutomaticPresence': self._automatic_presence = dbus.Struct( (dbus.UInt32(value[0]), unicode(value[1]), unicode(value[2])), signature='uss') elif prop == 'RequestedPresence': self._requested_presence = dbus.Struct( (dbus.UInt32(value[0]), unicode(value[1]), unicode(value[2])), signature='uss') # pretend to put the account online, if the presence != offline if value[0] != Connection_Presence_Type_Offline: # simulate that we are connecting/changing presence props["ChangingPresence"] = True if self._connection_status == Connection_Status_Disconnected: self._connection_status = Connection_Status_Connecting props["ConnectionStatus"] = self._connection_status props[prop] = self._account_props()[prop] self.AccountPropertyChanged(props) props["ChangingPresence"] = False if "(deny)" in self._requested_presence[2]: self._connection_status = Connection_Status_Disconnected self._connection_status_reason = Connection_Status_Reason_Network_Error self._connection_error = TELEPATHY_ERROR_NETWORK_ERROR self._connection_error_details = dbus.Dictionary( {'debug-message': u'You asked for it'}, signature='sv') self._current_presence = dbus.Struct( (Connection_Presence_Type_Offline, 'offline', ''), signature='uss') else: self._connection_status = Connection_Status_Connected self._connection_status_reason = Connection_Status_Reason_None_Specified self._connection_error = u'' self._connection_error_details = dbus.Dictionary({}, signature='sv') self._current_presence = self._requested_presence if self._has_been_online == False: self._has_been_online = True props["HasBeenOnline"] = self._has_been_online else: self._connection_status = Connection_Status_Disconnected self._connection_status_reason = Connection_Status_Reason_Requested self._connection_error = TELEPATHY_ERROR_CANCELLED self._connection_error_details = dbus.Dictionary( {'debug-message': u'You asked for it'}, signature='sv') self._current_presence = dbus.Struct( (Connection_Presence_Type_Offline, 'offline', ''), signature='uss') props["ConnectionStatus"] = self._connection_status props["ConnectionStatusReason"] = self._connection_status_reason props["ConnectionError"] = self._connection_error props["ConnectionErrorDetails"] = self._connection_error_details props["CurrentPresence"] = self._current_presence elif prop == 'ConnectAutomatically': self._connect_automatically = bool(value) elif prop == 'Connection': self._connection = dbus.ObjectPath(value) else: raise ValueError('Read-only or nonexistent property') props[prop] = self._account_props()[prop] self.AccountPropertyChanged(props) elif iface == ACCOUNT_IFACE_AVATAR_IFACE: if prop == 'Avatar': self._avatar = dbus.Struct( (dbus.ByteArray(value[0]), unicode(value[1])), signature='ays') self.AvatarChanged() else: raise ValueError('Nonexistent property') else: raise ValueError('No such interface') if __name__ == '__main__': DBusGMainLoop(set_as_default=True) try: am = AccountManager() except dbus.NameExistsException: print >> sys.stderr, 'AccountManager already running' sys.exit(1) print "AccountManager running..." mainloop = MainLoop() mainloop.run() telepathy-qt-0.9.6~git1/tests/lib/glib/0000775000175000017500000000000012470405660015575 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/simple-account-manager.c0000664000175000017500000001264612470405660022305 0ustar jrjr/* * simple-account-manager.c - a simple account manager service. * * Copyright (C) 2007-2009 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "simple-account-manager.h" #include #include #include #include static void account_manager_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (TpTestsSimpleAccountManager, tp_tests_simple_account_manager, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_ACCOUNT_MANAGER, account_manager_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init) ) /* TP_IFACE_ACCOUNT_MANAGER is implied */ static const char *ACCOUNT_MANAGER_INTERFACES[] = { NULL }; static gchar *VALID_ACCOUNTS[] = { "/org/freedesktop/Telepathy/Account/fakecm/fakeproto/validaccount", NULL }; static gchar *INVALID_ACCOUNTS[] = { "/org/freedesktop/Telepathy/Account/fakecm/fakeproto/invalidaccount", NULL }; enum { PROP_0, PROP_INTERFACES, PROP_VALID_ACCOUNTS, PROP_INVALID_ACCOUNTS, }; struct _TpTestsSimpleAccountManagerPrivate { int dummy; }; static void tp_tests_simple_account_manager_create_account (TpSvcAccountManager *self, const gchar *in_Connection_Manager, const gchar *in_Protocol, const gchar *in_Display_Name, GHashTable *in_Parameters, GHashTable *in_Properties, DBusGMethodInvocation *context) { const gchar *out_Account = "/some/fake/account/i/think"; tp_svc_account_manager_return_from_create_account (context, out_Account); } static void account_manager_iface_init (gpointer klass, gpointer unused G_GNUC_UNUSED) { #define IMPLEMENT(x) tp_svc_account_manager_implement_##x (\ klass, tp_tests_simple_account_manager_##x) IMPLEMENT (create_account); #undef IMPLEMENT } static void tp_tests_simple_account_manager_init (TpTestsSimpleAccountManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_SIMPLE_ACCOUNT_MANAGER, TpTestsSimpleAccountManagerPrivate); } static void tp_tests_simple_account_manager_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { GPtrArray *accounts; guint i = 0; switch (property_id) { case PROP_INTERFACES: g_value_set_boxed (value, ACCOUNT_MANAGER_INTERFACES); break; case PROP_VALID_ACCOUNTS: accounts = g_ptr_array_new (); for (i=0; VALID_ACCOUNTS[i] != NULL; i++) g_ptr_array_add (accounts, g_strdup (VALID_ACCOUNTS[i])); g_value_take_boxed (value, accounts); break; case PROP_INVALID_ACCOUNTS: accounts = g_ptr_array_new (); for (i=0; INVALID_ACCOUNTS[i] != NULL; i++) g_ptr_array_add (accounts, g_strdup (VALID_ACCOUNTS[i])); g_value_take_boxed (value, accounts); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); break; } } /** * This class currently only provides the minimum for * tp_account_manager_prepare to succeed. This turns out to be only a working * Properties.GetAll(). If we wanted later to check the case where * tp_account_prepare succeeds, we would need to implement an account object * too. */ static void tp_tests_simple_account_manager_class_init ( TpTestsSimpleAccountManagerClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; static TpDBusPropertiesMixinPropImpl am_props[] = { { "Interfaces", "interfaces", NULL }, { "ValidAccounts", "valid-accounts", NULL }, { "InvalidAccounts", "invalid-accounts", NULL }, /* { "SupportedAccountProperties", "supported-account-properties", NULL }, */ { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_ACCOUNT_MANAGER, tp_dbus_properties_mixin_getter_gobject_properties, NULL, am_props }, { NULL }, }; g_type_class_add_private (klass, sizeof (TpTestsSimpleAccountManagerPrivate)); object_class->get_property = tp_tests_simple_account_manager_get_property; param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "In this case we only implement AccountManager, so none.", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_boxed ("valid-accounts", "Valid accounts", "The accounts which are valid on this account. This may be a lie.", TP_ARRAY_TYPE_OBJECT_PATH_LIST, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_VALID_ACCOUNTS, param_spec); param_spec = g_param_spec_boxed ("invalid-accounts", "Invalid accounts", "The accounts which are invalid on this account. This may be a lie.", TP_ARRAY_TYPE_OBJECT_PATH_LIST, G_PARAM_READABLE); g_object_class_install_property (object_class, PROP_INVALID_ACCOUNTS, param_spec); klass->dbus_props_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsSimpleAccountManagerClass, dbus_props_class)); } telepathy-qt-0.9.6~git1/tests/lib/glib/simple-client.h0000664000175000017500000000356612470405660020525 0ustar jrjr/* * simple-client.h - header for a simple client * * Copyright © 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_SIMPLE_CLIENT_H__ #define __TP_TESTS_SIMPLE_CLIENT_H__ #include #include G_BEGIN_DECLS typedef struct _TpTestsSimpleClient TpTestsSimpleClient; typedef struct _TpTestsSimpleClientClass TpTestsSimpleClientClass; struct _TpTestsSimpleClientClass { TpBaseClientClass parent_class; }; struct _TpTestsSimpleClient { TpBaseClient parent; TpObserveChannelsContext *observe_ctx; TpAddDispatchOperationContext *add_dispatch_ctx; TpHandleChannelsContext *handle_channels_ctx; }; GType tp_tests_simple_client_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_SIMPLE_CLIENT \ (tp_tests_simple_client_get_type ()) #define TP_TESTS_SIMPLE_CLIENT(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_SIMPLE_CLIENT, \ TpTestsSimpleClient)) #define TP_TESTS_SIMPLE_CLIENT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_SIMPLE_CLIENT, \ TpTestsSimpleClientClass)) #define SIMPLE_IS_CLIENT(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_SIMPLE_CLIENT)) #define SIMPLE_IS_CLIENT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_SIMPLE_CLIENT)) #define TP_TESTS_SIMPLE_CLIENT_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_SIMPLE_CLIENT, \ TpTestsSimpleClientClass)) TpTestsSimpleClient * tp_tests_simple_client_new (TpDBusDaemon *dbus_daemon, const gchar *name, gboolean uniquify_name); G_END_DECLS #endif /* #ifndef __TP_TESTS_SIMPLE_CONN_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/stream-tube-chan.c0000664000175000017500000005265412470405660021114 0ustar jrjr/* * stream-tube-chan.c - Simple stream tube channel * * Copyright (C) 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "stream-tube-chan.h" #include #include #include #include #include #include #include enum { PROP_SERVICE = 1, PROP_SUPPORTED_SOCKET_TYPES, PROP_PARAMETERS, PROP_STATE, }; enum { SIG_INCOMING_CONNECTION, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = {0, }; struct _TpTestsStreamTubeChannelPrivate { TpTubeChannelState state; GHashTable *supported_socket_types; /* Accepting side */ GSocketService *service; GValue *access_control_param; /* Offering side */ TpSocketAddressType address_type; GValue *address; gchar *unix_address; guint connection_id; TpSocketAccessControl access_control; GHashTable *parameters; gboolean close_on_accept; }; static void destroy_socket_control_list (gpointer data) { GArray *tab = data; g_array_free (tab, TRUE); } static void create_supported_socket_types (TpTestsStreamTubeChannel *self) { TpSocketAccessControl access_control; GArray *unix_tab; g_assert (self->priv->supported_socket_types == NULL); self->priv->supported_socket_types = g_hash_table_new_full (NULL, NULL, NULL, destroy_socket_control_list); /* Socket_Address_Type_Unix */ unix_tab = g_array_sized_new (FALSE, FALSE, sizeof (TpSocketAccessControl), 1); access_control = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; g_array_append_val (unix_tab, access_control); g_hash_table_insert (self->priv->supported_socket_types, GUINT_TO_POINTER (TP_SOCKET_ADDRESS_TYPE_UNIX), unix_tab); } static void tp_tests_stream_tube_channel_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { TpTestsStreamTubeChannel *self = (TpTestsStreamTubeChannel *) object; switch (property_id) { case PROP_SERVICE: g_value_set_string (value, "test-service"); break; case PROP_SUPPORTED_SOCKET_TYPES: g_value_set_boxed (value, self->priv->supported_socket_types); break; case PROP_PARAMETERS: g_value_set_boxed (value, self->priv->parameters); break; case PROP_STATE: g_value_set_uint (value, self->priv->state); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void tp_tests_stream_tube_channel_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { TpTestsStreamTubeChannel *self = (TpTestsStreamTubeChannel *) object; switch (property_id) { case PROP_SUPPORTED_SOCKET_TYPES: self->priv->supported_socket_types = g_value_dup_boxed (value); break; case PROP_PARAMETERS: if (self->priv->parameters != NULL) g_hash_table_destroy (self->priv->parameters); self->priv->parameters = g_value_dup_boxed (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void stream_tube_iface_init (gpointer iface, gpointer data); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (TpTestsStreamTubeChannel, tp_tests_stream_tube_channel, TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_STREAM_TUBE, stream_tube_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_TUBE, NULL); ) /* type definition stuff */ static const char * tp_tests_stream_tube_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_TUBE, NULL }; static void tp_tests_stream_tube_channel_init (TpTestsStreamTubeChannel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), TP_TESTS_TYPE_STREAM_TUBE_CHANNEL, TpTestsStreamTubeChannelPrivate); } static GObject * constructor (GType type, guint n_props, GObjectConstructParam *props) { GObject *object = G_OBJECT_CLASS (tp_tests_stream_tube_channel_parent_class)->constructor ( type, n_props, props); TpTestsStreamTubeChannel *self = TP_TESTS_STREAM_TUBE_CHANNEL (object); if (tp_base_channel_is_requested (TP_BASE_CHANNEL (self))) { self->priv->state = TP_TUBE_CHANNEL_STATE_NOT_OFFERED; self->priv->parameters = tp_asv_new (NULL, NULL); } else { self->priv->state = TP_TUBE_CHANNEL_STATE_LOCAL_PENDING; self->priv->parameters = tp_asv_new ("badger", G_TYPE_UINT, 42, NULL); } if (self->priv->supported_socket_types == NULL) create_supported_socket_types (self); tp_base_channel_register (TP_BASE_CHANNEL (self)); return object; } static void dispose (GObject *object) { TpTestsStreamTubeChannel *self = (TpTestsStreamTubeChannel *) object; if (self->priv->service != NULL) { g_socket_service_stop (self->priv->service); tp_clear_object (&self->priv->service); } tp_clear_pointer (&self->priv->address, tp_g_value_slice_free); tp_clear_pointer (&self->priv->supported_socket_types, g_hash_table_unref); tp_clear_pointer (&self->priv->access_control_param, tp_g_value_slice_free); if (self->priv->unix_address != NULL) g_unlink (self->priv->unix_address); tp_clear_pointer (&self->priv->unix_address, g_free); ((GObjectClass *) tp_tests_stream_tube_channel_parent_class)->dispose ( object); } static void channel_close (TpBaseChannel *channel) { tp_base_channel_destroyed (channel); } static void fill_immutable_properties (TpBaseChannel *chan, GHashTable *properties) { TpBaseChannelClass *klass = TP_BASE_CHANNEL_CLASS ( tp_tests_stream_tube_channel_parent_class); klass->fill_immutable_properties (chan, properties); tp_dbus_properties_mixin_fill_properties_hash ( G_OBJECT (chan), properties, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, "Service", TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, "SupportedSocketTypes", NULL); if (!tp_base_channel_is_requested (chan)) { /* Parameters is immutable only for incoming tubes */ tp_dbus_properties_mixin_fill_properties_hash ( G_OBJECT (chan), properties, TP_IFACE_CHANNEL_INTERFACE_TUBE, "Parameters", NULL); } } static void tp_tests_stream_tube_channel_class_init (TpTestsStreamTubeChannelClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass); GParamSpec *param_spec; static TpDBusPropertiesMixinPropImpl stream_tube_props[] = { { "Service", "service", NULL, }, { "SupportedSocketTypes", "supported-socket-types", NULL }, { NULL } }; static TpDBusPropertiesMixinPropImpl tube_props[] = { { "Parameters", "parameters", NULL, }, { "State", "state", NULL, }, { NULL } }; object_class->constructor = constructor; object_class->get_property = tp_tests_stream_tube_channel_get_property; object_class->set_property = tp_tests_stream_tube_channel_set_property; object_class->dispose = dispose; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_STREAM_TUBE; base_class->interfaces = tp_tests_stream_tube_channel_interfaces; base_class->close = channel_close; base_class->fill_immutable_properties = fill_immutable_properties; /* base_class->target_handle_type is defined in subclasses */ param_spec = g_param_spec_string ("service", "service name", "the service associated with this tube object.", "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SERVICE, param_spec); param_spec = g_param_spec_boxed ( "supported-socket-types", "Supported socket types", "GHashTable containing supported socket types.", TP_HASH_TYPE_SUPPORTED_SOCKET_MAP, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SUPPORTED_SOCKET_TYPES, param_spec); param_spec = g_param_spec_boxed ( "parameters", "Parameters", "parameters of the tube", TP_HASH_TYPE_STRING_VARIANT_MAP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_PARAMETERS, param_spec); param_spec = g_param_spec_uint ( "state", "TpTubeState", "state of the tube", 0, NUM_TP_TUBE_CHANNEL_STATES - 1, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_STATE, param_spec); signals[SIG_INCOMING_CONNECTION] = g_signal_new ("incoming-connection", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_IO_STREAM); tp_dbus_properties_mixin_implement_interface (object_class, TP_IFACE_QUARK_CHANNEL_TYPE_STREAM_TUBE, tp_dbus_properties_mixin_getter_gobject_properties, NULL, stream_tube_props); tp_dbus_properties_mixin_implement_interface (object_class, TP_IFACE_QUARK_CHANNEL_INTERFACE_TUBE, tp_dbus_properties_mixin_getter_gobject_properties, NULL, tube_props); g_type_class_add_private (object_class, sizeof (TpTestsStreamTubeChannelPrivate)); } static void change_state (TpTestsStreamTubeChannel *self, TpTubeChannelState state) { self->priv->state = state; tp_svc_channel_interface_tube_emit_tube_channel_state_changed (self, state); } /* Return the address of the socket which has been shared over the tube */ GSocketAddress * tp_tests_stream_tube_channel_get_server_address (TpTestsStreamTubeChannel *self) { return tp_g_socket_address_from_variant (self->priv->address_type, self->priv->address, NULL); } static gboolean check_address_type (TpTestsStreamTubeChannel *self, TpSocketAddressType address_type, TpSocketAccessControl access_control) { GArray *arr; guint i; arr = g_hash_table_lookup (self->priv->supported_socket_types, GUINT_TO_POINTER (address_type)); if (arr == NULL) return FALSE; for (i = 0; i < arr->len; i++) { if (g_array_index (arr, TpSocketAccessControl, i) == access_control) return TRUE; } return FALSE; } static void stream_tube_offer (TpSvcChannelTypeStreamTube *iface, guint address_type, const GValue *address, guint access_control, GHashTable *parameters, DBusGMethodInvocation *context) { TpTestsStreamTubeChannel *self = (TpTestsStreamTubeChannel *) iface; GError *error = NULL; if (self->priv->state != TP_TUBE_CHANNEL_STATE_NOT_OFFERED) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Tube is not in the not offered state"); goto fail; } if (!check_address_type (self, address_type, access_control)) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Address type not supported with this access control"); goto fail; } self->priv->address_type = address_type; self->priv->address = tp_g_value_slice_dup (address); self->priv->access_control = access_control; g_object_set (self, "parameters", parameters, NULL); change_state (self, TP_TUBE_CHANNEL_STATE_REMOTE_PENDING); tp_svc_channel_type_stream_tube_return_from_offer (context); return; fail: dbus_g_method_return_error (context, error); g_error_free (error); } static void service_incoming_cb (GSocketService *service, GSocketConnection *connection, GObject *source_object, gpointer user_data) { TpTestsStreamTubeChannel *self = user_data; GError *error = NULL; if (self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS) { GCredentials *creds; guchar byte; /* FIXME: we should an async version of this API (bgo #629503) */ creds = tp_unix_connection_receive_credentials_with_byte ( connection, &byte, NULL, &error); g_assert_no_error (error); g_assert_cmpuint (byte, ==, g_value_get_uchar (self->priv->access_control_param)); g_object_unref (creds); } else if (self->priv->access_control == TP_SOCKET_ACCESS_CONTROL_PORT) { GSocketAddress *remote_addr; gchar *host, *remote_host; guint port, remote_port; dbus_g_type_struct_get (self->priv->access_control_param, 0, &host, 1, &port, G_MAXUINT); remote_addr = g_socket_connection_get_remote_address (connection, &error); g_assert_no_error (error); remote_host = g_inet_address_to_string ( g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (remote_addr))); remote_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (remote_addr)); g_assert_cmpuint (remote_port, ==, port); g_assert_cmpstr (remote_host, ==, host); g_free (host); g_free (remote_host); g_object_unref (remote_addr); } tp_svc_channel_type_stream_tube_emit_new_local_connection (self, self->priv->connection_id); self->priv->connection_id++; g_signal_emit (self, signals[SIG_INCOMING_CONNECTION], 0, connection); } static GValue * create_local_socket (TpTestsStreamTubeChannel *self, TpSocketAddressType address_type, TpSocketAccessControl access_control, GError **error) { gboolean success; GSocketAddress *address, *effective_address; GValue *address_gvalue; switch (access_control) { case TP_SOCKET_ACCESS_CONTROL_LOCALHOST: case TP_SOCKET_ACCESS_CONTROL_CREDENTIALS: case TP_SOCKET_ACCESS_CONTROL_PORT: break; default: g_assert_not_reached (); } switch (address_type) { case TP_SOCKET_ADDRESS_TYPE_UNIX: { address = g_unix_socket_address_new (tmpnam (NULL)); break; } case TP_SOCKET_ADDRESS_TYPE_IPV4: case TP_SOCKET_ADDRESS_TYPE_IPV6: { GInetAddress *localhost; localhost = g_inet_address_new_loopback ( address_type == TP_SOCKET_ADDRESS_TYPE_IPV4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6); address = g_inet_socket_address_new (localhost, 0); g_object_unref (localhost); break; } default: g_assert_not_reached (); } self->priv->service = g_socket_service_new (); success = g_socket_listener_add_address ( G_SOCKET_LISTENER (self->priv->service), address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, NULL, &effective_address, NULL); g_assert (success); tp_g_signal_connect_object (self->priv->service, "incoming", G_CALLBACK (service_incoming_cb), self, 0); switch (address_type) { case TP_SOCKET_ADDRESS_TYPE_UNIX: self->priv->unix_address = g_strdup (g_unix_socket_address_get_path ( G_UNIX_SOCKET_ADDRESS (effective_address))); address_gvalue = tp_g_value_slice_new_bytes ( g_unix_socket_address_get_path_len ( G_UNIX_SOCKET_ADDRESS (effective_address)), g_unix_socket_address_get_path ( G_UNIX_SOCKET_ADDRESS (effective_address))); break; case TP_SOCKET_ADDRESS_TYPE_IPV4: case TP_SOCKET_ADDRESS_TYPE_IPV6: address_gvalue = tp_g_value_slice_new_take_boxed ( TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4, dbus_g_type_specialized_construct ( TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4)); dbus_g_type_struct_set (address_gvalue, 0, address_type == TP_SOCKET_ADDRESS_TYPE_IPV4 ? "127.0.0.1" : "::1", 1, g_inet_socket_address_get_port ( G_INET_SOCKET_ADDRESS (effective_address)), G_MAXUINT); break; default: g_assert_not_reached (); } g_object_unref (address); g_object_unref (effective_address); return address_gvalue; } static void stream_tube_accept (TpSvcChannelTypeStreamTube *iface, TpSocketAddressType address_type, TpSocketAccessControl access_control, const GValue *access_control_param, DBusGMethodInvocation *context) { TpTestsStreamTubeChannel *self = (TpTestsStreamTubeChannel *) iface; GError *error = NULL; GValue *address; if (self->priv->state != TP_TUBE_CHANNEL_STATE_LOCAL_PENDING) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Tube is not in the local pending state"); goto fail; } if (!check_address_type (self, address_type, access_control)) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Address type not supported with this access control"); goto fail; } if (self->priv->close_on_accept) { tp_base_channel_close (TP_BASE_CHANNEL (self)); return; } address = create_local_socket (self, address_type, access_control, &error); self->priv->access_control = access_control; self->priv->access_control_param = tp_g_value_slice_dup ( access_control_param); change_state (self, TP_TUBE_CHANNEL_STATE_OPEN); tp_svc_channel_type_stream_tube_return_from_accept (context, address); tp_g_value_slice_free (address); return; fail: dbus_g_method_return_error (context, error); g_error_free (error); } static void stream_tube_iface_init (gpointer iface, gpointer data) { TpSvcChannelTypeStreamTubeClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_type_stream_tube_implement_##x (klass, stream_tube_##x) IMPLEMENT(offer); IMPLEMENT(accept); #undef IMPLEMENT } /* Called to emulate a peer connecting to an offered tube */ void tp_tests_stream_tube_channel_peer_connected (TpTestsStreamTubeChannel *self, GIOStream *stream, TpHandle handle) { GValue *connection_param; if (self->priv->state == TP_TUBE_CHANNEL_STATE_REMOTE_PENDING) change_state (self, TP_TUBE_CHANNEL_STATE_OPEN); g_assert (self->priv->state == TP_TUBE_CHANNEL_STATE_OPEN); switch (self->priv->access_control) { case TP_SOCKET_ACCESS_CONTROL_LOCALHOST: connection_param = tp_g_value_slice_new_static_string ("dummy"); break; case TP_SOCKET_ACCESS_CONTROL_CREDENTIALS: { GError *error = NULL; guchar byte = g_random_int_range (0, G_MAXUINT8); /* FIXME: we should an async version of this API (bgo #629503) */ tp_unix_connection_send_credentials_with_byte ( G_SOCKET_CONNECTION (stream), byte, NULL, &error); g_assert_no_error (error); connection_param = tp_g_value_slice_new_byte (byte); } break; case TP_SOCKET_ACCESS_CONTROL_PORT: { GSocketAddress *addr; GError *error = NULL; addr = g_socket_connection_get_local_address ( G_SOCKET_CONNECTION (stream), &error); g_assert_no_error (error); connection_param = tp_g_value_slice_new_take_boxed ( TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4, dbus_g_type_specialized_construct ( TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4)); dbus_g_type_struct_set (connection_param, 0, "badger", 1, g_inet_socket_address_get_port ( G_INET_SOCKET_ADDRESS (addr)), G_MAXUINT); g_object_unref (addr); } break; default: g_assert_not_reached (); } tp_svc_channel_type_stream_tube_emit_new_remote_connection (self, handle, connection_param, self->priv->connection_id); self->priv->connection_id++; tp_g_value_slice_free (connection_param); } /* Called to emulate a peer connecting to an offered tube */ void tp_tests_stream_tube_channel_peer_connected_no_stream (TpTestsStreamTubeChannel *self, const GValue *connection_param, TpHandle handle) { if (self->priv->state == TP_TUBE_CHANNEL_STATE_REMOTE_PENDING) change_state (self, TP_TUBE_CHANNEL_STATE_OPEN); g_assert (self->priv->state == TP_TUBE_CHANNEL_STATE_OPEN); tp_svc_channel_type_stream_tube_emit_new_remote_connection (self, handle, connection_param, self->priv->connection_id); self->priv->connection_id++; } void tp_tests_stream_tube_channel_last_connection_disconnected ( TpTestsStreamTubeChannel *self, const gchar *error) { tp_svc_channel_type_stream_tube_emit_connection_closed (self, self->priv->connection_id - 1, error, "kaboum"); } void tp_tests_stream_tube_channel_set_close_on_accept ( TpTestsStreamTubeChannel *self, gboolean close_on_accept) { self->priv->close_on_accept = close_on_accept; } /* Contact Stream Tube */ G_DEFINE_TYPE (TpTestsContactStreamTubeChannel, tp_tests_contact_stream_tube_channel, TP_TESTS_TYPE_STREAM_TUBE_CHANNEL) static void tp_tests_contact_stream_tube_channel_init ( TpTestsContactStreamTubeChannel *self) { } static void tp_tests_contact_stream_tube_channel_class_init ( TpTestsContactStreamTubeChannelClass *klass) { TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass); base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; } /* Room Stream Tube */ G_DEFINE_TYPE (TpTestsRoomStreamTubeChannel, tp_tests_room_stream_tube_channel, TP_TESTS_TYPE_STREAM_TUBE_CHANNEL) static void tp_tests_room_stream_tube_channel_init ( TpTestsRoomStreamTubeChannel *self) { } static void tp_tests_room_stream_tube_channel_class_init ( TpTestsRoomStreamTubeChannelClass *klass) { TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass); base_class->target_handle_type = TP_HANDLE_TYPE_ROOM; } telepathy-qt-0.9.6~git1/tests/lib/glib/dbus-tube-chan.c0000664000175000017500000005213212470405660020545 0ustar jrjr/* * dbus-tube-chan.c - Simple dbus tube channel * * Copyright (C) 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "dbus-tube-chan.h" #include #include #include #include #include #include #include enum { PROP_SERVICE_NAME = 1, PROP_DBUS_NAMES, PROP_SUPPORTED_ACCESS_CONTROLS, PROP_PARAMETERS, PROP_STATE, PROP_DBUS_ADDRESS }; struct _TpTestsDBusTubeChannelPrivate { TpTubeChannelState state; TpSocketAccessControl access_control; /* our unique D-Bus name on the virtual tube bus (NULL for 1-1 D-Bus tubes)*/ gchar *dbus_local_name; /* the address that we are listening for D-Bus connections on */ gchar *dbus_srv_addr; /* the path of the UNIX socket used by the D-Bus server */ gchar *socket_path; /* the server that's listening on dbus_srv_addr */ DBusServer *dbus_srv; /* the connection to dbus_srv from a local client, or NULL */ DBusConnection *dbus_conn; /* the queue of D-Bus messages to be delivered to a local client when it * will connect */ GSList *dbus_msg_queue; /* current size of the queue in bytes. The maximum is MAX_QUEUE_SIZE */ unsigned long dbus_msg_queue_size; /* mapping of contact handle -> D-Bus name (empty for 1-1 D-Bus tubes) */ GHashTable *dbus_names; GArray *supported_access_controls; GHashTable *parameters; gboolean close_on_accept; }; static void tp_tests_dbus_tube_channel_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { TpTestsDBusTubeChannel *self = (TpTestsDBusTubeChannel *) object; switch (property_id) { case PROP_SERVICE_NAME: g_value_set_string (value, "com.test.Test"); break; case PROP_DBUS_NAMES: g_value_set_boxed (value, self->priv->dbus_names); break; case PROP_SUPPORTED_ACCESS_CONTROLS: g_value_set_boxed (value, self->priv->supported_access_controls); break; case PROP_PARAMETERS: g_value_set_boxed (value, self->priv->parameters); break; case PROP_DBUS_ADDRESS: g_value_set_string (value, self->priv->dbus_srv_addr); break; case PROP_STATE: g_value_set_uint (value, self->priv->state); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void tp_tests_dbus_tube_channel_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { TpTestsDBusTubeChannel *self = (TpTestsDBusTubeChannel *) object; switch (property_id) { case PROP_SUPPORTED_ACCESS_CONTROLS: if (self->priv->supported_access_controls != NULL) g_array_free (self->priv->supported_access_controls, FALSE); self->priv->supported_access_controls = g_value_dup_boxed (value); break; case PROP_PARAMETERS: if (self->priv->parameters != NULL) g_hash_table_destroy (self->priv->parameters); self->priv->parameters = g_value_dup_boxed (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dbus_tube_iface_init (gpointer iface, gpointer data); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (TpTestsDBusTubeChannel, tp_tests_dbus_tube_channel, TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_DBUS_TUBE, dbus_tube_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_TUBE, NULL); ) /* type definition stuff */ static const char * tp_tests_dbus_tube_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_TUBE, NULL }; static void tp_tests_dbus_tube_channel_init (TpTestsDBusTubeChannel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), TP_TESTS_TYPE_DBUS_TUBE_CHANNEL, TpTestsDBusTubeChannelPrivate); self->priv->dbus_names = g_hash_table_new (g_direct_hash, g_direct_equal); } static GObject * constructor (GType type, guint n_props, GObjectConstructParam *props) { GObject *object = G_OBJECT_CLASS (tp_tests_dbus_tube_channel_parent_class)->constructor ( type, n_props, props); TpTestsDBusTubeChannel *self = TP_TESTS_DBUS_TUBE_CHANNEL (object); if (tp_base_channel_is_requested (TP_BASE_CHANNEL (self))) { self->priv->state = TP_TUBE_CHANNEL_STATE_NOT_OFFERED; self->priv->parameters = tp_asv_new (NULL, NULL); } else { self->priv->state = TP_TUBE_CHANNEL_STATE_LOCAL_PENDING; self->priv->parameters = tp_asv_new ("badger", G_TYPE_UINT, 42, NULL); } if (self->priv->supported_access_controls == NULL) { GArray *acontrols; TpSocketAccessControl a; acontrols = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); a = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; acontrols = g_array_append_val (acontrols, a); self->priv->supported_access_controls = acontrols; } tp_base_channel_register (TP_BASE_CHANNEL (self)); return object; } static void dispose (GObject *object) { TpTestsDBusTubeChannel *self = (TpTestsDBusTubeChannel *) object; tp_clear_pointer (&self->priv->dbus_names, g_hash_table_unref); if (self->priv->supported_access_controls != NULL) g_array_free (self->priv->supported_access_controls, TRUE); if (self->priv->parameters != NULL) g_hash_table_destroy (self->priv->parameters); if (self->priv->dbus_srv != NULL) dbus_server_unref (self->priv->dbus_srv); if (self->priv->dbus_conn != NULL) dbus_connection_unref (self->priv->dbus_conn); if (self->priv->dbus_srv_addr != NULL) g_free (self->priv->dbus_srv_addr); if (self->priv->socket_path != NULL) g_free (self->priv->socket_path); ((GObjectClass *) tp_tests_dbus_tube_channel_parent_class)->dispose ( object); } static void channel_close (TpBaseChannel *channel) { tp_base_channel_destroyed (channel); } static void fill_immutable_properties (TpBaseChannel *chan, GHashTable *properties) { TpBaseChannelClass *klass = TP_BASE_CHANNEL_CLASS ( tp_tests_dbus_tube_channel_parent_class); klass->fill_immutable_properties (chan, properties); tp_dbus_properties_mixin_fill_properties_hash ( G_OBJECT (chan), properties, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, "ServiceName", TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, "SupportedAccessControls", NULL); if (!tp_base_channel_is_requested (chan)) { /* Parameters is immutable only for incoming tubes */ tp_dbus_properties_mixin_fill_properties_hash ( G_OBJECT (chan), properties, TP_IFACE_CHANNEL_INTERFACE_TUBE, "Parameters", NULL); } } static void tp_tests_dbus_tube_channel_class_init (TpTestsDBusTubeChannelClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass); GParamSpec *param_spec; static TpDBusPropertiesMixinPropImpl dbus_tube_props[] = { { "ServiceName", "service-name", NULL, }, { "DBusNames", "dbus-names", NULL, }, { "SupportedAccessControls", "supported-access-controls", NULL, }, { NULL } }; static TpDBusPropertiesMixinPropImpl tube_props[] = { { "Parameters", "parameters", NULL, }, { "State", "state", NULL, }, { NULL } }; object_class->constructor = constructor; object_class->get_property = tp_tests_dbus_tube_channel_get_property; object_class->set_property = tp_tests_dbus_tube_channel_set_property; object_class->dispose = dispose; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_DBUS_TUBE; base_class->interfaces = tp_tests_dbus_tube_channel_interfaces; base_class->close = channel_close; base_class->fill_immutable_properties = fill_immutable_properties; /* base_class->target_handle_type is defined in subclasses */ param_spec = g_param_spec_string ("service-name", "Service Name", "the service name associated with this tube object.", "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SERVICE_NAME, param_spec); param_spec = g_param_spec_boxed ("dbus-names", "DBus Names", "DBusTube.DBusNames", TP_HASH_TYPE_DBUS_TUBE_PARTICIPANTS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_DBUS_NAMES, param_spec); param_spec = g_param_spec_boxed ("supported-access-controls", "Supported access-controls", "GArray containing supported access controls.", DBUS_TYPE_G_UINT_ARRAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SUPPORTED_ACCESS_CONTROLS, param_spec); param_spec = g_param_spec_string ( "dbus-address", "D-Bus address", "The D-Bus address on which this tube will listen for connections", "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_DBUS_ADDRESS, param_spec); param_spec = g_param_spec_boxed ( "parameters", "Parameters", "parameters of the tube", TP_HASH_TYPE_STRING_VARIANT_MAP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_PARAMETERS, param_spec); param_spec = g_param_spec_uint ( "state", "TpTubeState", "state of the tube", 0, NUM_TP_TUBE_CHANNEL_STATES - 1, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_STATE, param_spec); tp_dbus_properties_mixin_implement_interface (object_class, TP_IFACE_QUARK_CHANNEL_TYPE_DBUS_TUBE, tp_dbus_properties_mixin_getter_gobject_properties, NULL, dbus_tube_props); tp_dbus_properties_mixin_implement_interface (object_class, TP_IFACE_QUARK_CHANNEL_INTERFACE_TUBE, tp_dbus_properties_mixin_getter_gobject_properties, NULL, tube_props); g_type_class_add_private (object_class, sizeof (TpTestsDBusTubeChannelPrivate)); } static gboolean check_access_control (TpTestsDBusTubeChannel *self, TpSocketAccessControl access_control) { guint i; for (i = 0; i < self->priv->supported_access_controls->len; i++) { if (g_array_index (self->priv->supported_access_controls, TpSocketAccessControl, i) == access_control) return TRUE; } return FALSE; } static void change_state (TpTestsDBusTubeChannel *self, TpTubeChannelState state) { self->priv->state = state; tp_svc_channel_interface_tube_emit_tube_channel_state_changed (self, state); } /* * Characters used are permissible both in filenames and in D-Bus names. (See * D-Bus specification for restrictions.) */ static void generate_ascii_string (guint len, gchar *buf) { const gchar *chars = "0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "_-"; guint i; for (i = 0; i < len; i++) buf[i] = chars[g_random_int_range (0, 64)]; } static DBusHandlerResult filter_cb (DBusConnection *conn, DBusMessage *msg, void *user_data) { TpTestsDBusTubeChannel *self = TP_TESTS_DBUS_TUBE_CHANNEL (user_data); TpTestsDBusTubeChannelPrivate *priv = self->priv; gchar *marshalled = NULL; gint len; if (dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_SIGNAL && !tp_strdiff (dbus_message_get_interface (msg), "org.freedesktop.DBus.Local") && !tp_strdiff (dbus_message_get_member (msg), "Disconnected")) { /* connection was disconnected */ g_debug ("connection was disconnected"); dbus_connection_close (priv->dbus_conn); tp_clear_pointer (&priv->dbus_conn, dbus_connection_unref); goto out; } if (priv->dbus_local_name != NULL) { if (!dbus_message_set_sender (msg, priv->dbus_local_name)) g_debug ("dbus_message_set_sender failed"); } if (!dbus_message_marshal (msg, &marshalled, &len)) goto out; out: if (marshalled != NULL) g_free (marshalled); return DBUS_HANDLER_RESULT_HANDLED; } static dbus_bool_t allow_all_connections (DBusConnection *conn, unsigned long uid, void *data) { return TRUE; } static void new_connection_cb (DBusServer *server, DBusConnection *conn, void *data) { TpTestsDBusTubeChannel *self = TP_TESTS_DBUS_TUBE_CHANNEL (data); TpTestsDBusTubeChannelPrivate *priv = self->priv; guint32 serial; GSList *i; if (priv->dbus_conn != NULL) /* we already have a connection; drop this new one */ /* return without reffing conn means it will be dropped */ return; dbus_connection_ref (conn); dbus_connection_setup_with_g_main (conn, NULL); dbus_connection_add_filter (conn, filter_cb, self, NULL); priv->dbus_conn = conn; if (priv->access_control == TP_SOCKET_ACCESS_CONTROL_LOCALHOST) { /* By default libdbus use Credentials access control. If user wants * to use the Localhost access control, we need to bypass this check. */ dbus_connection_set_unix_user_function (conn, allow_all_connections, NULL, NULL); } /* We may have received messages to deliver before the local connection is * established. Theses messages are kept in the dbus_msg_queue list and are * delivered as soon as we get the connection. */ g_debug ("%u messages in the queue (%lu bytes)", g_slist_length (priv->dbus_msg_queue), priv->dbus_msg_queue_size); priv->dbus_msg_queue = g_slist_reverse (priv->dbus_msg_queue); for (i = priv->dbus_msg_queue; i != NULL; i = g_slist_delete_link (i, i)) { DBusMessage *msg = i->data; g_debug ("delivering queued message from '%s' to '%s' on the " "new connection", dbus_message_get_sender (msg), dbus_message_get_destination (msg)); dbus_connection_send (priv->dbus_conn, msg, &serial); dbus_message_unref (msg); } priv->dbus_msg_queue = NULL; priv->dbus_msg_queue_size = 0; } /* There is two step to enable receiving a D-Bus connection from the local * application: * - listen on the socket * - add the socket in the mainloop * * We need to know the socket path to return from the AcceptDBusTube D-Bus * call but the socket in the mainloop must be added only when we are ready * to receive connections, that is when the bytestream is fully open with the * remote contact. * * See also Bug 13891: * https://bugs.freedesktop.org/show_bug.cgi?id=13891 * */ static gboolean create_dbus_server (TpTestsDBusTubeChannel *self, GError **err) { #define SERVER_LISTEN_MAX_TRIES 5 TpTestsDBusTubeChannelPrivate *priv = self->priv; guint i; if (priv->dbus_srv != NULL) return TRUE; for (i = 0; i < SERVER_LISTEN_MAX_TRIES; i++) { gchar suffix[8]; DBusError error; g_free (priv->dbus_srv_addr); g_free (priv->socket_path); generate_ascii_string (8, suffix); priv->socket_path = g_strdup_printf ("%s/dbus-tpqt4-test-%.8s", g_get_tmp_dir (), suffix); priv->dbus_srv_addr = g_strdup_printf ("unix:path=%s", priv->socket_path); dbus_error_init (&error); priv->dbus_srv = dbus_server_listen (priv->dbus_srv_addr, &error); if (priv->dbus_srv != NULL) break; g_debug ("dbus_server_listen failed (try %u): %s: %s", i, error.name, error.message); dbus_error_free (&error); } if (priv->dbus_srv == NULL) { g_debug ("all attempts failed. Close the tube"); g_free (priv->dbus_srv_addr); priv->dbus_srv_addr = NULL; g_free (priv->socket_path); priv->socket_path = NULL; g_set_error (err, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Can't create D-Bus server"); return FALSE; } g_debug ("listening on %s", priv->dbus_srv_addr); dbus_server_set_new_connection_function (priv->dbus_srv, new_connection_cb, self, NULL); return TRUE; } static void dbus_tube_offer (TpSvcChannelTypeDBusTube *iface, GHashTable *parameters, guint access_control, DBusGMethodInvocation *context) { TpTestsDBusTubeChannel *self = (TpTestsDBusTubeChannel *) iface; GError *error = NULL; if (self->priv->state != TP_TUBE_CHANNEL_STATE_NOT_OFFERED) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Tube is not in the not offered state"); goto fail; } if (!check_access_control (self, access_control)) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Address type not supported with this access control"); goto fail; } self->priv->access_control = access_control; if (!create_dbus_server (self, &error)) goto fail; g_object_set (self, "parameters", parameters, NULL); change_state (self, TP_TUBE_CHANNEL_STATE_REMOTE_PENDING); tp_svc_channel_type_dbus_tube_return_from_offer (context, self->priv->dbus_srv_addr); return; fail: dbus_g_method_return_error (context, error); g_error_free (error); } static void dbus_tube_accept (TpSvcChannelTypeDBusTube *iface, guint access_control, DBusGMethodInvocation *context) { TpTestsDBusTubeChannel *self = (TpTestsDBusTubeChannel *) iface; GError *error = NULL; if (self->priv->state != TP_TUBE_CHANNEL_STATE_LOCAL_PENDING) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Tube is not in the local pending state"); goto fail; } if (!check_access_control (self, access_control)) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Address type not supported with this access control"); goto fail; } if (self->priv->close_on_accept) { tp_base_channel_close (TP_BASE_CHANNEL (self)); return; } if (!create_dbus_server (self, &error)) goto fail; change_state (self, TP_TUBE_CHANNEL_STATE_OPEN); tp_svc_channel_type_dbus_tube_return_from_accept (context, self->priv->dbus_srv_addr); return; fail: dbus_g_method_return_error (context, error); g_error_free (error); } static void dbus_tube_iface_init (gpointer iface, gpointer data) { TpSvcChannelTypeDBusTubeClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_type_dbus_tube_implement_##x (klass, dbus_tube_##x) IMPLEMENT(offer); IMPLEMENT(accept); #undef IMPLEMENT } /* Called to emulate a peer connecting to an offered tube */ void tp_tests_dbus_tube_channel_peer_connected_no_stream (TpTestsDBusTubeChannel *self, gchar *bus_name, TpHandle handle) { GHashTable *added; GArray *removed; if (self->priv->state == TP_TUBE_CHANNEL_STATE_REMOTE_PENDING) change_state (self, TP_TUBE_CHANNEL_STATE_OPEN); g_assert (self->priv->state == TP_TUBE_CHANNEL_STATE_OPEN); added = g_hash_table_new (g_direct_hash, g_direct_equal); removed = g_array_new (FALSE, FALSE, sizeof (TpHandle)); g_hash_table_insert (added, GUINT_TO_POINTER (handle), bus_name); // Add to the global hash table as well g_hash_table_insert (self->priv->dbus_names, GUINT_TO_POINTER (handle), bus_name); tp_svc_channel_type_dbus_tube_emit_dbus_names_changed (self, added, removed); g_hash_table_destroy (added); g_array_free (removed, TRUE); } /* Called to emulate a peer connecting to an offered tube */ void tp_tests_dbus_tube_channel_peer_disconnected (TpTestsDBusTubeChannel *self, TpHandle handle) { GHashTable *added; GArray *removed; g_assert (self->priv->state == TP_TUBE_CHANNEL_STATE_OPEN); added = g_hash_table_new (g_direct_hash, g_direct_equal); removed = g_array_new (FALSE, FALSE, sizeof (TpHandle)); g_array_append_val (removed, handle); // Remove from the global hash table as well g_hash_table_remove (self->priv->dbus_names, GUINT_TO_POINTER (handle)); tp_svc_channel_type_dbus_tube_emit_dbus_names_changed (self, added, removed); g_hash_table_destroy (added); g_array_free (removed, TRUE); } void tp_tests_dbus_tube_channel_set_close_on_accept ( TpTestsDBusTubeChannel *self, gboolean close_on_accept) { self->priv->close_on_accept = close_on_accept; } /* Contact DBus Tube */ G_DEFINE_TYPE (TpTestsContactDBusTubeChannel, tp_tests_contact_dbus_tube_channel, TP_TESTS_TYPE_DBUS_TUBE_CHANNEL) static void tp_tests_contact_dbus_tube_channel_init ( TpTestsContactDBusTubeChannel *self) { } static void tp_tests_contact_dbus_tube_channel_class_init ( TpTestsContactDBusTubeChannelClass *klass) { TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass); base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; } /* Room DBus Tube */ G_DEFINE_TYPE (TpTestsRoomDBusTubeChannel, tp_tests_room_dbus_tube_channel, TP_TESTS_TYPE_DBUS_TUBE_CHANNEL) static void tp_tests_room_dbus_tube_channel_init ( TpTestsRoomDBusTubeChannel *self) { } static void tp_tests_room_dbus_tube_channel_class_init ( TpTestsRoomDBusTubeChannelClass *klass) { TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass); base_class->target_handle_type = TP_HANDLE_TYPE_ROOM; } telepathy-qt-0.9.6~git1/tests/lib/glib/contacts-conn.c0000664000175000017500000012727012470405660020523 0ustar jrjr/* * contacts-conn.c - connection with contact info * * Copyright (C) 2007-2008 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "contacts-conn.h" #include #include #include #include #include #include #include #include "debug.h" static void init_aliasing (gpointer, gpointer); static void init_avatars (gpointer, gpointer); static void init_location (gpointer, gpointer); static void init_contact_caps (gpointer, gpointer); static void init_contact_info (gpointer, gpointer); static void init_client_types (gpointer, gpointer); static void conn_avatars_properties_getter (GObject *object, GQuark interface, GQuark name, GValue *value, gpointer getter_data); G_DEFINE_TYPE_WITH_CODE (TpTestsContactsConnection, tp_tests_contacts_connection, TP_TESTS_TYPE_SIMPLE_CONNECTION, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING, init_aliasing); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_AVATARS, init_avatars); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE, tp_presence_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE, tp_presence_mixin_simple_presence_iface_init) G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_LOCATION, init_location) G_IMPLEMENT_INTERFACE ( TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_CAPABILITIES, init_contact_caps) G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO, init_contact_info) G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CLIENT_TYPES, init_client_types); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, tp_contacts_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST, tp_base_contact_list_mixin_list_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS, tp_base_contact_list_mixin_groups_iface_init); ); /* type definition stuff */ static const char *mime_types[] = { "image/png", NULL }; static TpDBusPropertiesMixinPropImpl conn_avatars_properties[] = { { "MinimumAvatarWidth", GUINT_TO_POINTER (1), NULL }, { "MinimumAvatarHeight", GUINT_TO_POINTER (2), NULL }, { "RecommendedAvatarWidth", GUINT_TO_POINTER (3), NULL }, { "RecommendedAvatarHeight", GUINT_TO_POINTER (4), NULL }, { "MaximumAvatarWidth", GUINT_TO_POINTER (5), NULL }, { "MaximumAvatarHeight", GUINT_TO_POINTER (6), NULL }, { "MaximumAvatarBytes", GUINT_TO_POINTER (7), NULL }, /* special-cased - it's the only one with a non-guint value */ { "SupportedAvatarMIMETypes", NULL, NULL }, { NULL } }; enum { N_SIGNALS }; struct _TpTestsContactsConnectionPrivate { /* TpHandle => gchar * */ GHashTable *aliases; /* TpHandle => AvatarData */ GHashTable *avatars; /* TpHandle => ContactsConnectionPresenceStatusIndex */ GHashTable *presence_statuses; /* TpHandle => gchar * */ GHashTable *presence_messages; /* TpHandle => GHashTable * */ GHashTable *locations; /* TpHandle => GPtrArray * */ GHashTable *capabilities; /* TpHandle => GPtrArray * */ GHashTable *contact_info; GPtrArray *default_contact_info; /* TpHandle => gchar ** */ GHashTable *client_types; TestContactListManager *list_manager; }; typedef struct { GArray *data; gchar *mime_type; gchar *token; } AvatarData; static AvatarData * avatar_data_new (GArray *data, const gchar *mime_type, const gchar *token) { AvatarData *a; a = g_slice_new (AvatarData); a->data = data ? g_array_ref (data) : NULL; a->mime_type = g_strdup (mime_type); a->token = g_strdup (token); return a; } static void avatar_data_free (gpointer data) { AvatarData *a = data; if (a != NULL) { if (a->data != NULL) g_array_unref (a->data); g_free (a->mime_type); g_free (a->token); g_slice_free (AvatarData, a); } } static void free_rcc_list (GPtrArray *rccs) { g_boxed_free (TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, rccs); } static void tp_tests_contacts_connection_init (TpTestsContactsConnection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_CONTACTS_CONNECTION, TpTestsContactsConnectionPrivate); self->priv->aliases = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); self->priv->avatars = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, avatar_data_free); self->priv->presence_statuses = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); self->priv->presence_messages = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); self->priv->locations = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_hash_table_unref); self->priv->capabilities = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) free_rcc_list); self->priv->contact_info = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_ptr_array_unref); self->priv->default_contact_info = (GPtrArray *) dbus_g_type_specialized_construct ( TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST); self->priv->client_types = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_strfreev); } static void finalize (GObject *object) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); tp_contacts_mixin_finalize (object); g_hash_table_destroy (self->priv->aliases); g_hash_table_destroy (self->priv->avatars); g_hash_table_destroy (self->priv->presence_statuses); g_hash_table_destroy (self->priv->presence_messages); g_hash_table_destroy (self->priv->locations); g_hash_table_destroy (self->priv->capabilities); g_hash_table_destroy (self->priv->contact_info); g_hash_table_destroy (self->priv->client_types); if (self->priv->default_contact_info != NULL) g_ptr_array_unref (self->priv->default_contact_info); G_OBJECT_CLASS (tp_tests_contacts_connection_parent_class)->finalize (object); } static void aliasing_fill_contact_attributes (GObject *object, const GArray *contacts, GHashTable *attributes) { guint i; TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); TpBaseConnection *base = TP_BASE_CONNECTION (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, guint, i); const gchar *alias = g_hash_table_lookup (self->priv->aliases, GUINT_TO_POINTER (handle)); if (alias == NULL) { alias = tp_handle_inspect (contact_repo, handle); } tp_contacts_mixin_set_contact_attribute (attributes, handle, TP_IFACE_CONNECTION_INTERFACE_ALIASING "/alias", tp_g_value_slice_new_string (alias)); } } static void avatars_fill_contact_attributes (GObject *object, const GArray *contacts, GHashTable *attributes) { guint i; TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, guint, i); AvatarData *a = g_hash_table_lookup (self->priv->avatars, GUINT_TO_POINTER (handle)); if (a != NULL && a->token != NULL) { tp_contacts_mixin_set_contact_attribute (attributes, handle, TP_IFACE_CONNECTION_INTERFACE_AVATARS "/token", tp_g_value_slice_new_string (a->token)); } } } static void location_fill_contact_attributes (GObject *object, const GArray *contacts, GHashTable *attributes) { guint i; TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, guint, i); GHashTable *location = g_hash_table_lookup (self->priv->locations, GUINT_TO_POINTER (handle)); if (location != NULL) { tp_contacts_mixin_set_contact_attribute (attributes, handle, TP_IFACE_CONNECTION_INTERFACE_LOCATION "/location", tp_g_value_slice_new_boxed (TP_HASH_TYPE_LOCATION, location)); } } } static void contact_caps_fill_contact_attributes (GObject *object, const GArray *contacts, GHashTable *attributes) { guint i; TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, guint, i); GPtrArray *caps = g_hash_table_lookup (self->priv->capabilities, GUINT_TO_POINTER (handle)); if (caps != NULL) { tp_contacts_mixin_set_contact_attribute (attributes, handle, TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES "/capabilities", tp_g_value_slice_new_boxed ( TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, caps)); } } } static void contact_info_fill_contact_attributes (GObject *object, const GArray *contacts, GHashTable *attributes) { guint i; TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, guint, i); GPtrArray *info = g_hash_table_lookup (self->priv->contact_info, GUINT_TO_POINTER (handle)); if (info != NULL) { tp_contacts_mixin_set_contact_attribute (attributes, handle, TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO "/info", tp_g_value_slice_new_boxed (TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST, info)); } } } static TpDBusPropertiesMixinPropImpl conn_contact_info_properties[] = { { "ContactInfoFlags", GUINT_TO_POINTER (TP_CONTACT_INFO_FLAG_PUSH | TP_CONTACT_INFO_FLAG_CAN_SET), NULL }, { "SupportedFields", NULL, NULL }, { NULL } }; static void conn_contact_info_properties_getter (GObject *object, GQuark interface, GQuark name, GValue *value, gpointer getter_data) { GQuark q_supported_fields = g_quark_from_static_string ("SupportedFields"); static GPtrArray *supported_fields = NULL; if (name == q_supported_fields) { if (supported_fields == NULL) { supported_fields = g_ptr_array_new (); g_ptr_array_add (supported_fields, tp_value_array_build (4, G_TYPE_STRING, "n", G_TYPE_STRV, NULL, G_TYPE_UINT, 0, G_TYPE_UINT, 0, G_TYPE_INVALID)); } g_value_set_boxed (value, supported_fields); } else { g_value_set_uint (value, GPOINTER_TO_UINT (getter_data)); } } static void client_types_fill_contact_attributes ( GObject *object, const GArray *contacts, GHashTable *attributes) { guint i; TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, TpHandle, i); gchar **types = g_hash_table_lookup (self->priv->client_types, GUINT_TO_POINTER (handle)); if (types != NULL) { tp_contacts_mixin_set_contact_attribute (attributes, handle, TP_IFACE_CONNECTION_INTERFACE_CLIENT_TYPES "/client-types", tp_g_value_slice_new_boxed (G_TYPE_STRV, types)); } } } static void constructed (GObject *object) { TpBaseConnection *base = TP_BASE_CONNECTION (object); void (*parent_impl) (GObject *) = G_OBJECT_CLASS (tp_tests_contacts_connection_parent_class)->constructed; if (parent_impl != NULL) parent_impl (object); tp_contacts_mixin_init (object, G_STRUCT_OFFSET (TpTestsContactsConnection, contacts_mixin)); tp_base_connection_register_with_contacts_mixin (base); tp_base_contact_list_mixin_register_with_contacts_mixin (base); tp_contacts_mixin_add_contact_attributes_iface (object, TP_IFACE_CONNECTION_INTERFACE_ALIASING, aliasing_fill_contact_attributes); tp_contacts_mixin_add_contact_attributes_iface (object, TP_IFACE_CONNECTION_INTERFACE_AVATARS, avatars_fill_contact_attributes); tp_contacts_mixin_add_contact_attributes_iface (object, TP_IFACE_CONNECTION_INTERFACE_LOCATION, location_fill_contact_attributes); tp_contacts_mixin_add_contact_attributes_iface (object, TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES, contact_caps_fill_contact_attributes); tp_contacts_mixin_add_contact_attributes_iface (object, TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO, contact_info_fill_contact_attributes); tp_contacts_mixin_add_contact_attributes_iface (object, TP_IFACE_CONNECTION_INTERFACE_CLIENT_TYPES, client_types_fill_contact_attributes); tp_presence_mixin_init (object, G_STRUCT_OFFSET (TpTestsContactsConnection, presence_mixin)); tp_presence_mixin_simple_presence_register_with_contacts_mixin (object); } static const TpPresenceStatusOptionalArgumentSpec can_have_message[] = { { "message", "s", NULL, NULL }, { NULL } }; /* Must match TpTestsContactsConnectionPresenceStatusIndex in the .h */ static const TpPresenceStatusSpec my_statuses[] = { { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, can_have_message }, { "busy", TP_CONNECTION_PRESENCE_TYPE_BUSY, TRUE, can_have_message }, { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, can_have_message }, { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, NULL }, { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, NULL }, { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, NULL }, { NULL } }; static gboolean my_status_available (GObject *object, guint index) { TpBaseConnection *base = TP_BASE_CONNECTION (object); if (base->status != TP_CONNECTION_STATUS_CONNECTED) return FALSE; return TRUE; } static GHashTable * my_get_contact_statuses (GObject *object, const GArray *contacts, GError **error) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); GHashTable *result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) tp_presence_status_free); guint i; for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, TpHandle, i); gpointer key = GUINT_TO_POINTER (handle); TpTestsContactsConnectionPresenceStatusIndex index; const gchar *presence_message; GHashTable *parameters; index = GPOINTER_TO_UINT (g_hash_table_lookup ( self->priv->presence_statuses, key)); presence_message = g_hash_table_lookup ( self->priv->presence_messages, key); parameters = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); if (presence_message != NULL) g_hash_table_insert (parameters, "message", tp_g_value_slice_new_string (presence_message)); g_hash_table_insert (result, key, tp_presence_status_new (index, parameters)); g_hash_table_destroy (parameters); } return result; } static gboolean my_set_own_status (GObject *object, const TpPresenceStatus *status, GError **error) { TpBaseConnection *base_conn = TP_BASE_CONNECTION (object); TpTestsContactsConnectionPresenceStatusIndex index = status->index; const gchar *message = ""; if (status->optional_arguments != NULL) { message = g_hash_table_lookup (status->optional_arguments, "message"); if (message == NULL) message = ""; } tp_tests_contacts_connection_change_presences (TP_TESTS_CONTACTS_CONNECTION (object), 1, &(base_conn->self_handle), &index, &message); return TRUE; } static guint my_get_maximum_status_message_length_cb (GObject *obj) { return 512; } static GPtrArray * create_channel_managers (TpBaseConnection *conn) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (conn); GPtrArray *ret = g_ptr_array_sized_new (1); self->priv->list_manager = g_object_new (TEST_TYPE_CONTACT_LIST_MANAGER, "connection", conn, NULL); g_ptr_array_add (ret, self->priv->list_manager); return ret; } static void tp_tests_contacts_connection_class_init (TpTestsContactsConnectionClass *klass) { TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; TpPresenceMixinClass *mixin_class; static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_ALIASING, TP_IFACE_CONNECTION_INTERFACE_AVATARS, TP_IFACE_CONNECTION_INTERFACE_CONTACTS, TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST, TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS, TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_LOCATION, TP_IFACE_CONNECTION_INTERFACE_CLIENT_TYPES, TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES, TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, NULL }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CONNECTION_INTERFACE_AVATARS, conn_avatars_properties_getter, NULL, conn_avatars_properties, }, { TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO, conn_contact_info_properties_getter, NULL, conn_contact_info_properties, }, { NULL } }; object_class->constructed = constructed; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (TpTestsContactsConnectionPrivate)); base_class->interfaces_always_present = interfaces_always_present; base_class->create_channel_managers = create_channel_managers; tp_contacts_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsContactsConnectionClass, contacts_mixin)); tp_presence_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsContactsConnectionClass, presence_mixin), my_status_available, my_get_contact_statuses, my_set_own_status, my_statuses); mixin_class = TP_PRESENCE_MIXIN_CLASS(klass); mixin_class->get_maximum_status_message_length = my_get_maximum_status_message_length_cb; tp_presence_mixin_simple_presence_init_dbus_properties (object_class); klass->properties_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsContactsConnectionClass, properties_class)); tp_base_contact_list_mixin_class_init (base_class); } TestContactListManager * tp_tests_contacts_connection_get_contact_list_manager ( TpTestsContactsConnection *self) { return self->priv->list_manager; } void tp_tests_contacts_connection_change_aliases (TpTestsContactsConnection *self, guint n, const TpHandle *handles, const gchar * const *aliases) { GPtrArray *structs = g_ptr_array_sized_new (n); guint i; for (i = 0; i < n; i++) { GValueArray *pair = g_value_array_new (2); DEBUG ("contact#%u -> %s", handles[i], aliases[i]); g_hash_table_insert (self->priv->aliases, GUINT_TO_POINTER (handles[i]), g_strdup (aliases[i])); g_value_array_append (pair, NULL); g_value_init (pair->values + 0, G_TYPE_UINT); g_value_set_uint (pair->values + 0, handles[i]); g_value_array_append (pair, NULL); g_value_init (pair->values + 1, G_TYPE_STRING); g_value_set_string (pair->values + 1, aliases[i]); g_ptr_array_add (structs, pair); } tp_svc_connection_interface_aliasing_emit_aliases_changed (self, structs); g_ptr_array_foreach (structs, (GFunc) g_value_array_free, NULL); g_ptr_array_free (structs, TRUE); } void tp_tests_contacts_connection_change_presences ( TpTestsContactsConnection *self, guint n, const TpHandle *handles, const TpTestsContactsConnectionPresenceStatusIndex *indexes, const gchar * const *messages) { GHashTable *presences = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) tp_presence_status_free); guint i; for (i = 0; i < n; i++) { GHashTable *parameters; gpointer key = GUINT_TO_POINTER (handles[i]); DEBUG ("contact#%u -> %s \"%s\"", handles[i], my_statuses[indexes[i]].name, messages[i]); g_hash_table_insert (self->priv->presence_statuses, key, GUINT_TO_POINTER (indexes[i])); g_hash_table_insert (self->priv->presence_messages, key, g_strdup (messages[i])); parameters = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); if (messages[i] != NULL && messages[i][0] != '\0') g_hash_table_insert (parameters, "message", tp_g_value_slice_new_string (messages[i])); g_hash_table_insert (presences, key, tp_presence_status_new (indexes[i], parameters)); g_hash_table_destroy (parameters); } tp_presence_mixin_emit_presence_update ((GObject *) self, presences); g_hash_table_destroy (presences); } void tp_tests_contacts_connection_change_avatar_tokens (TpTestsContactsConnection *self, guint n, const TpHandle *handles, const gchar * const *tokens) { guint i; for (i = 0; i < n; i++) { DEBUG ("contact#%u -> %s", handles[i], tokens[i]); g_hash_table_insert (self->priv->avatars, GUINT_TO_POINTER (handles[i]), avatar_data_new (NULL, NULL, tokens[i])); tp_svc_connection_interface_avatars_emit_avatar_updated (self, handles[i], tokens[i]); } } void tp_tests_contacts_connection_change_avatar_data ( TpTestsContactsConnection *self, TpHandle handle, GArray *data, const gchar *mime_type, const gchar *token, gboolean emit_avatar_updated) { g_hash_table_insert (self->priv->avatars, GUINT_TO_POINTER (handle), avatar_data_new (data, mime_type, token)); if (emit_avatar_updated) { tp_svc_connection_interface_avatars_emit_avatar_updated (self, handle, token); } } void tp_tests_contacts_connection_change_locations (TpTestsContactsConnection *self, guint n, const TpHandle *handles, GHashTable **locations) { guint i; for (i = 0; i < n; i++) { DEBUG ("contact#%u ->", handles[i]); tp_asv_dump (locations[i]); g_hash_table_insert (self->priv->locations, GUINT_TO_POINTER (handles[i]), g_hash_table_ref (locations[i])); tp_svc_connection_interface_location_emit_location_updated (self, handles[i], locations[i]); } } void tp_tests_contacts_connection_change_capabilities ( TpTestsContactsConnection *self, GHashTable *capabilities) { GHashTableIter iter; gpointer handle, caps; g_hash_table_iter_init (&iter, capabilities); while (g_hash_table_iter_next (&iter, &handle, &caps)) { g_hash_table_insert (self->priv->capabilities, handle, g_boxed_copy (TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, caps)); } tp_svc_connection_interface_contact_capabilities_emit_contact_capabilities_changed ( self, capabilities); } void tp_tests_contacts_connection_change_contact_info ( TpTestsContactsConnection *self, TpHandle handle, GPtrArray *info) { g_hash_table_insert (self->priv->contact_info, GUINT_TO_POINTER (handle), g_ptr_array_ref (info)); tp_svc_connection_interface_contact_info_emit_contact_info_changed (self, handle, info); } void tp_tests_contacts_connection_set_default_contact_info ( TpTestsContactsConnection *self, GPtrArray *info) { if (self->priv->default_contact_info != NULL) g_ptr_array_unref (self->priv->default_contact_info); self->priv->default_contact_info = g_ptr_array_ref (info); } void tp_tests_contacts_connection_change_client_types( TpTestsContactsConnection *self, TpHandle handle, gchar **client_types) { g_hash_table_insert (self->priv->client_types, GUINT_TO_POINTER (handle), client_types); tp_svc_connection_interface_client_types_emit_client_types_updated (self, handle, (const gchar **) client_types); } static void my_get_alias_flags (TpSvcConnectionInterfaceAliasing *aliasing, DBusGMethodInvocation *context) { TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); tp_svc_connection_interface_aliasing_return_from_get_alias_flags (context, 0); } static void my_get_aliases (TpSvcConnectionInterfaceAliasing *aliasing, const GArray *contacts, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (aliasing); TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GHashTable *result; GError *error = NULL; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, TpHandle, i); const gchar *alias = g_hash_table_lookup (self->priv->aliases, GUINT_TO_POINTER (handle)); if (alias == NULL) g_hash_table_insert (result, GUINT_TO_POINTER (handle), (gchar *) tp_handle_inspect (contact_repo, handle)); else g_hash_table_insert (result, GUINT_TO_POINTER (handle), (gchar *) alias); } tp_svc_connection_interface_aliasing_return_from_get_aliases (context, result); g_hash_table_destroy (result); } static void my_request_aliases (TpSvcConnectionInterfaceAliasing *aliasing, const GArray *contacts, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (aliasing); TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GPtrArray *result; gchar **strings; GError *error = NULL; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_ptr_array_sized_new (contacts->len + 1); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, TpHandle, i); const gchar *alias = g_hash_table_lookup (self->priv->aliases, GUINT_TO_POINTER (handle)); if (alias == NULL) g_ptr_array_add (result, (gchar *) tp_handle_inspect (contact_repo, handle)); else g_ptr_array_add (result, (gchar *) alias); } g_ptr_array_add (result, NULL); strings = (gchar **) g_ptr_array_free (result, FALSE); tp_svc_connection_interface_aliasing_return_from_request_aliases (context, (const gchar **) strings); g_free (strings); } static void init_aliasing (gpointer g_iface, gpointer iface_data) { TpSvcConnectionInterfaceAliasingClass *klass = g_iface; #define IMPLEMENT(x) tp_svc_connection_interface_aliasing_implement_##x (\ klass, my_##x) IMPLEMENT(get_alias_flags); IMPLEMENT(request_aliases); IMPLEMENT(get_aliases); /* IMPLEMENT(set_aliases); */ #undef IMPLEMENT } static void my_get_avatar_tokens (TpSvcConnectionInterfaceAvatars *avatars, const GArray *contacts, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (avatars); TpBaseConnection *base = TP_BASE_CONNECTION (avatars); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; GHashTable *result; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, TpHandle, i); AvatarData *a = g_hash_table_lookup (self->priv->avatars, GUINT_TO_POINTER (handle)); if (a == NULL || a->token == NULL) { /* we're expected to do a round-trip to the server to find out * their token, so we have to give some sort of result. Assume * no avatar, here */ a = avatar_data_new (NULL, NULL, ""); g_hash_table_insert (self->priv->avatars, GUINT_TO_POINTER (handle), a); tp_svc_connection_interface_avatars_emit_avatar_updated (self, handle, a->token); } g_hash_table_insert (result, GUINT_TO_POINTER (handle), a->token); } tp_svc_connection_interface_avatars_return_from_get_known_avatar_tokens ( context, result); g_hash_table_destroy (result); } static void my_get_known_avatar_tokens (TpSvcConnectionInterfaceAvatars *avatars, const GArray *contacts, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (avatars); TpBaseConnection *base = TP_BASE_CONNECTION (avatars); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; GHashTable *result; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, TpHandle, i); AvatarData *a = g_hash_table_lookup (self->priv->avatars, GUINT_TO_POINTER (handle)); const gchar *token = a ? a->token : NULL; g_hash_table_insert (result, GUINT_TO_POINTER (handle), (gchar *) (token != NULL ? token : "")); } tp_svc_connection_interface_avatars_return_from_get_known_avatar_tokens ( context, result); g_hash_table_destroy (result); } static void my_request_avatars (TpSvcConnectionInterfaceAvatars *avatars, const GArray *contacts, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (avatars); TpBaseConnection *base = TP_BASE_CONNECTION (avatars); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, TpHandle, i); AvatarData *a = g_hash_table_lookup (self->priv->avatars, GUINT_TO_POINTER (handle)); if (a != NULL) tp_svc_connection_interface_avatars_emit_avatar_retrieved (self, handle, a->token, a->data, a->mime_type); } tp_svc_connection_interface_avatars_return_from_request_avatars (context); } static void conn_avatars_properties_getter (GObject *object, GQuark interface, GQuark name, GValue *value, gpointer getter_data) { GQuark q_mime_types = g_quark_from_static_string ( "SupportedAvatarMIMETypes"); if (name == q_mime_types) { g_value_set_static_boxed (value, mime_types); } else { g_value_set_uint (value, GPOINTER_TO_UINT (getter_data)); } } static void init_avatars (gpointer g_iface, gpointer iface_data) { TpSvcConnectionInterfaceAvatarsClass *klass = g_iface; #define IMPLEMENT(x) tp_svc_connection_interface_avatars_implement_##x (\ klass, my_##x) /* IMPLEMENT(get_avatar_requirements); */ IMPLEMENT(get_avatar_tokens); IMPLEMENT(get_known_avatar_tokens); /* IMPLEMENT(request_avatar); */ IMPLEMENT(request_avatars); /* IMPLEMENT(set_avatar); */ /* IMPLEMENT(clear_avatar); */ #undef IMPLEMENT } static void my_get_locations (TpSvcConnectionInterfaceLocation *avatars, const GArray *contacts, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (avatars); TpBaseConnection *base = TP_BASE_CONNECTION (avatars); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; GHashTable *result; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, TpHandle, i); GHashTable *location = g_hash_table_lookup (self->priv->locations, GUINT_TO_POINTER (handle)); if (location != NULL) { g_hash_table_insert (result, GUINT_TO_POINTER (handle), location); } } tp_svc_connection_interface_location_return_from_get_locations ( context, result); g_hash_table_destroy (result); } static void init_location (gpointer g_iface, gpointer iface_data) { TpSvcConnectionInterfaceLocationClass *klass = g_iface; #define IMPLEMENT(x) tp_svc_connection_interface_location_implement_##x (\ klass, my_##x) IMPLEMENT(get_locations); #undef IMPLEMENT } static void my_get_contact_capabilities (TpSvcConnectionInterfaceContactCapabilities *obj, const GArray *contacts, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (obj); TpBaseConnection *base = TP_BASE_CONNECTION (obj); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; GHashTable *result; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, TpHandle, i); GPtrArray *arr = g_hash_table_lookup (self->priv->capabilities, GUINT_TO_POINTER (handle)); if (arr != NULL) { g_hash_table_insert (result, GUINT_TO_POINTER (handle), arr); } } tp_svc_connection_interface_contact_capabilities_return_from_get_contact_capabilities ( context, result); g_hash_table_destroy (result); } static void init_contact_caps (gpointer g_iface, gpointer iface_data) { TpSvcConnectionInterfaceContactCapabilitiesClass *klass = g_iface; #define IMPLEMENT(x) tp_svc_connection_interface_contact_capabilities_implement_##x (\ klass, my_##x) IMPLEMENT(get_contact_capabilities); #undef IMPLEMENT } static GPtrArray * lookup_contact_info (TpTestsContactsConnection *self, TpHandle handle) { GPtrArray *ret = g_hash_table_lookup (self->priv->contact_info, GUINT_TO_POINTER (handle)); if (ret == NULL && self->priv->default_contact_info != NULL) { ret = self->priv->default_contact_info; g_hash_table_insert (self->priv->contact_info, GUINT_TO_POINTER (handle), g_ptr_array_ref (ret)); } if (ret == NULL) return g_ptr_array_new (); return g_ptr_array_ref (ret); } static void my_refresh_contact_info (TpSvcConnectionInterfaceContactInfo *obj, const GArray *contacts, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (obj); TpBaseConnection *base = TP_BASE_CONNECTION (obj); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } self->refresh_contact_info_called++; for (i = 0; i < contacts->len; i++) { TpHandle handle = g_array_index (contacts, guint, i); // actually update the info (if not using the default info) so there is an actual change g_hash_table_insert (self->priv->contact_info, GUINT_TO_POINTER (handle), g_ptr_array_ref (self->priv->default_contact_info)); tp_svc_connection_interface_contact_info_emit_contact_info_changed (self, handle, self->priv->default_contact_info); } tp_svc_connection_interface_contact_info_return_from_refresh_contact_info ( context); } static void my_request_contact_info (TpSvcConnectionInterfaceContactInfo *obj, guint handle, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (obj); TpBaseConnection *base = TP_BASE_CONNECTION (obj); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; GPtrArray *ret; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handle_is_valid (contact_repo, handle, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } ret = lookup_contact_info (self, handle); tp_svc_connection_interface_contact_info_return_from_request_contact_info ( context, ret); g_ptr_array_unref (ret); } static void my_set_contact_info (TpSvcConnectionInterfaceContactInfo *obj, const GPtrArray *info, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (obj); TpBaseConnection *base = TP_BASE_CONNECTION (obj); GPtrArray *copy; guint i; TpHandle self_handle; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); /* Deep copy info */ copy = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free); for (i = 0; i < info->len; i++) g_ptr_array_add (copy, g_value_array_copy (g_ptr_array_index (info, i))); self_handle = tp_base_connection_get_self_handle (base); g_hash_table_insert (self->priv->contact_info, GUINT_TO_POINTER (self_handle), copy); tp_svc_connection_interface_contact_info_return_from_set_contact_info ( context); } static void init_contact_info (gpointer g_iface, gpointer iface_data) { TpSvcConnectionInterfaceContactInfoClass *klass = g_iface; #define IMPLEMENT(x) tp_svc_connection_interface_contact_info_implement_##x (\ klass, my_##x) IMPLEMENT (refresh_contact_info); IMPLEMENT (request_contact_info); IMPLEMENT (set_contact_info); #undef IMPLEMENT } static void my_request_client_types (TpSvcConnectionInterfaceClientTypes *obj, guint handle, DBusGMethodInvocation *context) { TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (obj); TpBaseConnection *base = TP_BASE_CONNECTION (obj); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; gchar **types; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handle_is_valid (contact_repo, handle, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } types = g_hash_table_lookup(self->priv->client_types, GUINT_TO_POINTER (handle)); tp_svc_connection_interface_client_types_return_from_request_client_types ( context, (const gchar **) types); } static void init_client_types (gpointer g_iface, gpointer iface_data) { TpSvcConnectionInterfaceClientTypesClass *klass = g_iface; #define IMPLEMENT(x) tp_svc_connection_interface_client_types_implement_##x (\ klass, my_##x) /* IMPLEMENT (get_client_types); */ IMPLEMENT (request_client_types); #undef IMPLEMENT } /* =============== Legacy version (no Contacts interface) ================= */ G_DEFINE_TYPE (TpTestsLegacyContactsConnection, tp_tests_legacy_contacts_connection, TP_TESTS_TYPE_CONTACTS_CONNECTION); enum { LEGACY_PROP_HAS_IMMORTAL_HANDLES = 1 }; static void legacy_contacts_connection_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { case LEGACY_PROP_HAS_IMMORTAL_HANDLES: /* Pretend we don't. */ g_value_set_boolean (value, FALSE); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void tp_tests_legacy_contacts_connection_init (TpTestsLegacyContactsConnection *self) { } static void tp_tests_legacy_contacts_connection_class_init ( TpTestsLegacyContactsConnectionClass *klass) { /* Leave Contacts out of the interfaces we say are present, so clients * won't use it */ static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_ALIASING, TP_IFACE_CONNECTION_INTERFACE_AVATARS, TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_LOCATION, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, NULL }; TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; object_class->get_property = legacy_contacts_connection_get_property; base_class->interfaces_always_present = interfaces_always_present; g_object_class_override_property (object_class, LEGACY_PROP_HAS_IMMORTAL_HANDLES, "has-immortal-handles"); } /* =============== No Requests and no ContactCapabilities ================= */ G_DEFINE_TYPE (TpTestsNoRequestsConnection, tp_tests_no_requests_connection, TP_TESTS_TYPE_CONTACTS_CONNECTION); static void tp_tests_no_requests_connection_init (TpTestsNoRequestsConnection *self) { } static void tp_tests_no_requests_connection_class_init ( TpTestsNoRequestsConnectionClass *klass) { static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_ALIASING, TP_IFACE_CONNECTION_INTERFACE_AVATARS, TP_IFACE_CONNECTION_INTERFACE_CONTACTS, TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_LOCATION, NULL }; TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; base_class->interfaces_always_present = interfaces_always_present; } telepathy-qt-0.9.6~git1/tests/lib/glib/params-cm.c0000664000175000017500000001454312470405660017630 0ustar jrjr/* * params-cm.h - source for TpTestsParamConnectionManager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "params-cm.h" #include #include #include G_DEFINE_TYPE (TpTestsParamConnectionManager, tp_tests_param_connection_manager, TP_TYPE_BASE_CONNECTION_MANAGER) struct _TpTestsParamConnectionManagerPrivate { int dummy; }; static void tp_tests_param_connection_manager_init ( TpTestsParamConnectionManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_PARAM_CONNECTION_MANAGER, TpTestsParamConnectionManagerPrivate); } enum { TP_TESTS_PARAM_STRING, TP_TESTS_PARAM_INT16, TP_TESTS_PARAM_INT32, TP_TESTS_PARAM_UINT16, TP_TESTS_PARAM_UINT32, TP_TESTS_PARAM_INT64, TP_TESTS_PARAM_UINT64, TP_TESTS_PARAM_BOOLEAN, TP_TESTS_PARAM_DOUBLE, TP_TESTS_PARAM_ARRAY_STRINGS, TP_TESTS_PARAM_ARRAY_BYTES, TP_TESTS_PARAM_OBJECT_PATH, TP_TESTS_PARAM_LC_STRING, TP_TESTS_PARAM_UC_STRING, NUM_PARAM }; static gboolean filter_string_ascii_case (const TpCMParamSpec *param_spec, GValue *value, GError **error) { const gchar *s = g_value_get_string (value); guint i; for (i = 0; s[i] != '\0'; i++) { int c = s[i]; /* just to avoid -Wtype-limits */ if (c < 0 || c > 127) /* char might be signed or unsigned */ { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s must be ASCII", param_spec->name); return FALSE; } } if (GINT_TO_POINTER (param_spec->filter_data)) g_value_take_string (value, g_ascii_strup (s, -1)); else g_value_take_string (value, g_ascii_strdown (s, -1)); return TRUE; } static TpCMParamSpec param_example_params[] = { { "a-string", "s", G_TYPE_STRING, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, "the default string", G_STRUCT_OFFSET (TpTestsCMParams, a_string), NULL, NULL, NULL }, { "a-int16", "n", G_TYPE_INT, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, GINT_TO_POINTER (42), G_STRUCT_OFFSET (TpTestsCMParams, a_int16), NULL, NULL, NULL }, { "a-int32", "i", G_TYPE_INT, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, GINT_TO_POINTER (42), G_STRUCT_OFFSET (TpTestsCMParams, a_int32), NULL, NULL, NULL }, { "a-uint16", "q", G_TYPE_UINT, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, a_uint16), NULL, NULL, NULL }, { "a-uint32", "u", G_TYPE_UINT, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, a_uint32), NULL, NULL, NULL }, { "a-int64", "x", G_TYPE_INT64, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, a_int64), NULL, NULL, NULL }, { "a-uint64", "t", G_TYPE_UINT64, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, a_uint64), NULL, NULL, NULL }, { "a-boolean", "b", G_TYPE_BOOLEAN, TP_CONN_MGR_PARAM_FLAG_REQUIRED, NULL, G_STRUCT_OFFSET (TpTestsCMParams, a_boolean), NULL, NULL, NULL }, { "a-double", "d", G_TYPE_DOUBLE, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, a_double), NULL, NULL, NULL }, { "a-array-of-strings", "as", 0, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, a_array_of_strings), NULL, NULL, NULL }, { "a-array-of-bytes", "ay", 0, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, a_array_of_bytes), NULL, NULL, NULL }, { "a-object-path", "o", 0, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, a_object_path), NULL, NULL, NULL }, /* demo of a filter */ { "lc-string", "s", G_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, lc_string), filter_string_ascii_case, GINT_TO_POINTER (FALSE), NULL }, { "uc-string", "s", G_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET (TpTestsCMParams, uc_string), filter_string_ascii_case, GINT_TO_POINTER (TRUE), NULL }, { NULL } }; static TpTestsCMParams *params = NULL; static gpointer alloc_params (void) { params = g_slice_new0 (TpTestsCMParams); return params; } static void free_params (gpointer p) { /* CM user is responsible to free params so he can check their values */ params = (TpTestsCMParams *) p; params->would_have_been_freed = TRUE; } static const TpCMProtocolSpec example_protocols[] = { { "example", param_example_params, alloc_params, free_params }, { NULL, NULL } }; static TpBaseConnection * new_connection (TpBaseConnectionManager *self, const gchar *proto, TpIntSet *params_present, gpointer parsed_params, GError **error) { g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "No connection for you"); return NULL; } static void tp_tests_param_connection_manager_class_init ( TpTestsParamConnectionManagerClass *klass) { TpBaseConnectionManagerClass *base_class = (TpBaseConnectionManagerClass *) klass; g_type_class_add_private (klass, sizeof (TpTestsParamConnectionManagerPrivate)); param_example_params[TP_TESTS_PARAM_ARRAY_STRINGS].gtype = G_TYPE_STRV; param_example_params[TP_TESTS_PARAM_ARRAY_BYTES].gtype = DBUS_TYPE_G_UCHAR_ARRAY; param_example_params[TP_TESTS_PARAM_OBJECT_PATH].gtype = DBUS_TYPE_G_OBJECT_PATH; base_class->new_connection = new_connection; base_class->cm_dbus_name = "params_cm"; base_class->protocol_params = example_protocols; } TpTestsCMParams * tp_tests_param_connection_manager_steal_params_last_conn (void) { TpTestsCMParams *p = params; params = NULL; return p; } void tp_tests_param_connection_manager_free_params (TpTestsCMParams *p) { g_free (p->a_string); g_strfreev (p->a_array_of_strings); if (p->a_array_of_bytes != NULL) g_array_free (p->a_array_of_bytes, TRUE); g_free (p->a_object_path); g_slice_free (TpTestsCMParams, p); } telepathy-qt-0.9.6~git1/tests/lib/glib/simple-channel-dispatch-operation.c0000664000175000017500000002224012470405660024433 0ustar jrjr/* * simple-channel-dispatch-operation.c - a simple channel dispatch operation * service. * * Copyright © 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "simple-channel-dispatch-operation.h" #include #include #include #include #include #include #include #include #include static void channel_dispatch_operation_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (TpTestsSimpleChannelDispatchOperation, tp_tests_simple_channel_dispatch_operation, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_DISPATCH_OPERATION, channel_dispatch_operation_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init) ) /* TP_IFACE_CHANNEL_DISPATCH_OPERATION is implied */ static const char *CHANNEL_DISPATCH_OPERATION_INTERFACES[] = { NULL }; static const gchar *CHANNEL_DISPATCH_OPERATION_POSSIBLE_HANDLERS[] = { TP_CLIENT_BUS_NAME_BASE ".Badger", NULL, }; enum { PROP_0, PROP_INTERFACES, PROP_CONNECTION, PROP_ACCOUNT, PROP_CHANNELS, PROP_POSSIBLE_HANDLERS, }; struct _SimpleChannelDispatchOperationPrivate { gchar *conn_path; gchar *account_path; /* Array of TpChannel */ GPtrArray *channels; }; static void tp_tests_simple_channel_dispatch_operation_handle_with ( TpSvcChannelDispatchOperation *iface, const gchar *handler, DBusGMethodInvocation *context) { if (!tp_strdiff (handler, "FAIL")) { GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Nope" }; dbus_g_method_return_error (context, &error); return; } dbus_g_method_return (context); } static void tp_tests_simple_channel_dispatch_operation_claim ( TpSvcChannelDispatchOperation *iface, DBusGMethodInvocation *context) { dbus_g_method_return (context); } static void tp_tests_simple_channel_dispatch_operation_handle_with_time ( TpSvcChannelDispatchOperation *iface, const gchar *handler, gint64 user_action_timestamp, DBusGMethodInvocation *context) { dbus_g_method_return (context); } static void channel_dispatch_operation_iface_init (gpointer klass, gpointer unused G_GNUC_UNUSED) { #define IMPLEMENT(x) tp_svc_channel_dispatch_operation_implement_##x (\ klass, tp_tests_simple_channel_dispatch_operation_##x) IMPLEMENT(handle_with); IMPLEMENT(claim); IMPLEMENT(handle_with_time); #undef IMPLEMENT } static void tp_tests_simple_channel_dispatch_operation_init (TpTestsSimpleChannelDispatchOperation *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCH_OPERATION, TpTestsSimpleChannelDispatchOperationPrivate); self->priv->channels = g_ptr_array_new_with_free_func ( (GDestroyNotify) g_object_unref); } static void tp_tests_simple_channel_dispatch_operation_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { TpTestsSimpleChannelDispatchOperation *self = TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION (object); switch (property_id) { case PROP_INTERFACES: g_value_set_boxed (value, CHANNEL_DISPATCH_OPERATION_INTERFACES); break; case PROP_ACCOUNT: g_value_set_boxed (value, self->priv->account_path); break; case PROP_CONNECTION: g_value_set_boxed (value, self->priv->conn_path); break; case PROP_CHANNELS: { GPtrArray *arr = g_ptr_array_new (); guint i; for (i = 0; i < self->priv->channels->len; i++) { TpChannel *channel = g_ptr_array_index (self->priv->channels, i); GValue props_value = G_VALUE_INIT; GVariant *props_variant; /* Yay, double conversion! But this is for tests corner case */ props_variant = tp_channel_dup_immutable_properties (channel); dbus_g_value_parse_g_variant (props_variant, &props_value); g_ptr_array_add (arr, tp_value_array_build (2, DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (channel), TP_HASH_TYPE_STRING_VARIANT_MAP, g_value_get_boxed (&props_value), G_TYPE_INVALID)); g_variant_unref (props_variant); g_value_unset (&props_value); } g_value_take_boxed (value, arr); } break; case PROP_POSSIBLE_HANDLERS: g_value_set_boxed (value, CHANNEL_DISPATCH_OPERATION_POSSIBLE_HANDLERS); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); break; } } static void tp_tests_simple_channel_dispatch_operation_finalize (GObject *object) { TpTestsSimpleChannelDispatchOperation *self = TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION (object); void (*finalize) (GObject *) = G_OBJECT_CLASS (tp_tests_simple_channel_dispatch_operation_parent_class)->finalize; g_free (self->priv->conn_path); g_free (self->priv->account_path); g_ptr_array_free (self->priv->channels, TRUE); if (finalize != NULL) finalize (object); } /** * This class currently only provides the minimum for * tp_channel_dispatch_operation_prepare to succeed. This turns out to be only a working * Properties.GetAll(). */ static void tp_tests_simple_channel_dispatch_operation_class_init (TpTestsSimpleChannelDispatchOperationClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; static TpDBusPropertiesMixinPropImpl a_props[] = { { "Interfaces", "interfaces", NULL }, { "Connection", "connection", NULL }, { "Account", "account", NULL }, { "Channels", "channels", NULL }, { "PossibleHandlers", "possible-handlers", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CHANNEL_DISPATCH_OPERATION, tp_dbus_properties_mixin_getter_gobject_properties, NULL, a_props }, { NULL }, }; g_type_class_add_private (klass, sizeof (TpTestsSimpleChannelDispatchOperationPrivate)); object_class->get_property = tp_tests_simple_channel_dispatch_operation_get_property; object_class->finalize = tp_tests_simple_channel_dispatch_operation_finalize; param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "In this case we only implement ChannelDispatchOperation, so none.", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_boxed ("connection", "connection path", "Connection path", DBUS_TYPE_G_OBJECT_PATH, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_boxed ("account", "account path", "Account path", DBUS_TYPE_G_OBJECT_PATH, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); param_spec = g_param_spec_boxed ("channels", "channel paths", "Channel paths", TP_ARRAY_TYPE_CHANNEL_DETAILS_LIST, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CHANNELS, param_spec); param_spec = g_param_spec_boxed ("possible-handlers", "possible handlers", "possible handles", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_POSSIBLE_HANDLERS, param_spec); klass->dbus_props_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsSimpleChannelDispatchOperationClass, dbus_props_class)); } void tp_tests_simple_channel_dispatch_operation_set_conn_path ( TpTestsSimpleChannelDispatchOperation *self, const gchar *conn_path) { self->priv->conn_path = g_strdup (conn_path); } void tp_tests_simple_channel_dispatch_operation_add_channel ( TpTestsSimpleChannelDispatchOperation *self, TpChannel *chan) { g_ptr_array_add (self->priv->channels, g_object_ref (chan)); } void tp_tests_simple_channel_dispatch_operation_lost_channel ( TpTestsSimpleChannelDispatchOperation *self, TpChannel *chan) { const gchar *path = tp_proxy_get_object_path (chan); g_ptr_array_remove (self->priv->channels, chan); tp_svc_channel_dispatch_operation_emit_channel_lost (self, path, TP_ERROR_STR_NOT_AVAILABLE, "Badger"); if (self->priv->channels->len == 0) { /* We removed the last channel; fire Finished */ tp_svc_channel_dispatch_operation_emit_finished (self); } } void tp_tests_simple_channel_dispatch_operation_set_account_path ( TpTestsSimpleChannelDispatchOperation *self, const gchar *account_path) { self->priv->account_path = g_strdup (account_path); } telepathy-qt-0.9.6~git1/tests/lib/glib/textchan-group.c0000664000175000017500000003215112470405660020713 0ustar jrjr/* * a stub anonymous MUC * * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ //TODO This either needs to be ported away from TpTextMixin, //or we need to use another test CM instead of this one on the tests where it is used. //tp-glib has not ported it because it is used in TpTextMixin tests. #define _TP_IGNORE_DEPRECATIONS #include "textchan-group.h" #include #include #include #include #include #include #include static void text_iface_init (gpointer iface, gpointer data); static void channel_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (TpTestsTextChannelGroup, tp_tests_text_channel_group, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, text_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, tp_group_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init)) static const char *text_channel_group_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_GROUP, NULL }; /* type definition stuff */ enum { PROP_OBJECT_PATH = 1, PROP_CHANNEL_TYPE, PROP_HANDLE_TYPE, PROP_HANDLE, PROP_TARGET_ID, PROP_CONNECTION, PROP_INTERFACES, PROP_REQUESTED, PROP_INITIATOR_HANDLE, PROP_INITIATOR_ID, PROP_DETAILED, PROP_PROPERTIES, N_PROPS }; struct _TpTestsTextChannelGroupPrivate { gchar *object_path; gboolean detailed; gboolean properties; gboolean closed; gboolean disposed; }; static gboolean add_member (GObject *obj, TpHandle handle, const gchar *message, GError **error) { TpTestsTextChannelGroup *self = TP_TESTS_TEXT_CHANNEL_GROUP (obj); TpIntSet *add = tp_intset_new (); tp_intset_add (add, handle); tp_group_mixin_change_members (obj, message, add, NULL, NULL, NULL, self->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (add); return TRUE; } static void tp_tests_text_channel_group_init (TpTestsTextChannelGroup *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_TEXT_CHANNEL_GROUP, TpTestsTextChannelGroupPrivate); } static GObject * constructor (GType type, guint n_props, GObjectConstructParam *props) { GObject *object = G_OBJECT_CLASS (tp_tests_text_channel_group_parent_class)->constructor (type, n_props, props); TpTestsTextChannelGroup *self = TP_TESTS_TEXT_CHANNEL_GROUP (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->conn, TP_HANDLE_TYPE_CONTACT); TpChannelGroupFlags flags = 0; tp_dbus_daemon_register_object ( tp_base_connection_get_dbus_daemon (self->conn), self->priv->object_path, self); tp_text_mixin_init (object, G_STRUCT_OFFSET (TpTestsTextChannelGroup, text), contact_repo); tp_text_mixin_set_message_types (object, TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION, TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE, G_MAXUINT); if (self->priv->detailed) flags |= TP_CHANNEL_GROUP_FLAG_MEMBERS_CHANGED_DETAILED; if (self->priv->properties) flags |= TP_CHANNEL_GROUP_FLAG_PROPERTIES; tp_group_mixin_init (object, G_STRUCT_OFFSET (TpTestsTextChannelGroup, group), contact_repo, self->conn->self_handle); tp_group_mixin_change_flags (object, flags, 0); return object; } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { TpTestsTextChannelGroup *self = TP_TESTS_TEXT_CHANNEL_GROUP (object); switch (property_id) { case PROP_OBJECT_PATH: g_value_set_string (value, self->priv->object_path); break; case PROP_CHANNEL_TYPE: g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT); break; case PROP_HANDLE_TYPE: g_value_set_uint (value, TP_HANDLE_TYPE_NONE); break; case PROP_HANDLE: g_value_set_uint (value, 0); break; case PROP_TARGET_ID: g_value_set_static_string (value, ""); break; case PROP_REQUESTED: g_value_set_boolean (value, TRUE); break; case PROP_INITIATOR_HANDLE: g_value_set_uint (value, self->conn->self_handle); break; case PROP_INITIATOR_ID: { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( self->conn, TP_HANDLE_TYPE_CONTACT); g_value_set_string (value, tp_handle_inspect (contact_repo, self->conn->self_handle)); } break; case PROP_INTERFACES: g_value_set_boxed (value, text_channel_group_interfaces); break; case PROP_CONNECTION: g_value_set_object (value, self->conn); break; case PROP_DETAILED: g_value_set_boolean (value, self->priv->detailed); break; case PROP_PROPERTIES: g_value_set_boolean (value, self->priv->properties); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { TpTestsTextChannelGroup *self = TP_TESTS_TEXT_CHANNEL_GROUP (object); switch (property_id) { case PROP_OBJECT_PATH: g_free (self->priv->object_path); self->priv->object_path = g_value_dup_string (value); break; case PROP_HANDLE: case PROP_HANDLE_TYPE: case PROP_CHANNEL_TYPE: /* these properties are writable in the interface, but not actually * meaningfully changable on this channel, so we do nothing */ break; case PROP_CONNECTION: self->conn = g_value_get_object (value); break; case PROP_DETAILED: self->priv->detailed = g_value_get_boolean (value); break; case PROP_PROPERTIES: self->priv->properties = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dispose (GObject *object) { TpTestsTextChannelGroup *self = TP_TESTS_TEXT_CHANNEL_GROUP (object); if (self->priv->disposed) return; self->priv->disposed = TRUE; if (!self->priv->closed) { tp_svc_channel_emit_closed (self); } ((GObjectClass *) tp_tests_text_channel_group_parent_class)->dispose (object); } static void finalize (GObject *object) { TpTestsTextChannelGroup *self = TP_TESTS_TEXT_CHANNEL_GROUP (object); g_free (self->priv->object_path); tp_text_mixin_finalize (object); tp_group_mixin_finalize (object); ((GObjectClass *) tp_tests_text_channel_group_parent_class)->finalize (object); } static void tp_tests_text_channel_group_class_init (TpTestsTextChannelGroupClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; static TpDBusPropertiesMixinPropImpl channel_props[] = { { "TargetHandleType", "handle-type", NULL }, { "TargetHandle", "handle", NULL }, { "ChannelType", "channel-type", NULL }, { "Interfaces", "interfaces", NULL }, { "TargetID", "target-id", NULL }, { "Requested", "requested", NULL }, { "InitiatorHandle", "initiator-handle", NULL }, { "InitiatorID", "initiator-id", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CHANNEL, tp_dbus_properties_mixin_getter_gobject_properties, NULL, channel_props, }, { NULL } }; g_type_class_add_private (klass, sizeof (TpTestsTextChannelGroupPrivate)); object_class->constructor = constructor; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path"); g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type"); g_object_class_override_property (object_class, PROP_HANDLE, "handle"); param_spec = g_param_spec_object ("connection", "TpBaseConnection object", "Connection object that owns this channel", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "Additional Channel.Interface.* interfaces", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_string ("target-id", "Peer's ID", "Always the empty string on this channel", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", "The contact who initiated the channel", 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, param_spec); param_spec = g_param_spec_string ("initiator-id", "Initiator's ID", "The string obtained by inspecting the initiator-handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_ID, param_spec); param_spec = g_param_spec_boolean ("requested", "Requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); param_spec = g_param_spec_boolean ("detailed", "Has the Members_Changed_Detailed flag?", "True if the Members_Changed_Detailed group flag should be set", TRUE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_DETAILED, param_spec); param_spec = g_param_spec_boolean ("properties", "Has the Properties flag?", "True if the Properties group flag should be set", TRUE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_PROPERTIES, param_spec); tp_text_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsTextChannelGroupClass, text_class)); tp_group_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsTextChannelGroupClass, group_class), add_member, NULL); klass->dbus_properties_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsTextChannelGroupClass, dbus_properties_class)); tp_group_mixin_init_dbus_properties (object_class); } static void channel_close (TpSvcChannel *iface, DBusGMethodInvocation *context) { TpTestsTextChannelGroup *self = TP_TESTS_TEXT_CHANNEL_GROUP (iface); if (!self->priv->closed) { self->priv->closed = TRUE; tp_svc_channel_emit_closed (self); } tp_svc_channel_return_from_close (context); } static void channel_get_channel_type (TpSvcChannel *iface, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_channel_type (context, TP_IFACE_CHANNEL_TYPE_TEXT); } static void channel_get_handle (TpSvcChannel *iface, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_NONE, 0); } static void channel_get_interfaces (TpSvcChannel *iface, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_interfaces (context, text_channel_group_interfaces); } static void channel_iface_init (gpointer iface, gpointer data) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x) IMPLEMENT (close); IMPLEMENT (get_channel_type); IMPLEMENT (get_handle); IMPLEMENT (get_interfaces); #undef IMPLEMENT } static void text_send (TpSvcChannelTypeText *iface, guint type, const gchar *text, DBusGMethodInvocation *context) { /* silently swallow the message */ tp_svc_channel_type_text_return_from_send (context); } static void text_iface_init (gpointer iface, gpointer data) { TpSvcChannelTypeTextClass *klass = iface; tp_text_mixin_iface_init (iface, data); #define IMPLEMENT(x) tp_svc_channel_type_text_implement_##x (klass, text_##x) IMPLEMENT (send); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/simple-conn.h0000664000175000017500000000502712470405660020176 0ustar jrjr/* * simple-conn.h - header for a simple connection * * Copyright (C) 2007-2008 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_SIMPLE_CONN_H__ #define __TP_TESTS_SIMPLE_CONN_H__ #include #include G_BEGIN_DECLS typedef struct _TpTestsSimpleConnection TpTestsSimpleConnection; typedef struct _TpTestsSimpleConnectionClass TpTestsSimpleConnectionClass; typedef struct _TpTestsSimpleConnectionPrivate TpTestsSimpleConnectionPrivate; struct _TpTestsSimpleConnectionClass { TpBaseConnectionClass parent_class; }; struct _TpTestsSimpleConnection { TpBaseConnection parent; TpTestsSimpleConnectionPrivate *priv; }; GType tp_tests_simple_connection_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_SIMPLE_CONNECTION \ (tp_tests_simple_connection_get_type ()) #define TP_TESTS_SIMPLE_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_SIMPLE_CONNECTION, \ TpTestsSimpleConnection)) #define TP_TESTS_SIMPLE_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_SIMPLE_CONNECTION, \ TpTestsSimpleConnectionClass)) #define TP_TESTS_SIMPLE_IS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_SIMPLE_CONNECTION)) #define TP_TESTS_SIMPLE_IS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_SIMPLE_CONNECTION)) #define TP_TESTS_SIMPLE_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_SIMPLE_CONNECTION, \ TpTestsSimpleConnectionClass)) TpTestsSimpleConnection * tp_tests_simple_connection_new (const gchar *account, const gchar *protocol); /* Cause "network events", for debugging/testing */ void tp_tests_simple_connection_inject_disconnect ( TpTestsSimpleConnection *self); void tp_tests_simple_connection_set_identifier (TpTestsSimpleConnection *self, const gchar *identifier); gchar * tp_tests_simple_connection_ensure_text_chan ( TpTestsSimpleConnection *self, const gchar *target_id, GHashTable **props); void tp_tests_simple_connection_set_get_self_handle_error ( TpTestsSimpleConnection *self, GQuark domain, gint code, const gchar *message); G_END_DECLS #endif /* #ifndef __TP_TESTS_SIMPLE_CONN_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/dbus-tube-chan.h0000664000175000017500000001202112470405660020543 0ustar jrjr/* * dbus-tube-chan.h - Simple dbus tube channel * * Copyright (C) 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_DBUS_TUBE_CHAN_H__ #define __TP_DBUS_TUBE_CHAN_H__ #include #include #include #include G_BEGIN_DECLS /* Base Class */ typedef struct _TpTestsDBusTubeChannel TpTestsDBusTubeChannel; typedef struct _TpTestsDBusTubeChannelClass TpTestsDBusTubeChannelClass; typedef struct _TpTestsDBusTubeChannelPrivate TpTestsDBusTubeChannelPrivate; GType tp_tests_dbus_tube_channel_get_type (void); #define TP_TESTS_TYPE_DBUS_TUBE_CHANNEL \ (tp_tests_dbus_tube_channel_get_type ()) #define TP_TESTS_DBUS_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_DBUS_TUBE_CHANNEL, \ TpTestsDBusTubeChannel)) #define TP_TESTS_DBUS_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_DBUS_TUBE_CHANNEL, \ TpTestsDBusTubeChannelClass)) #define TP_TESTS_IS_DBUS_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_DBUS_TUBE_CHANNEL)) #define TP_TESTS_IS_DBUS_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_DBUS_TUBE_CHANNEL)) #define TP_TESTS_DBUS_TUBE_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_DBUS_TUBE_CHANNEL, \ TpTestsDBusTubeChannelClass)) struct _TpTestsDBusTubeChannelClass { TpBaseChannelClass parent_class; TpTextMixinClass text_class; TpDBusPropertiesMixinClass dbus_properties_class; }; struct _TpTestsDBusTubeChannel { TpBaseChannel parent; TpTextMixin text; TpTestsDBusTubeChannelPrivate *priv; }; /* Contact DBus Tube */ typedef struct _TpTestsContactDBusTubeChannel TpTestsContactDBusTubeChannel; typedef struct _TpTestsContactDBusTubeChannelClass TpTestsContactDBusTubeChannelClass; GType tp_tests_contact_dbus_tube_channel_get_type (void); void tp_tests_dbus_tube_channel_set_close_on_accept ( TpTestsDBusTubeChannel *self, gboolean close_on_accept); void tp_tests_dbus_tube_channel_peer_connected_no_stream ( TpTestsDBusTubeChannel *self, gchar *bus_name, TpHandle handle); void tp_tests_dbus_tube_channel_peer_disconnected ( TpTestsDBusTubeChannel *self, TpHandle handle); #define TP_TESTS_TYPE_CONTACT_DBUS_TUBE_CHANNEL \ (tp_tests_contact_dbus_tube_channel_get_type ()) #define TP_TESTS_CONTACT_DBUS_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_CONTACT_DBUS_TUBE_CHANNEL, \ TpTestsContactDBusTubeChannel)) #define TP_TESTS_CONTACT_DBUS_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_CONTACT_DBUS_TUBE_CHANNEL, \ TpTestsContactDBusTubeChannelClass)) #define TP_TESTS_IS_CONTACT_DBUS_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_CONTACT_DBUS_TUBE_CHANNEL)) #define TP_TESTS_IS_CONTACT_DBUS_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_CONTACT_DBUS_TUBE_CHANNEL)) #define TP_TESTS_CONTACT_DBUS_TUBE_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_CONTACT_DBUS_TUBE_CHANNEL, \ TpTestsContactDBusTubeChannelClass)) struct _TpTestsContactDBusTubeChannelClass { TpTestsDBusTubeChannelClass parent_class; }; struct _TpTestsContactDBusTubeChannel { TpTestsDBusTubeChannel parent; }; /* Room DBus Tube */ typedef struct _TpTestsRoomDBusTubeChannel TpTestsRoomDBusTubeChannel; typedef struct _TpTestsRoomDBusTubeChannelClass TpTestsRoomDBusTubeChannelClass; GType tp_tests_room_dbus_tube_channel_get_type (void); #define TP_TESTS_TYPE_ROOM_DBUS_TUBE_CHANNEL \ (tp_tests_room_dbus_tube_channel_get_type ()) #define TP_TESTS_ROOM_DBUS_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_ROOM_DBUS_TUBE_CHANNEL, \ TpTestsRoomDBusTubeChannel)) #define TP_TESTS_ROOM_DBUS_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_ROOM_DBUS_TUBE_CHANNEL, \ TpTestsRoomDBusTubeChannelClass)) #define TP_TESTS_IS_ROOM_DBUS_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_ROOM_DBUS_TUBE_CHANNEL)) #define TP_TESTS_IS_ROOM_DBUS_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_ROOM_DBUS_TUBE_CHANNEL)) #define TP_TESTS_ROOM_DBUS_TUBE_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_ROOM_DBUS_TUBE_CHANNEL, \ TpTestsRoomDBusTubeChannelClass)) struct _TpTestsRoomDBusTubeChannelClass { TpTestsDBusTubeChannelClass parent_class; }; struct _TpTestsRoomDBusTubeChannel { TpTestsDBusTubeChannel parent; }; G_END_DECLS #endif /* #ifndef __TP_DBUS_TUBE_CHAN_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/contact-list-manager.h0000664000175000017500000000517112470405660021766 0ustar jrjr/* * Example channel manager for contact lists * * Copyright © 2007-2010 Collabora Ltd. * Copyright © 2007-2010 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TEST_CONTACT_LIST_MANAGER_H__ #define __TEST_CONTACT_LIST_MANAGER_H__ #include G_BEGIN_DECLS #define TEST_TYPE_CONTACT_LIST_MANAGER \ (test_contact_list_manager_get_type ()) #define TEST_CONTACT_LIST_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TEST_TYPE_CONTACT_LIST_MANAGER, \ TestContactListManager)) #define TEST_CONTACT_LIST_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TEST_TYPE_CONTACT_LIST_MANAGER, \ TestContactListManagerClass)) #define TEST_IS_CONTACT_LIST_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TEST_TYPE_CONTACT_LIST_MANAGER)) #define TEST_IS_CONTACT_LIST_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TEST_TYPE_CONTACT_LIST_MANAGER)) #define TEST_CONTACT_LIST_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_CONTACT_LIST_MANAGER, \ TestContactListManagerClass)) typedef struct _TestContactListManager TestContactListManager; typedef struct _TestContactListManagerClass TestContactListManagerClass; typedef struct _TestContactListManagerPrivate TestContactListManagerPrivate; struct _TestContactListManagerClass { TpBaseContactListClass parent_class; }; struct _TestContactListManager { TpBaseContactList parent; TestContactListManagerPrivate *priv; }; GType test_contact_list_manager_get_type (void); void test_contact_list_manager_add_to_group (TestContactListManager *self, const gchar *group_name, TpHandle member); void test_contact_list_manager_remove_from_group (TestContactListManager *self, const gchar *group_name, TpHandle member); void test_contact_list_manager_request_subscription (TestContactListManager *self, guint n_members, TpHandle *members, const gchar *message); void test_contact_list_manager_unsubscribe (TestContactListManager *self, guint n_members, TpHandle *members); void test_contact_list_manager_authorize_publication (TestContactListManager *self, guint n_members, TpHandle *members); void test_contact_list_manager_unpublish (TestContactListManager *self, guint n_members, TpHandle *members); void test_contact_list_manager_remove (TestContactListManager *self, guint n_members, TpHandle *members); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/simple-manager.h0000664000175000017500000000440012470405660020645 0ustar jrjr/* * simple-manager.h - header for a simple connection manager * Copyright (C) 2007-2008 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_SIMPLE_CONNECTION_MANAGER_H__ #define __TP_TESTS_SIMPLE_CONNECTION_MANAGER_H__ #include #include G_BEGIN_DECLS typedef struct _TpTestsSimpleConnectionManager TpTestsSimpleConnectionManager; typedef struct _TpTestsSimpleConnectionManagerPrivate TpTestsSimpleConnectionManagerPrivate; typedef struct _TpTestsSimpleConnectionManagerClass TpTestsSimpleConnectionManagerClass; typedef struct _TpTestsSimpleConnectionManagerClassPrivate TpTestsSimpleConnectionManagerClassPrivate; struct _TpTestsSimpleConnectionManagerClass { TpBaseConnectionManagerClass parent_class; TpTestsSimpleConnectionManagerClassPrivate *priv; }; struct _TpTestsSimpleConnectionManager { TpBaseConnectionManager parent; TpTestsSimpleConnectionManagerPrivate *priv; }; GType tp_tests_simple_connection_manager_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_SIMPLE_CONNECTION_MANAGER \ (tp_tests_simple_connection_manager_get_type ()) #define TP_TESTS_SIMPLE_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_SIMPLE_CONNECTION_MANAGER, \ simpleConnectionManager)) #define TP_TESTS_SIMPLE_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_SIMPLE_CONNECTION_MANAGER, \ TpTestsSimpleConnectionManagerClass)) #define TP_TESTS_SIMPLE_IS_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_SIMPLE_CONNECTION_MANAGER)) #define TP_TESTS_SIMPLE_IS_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_SIMPLE_CONNECTION_MANAGER)) #define TP_TESTS_SIMPLE_CONNECTION_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_SIMPLE_CONNECTION_MANAGER, \ TpTestsSimpleConnectionManagerClass)) G_END_DECLS #endif /* #ifndef __TP_TESTS_SIMPLE_CONNECTION_MANAGER_H__*/ telepathy-qt-0.9.6~git1/tests/lib/glib/CMakeLists.txt0000664000175000017500000000402112470405660020332 0ustar jrjrinclude_directories( ${CMAKE_CURRENT_BINARY_DIR} ${TELEPATHY_GLIB_INCLUDE_DIR} ${GLIB2_INCLUDE_DIR} ${GOBJECT_INCLUDE_DIR} ${GIO_INCLUDE_DIR} ${GIOUNIX_INCLUDE_DIR} ${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR}) if(ENABLE_TP_GLIB_TESTS) add_subdirectory(call) add_subdirectory(callable) add_subdirectory(contactlist) add_subdirectory(contactlist2) add_subdirectory(echo) add_subdirectory(echo2) add_subdirectory(future) set(tp_glib_tests_SRCS bug16307-conn.c bug16307-conn.h captcha-chan.c captcha-chan.h contacts-conn.c contacts-conn.h contacts-noroster-conn.c contacts-noroster-conn.h contact-list-manager.h contact-list-manager.c contact-search-chan.c contact-search-chan.h debug.h params-cm.c params-cm.h simple-account.c simple-account.h simple-account-manager.c simple-account-manager.h simple-channel-dispatch-operation.c simple-channel-dispatch-operation.h simple-client.c simple-client.h simple-conn.c simple-conn.h simple-manager.c simple-manager.h textchan-group.c textchan-group.h textchan-null.c textchan-null.h util.c util.h) if(ENABLE_TP_GLIB_GIO_TESTS) list(APPEND tp_glib_tests_SRCS dbus-tube-chan.c dbus-tube-chan.h stream-tube-chan.c stream-tube-chan.h) endif(ENABLE_TP_GLIB_GIO_TESTS) add_library(tp-glib-tests SHARED ${tp_glib_tests_SRCS}) target_link_libraries(tp-glib-tests ${TELEPATHY_GLIB_LIBRARIES} ${GLIB2_LIBRARIES} ${GOBJECT_LIBRARIES} ${GIO_LIBRARIES} ${DBUS_GLIB_LIBRARIES} ${DBUS_LIBRARIES} example-cm-call example-cm-callable example-cm-contactlist example-cm-echo example-cm-echo2 tp-glib-tests-future-extensions) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/0000775000175000017500000000000012470405660020206 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/connection-manager.h0000664000175000017500000000454612470405660024137 0ustar jrjr/* * manager.h - header for an example connection manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER_H__ #define __EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER_H__ #include #include G_BEGIN_DECLS typedef struct _ExampleContactListConnectionManager ExampleContactListConnectionManager; typedef struct _ExampleContactListConnectionManagerClass ExampleContactListConnectionManagerClass; typedef struct _ExampleContactListConnectionManagerPrivate ExampleContactListConnectionManagerPrivate; struct _ExampleContactListConnectionManagerClass { TpBaseConnectionManagerClass parent_class; }; struct _ExampleContactListConnectionManager { TpBaseConnectionManager parent; ExampleContactListConnectionManagerPrivate *priv; }; GType example_contact_list_connection_manager_get_type (void); #define EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER \ (example_contact_list_connection_manager_get_type ()) #define EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER, \ ExampleContactListConnectionManager)) #define EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER, \ ExampleContactListConnectionManagerClass)) #define EXAMPLE_IS_CONTACT_LIST_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER)) #define EXAMPLE_IS_CONTACT_LIST_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER)) #define EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER, \ ExampleContactListConnectionManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/example_contact_list.manager0000664000175000017500000000207112470405660025743 0ustar jrjr[ConnectionManager] Interfaces= [Protocol example] Interfaces= ConnectionInterfaces=org.freedesktop.Telepathy.Connection.Interface.Requests;org.freedesktop.Telepathy.Connection.Interface.Contacts;org.freedesktop.Telepathy.Connection.Interface.Presence;org.freedesktop.Telepathy.Connection.Interface.SimplePresence; param-account=s required register param-simulation-delay=u default-simulation-delay=1000 RequestableChannelClasses=contactlist;contactgroup; VCardField=x-telepathy-example EnglishName=Example with a contact list Icon=face-smile [contactlist] org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.ContactList org.freedesktop.Telepathy.Channel.TargetHandleType u=3 allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID; [contactgroup] org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.ContactList org.freedesktop.Telepathy.Channel.TargetHandleType u=4 allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID; telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/contact-list.h0000664000175000017500000000503112470405660022762 0ustar jrjr/* * Example channel manager for contact lists * * Copyright © 2007-2010 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_CONTACT_LIST_H__ #define __EXAMPLE_CONTACT_LIST_H__ #include #include #include #include #include G_BEGIN_DECLS typedef struct _ExampleContactList ExampleContactList; typedef struct _ExampleContactListClass ExampleContactListClass; typedef struct _ExampleContactListPrivate ExampleContactListPrivate; struct _ExampleContactListClass { TpBaseContactListClass parent_class; }; struct _ExampleContactList { TpBaseContactList parent; ExampleContactListPrivate *priv; }; GType example_contact_list_get_type (void); #define EXAMPLE_TYPE_CONTACT_LIST \ (example_contact_list_get_type ()) #define EXAMPLE_CONTACT_LIST(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CONTACT_LIST, \ ExampleContactList)) #define EXAMPLE_CONTACT_LIST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CONTACT_LIST, \ ExampleContactListClass)) #define EXAMPLE_IS_CONTACT_LIST(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CONTACT_LIST)) #define EXAMPLE_IS_CONTACT_LIST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CONTACT_LIST)) #define EXAMPLE_CONTACT_LIST_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CONTACT_LIST, \ ExampleContactListClass)) /* this enum must be kept in sync with the array _statuses in * contact-list.c */ typedef enum { EXAMPLE_CONTACT_LIST_PRESENCE_OFFLINE = 0, EXAMPLE_CONTACT_LIST_PRESENCE_UNKNOWN, EXAMPLE_CONTACT_LIST_PRESENCE_ERROR, EXAMPLE_CONTACT_LIST_PRESENCE_AWAY, EXAMPLE_CONTACT_LIST_PRESENCE_AVAILABLE } ExampleContactListPresence; const TpPresenceStatusSpec *example_contact_list_presence_statuses ( void); ExampleContactListPresence example_contact_list_get_presence ( ExampleContactList *self, TpHandle contact); const gchar *example_contact_list_get_alias ( ExampleContactList *self, TpHandle contact); void example_contact_list_set_alias ( ExampleContactList *self, TpHandle contact, const gchar *alias); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/conn.h0000664000175000017500000000463412470405660021323 0ustar jrjr/* * conn.h - header for an example connection * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_CONTACT_LIST_CONN_H__ #define __EXAMPLE_CONTACT_LIST_CONN_H__ #include #include #include #include G_BEGIN_DECLS typedef struct _ExampleContactListConnection ExampleContactListConnection; typedef struct _ExampleContactListConnectionClass ExampleContactListConnectionClass; typedef struct _ExampleContactListConnectionPrivate ExampleContactListConnectionPrivate; struct _ExampleContactListConnectionClass { TpBaseConnectionClass parent_class; TpPresenceMixinClass presence_mixin; TpContactsMixinClass contacts_mixin; }; struct _ExampleContactListConnection { TpBaseConnection parent; TpPresenceMixin presence_mixin; TpContactsMixin contacts_mixin; ExampleContactListConnectionPrivate *priv; }; GType example_contact_list_connection_get_type (void); #define EXAMPLE_TYPE_CONTACT_LIST_CONNECTION \ (example_contact_list_connection_get_type ()) #define EXAMPLE_CONTACT_LIST_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, \ ExampleContactListConnection)) #define EXAMPLE_CONTACT_LIST_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, \ ExampleContactListConnectionClass)) #define EXAMPLE_IS_CONTACT_LIST_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION)) #define EXAMPLE_IS_CONTACT_LIST_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION)) #define EXAMPLE_CONTACT_LIST_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, \ ExampleContactListConnectionClass)) gchar *example_contact_list_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error); const gchar * const * example_contact_list_connection_get_possible_interfaces ( void); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/CMakeLists.txt0000664000175000017500000000063712470405660022754 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) set(example_cm_contactlist2_SRCS conn.c conn.h connection-manager.c connection-manager.h contact-list.c contact-list.h protocol.c protocol.h) add_library(example-cm-contactlist2 STATIC ${example_cm_contactlist2_SRCS}) target_link_libraries(example-cm-contactlist2 ${TPGLIB_LIBRARIES}) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/contact-list.c0000664000175000017500000015055412470405660022770 0ustar jrjr/* * Example implementation of TpBaseContactList. * * Copyright © 2007-2010 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "contact-list.h" #include #include #include #include /* this array must be kept in sync with the enum * ExampleContactListPresence in contact-list.h */ static const TpPresenceStatusSpec _statuses[] = { { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, NULL }, { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, NULL }, { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, NULL }, { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, NULL }, { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, NULL }, { NULL } }; const TpPresenceStatusSpec * example_contact_list_presence_statuses (void) { return _statuses; } typedef struct { gchar *alias; guint subscribe:1; guint publish:1; guint pre_approved:1; guint subscribe_requested:1; guint subscribe_rejected:1; /* string borrowed from priv->all_tags => the same pointer */ GHashTable *tags; } ExampleContactDetails; static ExampleContactDetails * example_contact_details_new (void) { return g_slice_new0 (ExampleContactDetails); } static void example_contact_details_destroy (gpointer p) { ExampleContactDetails *d = p; tp_clear_pointer (&d->tags, g_hash_table_unref); g_free (d->alias); g_slice_free (ExampleContactDetails, d); } static void mutable_contact_list_iface_init (TpMutableContactListInterface *); static void blockable_contact_list_iface_init ( TpBlockableContactListInterface *); static void contact_group_list_iface_init (TpContactGroupListInterface *); static void mutable_contact_group_list_iface_init ( TpMutableContactGroupListInterface *); G_DEFINE_TYPE_WITH_CODE (ExampleContactList, example_contact_list, TP_TYPE_BASE_CONTACT_LIST, G_IMPLEMENT_INTERFACE (TP_TYPE_BLOCKABLE_CONTACT_LIST, blockable_contact_list_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_CONTACT_GROUP_LIST, contact_group_list_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_MUTABLE_CONTACT_GROUP_LIST, mutable_contact_group_list_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_MUTABLE_CONTACT_LIST, mutable_contact_list_iface_init)) enum { ALIAS_UPDATED, PRESENCE_UPDATED, N_SIGNALS }; static guint signals[N_SIGNALS] = { 0 }; enum { PROP_SIMULATION_DELAY = 1, N_PROPS }; struct _ExampleContactListPrivate { TpBaseConnection *conn; guint simulation_delay; TpHandleRepoIface *contact_repo; /* g_strdup (group name) => the same pointer */ GHashTable *all_tags; /* All contacts on our (fake) protocol-level contact list, * plus all contacts in publish_requests or cancelled_publish_requests */ TpHandleSet *contacts; /* All contacts on our (fake) protocol-level contact list * GUINT_TO_POINTER (handle borrowed from contacts) * => ExampleContactDetails */ GHashTable *contact_details; /* Contacts with an outstanding request for presence publication * (may or may not be in contact_details) * handle borrowed from contacts => g_strdup (message) */ GHashTable *publish_requests; /* Contacts who have requested presence but then cancelled their request * (may or may not be in contact_details) */ TpHandleSet *cancelled_publish_requests; TpHandleSet *blocked_contacts; gulong status_changed_id; }; static void example_contact_list_init (ExampleContactList *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST, ExampleContactListPrivate); self->priv->contact_details = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, example_contact_details_destroy); self->priv->publish_requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); self->priv->all_tags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* initialized properly in constructed() */ self->priv->contact_repo = NULL; self->priv->contacts = NULL; self->priv->blocked_contacts = NULL; self->priv->cancelled_publish_requests = NULL; } static void example_contact_list_close_all (ExampleContactList *self) { tp_clear_pointer (&self->priv->contacts, tp_handle_set_destroy); tp_clear_pointer (&self->priv->blocked_contacts, tp_handle_set_destroy); tp_clear_pointer (&self->priv->cancelled_publish_requests, tp_handle_set_destroy); tp_clear_pointer (&self->priv->publish_requests, g_hash_table_unref); tp_clear_pointer (&self->priv->contact_details, g_hash_table_unref); /* this must come after freeing contact_details, because the strings are * borrowed */ tp_clear_pointer (&self->priv->all_tags, g_hash_table_unref); if (self->priv->status_changed_id != 0) { g_signal_handler_disconnect (self->priv->conn, self->priv->status_changed_id); self->priv->status_changed_id = 0; } } static void dispose (GObject *object) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (object); example_contact_list_close_all (self); ((GObjectClass *) example_contact_list_parent_class)->dispose ( object); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (object); switch (property_id) { case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (object); switch (property_id) { case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static ExampleContactDetails * lookup_contact (ExampleContactList *self, TpHandle contact) { return g_hash_table_lookup (self->priv->contact_details, GUINT_TO_POINTER (contact)); } static ExampleContactDetails * ensure_contact (ExampleContactList *self, TpHandle contact, gboolean *created) { ExampleContactDetails *ret = lookup_contact (self, contact); if (ret == NULL) { tp_handle_set_add (self->priv->contacts, contact); ret = example_contact_details_new (); ret->alias = g_strdup (tp_handle_inspect (self->priv->contact_repo, contact)); g_hash_table_insert (self->priv->contact_details, GUINT_TO_POINTER (contact), ret); /* if we already had a publish request from them, then adding them to * the protocol-level contact list doesn't alter the Telepathy contact * list */ if (created != NULL) { *created = (g_hash_table_lookup (self->priv->publish_requests, GUINT_TO_POINTER (contact)) == NULL); } } else if (created != NULL) { *created = FALSE; } return ret; } static gchar * ensure_tag (ExampleContactList *self, const gchar *s, gboolean emit_signal) { gchar *r = g_hash_table_lookup (self->priv->all_tags, s); if (r == NULL) { g_message ("creating group %s", s); r = g_strdup (s); g_hash_table_insert (self->priv->all_tags, r, r); if (emit_signal) tp_base_contact_list_groups_created ((TpBaseContactList *) self, &s, 1); } return r; } static void example_contact_list_set_contact_groups_async (TpBaseContactList *contact_list, TpHandle contact, const gchar * const *names, gsize n, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); gboolean created; gsize i; ExampleContactDetails *d; GPtrArray *old_names, *new_names; GHashTableIter iter; gpointer k; for (i = 0; i < n; i++) ensure_tag (self, names[i], FALSE); tp_base_contact_list_groups_created (contact_list, names, n); d = ensure_contact (self, contact, &created); if (created) tp_base_contact_list_one_contact_changed (contact_list, contact); if (d->tags == NULL) d->tags = g_hash_table_new (g_str_hash, g_str_equal); old_names = g_ptr_array_sized_new (g_hash_table_size (d->tags)); new_names = g_ptr_array_sized_new (n); for (i = 0; i < n; i++) { if (g_hash_table_lookup (d->tags, names[i]) == NULL) { gchar *tag = g_hash_table_lookup (self->priv->all_tags, names[i]); g_assert (tag != NULL); /* already ensured to exist, above */ g_hash_table_insert (d->tags, tag, tag); g_ptr_array_add (new_names, tag); } } g_hash_table_iter_init (&iter, d->tags); while (g_hash_table_iter_next (&iter, &k, NULL)) { for (i = 0; i < n; i++) { if (!tp_strdiff (names[i], k)) goto next_hash_element; } /* not found in @names, so remove it */ g_ptr_array_add (old_names, k); g_hash_table_iter_remove (&iter); next_hash_element: continue; } tp_base_contact_list_one_contact_groups_changed (contact_list, contact, (const gchar * const *) new_names->pdata, new_names->len, (const gchar * const *) old_names->pdata, old_names->len); g_ptr_array_unref (old_names); g_ptr_array_unref (new_names); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_set_contact_groups_async); } static gboolean receive_contact_lists (gpointer p) { TpBaseContactList *contact_list = p; ExampleContactList *self = p; TpHandle handle; gchar *cambridge, *montreal, *francophones; ExampleContactDetails *d; GHashTableIter iter; gpointer handle_p; if (self->priv->all_tags == NULL) { /* connection already disconnected, so don't process the * "data from the server" */ return FALSE; } /* In a real CM we'd have received a contact list from the server at this * point. But this isn't a real CM, so we have to make one up... */ g_message ("Receiving roster from server"); cambridge = ensure_tag (self, "Cambridge", FALSE); montreal = ensure_tag (self, "Montreal", FALSE); francophones = ensure_tag (self, "Francophones", FALSE); /* Add various people who are already subscribing and publishing */ handle = tp_handle_ensure (self->priv->contact_repo, "sjoerd@example.com", NULL, NULL); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Sjoerd"); d->subscribe = TRUE; d->publish = TRUE; d->tags = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (d->tags, cambridge, cambridge); handle = tp_handle_ensure (self->priv->contact_repo, "guillaume@example.com", NULL, NULL); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Guillaume"); d->subscribe = TRUE; d->publish = TRUE; d->tags = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (d->tags, cambridge, cambridge); g_hash_table_insert (d->tags, francophones, francophones); handle = tp_handle_ensure (self->priv->contact_repo, "olivier@example.com", NULL, NULL); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Olivier"); d->subscribe = TRUE; d->publish = TRUE; d->tags = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (d->tags, montreal, montreal); g_hash_table_insert (d->tags, francophones, francophones); handle = tp_handle_ensure (self->priv->contact_repo, "travis@example.com", NULL, NULL); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Travis"); d->subscribe = TRUE; d->publish = TRUE; /* Add a couple of people whose presence we've requested. They are * remote-pending in subscribe */ handle = tp_handle_ensure (self->priv->contact_repo, "geraldine@example.com", NULL, NULL); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Géraldine"); d->subscribe_requested = TRUE; d->tags = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (d->tags, cambridge, cambridge); g_hash_table_insert (d->tags, francophones, francophones); handle = tp_handle_ensure (self->priv->contact_repo, "helen@example.com", NULL, NULL); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Helen"); d->subscribe_requested = TRUE; d->tags = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (d->tags, cambridge, cambridge); /* Receive a couple of authorization requests too. These people are * local-pending in publish; they're not actually on our protocol-level * contact list */ handle = tp_handle_ensure (self->priv->contact_repo, "wim@example.com", NULL, NULL); tp_handle_set_add (self->priv->contacts, handle); g_hash_table_insert (self->priv->publish_requests, GUINT_TO_POINTER (handle), g_strdup ("I'm more metal than you!")); handle = tp_handle_ensure (self->priv->contact_repo, "christian@example.com", NULL, NULL); tp_handle_set_add (self->priv->contacts, handle); g_hash_table_insert (self->priv->publish_requests, GUINT_TO_POINTER (handle), g_strdup ("I have some fermented herring for you")); /* Add a couple of blocked contacts. */ handle = tp_handle_ensure (self->priv->contact_repo, "bill@example.com", NULL, NULL); tp_handle_set_add (self->priv->blocked_contacts, handle); handle = tp_handle_ensure (self->priv->contact_repo, "steve@example.com", NULL, NULL); tp_handle_set_add (self->priv->blocked_contacts, handle); g_hash_table_iter_init (&iter, self->priv->contact_details); /* emit initial aliases, presences */ while (g_hash_table_iter_next (&iter, &handle_p, NULL)) { handle = GPOINTER_TO_UINT (handle_p); g_signal_emit (self, signals[ALIAS_UPDATED], 0, handle); g_signal_emit (self, signals[PRESENCE_UPDATED], 0, handle); } /* ... and off we go */ tp_base_contact_list_set_list_received (contact_list); return FALSE; } static void status_changed_cb (TpBaseConnection *conn, guint status, guint reason, ExampleContactList *self) { switch (status) { case TP_CONNECTION_STATUS_CONNECTED: { /* Do network I/O to get the contact list. This connection manager * doesn't really have a server, so simulate a small network delay * then invent a contact list */ tp_base_contact_list_set_list_pending ((TpBaseContactList *) self); g_timeout_add_full (G_PRIORITY_DEFAULT, 2 * self->priv->simulation_delay, receive_contact_lists, g_object_ref (self), g_object_unref); } break; case TP_CONNECTION_STATUS_DISCONNECTED: { example_contact_list_close_all (self); tp_clear_object (&self->priv->conn); } break; } } static void constructed (GObject *object) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_contact_list_parent_class)->constructed; if (chain_up != NULL) { chain_up (object); } g_object_get (self, "connection", &self->priv->conn, NULL); g_assert (self->priv->conn != NULL); self->priv->contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); self->priv->contacts = tp_handle_set_new (self->priv->contact_repo); self->priv->blocked_contacts = tp_handle_set_new (self->priv->contact_repo); self->priv->cancelled_publish_requests = tp_handle_set_new ( self->priv->contact_repo); self->priv->status_changed_id = g_signal_connect (self->priv->conn, "status-changed", (GCallback) status_changed_cb, self); } static void send_updated_roster (ExampleContactList *self, TpHandle contact) { ExampleContactDetails *d = g_hash_table_lookup (self->priv->contact_details, GUINT_TO_POINTER (contact)); const gchar *request = g_hash_table_lookup (self->priv->publish_requests, GUINT_TO_POINTER (contact)); const gchar *identifier = tp_handle_inspect (self->priv->contact_repo, contact); /* In a real connection manager, we'd transmit these new details to the * server, rather than just printing messages. */ if (d == NULL) { g_message ("Deleting contact %s from server", identifier); } else { g_message ("Transmitting new state of contact %s to server", identifier); g_message ("\talias = %s", d->alias); g_message ("\tcan see our presence = %s", d->publish ? "yes" : (request != NULL ? "no, but has requested it" : "no")); g_message ("\tsends us presence = %s", d->subscribe ? "yes" : (d->subscribe_requested ? "no, but we have requested it" : (d->subscribe_rejected ? "no, request refused" : "no"))); if (d->tags == NULL || g_hash_table_size (d->tags) == 0) { g_message ("\tnot in any groups"); } else { GHashTableIter iter; gpointer k; g_hash_table_iter_init (&iter, d->tags); while (g_hash_table_iter_next (&iter, &k, NULL)) { g_message ("\tin group: %s", (gchar *) k); } } } } static void example_contact_list_set_group_members_async (TpBaseContactList *contact_list, const gchar *group, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpHandleSet *new_contacts = tp_handle_set_new (self->priv->contact_repo); TpHandleSet *added = tp_handle_set_new (self->priv->contact_repo); TpHandleSet *removed = tp_handle_set_new (self->priv->contact_repo); TpIntsetFastIter iter; TpHandle member; gchar *tag = ensure_tag (self, group, TRUE); tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { gboolean created = FALSE, updated = FALSE; ExampleContactDetails *d = ensure_contact (self, member, &created); if (created) tp_handle_set_add (new_contacts, member); if (d->tags == NULL) d->tags = g_hash_table_new (g_str_hash, g_str_equal); if (g_hash_table_lookup (d->tags, tag) == NULL) { g_hash_table_insert (d->tags, tag, tag); updated = TRUE; } if (created || updated) { send_updated_roster (self, member); tp_handle_set_add (added, member); } } tp_intset_fast_iter_init (&iter, tp_handle_set_peek (self->priv->contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { ExampleContactDetails *d; if (tp_handle_set_is_member (contacts, member)) continue; d = lookup_contact (self, member); if (d != NULL && d->tags != NULL && g_hash_table_remove (d->tags, group)) tp_handle_set_add (removed, member); } if (!tp_handle_set_is_empty (new_contacts)) tp_base_contact_list_contacts_changed (contact_list, new_contacts, NULL); if (!tp_handle_set_is_empty (added)) tp_base_contact_list_groups_changed (contact_list, added, &group, 1, NULL, 0); if (!tp_handle_set_is_empty (removed)) tp_base_contact_list_groups_changed (contact_list, removed, NULL, 0, &group, 1); tp_handle_set_destroy (added); tp_handle_set_destroy (removed); tp_handle_set_destroy (new_contacts); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_set_group_members_async); } static void example_contact_list_add_to_group_async (TpBaseContactList *contact_list, const gchar *group, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpHandleSet *new_contacts = tp_handle_set_new (self->priv->contact_repo); TpHandleSet *new_to_group = tp_handle_set_new (self->priv->contact_repo); TpIntsetFastIter iter; TpHandle member; gchar *tag = ensure_tag (self, group, TRUE); tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { gboolean created = FALSE, updated = FALSE; ExampleContactDetails *d = ensure_contact (self, member, &created); if (created) tp_handle_set_add (new_contacts, member); if (d->tags == NULL) d->tags = g_hash_table_new (g_str_hash, g_str_equal); if (g_hash_table_lookup (d->tags, tag) == NULL) { g_hash_table_insert (d->tags, tag, tag); updated = TRUE; } if (created || updated) { send_updated_roster (self, member); tp_handle_set_add (new_to_group, member); } } if (!tp_handle_set_is_empty (new_contacts)) tp_base_contact_list_contacts_changed (contact_list, new_contacts, NULL); if (!tp_handle_set_is_empty (new_to_group)) tp_base_contact_list_groups_changed (contact_list, new_to_group, &group, 1, NULL, 0); tp_handle_set_destroy (new_to_group); tp_handle_set_destroy (new_contacts); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_add_to_group_async); } static void example_contact_list_remove_from_group_async (TpBaseContactList *contact_list, const gchar *group, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpHandleSet *changed = tp_handle_set_new (self->priv->contact_repo); TpIntsetFastIter iter; TpHandle member; tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { ExampleContactDetails *d = lookup_contact (self, member); /* If not on the roster or not in any groups, we have nothing to do */ if (d != NULL && d->tags != NULL && g_hash_table_remove (d->tags, group)) { send_updated_roster (self, member); tp_handle_set_add (changed, member); } } if (!tp_handle_set_is_empty (changed)) tp_base_contact_list_groups_changed (contact_list, changed, NULL, 0, &group, 1); tp_handle_set_destroy (changed); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_remove_from_group_async); } typedef struct { ExampleContactList *self; TpHandle contact; } SelfAndContact; static SelfAndContact * self_and_contact_new (ExampleContactList *self, TpHandle contact) { SelfAndContact *ret = g_slice_new0 (SelfAndContact); ret->self = g_object_ref (self); ret->contact = contact; return ret; } static void self_and_contact_destroy (gpointer p) { SelfAndContact *s = p; g_object_unref (s->self); g_slice_free (SelfAndContact, s); } static void receive_auth_request (ExampleContactList *self, TpHandle contact) { ExampleContactDetails *d; /* if shutting down, do nothing */ if (self->priv->conn == NULL) return; /* A remote contact has asked to see our presence. * * In a real connection manager this would be the result of incoming * data from the server. */ g_message ("From server: %s has sent us a publish request", tp_handle_inspect (self->priv->contact_repo, contact)); d = lookup_contact (self, contact); if (d != NULL && d->publish) return; if (d != NULL && d->pre_approved) { /* the user already said yes, no need to signal anything */ g_message ("... this publish request was already approved"); d->pre_approved = FALSE; d->publish = TRUE; g_hash_table_remove (self->priv->publish_requests, GUINT_TO_POINTER (contact)); tp_handle_set_remove (self->priv->cancelled_publish_requests, contact); send_updated_roster (self, contact); } else { tp_handle_set_add (self->priv->contacts, contact); g_hash_table_insert (self->priv->publish_requests, GUINT_TO_POINTER (contact), g_strdup ("May I see your presence, please?")); } tp_base_contact_list_one_contact_changed ((TpBaseContactList *) self, contact); /* If the contact has a name ending with "@cancel.something", they * immediately take it back; this is mainly for the regression test. */ if (strstr (tp_handle_inspect (self->priv->contact_repo, contact), "@cancel.") != NULL) { g_message ("From server: %s has cancelled their publish request", tp_handle_inspect (self->priv->contact_repo, contact)); d->publish = FALSE; d->pre_approved = FALSE; g_hash_table_remove (self->priv->publish_requests, GUINT_TO_POINTER (contact)); tp_handle_set_add (self->priv->cancelled_publish_requests, contact); tp_base_contact_list_one_contact_changed ((TpBaseContactList *) self, contact); } } static gboolean receive_authorized (gpointer p) { SelfAndContact *s = p; ExampleContactDetails *d; /* if shutting down, do nothing */ if (s->self->priv->conn == NULL) return FALSE; /* A remote contact has accepted our request to see their presence. * * In a real connection manager this would be the result of incoming * data from the server. */ g_message ("From server: %s has accepted our subscribe request", tp_handle_inspect (s->self->priv->contact_repo, s->contact)); d = ensure_contact (s->self, s->contact, NULL); /* if we were already subscribed to them, then nothing really happened */ if (d->subscribe) return FALSE; /* DITTO, if our subscription request was cancelled in the meantime */ if (!d->subscribe_requested) return FALSE; d->subscribe_requested = FALSE; d->subscribe_rejected = FALSE; d->subscribe = TRUE; tp_base_contact_list_one_contact_changed ((TpBaseContactList *) s->self, s->contact); /* their presence changes to something other than UNKNOWN */ g_signal_emit (s->self, signals[PRESENCE_UPDATED], 0, s->contact); /* if we're not publishing to them, also pretend they have asked us to * do so */ if (!d->publish) { receive_auth_request (s->self, s->contact); } return FALSE; } static gboolean receive_unauthorized (gpointer p) { SelfAndContact *s = p; ExampleContactDetails *d; /* if shutting down, do nothing */ if (s->self->priv->conn == NULL) return FALSE; /* A remote contact has rejected our request to see their presence. * * In a real connection manager this would be the result of incoming * data from the server. */ g_message ("From server: %s has rejected our subscribe request", tp_handle_inspect (s->self->priv->contact_repo, s->contact)); d = ensure_contact (s->self, s->contact, NULL); if (!d->subscribe && !d->subscribe_requested) return FALSE; d->subscribe_requested = FALSE; d->subscribe_rejected = TRUE; d->subscribe = FALSE; tp_base_contact_list_one_contact_changed ((TpBaseContactList *) s->self, s->contact); /* their presence changes to UNKNOWN */ g_signal_emit (s->self, signals[PRESENCE_UPDATED], 0, s->contact); return FALSE; } static gboolean auth_request_cb (gpointer p) { SelfAndContact *s = p; receive_auth_request (s->self, s->contact); return FALSE; } ExampleContactListPresence example_contact_list_get_presence (ExampleContactList *self, TpHandle contact) { ExampleContactDetails *d = lookup_contact (self, contact); const gchar *id; if (d == NULL || !d->subscribe) { /* we don't know the presence of people not on the subscribe list, * by definition */ return EXAMPLE_CONTACT_LIST_PRESENCE_UNKNOWN; } id = tp_handle_inspect (self->priv->contact_repo, contact); /* In this example CM, we fake contacts' presence based on their name: * contacts in the first half of the alphabet are available, the rest * (including non-alphabetic and non-ASCII initial letters) are away. */ if ((id[0] >= 'A' && id[0] <= 'M') || (id[0] >= 'a' && id[0] <= 'm')) { return EXAMPLE_CONTACT_LIST_PRESENCE_AVAILABLE; } return EXAMPLE_CONTACT_LIST_PRESENCE_AWAY; } const gchar * example_contact_list_get_alias (ExampleContactList *self, TpHandle contact) { ExampleContactDetails *d = lookup_contact (self, contact); if (d == NULL) { /* we don't have a user-defined alias for people not on the roster */ return tp_handle_inspect (self->priv->contact_repo, contact); } return d->alias; } void example_contact_list_set_alias (ExampleContactList *self, TpHandle contact, const gchar *alias) { gboolean created; ExampleContactDetails *d; gchar *old; /* if shutting down, do nothing */ if (self->priv->conn == NULL) return; d = ensure_contact (self, contact, &created); if (created) { tp_base_contact_list_one_contact_changed ( (TpBaseContactList *) self, contact); } /* FIXME: if stored list hasn't been retrieved yet, queue the change for * later */ old = d->alias; d->alias = g_strdup (alias); if (created || tp_strdiff (old, alias)) send_updated_roster (self, contact); g_free (old); } static TpHandleSet * example_contact_list_dup_contacts (TpBaseContactList *contact_list) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); return tp_handle_set_copy (self->priv->contacts); } static TpHandleSet * example_contact_list_dup_group_members (TpBaseContactList *contact_list, const gchar *group) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpIntsetFastIter iter; TpHandle member; TpHandleSet *members = tp_handle_set_new (self->priv->contact_repo); tp_intset_fast_iter_init (&iter, tp_handle_set_peek (self->priv->contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { ExampleContactDetails *d = lookup_contact (self, member); if (d != NULL && d->tags != NULL && g_hash_table_lookup_extended (d->tags, group, NULL, NULL)) tp_handle_set_add (members, member); } return members; } static const ExampleContactDetails no_details = { NULL, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }; static inline TpSubscriptionState compose_presence (gboolean full, gboolean ask, gboolean removed_remotely) { if (full) return TP_SUBSCRIPTION_STATE_YES; else if (ask) return TP_SUBSCRIPTION_STATE_ASK; else if (removed_remotely) return TP_SUBSCRIPTION_STATE_REMOVED_REMOTELY; else return TP_SUBSCRIPTION_STATE_NO; } static void example_contact_list_dup_states (TpBaseContactList *contact_list, TpHandle contact, TpSubscriptionState *subscribe, TpSubscriptionState *publish, gchar **publish_request) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); const ExampleContactDetails *details = lookup_contact (self, contact); const gchar *request = g_hash_table_lookup (self->priv->publish_requests, GUINT_TO_POINTER (contact)); if (details == NULL) details = &no_details; if (subscribe != NULL) *subscribe = compose_presence (details->subscribe, details->subscribe_requested, details->subscribe_rejected); if (publish != NULL) *publish = compose_presence (details->publish, (request != NULL), tp_handle_set_is_member (self->priv->cancelled_publish_requests, contact)); if (publish_request != NULL) *publish_request = g_strdup (request); } static void example_contact_list_request_subscription_async ( TpBaseContactList *contact_list, TpHandleSet *contacts, const gchar *message, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpHandleSet *changed = tp_handle_set_new (self->priv->contact_repo); TpIntsetFastIter iter; TpHandle member; tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { gboolean created; ExampleContactDetails *d = ensure_contact (self, member, &created); gchar *message_lc; /* if they already authorized us, it's a no-op */ if (d->subscribe) continue; /* In a real connection manager we'd start a network request here */ g_message ("Transmitting authorization request to %s: %s", tp_handle_inspect (self->priv->contact_repo, member), message); tp_handle_set_add (changed, member); d->subscribe_rejected = FALSE; d->subscribe_requested = TRUE; send_updated_roster (self, member); /* Pretend that after a delay, the contact notices the request * and allows or rejects it. In this example connection manager, * empty requests are allowed, as are requests that contain "please" * case-insensitively. All other requests are denied. */ message_lc = g_ascii_strdown (message, -1); if (message[0] == '\0' || strstr (message_lc, "please") != NULL) { g_timeout_add_full (G_PRIORITY_LOW, self->priv->simulation_delay, receive_authorized, self_and_contact_new (self, member), self_and_contact_destroy); } else { g_timeout_add_full (G_PRIORITY_LOW, self->priv->simulation_delay, receive_unauthorized, self_and_contact_new (self, member), self_and_contact_destroy); } g_free (message_lc); } tp_base_contact_list_contacts_changed (contact_list, changed, NULL); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_request_subscription_async); } static void example_contact_list_authorize_publication_async ( TpBaseContactList *contact_list, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpHandleSet *changed = tp_handle_set_new (self->priv->contact_repo); TpIntsetFastIter iter; TpHandle member; tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { ExampleContactDetails *d = ensure_contact (self, member, NULL); const gchar *request = g_hash_table_lookup (self->priv->publish_requests, GUINT_TO_POINTER (member)); if (tp_handle_set_remove (self->priv->cancelled_publish_requests, member)) tp_handle_set_add (changed, member); /* We would like member to see our presence. In this simulated protocol, * this is meaningless, unless they have asked for it; but we can still * remember the pre-authorization in case they ask later. */ if (request == NULL) { d->pre_approved = TRUE; } else if (!d->publish) { d->publish = TRUE; g_hash_table_remove (self->priv->publish_requests, GUINT_TO_POINTER (member)); send_updated_roster (self, member); tp_handle_set_add (changed, member); } } tp_base_contact_list_contacts_changed (contact_list, changed, NULL); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_authorize_publication_async); } static void example_contact_list_store_contacts_async ( TpBaseContactList *contact_list, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpHandleSet *changed = tp_handle_set_new (self->priv->contact_repo); TpIntsetFastIter iter; TpHandle member; tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { /* We would like member to be on the roster, but nothing more. */ if (lookup_contact (self, member) == NULL) { gboolean created; ensure_contact (self, member, &created); send_updated_roster (self, member); /* If we'd had a publish request from this member, then adding them * to the protocol-level contact list doesn't actually cause a * state change visible on Telepathy. */ if (created) tp_handle_set_add (changed, member); } } tp_base_contact_list_contacts_changed (contact_list, changed, NULL); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_store_contacts_async); } static void example_contact_list_remove_contacts_async (TpBaseContactList *contact_list, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpHandleSet *removed = tp_handle_set_new (self->priv->contact_repo); TpIntsetFastIter iter; TpHandle member; tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { /* we would like to remove member from the roster altogether */ if (lookup_contact (self, member) != NULL || g_hash_table_lookup (self->priv->publish_requests, GUINT_TO_POINTER (member)) != NULL || tp_handle_set_is_member (self->priv->cancelled_publish_requests, member)) { tp_handle_set_add (removed, member); g_hash_table_remove (self->priv->contact_details, GUINT_TO_POINTER (member)); g_hash_table_remove (self->priv->publish_requests, GUINT_TO_POINTER (member)); tp_handle_set_remove (self->priv->contacts, member); tp_handle_set_remove (self->priv->cancelled_publish_requests, member); send_updated_roster (self, member); /* since they're no longer on the subscribe list, we can't * see their presence, so emit a signal changing it to * UNKNOWN */ g_signal_emit (self, signals[PRESENCE_UPDATED], 0, member); } } tp_base_contact_list_contacts_changed (contact_list, NULL, removed); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_remove_contacts_async); } static void example_contact_list_unsubscribe_async (TpBaseContactList *contact_list, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpHandleSet *changed = tp_handle_set_new (self->priv->contact_repo); TpIntsetFastIter iter; TpHandle member; tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { ExampleContactDetails *d = lookup_contact (self, member); /* we would like to avoid receiving member's presence any more, * or we would like to cancel an outstanding request for their * presence */ if (d != NULL) { if (d->subscribe_requested) { g_message ("Cancelling our authorization request to %s", tp_handle_inspect (self->priv->contact_repo, member)); d->subscribe_requested = FALSE; tp_handle_set_add (changed, member); send_updated_roster (self, member); } else if (d->subscribe_rejected) { g_message ("Forgetting rejected authorization request to %s", tp_handle_inspect (self->priv->contact_repo, member)); d->subscribe_rejected = FALSE; tp_handle_set_add (changed, member); send_updated_roster (self, member); } else if (d->subscribe) { g_message ("We no longer want presence from %s", tp_handle_inspect (self->priv->contact_repo, member)); d->subscribe = FALSE; /* since they're no longer on the subscribe list, we can't * see their presence, so emit a signal changing it to * UNKNOWN */ g_signal_emit (self, signals[PRESENCE_UPDATED], 0, member); tp_handle_set_add (changed, member); send_updated_roster (self, member); } } } tp_base_contact_list_contacts_changed (contact_list, changed, NULL); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_unsubscribe_async); } static void example_contact_list_unpublish_async (TpBaseContactList *contact_list, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpHandleSet *changed = tp_handle_set_new (self->priv->contact_repo); TpHandleSet *removed = tp_handle_set_new (self->priv->contact_repo); TpIntsetFastIter iter; TpHandle member; tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { ExampleContactDetails *d = lookup_contact (self, member); const gchar *request = g_hash_table_lookup (self->priv->publish_requests, GUINT_TO_POINTER (member)); /* we would like member not to see our presence any more, or we * would like to reject a request from them to see our presence */ if (request != NULL) { g_message ("Rejecting authorization request from %s", tp_handle_inspect (self->priv->contact_repo, member)); g_hash_table_remove (self->priv->publish_requests, GUINT_TO_POINTER (member)); if (d == NULL) { /* the contact wasn't actually on our protocol-level contact * list, only on the Telepathy-level contact list, so rejecting * authorization makes them disappear */ tp_handle_set_add (removed, member); } else { tp_handle_set_add (changed, member); } } if (tp_handle_set_remove (self->priv->cancelled_publish_requests, member)) { g_message ("Acknowledging remotely-cancelled publish request"); tp_handle_set_add (changed, member); } if (d != NULL) { d->pre_approved = FALSE; if (d->publish) { g_message ("Removing authorization from %s", tp_handle_inspect (self->priv->contact_repo, member)); d->publish = FALSE; tp_handle_set_add (changed, member); send_updated_roster (self, member); /* Pretend that after a delay, the contact notices the change * and asks for our presence again */ g_timeout_add_full (G_PRIORITY_LOW, self->priv->simulation_delay, auth_request_cb, self_and_contact_new (self, member), self_and_contact_destroy); } } } tp_base_contact_list_contacts_changed (contact_list, changed, removed); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_unpublish_async); } static TpHandleSet * example_contact_list_dup_blocked_contacts (TpBaseContactList *contact_list) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); return tp_handle_set_copy (self->priv->blocked_contacts); } static void example_contact_list_block_contacts_async (TpBaseContactList *contact_list, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpIntsetFastIter iter; TpHandleSet *changed = tp_handle_set_new (self->priv->contact_repo); TpHandle member; tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { if (!tp_handle_set_is_member (self->priv->blocked_contacts, member)) { g_message ("Adding contact %s to blocked list", tp_handle_inspect (self->priv->contact_repo, member)); tp_handle_set_add (self->priv->blocked_contacts, member); tp_handle_set_add (changed, member); } } tp_base_contact_list_contact_blocking_changed (contact_list, changed); tp_handle_set_destroy (changed); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_block_contacts_async); } static void example_contact_list_unblock_contacts_async (TpBaseContactList *contact_list, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpIntsetFastIter iter; TpHandleSet *changed = tp_handle_set_new (self->priv->contact_repo); TpHandle member; tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { if (tp_handle_set_remove (self->priv->blocked_contacts, member)) { g_message ("Removing contact %s from blocked list", tp_handle_inspect (self->priv->contact_repo, member)); tp_handle_set_add (changed, member); } } tp_base_contact_list_contact_blocking_changed (contact_list, changed); tp_handle_set_destroy (changed); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, example_contact_list_unblock_contacts_async); } static guint example_contact_list_get_group_storage ( TpBaseContactList *contact_list G_GNUC_UNUSED) { return TP_CONTACT_METADATA_STORAGE_TYPE_ANYONE; } static GStrv example_contact_list_dup_groups (TpBaseContactList *contact_list) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); GPtrArray *tags = g_ptr_array_sized_new ( g_hash_table_size (self->priv->all_tags) + 1); GHashTableIter iter; gpointer tag; g_hash_table_iter_init (&iter, self->priv->all_tags); while (g_hash_table_iter_next (&iter, &tag, NULL)) g_ptr_array_add (tags, g_strdup (tag)); g_ptr_array_add (tags, NULL); return (GStrv) g_ptr_array_free (tags, FALSE); } static GStrv example_contact_list_dup_contact_groups (TpBaseContactList *contact_list, TpHandle contact) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); GPtrArray *tags = g_ptr_array_sized_new ( g_hash_table_size (self->priv->all_tags) + 1); ExampleContactDetails *d = lookup_contact (self, contact); if (d != NULL && d->tags != NULL) { GHashTableIter iter; gpointer tag; g_hash_table_iter_init (&iter, d->tags); while (g_hash_table_iter_next (&iter, &tag, NULL)) g_ptr_array_add (tags, g_strdup (tag)); } g_ptr_array_add (tags, NULL); return (GStrv) g_ptr_array_free (tags, FALSE); } static void example_contact_list_remove_group_async (TpBaseContactList *contact_list, const gchar *group, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); TpIntsetFastIter iter; TpHandle member; /* signal the deletion */ g_message ("deleting group %s", group); tp_base_contact_list_groups_removed (contact_list, &group, 1); /* apply the change to our model of the contacts too; we don't need to signal * the change, because TpBaseContactList already did */ tp_intset_fast_iter_init (&iter, tp_handle_set_peek (self->priv->contacts)); while (tp_intset_fast_iter_next (&iter, &member)) { ExampleContactDetails *d = lookup_contact (self, member); if (d != NULL && d->tags != NULL) g_hash_table_remove (d->tags, group); } tp_simple_async_report_success_in_idle ((GObject *) contact_list, callback, user_data, example_contact_list_remove_group_async); } static gchar * example_contact_list_normalize_group (TpBaseContactList *contact_list, const gchar *id) { if (id[0] == '\0') return NULL; return g_utf8_normalize (id, -1, G_NORMALIZE_ALL_COMPOSE); } static void example_contact_list_rename_group_async (TpBaseContactList *contact_list, const gchar *old_name, const gchar *new_name, GAsyncReadyCallback callback, gpointer user_data) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (contact_list); gchar *tag = ensure_tag (self, new_name, FALSE); GHashTableIter iter; gpointer v; /* signal the rename */ g_print ("renaming group %s to %s", old_name, new_name); tp_base_contact_list_group_renamed (contact_list, old_name, new_name); /* update our model (this doesn't need to signal anything because * TpBaseContactList already did) */ g_hash_table_iter_init (&iter, self->priv->contact_details); while (g_hash_table_iter_next (&iter, NULL, &v)) { ExampleContactDetails *d = v; if (d->tags != NULL && g_hash_table_remove (d->tags, old_name)) g_hash_table_insert (d->tags, tag, tag); } tp_simple_async_report_success_in_idle ((GObject *) contact_list, callback, user_data, example_contact_list_rename_group_async); } static void example_contact_list_class_init (ExampleContactListClass *klass) { TpBaseContactListClass *contact_list_class = (TpBaseContactListClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); contact_list_class->dup_contacts = example_contact_list_dup_contacts; contact_list_class->dup_states = example_contact_list_dup_states; /* for this example CM we pretend there is a server-stored contact list, * like in XMPP, even though there obviously isn't really */ contact_list_class->get_contact_list_persists = tp_base_contact_list_true_func; g_type_class_add_private (klass, sizeof (ExampleContactListPrivate)); signals[ALIAS_UPDATED] = g_signal_new ("alias-updated", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals[PRESENCE_UPDATED] = g_signal_new ("presence-updated", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); } static void mutable_contact_list_iface_init (TpMutableContactListInterface *iface) { iface->can_change_contact_list = tp_base_contact_list_true_func; iface->get_request_uses_message = tp_base_contact_list_true_func; iface->request_subscription_async = example_contact_list_request_subscription_async; iface->authorize_publication_async = example_contact_list_authorize_publication_async; iface->store_contacts_async = example_contact_list_store_contacts_async; iface->remove_contacts_async = example_contact_list_remove_contacts_async; iface->unsubscribe_async = example_contact_list_unsubscribe_async; iface->unpublish_async = example_contact_list_unpublish_async; } static void blockable_contact_list_iface_init (TpBlockableContactListInterface *iface) { iface->can_block = tp_base_contact_list_true_func; iface->dup_blocked_contacts = example_contact_list_dup_blocked_contacts; iface->block_contacts_async = example_contact_list_block_contacts_async; iface->unblock_contacts_async = example_contact_list_unblock_contacts_async; } static void contact_group_list_iface_init (TpContactGroupListInterface *iface) { iface->dup_groups = example_contact_list_dup_groups; iface->dup_group_members = example_contact_list_dup_group_members; iface->dup_contact_groups = example_contact_list_dup_contact_groups; iface->normalize_group = example_contact_list_normalize_group; } static void mutable_contact_group_list_iface_init ( TpMutableContactGroupListInterface *iface) { iface->set_group_members_async = example_contact_list_set_group_members_async; iface->add_to_group_async = example_contact_list_add_to_group_async; iface->remove_from_group_async = example_contact_list_remove_from_group_async; iface->remove_group_async = example_contact_list_remove_group_async; iface->rename_group_async = example_contact_list_rename_group_async; iface->set_contact_groups_async = example_contact_list_set_contact_groups_async; iface->get_group_storage = example_contact_list_get_group_storage; } telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/conn.c0000664000175000017500000004367312470405660021324 0ustar jrjr/* * conn.c - an example connection * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "conn.h" #include #include #include #include #include "contact-list.h" #include "protocol.h" static void init_aliasing (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (ExampleContactListConnection, example_contact_list_connection, TP_TYPE_BASE_CONNECTION, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING, init_aliasing); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, tp_contacts_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST, tp_base_contact_list_mixin_list_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS, tp_base_contact_list_mixin_groups_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_BLOCKING, tp_base_contact_list_mixin_blocking_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE, tp_presence_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE, tp_presence_mixin_simple_presence_iface_init)) enum { PROP_ACCOUNT = 1, PROP_SIMULATION_DELAY, N_PROPS }; struct _ExampleContactListConnectionPrivate { gchar *account; guint simulation_delay; ExampleContactList *contact_list; gboolean away; }; static void example_contact_list_connection_init (ExampleContactListConnection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, ExampleContactListConnectionPrivate); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_value_set_string (value, self->priv->account); break; case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *spec) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_free (self->priv->account); self->priv->account = g_value_dup_string (value); break; case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void finalize (GObject *object) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); tp_contacts_mixin_finalize (object); g_free (self->priv->account); G_OBJECT_CLASS (example_contact_list_connection_parent_class)->finalize ( object); } static gchar * get_unique_connection_name (TpBaseConnection *conn) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (conn); return g_strdup_printf ("%s@%p", self->priv->account, self); } gchar * example_contact_list_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error) { gchar *normal = NULL; if (example_contact_list_protocol_check_contact_id (id, &normal, error)) return normal; else return NULL; } static void create_handle_repos (TpBaseConnection *conn, TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]) { repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_CONTACT, example_contact_list_normalize_contact, NULL); } static void alias_updated_cb (ExampleContactList *contact_list, TpHandle contact, ExampleContactListConnection *self) { GPtrArray *aliases; GValueArray *pair; pair = g_value_array_new (2); g_value_array_append (pair, NULL); g_value_array_append (pair, NULL); g_value_init (pair->values + 0, G_TYPE_UINT); g_value_init (pair->values + 1, G_TYPE_STRING); g_value_set_uint (pair->values + 0, contact); g_value_set_string (pair->values + 1, example_contact_list_get_alias (contact_list, contact)); aliases = g_ptr_array_sized_new (1); g_ptr_array_add (aliases, pair); tp_svc_connection_interface_aliasing_emit_aliases_changed (self, aliases); g_ptr_array_free (aliases, TRUE); g_value_array_free (pair); } static void presence_updated_cb (ExampleContactList *contact_list, TpHandle contact, ExampleContactListConnection *self) { TpBaseConnection *base = (TpBaseConnection *) self; TpPresenceStatus *status; /* we ignore the presence indicated by the contact list for our own handle */ if (contact == base->self_handle) return; status = tp_presence_status_new ( example_contact_list_get_presence (contact_list, contact), NULL); tp_presence_mixin_emit_one_presence_update ((GObject *) self, contact, status); tp_presence_status_free (status); } static GPtrArray * create_channel_managers (TpBaseConnection *conn) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (conn); GPtrArray *ret = g_ptr_array_sized_new (1); self->priv->contact_list = EXAMPLE_CONTACT_LIST (g_object_new ( EXAMPLE_TYPE_CONTACT_LIST, "connection", conn, "simulation-delay", self->priv->simulation_delay, NULL)); g_signal_connect (self->priv->contact_list, "alias-updated", G_CALLBACK (alias_updated_cb), self); g_signal_connect (self->priv->contact_list, "presence-updated", G_CALLBACK (presence_updated_cb), self); g_ptr_array_add (ret, self->priv->contact_list); return ret; } static gboolean start_connecting (TpBaseConnection *conn, GError **error) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (conn); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); /* In a real connection manager we'd ask the underlying implementation to * start connecting, then go to state CONNECTED when finished, but here * we can do it immediately. */ conn->self_handle = tp_handle_ensure (contact_repo, self->priv->account, NULL, error); if (conn->self_handle == 0) return FALSE; tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); return TRUE; } static void shut_down (TpBaseConnection *conn) { /* In a real connection manager we'd ask the underlying implementation to * start shutting down, then call this function when finished, but here * we can do it immediately. */ tp_base_connection_finish_shutdown (conn); } static void aliasing_fill_contact_attributes (GObject *object, const GArray *contacts, GHashTable *attributes) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); guint i; for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, guint, i); tp_contacts_mixin_set_contact_attribute (attributes, contact, TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS, tp_g_value_slice_new_string ( example_contact_list_get_alias (self->priv->contact_list, contact))); } } static void constructed (GObject *object) { TpBaseConnection *base = TP_BASE_CONNECTION (object); void (*chain_up) (GObject *) = G_OBJECT_CLASS (example_contact_list_connection_parent_class)->constructed; if (chain_up != NULL) chain_up (object); tp_contacts_mixin_init (object, G_STRUCT_OFFSET (ExampleContactListConnection, contacts_mixin)); tp_base_connection_register_with_contacts_mixin (base); tp_base_contact_list_mixin_register_with_contacts_mixin (base); tp_contacts_mixin_add_contact_attributes_iface (object, TP_IFACE_CONNECTION_INTERFACE_ALIASING, aliasing_fill_contact_attributes); tp_presence_mixin_init (object, G_STRUCT_OFFSET (ExampleContactListConnection, presence_mixin)); tp_presence_mixin_simple_presence_register_with_contacts_mixin (object); } static gboolean status_available (GObject *object, guint index_) { TpBaseConnection *base = TP_BASE_CONNECTION (object); if (base->status != TP_CONNECTION_STATUS_CONNECTED) return FALSE; return TRUE; } static GHashTable * get_contact_statuses (GObject *object, const GArray *contacts, GError **error) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); TpBaseConnection *base = TP_BASE_CONNECTION (object); guint i; GHashTable *result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) tp_presence_status_free); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, guint, i); ExampleContactListPresence presence; GHashTable *parameters; /* we get our own status from the connection, and everyone else's status * from the contact lists */ if (contact == base->self_handle) { presence = (self->priv->away ? EXAMPLE_CONTACT_LIST_PRESENCE_AWAY : EXAMPLE_CONTACT_LIST_PRESENCE_AVAILABLE); } else { presence = example_contact_list_get_presence ( self->priv->contact_list, contact); } parameters = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); g_hash_table_insert (result, GUINT_TO_POINTER (contact), tp_presence_status_new (presence, parameters)); g_hash_table_destroy (parameters); } return result; } static gboolean set_own_status (GObject *object, const TpPresenceStatus *status, GError **error) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); TpBaseConnection *base = TP_BASE_CONNECTION (object); GHashTable *presences; if (status->index == EXAMPLE_CONTACT_LIST_PRESENCE_AWAY) { if (self->priv->away) return TRUE; self->priv->away = TRUE; } else { if (!self->priv->away) return TRUE; self->priv->away = FALSE; } presences = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); g_hash_table_insert (presences, GUINT_TO_POINTER (base->self_handle), (gpointer) status); tp_presence_mixin_emit_presence_update (object, presences); g_hash_table_destroy (presences); return TRUE; } static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_ALIASING, TP_IFACE_CONNECTION_INTERFACE_CONTACTS, TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST, TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS, TP_IFACE_CONNECTION_INTERFACE_CONTACT_BLOCKING, TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, NULL }; const gchar * const * example_contact_list_connection_get_possible_interfaces (void) { /* in this example CM we don't have any extra interfaces that are sometimes, * but not always, present */ return interfaces_always_present; } static void example_contact_list_connection_class_init ( ExampleContactListConnectionClass *klass) { TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; object_class->get_property = get_property; object_class->set_property = set_property; object_class->constructed = constructed; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (ExampleContactListConnectionPrivate)); base_class->create_handle_repos = create_handle_repos; base_class->get_unique_connection_name = get_unique_connection_name; base_class->create_channel_managers = create_channel_managers; base_class->start_connecting = start_connecting; base_class->shut_down = shut_down; base_class->interfaces_always_present = interfaces_always_present; param_spec = g_param_spec_string ("account", "Account name", "The username of this user", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); tp_contacts_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleContactListConnectionClass, contacts_mixin)); tp_presence_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleContactListConnectionClass, presence_mixin), status_available, get_contact_statuses, set_own_status, example_contact_list_presence_statuses ()); tp_presence_mixin_simple_presence_init_dbus_properties (object_class); tp_base_contact_list_mixin_class_init (base_class); } static void get_alias_flags (TpSvcConnectionInterfaceAliasing *aliasing, DBusGMethodInvocation *context) { TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); tp_svc_connection_interface_aliasing_return_from_get_alias_flags (context, TP_CONNECTION_ALIAS_FLAG_USER_SET); } static void get_aliases (TpSvcConnectionInterfaceAliasing *aliasing, const GArray *contacts, DBusGMethodInvocation *context) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (aliasing); TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GHashTable *result; GError *error = NULL; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, TpHandle, i); const gchar *alias = example_contact_list_get_alias ( self->priv->contact_list, contact); g_hash_table_insert (result, GUINT_TO_POINTER (contact), (gchar *) alias); } tp_svc_connection_interface_aliasing_return_from_get_aliases (context, result); g_hash_table_destroy (result); } static void request_aliases (TpSvcConnectionInterfaceAliasing *aliasing, const GArray *contacts, DBusGMethodInvocation *context) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (aliasing); TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GPtrArray *result; gchar **strings; GError *error = NULL; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_ptr_array_sized_new (contacts->len + 1); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, TpHandle, i); const gchar *alias = example_contact_list_get_alias ( self->priv->contact_list, contact); g_ptr_array_add (result, (gchar *) alias); } g_ptr_array_add (result, NULL); strings = (gchar **) g_ptr_array_free (result, FALSE); tp_svc_connection_interface_aliasing_return_from_request_aliases (context, (const gchar **) strings); g_free (strings); } static void set_aliases (TpSvcConnectionInterfaceAliasing *aliasing, GHashTable *aliases, DBusGMethodInvocation *context) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (aliasing); TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, aliases); while (g_hash_table_iter_next (&iter, &key, &value)) { GError *error = NULL; if (!tp_handle_is_valid (contact_repo, GPOINTER_TO_UINT (key), &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } } g_hash_table_iter_init (&iter, aliases); while (g_hash_table_iter_next (&iter, &key, &value)) { example_contact_list_set_alias (self->priv->contact_list, GPOINTER_TO_UINT (key), value); } tp_svc_connection_interface_aliasing_return_from_set_aliases (context); } static void init_aliasing (gpointer iface, gpointer iface_data G_GNUC_UNUSED) { TpSvcConnectionInterfaceAliasingClass *klass = iface; #define IMPLEMENT(x) tp_svc_connection_interface_aliasing_implement_##x (\ klass, x) IMPLEMENT(get_alias_flags); IMPLEMENT(request_aliases); IMPLEMENT(get_aliases); IMPLEMENT(set_aliases); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/protocol.h0000664000175000017500000000413512470405660022223 0ustar jrjr/* * protocol.h - header for an example Protocol * Copyright © 2007-2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef EXAMPLE_CONTACT_LIST_PROTOCOL_H #define EXAMPLE_CONTACT_LIST_PROTOCOL_H #include #include G_BEGIN_DECLS typedef struct _ExampleContactListProtocol ExampleContactListProtocol; typedef struct _ExampleContactListProtocolPrivate ExampleContactListProtocolPrivate; typedef struct _ExampleContactListProtocolClass ExampleContactListProtocolClass; typedef struct _ExampleContactListProtocolClassPrivate ExampleContactListProtocolClassPrivate; struct _ExampleContactListProtocolClass { TpBaseProtocolClass parent_class; ExampleContactListProtocolClassPrivate *priv; }; struct _ExampleContactListProtocol { TpBaseProtocol parent; ExampleContactListProtocolPrivate *priv; }; GType example_contact_list_protocol_get_type (void); #define EXAMPLE_TYPE_CONTACT_LIST_PROTOCOL \ (example_contact_list_protocol_get_type ()) #define EXAMPLE_CONTACT_LIST_PROTOCOL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ EXAMPLE_TYPE_CONTACT_LIST_PROTOCOL, \ ExampleContactListProtocol)) #define EXAMPLE_CONTACT_LIST_PROTOCOL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ EXAMPLE_TYPE_CONTACT_LIST_PROTOCOL, \ ExampleContactListProtocolClass)) #define EXAMPLE_IS_CONTACT_LIST_PROTOCOL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ EXAMPLE_TYPE_CONTACT_LIST_PROTOCOL)) #define EXAMPLE_IS_CONTACT_LIST_PROTOCOL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ EXAMPLE_TYPE_CONTACT_LIST_PROTOCOL)) #define EXAMPLE_CONTACT_LIST_PROTOCOL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ EXAMPLE_TYPE_CONTACT_LIST_PROTOCOL, \ ExampleContactListProtocolClass)) gboolean example_contact_list_protocol_check_contact_id (const gchar *id, gchar **normal, GError **error); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/connection-manager.c0000664000175000017500000000416012470405660024122 0ustar jrjr/* * manager.c - an example connection manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "connection-manager.h" #include #include #include #include "conn.h" #include "protocol.h" G_DEFINE_TYPE (ExampleContactListConnectionManager, example_contact_list_connection_manager, TP_TYPE_BASE_CONNECTION_MANAGER) struct _ExampleContactListConnectionManagerPrivate { int dummy; }; static void example_contact_list_connection_manager_init ( ExampleContactListConnectionManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER, ExampleContactListConnectionManagerPrivate); } static void example_contact_list_connection_manager_constructed (GObject *object) { ExampleContactListConnectionManager *self = EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER (object); TpBaseConnectionManager *base = (TpBaseConnectionManager *) self; void (*constructed) (GObject *) = ((GObjectClass *) example_contact_list_connection_manager_parent_class)->constructed; TpBaseProtocol *protocol; if (constructed != NULL) constructed (object); protocol = g_object_new (EXAMPLE_TYPE_CONTACT_LIST_PROTOCOL, "name", "example", NULL); tp_base_connection_manager_add_protocol (base, protocol); g_object_unref (protocol); } static void example_contact_list_connection_manager_class_init ( ExampleContactListConnectionManagerClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseConnectionManagerClass *base_class = (TpBaseConnectionManagerClass *) klass; g_type_class_add_private (klass, sizeof (ExampleContactListConnectionManagerPrivate)); object_class->constructed = example_contact_list_connection_manager_constructed; base_class->cm_dbus_name = "example_contact_list"; } telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist2/protocol.c0000664000175000017500000001152212470405660022214 0ustar jrjr/* * protocol.c - an example Protocol * * Copyright © 2007-2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "protocol.h" #include #include "conn.h" #include "contact-list.h" G_DEFINE_TYPE (ExampleContactListProtocol, example_contact_list_protocol, TP_TYPE_BASE_PROTOCOL) static void example_contact_list_protocol_init ( ExampleContactListProtocol *self) { } gboolean example_contact_list_protocol_check_contact_id (const gchar *id, gchar **normal, GError **error) { g_return_val_if_fail (id != NULL, FALSE); if (id[0] == '\0') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "ID must not be empty"); return FALSE; } if (normal != NULL) *normal = g_utf8_normalize (id, -1, G_NORMALIZE_ALL_COMPOSE); return TRUE; } static gboolean account_param_filter (const TpCMParamSpec *paramspec, GValue *value, GError **error) { const gchar *id = g_value_get_string (value); return example_contact_list_protocol_check_contact_id (id, NULL, error); } static const TpCMParamSpec example_contact_list_example_params[] = { { "account", "s", G_TYPE_STRING, TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, NULL, /* no default */ 0, /* unused, formerly struct offset */ account_param_filter, NULL, /* filter data, unused here */ NULL }, /* setter data, now unused */ { "simulation-delay", "u", G_TYPE_UINT, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, GUINT_TO_POINTER (1000), /* default */ 0, /* unused, formerly struct offset */ NULL, /* no filter */ NULL, /* filter data, unused here */ NULL }, /* setter data, now unused */ { NULL } }; static const TpCMParamSpec * get_parameters (TpBaseProtocol *self) { return example_contact_list_example_params; } static TpBaseConnection * new_connection (TpBaseProtocol *protocol, GHashTable *asv, GError **error) { ExampleContactListConnection *conn; const gchar *account; guint sim_delay; account = tp_asv_get_string (asv, "account"); /* telepathy-glib checked this for us */ g_assert (account != NULL); sim_delay = tp_asv_get_uint32 (asv, "simulation-delay", NULL); conn = EXAMPLE_CONTACT_LIST_CONNECTION ( g_object_new (EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, "account", account, "protocol", tp_base_protocol_get_name (protocol), "simulation-delay", sim_delay, NULL)); return (TpBaseConnection *) conn; } static gchar * normalize_contact (TpBaseProtocol *self G_GNUC_UNUSED, const gchar *contact, GError **error) { gchar *normal; if (example_contact_list_protocol_check_contact_id (contact, &normal, error)) return normal; else return NULL; } static gchar * identify_account (TpBaseProtocol *self G_GNUC_UNUSED, GHashTable *asv, GError **error) { const gchar *account = tp_asv_get_string (asv, "account"); if (account != NULL) return normalize_contact (self, account, error); g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'account' parameter not given"); return NULL; } static GStrv get_interfaces (TpBaseProtocol *self) { return NULL; } static void get_connection_details (TpBaseProtocol *self G_GNUC_UNUSED, GStrv *connection_interfaces, GType **channel_managers, gchar **icon_name, gchar **english_name, gchar **vcard_field) { if (connection_interfaces != NULL) { *connection_interfaces = g_strdupv ( (GStrv) example_contact_list_connection_get_possible_interfaces ()); } if (channel_managers != NULL) { GType types[] = { EXAMPLE_TYPE_CONTACT_LIST, G_TYPE_INVALID }; *channel_managers = g_memdup (types, sizeof (types)); } if (icon_name != NULL) *icon_name = g_strdup ("face-smile"); if (english_name != NULL) *english_name = g_strdup ("Example with a contact list"); if (vcard_field != NULL) *vcard_field = g_strdup ("x-telepathy-example"); } static void example_contact_list_protocol_class_init ( ExampleContactListProtocolClass *klass) { TpBaseProtocolClass *base_class = (TpBaseProtocolClass *) klass; base_class->get_parameters = get_parameters; base_class->new_connection = new_connection; base_class->normalize_contact = normalize_contact; base_class->identify_account = identify_account; base_class->get_interfaces = get_interfaces; base_class->get_connection_details = get_connection_details; } telepathy-qt-0.9.6~git1/tests/lib/glib/textchan-null.h0000664000175000017500000001174212470405660020541 0ustar jrjr/* * /dev/null as a text channel * * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_TEXT_CHANNEL_NULL_H__ #define __TP_TESTS_TEXT_CHANNEL_NULL_H__ #include #include #include #include G_BEGIN_DECLS typedef struct _TpTestsTextChannelNull TpTestsTextChannelNull; typedef struct _TpTestsTextChannelNullClass TpTestsTextChannelNullClass; typedef struct _TpTestsTextChannelNullPrivate TpTestsTextChannelNullPrivate; GType tp_tests_text_channel_null_get_type (void); #define TP_TESTS_TYPE_TEXT_CHANNEL_NULL \ (tp_tests_text_channel_null_get_type ()) #define TP_TESTS_TEXT_CHANNEL_NULL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_TEXT_CHANNEL_NULL, \ TpTestsTextChannelNull)) #define TP_TESTS_TEXT_CHANNEL_NULL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_TEXT_CHANNEL_NULL, \ TpTestsTextChannelNullClass)) #define TP_TESTS_IS_TEXT_CHANNEL_NULL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_TEXT_CHANNEL_NULL)) #define TP_TESTS_IS_TEXT_CHANNEL_NULL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_TEXT_CHANNEL_NULL)) #define TP_TESTS_TEXT_CHANNEL_NULL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_TEXT_CHANNEL_NULL, \ TpTestsTextChannelNullClass)) struct _TpTestsTextChannelNullClass { GObjectClass parent_class; const gchar **interfaces; TpTextMixinClass text_class; }; struct _TpTestsTextChannelNull { GObject parent; TpTextMixin text; guint get_handle_called; guint get_interfaces_called; guint get_channel_type_called; TpTestsTextChannelNullPrivate *priv; }; /* Subclass with D-Bus properties */ typedef struct _TestPropsTextChannel TpTestsPropsTextChannel; typedef struct _TestPropsTextChannelClass TpTestsPropsTextChannelClass; struct _TestPropsTextChannel { TpTestsTextChannelNull parent; GHashTable *dbus_property_interfaces_retrieved; }; struct _TestPropsTextChannelClass { TpTestsTextChannelNullClass parent; TpDBusPropertiesMixinClass dbus_properties_class; }; GType tp_tests_props_text_channel_get_type (void); #define TP_TESTS_TYPE_PROPS_TEXT_CHANNEL \ (tp_tests_props_text_channel_get_type ()) #define TP_TESTS_PROPS_TEXT_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL, \ TpTestsPropsTextChannel)) #define TP_TESTS_PROPS_TEXT_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL, \ TpTestsPropsTextChannelClass)) #define TP_TESTS_IS_PROPS_TEXT_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL)) #define TP_TESTS_IS_PROPS_TEXT_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL)) #define TP_TESTS_PROPS_TEXT_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_PROPS_TEXT_CHANNEL, \ TpTestsPropsTextChannelClass)) /* Subclass with D-Bus properties and Group */ typedef struct _TestPropsGroupTextChannel TpTestsPropsGroupTextChannel; typedef struct _TestPropsGroupTextChannelClass TpTestsPropsGroupTextChannelClass; struct _TestPropsGroupTextChannel { TpTestsPropsTextChannel parent; TpGroupMixin group; }; struct _TestPropsGroupTextChannelClass { TpTestsPropsTextChannelClass parent; TpGroupMixinClass group_class; }; GType tp_tests_props_group_text_channel_get_type (void); #define TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL \ (tp_tests_props_group_text_channel_get_type ()) #define TP_TESTS_PROPS_GROUP_TEXT_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL, \ TpTestsPropsGroupTextChannel)) #define TP_TESTS_PROPS_GROUP_TEXT_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL, \ TpTestsPropsGroupTextChannelClass)) #define TP_TESTS_IS_PROPS_GROUP_TEXT_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL)) #define TP_TESTS_IS_PROPS_GROUP_TEXT_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL)) #define TP_TESTS_PROPS_GROUP_TEXT_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL, \ TpTestsPropsGroupTextChannelClass)) void tp_tests_text_channel_null_close (TpTestsTextChannelNull *self); GHashTable * tp_tests_text_channel_get_props (TpTestsTextChannelNull *self); G_END_DECLS #endif /* #ifndef __TP_TESTS_TEXT_CHANNEL_NULL_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/captcha-chan.c0000664000175000017500000004171312470405660020261 0ustar jrjr/* * captcha-chan.c - Simple captcha channel * * Copyright (C) 2012 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "captcha-chan.h" #include #include #include #include enum { PROP_METHOD = 1, PROP_RETRY, PROP_STATUS, PROP_ERROR, PROP_ERROR_DETAILS }; struct _TpTestsCaptchaChannelPrivate { TpCaptchaStatus status; TpSocketAccessControl access_control; GHashTable *parameters; gchar *error_string; GHashTable *error_details; gboolean can_retry; gboolean is_retrying; }; static void tp_tests_captcha_channel_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { TpTestsCaptchaChannel *self = (TpTestsCaptchaChannel *) object; switch (property_id) { case PROP_METHOD: g_value_set_string (value, TP_IFACE_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION); break; case PROP_RETRY: g_value_set_boolean (value, self->priv->can_retry); break; case PROP_STATUS: g_value_set_uint (value, self->priv->status); break; case PROP_ERROR: g_value_set_string (value, self->priv->error_string); break; case PROP_ERROR_DETAILS: g_value_set_boxed (value, self->priv->error_details); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void tp_tests_captcha_channel_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { TpTestsCaptchaChannel *self = (TpTestsCaptchaChannel *) object; switch (property_id) { case PROP_RETRY: self->priv->can_retry = g_value_get_boolean(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void captcha_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (TpTestsCaptchaChannel, tp_tests_captcha_channel, TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_SERVER_AUTHENTICATION, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION, captcha_iface_init); ) /* type definition stuff */ static const char * tp_tests_captcha_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION, NULL }; static void tp_tests_captcha_channel_init (TpTestsCaptchaChannel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), TP_TESTS_TYPE_CAPTCHA_CHANNEL, TpTestsCaptchaChannelPrivate); } static GObject * constructor (GType type, guint n_props, GObjectConstructParam *props) { GObject *object = G_OBJECT_CLASS (tp_tests_captcha_channel_parent_class)->constructor ( type, n_props, props); TpTestsCaptchaChannel *self = TP_TESTS_CAPTCHA_CHANNEL (object); self->priv->status = TP_CAPTCHA_STATUS_LOCAL_PENDING; self->priv->is_retrying = FALSE; self->priv->error_string = NULL; self->priv->error_details = tp_asv_new (NULL, NULL); tp_base_channel_register (TP_BASE_CHANNEL (self)); return object; } static void dispose (GObject *object) { // TpTestsCaptchaChannel *self = (TpTestsCaptchaChannel *) object; // Free memory here if needed ((GObjectClass *) tp_tests_captcha_channel_parent_class)->dispose ( object); } static void channel_close (TpBaseChannel *channel) { tp_base_channel_destroyed (channel); } static void fill_immutable_properties (TpBaseChannel *chan, GHashTable *properties) { TpBaseChannelClass *klass = TP_BASE_CHANNEL_CLASS ( tp_tests_captcha_channel_parent_class); tp_dbus_properties_mixin_fill_properties_hash ( G_OBJECT (chan), properties, TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION, "AuthenticationMethod", TP_IFACE_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION, "CanRetryCaptcha", NULL); klass->fill_immutable_properties (chan, properties); } static void tp_tests_captcha_channel_class_init (TpTestsCaptchaChannelClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass); GParamSpec *param_spec; static TpDBusPropertiesMixinPropImpl server_authentication_props[] = { { "AuthenticationMethod", "authentication-method", NULL }, { NULL, NULL, NULL } }; static TpDBusPropertiesMixinPropImpl captcha_authentication_props[] = { { "CanRetryCaptcha", "can-retry-captcha", NULL }, { "CaptchaStatus", "captcha-status", NULL }, { "CaptchaError", "captcha-error", NULL }, { "CaptchaErrorDetails", "captcha-error-details", NULL }, { NULL } }; object_class->constructor = constructor; object_class->get_property = tp_tests_captcha_channel_get_property; object_class->set_property = tp_tests_captcha_channel_set_property; object_class->dispose = dispose; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION; base_class->target_handle_type = TP_HANDLE_TYPE_NONE; base_class->interfaces = tp_tests_captcha_channel_interfaces; base_class->close = channel_close; base_class->fill_immutable_properties = fill_immutable_properties; param_spec = g_param_spec_string ("authentication-method", "AuthenticationMethod", "the authentication method for this channel", "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_METHOD, param_spec); param_spec = g_param_spec_boolean ( "can-retry-captcha", "CanRetryCaptcha", "Whether Captcha can be retried or not.", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_RETRY, param_spec); param_spec = g_param_spec_string ( "captcha-error", "CaptchaError", "error details of the captcha", "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ERROR, param_spec); param_spec = g_param_spec_boxed ( "captcha-error-details", "CaptchaErrorDetails", "error details of the captcha", TP_HASH_TYPE_STRING_VARIANT_MAP, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ERROR_DETAILS, param_spec); param_spec = g_param_spec_uint ( "captcha-status", "CaptchaStatus", "state of the captcha", 0, NUM_TP_CAPTCHA_STATUSES - 1, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_STATUS, param_spec); tp_dbus_properties_mixin_implement_interface (object_class, TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION, tp_dbus_properties_mixin_getter_gobject_properties, NULL, server_authentication_props); tp_dbus_properties_mixin_implement_interface (object_class, TP_IFACE_QUARK_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION, tp_dbus_properties_mixin_getter_gobject_properties, NULL, captcha_authentication_props); g_type_class_add_private (object_class, sizeof (TpTestsCaptchaChannelPrivate)); } static void set_status (TpTestsCaptchaChannel *self, guint status, const gchar *error, GHashTable *error_details) { GPtrArray *changed = g_ptr_array_new (); GHashTable *realerrors = error_details == NULL ? tp_asv_new (NULL, NULL) : error_details; if (self->priv->status != status) { self->priv->status = status; g_ptr_array_add (changed, (gpointer) "CaptchaStatus"); } if (self->priv->error_string != error) { g_free (self->priv->error_string); self->priv->error_string = g_strdup (error); g_ptr_array_add (changed, (gpointer) "CaptchaError"); } if (self->priv->error_details != realerrors) { if (self->priv->error_details != NULL) g_hash_table_unref (self->priv->error_details); self->priv->error_details = realerrors; if (self->priv->error_details != NULL) g_hash_table_ref (self->priv->error_details); g_ptr_array_add (changed, (gpointer) "CaptchaErrorDetails"); } if (changed->len > 0) { g_ptr_array_add (changed, NULL); tp_dbus_properties_mixin_emit_properties_changed (G_OBJECT (self), TP_IFACE_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION, (const gchar * const *) changed->pdata); } g_ptr_array_unref (changed); } static void captcha_auth_answer_captchas (TpSvcChannelInterfaceCaptchaAuthentication *iface, GHashTable *answers, DBusGMethodInvocation *context) { TpTestsCaptchaChannel *self = (TpTestsCaptchaChannel *) iface; const gchar *answer; GError *error; if (self->priv->status != TP_CAPTCHA_STATUS_LOCAL_PENDING) { error = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Captcha status is in state %u", self->priv->status); dbus_g_method_return_error (context, error); g_error_free (error); return; } set_status(self, TP_CAPTCHA_STATUS_REMOTE_PENDING, NULL, NULL); answer = (const gchar *) g_hash_table_lookup (answers, GUINT_TO_POINTER (42)); if (answer == NULL) { error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Missing required challenge ID (%u)", 42); dbus_g_method_return_error (context, error); g_error_free (error); return; } if (tp_str_empty (answer)) { error = g_error_new_literal (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Empty answer"); dbus_g_method_return_error (context, error); g_error_free (error); return; } if (tp_strdiff (answer, "This is the right answer")) { if (self->priv->can_retry) { set_status(self, TP_CAPTCHA_STATUS_TRY_AGAIN, NULL, NULL); } else { set_status(self, TP_CAPTCHA_STATUS_FAILED, NULL, NULL); } error = g_error_new_literal (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Wrong answer"); dbus_g_method_return_error (context, error); g_error_free (error); return; } else { set_status(self, TP_CAPTCHA_STATUS_SUCCEEDED, NULL, NULL); } tp_svc_channel_interface_captcha_authentication_return_from_answer_captchas (context); } static void captcha_auth_get_captchas (TpSvcChannelInterfaceCaptchaAuthentication *iface, DBusGMethodInvocation *context) { TpTestsCaptchaChannel *self = (TpTestsCaptchaChannel *) iface; GPtrArray *infos; GValueArray *info; static const gchar *mime_types_1[] = { "image/png", NULL }; static const gchar *mime_types_2[] = { "lol/wut", NULL }; static const gchar *no_mime_types[] = { NULL }; if (self->priv->status != TP_CAPTCHA_STATUS_LOCAL_PENDING && self->priv->status != TP_CAPTCHA_STATUS_TRY_AGAIN) { GError *error = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Captcha status is in state %u", self->priv->status); dbus_g_method_return_error (context, error); g_error_free (error); return; } /* Yes, g_ptr_array_new_full() could be used here, but use * these functions instead to support older GLibs */ infos = g_ptr_array_sized_new (5); g_ptr_array_set_free_func (infos, (GDestroyNotify) g_value_array_free); info = tp_value_array_build (5, G_TYPE_UINT, 42, G_TYPE_STRING, "ocr", G_TYPE_STRING, "Enter the text displayed", G_TYPE_UINT, 0, G_TYPE_STRV, mime_types_1, G_TYPE_INVALID); g_ptr_array_add (infos, info); info = tp_value_array_build (5, G_TYPE_UINT, 76, G_TYPE_STRING, "picture_q", G_TYPE_STRING, "What in this picture?", G_TYPE_UINT, 0, G_TYPE_STRV, mime_types_2, G_TYPE_INVALID); g_ptr_array_add (infos, info); info = tp_value_array_build (5, G_TYPE_UINT, 15, G_TYPE_STRING, "qa", G_TYPE_STRING, "What is the answer?", G_TYPE_UINT, 0, G_TYPE_STRV, no_mime_types, G_TYPE_INVALID); g_ptr_array_add (infos, info); info = tp_value_array_build (5, G_TYPE_UINT, 51, G_TYPE_STRING, "video_q", G_TYPE_STRING, "Totallyfake", G_TYPE_UINT, 0, G_TYPE_STRV, no_mime_types, G_TYPE_INVALID); g_ptr_array_add (infos, info); info = tp_value_array_build (5, G_TYPE_UINT, 17, G_TYPE_STRING, "video_recog", G_TYPE_STRING, "Totallyfakeurgonnadie", G_TYPE_UINT, 0, G_TYPE_STRV, mime_types_2, G_TYPE_INVALID); g_ptr_array_add (infos, info); if (self->priv->status == TP_CAPTCHA_STATUS_TRY_AGAIN) { /* Handler started trying again, change status back */ set_status (self, TP_CAPTCHA_STATUS_LOCAL_PENDING, NULL, NULL); self->priv->is_retrying = TRUE; } tp_svc_channel_interface_captcha_authentication_return_from_get_captchas (context, infos, 1, ""); g_ptr_array_unref (infos); } static void captcha_auth_get_captcha_data (TpSvcChannelInterfaceCaptchaAuthentication *iface, guint id, const gchar *mime_type, DBusGMethodInvocation *context) { TpTestsCaptchaChannel *self = (TpTestsCaptchaChannel *) iface; GArray *captcha; if (self->priv->status != TP_CAPTCHA_STATUS_LOCAL_PENDING) { GError *error = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Captcha status is in state %u", self->priv->status); dbus_g_method_return_error (context, error); g_error_free (error); return; } if (id != 42 && id != 76) { GError *error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Invalid captcha ID (%u).", id); dbus_g_method_return_error (context, error); g_error_free (error); return; } if (tp_strdiff (mime_type, "image/png") && tp_strdiff (mime_type, "lol/wut")) { GError *error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "MIME type '%s' was not in the list provided. ", mime_type); dbus_g_method_return_error (context, error); g_error_free (error); return; } captcha = g_array_new (TRUE, FALSE, sizeof (guchar)); if (self->priv->is_retrying) { g_array_append_vals (captcha, "This is a reloaded payload", 26); } else { g_array_append_vals (captcha, "This is a fake payload", 22); } tp_svc_channel_interface_captcha_authentication_return_from_get_captcha_data (context, captcha); g_array_unref (captcha); } static void captcha_auth_cancel_captcha (TpSvcChannelInterfaceCaptchaAuthentication *iface, guint reason, const gchar *debug_message, DBusGMethodInvocation *context) { TpTestsCaptchaChannel *self = (TpTestsCaptchaChannel *) iface; const gchar *error = NULL; GError *gerror = NULL; GHashTable *error_details = NULL; if (self->priv->status == TP_CAPTCHA_STATUS_FAILED) { gerror = g_error_new_literal (TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Captcha status is already Failed"); dbus_g_method_return_error (context, gerror); g_error_free (gerror); return; } switch (reason) { case TP_CAPTCHA_CANCEL_REASON_USER_CANCELLED: error = TP_ERROR_STR_CANCELLED; break; case TP_CAPTCHA_CANCEL_REASON_NOT_SUPPORTED: error = TP_ERROR_STR_CAPTCHA_NOT_SUPPORTED; break; case TP_CAPTCHA_CANCEL_REASON_SERVICE_CONFUSED: error = TP_ERROR_STR_SERVICE_CONFUSED; break; default: g_warning ("Unknown cancel reason"); } error_details = tp_asv_new ( "debug-message", G_TYPE_STRING, debug_message, NULL); set_status (self, TP_CAPTCHA_STATUS_FAILED, error, error_details); g_hash_table_unref (error_details); tp_svc_channel_interface_captcha_authentication_return_from_cancel_captcha (context); } static void captcha_iface_init (gpointer g_iface, gpointer data G_GNUC_UNUSED) { TpSvcChannelInterfaceCaptchaAuthenticationClass *iface = (TpSvcChannelInterfaceCaptchaAuthenticationClass *) g_iface; #define IMPLEMENT(x) \ tp_svc_channel_interface_captcha_authentication_implement_##x (iface, \ captcha_auth_##x) IMPLEMENT(answer_captchas); IMPLEMENT(get_captchas); IMPLEMENT(get_captcha_data); IMPLEMENT(cancel_captcha); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/bug16307-conn.h0000664000175000017500000000422012470405660020055 0ustar jrjr/* * bug16307-conn.h - header for a connection that reproduces the #15307 bug * * Copyright (C) 2007-2008 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_BUG16307_CONN_H__ #define __TP_TESTS_BUG16307_CONN_H__ #include #include #include "simple-conn.h" G_BEGIN_DECLS typedef struct _TpTestsBug16307Connection TpTestsBug16307Connection; typedef struct _TpTestsBug16307ConnectionClass TpTestsBug16307ConnectionClass; typedef struct _TpTestsBug16307ConnectionPrivate TpTestsBug16307ConnectionPrivate; struct _TpTestsBug16307ConnectionClass { TpTestsSimpleConnectionClass parent_class; }; struct _TpTestsBug16307Connection { TpTestsSimpleConnection parent; TpTestsBug16307ConnectionPrivate *priv; }; GType tp_tests_bug16307_connection_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_BUG16307_CONNECTION \ (tp_tests_bug16307_connection_get_type ()) #define TP_TESTS_BUG16307_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_BUG16307_CONNECTION, \ TpTestsBug16307Connection)) #define TP_TESTS_BUG16307_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_BUG16307_CONNECTION, \ TpTestsBug16307ConnectionClass)) #define TP_TESTS_BUG16307_IS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_BUG16307_CONNECTION)) #define TP_TESTS_BUG16307_IS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_BUG16307_CONNECTION)) #define TP_TESTS_BUG16307_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_BUG16307_CONNECTION, \ TpTestsBug16307ConnectionClass)) /* Cause "network events", for debugging/testing */ void tp_tests_bug16307_connection_inject_get_status_return (TpTestsBug16307Connection *self); G_END_DECLS #endif /* #ifndef __TP_TESTS_BUG16307_CONN_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/util.c0000664000175000017500000002675312470405660016733 0ustar jrjr/* Simple utility code used by the regression tests. * * Copyright © 2008-2010 Collabora Ltd. * Copyright © 2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "config.h" #include "util.h" #include #include #include #ifdef G_OS_UNIX # include /* for alarm() */ #endif #ifdef HAVE_GIO_UNIX #include #include #endif void tp_tests_proxy_run_until_prepared (gpointer proxy, const GQuark *features) { GError *error = NULL; tp_tests_proxy_run_until_prepared_or_failed (proxy, features, &error); g_assert_no_error (error); } /* A GAsyncReadyCallback whose user_data is a GAsyncResult **. It writes a * reference to the result into that pointer. */ void tp_tests_result_ready_cb (GObject *object, GAsyncResult *res, gpointer user_data) { GAsyncResult **result = user_data; *result = g_object_ref (res); } /* Run until *result contains a result. Intended to be used with a pending * async call that uses tp_tests_result_ready_cb. */ void tp_tests_run_until_result (GAsyncResult **result) { /* not synchronous */ g_assert (*result == NULL); while (*result == NULL) g_main_context_iteration (NULL, TRUE); } gboolean tp_tests_proxy_run_until_prepared_or_failed (gpointer proxy, const GQuark *features, GError **error) { GAsyncResult *result = NULL; gboolean r; tp_proxy_prepare_async (proxy, features, tp_tests_result_ready_cb, &result); tp_tests_run_until_result (&result); r = tp_proxy_prepare_finish (proxy, result, error); g_object_unref (result); return r; } TpDBusDaemon * tp_tests_dbus_daemon_dup_or_die (void) { TpDBusDaemon *d = tp_dbus_daemon_dup (NULL); /* In a shared library, this would be very bad (see fd.o #18832), but in a * regression test that's going to be run under a temporary session bus, * it's just what we want. */ if (d == NULL) { g_error ("Unable to connect to session bus"); } return d; } static void introspect_cb (TpProxy *proxy G_GNUC_UNUSED, const gchar *xml G_GNUC_UNUSED, const GError *error G_GNUC_UNUSED, gpointer user_data, GObject *weak_object G_GNUC_UNUSED) { g_main_loop_quit (user_data); } void tp_tests_proxy_run_until_dbus_queue_processed (gpointer proxy) { GMainLoop *loop = g_main_loop_new (NULL, FALSE); tp_cli_dbus_introspectable_call_introspect (proxy, -1, introspect_cb, loop, NULL, NULL); g_main_loop_run (loop); g_main_loop_unref (loop); } void _test_assert_empty_strv (const char *file, int line, gconstpointer strv) { const gchar * const *strings = strv; if (strv != NULL && strings[0] != NULL) { guint i; g_message ("%s:%d: expected empty strv, but got:", file, line); for (i = 0; strings[i] != NULL; i++) { g_message ("* \"%s\"", strings[i]); } g_error ("%s:%d: strv wasn't empty (see above for contents", file, line); } } void _tp_tests_assert_strv_equals (const char *file, int line, const char *expected_desc, gconstpointer expected_strv, const char *actual_desc, gconstpointer actual_strv) { const gchar * const *expected = expected_strv; const gchar * const *actual = actual_strv; guint i; g_assert (expected != NULL); g_assert (actual != NULL); for (i = 0; expected[i] != NULL || actual[i] != NULL; i++) { if (expected[i] == NULL) { g_error ("%s:%d: assertion failed: (%s)[%u] == (%s)[%u]: " "NULL == %s", file, line, expected_desc, i, actual_desc, i, actual[i]); } else if (actual[i] == NULL) { g_error ("%s:%d: assertion failed: (%s)[%u] == (%s)[%u]: " "%s == NULL", file, line, expected_desc, i, actual_desc, i, expected[i]); } else if (tp_strdiff (expected[i], actual[i])) { g_error ("%s:%d: assertion failed: (%s)[%u] == (%s)[%u]: " "%s == %s", file, line, expected_desc, i, actual_desc, i, expected[i], actual[i]); } } } void tp_tests_create_conn (GType conn_type, const gchar *account, gboolean connect, TpBaseConnection **service_conn, TpConnection **client_conn) { TpDBusDaemon *dbus; TpSimpleClientFactory *factory; gchar *name; gchar *conn_path; GError *error = NULL; g_assert (service_conn != NULL); g_assert (client_conn != NULL); dbus = tp_tests_dbus_daemon_dup_or_die (); factory = (TpSimpleClientFactory *) tp_automatic_client_factory_new (dbus); *service_conn = tp_tests_object_new_static_class ( conn_type, "account", account, "protocol", "simple", NULL); g_assert (*service_conn != NULL); g_assert (tp_base_connection_register (*service_conn, "simple", &name, &conn_path, &error)); g_assert_no_error (error); *client_conn = tp_simple_client_factory_ensure_connection (factory, conn_path, NULL, &error); g_assert (*client_conn != NULL); g_assert_no_error (error); if (connect) { GQuark conn_features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 }; tp_cli_connection_call_connect (*client_conn, -1, NULL, NULL, NULL, NULL); tp_tests_proxy_run_until_prepared (*client_conn, conn_features); } g_free (name); g_free (conn_path); g_object_unref (dbus); g_object_unref (factory); } void tp_tests_create_and_connect_conn (GType conn_type, const gchar *account, TpBaseConnection **service_conn, TpConnection **client_conn) { tp_tests_create_conn (conn_type, account, TRUE, service_conn, client_conn); } /* This object exists solely so that tests/tests.supp can ignore "leaked" * classes. */ gpointer tp_tests_object_new_static_class (GType type, ...) { va_list ap; GObject *object; const gchar *first_property; va_start (ap, type); first_property = va_arg (ap, const gchar *); object = g_object_new_valist (type, first_property, ap); va_end (ap); return object; } static gboolean time_out (gpointer nil G_GNUC_UNUSED) { g_error ("Timed out"); g_assert_not_reached (); return FALSE; } void tp_tests_abort_after (guint sec) { gboolean debugger = FALSE; gchar *contents; if (g_file_get_contents ("/proc/self/status", &contents, NULL, NULL)) { /* http://www.youtube.com/watch?v=SXmv8quf_xM */ #define TRACER_T "\nTracerPid:\t" gchar *line = strstr (contents, TRACER_T); if (line != NULL) { gchar *value = line + strlen (TRACER_T); if (value[0] != '0' || value[1] != '\n') debugger = TRUE; } g_free (contents); } if (g_getenv ("TP_TESTS_NO_TIMEOUT") != NULL || debugger) return; g_timeout_add_seconds (sec, time_out, NULL); #ifdef G_OS_UNIX /* On Unix, we can kill the process more reliably; this is a safety-catch * in case it deadlocks or something, in which case the main loop won't be * processed. The default handler for SIGALRM is process termination. */ alarm (sec + 2); #endif } void tp_tests_init (int *argc, char ***argv) { g_type_init (); tp_tests_abort_after (10); tp_debug_set_flags ("all"); g_test_init (argc, argv, NULL); } void _tp_destroy_socket_control_list (gpointer data) { GArray *tab = data; g_array_unref (tab); } GValue * _tp_create_local_socket (TpSocketAddressType address_type, TpSocketAccessControl access_control, GSocketService **service, gchar **unix_address, GError **error) { gboolean success; GSocketAddress *address, *effective_address; GValue *address_gvalue; g_assert (service != NULL); g_assert (unix_address != NULL); switch (access_control) { case TP_SOCKET_ACCESS_CONTROL_LOCALHOST: case TP_SOCKET_ACCESS_CONTROL_CREDENTIALS: case TP_SOCKET_ACCESS_CONTROL_PORT: break; default: g_assert_not_reached (); } switch (address_type) { #ifdef HAVE_GIO_UNIX case TP_SOCKET_ADDRESS_TYPE_UNIX: { address = g_unix_socket_address_new (tmpnam (NULL)); break; } #endif case TP_SOCKET_ADDRESS_TYPE_IPV4: case TP_SOCKET_ADDRESS_TYPE_IPV6: { GInetAddress *localhost; localhost = g_inet_address_new_loopback ( address_type == TP_SOCKET_ADDRESS_TYPE_IPV4 ? G_SOCKET_FAMILY_IPV4 : G_SOCKET_FAMILY_IPV6); address = g_inet_socket_address_new (localhost, 0); g_object_unref (localhost); break; } default: g_assert_not_reached (); } *service = g_socket_service_new (); success = g_socket_listener_add_address ( G_SOCKET_LISTENER (*service), address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, NULL, &effective_address, NULL); g_assert (success); switch (address_type) { #ifdef HAVE_GIO_UNIX case TP_SOCKET_ADDRESS_TYPE_UNIX: *unix_address = g_strdup (g_unix_socket_address_get_path ( G_UNIX_SOCKET_ADDRESS (effective_address))); address_gvalue = tp_g_value_slice_new_bytes ( g_unix_socket_address_get_path_len ( G_UNIX_SOCKET_ADDRESS (effective_address)), g_unix_socket_address_get_path ( G_UNIX_SOCKET_ADDRESS (effective_address))); break; #endif case TP_SOCKET_ADDRESS_TYPE_IPV4: case TP_SOCKET_ADDRESS_TYPE_IPV6: *unix_address = NULL; address_gvalue = tp_g_value_slice_new_take_boxed ( TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4, dbus_g_type_specialized_construct ( TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4)); dbus_g_type_struct_set (address_gvalue, 0, address_type == TP_SOCKET_ADDRESS_TYPE_IPV4 ? "127.0.0.1" : "::1", 1, g_inet_socket_address_get_port ( G_INET_SOCKET_ADDRESS (effective_address)), G_MAXUINT); break; default: g_assert_not_reached (); } g_object_unref (address); g_object_unref (effective_address); return address_gvalue; } void tp_tests_connection_assert_disconnect_succeeds (TpConnection *connection) { GAsyncResult *result = NULL; GError *error = NULL; gboolean ok; tp_connection_disconnect_async (connection, tp_tests_result_ready_cb, &result); tp_tests_run_until_result (&result); ok = tp_connection_disconnect_finish (connection, result, &error); g_assert_no_error (error); g_assert (ok); g_object_unref (result); } /* The following blocks require tp-glib 0.19 to compile. However, tp_tests_connection_run_until_contact_by_id is never used in our code, so we simply disable its compilation. */ #if 0 static void one_contact_cb (GObject *object, GAsyncResult *result, gpointer user_data) { TpConnection *connection = (TpConnection *) object; TpContact **contact_loc = user_data; GError *error = NULL; *contact_loc = tp_connection_dup_contact_by_id_finish (connection, result, &error); g_assert_no_error (error); g_assert (TP_IS_CONTACT (*contact_loc)); } TpContact * tp_tests_connection_run_until_contact_by_id (TpConnection *connection, const gchar *id, guint n_features, const TpContactFeature *features) { TpContact *contact = NULL; tp_connection_dup_contact_by_id_async (connection, id, n_features, features, one_contact_cb, &contact); while (contact == NULL) g_main_context_iteration (NULL, TRUE); return contact; } #endif telepathy-qt-0.9.6~git1/tests/lib/glib/contact-search-chan.c0000664000175000017500000005331312470405660021553 0ustar jrjr/* * contact-search-channel.c - an tp_tests contact search channel * * Copyright © 2010 Collabora Ltd. * Copyright © 2010 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "contact-search-chan.h" #include #include #include #include #include #include #include #include static void contact_search_iface_init (gpointer iface, gpointer data); static void channel_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (TpTestsContactSearchChannel, tp_tests_contact_search_channel, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_CONTACT_SEARCH, contact_search_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, tp_group_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL)) enum { PROP_OBJECT_PATH = 1, PROP_CHANNEL_TYPE, PROP_HANDLE_TYPE, PROP_HANDLE, PROP_TARGET_ID, PROP_REQUESTED, PROP_INITIATOR_HANDLE, PROP_INITIATOR_ID, PROP_CONNECTION, PROP_INTERFACES, PROP_CHANNEL_DESTROYED, PROP_CHANNEL_PROPERTIES, PROP_CONTACT_SEARCH_STATE, PROP_CONTACT_SEARCH_LIMIT, PROP_CONTACT_SEARCH_AVAILABLE_SEARCH_KEYS, PROP_CONTACT_SEARCH_SERVER, N_PROPS }; typedef struct { gchar *id; gchar *employer; GPtrArray *contact_info; } TpTestsContactSearchContact; struct _TpTestsContactSearchChannelPrivate { TpBaseConnection *conn; gchar *object_path; guint contact_search_state; guint contact_search_limit; gchar **contact_search_available_search_keys; gchar *contact_search_server; GSList *contact_search_contacts; gboolean disposed; gboolean closed; }; static const gchar * tp_tests_contact_search_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_GROUP, NULL }; static void tp_tests_contact_search_channel_init (TpTestsContactSearchChannel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_CONTACT_SEARCH_CHANNEL, TpTestsContactSearchChannelPrivate); } static TpTestsContactSearchContact * new_contact (const gchar *id, const gchar *employer, const gchar *fn) { TpTestsContactSearchContact *contact = g_new (TpTestsContactSearchContact, 1); GPtrArray *contact_info = dbus_g_type_specialized_construct ( TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST); const gchar * const field_values[2] = { fn, NULL }; contact->id = g_strdup (id); contact->employer = g_strdup (employer); g_ptr_array_add (contact_info, tp_value_array_build (3, G_TYPE_STRING, "fn", G_TYPE_STRV, NULL, G_TYPE_STRV, field_values, G_TYPE_INVALID)); contact->contact_info = contact_info; return contact; } static void free_contact (TpTestsContactSearchContact *contact) { g_free (contact->id); g_free (contact->employer); g_boxed_free (TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST, contact->contact_info); g_free (contact); } static void constructed (GObject *object) { void (*chain_up) (GObject *) = ((GObjectClass *) tp_tests_contact_search_channel_parent_class)->constructed; TpTestsContactSearchChannel *self = TP_TESTS_CONTACT_SEARCH_CHANNEL (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); TpDBusDaemon *bus; if (chain_up != NULL) { chain_up (object); } bus = tp_dbus_daemon_dup (NULL); tp_dbus_daemon_register_object (bus, self->priv->object_path, object); tp_group_mixin_init (object, G_STRUCT_OFFSET (TpTestsContactSearchChannel, group), contact_repo, self->priv->conn->self_handle); self->priv->contact_search_state = TP_CHANNEL_CONTACT_SEARCH_STATE_NOT_STARTED; self->priv->contact_search_limit = 0; self->priv->contact_search_available_search_keys = g_new0 (gchar *, 2); self->priv->contact_search_available_search_keys[0] = g_strdup ("employer"); self->priv->contact_search_server = g_strdup ("characters.shakespeare.lit"); self->priv->contact_search_contacts = g_slist_append (self->priv->contact_search_contacts, new_contact ("oggis", "Collabora", "Olli Salli")); self->priv->contact_search_contacts = g_slist_append (self->priv->contact_search_contacts, new_contact ("andrunko", "Collabora", "Andre Moreira Magalhaes")); self->priv->contact_search_contacts = g_slist_append (self->priv->contact_search_contacts, new_contact ("wjt", "Collabora", "Will Thompson")); self->priv->contact_search_contacts = g_slist_append (self->priv->contact_search_contacts, new_contact ("foo", "Other Employer", "Foo")); self->priv->contact_search_contacts = g_slist_append (self->priv->contact_search_contacts, new_contact ("bar", "Other Employer", "Bar")); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { TpTestsContactSearchChannel *self = TP_TESTS_CONTACT_SEARCH_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: g_value_set_string (value, self->priv->object_path); break; case PROP_CHANNEL_TYPE: g_value_set_static_string (value, TP_IFACE_CHANNEL); break; case PROP_HANDLE_TYPE: g_value_set_uint (value, TP_HANDLE_TYPE_NONE); break; case PROP_HANDLE: g_value_set_uint (value, 0); break; case PROP_TARGET_ID: g_value_set_string (value, ""); break; case PROP_REQUESTED: g_value_set_boolean (value, TRUE); break; case PROP_INITIATOR_HANDLE: g_value_set_uint (value, 0); break; case PROP_INITIATOR_ID: g_value_set_string (value, ""); break; case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; case PROP_INTERFACES: g_value_set_boxed (value, tp_tests_contact_search_channel_interfaces); break; case PROP_CHANNEL_DESTROYED: g_value_set_boolean (value, self->priv->closed); break; case PROP_CHANNEL_PROPERTIES: g_value_take_boxed (value, tp_dbus_properties_mixin_make_properties_hash (object, TP_IFACE_CHANNEL, "ChannelType", TP_IFACE_CHANNEL, "TargetHandleType", TP_IFACE_CHANNEL, "TargetHandle", TP_IFACE_CHANNEL, "TargetID", TP_IFACE_CHANNEL, "InitiatorHandle", TP_IFACE_CHANNEL, "InitiatorID", TP_IFACE_CHANNEL, "Requested", TP_IFACE_CHANNEL, "Interfaces", TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, "SearchState", TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, "Limit", TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, "AvailableSearchKeys", TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, "Server", NULL)); break; case PROP_CONTACT_SEARCH_STATE: g_value_set_uint (value, self->priv->contact_search_state); g_assert (G_VALUE_HOLDS (value, G_TYPE_UINT)); break; case PROP_CONTACT_SEARCH_LIMIT: g_value_set_uint (value, self->priv->contact_search_limit); g_assert (G_VALUE_HOLDS (value, G_TYPE_UINT)); break; case PROP_CONTACT_SEARCH_AVAILABLE_SEARCH_KEYS: g_value_set_boxed (value, self->priv->contact_search_available_search_keys); g_assert (G_VALUE_HOLDS (value, G_TYPE_STRV)); break; case PROP_CONTACT_SEARCH_SERVER: g_value_set_string (value, self->priv->contact_search_server); g_assert (G_VALUE_HOLDS (value, G_TYPE_STRING)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { TpTestsContactSearchChannel *self = TP_TESTS_CONTACT_SEARCH_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: self->priv->object_path = g_value_dup_string (value); break; case PROP_CONNECTION: self->priv->conn = g_value_get_object (value); break; case PROP_CHANNEL_TYPE: case PROP_HANDLE: case PROP_HANDLE_TYPE: case PROP_TARGET_ID: case PROP_REQUESTED: case PROP_INITIATOR_HANDLE: case PROP_INITIATOR_ID: /* these properties are not actually meaningfully changeable on this * channel, so we do nothing */ break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dispose (GObject *object) { TpTestsContactSearchChannel *self = TP_TESTS_CONTACT_SEARCH_CHANNEL (object); GSList *l; if (self->priv->disposed) { return; } self->priv->disposed = TRUE; g_strfreev (self->priv->contact_search_available_search_keys); self->priv->contact_search_available_search_keys = NULL; g_free (self->priv->contact_search_server); self->priv->contact_search_server = NULL; for (l = self->priv->contact_search_contacts; l != NULL; l = g_slist_next (l)) { free_contact ((TpTestsContactSearchContact *) l->data); } g_slist_free (self->priv->contact_search_contacts); if (!self->priv->closed) { self->priv->closed = TRUE; tp_svc_channel_emit_closed (self); } ((GObjectClass *) tp_tests_contact_search_channel_parent_class)->dispose (object); } static void finalize (GObject *object) { TpTestsContactSearchChannel *self = TP_TESTS_CONTACT_SEARCH_CHANNEL (object); g_free (self->priv->object_path); tp_group_mixin_finalize (object); ((GObjectClass *) tp_tests_contact_search_channel_parent_class)->finalize (object); } static void tp_tests_contact_search_channel_class_init (TpTestsContactSearchChannelClass *klass) { static TpDBusPropertiesMixinPropImpl channel_props[] = { { "TargetHandleType", "handle-type", NULL }, { "TargetHandle", "handle", NULL }, { "ChannelType", "channel-type", NULL }, { "Interfaces", "interfaces", NULL }, { "TargetID", "target-id", NULL }, { "Requested", "requested", NULL }, { "InitiatorHandle", "initiator-handle", NULL }, { "InitiatorID", "initiator-id", NULL }, { NULL } }; static TpDBusPropertiesMixinPropImpl contact_search_props[] = { { "SearchState", "search-state", NULL }, { "Limit", "limit", NULL }, { "AvailableSearchKeys", "available-search-keys", NULL }, { "Server", "server", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CHANNEL, tp_dbus_properties_mixin_getter_gobject_properties, NULL, channel_props, }, { TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, tp_dbus_properties_mixin_getter_gobject_properties, NULL, contact_search_props, }, { NULL } }; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (TpTestsContactSearchChannelPrivate)); object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path"); g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type"); g_object_class_override_property (object_class, PROP_HANDLE, "handle"); g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, "channel-destroyed"); g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, "channel-properties"); param_spec = g_param_spec_object ("connection", "TpBaseConnection object", "Connection object that owns this channel", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "Additional Channel.Interface.* interfaces", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_string ("target-id", "Peer's ID", "The string obtained by inspecting the target handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", "The contact who initiated the channel", 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, param_spec); param_spec = g_param_spec_string ("initiator-id", "Initiator's ID", "The string obtained by inspecting the initiator-handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_ID, param_spec); param_spec = g_param_spec_boolean ("requested", "Requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); param_spec = g_param_spec_uint ("search-state", "Search state", "The search state", 0, NUM_TP_CHANNEL_CONTACT_SEARCH_STATES, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONTACT_SEARCH_STATE, param_spec); param_spec = g_param_spec_uint ("limit", "Search limit", "The search limit", 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONTACT_SEARCH_LIMIT, param_spec); param_spec = g_param_spec_boxed ("available-search-keys", "Available Search Keys", "The available search keys", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONTACT_SEARCH_AVAILABLE_SEARCH_KEYS, param_spec); param_spec = g_param_spec_string ("server", "Server", "The search server", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONTACT_SEARCH_SERVER, param_spec); klass->dbus_properties_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsContactSearchChannelClass, dbus_properties_class)); tp_group_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsContactSearchChannelClass, group_class), NULL, NULL); tp_group_mixin_init_dbus_properties (object_class); } static void channel_close (TpSvcChannel *iface, DBusGMethodInvocation *context) { TpTestsContactSearchChannel *self = TP_TESTS_CONTACT_SEARCH_CHANNEL (iface); if (!self->priv->closed) { self->priv->closed = TRUE; tp_svc_channel_emit_closed (self); } tp_svc_channel_return_from_close (context); } static void channel_get_channel_type (TpSvcChannel *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_channel_type (context, TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); } static void channel_get_handle (TpSvcChannel *iface, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_NONE, 0); } static void channel_get_interfaces (TpSvcChannel *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_interfaces (context, tp_tests_contact_search_channel_interfaces); } static void channel_iface_init (gpointer iface, gpointer data) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x) IMPLEMENT (close); IMPLEMENT (get_channel_type); IMPLEMENT (get_handle); IMPLEMENT (get_interfaces); #undef IMPLEMENT } static void change_search_state (TpTestsContactSearchChannel *self, guint state, const gchar *debug_message) { GHashTable *details = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); g_hash_table_insert (details, "debug-message", tp_g_value_slice_new_string (debug_message)); self->priv->contact_search_state = state; tp_svc_channel_type_contact_search_emit_search_state_changed (self, self->priv->contact_search_state, "", details); g_hash_table_destroy (details); } static gboolean validate_terms (TpTestsContactSearchChannel *self, GHashTable *terms, GError **error) { const gchar * const *asks = (const gchar * const *) self->priv->contact_search_available_search_keys; GHashTableIter iter; gpointer key; g_hash_table_iter_init (&iter, terms); while (g_hash_table_iter_next (&iter, &key, NULL)) { gchar *field = key; if (!tp_strv_contains (asks, field)) { g_debug ("%s is not in AvailableSearchKeys", field); g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s is not in AvailableSearchKeys", field); return FALSE; } } return TRUE; } static gboolean do_search (TpTestsContactSearchChannel *self, GHashTable *terms, GError **error) { GHashTable *results = g_hash_table_new (g_str_hash, g_str_equal); GHashTableIter iter; gchar *key, *value; if (!validate_terms (self, terms, error)) { return FALSE; } g_debug ("Doing search"); change_search_state (self, TP_CHANNEL_CONTACT_SEARCH_STATE_IN_PROGRESS, "in progress"); g_hash_table_iter_init (&iter, terms); while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) { GSList *l; for (l = self->priv->contact_search_contacts; l != NULL; l = g_slist_next (l)) { TpTestsContactSearchContact *contact = (TpTestsContactSearchContact *) l->data; if (strcmp (contact->employer, value) == 0) { g_hash_table_insert (results, contact->id, contact->contact_info); } } } tp_svc_channel_type_contact_search_emit_search_result_received (self, results); change_search_state (self, TP_CHANNEL_CONTACT_SEARCH_STATE_COMPLETED, "completed"); g_hash_table_destroy (results); return TRUE; } static void contact_search_search (TpSvcChannelTypeContactSearch *iface G_GNUC_UNUSED, GHashTable *terms, DBusGMethodInvocation *context) { TpTestsContactSearchChannel *self = TP_TESTS_CONTACT_SEARCH_CHANNEL (iface); TpTestsContactSearchChannelPrivate *priv = self->priv; GError *error = NULL; if (priv->contact_search_state != TP_CHANNEL_CONTACT_SEARCH_STATE_NOT_STARTED) { g_debug ("Search state is %d", priv->contact_search_state); error = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE, "SearchState is %d", priv->contact_search_state); goto err; } if (do_search (self, terms, &error)) { tp_svc_channel_type_contact_search_return_from_search (context); return; } err: dbus_g_method_return_error (context, error); g_error_free (error); } static void contact_search_more (TpSvcChannelTypeContactSearch *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { tp_svc_channel_type_contact_search_return_from_more (context); } static void contact_search_stop (TpSvcChannelTypeContactSearch *iface, DBusGMethodInvocation *context) { TpTestsContactSearchChannel *self = TP_TESTS_CONTACT_SEARCH_CHANNEL (iface); TpTestsContactSearchChannelPrivate *priv = self->priv; switch (priv->contact_search_state) { case TP_CHANNEL_CONTACT_SEARCH_STATE_IN_PROGRESS: change_search_state (self, TP_CHANNEL_CONTACT_SEARCH_STATE_FAILED, "stopped while in progress"); case TP_CHANNEL_CONTACT_SEARCH_STATE_COMPLETED: tp_svc_channel_type_contact_search_return_from_stop (context); break; case TP_CHANNEL_CONTACT_SEARCH_STATE_NOT_STARTED: { GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Search() hasn't been called yet" }; g_debug ("%s", e.message); dbus_g_method_return_error (context, &e); break; } case TP_CHANNEL_CONTACT_SEARCH_STATE_FAILED: case TP_CHANNEL_CONTACT_SEARCH_STATE_MORE_AVAILABLE: g_assert_not_reached (); } } static void contact_search_iface_init (gpointer iface, gpointer data) { TpSvcChannelTypeContactSearchClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_type_contact_search_implement_##x (klass, contact_search_##x) IMPLEMENT (search); IMPLEMENT (more); IMPLEMENT (stop); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/echo/0000775000175000017500000000000012470405660016513 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/echo/connection-manager.h0000664000175000017500000000413112470405660022432 0ustar jrjr/* * manager.h - header for an example connection manager * Copyright (C) 2007 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_ECHO_CONNECTION_MANAGER_H__ #define __EXAMPLE_ECHO_CONNECTION_MANAGER_H__ #include #include G_BEGIN_DECLS typedef struct _ExampleEchoConnectionManager ExampleEchoConnectionManager; typedef struct _ExampleEchoConnectionManagerPrivate ExampleEchoConnectionManagerPrivate; typedef struct _ExampleEchoConnectionManagerClass ExampleEchoConnectionManagerClass; typedef struct _ExampleEchoConnectionManagerClassPrivate ExampleEchoConnectionManagerClassPrivate; struct _ExampleEchoConnectionManagerClass { TpBaseConnectionManagerClass parent_class; ExampleEchoConnectionManagerClassPrivate *priv; }; struct _ExampleEchoConnectionManager { TpBaseConnectionManager parent; ExampleEchoConnectionManagerPrivate *priv; }; GType example_echo_connection_manager_get_type (void); /* TYPE MACROS */ #define EXAMPLE_TYPE_ECHO_CONNECTION_MANAGER \ (example_echo_connection_manager_get_type ()) #define EXAMPLE_ECHO_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_ECHO_CONNECTION_MANAGER, \ ExampleEchoConnectionManager)) #define EXAMPLE_ECHO_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_ECHO_CONNECTION_MANAGER, \ ExampleEchoConnectionManagerClass)) #define EXAMPLE_IS_ECHO_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_ECHO_CONNECTION_MANAGER)) #define EXAMPLE_IS_ECHO_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_ECHO_CONNECTION_MANAGER)) #define EXAMPLE_ECHO_CONNECTION_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_CONNECTION_MANAGER, \ ExampleEchoConnectionManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/echo/conn.h0000664000175000017500000000340512470405660017623 0ustar jrjr/* * conn.h - header for an example connection * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_ECHO_CONN_H__ #define __EXAMPLE_ECHO_CONN_H__ #include #include G_BEGIN_DECLS typedef struct _ExampleEchoConnection ExampleEchoConnection; typedef struct _ExampleEchoConnectionClass ExampleEchoConnectionClass; typedef struct _ExampleEchoConnectionPrivate ExampleEchoConnectionPrivate; struct _ExampleEchoConnectionClass { TpBaseConnectionClass parent_class; }; struct _ExampleEchoConnection { TpBaseConnection parent; ExampleEchoConnectionPrivate *priv; }; GType example_echo_connection_get_type (void); /* TYPE MACROS */ #define EXAMPLE_TYPE_ECHO_CONNECTION \ (example_echo_connection_get_type ()) #define EXAMPLE_ECHO_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_ECHO_CONNECTION, \ ExampleEchoConnection)) #define EXAMPLE_ECHO_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_ECHO_CONNECTION, \ ExampleEchoConnectionClass)) #define EXAMPLE_IS_ECHO_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_ECHO_CONNECTION)) #define EXAMPLE_IS_ECHO_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_ECHO_CONNECTION)) #define EXAMPLE_ECHO_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_CONNECTION, \ ExampleEchoConnectionClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/echo/CMakeLists.txt0000664000175000017500000000104412470405660021252 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(example_cm_echo_SRCS chan.c chan.h conn.c conn.h connection-manager.c connection-manager.h im-manager.c im-manager.h ) add_library(example-cm-echo STATIC ${example_cm_echo_SRCS}) target_link_libraries(example-cm-echo ${TPGLIB_LIBRARIES}) tpqt_generate_manager_file(${CMAKE_CURRENT_SOURCE_DIR}/manager-file.py example_echo.manager connection-manager.c) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/echo/manager-file.py0000664000175000017500000000100412470405660021407 0ustar jrjr# Input for tools/manager-file.py MANAGER = 'example_echo' PARAMS = { 'example' : { 'account': { 'dtype': 's', 'flags': 'required register', 'filter': 'tp_cm_param_filter_string_nonempty', # 'filter_data': 'NULL', # 'default': ..., # 'struct_field': '...', # 'setter_data': 'NULL', }, }, } STRUCTS = { 'example': 'ExampleParams' } telepathy-qt-0.9.6~git1/tests/lib/glib/echo/chan.h0000664000175000017500000000350412470405660017577 0ustar jrjr/* * chan.h - header for an example channel * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_CHAN_H__ #define __EXAMPLE_CHAN_H__ #include #include #include G_BEGIN_DECLS typedef struct _ExampleEchoChannel ExampleEchoChannel; typedef struct _ExampleEchoChannelClass ExampleEchoChannelClass; typedef struct _ExampleEchoChannelPrivate ExampleEchoChannelPrivate; GType example_echo_channel_get_type (void); #define EXAMPLE_TYPE_ECHO_CHANNEL \ (example_echo_channel_get_type ()) #define EXAMPLE_ECHO_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_ECHO_CHANNEL, \ ExampleEchoChannel)) #define EXAMPLE_ECHO_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_ECHO_CHANNEL, \ ExampleEchoChannelClass)) #define EXAMPLE_IS_ECHO_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_ECHO_CHANNEL)) #define EXAMPLE_IS_ECHO_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_ECHO_CHANNEL)) #define EXAMPLE_ECHO_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_CHANNEL, \ ExampleEchoChannelClass)) struct _ExampleEchoChannelClass { GObjectClass parent_class; TpTextMixinClass text_class; TpDBusPropertiesMixinClass dbus_properties_class; }; struct _ExampleEchoChannel { GObject parent; TpTextMixin text; ExampleEchoChannelPrivate *priv; }; G_END_DECLS #endif /* #ifndef __EXAMPLE_CHAN_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/echo/conn.c0000664000175000017500000001225212470405660017616 0ustar jrjr/* * conn.c - an example connection * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "conn.h" #include #include #include #include "im-manager.h" G_DEFINE_TYPE (ExampleEchoConnection, example_echo_connection, TP_TYPE_BASE_CONNECTION) /* type definition stuff */ enum { PROP_ACCOUNT = 1, N_PROPS }; struct _ExampleEchoConnectionPrivate { gchar *account; }; static void example_echo_connection_init (ExampleEchoConnection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_CONNECTION, ExampleEchoConnectionPrivate); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { ExampleEchoConnection *self = EXAMPLE_ECHO_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_value_set_string (value, self->priv->account); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *spec) { ExampleEchoConnection *self = EXAMPLE_ECHO_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_free (self->priv->account); self->priv->account = g_utf8_strdown (g_value_get_string (value), -1); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void finalize (GObject *object) { ExampleEchoConnection *self = EXAMPLE_ECHO_CONNECTION (object); g_free (self->priv->account); G_OBJECT_CLASS (example_echo_connection_parent_class)->finalize (object); } static gchar * get_unique_connection_name (TpBaseConnection *conn) { ExampleEchoConnection *self = EXAMPLE_ECHO_CONNECTION (conn); return g_strdup (self->priv->account); } static gchar * example_echo_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error) { if (id[0] == '\0') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "ID must not be empty"); return NULL; } return g_utf8_strdown (id, -1); } static void create_handle_repos (TpBaseConnection *conn, TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]) { repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_CONTACT, example_echo_normalize_contact, NULL); } static GPtrArray * create_channel_managers (TpBaseConnection *conn) { GPtrArray *ret = g_ptr_array_sized_new (1); g_ptr_array_add (ret, g_object_new (EXAMPLE_TYPE_ECHO_IM_MANAGER, "connection", conn, NULL)); return ret; } static gboolean start_connecting (TpBaseConnection *conn, GError **error) { ExampleEchoConnection *self = EXAMPLE_ECHO_CONNECTION (conn); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); /* In a real connection manager we'd ask the underlying implementation to * start connecting, then go to state CONNECTED when finished, but here * we can do it immediately. */ conn->self_handle = tp_handle_ensure (contact_repo, self->priv->account, NULL, NULL); tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); return TRUE; } static void shut_down (TpBaseConnection *conn) { /* In a real connection manager we'd ask the underlying implementation to * start shutting down, then call this function when finished, but here * we can do it immediately. */ tp_base_connection_finish_shutdown (conn); } static void example_echo_connection_class_init (ExampleEchoConnectionClass *klass) { static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_REQUESTS, NULL }; TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; object_class->get_property = get_property; object_class->set_property = set_property; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (ExampleEchoConnectionPrivate)); base_class->create_handle_repos = create_handle_repos; base_class->get_unique_connection_name = get_unique_connection_name; base_class->create_channel_managers = create_channel_managers; base_class->start_connecting = start_connecting; base_class->shut_down = shut_down; base_class->interfaces_always_present = interfaces_always_present; param_spec = g_param_spec_string ("account", "Account name", "The username of this user", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); } telepathy-qt-0.9.6~git1/tests/lib/glib/echo/im-manager.h0000664000175000017500000000332212470405660020701 0ustar jrjr/* * im-manager.h - header for an example channel manager * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_ECHO_IM_MANAGER_H__ #define __EXAMPLE_ECHO_IM_MANAGER_H__ #include G_BEGIN_DECLS typedef struct _ExampleEchoImManager ExampleEchoImManager; typedef struct _ExampleEchoImManagerClass ExampleEchoImManagerClass; typedef struct _ExampleEchoImManagerPrivate ExampleEchoImManagerPrivate; struct _ExampleEchoImManagerClass { GObjectClass parent_class; }; struct _ExampleEchoImManager { GObject parent; ExampleEchoImManagerPrivate *priv; }; GType example_echo_im_manager_get_type (void); /* TYPE MACROS */ #define EXAMPLE_TYPE_ECHO_IM_MANAGER \ (example_echo_im_manager_get_type ()) #define EXAMPLE_ECHO_IM_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_ECHO_IM_MANAGER, \ ExampleEchoImManager)) #define EXAMPLE_ECHO_IM_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_ECHO_IM_MANAGER, \ ExampleEchoImManagerClass)) #define EXAMPLE_IS_ECHO_IM_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_ECHO_IM_MANAGER)) #define EXAMPLE_IS_ECHO_IM_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_ECHO_IM_MANAGER)) #define EXAMPLE_ECHO_IM_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_IM_MANAGER, \ ExampleEchoImManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/echo/chan.c0000664000175000017500000003651312470405660017600 0ustar jrjr/* * chan.c - an example text channel talking to a particular * contact. Similar code is used for 1-1 IM channels in many protocols * (IRC private messages ("/query"), XMPP IM etc.) * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ // We need to use the deprecated TpTextMixin here to test compatibility functionality #define _TP_IGNORE_DEPRECATIONS #include "chan.h" #include #include #include static void text_iface_init (gpointer iface, gpointer data); static void channel_iface_init (gpointer iface, gpointer data); static void destroyable_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (ExampleEchoChannel, example_echo_channel, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, text_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DESTROYABLE, destroyable_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL)) /* type definition stuff */ enum { PROP_OBJECT_PATH = 1, PROP_CHANNEL_TYPE, PROP_HANDLE_TYPE, PROP_HANDLE, PROP_TARGET_ID, PROP_REQUESTED, PROP_INITIATOR_HANDLE, PROP_INITIATOR_ID, PROP_CONNECTION, PROP_INTERFACES, PROP_CHANNEL_DESTROYED, PROP_CHANNEL_PROPERTIES, N_PROPS }; struct _ExampleEchoChannelPrivate { TpBaseConnection *conn; gchar *object_path; TpHandle handle; TpHandle initiator; /* These are really booleans, but gboolean is signed. Thanks, GLib */ unsigned closed:1; unsigned disposed:1; }; static const char * example_echo_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_DESTROYABLE, NULL }; static void example_echo_channel_init (ExampleEchoChannel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_CHANNEL, ExampleEchoChannelPrivate); } static GObject * constructor (GType type, guint n_props, GObjectConstructParam *props) { GObject *object = G_OBJECT_CLASS (example_echo_channel_parent_class)->constructor (type, n_props, props); ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); tp_dbus_daemon_register_object ( tp_base_connection_get_dbus_daemon (self->priv->conn), self->priv->object_path, self); tp_text_mixin_init (object, G_STRUCT_OFFSET (ExampleEchoChannel, text), contact_repo); tp_text_mixin_set_message_types (object, TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION, TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE, G_MAXUINT); return object; } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: g_value_set_string (value, self->priv->object_path); break; case PROP_CHANNEL_TYPE: g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT); break; case PROP_HANDLE_TYPE: g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); break; case PROP_HANDLE: g_value_set_uint (value, self->priv->handle); break; case PROP_TARGET_ID: { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( self->priv->conn, TP_HANDLE_TYPE_CONTACT); g_value_set_string (value, tp_handle_inspect (contact_repo, self->priv->handle)); } break; case PROP_REQUESTED: g_value_set_boolean (value, (self->priv->initiator == self->priv->conn->self_handle)); break; case PROP_INITIATOR_HANDLE: g_value_set_uint (value, self->priv->initiator); break; case PROP_INITIATOR_ID: { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( self->priv->conn, TP_HANDLE_TYPE_CONTACT); g_value_set_string (value, self->priv->initiator == 0 ? "" : tp_handle_inspect (contact_repo, self->priv->initiator)); } break; case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; case PROP_INTERFACES: g_value_set_boxed (value, example_echo_channel_interfaces); break; case PROP_CHANNEL_DESTROYED: g_value_set_boolean (value, self->priv->closed); break; case PROP_CHANNEL_PROPERTIES: g_value_take_boxed (value, tp_dbus_properties_mixin_make_properties_hash (object, TP_IFACE_CHANNEL, "ChannelType", TP_IFACE_CHANNEL, "TargetHandleType", TP_IFACE_CHANNEL, "TargetHandle", TP_IFACE_CHANNEL, "TargetID", TP_IFACE_CHANNEL, "InitiatorHandle", TP_IFACE_CHANNEL, "InitiatorID", TP_IFACE_CHANNEL, "Requested", TP_IFACE_CHANNEL, "Interfaces", NULL)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: g_free (self->priv->object_path); self->priv->object_path = g_value_dup_string (value); break; case PROP_HANDLE: /* we don't ref it here because we don't necessarily have access to the * contact repo yet - instead we ref it in the constructor. */ self->priv->handle = g_value_get_uint (value); break; case PROP_INITIATOR_HANDLE: /* likewise */ self->priv->initiator = g_value_get_uint (value); break; case PROP_HANDLE_TYPE: case PROP_CHANNEL_TYPE: /* these properties are writable in the interface, but not actually * meaningfully changable on this channel, so we do nothing */ break; case PROP_CONNECTION: self->priv->conn = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dispose (GObject *object) { ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (object); if (self->priv->disposed) return; self->priv->disposed = TRUE; if (!self->priv->closed) { self->priv->closed = TRUE; tp_svc_channel_emit_closed (self); } ((GObjectClass *) example_echo_channel_parent_class)->dispose (object); } static void finalize (GObject *object) { ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (object); g_free (self->priv->object_path); tp_text_mixin_finalize (object); ((GObjectClass *) example_echo_channel_parent_class)->finalize (object); } static void example_echo_channel_class_init (ExampleEchoChannelClass *klass) { static TpDBusPropertiesMixinPropImpl channel_props[] = { { "TargetHandleType", "handle-type", NULL }, { "TargetHandle", "handle", NULL }, { "ChannelType", "channel-type", NULL }, { "Interfaces", "interfaces", NULL }, { "TargetID", "target-id", NULL }, { "Requested", "requested", NULL }, { "InitiatorHandle", "initiator-handle", NULL }, { "InitiatorID", "initiator-id", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CHANNEL, tp_dbus_properties_mixin_getter_gobject_properties, NULL, channel_props, }, { NULL } }; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (ExampleEchoChannelPrivate)); object_class->constructor = constructor; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path"); g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type"); g_object_class_override_property (object_class, PROP_HANDLE, "handle"); g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, "channel-destroyed"); g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, "channel-properties"); param_spec = g_param_spec_object ("connection", "TpBaseConnection object", "Connection object that owns this channel", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "Additional Channel.Interface.* interfaces", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_string ("target-id", "Peer's ID", "The string obtained by inspecting the target handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", "The contact who initiated the channel", 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, param_spec); param_spec = g_param_spec_string ("initiator-id", "Initiator's ID", "The string obtained by inspecting the initiator-handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_ID, param_spec); param_spec = g_param_spec_boolean ("requested", "Requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); tp_text_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleEchoChannelClass, text_class)); klass->dbus_properties_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleEchoChannelClass, dbus_properties_class)); } static void example_echo_channel_close (ExampleEchoChannel *self) { GObject *object = (GObject *) self; if (!self->priv->closed) { TpHandle first_sender; /* The manager wants to be able to respawn the channel if it has pending * messages. When respawned, the channel must have the initiator set * to the contact who sent us those messages (if it isn't already), * and the messages must be marked as having been rescued so they * don't get logged twice. */ if (tp_text_mixin_has_pending_messages (object, &first_sender)) { if (self->priv->initiator != first_sender) { self->priv->initiator = first_sender; } tp_text_mixin_set_rescued (object); } else { /* No pending messages, so it's OK to really close */ self->priv->closed = TRUE; } tp_svc_channel_emit_closed (self); } } static void channel_close (TpSvcChannel *iface, DBusGMethodInvocation *context) { ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (iface); example_echo_channel_close (self); tp_svc_channel_return_from_close (context); } static void channel_get_channel_type (TpSvcChannel *iface, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_channel_type (context, TP_IFACE_CHANNEL_TYPE_TEXT); } static void channel_get_handle (TpSvcChannel *iface, DBusGMethodInvocation *context) { ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (iface); tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT, self->priv->handle); } static void channel_get_interfaces (TpSvcChannel *iface, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_interfaces (context, example_echo_channel_interfaces); } static void channel_iface_init (gpointer iface, gpointer data) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x) IMPLEMENT (close); IMPLEMENT (get_channel_type); IMPLEMENT (get_handle); IMPLEMENT (get_interfaces); #undef IMPLEMENT } static void text_send (TpSvcChannelTypeText *iface, guint type, const gchar *text, DBusGMethodInvocation *context) { ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (iface); time_t timestamp = time (NULL); gchar *echo; guint echo_type = type; /* Send should return just before Sent is emitted. */ tp_svc_channel_type_text_return_from_send (context); /* Tell the client that the message was submitted for sending */ tp_svc_channel_type_text_emit_sent ((GObject *) self, timestamp, type, text); /* Pretend that the remote contact has replied. Normally, you'd * call tp_text_mixin_receive or tp_text_mixin_receive_with_flags * in response to network events */ switch (type) { case TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL: echo = g_strdup_printf ("You said: %s", text); break; case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION: echo = g_strdup_printf ("notices that the user %s", text); break; case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE: echo = g_strdup_printf ("You sent a notice: %s", text); break; default: echo = g_strdup_printf ("You sent some weird message type, %u: \"%s\"", type, text); echo_type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL; } tp_text_mixin_receive ((GObject *) self, echo_type, self->priv->handle, timestamp, echo); g_free (echo); } static void text_iface_init (gpointer iface, gpointer data) { TpSvcChannelTypeTextClass *klass = iface; tp_text_mixin_iface_init (iface, data); #define IMPLEMENT(x) tp_svc_channel_type_text_implement_##x (klass, text_##x) IMPLEMENT (send); #undef IMPLEMENT } static void destroyable_destroy (TpSvcChannelInterfaceDestroyable *iface, DBusGMethodInvocation *context) { ExampleEchoChannel *self = EXAMPLE_ECHO_CHANNEL (iface); tp_text_mixin_clear ((GObject *) self); example_echo_channel_close (self); g_assert (self->priv->closed); tp_svc_channel_interface_destroyable_return_from_destroy (context); } static void destroyable_iface_init (gpointer iface, gpointer data) { TpSvcChannelInterfaceDestroyableClass *klass = iface; #define IMPLEMENT(x) \ tp_svc_channel_interface_destroyable_implement_##x (klass, destroyable_##x) IMPLEMENT (destroy); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/echo/connection-manager.c0000664000175000017500000000371512470405660022434 0ustar jrjr/* * manager.c - an example connection manager * * Copyright (C) 2007 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "connection-manager.h" #include #include #include #include "conn.h" G_DEFINE_TYPE (ExampleEchoConnectionManager, example_echo_connection_manager, TP_TYPE_BASE_CONNECTION_MANAGER) /* type definition stuff */ static void example_echo_connection_manager_init (ExampleEchoConnectionManager *self) { } /* private data */ typedef struct { gchar *account; } ExampleParams; #include "_gen/param-spec-struct.h" static gpointer alloc_params (void) { return g_slice_new0 (ExampleParams); } static void free_params (gpointer p) { ExampleParams *params = p; g_free (params->account); g_slice_free (ExampleParams, params); } static const TpCMProtocolSpec example_protocols[] = { { "example", example_echo_example_params, alloc_params, free_params }, { NULL, NULL } }; static TpBaseConnection * new_connection (TpBaseConnectionManager *self, const gchar *proto, TpIntSet *params_present, gpointer parsed_params, GError **error) { ExampleParams *params = parsed_params; ExampleEchoConnection *conn = EXAMPLE_ECHO_CONNECTION (g_object_new (EXAMPLE_TYPE_ECHO_CONNECTION, "account", params->account, "protocol", proto, NULL)); return (TpBaseConnection *) conn; } static void example_echo_connection_manager_class_init ( ExampleEchoConnectionManagerClass *klass) { TpBaseConnectionManagerClass *base_class = (TpBaseConnectionManagerClass *) klass; base_class->new_connection = new_connection; base_class->cm_dbus_name = "example_echo"; base_class->protocol_params = example_protocols; } telepathy-qt-0.9.6~git1/tests/lib/glib/echo/im-manager.c0000664000175000017500000002463212470405660020703 0ustar jrjr/* * im-manager.c - an example channel manager for channels talking to a * particular contact. Similar code is used for 1-1 IM channels in many * protocols (IRC private messages ("/query"), XMPP IM etc.) * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "im-manager.h" #include #include #include "chan.h" static void channel_manager_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (ExampleEchoImManager, example_echo_im_manager, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, channel_manager_iface_init)) /* type definition stuff */ enum { PROP_CONNECTION = 1, N_PROPS }; struct _ExampleEchoImManagerPrivate { TpBaseConnection *conn; /* GUINT_TO_POINTER (handle) => ExampleEchoChannel */ GHashTable *channels; gulong status_changed_id; }; static void example_echo_im_manager_init (ExampleEchoImManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_IM_MANAGER, ExampleEchoImManagerPrivate); self->priv->channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); } static void example_echo_im_manager_close_all (ExampleEchoImManager *self); static void dispose (GObject *object) { ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (object); example_echo_im_manager_close_all (self); g_assert (self->priv->channels == NULL); ((GObjectClass *) example_echo_im_manager_parent_class)->dispose (object); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (object); switch (property_id) { case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (object); switch (property_id) { case PROP_CONNECTION: /* We don't ref the connection, because it owns a reference to the * channel manager, and it guarantees that the manager's lifetime is * less than its lifetime */ self->priv->conn = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void status_changed_cb (TpBaseConnection *conn, guint status, guint reason, ExampleEchoImManager *self) { if (status == TP_CONNECTION_STATUS_DISCONNECTED) example_echo_im_manager_close_all (self); } static void constructed (GObject *object) { ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_echo_im_manager_parent_class)->constructed; if (chain_up != NULL) { chain_up (object); } self->priv->status_changed_id = g_signal_connect (self->priv->conn, "status-changed", (GCallback) status_changed_cb, self); } static void example_echo_im_manager_class_init (ExampleEchoImManagerClass *klass) { GParamSpec *param_spec; GObjectClass *object_class = (GObjectClass *) klass; object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; param_spec = g_param_spec_object ("connection", "Connection object", "The connection that owns this channel manager", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); g_type_class_add_private (klass, sizeof (ExampleEchoImManagerPrivate)); } static void example_echo_im_manager_close_all (ExampleEchoImManager *self) { if (self->priv->channels != NULL) { GHashTable *tmp = self->priv->channels; self->priv->channels = NULL; g_hash_table_destroy (tmp); } if (self->priv->status_changed_id != 0) { g_signal_handler_disconnect (self->priv->conn, self->priv->status_changed_id); self->priv->status_changed_id = 0; } } static void example_echo_im_manager_foreach_channel (TpChannelManager *iface, TpExportableChannelFunc callback, gpointer user_data) { ExampleEchoImManager *self = EXAMPLE_ECHO_IM_MANAGER (iface); GHashTableIter iter; gpointer handle, channel; g_hash_table_iter_init (&iter, self->priv->channels); while (g_hash_table_iter_next (&iter, &handle, &channel)) { callback (TP_EXPORTABLE_CHANNEL (channel), user_data); } } static void channel_closed_cb (ExampleEchoChannel *chan, ExampleEchoImManager *self) { tp_channel_manager_emit_channel_closed_for_object (self, TP_EXPORTABLE_CHANNEL (chan)); if (self->priv->channels != NULL) { TpHandle handle; gboolean really_destroyed; g_object_get (chan, "handle", &handle, "channel-destroyed", &really_destroyed, NULL); /* Re-announce the channel if it's not yet ready to go away (pending * messages) */ if (really_destroyed) { g_hash_table_remove (self->priv->channels, GUINT_TO_POINTER (handle)); } else { tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan), NULL); } } } static void new_channel (ExampleEchoImManager *self, TpHandle handle, TpHandle initiator, gpointer request_token) { ExampleEchoChannel *chan; gchar *object_path; GSList *requests = NULL; object_path = g_strdup_printf ("%s/EchoChannel%u", self->priv->conn->object_path, handle); chan = g_object_new (EXAMPLE_TYPE_ECHO_CHANNEL, "connection", self->priv->conn, "object-path", object_path, "handle", handle, "initiator-handle", initiator, NULL); g_free (object_path); g_signal_connect (chan, "closed", (GCallback) channel_closed_cb, self); /* self->priv->channels takes ownership of 'chan' */ g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle), chan); if (request_token != NULL) requests = g_slist_prepend (requests, request_token); tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan), requests); g_slist_free (requests); } static const gchar * const fixed_properties[] = { TP_PROP_CHANNEL_CHANNEL_TYPE, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL }; static const gchar * const allowed_properties[] = { TP_PROP_CHANNEL_TARGET_HANDLE, TP_PROP_CHANNEL_TARGET_ID, NULL }; static void example_echo_im_manager_foreach_channel_class (TpChannelManager *manager, TpChannelManagerChannelClassFunc func, gpointer user_data) { GHashTable *table = tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, NULL); func (manager, table, allowed_properties, user_data); g_hash_table_destroy (table); } static gboolean example_echo_im_manager_request (ExampleEchoImManager *self, gpointer request_token, GHashTable *request_properties, gboolean require_new) { TpHandle handle; ExampleEchoChannel *chan; GError *error = NULL; if (tp_strdiff (tp_asv_get_string (request_properties, TP_PROP_CHANNEL_CHANNEL_TYPE), TP_IFACE_CHANNEL_TYPE_TEXT)) { return FALSE; } if (tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != TP_HANDLE_TYPE_CONTACT) { return FALSE; } handle = tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE, NULL); g_assert (handle != 0); if (tp_channel_manager_asv_has_unknown_properties (request_properties, fixed_properties, allowed_properties, &error)) { goto error; } chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle)); if (chan == NULL) { new_channel (self, handle, self->priv->conn->self_handle, request_token); } else if (require_new) { g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "An echo channel to contact #%u already exists", handle); goto error; } else { tp_channel_manager_emit_request_already_satisfied (self, request_token, TP_EXPORTABLE_CHANNEL (chan)); } return TRUE; error: tp_channel_manager_emit_request_failed (self, request_token, error->domain, error->code, error->message); g_error_free (error); return TRUE; } static gboolean example_echo_im_manager_create_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_echo_im_manager_request (EXAMPLE_ECHO_IM_MANAGER (manager), request_token, request_properties, TRUE); } static gboolean example_echo_im_manager_ensure_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_echo_im_manager_request (EXAMPLE_ECHO_IM_MANAGER (manager), request_token, request_properties, FALSE); } static void channel_manager_iface_init (gpointer g_iface, gpointer iface_data G_GNUC_UNUSED) { TpChannelManagerIface *iface = g_iface; iface->foreach_channel = example_echo_im_manager_foreach_channel; iface->foreach_channel_class = example_echo_im_manager_foreach_channel_class; iface->create_channel = example_echo_im_manager_create_channel; iface->ensure_channel = example_echo_im_manager_ensure_channel; /* In this channel manager, Request has the same semantics as Ensure */ iface->request_channel = example_echo_im_manager_ensure_channel; } telepathy-qt-0.9.6~git1/tests/lib/glib/call/0000775000175000017500000000000012470405660016510 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/call/call-content.h0000664000175000017500000000530412470405660021246 0ustar jrjr/* * call-content.h - header for an example content * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef EXAMPLE_CALL_CONTENT_H #define EXAMPLE_CALL_CONTENT_H #include #include #include "call-stream.h" G_BEGIN_DECLS typedef struct _ExampleCallContent ExampleCallContent; typedef struct _ExampleCallContentPrivate ExampleCallContentPrivate; typedef struct _ExampleCallContentClass ExampleCallContentClass; typedef struct _ExampleCallContentClassPrivate ExampleCallContentClassPrivate; GType example_call_content_get_type (void); #define EXAMPLE_TYPE_CALL_CONTENT \ (example_call_content_get_type ()) #define EXAMPLE_CALL_CONTENT(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_CALL_CONTENT, \ ExampleCallContent)) #define EXAMPLE_CALL_CONTENT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_CALL_CONTENT, \ ExampleCallContentClass)) #define EXAMPLE_IS_CALL_CONTENT(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_CALL_CONTENT)) #define EXAMPLE_IS_CALL_CONTENT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_CALL_CONTENT)) #define EXAMPLE_CALL_CONTENT_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALL_CONTENT, \ ExampleCallContentClass)) struct _ExampleCallContentClass { TpBaseMediaCallContentClass parent_class; ExampleCallContentClassPrivate *priv; }; struct _ExampleCallContent { TpBaseMediaCallContent parent; ExampleCallContentPrivate *priv; }; /* In this example, each content can only have one stream. */ ExampleCallStream *example_call_content_get_stream (ExampleCallContent *self); void example_call_content_add_stream (ExampleCallContent *self, ExampleCallStream *stream); void example_call_content_remove_stream (ExampleCallContent *self); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/call/cm.c0000664000175000017500000000477512470405660017270 0ustar jrjr/* * manager.c - an example connection manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "cm.h" #include #include #include #include "conn.h" #include "protocol.h" G_DEFINE_TYPE (ExampleCallConnectionManager, example_call_connection_manager, TP_TYPE_BASE_CONNECTION_MANAGER) struct _ExampleCallConnectionManagerPrivate { int dummy; }; static void example_call_connection_manager_init (ExampleCallConnectionManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALL_CONNECTION_MANAGER, ExampleCallConnectionManagerPrivate); } static void example_call_connection_manager_constructed (GObject *object) { ExampleCallConnectionManager *self = EXAMPLE_CALL_CONNECTION_MANAGER (object); TpBaseConnectionManager *base = (TpBaseConnectionManager *) self; void (*constructed) (GObject *) = ((GObjectClass *) example_call_connection_manager_parent_class)->constructed; TpBaseProtocol *protocol; if (constructed != NULL) constructed (object); protocol = g_object_new (EXAMPLE_TYPE_CALL_PROTOCOL, "name", "example", NULL); tp_base_connection_manager_add_protocol (base, protocol); g_object_unref (protocol); } static void example_call_connection_manager_class_init ( ExampleCallConnectionManagerClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseConnectionManagerClass *base_class = (TpBaseConnectionManagerClass *) klass; g_type_class_add_private (klass, sizeof (ExampleCallConnectionManagerPrivate)); object_class->constructed = example_call_connection_manager_constructed; base_class->cm_dbus_name = "example_call"; } telepathy-qt-0.9.6~git1/tests/lib/glib/call/cm.h0000664000175000017500000000526112470405660017264 0ustar jrjr/* * manager.h - header for an example connection manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef EXAMPLE_CALL_CM_H #define EXAMPLE_CALL_CM_H #include #include G_BEGIN_DECLS typedef struct _ExampleCallConnectionManager ExampleCallConnectionManager; typedef struct _ExampleCallConnectionManagerPrivate ExampleCallConnectionManagerPrivate; typedef struct _ExampleCallConnectionManagerClass ExampleCallConnectionManagerClass; typedef struct _ExampleCallConnectionManagerClassPrivate ExampleCallConnectionManagerClassPrivate; struct _ExampleCallConnectionManagerClass { TpBaseConnectionManagerClass parent_class; ExampleCallConnectionManagerClassPrivate *priv; }; struct _ExampleCallConnectionManager { TpBaseConnectionManager parent; ExampleCallConnectionManagerPrivate *priv; }; GType example_call_connection_manager_get_type (void); /* TYPE MACROS */ #define EXAMPLE_TYPE_CALL_CONNECTION_MANAGER \ (example_call_connection_manager_get_type ()) #define EXAMPLE_CALL_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CALL_CONNECTION_MANAGER, \ ExampleCallConnectionManager)) #define EXAMPLE_CALL_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CALL_CONNECTION_MANAGER, \ ExampleCallConnectionManagerClass)) #define EXAMPLE_IS_CALL_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CALL_CONNECTION_MANAGER)) #define EXAMPLE_IS_CALL_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CALL_CONNECTION_MANAGER)) #define EXAMPLE_CALL_CONNECTION_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALL_CONNECTION_MANAGER, \ ExampleCallConnectionManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/call/call-stream.h0000664000175000017500000000524512470405660021073 0ustar jrjr/* * call-stream.h - header for an example stream * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef EXAMPLE_CALL_STREAM_H #define EXAMPLE_CALL_STREAM_H #include #include G_BEGIN_DECLS typedef struct _ExampleCallStream ExampleCallStream; typedef struct _ExampleCallStreamPrivate ExampleCallStreamPrivate; typedef struct _ExampleCallStreamClass ExampleCallStreamClass; typedef struct _ExampleCallStreamClassPrivate ExampleCallStreamClassPrivate; GType example_call_stream_get_type (void); #define EXAMPLE_TYPE_CALL_STREAM \ (example_call_stream_get_type ()) #define EXAMPLE_CALL_STREAM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_CALL_STREAM, \ ExampleCallStream)) #define EXAMPLE_CALL_STREAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_CALL_STREAM, \ ExampleCallStreamClass)) #define EXAMPLE_IS_CALL_STREAM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_CALL_STREAM)) #define EXAMPLE_IS_CALL_STREAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_CALL_STREAM)) #define EXAMPLE_CALL_STREAM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALL_STREAM, \ ExampleCallStreamClass)) struct _ExampleCallStreamClass { TpBaseMediaCallStreamClass parent_class; ExampleCallStreamClassPrivate *priv; }; struct _ExampleCallStream { TpBaseMediaCallStream parent; ExampleCallStreamPrivate *priv; }; void example_call_stream_accept_proposed_direction (ExampleCallStream *self); void example_call_stream_connect (ExampleCallStream *self); /* This controls receiving emulated network events, so it wouldn't exist in * a real connection manager */ void example_call_stream_simulate_contact_agreed_to_send ( ExampleCallStream *self); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/call/call-manager.c0000664000175000017500000003567612470405660021220 0ustar jrjr/* * call-manager.c - an example channel manager for Call channels. * * This channel manager emulates a protocol like XMPP Jingle, where you can * make several simultaneous calls to the same or different contacts. * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "call-manager.h" #include #include #include #include #include #include #include "call-channel.h" static void channel_manager_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (ExampleCallManager, example_call_manager, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, channel_manager_iface_init)) /* type definition stuff */ enum { PROP_CONNECTION = 1, PROP_SIMULATION_DELAY, N_PROPS }; struct _ExampleCallManagerPrivate { TpBaseConnection *conn; guint simulation_delay; /* Map from reffed ExampleCallChannel to the same pointer; used as a * set. */ GHashTable *channels; /* Next channel will be ("CallChannel%u", next_channel_index) */ guint next_channel_index; gulong status_changed_id; gulong available_id; }; static void example_call_manager_init (ExampleCallManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALL_MANAGER, ExampleCallManagerPrivate); self->priv->conn = NULL; self->priv->channels = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL); self->priv->status_changed_id = 0; self->priv->available_id = 0; } static void example_call_manager_close_all (ExampleCallManager *self) { if (self->priv->channels != NULL) { GHashTable *tmp = self->priv->channels; GHashTableIter iter; gpointer v; self->priv->channels = NULL; g_hash_table_iter_init (&iter, tmp); while (g_hash_table_iter_next (&iter, NULL, &v)) tp_base_channel_close (v); g_hash_table_unref (tmp); } if (self->priv->available_id != 0) { g_signal_handler_disconnect (self->priv->conn, self->priv->available_id); self->priv->available_id = 0; } if (self->priv->status_changed_id != 0) { g_signal_handler_disconnect (self->priv->conn, self->priv->status_changed_id); self->priv->status_changed_id = 0; } } static void dispose (GObject *object) { ExampleCallManager *self = EXAMPLE_CALL_MANAGER (object); example_call_manager_close_all (self); g_assert (self->priv->channels == NULL); ((GObjectClass *) example_call_manager_parent_class)->dispose ( object); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleCallManager *self = EXAMPLE_CALL_MANAGER (object); switch (property_id) { case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleCallManager *self = EXAMPLE_CALL_MANAGER (object); switch (property_id) { case PROP_CONNECTION: /* We don't ref the connection, because it owns a reference to the * channel manager, and it guarantees that the manager's lifetime is * less than its lifetime */ self->priv->conn = g_value_get_object (value); break; case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void status_changed_cb (TpBaseConnection *conn, guint status, guint reason, ExampleCallManager *self) { switch (status) { case TP_CONNECTION_STATUS_DISCONNECTED: { example_call_manager_close_all (self); } break; default: break; } } static ExampleCallChannel *new_channel (ExampleCallManager *self, TpHandle handle, TpHandle initiator, gpointer request_token, gboolean initial_audio, gboolean initial_video); static gboolean simulate_incoming_call_cb (gpointer p) { ExampleCallManager *self = p; TpHandleRepoIface *contact_repo; TpHandle caller; /* do nothing if we've been disconnected while waiting for the contact to * call us */ if (self->priv->available_id == 0) return FALSE; /* We're called by someone whose ID on the IM service is "caller" */ contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); caller = tp_handle_ensure (contact_repo, "caller", NULL, NULL); new_channel (self, caller, caller, NULL, TRUE, FALSE); return FALSE; } /* Whenever our presence changes from away to available, and whenever our * presence message changes while remaining available, simulate a call from * a contact */ static void available_cb (GObject *conn G_GNUC_UNUSED, const gchar *message, ExampleCallManager *self) { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_incoming_call_cb, g_object_ref (self), g_object_unref); } static void constructed (GObject *object) { ExampleCallManager *self = EXAMPLE_CALL_MANAGER (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_call_manager_parent_class)->constructed; if (chain_up != NULL) { chain_up (object); } self->priv->status_changed_id = g_signal_connect (self->priv->conn, "status-changed", (GCallback) status_changed_cb, self); self->priv->available_id = g_signal_connect (self->priv->conn, "available", (GCallback) available_cb, self); } static void example_call_manager_class_init (ExampleCallManagerClass *klass) { GParamSpec *param_spec; GObjectClass *object_class = (GObjectClass *) klass; object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; param_spec = g_param_spec_object ("connection", "Connection object", "The connection that owns this channel manager", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); g_type_class_add_private (klass, sizeof (ExampleCallManagerPrivate)); } static void example_call_manager_foreach_channel (TpChannelManager *iface, TpExportableChannelFunc callback, gpointer user_data) { ExampleCallManager *self = EXAMPLE_CALL_MANAGER (iface); GHashTableIter iter; gpointer chan; g_hash_table_iter_init (&iter, self->priv->channels); while (g_hash_table_iter_next (&iter, &chan, NULL)) callback (chan, user_data); } static void channel_closed_cb (ExampleCallChannel *chan, ExampleCallManager *self) { tp_channel_manager_emit_channel_closed_for_object (self, TP_EXPORTABLE_CHANNEL (chan)); if (self->priv->channels != NULL) g_hash_table_remove (self->priv->channels, chan); } static ExampleCallChannel * new_channel (ExampleCallManager *self, TpHandle handle, TpHandle initiator, gpointer request_token, gboolean initial_audio, gboolean initial_video) { ExampleCallChannel *chan; gchar *object_path; GSList *requests = NULL; /* FIXME: This could potentially wrap around, but only after 4 billion * calls, which is probably plenty. */ object_path = g_strdup_printf ("%s/CallChannel%u", self->priv->conn->object_path, self->priv->next_channel_index++); chan = g_object_new (EXAMPLE_TYPE_CALL_CHANNEL, "connection", self->priv->conn, "object-path", object_path, "handle", handle, "initiator-handle", initiator, "requested", (self->priv->conn->self_handle == initiator), "simulation-delay", self->priv->simulation_delay, "initial-audio", initial_audio, "initial-video", initial_video, "mutable-contents", TRUE, NULL); g_free (object_path); g_signal_connect (chan, "closed", G_CALLBACK (channel_closed_cb), self); g_hash_table_insert (self->priv->channels, chan, chan); if (request_token != NULL) requests = g_slist_prepend (requests, request_token); tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan), requests); g_slist_free (requests); return chan; } static const gchar * const audio_fixed_properties[] = { TP_PROP_CHANNEL_CHANNEL_TYPE, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, NULL }; static const gchar * const video_fixed_properties[] = { TP_PROP_CHANNEL_CHANNEL_TYPE, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, NULL }; static const gchar * const audio_allowed_properties[] = { TP_PROP_CHANNEL_TARGET_HANDLE, TP_PROP_CHANNEL_TARGET_ID, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, NULL }; static const gchar * const video_allowed_properties[] = { TP_PROP_CHANNEL_TARGET_HANDLE, TP_PROP_CHANNEL_TARGET_ID, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, NULL }; static void example_call_manager_type_foreach_channel_class (GType type, TpChannelManagerTypeChannelClassFunc func, gpointer user_data) { GHashTable *table = tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_CALL, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, G_TYPE_BOOLEAN, TRUE, NULL); func (type, table, audio_allowed_properties, user_data); g_hash_table_remove (table, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO); tp_asv_set_boolean (table, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, TRUE); func (type, table, video_allowed_properties, user_data); g_hash_table_unref (table); } static gboolean example_call_manager_request (ExampleCallManager *self, gpointer request_token, GHashTable *request_properties, gboolean require_new) { TpHandle handle; GError *error = NULL; gboolean initial_audio, initial_video; if (tp_strdiff (tp_asv_get_string (request_properties, TP_PROP_CHANNEL_CHANNEL_TYPE), TP_IFACE_CHANNEL_TYPE_CALL)) { return FALSE; } if (tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != TP_HANDLE_TYPE_CONTACT) { return FALSE; } handle = tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE, NULL); g_assert (handle != 0); initial_audio = tp_asv_get_boolean (request_properties, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, NULL); initial_video = tp_asv_get_boolean (request_properties, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, NULL); if (!initial_audio && !initial_video) { g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Call channels must initially have either audio or video content"); goto error; } /* the set of (fixed | allowed) properties is the same for audio and video, * so we only need to check with one set */ if (tp_channel_manager_asv_has_unknown_properties (request_properties, audio_fixed_properties, audio_allowed_properties, &error)) { goto error; } if (handle == self->priv->conn->self_handle) { /* In protocols with a concept of multiple "resources" signed in to * one account (XMPP, and possibly MSN) it is technically possible to * call yourself - e.g. if you're signed in on two PCs, you can call one * from the other. For simplicity, this example simulates a protocol * where this is not the case. */ g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "In this protocol, you can't call yourself"); goto error; } if (!require_new) { /* see if we're already calling that handle */ GHashTableIter iter; gpointer chan; g_hash_table_iter_init (&iter, self->priv->channels); while (g_hash_table_iter_next (&iter, &chan, NULL)) { guint its_handle; g_object_get (chan, "handle", &its_handle, NULL); if (its_handle == handle) { tp_channel_manager_emit_request_already_satisfied (self, request_token, TP_EXPORTABLE_CHANNEL (chan)); return TRUE; } } } new_channel (self, handle, self->priv->conn->self_handle, request_token, initial_audio, initial_video); return TRUE; error: tp_channel_manager_emit_request_failed (self, request_token, error->domain, error->code, error->message); g_error_free (error); return TRUE; } static gboolean example_call_manager_create_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_call_manager_request ( EXAMPLE_CALL_MANAGER (manager), request_token, request_properties, TRUE); } static gboolean example_call_manager_ensure_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_call_manager_request ( EXAMPLE_CALL_MANAGER (manager), request_token, request_properties, FALSE); } static void channel_manager_iface_init (gpointer g_iface, gpointer iface_data G_GNUC_UNUSED) { TpChannelManagerIface *iface = g_iface; iface->foreach_channel = example_call_manager_foreach_channel; iface->type_foreach_channel_class = example_call_manager_type_foreach_channel_class; iface->create_channel = example_call_manager_create_channel; iface->ensure_channel = example_call_manager_ensure_channel; /* In this channel manager, RequestChannel is not supported; Call is not * designed to work with the old RequestChannel API. */ iface->request_channel = NULL; } telepathy-qt-0.9.6~git1/tests/lib/glib/call/conn.h0000664000175000017500000000512212470405660017616 0ustar jrjr/* * conn.h - header for an example connection * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef EXAMPLE_CALL_CONN_H #define EXAMPLE_CALL_CONN_H #include #include #include #include G_BEGIN_DECLS typedef struct _ExampleCallConnection ExampleCallConnection; typedef struct _ExampleCallConnectionPrivate ExampleCallConnectionPrivate; typedef struct _ExampleCallConnectionClass ExampleCallConnectionClass; typedef struct _ExampleCallConnectionClassPrivate ExampleCallConnectionClassPrivate; struct _ExampleCallConnectionClass { TpBaseConnectionClass parent_class; TpPresenceMixinClass presence_mixin; TpContactsMixinClass contacts_mixin; ExampleCallConnectionClassPrivate *priv; }; struct _ExampleCallConnection { TpBaseConnection parent; TpPresenceMixin presence_mixin; TpContactsMixin contacts_mixin; ExampleCallConnectionPrivate *priv; }; GType example_call_connection_get_type (void); #define EXAMPLE_TYPE_CALL_CONNECTION \ (example_call_connection_get_type ()) #define EXAMPLE_CALL_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CALL_CONNECTION, \ ExampleCallConnection)) #define EXAMPLE_CALL_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CALL_CONNECTION, \ ExampleCallConnectionClass)) #define EXAMPLE_IS_CALL_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CALL_CONNECTION)) #define EXAMPLE_IS_CALL_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CALL_CONNECTION)) #define EXAMPLE_CALL_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALL_CONNECTION, \ ExampleCallConnectionClass)) /* Must be kept in sync with the array presence_statuses in conn.c */ typedef enum { EXAMPLE_CALL_PRESENCE_OFFLINE = 0, EXAMPLE_CALL_PRESENCE_UNKNOWN, EXAMPLE_CALL_PRESENCE_ERROR, EXAMPLE_CALL_PRESENCE_AWAY, EXAMPLE_CALL_PRESENCE_AVAILABLE } ExampleCallPresence; gchar *example_call_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error); const gchar * const *example_call_connection_get_possible_interfaces (void); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/call/CMakeLists.txt0000664000175000017500000000074712470405660021260 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) set(example_cm_call_SRCS call-channel.c call-channel.h call-content.c call-content.h call-manager.c call-manager.h call-stream.c call-stream.h cm.c cm.h conn.c conn.h protocol.c protocol.h) add_library(example-cm-call STATIC ${example_cm_call_SRCS}) target_link_libraries(example-cm-call ${TPGLIB_LIBRARIES}) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/call/call-manager.h0000664000175000017500000000450112470405660021204 0ustar jrjr/* * media-manager.h - header for an example channel manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef EXAMPLE_CALL_MANAGER_H #define EXAMPLE_CALL_MANAGER_H #include G_BEGIN_DECLS typedef struct _ExampleCallManager ExampleCallManager; typedef struct _ExampleCallManagerPrivate ExampleCallManagerPrivate; typedef struct _ExampleCallManagerClass ExampleCallManagerClass; typedef struct _ExampleCallManagerClassPrivate ExampleCallManagerClassPrivate; struct _ExampleCallManagerClass { GObjectClass parent_class; ExampleCallManagerClassPrivate *priv; }; struct _ExampleCallManager { GObject parent; ExampleCallManagerPrivate *priv; }; GType example_call_manager_get_type (void); /* TYPE MACROS */ #define EXAMPLE_TYPE_CALL_MANAGER \ (example_call_manager_get_type ()) #define EXAMPLE_CALL_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CALL_MANAGER, \ ExampleCallManager)) #define EXAMPLE_CALL_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CALL_MANAGER, \ ExampleCallManagerClass)) #define EXAMPLE_IS_CALL_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CALL_MANAGER)) #define EXAMPLE_IS_CALL_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CALL_MANAGER)) #define EXAMPLE_CALL_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALL_MANAGER, \ ExampleCallManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/call/call-channel.h0000664000175000017500000000436712470405660021214 0ustar jrjr/* * call-channel.h - header for an example channel * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef EXAMPLE_CALL_CHANNEL_H #define EXAMPLE_CALL_CHANNEL_H #include #include G_BEGIN_DECLS typedef struct _ExampleCallChannel ExampleCallChannel; typedef struct _ExampleCallChannelPrivate ExampleCallChannelPrivate; typedef struct _ExampleCallChannelClass ExampleCallChannelClass; GType example_call_channel_get_type (void); #define EXAMPLE_TYPE_CALL_CHANNEL \ (example_call_channel_get_type ()) #define EXAMPLE_CALL_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_CALL_CHANNEL, \ ExampleCallChannel)) #define EXAMPLE_CALL_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_CALL_CHANNEL, \ ExampleCallChannelClass)) #define EXAMPLE_IS_CALL_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_CALL_CHANNEL)) #define EXAMPLE_IS_CALL_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_CALL_CHANNEL)) #define EXAMPLE_CALL_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALL_CHANNEL, \ ExampleCallChannelClass)) struct _ExampleCallChannelClass { TpBaseMediaCallChannelClass parent_class; }; struct _ExampleCallChannel { TpBaseMediaCallChannel parent; ExampleCallChannelPrivate *priv; }; G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/call/conn.c0000664000175000017500000003042712470405660017617 0ustar jrjr/* * conn.c - an example connection * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "conn.h" #include #include #include #include #include "call-manager.h" #include "protocol.h" G_DEFINE_TYPE_WITH_CODE (ExampleCallConnection, example_call_connection, TP_TYPE_BASE_CONNECTION, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, tp_contacts_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE, tp_presence_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE, tp_presence_mixin_simple_presence_iface_init)) enum { PROP_ACCOUNT = 1, PROP_SIMULATION_DELAY, N_PROPS }; enum { SIGNAL_AVAILABLE, N_SIGNALS }; static guint signals[N_SIGNALS] = { 0 }; struct _ExampleCallConnectionPrivate { gchar *account; guint simulation_delay; gboolean away; gchar *presence_message; }; static void example_call_connection_init (ExampleCallConnection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALL_CONNECTION, ExampleCallConnectionPrivate); self->priv->away = FALSE; self->priv->presence_message = g_strdup (""); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_value_set_string (value, self->priv->account); break; case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *spec) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_free (self->priv->account); self->priv->account = g_value_dup_string (value); break; case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void finalize (GObject *object) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (object); tp_contacts_mixin_finalize (object); g_free (self->priv->account); g_free (self->priv->presence_message); G_OBJECT_CLASS (example_call_connection_parent_class)->finalize (object); } static gchar * get_unique_connection_name (TpBaseConnection *conn) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (conn); return g_strdup_printf ("%s@%p", self->priv->account, self); } gchar * example_call_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error) { gchar *normal = NULL; if (example_call_protocol_check_contact_id (id, &normal, error)) return normal; else return NULL; } static void create_handle_repos (TpBaseConnection *conn, TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]) { repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_CONTACT, example_call_normalize_contact, NULL); } static GPtrArray * create_channel_managers (TpBaseConnection *conn) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (conn); GPtrArray *ret = g_ptr_array_sized_new (1); g_ptr_array_add (ret, g_object_new (EXAMPLE_TYPE_CALL_MANAGER, "connection", conn, "simulation-delay", self->priv->simulation_delay, NULL)); return ret; } static gboolean start_connecting (TpBaseConnection *conn, GError **error) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (conn); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); /* In a real connection manager we'd ask the underlying implementation to * start connecting, then go to state CONNECTED when finished, but here * we can do it immediately. */ conn->self_handle = tp_handle_ensure (contact_repo, self->priv->account, NULL, error); if (conn->self_handle == 0) return FALSE; tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); return TRUE; } static void shut_down (TpBaseConnection *conn) { /* In a real connection manager we'd ask the underlying implementation to * start shutting down, then call this function when finished, but here * we can do it immediately. */ tp_base_connection_finish_shutdown (conn); } static void constructed (GObject *object) { TpBaseConnection *base = TP_BASE_CONNECTION (object); void (*chain_up) (GObject *) = G_OBJECT_CLASS (example_call_connection_parent_class)->constructed; if (chain_up != NULL) chain_up (object); tp_contacts_mixin_init (object, G_STRUCT_OFFSET (ExampleCallConnection, contacts_mixin)); tp_base_connection_register_with_contacts_mixin (base); tp_presence_mixin_init (object, G_STRUCT_OFFSET (ExampleCallConnection, presence_mixin)); tp_presence_mixin_simple_presence_register_with_contacts_mixin (object); } static gboolean status_available (GObject *object, guint index_) { TpBaseConnection *base = TP_BASE_CONNECTION (object); if (base->status != TP_CONNECTION_STATUS_CONNECTED) return FALSE; return TRUE; } static GHashTable * get_contact_statuses (GObject *object, const GArray *contacts, GError **error) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (object); TpBaseConnection *base = TP_BASE_CONNECTION (object); guint i; GHashTable *result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) tp_presence_status_free); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, guint, i); ExampleCallPresence presence; GHashTable *parameters; parameters = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); /* we know our own status from the connection; for this example CM, * everyone else's status is assumed to be "available" */ if (contact == base->self_handle) { presence = (self->priv->away ? EXAMPLE_CALL_PRESENCE_AWAY : EXAMPLE_CALL_PRESENCE_AVAILABLE); if (self->priv->presence_message[0] != '\0') g_hash_table_insert (parameters, "message", tp_g_value_slice_new_string (self->priv->presence_message)); } else { presence = EXAMPLE_CALL_PRESENCE_AVAILABLE; } g_hash_table_insert (result, GUINT_TO_POINTER (contact), tp_presence_status_new (presence, parameters)); g_hash_table_unref (parameters); } return result; } static gboolean set_own_status (GObject *object, const TpPresenceStatus *status, GError **error) { ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (object); TpBaseConnection *base = TP_BASE_CONNECTION (object); GHashTable *presences; const gchar *message = ""; if (status->optional_arguments != NULL) { GValue *v = g_hash_table_lookup (status->optional_arguments, "message"); if (v != NULL && G_VALUE_HOLDS_STRING (v)) { message = g_value_get_string (v); if (message == NULL) message = ""; } } if (status->index == EXAMPLE_CALL_PRESENCE_AWAY) { if (self->priv->away && !tp_strdiff (message, self->priv->presence_message)) return TRUE; self->priv->away = TRUE; } else { if (!self->priv->away && !tp_strdiff (message, self->priv->presence_message)) return TRUE; self->priv->away = FALSE; } g_free (self->priv->presence_message); self->priv->presence_message = g_strdup (message); presences = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); g_hash_table_insert (presences, GUINT_TO_POINTER (base->self_handle), (gpointer) status); tp_presence_mixin_emit_presence_update (object, presences); g_hash_table_unref (presences); if (!self->priv->away) { g_signal_emit (self, signals[SIGNAL_AVAILABLE], 0, message); } return TRUE; } static const TpPresenceStatusOptionalArgumentSpec can_have_message[] = { { "message", "s", NULL, NULL }, { NULL } }; /* Must be kept in sync with ExampleCallPresence enum in header */ static const TpPresenceStatusSpec presence_statuses[] = { { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, NULL }, { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, NULL }, { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, NULL }, { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, can_have_message }, { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, can_have_message }, { NULL } }; static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_CONTACTS, TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, NULL }; const gchar * const * example_call_connection_get_possible_interfaces (void) { /* in this example CM we don't have any extra interfaces that are sometimes, * but not always, present */ return interfaces_always_present; } static void example_call_connection_class_init ( ExampleCallConnectionClass *klass) { TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; object_class->get_property = get_property; object_class->set_property = set_property; object_class->constructed = constructed; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (ExampleCallConnectionPrivate)); base_class->create_handle_repos = create_handle_repos; base_class->get_unique_connection_name = get_unique_connection_name; base_class->create_channel_managers = create_channel_managers; base_class->start_connecting = start_connecting; base_class->shut_down = shut_down; base_class->interfaces_always_present = interfaces_always_present; param_spec = g_param_spec_string ("account", "Account name", "The username of this user", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); /* Used in the call manager, to simulate an incoming call when we become * available */ signals[SIGNAL_AVAILABLE] = g_signal_new ("available", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); tp_contacts_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleCallConnectionClass, contacts_mixin)); tp_presence_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleCallConnectionClass, presence_mixin), status_available, get_contact_statuses, set_own_status, presence_statuses); tp_presence_mixin_simple_presence_init_dbus_properties (object_class); } telepathy-qt-0.9.6~git1/tests/lib/glib/call/protocol.h0000664000175000017500000000354412470405660020530 0ustar jrjr/* * protocol.h - header for an example Protocol * Copyright © 2007-2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef EXAMPLE_CALL_PROTOCOL_H #define EXAMPLE_CALL_PROTOCOL_H #include #include G_BEGIN_DECLS typedef struct _ExampleCallProtocol ExampleCallProtocol; typedef struct _ExampleCallProtocolPrivate ExampleCallProtocolPrivate; typedef struct _ExampleCallProtocolClass ExampleCallProtocolClass; typedef struct _ExampleCallProtocolClassPrivate ExampleCallProtocolClassPrivate; struct _ExampleCallProtocolClass { TpBaseProtocolClass parent_class; ExampleCallProtocolClassPrivate *priv; }; struct _ExampleCallProtocol { TpBaseProtocol parent; ExampleCallProtocolPrivate *priv; }; GType example_call_protocol_get_type (void); #define EXAMPLE_TYPE_CALL_PROTOCOL \ (example_call_protocol_get_type ()) #define EXAMPLE_CALL_PROTOCOL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ EXAMPLE_TYPE_CALL_PROTOCOL, \ ExampleCallProtocol)) #define EXAMPLE_CALL_PROTOCOL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ EXAMPLE_TYPE_CALL_PROTOCOL, \ ExampleCallProtocolClass)) #define EXAMPLE_IS_CALL_PROTOCOL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ EXAMPLE_TYPE_CALL_PROTOCOL)) #define EXAMPLE_IS_CALL_PROTOCOL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ EXAMPLE_TYPE_CALL_PROTOCOL)) #define EXAMPLE_CALL_PROTOCOL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ EXAMPLE_TYPE_CALL_PROTOCOL, \ ExampleCallProtocolClass)) gboolean example_call_protocol_check_contact_id (const gchar *id, gchar **normal, GError **error); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/call/call-channel.c0000664000175000017500000006221112470405660021177 0ustar jrjr/* * call-channel.c - an example 1-1 audio/video call * * For simplicity, this channel emulates a device with its own * audio/video user interface, like a video-equipped form of the phones * manipulated by telepathy-snom or gnome-phone-manager. * * As a result, this channel has the HardwareStreaming flag, its contents * and streams do not have the Media interface, and clients should not attempt * to do their own streaming using telepathy-farsight, telepathy-stream-engine * or maemo-stream-engine. * * In practice, nearly all connection managers do not have HardwareStreaming, * and do have the Media interface on their contents/streams. Usage for those * CMs is the same, except that whichever client is the primary handler * for the channel should also hand the channel over to telepathy-farsight or * telepathy-stream-engine to implement the actual streaming. * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "call-channel.h" #include #include #include #include #include #include #include #include "call-content.h" #include "call-stream.h" static void hold_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (ExampleCallChannel, example_call_channel, TP_TYPE_BASE_MEDIA_CALL_CHANNEL, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_HOLD, hold_iface_init)) enum { PROP_SIMULATION_DELAY = 1, N_PROPS }; struct _ExampleCallChannelPrivate { guint simulation_delay; TpBaseConnection *conn; TpHandle handle; gboolean locally_requested; guint hold_state; guint hold_state_reason; guint next_stream_id; gboolean closed; }; static const char * example_call_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_HOLD, NULL }; /* In practice you need one for audio, plus one per video (e.g. a * presentation might have separate video contents for the slides * and a camera pointed at the presenter), so having more than three * would be highly unusual */ #define MAX_CONTENTS_PER_CALL 100 G_GNUC_NULL_TERMINATED static void example_call_channel_set_state (ExampleCallChannel *self, TpCallState state, TpCallFlags flags, TpHandle actor, TpCallStateChangeReason reason, const gchar *error, ...) { /* FIXME: TpBaseCallChannel is not that flexible */ tp_base_call_channel_set_state ((TpBaseCallChannel *) self, state, actor, reason, error, ""); } static void example_call_channel_init (ExampleCallChannel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALL_CHANNEL, ExampleCallChannelPrivate); self->priv->next_stream_id = 1; self->priv->hold_state = TP_LOCAL_HOLD_STATE_UNHELD; self->priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_NONE; } static ExampleCallContent *example_call_channel_add_content ( ExampleCallChannel *self, TpMediaStreamType media_type, gboolean locally_requested, gboolean initial, const gchar *requested_name, GError **error); static void example_call_channel_initiate_outgoing (ExampleCallChannel *self); static void constructed (GObject *object) { void (*chain_up) (GObject *) = ((GObjectClass *) example_call_channel_parent_class)->constructed; ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (object); TpBaseChannel *base = (TpBaseChannel *) self; TpBaseCallChannel *call = (TpBaseCallChannel *) self; if (chain_up != NULL) chain_up (object); self->priv->handle = tp_base_channel_get_target_handle (base); self->priv->locally_requested = tp_base_channel_is_requested (base); self->priv->conn = tp_base_channel_get_connection (base); tp_base_call_channel_update_member_flags (call, self->priv->handle, 0, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); if (self->priv->locally_requested) { /* Nobody is locally pending. The remote peer will turn up in * remote-pending state when we actually contact them, which is done * in example_call_channel_initiate_outgoing. */ example_call_channel_set_state (self, TP_CALL_STATE_PENDING_INITIATOR, 0, 0, TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, "", NULL); } else { /* This is an incoming call, so the self-handle is locally * pending, to indicate that we need to answer. */ example_call_channel_set_state (self, TP_CALL_STATE_INITIALISED, 0, self->priv->handle, TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, "", NULL); } /* FIXME: should respect initial names */ if (tp_base_call_channel_has_initial_audio (call, NULL)) { g_message ("Channel initially has an audio stream"); example_call_channel_add_content (self, TP_MEDIA_STREAM_TYPE_AUDIO, self->priv->locally_requested, TRUE, NULL, NULL); } if (tp_base_call_channel_has_initial_video (call, NULL)) { g_message ("Channel initially has a video stream"); example_call_channel_add_content (self, TP_MEDIA_STREAM_TYPE_VIDEO, self->priv->locally_requested, TRUE, NULL, NULL); } tp_base_channel_register (base); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (object); switch (property_id) { case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (object); switch (property_id) { case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void example_call_channel_terminate (ExampleCallChannel *self, TpHandle actor, TpChannelGroupChangeReason reason, TpCallStateChangeReason call_reason, const gchar *error_name) { TpBaseCallChannel *base = (TpBaseCallChannel *) self; TpCallState call_state = tp_base_call_channel_get_state (base); if (call_state != TP_CALL_STATE_ENDED) { GList *contents; example_call_channel_set_state (self, TP_CALL_STATE_ENDED, 0, actor, call_reason, error_name, NULL); /* FIXME: fd.o #24936 #c20: it's unclear in the spec whether we should * remove peers on call termination or not. For now this example does. */ tp_base_call_channel_remove_member (base, self->priv->handle, actor, call_reason, error_name, NULL); if (actor == tp_base_connection_get_self_handle (self->priv->conn)) { const gchar *send_reason; /* In a real protocol these would be some sort of real protocol * construct, like an XMPP error stanza or a SIP error code */ switch (reason) { case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY: send_reason = ""; break; case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER: send_reason = ""; break; default: send_reason = ""; } g_message ("SIGNALLING: send: Terminating call: %s", send_reason); } /* terminate all streams: to avoid modifying the hash table (in the * streams-removed handler) while iterating over it, we have to copy the * keys and iterate over those */ contents = tp_base_call_channel_get_contents (base); contents = g_list_copy (contents); for (; contents != NULL; contents = g_list_delete_link (contents, contents)) { example_call_content_remove_stream (contents->data); tp_base_call_channel_remove_content (base, contents->data, 0, call_reason, error_name, ""); } } } static void dispose (GObject *object) { ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (object); /* the manager is meant to hold a ref to us until we've closed */ g_assert (self->priv->closed); ((GObjectClass *) example_call_channel_parent_class)->dispose (object); } static void close_channel (TpBaseChannel *base) { ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (base); example_call_channel_terminate (self, tp_base_connection_get_self_handle (self->priv->conn), TP_CHANNEL_GROUP_CHANGE_REASON_NONE, TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, ""); self->priv->closed = TRUE; tp_base_channel_destroyed (base); } static void call_accept (TpBaseCallChannel *self); static TpBaseCallContent * call_add_content (TpBaseCallChannel *self, const gchar *name, TpMediaStreamType media, TpMediaStreamDirection initial_direction, GError **error); static void call_hangup (TpBaseCallChannel *self, guint reason, const gchar *detailed_reason, const gchar *message); static void example_call_channel_class_init (ExampleCallChannelClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass); TpBaseCallChannelClass *call_class = (TpBaseCallChannelClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (ExampleCallChannelPrivate)); call_class->accept = call_accept; call_class->add_content = call_add_content; call_class->hangup = call_hangup; base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; base_class->interfaces = example_call_channel_interfaces; base_class->close = close_channel; object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); } static gboolean simulate_contact_ended_cb (gpointer p) { ExampleCallChannel *self = p; TpBaseCallChannel *base = (TpBaseCallChannel *) self; TpCallState call_state = tp_base_call_channel_get_state (base); /* if the call has been cancelled while we were waiting for the * contact to do so, do nothing! */ if (call_state == TP_CALL_STATE_ENDED) return FALSE; g_message ("SIGNALLING: receive: call terminated: "); example_call_channel_terminate (self, self->priv->handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE, TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, ""); return FALSE; } static gboolean simulate_contact_answered_cb (gpointer p) { ExampleCallChannel *self = p; TpBaseCallChannel *base = (TpBaseCallChannel *) self; TpCallState call_state = tp_base_call_channel_get_state (base); GList *contents; TpHandleRepoIface *contact_repo; const gchar *peer; /* if the call has been cancelled while we were waiting for the * contact to answer, do nothing! */ if (call_state == TP_CALL_STATE_ENDED) return FALSE; /* otherwise, we're waiting for a response from the contact, which now * arrives */ g_assert_cmpuint (call_state, ==, TP_CALL_STATE_INITIALISED); g_message ("SIGNALLING: receive: contact answered our call"); tp_base_call_channel_remote_accept (base); contents = tp_base_call_channel_get_contents (base); for (; contents != NULL; contents = contents->next) { ExampleCallStream *stream = example_call_content_get_stream (contents->data); if (stream == NULL) continue; /* remote contact accepts our proposed stream direction */ example_call_stream_simulate_contact_agreed_to_send (stream); } contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); peer = tp_handle_inspect (contact_repo, self->priv->handle); /* If the contact's ID contains the magic string "(terminate)", simulate * them hanging up after a moment. */ if (strstr (peer, "(terminate)") != NULL) { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_contact_ended_cb, g_object_ref (self), g_object_unref); } return FALSE; } static gboolean simulate_contact_busy_cb (gpointer p) { ExampleCallChannel *self = p; TpBaseCallChannel *base = (TpBaseCallChannel *) self; TpCallState call_state = tp_base_call_channel_get_state (base); /* if the call has been cancelled while we were waiting for the * contact to answer, do nothing */ if (call_state == TP_CALL_STATE_ENDED) return FALSE; /* otherwise, we're waiting for a response from the contact, which now * arrives */ g_assert_cmpuint (call_state, ==, TP_CALL_STATE_INITIALISED); g_message ("SIGNALLING: receive: call terminated: "); example_call_channel_terminate (self, self->priv->handle, TP_CHANNEL_GROUP_CHANGE_REASON_BUSY, TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, TP_ERROR_STR_BUSY); return FALSE; } static ExampleCallContent * example_call_channel_add_content (ExampleCallChannel *self, TpMediaStreamType media_type, gboolean locally_requested, gboolean initial, const gchar *requested_name, GError **error) { TpBaseCallChannel *base = (TpBaseCallChannel *) self; GList *contents; const gchar *type_str; TpHandle creator = self->priv->handle; TpCallContentDisposition disposition = TP_CALL_CONTENT_DISPOSITION_NONE; guint id = self->priv->next_stream_id++; ExampleCallContent *content; ExampleCallStream *stream; gchar *name; gchar *path; guint i; /* an arbitrary limit much less than 2**32 means we don't use ridiculous * amounts of memory, and also means @i can't wrap around when we use it to * uniquify content names. */ contents = tp_base_call_channel_get_contents (base); if (g_list_length (contents) > MAX_CONTENTS_PER_CALL) { g_set_error (error, TP_ERROR, TP_ERROR_PERMISSION_DENIED, "What are you doing with all those contents anyway?!"); return NULL; } type_str = (media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video"); if (tp_str_empty (requested_name)) { requested_name = type_str; } for (i = 0; ; i++) { GList *l; if (i == 0) name = g_strdup (requested_name); else name = g_strdup_printf ("%s (%u)", requested_name, i); for (l = contents; l != NULL; l = l->next) { if (!tp_strdiff (tp_base_call_content_get_name (l->data), name)) break; } if (l == NULL) { /* this name hasn't been used - good enough */ break; } g_free (name); name = NULL; } if (initial) disposition = TP_CALL_CONTENT_DISPOSITION_INITIAL; if (locally_requested) { g_message ("SIGNALLING: send: new %s stream %s", type_str, name); creator = self->priv->conn->self_handle; } path = g_strdup_printf ("%s/Content%u", tp_base_channel_get_object_path ((TpBaseChannel *) self), id); content = g_object_new (EXAMPLE_TYPE_CALL_CONTENT, "connection", self->priv->conn, "creator", creator, "media-type", media_type, "name", name, "disposition", disposition, "object-path", path, NULL); tp_base_call_channel_add_content (base, (TpBaseCallContent *) content); g_free (path); path = g_strdup_printf ("%s/Stream%u", tp_base_channel_get_object_path ((TpBaseChannel *) self), id); stream = g_object_new (EXAMPLE_TYPE_CALL_STREAM, "connection", self->priv->conn, "handle", self->priv->handle, "locally-requested", locally_requested, "object-path", path, NULL); example_call_content_add_stream (content, stream); g_free (path); g_object_unref (content); g_object_unref (stream); return content; } static gboolean simulate_contact_ringing_cb (gpointer p) { ExampleCallChannel *self = p; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); const gchar *peer; tp_base_call_channel_update_member_flags ((TpBaseCallChannel *) self, self->priv->handle, TP_CALL_MEMBER_FLAG_RINGING, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); /* In this example there is no real contact, so just simulate them * answering after a short time - unless the contact's name * contains "(no answer)" or "(busy)" */ peer = tp_handle_inspect (contact_repo, self->priv->handle); if (strstr (peer, "(busy)") != NULL) { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_contact_busy_cb, g_object_ref (self), g_object_unref); } else if (strstr (peer, "(no answer)") != NULL) { /* do nothing - the call just rings forever */ } else { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_contact_answered_cb, g_object_ref (self), g_object_unref); } return FALSE; } static void example_call_channel_initiate_outgoing (ExampleCallChannel *self) { g_message ("SIGNALLING: send: new streamed media call"); example_call_channel_set_state (self, TP_CALL_STATE_INITIALISED, 0, tp_base_connection_get_self_handle (self->priv->conn), TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, "", NULL); /* After a moment, we're sent an informational message saying it's ringing */ g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_contact_ringing_cb, g_object_ref (self), g_object_unref); } static void accept_incoming_call (ExampleCallChannel *self) { TpBaseCallChannel *base = (TpBaseCallChannel *) self; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); GList *contents; g_message ("SIGNALLING: send: Accepting incoming call from %s", tp_handle_inspect (contact_repo, self->priv->handle)); example_call_channel_set_state (self, TP_CALL_STATE_ACCEPTED, 0, tp_base_connection_get_self_handle (self->priv->conn), TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, "", NULL); contents = tp_base_call_channel_get_contents (base); for (; contents != NULL; contents = contents->next) { ExampleCallStream *stream = example_call_content_get_stream (contents->data); guint disposition = tp_base_call_content_get_disposition (contents->data); if (stream == NULL || disposition != TP_CALL_CONTENT_DISPOSITION_INITIAL) continue; /* we accept the proposed stream direction */ example_call_stream_accept_proposed_direction (stream); } } static void call_accept (TpBaseCallChannel *base) { ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (base); if (self->priv->locally_requested) { /* Take the contents we've already added, and make them happen */ example_call_channel_initiate_outgoing (self); } else { accept_incoming_call (self); } } static void call_hangup (TpBaseCallChannel *base, guint reason, const gchar *detailed_reason, const gchar *message G_GNUC_UNUSED) { ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (base); example_call_channel_terminate (self, tp_base_connection_get_self_handle (self->priv->conn), TP_CHANNEL_GROUP_CHANGE_REASON_NONE, reason, detailed_reason); } static TpBaseCallContent * call_add_content (TpBaseCallChannel *base, const gchar *content_name, guint content_type, TpMediaStreamDirection initial_direction, GError **error) { ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (base); return (TpBaseCallContent *) example_call_channel_add_content (self, content_type, TRUE, FALSE, content_name, error); } static gboolean simulate_hold (gpointer p) { ExampleCallChannel *self = p; TpBaseCallChannel *base = (TpBaseCallChannel *) self; TpCallState call_state = tp_base_call_channel_get_state (base); TpCallFlags call_flags = 0; /* FIXME */ self->priv->hold_state = TP_LOCAL_HOLD_STATE_HELD; g_message ("SIGNALLING: hold state changed to held"); tp_svc_channel_interface_hold_emit_hold_state_changed (self, self->priv->hold_state, self->priv->hold_state_reason); example_call_channel_set_state (self, call_state, call_flags | TP_CALL_FLAG_LOCALLY_HELD, tp_base_connection_get_self_handle (self->priv->conn), TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, "", NULL); return FALSE; } static gboolean simulate_unhold (gpointer p) { ExampleCallChannel *self = p; TpBaseCallChannel *base = (TpBaseCallChannel *) self; TpCallState call_state = tp_base_call_channel_get_state (base); TpCallFlags call_flags = 0; /* FIXME */ self->priv->hold_state = TP_LOCAL_HOLD_STATE_UNHELD; g_message ("SIGNALLING: hold state changed to unheld"); tp_svc_channel_interface_hold_emit_hold_state_changed (self, self->priv->hold_state, self->priv->hold_state_reason); example_call_channel_set_state (self, call_state, call_flags & ~TP_CALL_FLAG_LOCALLY_HELD, tp_base_connection_get_self_handle (self->priv->conn), TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED, "", NULL); return FALSE; } static gboolean simulate_inability_to_unhold (gpointer p) { ExampleCallChannel *self = p; self->priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_HOLD; g_message ("SIGNALLING: unable to unhold - hold state changed to " "pending hold"); tp_svc_channel_interface_hold_emit_hold_state_changed (self, self->priv->hold_state, self->priv->hold_state_reason); /* hold again */ g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_hold, g_object_ref (self), g_object_unref); return FALSE; } static void hold_get_hold_state (TpSvcChannelInterfaceHold *iface, DBusGMethodInvocation *context) { ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (iface); tp_svc_channel_interface_hold_return_from_get_hold_state (context, self->priv->hold_state, self->priv->hold_state_reason); } static void hold_request_hold (TpSvcChannelInterfaceHold *iface, gboolean hold, DBusGMethodInvocation *context) { ExampleCallChannel *self = EXAMPLE_CALL_CHANNEL (iface); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; const gchar *peer; GSourceFunc callback; if ((hold && self->priv->hold_state == TP_LOCAL_HOLD_STATE_HELD) || (!hold && self->priv->hold_state == TP_LOCAL_HOLD_STATE_UNHELD)) { tp_svc_channel_interface_hold_return_from_request_hold (context); return; } peer = tp_handle_inspect (contact_repo, self->priv->handle); if (!hold && strstr (peer, "(no unhold)") != NULL) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "unable to unhold"); goto error; } self->priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_REQUESTED; if (hold) { self->priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_HOLD; callback = simulate_hold; } else { self->priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_UNHOLD; peer = tp_handle_inspect (contact_repo, self->priv->handle); if (strstr (peer, "(inability to unhold)") != NULL) { callback = simulate_inability_to_unhold; } else { callback = simulate_unhold; } } g_message ("SIGNALLING: hold state changed to pending %s", (hold ? "hold" : "unhold")); tp_svc_channel_interface_hold_emit_hold_state_changed (iface, self->priv->hold_state, self->priv->hold_state_reason); /* No need to change the call flags - we never change the actual hold state * here, only the pending hold state */ g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, callback, g_object_ref (self), g_object_unref); tp_svc_channel_interface_hold_return_from_request_hold (context); return; error: dbus_g_method_return_error (context, error); g_error_free (error); } void hold_iface_init (gpointer iface, gpointer data) { TpSvcChannelInterfaceHoldClass *klass = iface; #define IMPLEMENT(x) \ tp_svc_channel_interface_hold_implement_##x (klass, hold_##x) IMPLEMENT (get_hold_state); IMPLEMENT (request_hold); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/call/call-content.c0000664000175000017500000000553312470405660021245 0ustar jrjr/* * call-content.c - a content in a call. * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "call-content.h" #include #include #include G_DEFINE_TYPE (ExampleCallContent, example_call_content, TP_TYPE_BASE_MEDIA_CALL_CONTENT) struct _ExampleCallContentPrivate { ExampleCallStream *stream; }; static void example_call_content_init (ExampleCallContent *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALL_CONTENT, ExampleCallContentPrivate); } static void dispose (GObject *object) { ExampleCallContent *self = EXAMPLE_CALL_CONTENT (object); g_clear_object (&self->priv->stream); ((GObjectClass *) example_call_content_parent_class)->dispose (object); } static void example_call_content_class_init (ExampleCallContentClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; g_type_class_add_private (klass, sizeof (ExampleCallContentPrivate)); object_class->dispose = dispose; } ExampleCallStream * example_call_content_get_stream (ExampleCallContent *self) { g_return_val_if_fail (EXAMPLE_IS_CALL_CONTENT (self), NULL); return self->priv->stream; } void example_call_content_add_stream (ExampleCallContent *self, ExampleCallStream *stream) { g_return_if_fail (EXAMPLE_IS_CALL_CONTENT (self)); g_return_if_fail (EXAMPLE_IS_CALL_STREAM (stream)); g_return_if_fail (self->priv->stream == NULL); self->priv->stream = g_object_ref (stream); tp_base_call_content_add_stream ((TpBaseCallContent *) self, (TpBaseCallStream *) stream); } void example_call_content_remove_stream (ExampleCallContent *self) { TpBaseCallStream *stream; g_return_if_fail (EXAMPLE_IS_CALL_CONTENT (self)); g_return_if_fail (self->priv->stream != NULL); stream = (TpBaseCallStream *) self->priv->stream; self->priv->stream = NULL; tp_base_call_content_remove_stream ((TpBaseCallContent *) self, stream, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); g_object_unref (stream); } telepathy-qt-0.9.6~git1/tests/lib/glib/call/call-stream.c0000664000175000017500000003603612470405660021070 0ustar jrjr/* * call-stream.c - a stream in a call. * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "call-stream.h" #include #include #include G_DEFINE_TYPE (ExampleCallStream, example_call_stream, TP_TYPE_BASE_MEDIA_CALL_STREAM) enum { PROP_SIMULATION_DELAY = 1, PROP_LOCALLY_REQUESTED, PROP_HANDLE, N_PROPS }; struct _ExampleCallStreamPrivate { guint simulation_delay; gboolean locally_requested; TpHandle handle; guint agreed_delay_id; }; static void example_call_stream_init (ExampleCallStream *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALL_STREAM, ExampleCallStreamPrivate); } static void example_call_stream_receive_direction_request ( ExampleCallStream *self, gboolean local_send, gboolean remote_send); static void example_call_stream_change_direction (ExampleCallStream *self, gboolean want_to_send, gboolean want_to_receive); static void constructed (GObject *object) { ExampleCallStream *self = EXAMPLE_CALL_STREAM (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_call_stream_parent_class)->constructed; static guint count = 0; TpBaseConnection *conn; TpDBusDaemon *dbus; gchar *object_path; TpCallStreamEndpoint *endpoint; if (chain_up != NULL) chain_up (object); conn = tp_base_call_stream_get_connection ((TpBaseCallStream *) self); dbus = tp_base_connection_get_dbus_daemon (conn); object_path = g_strdup_printf ("%s/Endpoint%d", tp_base_call_stream_get_object_path ((TpBaseCallStream *) self), count++); endpoint = tp_call_stream_endpoint_new (dbus, object_path, TP_STREAM_TRANSPORT_TYPE_RAW_UDP, FALSE); tp_base_media_call_stream_add_endpoint ((TpBaseMediaCallStream *) self, endpoint); if (self->priv->locally_requested) { example_call_stream_change_direction (self, TRUE, TRUE); } else { example_call_stream_receive_direction_request (self, TRUE, TRUE); } g_object_unref (endpoint); g_free (object_path); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleCallStream *self = EXAMPLE_CALL_STREAM (object); switch (property_id) { case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; case PROP_LOCALLY_REQUESTED: g_value_set_boolean (value, self->priv->locally_requested); break; case PROP_HANDLE: g_value_set_uint (value, self->priv->handle); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleCallStream *self = EXAMPLE_CALL_STREAM (object); switch (property_id) { case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; case PROP_LOCALLY_REQUESTED: self->priv->locally_requested = g_value_get_boolean (value); break; case PROP_HANDLE: self->priv->handle = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static gboolean stream_request_receiving (TpBaseCallStream *base, TpHandle contact, gboolean receive, GError **error); static gboolean stream_set_sending (TpBaseCallStream *base, gboolean sending, GError **error); static void finalize (GObject *object) { ExampleCallStream *self = EXAMPLE_CALL_STREAM (object); if (self->priv->agreed_delay_id != 0) g_source_remove (self->priv->agreed_delay_id); G_OBJECT_CLASS (example_call_stream_parent_class)->finalize (object); } static void example_call_stream_class_init (ExampleCallStreamClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseCallStreamClass *stream_class = (TpBaseCallStreamClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (ExampleCallStreamPrivate)); object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->finalize = finalize; stream_class->request_receiving = stream_request_receiving; stream_class->set_sending = stream_set_sending; param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); param_spec = g_param_spec_boolean ("locally-requested", "Locally requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_LOCALLY_REQUESTED, param_spec); param_spec = g_param_spec_uint ("handle", "Peer's TpHandle", "The handle with which this stream communicates or 0 if not applicable", 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_HANDLE, param_spec); } void example_call_stream_accept_proposed_direction (ExampleCallStream *self) { TpBaseCallStream *base = (TpBaseCallStream *) self; TpSendingState state = tp_base_call_stream_get_local_sending_state (base); if (state != TP_SENDING_STATE_PENDING_SEND) return; tp_base_call_stream_update_local_sending_state (base, TP_SENDING_STATE_SENDING, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } void example_call_stream_simulate_contact_agreed_to_send (ExampleCallStream *self) { TpBaseCallStream *base = (TpBaseCallStream *) self; TpSendingState state = tp_base_call_stream_get_remote_sending_state (base, self->priv->handle); if (state != TP_SENDING_STATE_PENDING_SEND) g_message ("%s: SIGNALLING: Sending to server: OK, I'll send you media", tp_base_call_stream_get_object_path (base)); tp_base_call_stream_update_remote_sending_state ((TpBaseCallStream *) self, self->priv->handle, TP_SENDING_STATE_SENDING, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } static gboolean simulate_contact_agreed_to_send_cb (gpointer p) { example_call_stream_simulate_contact_agreed_to_send (p); return FALSE; } static void example_call_stream_change_direction (ExampleCallStream *self, gboolean want_to_send, gboolean want_to_receive) { TpBaseCallStream *base = (TpBaseCallStream *) self; TpSendingState local_sending_state = tp_base_call_stream_get_local_sending_state (base); TpSendingState remote_sending_state = tp_base_call_stream_get_remote_sending_state (base, self->priv->handle); if (want_to_send) { if (local_sending_state != TP_SENDING_STATE_SENDING) { if (local_sending_state == TP_SENDING_STATE_PENDING_SEND) { g_message ("%s: SIGNALLING: send: I will now send you media", tp_base_call_stream_get_object_path (base)); } g_message ("%s: MEDIA: sending media to peer", tp_base_call_stream_get_object_path (base)); tp_base_call_stream_update_local_sending_state (base, TP_SENDING_STATE_SENDING, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } } else { if (local_sending_state == TP_SENDING_STATE_SENDING) { g_message ("%s: SIGNALLING: send: I will no longer send you media", tp_base_call_stream_get_object_path (base)); g_message ("%s: MEDIA: no longer sending media to peer", tp_base_call_stream_get_object_path (base)); tp_base_call_stream_update_local_sending_state (base, TP_SENDING_STATE_NONE, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } else if (local_sending_state == TP_SENDING_STATE_PENDING_SEND) { g_message ("%s: SIGNALLING: send: refusing to send you media", tp_base_call_stream_get_object_path (base)); tp_base_call_stream_update_local_sending_state (base, TP_SENDING_STATE_NONE, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } } if (want_to_receive) { if (remote_sending_state == TP_SENDING_STATE_NONE) { g_message ("%s: SIGNALLING: send: send me media, please?", tp_base_call_stream_get_object_path (base)); tp_base_call_stream_update_remote_sending_state ( (TpBaseCallStream *) self, self->priv->handle, TP_SENDING_STATE_PENDING_SEND, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); if (self->priv->agreed_delay_id == 0) { self->priv->agreed_delay_id = g_timeout_add ( self->priv->simulation_delay, simulate_contact_agreed_to_send_cb, self); } } } else { if (remote_sending_state != TP_SENDING_STATE_NONE) { g_message ("%s: SIGNALLING: send: Please stop sending me media", tp_base_call_stream_get_object_path (base)); g_message ("%s: MEDIA: suppressing output of stream", tp_base_call_stream_get_object_path (base)); tp_base_call_stream_update_remote_sending_state ( (TpBaseCallStream *) self, self->priv->handle, TP_SENDING_STATE_NONE, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } } } /* The remote user wants to change the direction of this stream according * to @local_send and @remote_send. Shall we let him? */ static void example_call_stream_receive_direction_request (ExampleCallStream *self, gboolean local_send, gboolean remote_send) { TpBaseCallStream *base = (TpBaseCallStream *) self; TpSendingState local_sending_state = tp_base_call_stream_get_local_sending_state (base); TpSendingState remote_sending_state = tp_base_call_stream_get_remote_sending_state (base, self->priv->handle); /* In some protocols, streams cannot be neither sending nor receiving, so * if a stream is set to TP_MEDIA_STREAM_DIRECTION_NONE, this is equivalent * to removing it. (This is true in XMPP, for instance.) * * However, for this example we'll emulate a protocol where streams can be * directionless. */ if (local_send) { g_message ("%s: SIGNALLING: send: Please start sending me media", tp_base_call_stream_get_object_path (base)); if (local_sending_state == TP_SENDING_STATE_NONE) { /* ask the user for permission */ tp_base_call_stream_update_local_sending_state (base, TP_SENDING_STATE_PENDING_SEND, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } else { /* nothing to do, we're already sending (or asking the user for * permission to do so) on that stream */ } } else { g_message ("%s: SIGNALLING: receive: Please stop sending me media", tp_base_call_stream_get_object_path (base)); g_message ("%s: SIGNALLING: reply: OK!", tp_base_call_stream_get_object_path (base)); if (local_sending_state == TP_SENDING_STATE_SENDING) { g_message ("%s: MEDIA: no longer sending media to peer", tp_base_call_stream_get_object_path (base)); tp_base_call_stream_update_local_sending_state (base, TP_SENDING_STATE_NONE, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } else if (local_sending_state == TP_SENDING_STATE_PENDING_SEND) { tp_base_call_stream_update_local_sending_state (base, TP_SENDING_STATE_NONE, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } else { /* nothing to do, we're not sending on that stream anyway */ } } if (remote_send) { g_message ("%s: SIGNALLING: receive: I will now send you media", tp_base_call_stream_get_object_path (base)); if (remote_sending_state != TP_SENDING_STATE_SENDING) { tp_base_call_stream_update_remote_sending_state ( (TpBaseCallStream *) self, self->priv->handle, TP_SENDING_STATE_SENDING, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } } else { if (remote_sending_state == TP_SENDING_STATE_PENDING_SEND) { g_message ("%s: SIGNALLING: receive: No, I refuse to send you media", tp_base_call_stream_get_object_path (base)); tp_base_call_stream_update_remote_sending_state ( (TpBaseCallStream *) self, self->priv->handle, TP_SENDING_STATE_NONE, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } else if (remote_sending_state == TP_SENDING_STATE_SENDING) { g_message ("%s: SIGNALLING: receive: I will no longer send media", tp_base_call_stream_get_object_path (base)); tp_base_call_stream_update_remote_sending_state ( (TpBaseCallStream *) self, self->priv->handle, TP_SENDING_STATE_NONE, 0, TP_CALL_STATE_CHANGE_REASON_UNKNOWN, "", ""); } } } static gboolean stream_set_sending (TpBaseCallStream *base, gboolean sending, GError **error) { ExampleCallStream *self = EXAMPLE_CALL_STREAM (base); TpSendingState remote_sending_state = tp_base_call_stream_get_remote_sending_state (base, self->priv->handle); example_call_stream_change_direction (self, sending, (remote_sending_state == TP_SENDING_STATE_SENDING)); return TRUE; } static gboolean stream_request_receiving (TpBaseCallStream *base, TpHandle contact, gboolean receive, GError **error) { ExampleCallStream *self = EXAMPLE_CALL_STREAM (base); TpSendingState local_sending_state = tp_base_call_stream_get_local_sending_state (base); /* This is the only member */ g_assert (contact == self->priv->handle); example_call_stream_change_direction (self, (local_sending_state == TP_SENDING_STATE_SENDING), receive); return TRUE; } telepathy-qt-0.9.6~git1/tests/lib/glib/call/protocol.c0000664000175000017500000001133512470405660020520 0ustar jrjr/* * protocol.c - an example Protocol * * Copyright © 2007-2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "protocol.h" #include #include "call-manager.h" #include "conn.h" G_DEFINE_TYPE (ExampleCallProtocol, example_call_protocol, TP_TYPE_BASE_PROTOCOL) static void example_call_protocol_init ( ExampleCallProtocol *self) { } gboolean example_call_protocol_check_contact_id (const gchar *id, gchar **normal, GError **error) { g_return_val_if_fail (id != NULL, FALSE); if (id[0] == '\0') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "ID must not be empty"); return FALSE; } if (normal != NULL) *normal = g_utf8_normalize (id, -1, G_NORMALIZE_ALL_COMPOSE); return TRUE; } static gboolean account_param_filter (const TpCMParamSpec *paramspec, GValue *value, GError **error) { const gchar *id = g_value_get_string (value); return example_call_protocol_check_contact_id (id, NULL, error); } static const TpCMParamSpec example_call_example_params[] = { { "account", "s", G_TYPE_STRING, TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, NULL, /* no default */ 0, /* unused, formerly struct offset */ account_param_filter, NULL, /* filter data, unused here */ NULL }, /* setter data, now unused */ { "simulation-delay", "u", G_TYPE_UINT, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, GUINT_TO_POINTER (1000), /* default */ 0, /* unused, formerly struct offset */ NULL, /* no filter */ NULL, /* filter data, unused here */ NULL }, /* setter data, now unused */ { NULL } }; static const TpCMParamSpec * get_parameters (TpBaseProtocol *self) { return example_call_example_params; } static TpBaseConnection * new_connection (TpBaseProtocol *protocol, GHashTable *asv, GError **error) { ExampleCallConnection *conn; const gchar *account; guint sim_delay; account = tp_asv_get_string (asv, "account"); /* telepathy-glib checked this for us */ g_assert (account != NULL); sim_delay = tp_asv_get_uint32 (asv, "simulation-delay", NULL); conn = EXAMPLE_CALL_CONNECTION ( g_object_new (EXAMPLE_TYPE_CALL_CONNECTION, "account", account, "protocol", tp_base_protocol_get_name (protocol), "simulation-delay", sim_delay, NULL)); return (TpBaseConnection *) conn; } static gchar * normalize_contact (TpBaseProtocol *self G_GNUC_UNUSED, const gchar *contact, GError **error) { gchar *normal; if (example_call_protocol_check_contact_id (contact, &normal, error)) return normal; else return NULL; } static gchar * identify_account (TpBaseProtocol *self G_GNUC_UNUSED, GHashTable *asv, GError **error) { const gchar *account = tp_asv_get_string (asv, "account"); if (account != NULL) return normalize_contact (self, account, error); g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'account' parameter not given"); return NULL; } static GStrv get_interfaces (TpBaseProtocol *self) { return NULL; } static void get_connection_details (TpBaseProtocol *self G_GNUC_UNUSED, GStrv *connection_interfaces, GType **channel_managers, gchar **icon_name, gchar **english_name, gchar **vcard_field) { if (connection_interfaces != NULL) { *connection_interfaces = g_strdupv ( (GStrv) example_call_connection_get_possible_interfaces ()); } if (channel_managers != NULL) { GType types[] = { EXAMPLE_TYPE_CALL_MANAGER, G_TYPE_INVALID }; *channel_managers = g_memdup (types, sizeof (types)); } if (icon_name != NULL) *icon_name = g_strdup ("face-smile"); if (english_name != NULL) *english_name = g_strdup ("Example with Call channels"); if (vcard_field != NULL) *vcard_field = g_strdup ("x-telepathy-example"); } static void example_call_protocol_class_init ( ExampleCallProtocolClass *klass) { TpBaseProtocolClass *base_class = (TpBaseProtocolClass *) klass; base_class->get_parameters = get_parameters; base_class->new_connection = new_connection; base_class->normalize_contact = normalize_contact; base_class->identify_account = identify_account; base_class->get_interfaces = get_interfaces; base_class->get_connection_details = get_connection_details; } telepathy-qt-0.9.6~git1/tests/lib/glib/call/example_call.manager0000664000175000017500000000240212470405660022470 0ustar jrjr[ConnectionManager] Interfaces= [Protocol example] Interfaces= ConnectionInterfaces=org.freedesktop.Telepathy.Connection.Interface.Requests;org.freedesktop.Telepathy.Connection.Interface.Contacts;org.freedesktop.Telepathy.Connection.Interface.Presence;org.freedesktop.Telepathy.Connection.Interface.SimplePresence; param-account=s required register param-simulation-delay=u default-simulation-delay=1000 RequestableChannelClasses=audio;video; VCardField=x-telepathy-example EnglishName=Example with Call channels Icon=face-smile [audio] org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1 org.freedesktop.Telepathy.Channel.TargetHandleType u=1 org.freedesktop.Telepathy.Channel.Type.Call1.InitialAudio b=1 allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID;org.freedesktop.Telepathy.Channel.Type.Call1.InitialVideo; [video] org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Call1 org.freedesktop.Telepathy.Channel.TargetHandleType u=1 org.freedesktop.Telepathy.Channel.Type.Call1.InitialVideo b=1 allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID;org.freedesktop.Telepathy.Channel.Type.Call1.InitialAudio; telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/0000775000175000017500000000000012470405660020124 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/connection-manager.h0000664000175000017500000000454612470405660024055 0ustar jrjr/* * manager.h - header for an example connection manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER_H__ #define __EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER_H__ #include #include G_BEGIN_DECLS typedef struct _ExampleContactListConnectionManager ExampleContactListConnectionManager; typedef struct _ExampleContactListConnectionManagerClass ExampleContactListConnectionManagerClass; typedef struct _ExampleContactListConnectionManagerPrivate ExampleContactListConnectionManagerPrivate; struct _ExampleContactListConnectionManagerClass { TpBaseConnectionManagerClass parent_class; }; struct _ExampleContactListConnectionManager { TpBaseConnectionManager parent; ExampleContactListConnectionManagerPrivate *priv; }; GType example_contact_list_connection_manager_get_type (void); #define EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER \ (example_contact_list_connection_manager_get_type ()) #define EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER, \ ExampleContactListConnectionManager)) #define EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER, \ ExampleContactListConnectionManagerClass)) #define EXAMPLE_IS_CONTACT_LIST_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER)) #define EXAMPLE_IS_CONTACT_LIST_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER)) #define EXAMPLE_CONTACT_LIST_CONNECTION_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER, \ ExampleContactListConnectionManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/contact-list.h0000664000175000017500000001045712470405660022710 0ustar jrjr/* * Example ContactList channels with handle type LIST or GROUP * * Copyright © 2009 Collabora Ltd. * Copyright © 2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef EXAMPLE_CONTACT_LIST_H #define EXAMPLE_CONTACT_LIST_H #include #include #include G_BEGIN_DECLS typedef struct _ExampleContactListBase ExampleContactListBase; typedef struct _ExampleContactListBaseClass ExampleContactListBaseClass; typedef struct _ExampleContactListBasePrivate ExampleContactListBasePrivate; typedef struct _ExampleContactList ExampleContactList; typedef struct _ExampleContactListClass ExampleContactListClass; typedef struct _ExampleContactListPrivate ExampleContactListPrivate; typedef struct _ExampleContactGroup ExampleContactGroup; typedef struct _ExampleContactGroupClass ExampleContactGroupClass; typedef struct _ExampleContactGroupPrivate ExampleContactGroupPrivate; GType example_contact_list_base_get_type (void); GType example_contact_list_get_type (void); GType example_contact_group_get_type (void); #define EXAMPLE_TYPE_CONTACT_LIST_BASE \ (example_contact_list_base_get_type ()) #define EXAMPLE_CONTACT_LIST_BASE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_CONTACT_LIST_BASE, \ ExampleContactListBase)) #define EXAMPLE_CONTACT_LIST_BASE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_CONTACT_LIST_BASE, \ ExampleContactListBaseClass)) #define EXAMPLE_IS_CONTACT_LIST_BASE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_CONTACT_LIST_BASE)) #define EXAMPLE_IS_CONTACT_LIST_BASE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_CONTACT_LIST_BASE)) #define EXAMPLE_CONTACT_LIST_BASE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CONTACT_LIST_BASE, \ ExampleContactListBaseClass)) #define EXAMPLE_TYPE_CONTACT_LIST \ (example_contact_list_get_type ()) #define EXAMPLE_CONTACT_LIST(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_CONTACT_LIST, \ ExampleContactList)) #define EXAMPLE_CONTACT_LIST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_CONTACT_LIST, \ ExampleContactListClass)) #define EXAMPLE_IS_CONTACT_LIST(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_CONTACT_LIST)) #define EXAMPLE_IS_CONTACT_LIST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_CONTACT_LIST)) #define EXAMPLE_CONTACT_LIST_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CONTACT_LIST, \ ExampleContactListClass)) #define EXAMPLE_TYPE_CONTACT_GROUP \ (example_contact_group_get_type ()) #define EXAMPLE_CONTACT_GROUP(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_CONTACT_GROUP, \ ExampleContactGroup)) #define EXAMPLE_CONTACT_GROUP_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_CONTACT_GROUP, \ ExampleContactGroupClass)) #define EXAMPLE_IS_CONTACT_GROUP(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_CONTACT_GROUP)) #define EXAMPLE_IS_CONTACT_GROUP_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_CONTACT_GROUP)) #define EXAMPLE_CONTACT_GROUP_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CONTACT_GROUP, \ ExampleContactGroupClass)) struct _ExampleContactListBaseClass { GObjectClass parent_class; TpGroupMixinClass group_class; TpDBusPropertiesMixinClass dbus_properties_class; }; struct _ExampleContactListClass { ExampleContactListBaseClass parent_class; }; struct _ExampleContactGroupClass { ExampleContactListBaseClass parent_class; }; struct _ExampleContactListBase { GObject parent; TpGroupMixin group; ExampleContactListBasePrivate *priv; }; struct _ExampleContactList { ExampleContactListBase parent; ExampleContactListPrivate *priv; }; struct _ExampleContactGroup { ExampleContactListBase parent; ExampleContactGroupPrivate *priv; }; G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/contact-list-manager.h0000664000175000017500000000762512470405660024323 0ustar jrjr/* * Example channel manager for contact lists * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_CONTACT_LIST_MANAGER_H__ #define __EXAMPLE_CONTACT_LIST_MANAGER_H__ #include #include #include #include G_BEGIN_DECLS typedef struct _ExampleContactListManager ExampleContactListManager; typedef struct _ExampleContactListManagerClass ExampleContactListManagerClass; typedef struct _ExampleContactListManagerPrivate ExampleContactListManagerPrivate; struct _ExampleContactListManagerClass { GObjectClass parent_class; }; struct _ExampleContactListManager { GObject parent; ExampleContactListManagerPrivate *priv; }; GType example_contact_list_manager_get_type (void); #define EXAMPLE_TYPE_CONTACT_LIST_MANAGER \ (example_contact_list_manager_get_type ()) #define EXAMPLE_CONTACT_LIST_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CONTACT_LIST_MANAGER, \ ExampleContactListManager)) #define EXAMPLE_CONTACT_LIST_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CONTACT_LIST_MANAGER, \ ExampleContactListManagerClass)) #define EXAMPLE_IS_CONTACT_LIST_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CONTACT_LIST_MANAGER)) #define EXAMPLE_IS_CONTACT_LIST_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CONTACT_LIST_MANAGER)) #define EXAMPLE_CONTACT_LIST_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CONTACT_LIST_MANAGER, \ ExampleContactListManagerClass)) gboolean example_contact_list_manager_add_to_group ( ExampleContactListManager *self, GObject *channel, TpHandle group, TpHandle member, const gchar *message, GError **error); gboolean example_contact_list_manager_remove_from_group ( ExampleContactListManager *self, GObject *channel, TpHandle group, TpHandle member, const gchar *message, GError **error); /* elements 1, 2... of this enum must be kept in sync with elements 0, 1... * of the array _contact_lists in contact-list-manager.h */ typedef enum { INVALID_EXAMPLE_CONTACT_LIST, EXAMPLE_CONTACT_LIST_SUBSCRIBE = 1, EXAMPLE_CONTACT_LIST_PUBLISH, EXAMPLE_CONTACT_LIST_STORED, EXAMPLE_CONTACT_LIST_DENY, NUM_EXAMPLE_CONTACT_LISTS } ExampleContactListHandle; /* this enum must be kept in sync with the array _statuses in * contact-list-manager.c */ typedef enum { EXAMPLE_CONTACT_LIST_PRESENCE_OFFLINE = 0, EXAMPLE_CONTACT_LIST_PRESENCE_UNKNOWN, EXAMPLE_CONTACT_LIST_PRESENCE_ERROR, EXAMPLE_CONTACT_LIST_PRESENCE_AWAY, EXAMPLE_CONTACT_LIST_PRESENCE_AVAILABLE } ExampleContactListPresence; const TpPresenceStatusSpec *example_contact_list_presence_statuses ( void); gboolean example_contact_list_manager_add_to_list ( ExampleContactListManager *self, GObject *channel, ExampleContactListHandle list, TpHandle member, const gchar *message, GError **error); gboolean example_contact_list_manager_remove_from_list ( ExampleContactListManager *self, GObject *channel, ExampleContactListHandle list, TpHandle member, const gchar *message, GError **error); const gchar **example_contact_lists (void); ExampleContactListPresence example_contact_list_manager_get_presence ( ExampleContactListManager *self, TpHandle contact); const gchar *example_contact_list_manager_get_alias ( ExampleContactListManager *self, TpHandle contact); void example_contact_list_manager_set_alias ( ExampleContactListManager *self, TpHandle contact, const gchar *alias); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/conn.h0000664000175000017500000000450012470405660021231 0ustar jrjr/* * conn.h - header for an example connection * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_CONTACT_LIST_CONN_H__ #define __EXAMPLE_CONTACT_LIST_CONN_H__ #include #include #include #include G_BEGIN_DECLS typedef struct _ExampleContactListConnection ExampleContactListConnection; typedef struct _ExampleContactListConnectionClass ExampleContactListConnectionClass; typedef struct _ExampleContactListConnectionPrivate ExampleContactListConnectionPrivate; struct _ExampleContactListConnectionClass { TpBaseConnectionClass parent_class; TpPresenceMixinClass presence_mixin; TpContactsMixinClass contacts_mixin; }; struct _ExampleContactListConnection { TpBaseConnection parent; TpPresenceMixin presence_mixin; TpContactsMixin contacts_mixin; ExampleContactListConnectionPrivate *priv; }; GType example_contact_list_connection_get_type (void); #define EXAMPLE_TYPE_CONTACT_LIST_CONNECTION \ (example_contact_list_connection_get_type ()) #define EXAMPLE_CONTACT_LIST_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, \ ExampleContactListConnection)) #define EXAMPLE_CONTACT_LIST_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, \ ExampleContactListConnectionClass)) #define EXAMPLE_IS_CONTACT_LIST_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION)) #define EXAMPLE_IS_CONTACT_LIST_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION)) #define EXAMPLE_CONTACT_LIST_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, \ ExampleContactListConnectionClass)) gchar *example_contact_list_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/CMakeLists.txt0000664000175000017500000000106112470405660022662 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) set(example_cm_contactlist_SRCS conn.c conn.h connection-manager.c connection-manager.h contact-list.c contact-list.h contact-list-manager.c contact-list-manager.h) add_library(example-cm-contactlist STATIC ${example_cm_contactlist_SRCS}) target_link_libraries(example-cm-contactlist ${TPGLIB_LIBRARIES}) tpqt_generate_manager_file(${CMAKE_CURRENT_SOURCE_DIR}/manager-file.py example_contact_list.manager connection-manager.c) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/manager-file.py0000664000175000017500000000116212470405660023025 0ustar jrjr# Input for tools/manager-file.py MANAGER = 'example_contact_list' PARAMS = { 'example' : { 'account': { 'dtype': 's', 'flags': 'required register', 'filter': 'account_param_filter', # 'filter_data': 'NULL', # 'default': ..., # 'struct_field': '...', # 'setter_data': 'NULL', }, 'simulation-delay': { 'dtype': 'u', 'default': 1000, }, }, } STRUCTS = { 'example': 'ExampleParams' } telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/contact-list.c0000664000175000017500000004671012470405660022704 0ustar jrjr/* * An example ContactList channel with handle type LIST or GROUP * * Copyright © 2009 Collabora Ltd. * Copyright © 2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "contact-list.h" #include #include #include #include #include "contact-list-manager.h" static void channel_iface_init (gpointer iface, gpointer data); static void list_channel_iface_init (gpointer iface, gpointer data); static void group_channel_iface_init (gpointer iface, gpointer data); /* Abstract base class */ G_DEFINE_TYPE_WITH_CODE (ExampleContactListBase, example_contact_list_base, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_CONTACT_LIST, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, tp_group_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)) /* Subclass for handle type LIST */ G_DEFINE_TYPE_WITH_CODE (ExampleContactList, example_contact_list, EXAMPLE_TYPE_CONTACT_LIST_BASE, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, list_channel_iface_init)) /* Subclass for handle type GROUP */ G_DEFINE_TYPE_WITH_CODE (ExampleContactGroup, example_contact_group, EXAMPLE_TYPE_CONTACT_LIST_BASE, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, group_channel_iface_init)) static const gchar *contact_list_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_GROUP, NULL }; enum { PROP_OBJECT_PATH = 1, PROP_CHANNEL_TYPE, PROP_HANDLE_TYPE, PROP_HANDLE, PROP_TARGET_ID, PROP_REQUESTED, PROP_INITIATOR_HANDLE, PROP_INITIATOR_ID, PROP_CONNECTION, PROP_MANAGER, PROP_INTERFACES, PROP_CHANNEL_DESTROYED, PROP_CHANNEL_PROPERTIES, N_PROPS }; struct _ExampleContactListBasePrivate { TpBaseConnection *conn; ExampleContactListManager *manager; gchar *object_path; TpHandleType handle_type; TpHandle handle; /* These are really booleans, but gboolean is signed. Thanks, GLib */ unsigned closed:1; unsigned disposed:1; }; struct _ExampleContactListPrivate { int dummy:1; }; struct _ExampleContactGroupPrivate { int dummy:1; }; static void example_contact_list_base_init (ExampleContactListBase *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST_BASE, ExampleContactListBasePrivate); } static void example_contact_list_init (ExampleContactList *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST, ExampleContactListPrivate); } static void example_contact_group_init (ExampleContactGroup *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_GROUP, ExampleContactGroupPrivate); } static void constructed (GObject *object) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_contact_list_base_parent_class)->constructed; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); TpHandle self_handle = self->priv->conn->self_handle; if (chain_up != NULL) chain_up (object); g_assert (TP_IS_BASE_CONNECTION (self->priv->conn)); g_assert (EXAMPLE_IS_CONTACT_LIST_MANAGER (self->priv->manager)); tp_dbus_daemon_register_object ( tp_base_connection_get_dbus_daemon (self->priv->conn), self->priv->object_path, self); tp_group_mixin_init (object, G_STRUCT_OFFSET (ExampleContactListBase, group), contact_repo, self_handle); /* Both the subclasses have full support for telepathy-spec 0.17.6. */ tp_group_mixin_change_flags (object, TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0); } static void list_constructed (GObject *object) { ExampleContactList *self = EXAMPLE_CONTACT_LIST (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_contact_list_parent_class)->constructed; if (chain_up != NULL) chain_up (object); g_assert (self->parent.priv->handle_type == TP_HANDLE_TYPE_LIST); switch (self->parent.priv->handle) { case EXAMPLE_CONTACT_LIST_PUBLISH: /* We can stop publishing presence to people, but we can't * start sending people our presence unless they ask for it. * * (We can accept people's requests to see our presence - but that's * always allowed, so there's no flag.) */ tp_group_mixin_change_flags (object, TP_CHANNEL_GROUP_FLAG_CAN_REMOVE, 0); break; case EXAMPLE_CONTACT_LIST_STORED: case EXAMPLE_CONTACT_LIST_DENY: /* We can add people to our roster (not that that's very useful without * also adding them to subscribe), and we can remove them altogether * (which implicitly removes them from subscribe, publish, and all * user-defined groups). * * Similarly, we can block and unblock people (i.e. add/remove them * to/from the deny list) */ tp_group_mixin_change_flags (object, TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE, 0); break; case EXAMPLE_CONTACT_LIST_SUBSCRIBE: /* We can ask people to show us their presence, attaching a message. * We can also cancel (rescind) requests that they haven't replied to, * and stop receiving their presence after they allow it. */ tp_group_mixin_change_flags (object, TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND, 0); break; default: g_assert_not_reached (); } } static void group_constructed (GObject *object) { ExampleContactGroup *self = EXAMPLE_CONTACT_GROUP (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_contact_group_parent_class)->constructed; if (chain_up != NULL) chain_up (object); g_assert (self->parent.priv->handle_type == TP_HANDLE_TYPE_GROUP); /* We can add people to user-defined groups, and also remove them. */ tp_group_mixin_change_flags (object, TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE, 0); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); switch (property_id) { case PROP_OBJECT_PATH: g_value_set_string (value, self->priv->object_path); break; case PROP_CHANNEL_TYPE: g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST); break; case PROP_HANDLE_TYPE: g_value_set_uint (value, self->priv->handle_type); break; case PROP_HANDLE: g_value_set_uint (value, self->priv->handle); break; case PROP_TARGET_ID: { TpHandleRepoIface *handle_repo = tp_base_connection_get_handles ( self->priv->conn, self->priv->handle_type); g_value_set_string (value, tp_handle_inspect (handle_repo, self->priv->handle)); } break; case PROP_REQUESTED: g_value_set_boolean (value, FALSE); break; case PROP_INITIATOR_HANDLE: g_value_set_uint (value, 0); break; case PROP_INITIATOR_ID: g_value_set_static_string (value, ""); break; case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; case PROP_MANAGER: g_value_set_object (value, self->priv->manager); break; case PROP_INTERFACES: g_value_set_boxed (value, contact_list_interfaces); break; case PROP_CHANNEL_DESTROYED: g_value_set_boolean (value, self->priv->closed); break; case PROP_CHANNEL_PROPERTIES: g_value_take_boxed (value, tp_dbus_properties_mixin_make_properties_hash (object, TP_IFACE_CHANNEL, "ChannelType", TP_IFACE_CHANNEL, "TargetHandleType", TP_IFACE_CHANNEL, "TargetHandle", TP_IFACE_CHANNEL, "TargetID", TP_IFACE_CHANNEL, "InitiatorHandle", TP_IFACE_CHANNEL, "InitiatorID", TP_IFACE_CHANNEL, "Requested", TP_IFACE_CHANNEL, "Interfaces", NULL)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); switch (property_id) { case PROP_OBJECT_PATH: g_free (self->priv->object_path); self->priv->object_path = g_value_dup_string (value); break; case PROP_HANDLE: /* we don't ref it here because we don't necessarily have access to the * repository (or even type) yet - instead we ref it in the constructor. */ self->priv->handle = g_value_get_uint (value); break; case PROP_HANDLE_TYPE: self->priv->handle_type = g_value_get_uint (value); break; case PROP_CHANNEL_TYPE: /* this property is writable in the interface, but not actually * meaningfully changable on this channel, so we do nothing */ break; case PROP_CONNECTION: self->priv->conn = g_value_get_object (value); break; case PROP_MANAGER: self->priv->manager = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dispose (GObject *object) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); if (self->priv->disposed) return; self->priv->disposed = TRUE; if (!self->priv->closed) { self->priv->closed = TRUE; tp_svc_channel_emit_closed (self); } ((GObjectClass *) example_contact_list_base_parent_class)->dispose (object); } static void finalize (GObject *object) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); g_free (self->priv->object_path); tp_group_mixin_finalize (object); ((GObjectClass *) example_contact_list_base_parent_class)->finalize (object); } static gboolean group_add_member (GObject *object, TpHandle handle, const gchar *message, GError **error) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); return example_contact_list_manager_add_to_group (self->priv->manager, object, self->priv->handle, handle, message, error); } static gboolean group_remove_member (GObject *object, TpHandle handle, const gchar *message, GError **error) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); return example_contact_list_manager_remove_from_group (self->priv->manager, object, self->priv->handle, handle, message, error); } static gboolean list_add_member (GObject *object, TpHandle handle, const gchar *message, GError **error) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); return example_contact_list_manager_add_to_list (self->priv->manager, object, self->priv->handle, handle, message, error); } static gboolean list_remove_member (GObject *object, TpHandle handle, const gchar *message, GError **error) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (object); return example_contact_list_manager_remove_from_list (self->priv->manager, object, self->priv->handle, handle, message, error); } static void example_contact_list_base_class_init (ExampleContactListBaseClass *klass) { static TpDBusPropertiesMixinPropImpl channel_props[] = { { "TargetHandleType", "handle-type", NULL }, { "TargetHandle", "handle", NULL }, { "ChannelType", "channel-type", NULL }, { "Interfaces", "interfaces", NULL }, { "TargetID", "target-id", NULL }, { "Requested", "requested", NULL }, { "InitiatorHandle", "initiator-handle", NULL }, { "InitiatorID", "initiator-id", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CHANNEL, tp_dbus_properties_mixin_getter_gobject_properties, NULL, channel_props, }, { NULL } }; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (ExampleContactListBasePrivate)); object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path"); g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type"); g_object_class_override_property (object_class, PROP_HANDLE, "handle"); g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, "channel-destroyed"); g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, "channel-properties"); param_spec = g_param_spec_object ("connection", "TpBaseConnection object", "Connection object that owns this channel", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_object ("manager", "ExampleContactListManager", "ExampleContactListManager object that owns this channel", EXAMPLE_TYPE_CONTACT_LIST_MANAGER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_MANAGER, param_spec); param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "Additional Channel.Interface.* interfaces", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_string ("target-id", "Chatroom's ID", "The string obtained by inspecting the MUC's handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", "The contact who initiated the channel", 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, param_spec); param_spec = g_param_spec_string ("initiator-id", "Initiator's ID", "The string obtained by inspecting the initiator-handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_ID, param_spec); param_spec = g_param_spec_boolean ("requested", "Requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); klass->dbus_properties_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleContactListBaseClass, dbus_properties_class)); /* Group mixin is initialized separately for each subclass - they have * different callbacks */ } static void example_contact_list_class_init (ExampleContactListClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; g_type_class_add_private (klass, sizeof (ExampleContactListPrivate)); object_class->constructed = list_constructed; tp_group_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleContactListBaseClass, group_class), list_add_member, list_remove_member); tp_group_mixin_init_dbus_properties (object_class); } static void example_contact_group_class_init (ExampleContactGroupClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; g_type_class_add_private (klass, sizeof (ExampleContactGroupPrivate)); object_class->constructed = group_constructed; tp_group_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleContactListBaseClass, group_class), group_add_member, group_remove_member); tp_group_mixin_init_dbus_properties (object_class); } static void list_channel_close (TpSvcChannel *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { GError e = { TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "ContactList channels with handle type LIST may not be closed" }; dbus_g_method_return_error (context, &e); } static void group_channel_close (TpSvcChannel *iface, DBusGMethodInvocation *context) { ExampleContactGroup *self = EXAMPLE_CONTACT_GROUP (iface); ExampleContactListBase *base = EXAMPLE_CONTACT_LIST_BASE (iface); if (tp_handle_set_size (base->group.members) > 0) { GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Non-empty groups may not be deleted (closed)" }; dbus_g_method_return_error (context, &e); return; } if (!base->priv->closed) { /* If this was a real connection manager we'd delete the group here, * if such a concept existed in the protocol (in XMPP, it doesn't). * * Afterwards, close the channel: */ base->priv->closed = TRUE; tp_svc_channel_emit_closed (self); } tp_svc_channel_return_from_close (context); } static void channel_get_channel_type (TpSvcChannel *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_channel_type (context, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST); } static void channel_get_handle (TpSvcChannel *iface, DBusGMethodInvocation *context) { ExampleContactListBase *self = EXAMPLE_CONTACT_LIST_BASE (iface); tp_svc_channel_return_from_get_handle (context, self->priv->handle_type, self->priv->handle); } static void channel_get_interfaces (TpSvcChannel *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_interfaces (context, contact_list_interfaces); } static void channel_iface_init (gpointer iface, gpointer data) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x) /* close is implemented in subclasses, so don't IMPLEMENT (close); */ IMPLEMENT (get_channel_type); IMPLEMENT (get_handle); IMPLEMENT (get_interfaces); #undef IMPLEMENT } static void list_channel_iface_init (gpointer iface, gpointer data G_GNUC_UNUSED) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, list_channel_##x) IMPLEMENT (close); #undef IMPLEMENT } static void group_channel_iface_init (gpointer iface, gpointer data G_GNUC_UNUSED) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, group_channel_##x) IMPLEMENT (close); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/conn.c0000664000175000017500000004366412470405660021242 0ustar jrjr/* * conn.c - an example connection * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "conn.h" #include #include #include #include #include #include "contact-list-manager.h" static void init_aliasing (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (ExampleContactListConnection, example_contact_list_connection, TP_TYPE_BASE_CONNECTION, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING, init_aliasing); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, tp_contacts_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE, tp_presence_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE, tp_presence_mixin_simple_presence_iface_init)) enum { PROP_ACCOUNT = 1, PROP_SIMULATION_DELAY, N_PROPS }; struct _ExampleContactListConnectionPrivate { gchar *account; guint simulation_delay; ExampleContactListManager *list_manager; gboolean away; }; static void example_contact_list_connection_init (ExampleContactListConnection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, ExampleContactListConnectionPrivate); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_value_set_string (value, self->priv->account); break; case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *spec) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_free (self->priv->account); self->priv->account = g_value_dup_string (value); break; case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void finalize (GObject *object) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); tp_contacts_mixin_finalize (object); g_free (self->priv->account); G_OBJECT_CLASS (example_contact_list_connection_parent_class)->finalize ( object); } static gchar * get_unique_connection_name (TpBaseConnection *conn) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (conn); return g_strdup_printf ("%s@%p", self->priv->account, self); } gchar * example_contact_list_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error) { if (id[0] == '\0') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "Contact ID must not be empty"); return NULL; } return g_utf8_normalize (id, -1, G_NORMALIZE_ALL_COMPOSE); } static gchar * example_contact_list_normalize_group (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error) { if (id[0] == '\0') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "Contact group name cannot be empty"); return NULL; } return g_utf8_normalize (id, -1, G_NORMALIZE_ALL_COMPOSE); } static void create_handle_repos (TpBaseConnection *conn, TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]) { repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_CONTACT, example_contact_list_normalize_contact, NULL); repos[TP_HANDLE_TYPE_LIST] = tp_static_handle_repo_new (TP_HANDLE_TYPE_LIST, example_contact_lists ()); repos[TP_HANDLE_TYPE_GROUP] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_GROUP, example_contact_list_normalize_group, NULL); } static void alias_updated_cb (ExampleContactListManager *manager, TpHandle contact, ExampleContactListConnection *self) { GPtrArray *aliases; GValueArray *pair; pair = g_value_array_new (2); g_value_array_append (pair, NULL); g_value_array_append (pair, NULL); g_value_init (pair->values + 0, G_TYPE_UINT); g_value_init (pair->values + 1, G_TYPE_STRING); g_value_set_uint (pair->values + 0, contact); g_value_set_string (pair->values + 1, example_contact_list_manager_get_alias (manager, contact)); aliases = g_ptr_array_sized_new (1); g_ptr_array_add (aliases, pair); tp_svc_connection_interface_aliasing_emit_aliases_changed (self, aliases); g_ptr_array_free (aliases, TRUE); g_value_array_free (pair); } static void presence_updated_cb (ExampleContactListManager *manager, TpHandle contact, ExampleContactListConnection *self) { TpBaseConnection *base = (TpBaseConnection *) self; TpPresenceStatus *status; /* we ignore the presence indicated by the contact list for our own handle */ if (contact == base->self_handle) return; status = tp_presence_status_new ( example_contact_list_manager_get_presence (manager, contact), NULL); tp_presence_mixin_emit_one_presence_update ((GObject *) self, contact, status); tp_presence_status_free (status); } static GPtrArray * create_channel_managers (TpBaseConnection *conn) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (conn); GPtrArray *ret = g_ptr_array_sized_new (1); self->priv->list_manager = EXAMPLE_CONTACT_LIST_MANAGER (g_object_new ( EXAMPLE_TYPE_CONTACT_LIST_MANAGER, "connection", conn, "simulation-delay", self->priv->simulation_delay, NULL)); g_signal_connect (self->priv->list_manager, "alias-updated", G_CALLBACK (alias_updated_cb), self); g_signal_connect (self->priv->list_manager, "presence-updated", G_CALLBACK (presence_updated_cb), self); g_ptr_array_add (ret, self->priv->list_manager); return ret; } static gboolean start_connecting (TpBaseConnection *conn, GError **error) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (conn); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); /* In a real connection manager we'd ask the underlying implementation to * start connecting, then go to state CONNECTED when finished, but here * we can do it immediately. */ conn->self_handle = tp_handle_ensure (contact_repo, self->priv->account, NULL, error); if (conn->self_handle == 0) return FALSE; tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); return TRUE; } static void shut_down (TpBaseConnection *conn) { /* In a real connection manager we'd ask the underlying implementation to * start shutting down, then call this function when finished, but here * we can do it immediately. */ tp_base_connection_finish_shutdown (conn); } static void aliasing_fill_contact_attributes (GObject *object, const GArray *contacts, GHashTable *attributes) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); guint i; for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, guint, i); tp_contacts_mixin_set_contact_attribute (attributes, contact, TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS, tp_g_value_slice_new_string ( example_contact_list_manager_get_alias (self->priv->list_manager, contact))); } } static void constructed (GObject *object) { TpBaseConnection *base = TP_BASE_CONNECTION (object); void (*chain_up) (GObject *) = G_OBJECT_CLASS (example_contact_list_connection_parent_class)->constructed; if (chain_up != NULL) chain_up (object); tp_contacts_mixin_init (object, G_STRUCT_OFFSET (ExampleContactListConnection, contacts_mixin)); tp_base_connection_register_with_contacts_mixin (base); tp_contacts_mixin_add_contact_attributes_iface (object, TP_IFACE_CONNECTION_INTERFACE_ALIASING, aliasing_fill_contact_attributes); tp_presence_mixin_init (object, G_STRUCT_OFFSET (ExampleContactListConnection, presence_mixin)); tp_presence_mixin_simple_presence_register_with_contacts_mixin (object); } static gboolean status_available (GObject *object, guint index_) { TpBaseConnection *base = TP_BASE_CONNECTION (object); if (base->status != TP_CONNECTION_STATUS_CONNECTED) return FALSE; return TRUE; } static GHashTable * get_contact_statuses (GObject *object, const GArray *contacts, GError **error) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); TpBaseConnection *base = TP_BASE_CONNECTION (object); guint i; GHashTable *result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) tp_presence_status_free); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, guint, i); ExampleContactListPresence presence; GHashTable *parameters; /* we get our own status from the connection, and everyone else's status * from the contact lists */ if (contact == base->self_handle) { presence = (self->priv->away ? EXAMPLE_CONTACT_LIST_PRESENCE_AWAY : EXAMPLE_CONTACT_LIST_PRESENCE_AVAILABLE); } else { presence = example_contact_list_manager_get_presence ( self->priv->list_manager, contact); } parameters = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); g_hash_table_insert (result, GUINT_TO_POINTER (contact), tp_presence_status_new (presence, parameters)); g_hash_table_destroy (parameters); } return result; } static gboolean set_own_status (GObject *object, const TpPresenceStatus *status, GError **error) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (object); TpBaseConnection *base = TP_BASE_CONNECTION (object); GHashTable *presences; if (status->index == EXAMPLE_CONTACT_LIST_PRESENCE_AWAY) { if (self->priv->away) return TRUE; self->priv->away = TRUE; } else { if (!self->priv->away) return TRUE; self->priv->away = FALSE; } presences = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); g_hash_table_insert (presences, GUINT_TO_POINTER (base->self_handle), (gpointer) status); tp_presence_mixin_emit_presence_update (object, presences); g_hash_table_destroy (presences); return TRUE; } static void example_contact_list_connection_class_init ( ExampleContactListConnectionClass *klass) { static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_ALIASING, TP_IFACE_CONNECTION_INTERFACE_CONTACTS, TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, NULL }; TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; object_class->get_property = get_property; object_class->set_property = set_property; object_class->constructed = constructed; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (ExampleContactListConnectionPrivate)); base_class->create_handle_repos = create_handle_repos; base_class->get_unique_connection_name = get_unique_connection_name; base_class->create_channel_managers = create_channel_managers; base_class->start_connecting = start_connecting; base_class->shut_down = shut_down; base_class->interfaces_always_present = interfaces_always_present; param_spec = g_param_spec_string ("account", "Account name", "The username of this user", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); tp_contacts_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleContactListConnectionClass, contacts_mixin)); tp_presence_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleContactListConnectionClass, presence_mixin), status_available, get_contact_statuses, set_own_status, example_contact_list_presence_statuses ()); tp_presence_mixin_simple_presence_init_dbus_properties (object_class); } static void get_alias_flags (TpSvcConnectionInterfaceAliasing *aliasing, DBusGMethodInvocation *context) { TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); tp_svc_connection_interface_aliasing_return_from_get_alias_flags (context, TP_CONNECTION_ALIAS_FLAG_USER_SET); } static void get_aliases (TpSvcConnectionInterfaceAliasing *aliasing, const GArray *contacts, DBusGMethodInvocation *context) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (aliasing); TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GHashTable *result; GError *error = NULL; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, TpHandle, i); const gchar *alias = example_contact_list_manager_get_alias ( self->priv->list_manager, contact); g_hash_table_insert (result, GUINT_TO_POINTER (contact), (gchar *) alias); } tp_svc_connection_interface_aliasing_return_from_get_aliases (context, result); g_hash_table_destroy (result); } static void request_aliases (TpSvcConnectionInterfaceAliasing *aliasing, const GArray *contacts, DBusGMethodInvocation *context) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (aliasing); TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GPtrArray *result; gchar **strings; GError *error = NULL; guint i; TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } result = g_ptr_array_sized_new (contacts->len + 1); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, TpHandle, i); const gchar *alias = example_contact_list_manager_get_alias ( self->priv->list_manager, contact); g_ptr_array_add (result, (gchar *) alias); } g_ptr_array_add (result, NULL); strings = (gchar **) g_ptr_array_free (result, FALSE); tp_svc_connection_interface_aliasing_return_from_request_aliases (context, (const gchar **) strings); g_free (strings); } static void set_aliases (TpSvcConnectionInterfaceAliasing *aliasing, GHashTable *aliases, DBusGMethodInvocation *context) { ExampleContactListConnection *self = EXAMPLE_CONTACT_LIST_CONNECTION (aliasing); TpBaseConnection *base = TP_BASE_CONNECTION (aliasing); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, aliases); while (g_hash_table_iter_next (&iter, &key, &value)) { GError *error = NULL; if (!tp_handle_is_valid (contact_repo, GPOINTER_TO_UINT (key), &error)) { dbus_g_method_return_error (context, error); g_error_free (error); return; } } g_hash_table_iter_init (&iter, aliases); while (g_hash_table_iter_next (&iter, &key, &value)) { example_contact_list_manager_set_alias (self->priv->list_manager, GPOINTER_TO_UINT (key), value); } tp_svc_connection_interface_aliasing_return_from_set_aliases (context); } static void init_aliasing (gpointer iface, gpointer iface_data G_GNUC_UNUSED) { TpSvcConnectionInterfaceAliasingClass *klass = iface; #define IMPLEMENT(x) tp_svc_connection_interface_aliasing_implement_##x (\ klass, x) IMPLEMENT(get_alias_flags); IMPLEMENT(request_aliases); IMPLEMENT(get_aliases); IMPLEMENT(set_aliases); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/contact-list-manager.c0000664000175000017500000015276512470405660024324 0ustar jrjr/* * Example channel manager for contact lists * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "contact-list-manager.h" #include #include #include #include "contact-list.h" /* elements 0, 1... of this array must be kept in sync with elements 1, 2... * of the enum ExampleContactList in contact-list-manager.h */ static const gchar *_contact_lists[NUM_EXAMPLE_CONTACT_LISTS + 1] = { "subscribe", "publish", "stored", "deny", NULL }; const gchar ** example_contact_lists (void) { return _contact_lists; } /* this array must be kept in sync with the enum * ExampleContactListPresence in contact-list-manager.h */ static const TpPresenceStatusSpec _statuses[] = { { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, NULL }, { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, NULL }, { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, NULL }, { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, NULL }, { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, NULL }, { NULL } }; const TpPresenceStatusSpec * example_contact_list_presence_statuses (void) { return _statuses; } typedef struct { gchar *alias; guint subscribe:1; guint publish:1; guint subscribe_requested:1; guint publish_requested:1; guint stored:1; guint blocked:1; TpHandleSet *tags; } ExampleContactDetails; static ExampleContactDetails * example_contact_details_new (void) { return g_slice_new0 (ExampleContactDetails); } static void example_contact_details_destroy (gpointer p) { ExampleContactDetails *d = p; if (d->tags != NULL) tp_handle_set_destroy (d->tags); g_free (d->alias); g_slice_free (ExampleContactDetails, d); } static void channel_manager_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (ExampleContactListManager, example_contact_list_manager, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, channel_manager_iface_init)) enum { ALIAS_UPDATED, PRESENCE_UPDATED, N_SIGNALS }; static guint signals[N_SIGNALS] = { 0 }; enum { PROP_CONNECTION = 1, PROP_SIMULATION_DELAY, N_PROPS }; struct _ExampleContactListManagerPrivate { TpBaseConnection *conn; guint simulation_delay; TpHandleRepoIface *contact_repo; TpHandleRepoIface *group_repo; TpHandleSet *contacts; /* GUINT_TO_POINTER (handle borrowed from contacts) * => ExampleContactDetails */ GHashTable *contact_details; ExampleContactList *lists[NUM_EXAMPLE_CONTACT_LISTS]; /* GUINT_TO_POINTER (handle borrowed from channel) => ExampleContactGroup */ GHashTable *groups; /* borrowed TpExportableChannel => GSList of gpointer (request tokens) that * will be satisfied by that channel when the contact list has been * downloaded. The requests are in reverse chronological order */ GHashTable *queued_requests; gulong status_changed_id; }; static void example_contact_list_manager_init (ExampleContactListManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST_MANAGER, ExampleContactListManagerPrivate); self->priv->contact_details = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, example_contact_details_destroy); self->priv->groups = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); self->priv->queued_requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); /* initialized properly in constructed() */ self->priv->contact_repo = NULL; self->priv->group_repo = NULL; self->priv->contacts = NULL; } static void example_contact_list_manager_close_all (ExampleContactListManager *self) { guint i; if (self->priv->queued_requests != NULL) { GHashTable *tmp = self->priv->queued_requests; GHashTableIter iter; gpointer key, value; self->priv->queued_requests = NULL; g_hash_table_iter_init (&iter, tmp); while (g_hash_table_iter_next (&iter, &key, &value)) { GSList *requests = value; GSList *l; requests = g_slist_reverse (requests); for (l = requests; l != NULL; l = l->next) { tp_channel_manager_emit_request_failed (self, l->data, TP_ERROR, TP_ERROR_DISCONNECTED, "Unable to complete channel request due to disconnection"); } g_slist_free (requests); g_hash_table_iter_steal (&iter); } g_hash_table_destroy (tmp); } if (self->priv->contacts != NULL) { tp_handle_set_destroy (self->priv->contacts); self->priv->contacts = NULL; } if (self->priv->contact_details != NULL) { GHashTable *tmp = self->priv->contact_details; self->priv->contact_details = NULL; g_hash_table_destroy (tmp); } if (self->priv->groups != NULL) { GHashTable *tmp = self->priv->groups; self->priv->groups = NULL; g_hash_table_destroy (tmp); } for (i = 0; i < NUM_EXAMPLE_CONTACT_LISTS; i++) { if (self->priv->lists[i] != NULL) { ExampleContactList *list = self->priv->lists[i]; /* set self->priv->lists[i] to NULL here so list_closed_cb does * not try to delete the list again */ self->priv->lists[i] = NULL; g_object_unref (list); } } if (self->priv->status_changed_id != 0) { g_signal_handler_disconnect (self->priv->conn, self->priv->status_changed_id); self->priv->status_changed_id = 0; } } static void dispose (GObject *object) { ExampleContactListManager *self = EXAMPLE_CONTACT_LIST_MANAGER (object); example_contact_list_manager_close_all (self); g_assert (self->priv->groups == NULL); g_assert (self->priv->lists[0] == NULL); g_assert (self->priv->queued_requests == NULL); ((GObjectClass *) example_contact_list_manager_parent_class)->dispose ( object); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleContactListManager *self = EXAMPLE_CONTACT_LIST_MANAGER (object); switch (property_id) { case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleContactListManager *self = EXAMPLE_CONTACT_LIST_MANAGER (object); switch (property_id) { case PROP_CONNECTION: /* We don't ref the connection, because it owns a reference to the * manager, and it guarantees that the manager's lifetime is * less than its lifetime */ self->priv->conn = g_value_get_object (value); break; case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void satisfy_queued_requests (TpExportableChannel *channel, gpointer user_data) { ExampleContactListManager *self = EXAMPLE_CONTACT_LIST_MANAGER (user_data); GSList *requests = g_hash_table_lookup (self->priv->queued_requests, channel); /* this is all fine even if requests is NULL */ g_hash_table_steal (self->priv->queued_requests, channel); requests = g_slist_reverse (requests); tp_channel_manager_emit_new_channel (self, channel, requests); g_slist_free (requests); } static ExampleContactDetails * lookup_contact (ExampleContactListManager *self, TpHandle contact) { return g_hash_table_lookup (self->priv->contact_details, GUINT_TO_POINTER (contact)); } static ExampleContactDetails * ensure_contact (ExampleContactListManager *self, TpHandle contact, gboolean *created) { ExampleContactDetails *ret = lookup_contact (self, contact); if (ret == NULL) { tp_handle_set_add (self->priv->contacts, contact); ret = example_contact_details_new (); ret->alias = g_strdup (tp_handle_inspect (self->priv->contact_repo, contact)); g_hash_table_insert (self->priv->contact_details, GUINT_TO_POINTER (contact), ret); if (created != NULL) *created = TRUE; } else if (created != NULL) { *created = FALSE; } return ret; } static void example_contact_list_manager_foreach_channel (TpChannelManager *manager, TpExportableChannelFunc callback, gpointer user_data) { ExampleContactListManager *self = EXAMPLE_CONTACT_LIST_MANAGER (manager); GHashTableIter iter; gpointer handle, channel; guint i; for (i = 0; i < NUM_EXAMPLE_CONTACT_LISTS; i++) { if (self->priv->lists[i] != NULL) callback (TP_EXPORTABLE_CHANNEL (self->priv->lists[i]), user_data); } g_hash_table_iter_init (&iter, self->priv->groups); while (g_hash_table_iter_next (&iter, &handle, &channel)) { callback (TP_EXPORTABLE_CHANNEL (channel), user_data); } } static ExampleContactGroup *ensure_group (ExampleContactListManager *self, TpHandle handle); static ExampleContactList *ensure_list (ExampleContactListManager *self, ExampleContactListHandle handle); static gboolean receive_contact_lists (gpointer p) { ExampleContactListManager *self = p; TpHandle handle, cambridge, montreal, francophones; ExampleContactDetails *d; TpIntSet *set, *cam_set, *mtl_set, *fr_set; TpIntSetFastIter iter; ExampleContactList *subscribe, *publish, *stored, *deny; ExampleContactGroup *cambridge_group, *montreal_group, *francophones_group; if (self->priv->groups == NULL) { /* connection already disconnected, so don't process the * "data from the server" */ return FALSE; } /* In a real CM we'd have received a contact list from the server at this * point. But this isn't a real CM, so we have to make one up... */ g_message ("Receiving roster from server"); subscribe = ensure_list (self, EXAMPLE_CONTACT_LIST_SUBSCRIBE); publish = ensure_list (self, EXAMPLE_CONTACT_LIST_PUBLISH); stored = ensure_list (self, EXAMPLE_CONTACT_LIST_STORED); deny = ensure_list (self, EXAMPLE_CONTACT_LIST_DENY); cambridge = tp_handle_ensure (self->priv->group_repo, "Cambridge", NULL, NULL); montreal = tp_handle_ensure (self->priv->group_repo, "Montreal", NULL, NULL); francophones = tp_handle_ensure (self->priv->group_repo, "Francophones", NULL, NULL); cambridge_group = ensure_group (self, cambridge); montreal_group = ensure_group (self, montreal); francophones_group = ensure_group (self, francophones); /* Add various people who are already subscribing and publishing */ set = tp_intset_new (); cam_set = tp_intset_new (); mtl_set = tp_intset_new (); fr_set = tp_intset_new (); handle = tp_handle_ensure (self->priv->contact_repo, "sjoerd@example.com", NULL, NULL); tp_intset_add (set, handle); tp_intset_add (cam_set, handle); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Sjoerd"); d->subscribe = TRUE; d->publish = TRUE; d->stored = TRUE; d->tags = tp_handle_set_new (self->priv->group_repo); tp_handle_set_add (d->tags, cambridge); handle = tp_handle_ensure (self->priv->contact_repo, "guillaume@example.com", NULL, NULL); tp_intset_add (set, handle); tp_intset_add (cam_set, handle); tp_intset_add (fr_set, handle); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Guillaume"); d->subscribe = TRUE; d->publish = TRUE; d->stored = TRUE; d->tags = tp_handle_set_new (self->priv->group_repo); tp_handle_set_add (d->tags, cambridge); tp_handle_set_add (d->tags, francophones); handle = tp_handle_ensure (self->priv->contact_repo, "olivier@example.com", NULL, NULL); tp_intset_add (set, handle); tp_intset_add (mtl_set, handle); tp_intset_add (fr_set, handle); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Olivier"); d->subscribe = TRUE; d->publish = TRUE; d->stored = TRUE; d->tags = tp_handle_set_new (self->priv->group_repo); tp_handle_set_add (d->tags, montreal); tp_handle_set_add (d->tags, francophones); handle = tp_handle_ensure (self->priv->contact_repo, "travis@example.com", NULL, NULL); tp_intset_add (set, handle); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Travis"); d->subscribe = TRUE; d->publish = TRUE; d->stored = TRUE; tp_group_mixin_change_members ((GObject *) subscribe, "", set, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) publish, "", set, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) stored, "", set, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_fast_iter_init (&iter, set); while (tp_intset_fast_iter_next (&iter, &handle)) { g_signal_emit (self, signals[ALIAS_UPDATED], 0, handle); g_signal_emit (self, signals[PRESENCE_UPDATED], 0, handle); } tp_intset_destroy (set); /* Add a couple of people whose presence we've requested. They are * remote-pending in subscribe */ set = tp_intset_new (); handle = tp_handle_ensure (self->priv->contact_repo, "geraldine@example.com", NULL, NULL); tp_intset_add (set, handle); tp_intset_add (cam_set, handle); tp_intset_add (fr_set, handle); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Géraldine"); d->subscribe_requested = TRUE; d->stored = TRUE; d->tags = tp_handle_set_new (self->priv->group_repo); tp_handle_set_add (d->tags, cambridge); tp_handle_set_add (d->tags, francophones); handle = tp_handle_ensure (self->priv->contact_repo, "helen@example.com", NULL, NULL); tp_intset_add (set, handle); tp_intset_add (cam_set, handle); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Helen"); d->subscribe_requested = TRUE; d->stored = TRUE; d->tags = tp_handle_set_new (self->priv->group_repo); tp_handle_set_add (d->tags, cambridge); tp_group_mixin_change_members ((GObject *) subscribe, "", NULL, NULL, NULL, set, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) stored, "", set, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_fast_iter_init (&iter, set); while (tp_intset_fast_iter_next (&iter, &handle)) { g_signal_emit (self, signals[ALIAS_UPDATED], 0, handle); g_signal_emit (self, signals[PRESENCE_UPDATED], 0, handle); } tp_intset_destroy (set); /* Receive a couple of authorization requests too. These people are * local-pending in publish */ handle = tp_handle_ensure (self->priv->contact_repo, "wim@example.com", NULL, NULL); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Wim"); d->publish_requested = TRUE; d->stored = TRUE; set = tp_intset_new_containing (handle); tp_group_mixin_change_members ((GObject *) publish, "I'm more metal than you!", NULL, NULL, set, NULL, handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) stored, "", set, NULL, NULL, NULL, handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); g_signal_emit (self, signals[ALIAS_UPDATED], 0, handle); g_signal_emit (self, signals[PRESENCE_UPDATED], 0, handle); handle = tp_handle_ensure (self->priv->contact_repo, "christian@example.com", NULL, NULL); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Christian"); d->publish_requested = TRUE; d->stored = TRUE; set = tp_intset_new_containing (handle); tp_group_mixin_change_members ((GObject *) publish, "I have some fermented herring for you", NULL, NULL, set, NULL, handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) stored, "", set, NULL, NULL, NULL, handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); g_signal_emit (self, signals[ALIAS_UPDATED], 0, handle); g_signal_emit (self, signals[PRESENCE_UPDATED], 0, handle); /* Add a couple of people who are blocked */ set = tp_intset_new (); handle = tp_handle_ensure (self->priv->contact_repo, "bill@example.com", NULL, NULL); tp_intset_add (set, handle); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Bill"); d->blocked = TRUE; handle = tp_handle_ensure (self->priv->contact_repo, "steve@example.com", NULL, NULL); tp_intset_add (set, handle); d = ensure_contact (self, handle, NULL); g_free (d->alias); d->alias = g_strdup ("Steve"); d->blocked = TRUE; tp_group_mixin_change_members ((GObject *) deny, "", set, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_fast_iter_init (&iter, set); while (tp_intset_fast_iter_next (&iter, &handle)) { g_signal_emit (self, signals[ALIAS_UPDATED], 0, handle); g_signal_emit (self, signals[PRESENCE_UPDATED], 0, handle); } tp_intset_destroy (set); /* Handle groups */ tp_group_mixin_change_members ((GObject *) cambridge_group, "", cam_set, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) montreal_group, "", mtl_set, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) francophones_group, "", fr_set, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (fr_set); tp_intset_destroy (cam_set); tp_intset_destroy (mtl_set); /* Now we've received the roster, we can satisfy all the queued requests */ example_contact_list_manager_foreach_channel ((TpChannelManager *) self, satisfy_queued_requests, self); g_assert (g_hash_table_size (self->priv->queued_requests) == 0); g_hash_table_destroy (self->priv->queued_requests); self->priv->queued_requests = NULL; return FALSE; } static void status_changed_cb (TpBaseConnection *conn, guint status, guint reason, ExampleContactListManager *self) { switch (status) { case TP_CONNECTION_STATUS_CONNECTED: { /* Do network I/O to get the contact list. This connection manager * doesn't really have a server, so simulate a small network delay * then invent a contact list */ g_timeout_add_full (G_PRIORITY_DEFAULT, 2 * self->priv->simulation_delay, receive_contact_lists, g_object_ref (self), g_object_unref); } break; case TP_CONNECTION_STATUS_DISCONNECTED: { example_contact_list_manager_close_all (self); } break; } } static void constructed (GObject *object) { ExampleContactListManager *self = EXAMPLE_CONTACT_LIST_MANAGER (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_contact_list_manager_parent_class)->constructed; if (chain_up != NULL) { chain_up (object); } self->priv->contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); self->priv->group_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_GROUP); self->priv->contacts = tp_handle_set_new (self->priv->contact_repo); self->priv->status_changed_id = g_signal_connect (self->priv->conn, "status-changed", (GCallback) status_changed_cb, self); } static void example_contact_list_manager_class_init (ExampleContactListManagerClass *klass) { GParamSpec *param_spec; GObjectClass *object_class = (GObjectClass *) klass; object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; param_spec = g_param_spec_object ("connection", "Connection object", "The connection that owns this channel manager", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); g_type_class_add_private (klass, sizeof (ExampleContactListManagerPrivate)); signals[ALIAS_UPDATED] = g_signal_new ("alias-updated", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals[PRESENCE_UPDATED] = g_signal_new ("presence-updated", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); } static void list_closed_cb (ExampleContactList *chan, ExampleContactListManager *self) { TpHandle handle; tp_channel_manager_emit_channel_closed_for_object (self, TP_EXPORTABLE_CHANNEL (chan)); g_object_get (chan, "handle", &handle, NULL); if (self->priv->lists[handle] == NULL) return; g_assert (chan == self->priv->lists[handle]); g_object_unref (self->priv->lists[handle]); self->priv->lists[handle] = NULL; } static void group_closed_cb (ExampleContactGroup *chan, ExampleContactListManager *self) { tp_channel_manager_emit_channel_closed_for_object (self, TP_EXPORTABLE_CHANNEL (chan)); if (self->priv->groups != NULL) { TpHandle handle; g_object_get (chan, "handle", &handle, NULL); g_hash_table_remove (self->priv->groups, GUINT_TO_POINTER (handle)); } } static ExampleContactListBase * new_channel (ExampleContactListManager *self, TpHandleType handle_type, TpHandle handle, gpointer request_token) { ExampleContactListBase *chan; gchar *object_path; GType type; GSList *requests = NULL; if (handle_type == TP_HANDLE_TYPE_LIST) { /* Some Telepathy clients wrongly assume that contact lists of type LIST * have object paths ending with "/subscribe", "/publish" etc. - * telepathy-spec has no such guarantee, so in this example we break * those clients. Please read the spec when implementing it :-) */ object_path = g_strdup_printf ("%s/%sContactList", self->priv->conn->object_path, _contact_lists[handle - 1]); type = EXAMPLE_TYPE_CONTACT_LIST; } else { /* Using Group%u (with handle as the value of %u) would be OK here too, * but we'll encode the group name into the object path to be kind * to people reading debug logs. */ gchar *id = tp_escape_as_identifier (tp_handle_inspect ( self->priv->group_repo, handle)); g_assert (handle_type == TP_HANDLE_TYPE_GROUP); object_path = g_strdup_printf ("%s/Group/%s", self->priv->conn->object_path, id); type = EXAMPLE_TYPE_CONTACT_GROUP; g_free (id); } chan = g_object_new (type, "connection", self->priv->conn, "manager", self, "object-path", object_path, "handle-type", handle_type, "handle", handle, NULL); g_free (object_path); if (handle_type == TP_HANDLE_TYPE_LIST) { g_signal_connect (chan, "closed", (GCallback) list_closed_cb, self); g_assert (self->priv->lists[handle] == NULL); self->priv->lists[handle] = EXAMPLE_CONTACT_LIST (chan); } else { g_signal_connect (chan, "closed", (GCallback) group_closed_cb, self); g_assert (g_hash_table_lookup (self->priv->groups, GUINT_TO_POINTER (handle)) == NULL); g_hash_table_insert (self->priv->groups, GUINT_TO_POINTER (handle), EXAMPLE_CONTACT_GROUP (chan)); } if (self->priv->queued_requests == NULL) { if (request_token != NULL) requests = g_slist_prepend (requests, request_token); tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan), requests); g_slist_free (requests); } else if (request_token != NULL) { /* initial contact list not received yet, so we have to wait for it */ requests = g_hash_table_lookup (self->priv->queued_requests, chan); g_hash_table_steal (self->priv->queued_requests, chan); requests = g_slist_prepend (requests, request_token); g_hash_table_insert (self->priv->queued_requests, chan, requests); } return chan; } static ExampleContactList * ensure_list (ExampleContactListManager *self, ExampleContactListHandle handle) { if (self->priv->lists[handle] == NULL) { new_channel (self, TP_HANDLE_TYPE_LIST, handle, NULL); g_assert (self->priv->lists[handle] != NULL); } return self->priv->lists[handle]; } static ExampleContactGroup * ensure_group (ExampleContactListManager *self, TpHandle handle) { ExampleContactGroup *group = g_hash_table_lookup (self->priv->groups, GUINT_TO_POINTER (handle)); if (group == NULL) { group = EXAMPLE_CONTACT_GROUP (new_channel (self, TP_HANDLE_TYPE_GROUP, handle, NULL)); } return group; } static const gchar * const fixed_properties[] = { TP_PROP_CHANNEL_CHANNEL_TYPE, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL }; static const gchar * const allowed_properties[] = { TP_PROP_CHANNEL_TARGET_HANDLE, TP_PROP_CHANNEL_TARGET_ID, NULL }; static void example_contact_list_manager_foreach_channel_class (TpChannelManager *manager, TpChannelManagerChannelClassFunc func, gpointer user_data) { GHashTable *table = tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_LIST, NULL); func (manager, table, allowed_properties, user_data); g_hash_table_insert (table, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, tp_g_value_slice_new_uint (TP_HANDLE_TYPE_GROUP)); func (manager, table, allowed_properties, user_data); g_hash_table_destroy (table); } static gboolean example_contact_list_manager_request (ExampleContactListManager *self, gpointer request_token, GHashTable *request_properties, gboolean require_new) { TpHandleType handle_type; TpHandle handle; ExampleContactListBase *chan; GError *error = NULL; if (tp_strdiff (tp_asv_get_string (request_properties, TP_PROP_CHANNEL_CHANNEL_TYPE), TP_IFACE_CHANNEL_TYPE_CONTACT_LIST)) { return FALSE; } handle_type = tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL); if (handle_type != TP_HANDLE_TYPE_LIST && handle_type != TP_HANDLE_TYPE_GROUP) { return FALSE; } handle = tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE, NULL); g_assert (handle != 0); if (tp_channel_manager_asv_has_unknown_properties (request_properties, fixed_properties, allowed_properties, &error)) { goto error; } if (handle_type == TP_HANDLE_TYPE_LIST) { /* telepathy-glib has already checked that the handle is valid */ g_assert (handle < NUM_EXAMPLE_CONTACT_LISTS); chan = EXAMPLE_CONTACT_LIST_BASE (self->priv->lists[handle]); } else { chan = g_hash_table_lookup (self->priv->groups, GUINT_TO_POINTER (handle)); } if (chan == NULL) { new_channel (self, handle_type, handle, request_token); } else if (require_new) { g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "A ContactList channel for type #%u, handle #%u already exists", handle_type, handle); goto error; } else { tp_channel_manager_emit_request_already_satisfied (self, request_token, TP_EXPORTABLE_CHANNEL (chan)); } return TRUE; error: tp_channel_manager_emit_request_failed (self, request_token, error->domain, error->code, error->message); g_error_free (error); return TRUE; } static gboolean example_contact_list_manager_create_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_contact_list_manager_request ( EXAMPLE_CONTACT_LIST_MANAGER (manager), request_token, request_properties, TRUE); } static gboolean example_contact_list_manager_ensure_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_contact_list_manager_request ( EXAMPLE_CONTACT_LIST_MANAGER (manager), request_token, request_properties, FALSE); } static void channel_manager_iface_init (gpointer g_iface, gpointer data G_GNUC_UNUSED) { TpChannelManagerIface *iface = g_iface; iface->foreach_channel = example_contact_list_manager_foreach_channel; iface->foreach_channel_class = example_contact_list_manager_foreach_channel_class; iface->create_channel = example_contact_list_manager_create_channel; iface->ensure_channel = example_contact_list_manager_ensure_channel; /* In this channel manager, Request has the same semantics as Ensure */ iface->request_channel = example_contact_list_manager_ensure_channel; } static void send_updated_roster (ExampleContactListManager *self, TpHandle contact) { ExampleContactDetails *d = g_hash_table_lookup (self->priv->contact_details, GUINT_TO_POINTER (contact)); const gchar *identifier = tp_handle_inspect (self->priv->contact_repo, contact); /* In a real connection manager, we'd transmit these new details to the * server, rather than just printing messages. */ if (d == NULL) { g_message ("Deleting contact %s from server", identifier); } else { g_message ("Transmitting new state of contact %s to server", identifier); g_message ("\talias = %s", d->alias); g_message ("\tcan see our presence = %s", d->publish ? "yes" : (d->publish_requested ? "no, but has requested it" : "no")); g_message ("\tsends us presence = %s", d->subscribe ? "yes" : (d->subscribe_requested ? "no, but we have requested it" : "no")); g_message ("\tstored = %s", d->stored ? "yes" : "no"); g_message ("\tblocked = %s", d->blocked ? "yes" : "no"); if (d->tags == NULL || tp_handle_set_size (d->tags) == 0) { g_message ("\tnot in any groups"); } else { TpIntSet *set = tp_handle_set_peek (d->tags); TpIntSetFastIter iter; TpHandle member; tp_intset_fast_iter_init (&iter, set); while (tp_intset_fast_iter_next (&iter, &member)) { g_message ("\tin group: %s", tp_handle_inspect (self->priv->group_repo, member)); } } } } gboolean example_contact_list_manager_add_to_group (ExampleContactListManager *self, GObject *channel, TpHandle group, TpHandle member, const gchar *message, GError **error) { gboolean updated; ExampleContactDetails *d = ensure_contact (self, member, &updated); ExampleContactList *stored = self->priv->lists[ EXAMPLE_CONTACT_LIST_STORED]; if (d->tags == NULL) d->tags = tp_handle_set_new (self->priv->group_repo); if (!tp_handle_set_is_member (d->tags, group)) { tp_handle_set_add (d->tags, group); updated = TRUE; } if (updated) { TpIntSet *added = tp_intset_new_containing (member); d->stored = TRUE; send_updated_roster (self, member); tp_group_mixin_change_members (channel, "", added, NULL, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) stored, "", added, NULL, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (added); } return TRUE; } gboolean example_contact_list_manager_remove_from_group ( ExampleContactListManager *self, GObject *channel, TpHandle group, TpHandle member, const gchar *message, GError **error) { ExampleContactDetails *d = lookup_contact (self, member); /* If not on the roster or not in any groups, we have nothing to do */ if (d == NULL || d->tags == NULL) return TRUE; if (tp_handle_set_remove (d->tags, group)) { TpIntSet *removed = tp_intset_new_containing (member); send_updated_roster (self, member); tp_group_mixin_change_members (channel, "", NULL, removed, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (removed); } return TRUE; } typedef struct { ExampleContactListManager *self; TpHandle contact; } SelfAndContact; static SelfAndContact * self_and_contact_new (ExampleContactListManager *self, TpHandle contact) { SelfAndContact *ret = g_slice_new0 (SelfAndContact); ret->self = g_object_ref (self); ret->contact = contact; return ret; } static void self_and_contact_destroy (gpointer p) { SelfAndContact *s = p; g_object_unref (s->self); g_slice_free (SelfAndContact, s); } static void receive_auth_request (ExampleContactListManager *self, TpHandle contact) { ExampleContactDetails *d; TpIntSet *set; ExampleContactList *publish = self->priv->lists[ EXAMPLE_CONTACT_LIST_PUBLISH]; ExampleContactList *stored = self->priv->lists[ EXAMPLE_CONTACT_LIST_STORED]; /* if shutting down, do nothing */ if (publish == NULL) return; /* A remote contact has asked to see our presence. * * In a real connection manager this would be the result of incoming * data from the server. */ g_message ("From server: %s has sent us a publish request", tp_handle_inspect (self->priv->contact_repo, contact)); d = ensure_contact (self, contact, NULL); if (d->publish) return; d->publish_requested = TRUE; d->stored = TRUE; set = tp_intset_new_containing (contact); tp_group_mixin_change_members ((GObject *) publish, "May I see your presence, please?", NULL, NULL, set, NULL, contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) stored, "", set, NULL, NULL, NULL, contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); } static gboolean receive_authorized (gpointer p) { SelfAndContact *s = p; ExampleContactDetails *d; TpIntSet *set; ExampleContactList *subscribe = s->self->priv->lists[ EXAMPLE_CONTACT_LIST_SUBSCRIBE]; ExampleContactList *stored = s->self->priv->lists[ EXAMPLE_CONTACT_LIST_STORED]; /* A remote contact has accepted our request to see their presence. * * In a real connection manager this would be the result of incoming * data from the server. */ g_message ("From server: %s has accepted our subscribe request", tp_handle_inspect (s->self->priv->contact_repo, s->contact)); d = ensure_contact (s->self, s->contact, NULL); /* if we were already subscribed to them, then nothing really happened */ if (d->subscribe) return FALSE; d->subscribe_requested = FALSE; d->subscribe = TRUE; d->stored = TRUE; set = tp_intset_new_containing (s->contact); tp_group_mixin_change_members ((GObject *) subscribe, "", set, NULL, NULL, NULL, s->contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) stored, "", set, NULL, NULL, NULL, s->contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); /* their presence changes to something other than UNKNOWN */ g_signal_emit (s->self, signals[PRESENCE_UPDATED], 0, s->contact); /* if we're not publishing to them, also pretend they have asked us to * do so */ if (!d->publish) { receive_auth_request (s->self, s->contact); } return FALSE; } static gboolean receive_unauthorized (gpointer p) { SelfAndContact *s = p; ExampleContactDetails *d; TpIntSet *set; ExampleContactList *subscribe = s->self->priv->lists[ EXAMPLE_CONTACT_LIST_SUBSCRIBE]; /* if shutting down, do nothing */ if (subscribe == NULL) return FALSE; /* A remote contact has rejected our request to see their presence. * * In a real connection manager this would be the result of incoming * data from the server. */ g_message ("From server: %s has rejected our subscribe request", tp_handle_inspect (s->self->priv->contact_repo, s->contact)); d = ensure_contact (s->self, s->contact, NULL); if (!d->subscribe && !d->subscribe_requested) return FALSE; d->subscribe_requested = FALSE; d->subscribe = FALSE; set = tp_intset_new_containing (s->contact); tp_group_mixin_change_members ((GObject *) subscribe, "Say 'please'!", NULL, set, NULL, NULL, s->contact, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); /* their presence changes to UNKNOWN */ g_signal_emit (s->self, signals[PRESENCE_UPDATED], 0, s->contact); return FALSE; } gboolean example_contact_list_manager_add_to_list (ExampleContactListManager *self, GObject *channel, ExampleContactListHandle list, TpHandle member, const gchar *message, GError **error) { TpIntSet *set; ExampleContactList *stored = self->priv->lists[EXAMPLE_CONTACT_LIST_STORED]; switch (list) { case EXAMPLE_CONTACT_LIST_SUBSCRIBE: /* we would like to see member's presence */ { gboolean created; ExampleContactDetails *d = ensure_contact (self, member, &created); gchar *message_lc; /* if they already authorized us, it's a no-op */ if (d->subscribe) return TRUE; /* In a real connection manager we'd start a network request here */ g_message ("Transmitting authorization request to %s: %s", tp_handle_inspect (self->priv->contact_repo, member), message); if (created || !d->subscribe_requested) { d->subscribe_requested = TRUE; d->stored = TRUE; send_updated_roster (self, member); } set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, message, NULL, NULL, NULL, set, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); /* subscribing to someone implicitly puts them on Stored, too */ tp_group_mixin_change_members ((GObject *) stored, "", set, NULL, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); /* Pretend that after a delay, the contact notices the request * and allows or rejects it. In this example connection manager, * empty requests are allowed, as are requests that contain "please" * case-insensitively. All other requests are denied. */ message_lc = g_ascii_strdown (message, -1); if (message[0] == '\0' || strstr (message_lc, "please") != NULL) { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, receive_authorized, self_and_contact_new (self, member), self_and_contact_destroy); } else { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, receive_unauthorized, self_and_contact_new (self, member), self_and_contact_destroy); } g_free (message_lc); } return TRUE; case EXAMPLE_CONTACT_LIST_PUBLISH: /* We would like member to see our presence. This is meaningless, * unless they have asked for it. */ { ExampleContactDetails *d = lookup_contact (self, member); if (d == NULL || !d->publish_requested) { /* the group mixin won't actually allow this to be reached, * because of the flags we set */ g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Can't unilaterally send presence to %s", tp_handle_inspect (self->priv->contact_repo, member)); return FALSE; } if (!d->publish) { d->publish = TRUE; d->publish_requested = FALSE; d->stored = TRUE; send_updated_roster (self, member); set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, "", set, NULL, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ((GObject *) stored, "", set, NULL, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); } } return TRUE; case EXAMPLE_CONTACT_LIST_STORED: /* we would like member to be on the roster */ { ExampleContactDetails *d = ensure_contact (self, member, NULL); d->stored = TRUE; send_updated_roster (self, member); set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, "", set, NULL, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); } return TRUE; case EXAMPLE_CONTACT_LIST_DENY: /* We would like member to be blocked */ { ExampleContactDetails *d = ensure_contact (self, member, NULL); g_message ("Blocking %s", tp_handle_inspect (self->priv->contact_repo, member)); d->blocked = TRUE; send_updated_roster (self, member); set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, "", set, NULL, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); } return TRUE; default: g_return_val_if_reached (FALSE); } } static gboolean auth_request_cb (gpointer p) { SelfAndContact *s = p; receive_auth_request (s->self, s->contact); return FALSE; } gboolean example_contact_list_manager_remove_from_list (ExampleContactListManager *self, GObject *channel, ExampleContactListHandle list, TpHandle member, const gchar *message, GError **error) { TpIntSet *set; switch (list) { case EXAMPLE_CONTACT_LIST_PUBLISH: /* we would like member not to see our presence any more, or we * would like to reject a request from them to see our presence */ { ExampleContactDetails *d = lookup_contact (self, member); if (d != NULL) { if (d->publish_requested) { g_message ("Rejecting authorization request from %s", tp_handle_inspect (self->priv->contact_repo, member)); d->publish_requested = FALSE; set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, "", NULL, set, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); } else if (d->publish) { g_message ("Removing authorization from %s", tp_handle_inspect (self->priv->contact_repo, member)); d->publish = FALSE; set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, "", NULL, set, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); /* Pretend that after a delay, the contact notices the change * and asks for our presence again */ g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, auth_request_cb, self_and_contact_new (self, member), self_and_contact_destroy); } else { /* nothing to do, avoid "updating the roster" */ return TRUE; } send_updated_roster (self, member); } } return TRUE; case EXAMPLE_CONTACT_LIST_SUBSCRIBE: /* we would like to avoid receiving member's presence any more, * or we would like to cancel an outstanding request for their * presence */ { ExampleContactDetails *d = lookup_contact (self, member); if (d != NULL) { if (d->subscribe_requested) { g_message ("Cancelling our authorization request to %s", tp_handle_inspect (self->priv->contact_repo, member)); d->subscribe_requested = FALSE; set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, "", NULL, set, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); } else if (d->subscribe) { g_message ("We no longer want presence from %s", tp_handle_inspect (self->priv->contact_repo, member)); d->subscribe = FALSE; set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, "", NULL, set, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); /* since they're no longer on the subscribe list, we can't * see their presence, so emit a signal changing it to * UNKNOWN */ g_signal_emit (self, signals[PRESENCE_UPDATED], 0, member); } else { /* nothing to do, avoid "updating the roster" */ return TRUE; } send_updated_roster (self, member); } } return TRUE; case EXAMPLE_CONTACT_LIST_STORED: /* we would like to remove member from the roster altogether */ { ExampleContactDetails *d = lookup_contact (self, member); if (d != NULL) { /* if the contact is blocked, do not completely delete it */ if (d->blocked) { d->publish = FALSE; d->publish_requested = FALSE; d->subscribe = FALSE; d->subscribe_requested = FALSE; d->stored = FALSE; } else { g_hash_table_remove (self->priv->contact_details, GUINT_TO_POINTER (member)); } send_updated_roster (self, member); set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, "", NULL, set, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ( (GObject *) self->priv->lists[EXAMPLE_CONTACT_LIST_SUBSCRIBE], "", NULL, set, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_group_mixin_change_members ( (GObject *) self->priv->lists[EXAMPLE_CONTACT_LIST_PUBLISH], "", NULL, set, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); if (!d->blocked) tp_handle_set_remove (self->priv->contacts, member); /* since they're no longer on the subscribe list, we can't * see their presence, so emit a signal changing it to * UNKNOWN */ g_signal_emit (self, signals[PRESENCE_UPDATED], 0, member); } } return TRUE; case EXAMPLE_CONTACT_LIST_DENY: /* we would like to unblock member */ { ExampleContactDetails *d = lookup_contact (self, member); if (d != NULL) { g_message ("Unblocking %s", tp_handle_inspect (self->priv->contact_repo, member)); /* if the contact is also not stored, we need to delete it */ if (!d->stored) { g_hash_table_remove (self->priv->contact_details, GUINT_TO_POINTER (member)); } else { d->blocked = FALSE; } send_updated_roster (self, member); set = tp_intset_new_containing (member); tp_group_mixin_change_members (channel, "", NULL, set, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); if (!d->stored) tp_handle_set_remove (self->priv->contacts, member); } } return TRUE; default: g_return_val_if_reached (FALSE); } } ExampleContactListPresence example_contact_list_manager_get_presence (ExampleContactListManager *self, TpHandle contact) { ExampleContactDetails *d = lookup_contact (self, contact); const gchar *id; if (d == NULL || !d->subscribe) { /* we don't know the presence of people not on the subscribe list, * by definition */ return EXAMPLE_CONTACT_LIST_PRESENCE_UNKNOWN; } id = tp_handle_inspect (self->priv->contact_repo, contact); /* In this example CM, we fake contacts' presence based on their name: * contacts in the first half of the alphabet are available, the rest * (including non-alphabetic and non-ASCII initial letters) are away. */ if ((id[0] >= 'A' && id[0] <= 'M') || (id[0] >= 'a' && id[0] <= 'm')) { return EXAMPLE_CONTACT_LIST_PRESENCE_AVAILABLE; } return EXAMPLE_CONTACT_LIST_PRESENCE_AWAY; } const gchar * example_contact_list_manager_get_alias (ExampleContactListManager *self, TpHandle contact) { ExampleContactDetails *d = lookup_contact (self, contact); if (d == NULL) { /* we don't have a user-defined alias for people not on the roster */ return tp_handle_inspect (self->priv->contact_repo, contact); } return d->alias; } void example_contact_list_manager_set_alias (ExampleContactListManager *self, TpHandle contact, const gchar *alias) { gboolean created; ExampleContactDetails *d = ensure_contact (self, contact, &created); ExampleContactList *stored = self->priv->lists[ EXAMPLE_CONTACT_LIST_STORED]; gchar *old = d->alias; TpIntSet *set; /* FIXME: if stored list hasn't been retrieved yet, queue the change for * later */ /* if shutting down, do nothing */ if (stored == NULL) return; d->alias = g_strdup (alias); d->stored = TRUE; if (created || tp_strdiff (old, alias)) send_updated_roster (self, contact); g_free (old); set = tp_intset_new_containing (contact); tp_group_mixin_change_members ((GObject *) stored, "", set, NULL, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); } telepathy-qt-0.9.6~git1/tests/lib/glib/contactlist/connection-manager.c0000664000175000017500000000553412470405660024046 0ustar jrjr/* * manager.c - an example connection manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "connection-manager.h" #include #include #include #include "conn.h" G_DEFINE_TYPE (ExampleContactListConnectionManager, example_contact_list_connection_manager, TP_TYPE_BASE_CONNECTION_MANAGER) struct _ExampleContactListConnectionManagerPrivate { int dummy; }; static void example_contact_list_connection_manager_init ( ExampleContactListConnectionManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST_CONNECTION_MANAGER, ExampleContactListConnectionManagerPrivate); } typedef struct { gchar *account; guint simulation_delay; } ExampleParams; static gboolean account_param_filter (const TpCMParamSpec *paramspec, GValue *value, GError **error) { const gchar *id = g_value_get_string (value); g_value_take_string (value, example_contact_list_normalize_contact (NULL, id, NULL, error)); if (g_value_get_string (value) == NULL) return FALSE; return TRUE; } #include "_gen/param-spec-struct.h" static gpointer alloc_params (void) { return g_slice_new0 (ExampleParams); } static void free_params (gpointer p) { ExampleParams *params = p; g_free (params->account); g_slice_free (ExampleParams, params); } static const TpCMProtocolSpec example_protocols[] = { { "example", example_contact_list_example_params, alloc_params, free_params }, { NULL, NULL } }; static TpBaseConnection * new_connection (TpBaseConnectionManager *self, const gchar *proto, TpIntSet *params_present, gpointer parsed_params, GError **error) { ExampleParams *params = parsed_params; ExampleContactListConnection *conn; conn = EXAMPLE_CONTACT_LIST_CONNECTION (g_object_new (EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, "account", params->account, "simulation-delay", params->simulation_delay, "protocol", proto, NULL)); return (TpBaseConnection *) conn; } static void example_contact_list_connection_manager_class_init ( ExampleContactListConnectionManagerClass *klass) { TpBaseConnectionManagerClass *base_class = (TpBaseConnectionManagerClass *) klass; g_type_class_add_private (klass, sizeof (ExampleContactListConnectionManagerPrivate)); base_class->new_connection = new_connection; base_class->cm_dbus_name = "example_contact_list"; base_class->protocol_params = example_protocols; } telepathy-qt-0.9.6~git1/tests/lib/glib/contact-search-chan.h0000664000175000017500000000544312470405660021561 0ustar jrjr/* * contact-search-channel.h - header for an tp_tests contact search channel * * Copyright © 2010 Collabora Ltd. * Copyright © 2010 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TP_TESTS_CONTACT_SEARCH_CHANNEL_H #define TP_TESTS_CONTACT_SEARCH_CHANNEL_H #include #include #include G_BEGIN_DECLS typedef struct _TpTestsContactSearchChannel TpTestsContactSearchChannel; typedef struct _TpTestsContactSearchChannelPrivate TpTestsContactSearchChannelPrivate; typedef struct _TpTestsContactSearchChannelClass TpTestsContactSearchChannelClass; typedef struct _TpTestsContactSearchChannelClassPrivate TpTestsContactSearchChannelClassPrivate; GType tp_tests_contact_search_channel_get_type (void); #define TP_TESTS_TYPE_CONTACT_SEARCH_CHANNEL \ (tp_tests_contact_search_channel_get_type ()) #define TP_TESTS_CONTACT_SEARCH_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_CONTACT_SEARCH_CHANNEL, \ TpTestsContactSearchChannel)) #define TP_TESTS_CONTACT_SEARCH_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_CONTACT_SEARCH_CHANNEL, \ TpTestsContactSearchChannelClass)) #define TP_TESTS_IS_CONTACT_SEARCH_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_CONTACT_SEARCH_CHANNEL)) #define TP_TESTS_IS_CONTACT_SEARCH_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_CONTACT_SEARCH_CHANNEL)) #define TP_TESTS_CONTACT_SEARCH_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_CONTACT_SEARCH_CHANNEL, \ TpTestsContactSearchChannelClass)) struct _TpTestsContactSearchChannelClass { GObjectClass parent_class; TpDBusPropertiesMixinClass dbus_properties_class; TpGroupMixinClass group_class; TpTestsContactSearchChannelClassPrivate *priv; }; struct _TpTestsContactSearchChannel { GObject parent; TpGroupMixin group; TpTestsContactSearchChannelPrivate *priv; }; G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/simple-account.h0000664000175000017500000000347512470405660020702 0ustar jrjr/* * simple-account.h - header for a simple account service. * * Copyright (C) 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_SIMPLE_ACCOUNT_H__ #define __TP_TESTS_SIMPLE_ACCOUNT_H__ #include #include G_BEGIN_DECLS typedef struct _TpTestsSimpleAccount TpTestsSimpleAccount; typedef struct _TpTestsSimpleAccountClass TpTestsSimpleAccountClass; typedef struct _TpTestsSimpleAccountPrivate TpTestsSimpleAccountPrivate; struct _TpTestsSimpleAccountClass { GObjectClass parent_class; TpDBusPropertiesMixinClass dbus_props_class; }; struct _TpTestsSimpleAccount { GObject parent; TpTestsSimpleAccountPrivate *priv; }; GType tp_tests_simple_account_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_SIMPLE_ACCOUNT \ (tp_tests_simple_account_get_type ()) #define TP_TESTS_SIMPLE_ACCOUNT(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_SIMPLE_ACCOUNT, \ TpTestsSimpleAccount)) #define TP_TESTS_SIMPLE_ACCOUNT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_SIMPLE_ACCOUNT, \ TpTestsSimpleAccountClass)) #define TP_TESTS_SIMPLE_IS_ACCOUNT(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_SIMPLE_ACCOUNT)) #define TP_TESTS_SIMPLE_IS_ACCOUNT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_SIMPLE_ACCOUNT)) #define TP_TESTS_SIMPLE_ACCOUNT_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_SIMPLE_ACCOUNT, \ TpTestsSimpleAccountClass)) G_END_DECLS #endif /* #ifndef __TP_TESTS_SIMPLE_ACCOUNT_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/0000775000175000017500000000000012470405660016575 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/echo2/connection-manager.h0000664000175000017500000000416512470405660022523 0ustar jrjr/* * manager.h - header for an example connection manager * Copyright (C) 2007 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef EXAMPLE_ECHO_MESSAGE_PARTS_MANAGER_H #define EXAMPLE_ECHO_MESSAGE_PARTS_MANAGER_H #include #include G_BEGIN_DECLS typedef struct _ExampleEcho2ConnectionManager ExampleEcho2ConnectionManager; typedef struct _ExampleEcho2ConnectionManagerPrivate ExampleEcho2ConnectionManagerPrivate; typedef struct _ExampleEcho2ConnectionManagerClass ExampleEcho2ConnectionManagerClass; typedef struct _ExampleEcho2ConnectionManagerClassPrivate ExampleEcho2ConnectionManagerClassPrivate; struct _ExampleEcho2ConnectionManagerClass { TpBaseConnectionManagerClass parent_class; ExampleEcho2ConnectionManagerClassPrivate *priv; }; struct _ExampleEcho2ConnectionManager { TpBaseConnectionManager parent; ExampleEcho2ConnectionManagerPrivate *priv; }; GType example_echo_2_connection_manager_get_type (void); #define EXAMPLE_TYPE_ECHO_2_CONNECTION_MANAGER \ (example_echo_2_connection_manager_get_type ()) #define EXAMPLE_ECHO_2_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ EXAMPLE_TYPE_ECHO_2_CONNECTION_MANAGER, \ ExampleEcho2ConnectionManager)) #define EXAMPLE_ECHO_2_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ EXAMPLE_TYPE_ECHO_2_CONNECTION_MANAGER, \ ExampleEcho2ConnectionManagerClass)) #define EXAMPLE_IS_ECHO_2_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ EXAMPLE_TYPE_ECHO_2_CONNECTION_MANAGER)) #define EXAMPLE_IS_ECHO_2_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ EXAMPLE_TYPE_ECHO_2_CONNECTION_MANAGER)) #define EXAMPLE_ECHO_2_CONNECTION_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ EXAMPLE_TYPE_ECHO_2_CONNECTION_MANAGER, \ ExampleEcho2ConnectionManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/conn.h0000664000175000017500000000373012470405660017706 0ustar jrjr/* * conn.h - header for an example connection * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef EXAMPLE_ECHO_MESSAGE_PARTS_CONN_H #define EXAMPLE_ECHO_MESSAGE_PARTS_CONN_H #include #include G_BEGIN_DECLS typedef struct _ExampleEcho2Connection ExampleEcho2Connection; typedef struct _ExampleEcho2ConnectionClass ExampleEcho2ConnectionClass; typedef struct _ExampleEcho2ConnectionPrivate ExampleEcho2ConnectionPrivate; struct _ExampleEcho2ConnectionClass { TpBaseConnectionClass parent_class; }; struct _ExampleEcho2Connection { TpBaseConnection parent; ExampleEcho2ConnectionPrivate *priv; }; GType example_echo_2_connection_get_type (void); #define EXAMPLE_TYPE_ECHO_2_CONNECTION \ (example_echo_2_connection_get_type ()) #define EXAMPLE_ECHO_2_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_ECHO_2_CONNECTION, \ ExampleEcho2Connection)) #define EXAMPLE_ECHO_2_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_ECHO_2_CONNECTION, \ ExampleEcho2ConnectionClass)) #define EXAMPLE_IS_ECHO_2_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_ECHO_2_CONNECTION)) #define EXAMPLE_IS_ECHO_2_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_ECHO_2_CONNECTION)) #define EXAMPLE_ECHO_2_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_2_CONNECTION, \ ExampleEcho2ConnectionClass)) const gchar * const *example_echo_2_connection_get_guaranteed_interfaces ( void); const gchar * const *example_echo_2_connection_get_possible_interfaces ( void); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/CMakeLists.txt0000664000175000017500000000102512470405660021333 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) set(example_cm_echo2_SRCS chan.c chan.h conn.c connection-manager.c connection-manager.h conn.h im-manager.c im-manager.h protocol.c protocol.h) add_library(example-cm-echo2 STATIC ${example_cm_echo2_SRCS}) target_link_libraries(example-cm-echo2 ${TPGLIB_LIBRARIES}) tpqt_generate_manager_file(${CMAKE_CURRENT_SOURCE_DIR}/manager-file.py example_echo_2.manager connection-manager.c) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/manager-file.py0000664000175000017500000000077312470405660021505 0ustar jrjr# Input for tools/manager-file.py MANAGER = 'example_echo_2' PARAMS = { 'example' : { 'account': { 'dtype': 's', 'flags': 'required register', 'filter': 'tp_cm_param_filter_string_nonempty', # 'filter_data': 'NULL', # 'default': ..., # 'struct_field': '...', # 'setter_data': 'NULL', }, }, } STRUCTS = { 'example': None } telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/chan.h0000664000175000017500000000351512470405660017663 0ustar jrjr/* * chan.h - header for an example channel * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef EXAMPLE_ECHO_MESSAGE_PARTS_CHAN_H #define EXAMPLE_ECHO_MESSAGE_PARTS_CHAN_H #include #include #include G_BEGIN_DECLS typedef struct _ExampleEcho2Channel ExampleEcho2Channel; typedef struct _ExampleEcho2ChannelClass ExampleEcho2ChannelClass; typedef struct _ExampleEcho2ChannelPrivate ExampleEcho2ChannelPrivate; GType example_echo_2_channel_get_type (void); #define EXAMPLE_TYPE_ECHO_2_CHANNEL \ (example_echo_2_channel_get_type ()) #define EXAMPLE_ECHO_2_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_ECHO_2_CHANNEL, \ ExampleEcho2Channel)) #define EXAMPLE_ECHO_2_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_ECHO_2_CHANNEL, \ ExampleEcho2ChannelClass)) #define EXAMPLE_IS_ECHO_2_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_ECHO_2_CHANNEL)) #define EXAMPLE_IS_ECHO_2_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_ECHO_2_CHANNEL)) #define EXAMPLE_ECHO_2_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_2_CHANNEL, \ ExampleEcho2ChannelClass)) struct _ExampleEcho2ChannelClass { GObjectClass parent_class; TpDBusPropertiesMixinClass dbus_properties_class; }; struct _ExampleEcho2Channel { GObject parent; TpMessageMixin text; ExampleEcho2ChannelPrivate *priv; }; G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/conn.c0000664000175000017500000001246112470405660017702 0ustar jrjr/* * conn.c - an example connection * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "conn.h" #include #include #include #include "im-manager.h" #include "protocol.h" G_DEFINE_TYPE (ExampleEcho2Connection, example_echo_2_connection, TP_TYPE_BASE_CONNECTION) enum { PROP_ACCOUNT = 1, N_PROPS }; struct _ExampleEcho2ConnectionPrivate { gchar *account; }; static void example_echo_2_connection_init (ExampleEcho2Connection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_2_CONNECTION, ExampleEcho2ConnectionPrivate); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { ExampleEcho2Connection *self = EXAMPLE_ECHO_2_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_value_set_string (value, self->priv->account); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *spec) { ExampleEcho2Connection *self = EXAMPLE_ECHO_2_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_free (self->priv->account); self->priv->account = g_utf8_strdown (g_value_get_string (value), -1); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void finalize (GObject *object) { ExampleEcho2Connection *self = EXAMPLE_ECHO_2_CONNECTION (object); g_free (self->priv->account); G_OBJECT_CLASS (example_echo_2_connection_parent_class)->finalize (object); } static gchar * get_unique_connection_name (TpBaseConnection *conn) { ExampleEcho2Connection *self = EXAMPLE_ECHO_2_CONNECTION (conn); return g_strdup (self->priv->account); } static gchar * example_normalize_contact (TpHandleRepoIface *repo G_GNUC_UNUSED, const gchar *id, gpointer context G_GNUC_UNUSED, GError **error) { return example_echo_2_protocol_normalize_contact (id, error); } static void create_handle_repos (TpBaseConnection *conn, TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]) { repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_CONTACT, example_normalize_contact, NULL); } static GPtrArray * create_channel_managers (TpBaseConnection *conn) { GPtrArray *ret = g_ptr_array_sized_new (1); g_ptr_array_add (ret, g_object_new (EXAMPLE_TYPE_ECHO_2_IM_MANAGER, "connection", conn, NULL)); return ret; } static gboolean start_connecting (TpBaseConnection *conn, GError **error) { ExampleEcho2Connection *self = EXAMPLE_ECHO_2_CONNECTION (conn); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); /* In a real connection manager we'd ask the underlying implementation to * start connecting, then go to state CONNECTED when finished, but here * we can do it immediately. */ conn->self_handle = tp_handle_ensure (contact_repo, self->priv->account, NULL, NULL); tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); return TRUE; } static void shut_down (TpBaseConnection *conn) { /* In a real connection manager we'd ask the underlying implementation to * start shutting down, then call this function when finished, but here * we can do it immediately. */ tp_base_connection_finish_shutdown (conn); } static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_REQUESTS, NULL }; const gchar * const * example_echo_2_connection_get_possible_interfaces (void) { /* in this example CM we don't have any extra interfaces that are sometimes, * but not always, present */ return interfaces_always_present; } static void example_echo_2_connection_class_init (ExampleEcho2ConnectionClass *klass) { TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; object_class->get_property = get_property; object_class->set_property = set_property; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (ExampleEcho2ConnectionPrivate)); base_class->create_handle_repos = create_handle_repos; base_class->get_unique_connection_name = get_unique_connection_name; base_class->create_channel_managers = create_channel_managers; base_class->start_connecting = start_connecting; base_class->shut_down = shut_down; base_class->interfaces_always_present = interfaces_always_present; param_spec = g_param_spec_string ("account", "Account name", "The username of this user", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); } telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/protocol.h0000664000175000017500000000364712470405660020621 0ustar jrjr/* * protocol.h - header for an example Protocol * Copyright (C) 2007-2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef EXAMPLE_ECHO_MESSAGE_PARTS_PROTOCOL_H #define EXAMPLE_ECHO_MESSAGE_PARTS_PROTOCOL_H #include #include G_BEGIN_DECLS typedef struct _ExampleEcho2Protocol ExampleEcho2Protocol; typedef struct _ExampleEcho2ProtocolPrivate ExampleEcho2ProtocolPrivate; typedef struct _ExampleEcho2ProtocolClass ExampleEcho2ProtocolClass; typedef struct _ExampleEcho2ProtocolClassPrivate ExampleEcho2ProtocolClassPrivate; struct _ExampleEcho2ProtocolClass { TpBaseProtocolClass parent_class; ExampleEcho2ProtocolClassPrivate *priv; }; struct _ExampleEcho2Protocol { TpBaseProtocol parent; ExampleEcho2ProtocolPrivate *priv; }; GType example_echo_2_protocol_get_type (void); #define EXAMPLE_TYPE_ECHO_2_PROTOCOL \ (example_echo_2_protocol_get_type ()) #define EXAMPLE_ECHO_2_PROTOCOL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ EXAMPLE_TYPE_ECHO_2_PROTOCOL, \ ExampleEcho2Protocol)) #define EXAMPLE_ECHO_2_PROTOCOL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ EXAMPLE_TYPE_ECHO_2_PROTOCOL, \ ExampleEcho2ProtocolClass)) #define EXAMPLE_IS_ECHO_2_PROTOCOL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ EXAMPLE_TYPE_ECHO_2_PROTOCOL)) #define EXAMPLE_IS_ECHO_2_PROTOCOL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ EXAMPLE_TYPE_ECHO_2_PROTOCOL)) #define EXAMPLE_ECHO_2_PROTOCOL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ EXAMPLE_TYPE_ECHO_2_PROTOCOL, \ ExampleEcho2ProtocolClass)) gchar *example_echo_2_protocol_normalize_contact (const gchar *id, GError **error); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/im-manager.h0000664000175000017500000000341112470405660020762 0ustar jrjr/* * manager.h - header for an example channel manager * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef EXAMPLE_ECHO_MESSAGE_PARTS_IM_MANAGER_H #define EXAMPLE_ECHO_MESSAGE_PARTS_IM_MANAGER_H #include G_BEGIN_DECLS typedef struct _ExampleEcho2ImManager ExampleEcho2ImManager; typedef struct _ExampleEcho2ImManagerClass ExampleEcho2ImManagerClass; typedef struct _ExampleEcho2ImManagerPrivate ExampleEcho2ImManagerPrivate; struct _ExampleEcho2ImManagerClass { GObjectClass parent_class; }; struct _ExampleEcho2ImManager { GObject parent; ExampleEcho2ImManagerPrivate *priv; }; GType example_echo_2_im_manager_get_type (void); /* TYPE MACROS */ #define EXAMPLE_TYPE_ECHO_2_IM_MANAGER \ (example_echo_2_im_manager_get_type ()) #define EXAMPLE_ECHO_2_IM_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_ECHO_2_IM_MANAGER, \ ExampleEcho2ImManager)) #define EXAMPLE_ECHO_2_IM_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_ECHO_2_IM_MANAGER, \ ExampleEcho2ImManagerClass)) #define EXAMPLE_IS_ECHO_2_IM_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_ECHO_2_IM_MANAGER)) #define EXAMPLE_IS_ECHO_2_IM_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_ECHO_2_IM_MANAGER)) #define EXAMPLE_ECHO_2_IM_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_2_IM_MANAGER, \ ExampleEcho2ImManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/chan.c0000664000175000017500000004672112470405660017664 0ustar jrjr/* * chan.c - an example text channel talking to a particular * contact. Similar code is used for 1-1 IM channels in many protocols * (IRC private messages ("/query"), XMPP IM etc.) * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "chan.h" #include #include #include #include static void channel_iface_init (gpointer iface, gpointer data); static void chat_state_iface_init (gpointer iface, gpointer data); static void destroyable_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (ExampleEcho2Channel, example_echo_2_channel, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, tp_message_mixin_text_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MESSAGES, tp_message_mixin_messages_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CHAT_STATE, chat_state_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DESTROYABLE, destroyable_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL)) /* type definition stuff */ enum { PROP_OBJECT_PATH = 1, PROP_CHANNEL_TYPE, PROP_HANDLE_TYPE, PROP_HANDLE, PROP_TARGET_ID, PROP_REQUESTED, PROP_INITIATOR_HANDLE, PROP_INITIATOR_ID, PROP_CONNECTION, PROP_INTERFACES, PROP_CHANNEL_DESTROYED, PROP_CHANNEL_PROPERTIES, N_PROPS }; struct _ExampleEcho2ChannelPrivate { TpBaseConnection *conn; gchar *object_path; TpHandle handle; TpHandle initiator; /* These are really booleans, but gboolean is signed. Thanks, GLib */ unsigned closed:1; unsigned disposed:1; }; static const char * example_echo_2_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_MESSAGES, TP_IFACE_CHANNEL_INTERFACE_CHAT_STATE, TP_IFACE_CHANNEL_INTERFACE_DESTROYABLE, NULL }; static void example_echo_2_channel_init (ExampleEcho2Channel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_2_CHANNEL, ExampleEcho2ChannelPrivate); } static void send_message (GObject *object, TpMessage *message, TpMessageSendingFlags flags) { ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (object); time_t timestamp = time (NULL); guint len = tp_message_count_parts (message); const gchar *content = NULL; TpMessage *received = NULL; guint i; if (tp_asv_get_string (tp_message_peek (message, 0), "interface") != NULL) { /* this message is interface-specific - let's not echo it */ goto finally; } content = tp_asv_get_string (tp_message_peek (message, 1), "content"); if (content && strstr (content, "(fail)") != NULL) { TpMessage *delivery_report = tp_cm_message_new (self->priv->conn, 1); tp_cm_message_set_sender (delivery_report, self->priv->handle); tp_message_set_uint32 (delivery_report, 0, "message-type", TP_CHANNEL_TEXT_MESSAGE_TYPE_DELIVERY_REPORT); tp_message_set_int64 (delivery_report, 0, "message-received", timestamp); tp_message_set_uint32 (delivery_report, 0, "delivery-status", TP_DELIVERY_STATUS_PERMANENTLY_FAILED); tp_message_set_uint32 (delivery_report, 0, "delivery-error", TP_CHANNEL_TEXT_SEND_ERROR_PERMISSION_DENIED); tp_message_set_string (delivery_report, 0, "delivery-error-message", "You asked for it"); tp_message_set_string (delivery_report, 0, "delivery-token", "1111"); tp_cm_message_take_message (delivery_report, 0, "delivery-echo", message); tp_message_mixin_take_received (object, delivery_report); return; } received = tp_cm_message_new (self->priv->conn, 1); /* Copy/modify the headers for the "received" message */ { TpChannelTextMessageType message_type; gboolean valid; tp_cm_message_set_sender (received, self->priv->handle); tp_message_set_string (received, 0, "message-token", "0000"); tp_message_set_string (received, 0, "supersedes", "1234"); if (!tp_message_mixin_has_pending_messages (object, NULL)) tp_message_set_boolean (received, 0, "scrollback", TRUE); message_type = tp_asv_get_uint32 (tp_message_peek (message, 0), "message-type", &valid); /* The check for 'valid' means that if message-type is missing or of the * wrong type, fall back to NORMAL (this is in fact a no-op, since * NORMAL == 0 and tp_asv_get_uint32 returns 0 on missing or wrongly * typed values) */ if (valid && message_type != TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL) tp_message_set_uint32 (received, 0, "message-type", message_type); tp_message_set_uint32 (received, 0, "message-sent", timestamp); tp_message_set_uint32 (received, 0, "message-received", timestamp); } /* Copy the content for the "received" message */ for (i = 1; i < len; i++) { const GHashTable *input = tp_message_peek (message, i); const gchar *s; const GValue *value; guint j; /* in this example we ignore interface-specific parts */ s = tp_asv_get_string (input, "content-type"); if (s == NULL) continue; s = tp_asv_get_string (input, "interface"); if (s != NULL) continue; /* OK, we want to copy this part */ j = tp_message_append_part (received); s = tp_asv_get_string (input, "content-type"); g_assert (s != NULL); /* already checked */ tp_message_set_string (received, j, "content-type", s); s = tp_asv_get_string (input, "identifier"); if (s != NULL) tp_message_set_string (received, j, "identifier", s); s = tp_asv_get_string (input, "alternative"); if (s != NULL) tp_message_set_string (received, j, "alternative", s); s = tp_asv_get_string (input, "lang"); if (s != NULL) tp_message_set_string (received, j, "lang", s); value = tp_asv_lookup (input, "content"); if (value != NULL) tp_message_set (received, j, "content", value); } finally: /* "OK, we've sent the message" (after calling this, message must not be * dereferenced) */ tp_message_mixin_sent (object, message, flags, "", NULL); if (received != NULL) { /* Pretend the other user sent us back the same message. After this call, * the received message is owned by the mixin */ tp_message_mixin_take_received (object, received); } } static GObject * constructor (GType type, guint n_props, GObjectConstructParam *props) { GObject *object = G_OBJECT_CLASS (example_echo_2_channel_parent_class)->constructor (type, n_props, props); ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (object); static TpChannelTextMessageType const types[] = { TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION, TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE }; static const char * const content_types[] = { "*/*", NULL }; tp_dbus_daemon_register_object ( tp_base_connection_get_dbus_daemon (self->priv->conn), self->priv->object_path, self); tp_message_mixin_init (object, G_STRUCT_OFFSET (ExampleEcho2Channel, text), self->priv->conn); tp_message_mixin_implement_sending (object, send_message, (sizeof (types) / sizeof (types[0])), types, TP_MESSAGE_PART_SUPPORT_FLAG_ONE_ATTACHMENT | TP_MESSAGE_PART_SUPPORT_FLAG_MULTIPLE_ATTACHMENTS, TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_FAILURES, content_types); return object; } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: g_value_set_string (value, self->priv->object_path); break; case PROP_CHANNEL_TYPE: g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT); break; case PROP_HANDLE_TYPE: g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); break; case PROP_HANDLE: g_value_set_uint (value, self->priv->handle); break; case PROP_TARGET_ID: { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( self->priv->conn, TP_HANDLE_TYPE_CONTACT); g_value_set_string (value, tp_handle_inspect (contact_repo, self->priv->handle)); } break; case PROP_REQUESTED: g_value_set_boolean (value, (self->priv->initiator == self->priv->conn->self_handle)); break; case PROP_INITIATOR_HANDLE: g_value_set_uint (value, self->priv->initiator); break; case PROP_INITIATOR_ID: { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( self->priv->conn, TP_HANDLE_TYPE_CONTACT); g_value_set_string (value, self->priv->initiator == 0 ? "" : tp_handle_inspect (contact_repo, self->priv->initiator)); } break; case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; case PROP_INTERFACES: g_value_set_boxed (value, example_echo_2_channel_interfaces); break; case PROP_CHANNEL_DESTROYED: g_value_set_boolean (value, self->priv->closed); break; case PROP_CHANNEL_PROPERTIES: g_value_take_boxed (value, tp_dbus_properties_mixin_make_properties_hash (object, TP_IFACE_CHANNEL, "ChannelType", TP_IFACE_CHANNEL, "TargetHandleType", TP_IFACE_CHANNEL, "TargetHandle", TP_IFACE_CHANNEL, "TargetID", TP_IFACE_CHANNEL, "InitiatorHandle", TP_IFACE_CHANNEL, "InitiatorID", TP_IFACE_CHANNEL, "Requested", TP_IFACE_CHANNEL, "Interfaces", NULL)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: g_free (self->priv->object_path); self->priv->object_path = g_value_dup_string (value); break; case PROP_HANDLE: /* we don't ref it here because we don't necessarily have access to the * contact repo yet - instead we ref it in the constructor. */ self->priv->handle = g_value_get_uint (value); break; case PROP_INITIATOR_HANDLE: /* likewise */ self->priv->initiator = g_value_get_uint (value); break; case PROP_HANDLE_TYPE: case PROP_CHANNEL_TYPE: /* these properties are writable in the interface, but not actually * meaningfully changable on this channel, so we do nothing */ break; case PROP_CONNECTION: self->priv->conn = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dispose (GObject *object) { ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (object); if (self->priv->disposed) return; self->priv->disposed = TRUE; if (!self->priv->closed) { self->priv->closed = TRUE; tp_svc_channel_emit_closed (self); } ((GObjectClass *) example_echo_2_channel_parent_class)->dispose (object); } static void finalize (GObject *object) { ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (object); g_free (self->priv->object_path); tp_message_mixin_finalize (object); ((GObjectClass *) example_echo_2_channel_parent_class)->finalize (object); } static void example_echo_2_channel_class_init (ExampleEcho2ChannelClass *klass) { static TpDBusPropertiesMixinPropImpl channel_props[] = { { "TargetHandleType", "handle-type", NULL }, { "TargetHandle", "handle", NULL }, { "ChannelType", "channel-type", NULL }, { "Interfaces", "interfaces", NULL }, { "TargetID", "target-id", NULL }, { "Requested", "requested", NULL }, { "InitiatorHandle", "initiator-handle", NULL }, { "InitiatorID", "initiator-id", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CHANNEL, tp_dbus_properties_mixin_getter_gobject_properties, NULL, channel_props, }, { NULL } }; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (ExampleEcho2ChannelPrivate)); object_class->constructor = constructor; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path"); g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type"); g_object_class_override_property (object_class, PROP_HANDLE, "handle"); g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, "channel-destroyed"); g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, "channel-properties"); param_spec = g_param_spec_object ("connection", "TpBaseConnection object", "Connection object that owns this channel", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "Additional Channel.Interface.* interfaces", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_string ("target-id", "Peer's ID", "The string obtained by inspecting the target handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", "The contact who initiated the channel", 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, param_spec); param_spec = g_param_spec_string ("initiator-id", "Initiator's ID", "The string obtained by inspecting the initiator-handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_ID, param_spec); param_spec = g_param_spec_boolean ("requested", "Requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); klass->dbus_properties_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleEcho2ChannelClass, dbus_properties_class)); tp_message_mixin_init_dbus_properties (object_class); } static void example_echo_2_channel_close (ExampleEcho2Channel *self) { GObject *object = (GObject *) self; if (!self->priv->closed) { TpHandle first_sender; /* The manager wants to be able to respawn the channel if it has pending * messages. When respawned, the channel must have the initiator set * to the contact who sent us those messages (if it isn't already), * and the messages must be marked as having been rescued so they * don't get logged twice. */ if (tp_message_mixin_has_pending_messages (object, &first_sender)) { if (self->priv->initiator != first_sender) { self->priv->initiator = first_sender; } tp_message_mixin_set_rescued (object); } else { /* No pending messages, so it's OK to really close */ self->priv->closed = TRUE; } tp_svc_channel_emit_closed (self); } } static void channel_close (TpSvcChannel *iface, DBusGMethodInvocation *context) { ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (iface); example_echo_2_channel_close (self); tp_svc_channel_return_from_close (context); } static void channel_get_channel_type (TpSvcChannel *iface, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_channel_type (context, TP_IFACE_CHANNEL_TYPE_TEXT); } static void channel_get_handle (TpSvcChannel *iface, DBusGMethodInvocation *context) { ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (iface); tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT, self->priv->handle); } static void channel_get_interfaces (TpSvcChannel *iface, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_interfaces (context, example_echo_2_channel_interfaces); } static void channel_iface_init (gpointer iface, gpointer data) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x) IMPLEMENT (close); IMPLEMENT (get_channel_type); IMPLEMENT (get_handle); IMPLEMENT (get_interfaces); #undef IMPLEMENT } static void chat_state_set_chat_state(TpSvcChannelInterfaceChatState *iface, guint state, DBusGMethodInvocation *context) { ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (iface); GError *error = NULL; if (state >= NUM_TP_CHANNEL_CHAT_STATES) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "invalid state: %u", state); dbus_g_method_return_error (context, error); g_error_free (error); return; } tp_svc_channel_interface_chat_state_emit_chat_state_changed ( iface, self->priv->conn->self_handle, state); tp_svc_channel_interface_chat_state_return_from_set_chat_state (context); } static void chat_state_iface_init (gpointer iface, gpointer data) { TpSvcChannelInterfaceChatStateClass *klass = iface; #define IMPLEMENT(x) \ tp_svc_channel_interface_chat_state_implement_##x (klass, chat_state_##x) IMPLEMENT (set_chat_state); #undef IMPLEMENT } static void destroyable_destroy (TpSvcChannelInterfaceDestroyable *iface, DBusGMethodInvocation *context) { ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (iface); tp_message_mixin_clear ((GObject *) self); example_echo_2_channel_close (self); g_assert (self->priv->closed); tp_svc_channel_interface_destroyable_return_from_destroy (context); } static void destroyable_iface_init (gpointer iface, gpointer data) { TpSvcChannelInterfaceDestroyableClass *klass = iface; #define IMPLEMENT(x) \ tp_svc_channel_interface_destroyable_implement_##x (klass, destroyable_##x) IMPLEMENT (destroy); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/connection-manager.c0000664000175000017500000000426512470405660022517 0ustar jrjr/* * manager.c - an example connection manager * * Copyright © 2007-2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "connection-manager.h" #include #include #include #include "protocol.h" G_DEFINE_TYPE (ExampleEcho2ConnectionManager, example_echo_2_connection_manager, TP_TYPE_BASE_CONNECTION_MANAGER) /* type definition stuff */ static void example_echo_2_connection_manager_init ( ExampleEcho2ConnectionManager *self) { } static void example_echo_2_connection_manager_constructed (GObject *object) { ExampleEcho2ConnectionManager *self = EXAMPLE_ECHO_2_CONNECTION_MANAGER (object); TpBaseConnectionManager *base = (TpBaseConnectionManager *) self; void (*constructed) (GObject *) = ((GObjectClass *) example_echo_2_connection_manager_parent_class)->constructed; TpBaseProtocol *protocol; if (constructed != NULL) constructed (object); protocol = g_object_new (EXAMPLE_TYPE_ECHO_2_PROTOCOL, "name", "example", NULL); tp_base_connection_manager_add_protocol (base, protocol); g_object_unref (protocol); } static const TpCMProtocolSpec no_protocols[] = { { NULL, NULL } }; static TpBaseConnection * new_connection (TpBaseConnectionManager *self, const gchar *proto, TpIntSet *params_present, gpointer parsed_params, GError **error) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Protocol's new_connection() should be called instead"); return NULL; } static void example_echo_2_connection_manager_class_init ( ExampleEcho2ConnectionManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); TpBaseConnectionManagerClass *base_class = (TpBaseConnectionManagerClass *) klass; object_class->constructed = example_echo_2_connection_manager_constructed; base_class->new_connection = new_connection; base_class->cm_dbus_name = "example_echo_2"; base_class->protocol_params = no_protocols; } telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/im-manager.c0000664000175000017500000002466612470405660020774 0ustar jrjr/* * im-manager.c - an example channel manager for channels talking to a * particular contact. Similar code is used for 1-1 IM channels in many * protocols (IRC private messages ("/query"), XMPP IM etc.) * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "im-manager.h" #include #include #include "chan.h" static void channel_manager_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (ExampleEcho2ImManager, example_echo_2_im_manager, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, channel_manager_iface_init)) /* type definition stuff */ enum { PROP_CONNECTION = 1, N_PROPS }; struct _ExampleEcho2ImManagerPrivate { TpBaseConnection *conn; /* GUINT_TO_POINTER (handle) => ExampleEcho2Channel */ GHashTable *channels; gulong status_changed_id; }; static void example_echo_2_im_manager_init (ExampleEcho2ImManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_2_IM_MANAGER, ExampleEcho2ImManagerPrivate); self->priv->channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); } static void example_echo_2_im_manager_close_all (ExampleEcho2ImManager *self); static void dispose (GObject *object) { ExampleEcho2ImManager *self = EXAMPLE_ECHO_2_IM_MANAGER (object); example_echo_2_im_manager_close_all (self); g_assert (self->priv->channels == NULL); ((GObjectClass *) example_echo_2_im_manager_parent_class)->dispose (object); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleEcho2ImManager *self = EXAMPLE_ECHO_2_IM_MANAGER (object); switch (property_id) { case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleEcho2ImManager *self = EXAMPLE_ECHO_2_IM_MANAGER (object); switch (property_id) { case PROP_CONNECTION: /* We don't ref the connection, because it owns a reference to the * channel manager, and it guarantees that the manager's lifetime is * less than its lifetime */ self->priv->conn = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void status_changed_cb (TpBaseConnection *conn, guint status, guint reason, ExampleEcho2ImManager *self) { if (status == TP_CONNECTION_STATUS_DISCONNECTED) example_echo_2_im_manager_close_all (self); } static void constructed (GObject *object) { ExampleEcho2ImManager *self = EXAMPLE_ECHO_2_IM_MANAGER (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_echo_2_im_manager_parent_class)->constructed; if (chain_up != NULL) { chain_up (object); } self->priv->status_changed_id = g_signal_connect (self->priv->conn, "status-changed", (GCallback) status_changed_cb, self); } static void example_echo_2_im_manager_class_init (ExampleEcho2ImManagerClass *klass) { GParamSpec *param_spec; GObjectClass *object_class = (GObjectClass *) klass; object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; param_spec = g_param_spec_object ("connection", "Connection object", "The connection that owns this channel manager", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); g_type_class_add_private (klass, sizeof (ExampleEcho2ImManagerPrivate)); } static void example_echo_2_im_manager_close_all (ExampleEcho2ImManager *self) { if (self->priv->channels != NULL) { GHashTable *tmp = self->priv->channels; self->priv->channels = NULL; g_hash_table_destroy (tmp); } if (self->priv->status_changed_id != 0) { g_signal_handler_disconnect (self->priv->conn, self->priv->status_changed_id); self->priv->status_changed_id = 0; } } static void example_echo_2_im_manager_foreach_channel (TpChannelManager *iface, TpExportableChannelFunc callback, gpointer user_data) { ExampleEcho2ImManager *self = EXAMPLE_ECHO_2_IM_MANAGER (iface); GHashTableIter iter; gpointer handle, channel; g_hash_table_iter_init (&iter, self->priv->channels); while (g_hash_table_iter_next (&iter, &handle, &channel)) { callback (TP_EXPORTABLE_CHANNEL (channel), user_data); } } static void channel_closed_cb (ExampleEcho2Channel *chan, ExampleEcho2ImManager *self) { tp_channel_manager_emit_channel_closed_for_object (self, TP_EXPORTABLE_CHANNEL (chan)); if (self->priv->channels != NULL) { TpHandle handle; gboolean really_destroyed; g_object_get (chan, "handle", &handle, "channel-destroyed", &really_destroyed, NULL); /* Re-announce the channel if it's not yet ready to go away (pending * messages) */ if (really_destroyed) { g_hash_table_remove (self->priv->channels, GUINT_TO_POINTER (handle)); } else { tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan), NULL); } } } static void new_channel (ExampleEcho2ImManager *self, TpHandle handle, TpHandle initiator, gpointer request_token) { ExampleEcho2Channel *chan; gchar *object_path; GSList *requests = NULL; object_path = g_strdup_printf ("%s/Echo2Channel%u", self->priv->conn->object_path, handle); chan = g_object_new (EXAMPLE_TYPE_ECHO_2_CHANNEL, "connection", self->priv->conn, "object-path", object_path, "handle", handle, "initiator-handle", initiator, NULL); g_free (object_path); g_signal_connect (chan, "closed", (GCallback) channel_closed_cb, self); g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle), chan); if (request_token != NULL) requests = g_slist_prepend (requests, request_token); tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan), requests); g_slist_free (requests); } static const gchar * const fixed_properties[] = { TP_PROP_CHANNEL_CHANNEL_TYPE, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL }; static const gchar * const allowed_properties[] = { TP_PROP_CHANNEL_TARGET_HANDLE, TP_PROP_CHANNEL_TARGET_ID, NULL }; static void example_echo_2_im_manager_type_foreach_channel_class (GType type, TpChannelManagerTypeChannelClassFunc func, gpointer user_data) { GHashTable *table = tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, NULL); func (type, table, allowed_properties, user_data); g_hash_table_destroy (table); } static gboolean example_echo_2_im_manager_request (ExampleEcho2ImManager *self, gpointer request_token, GHashTable *request_properties, gboolean require_new) { TpHandle handle; ExampleEcho2Channel *chan; GError *error = NULL; if (tp_strdiff (tp_asv_get_string (request_properties, TP_PROP_CHANNEL_CHANNEL_TYPE), TP_IFACE_CHANNEL_TYPE_TEXT)) { return FALSE; } if (tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != TP_HANDLE_TYPE_CONTACT) { return FALSE; } handle = tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE, NULL); g_assert (handle != 0); if (tp_channel_manager_asv_has_unknown_properties (request_properties, fixed_properties, allowed_properties, &error)) { goto error; } chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle)); if (chan == NULL) { new_channel (self, handle, self->priv->conn->self_handle, request_token); } else if (require_new) { g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "An echo2 channel to contact #%u already exists", handle); goto error; } else { tp_channel_manager_emit_request_already_satisfied (self, request_token, TP_EXPORTABLE_CHANNEL (chan)); } return TRUE; error: tp_channel_manager_emit_request_failed (self, request_token, error->domain, error->code, error->message); g_error_free (error); return TRUE; } static gboolean example_echo_2_im_manager_create_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_echo_2_im_manager_request (EXAMPLE_ECHO_2_IM_MANAGER (manager), request_token, request_properties, TRUE); } static gboolean example_echo_2_im_manager_ensure_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_echo_2_im_manager_request (EXAMPLE_ECHO_2_IM_MANAGER (manager), request_token, request_properties, FALSE); } static void channel_manager_iface_init (gpointer g_iface, gpointer data G_GNUC_UNUSED) { TpChannelManagerIface *iface = g_iface; iface->foreach_channel = example_echo_2_im_manager_foreach_channel; iface->type_foreach_channel_class = example_echo_2_im_manager_type_foreach_channel_class; iface->create_channel = example_echo_2_im_manager_create_channel; iface->ensure_channel = example_echo_2_im_manager_ensure_channel; /* In this channel manager, Request has the same semantics as Ensure */ iface->request_channel = example_echo_2_im_manager_ensure_channel; } telepathy-qt-0.9.6~git1/tests/lib/glib/echo2/protocol.c0000664000175000017500000002327212470405660020610 0ustar jrjr/* * protocol.c - an example Protocol * * Copyright © 2007-2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "protocol.h" #include #include "conn.h" #include "im-manager.h" #include static void addressing_iface_init (TpProtocolAddressingInterface *iface); G_DEFINE_TYPE_WITH_CODE (ExampleEcho2Protocol, example_echo_2_protocol, TP_TYPE_BASE_PROTOCOL, G_IMPLEMENT_INTERFACE (TP_TYPE_PROTOCOL_ADDRESSING, addressing_iface_init); ) const gchar * const protocol_interfaces[] = { TP_IFACE_PROTOCOL_INTERFACE_ADDRESSING, TP_IFACE_PROTOCOL_INTERFACE_AVATARS, TP_IFACE_PROTOCOL_INTERFACE_PRESENCE, NULL }; const gchar * const supported_avatar_mime_types[] = { "image/png", "image/jpeg", "image/gif", NULL }; const gchar * const addressable_vcard_fields[] = { "x-echo2", NULL }; const gchar * const addressable_uri_schemes[] = { "echo2", NULL }; struct _ExampleEcho2ProtocolPrivate { TpPresenceStatusSpec *statuses; }; static TpPresenceStatusSpec new_status_spec (const gchar *name, TpConnectionPresenceType type, gboolean settable, gboolean can_have_message) { TpPresenceStatusSpec ret; TpPresenceStatusOptionalArgumentSpec *args = g_new0 (TpPresenceStatusOptionalArgumentSpec, 2); memset (&ret, 0, sizeof (TpPresenceStatusSpec)); ret.name = g_strdup (name); ret.presence_type = type; ret.self = settable; if (can_have_message) { args[0].name = g_strdup ("message"); args[0].dtype = g_strdup ("s"); } ret.optional_arguments = args; return ret; } static void example_echo_2_protocol_init ( ExampleEcho2Protocol *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_2_PROTOCOL, ExampleEcho2ProtocolPrivate); self->priv->statuses = g_new0 (TpPresenceStatusSpec, 4); self->priv->statuses[0] = new_status_spec ("offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, FALSE); self->priv->statuses[1] = new_status_spec ("dnd", TP_CONNECTION_PRESENCE_TYPE_BUSY, TRUE, FALSE); self->priv->statuses[2] = new_status_spec ("available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, TRUE); } static void example_echo_2_protocol_finalize (GObject *object) { ExampleEcho2Protocol *self = EXAMPLE_ECHO_2_PROTOCOL (object); TpPresenceStatusSpec *status = self->priv->statuses; for (; status->name != NULL; status++) { TpPresenceStatusOptionalArgumentSpec *arg = (TpPresenceStatusOptionalArgumentSpec *) status->optional_arguments; for (; arg->name != NULL; arg++) { g_free ((gpointer) arg->name); g_free ((gpointer) arg->dtype); } g_free ((gpointer) status->name); g_free ((gpointer) status->optional_arguments); } ((GObjectClass *) example_echo_2_protocol_parent_class)->finalize (object); } static const TpCMParamSpec example_echo_2_example_params[] = { { "account", "s", G_TYPE_STRING, TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, NULL, /* no default */ 0, /* formerly struct offset, now unused */ tp_cm_param_filter_string_nonempty, /* filter - empty strings disallowed */ NULL, /* filter data, unused for our filter */ NULL /* setter data, now unused */ }, { NULL } }; static const TpCMParamSpec * get_parameters (TpBaseProtocol *self) { return example_echo_2_example_params; } static TpBaseConnection * new_connection (TpBaseProtocol *protocol, GHashTable *asv, GError **error) { ExampleEcho2Connection *conn; const gchar *account; account = tp_asv_get_string (asv, "account"); if (account == NULL || account[0] == '\0') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "The 'account' parameter is required"); return NULL; } conn = EXAMPLE_ECHO_2_CONNECTION ( g_object_new (EXAMPLE_TYPE_ECHO_2_CONNECTION, "account", account, "protocol", tp_base_protocol_get_name (protocol), NULL)); return (TpBaseConnection *) conn; } gchar * example_echo_2_protocol_normalize_contact (const gchar *id, GError **error) { if (id[0] == '\0') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "ID must not be empty"); return NULL; } return g_utf8_strdown (id, -1); } static gchar * normalize_contact (TpBaseProtocol *self G_GNUC_UNUSED, const gchar *contact, GError **error) { return example_echo_2_protocol_normalize_contact (contact, error); } static gchar * identify_account (TpBaseProtocol *self G_GNUC_UNUSED, GHashTable *asv, GError **error) { const gchar *account = tp_asv_get_string (asv, "account"); if (account != NULL) return g_strdup (account); g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'account' parameter not given"); return NULL; } static GStrv get_interfaces (TpBaseProtocol *self) { return g_strdupv ((GStrv) protocol_interfaces); } static void get_connection_details (TpBaseProtocol *self G_GNUC_UNUSED, GStrv *connection_interfaces, GType **channel_managers, gchar **icon_name, gchar **english_name, gchar **vcard_field) { if (connection_interfaces != NULL) { *connection_interfaces = g_strdupv ( (GStrv) example_echo_2_connection_get_possible_interfaces ()); } if (channel_managers != NULL) { GType types[] = { EXAMPLE_TYPE_ECHO_2_IM_MANAGER, G_TYPE_INVALID }; *channel_managers = g_memdup (types, sizeof (types)); } if (icon_name != NULL) { /* a real protocol would use its own icon name - for this example we * borrow the one from ICQ */ *icon_name = g_strdup ("im-icq"); } if (english_name != NULL) { /* in a real protocol this would be "ICQ" or * "Windows Live Messenger (MSN)" or something */ *english_name = g_strdup ("Echo II example"); } if (vcard_field != NULL) { /* in a real protocol this would be "tel" or "x-jabber" or something */ *vcard_field = g_strdup ("x-telepathy-example"); } } static void get_avatar_details (TpBaseProtocol *self, GStrv *supported_mime_types, guint *min_height, guint *min_width, guint *recommended_height, guint *recommended_width, guint *max_height, guint *max_width, guint *max_bytes) { if (supported_mime_types != NULL) *supported_mime_types = g_strdupv ((GStrv) supported_avatar_mime_types); if (min_height != NULL) *min_height = 32; if (min_width != NULL) *min_width = 32; if (recommended_height != NULL) *recommended_height = 64; if (recommended_width != NULL) *recommended_width = 64; if (max_height != NULL) *max_height = 96; if (max_width != NULL) *max_width = 96; if (max_bytes != NULL) *max_bytes = 37748736; } static const TpPresenceStatusSpec * get_statuses (TpBaseProtocol *object) { ExampleEcho2Protocol *self = EXAMPLE_ECHO_2_PROTOCOL (object); return self->priv->statuses; } static void example_echo_2_protocol_class_init ( ExampleEcho2ProtocolClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseProtocolClass *base_class = (TpBaseProtocolClass *) klass; g_type_class_add_private (klass, sizeof (ExampleEcho2ProtocolPrivate)); object_class->finalize = example_echo_2_protocol_finalize; base_class->get_parameters = get_parameters; base_class->new_connection = new_connection; base_class->normalize_contact = normalize_contact; base_class->identify_account = identify_account; base_class->get_interfaces = get_interfaces; base_class->get_connection_details = get_connection_details; base_class->get_avatar_details = get_avatar_details; base_class->get_statuses = get_statuses; } static GStrv dup_supported_uri_schemes (TpBaseProtocol *self) { return g_strdupv ((gchar **) addressable_uri_schemes); } static GStrv dup_supported_vcard_fields (TpBaseProtocol *self) { return g_strdupv ((gchar **) addressable_vcard_fields); } static gchar * normalize_vcard_address (TpBaseProtocol *self, const gchar *vcard_field, const gchar *vcard_address, GError **error) { gchar *normalized_address = NULL; if (g_ascii_strcasecmp (vcard_field, "x-echo2") == 0) { normalized_address = g_ascii_strdown (vcard_address, -1); } else { g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' vCard field is not supported by this protocol", vcard_field); } return normalized_address; } static gchar * normalize_contact_uri (TpBaseProtocol *self, const gchar *uri, GError **error) { gchar *normalized_uri = NULL; gchar *scheme = g_uri_parse_scheme (uri); if (scheme == NULL) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid URI", uri); goto OUT; } else if (g_ascii_strcasecmp (scheme, "echo2") == 0) { gchar *scheme_down = g_ascii_strdown (scheme, -1); gchar *tmp = g_ascii_strdown (uri + strlen (scheme) + 1, -1); normalized_uri = g_strdup_printf ("%s:%s", scheme_down, tmp); g_free (scheme_down); g_free (tmp); } else { g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' URI scheme is not supported by this protocol", scheme); goto OUT; } OUT: g_free (scheme); return normalized_uri; } static void addressing_iface_init (TpProtocolAddressingInterface *iface) { iface->dup_supported_vcard_fields = dup_supported_vcard_fields; iface->dup_supported_uri_schemes = dup_supported_uri_schemes; iface->normalize_vcard_address = normalize_vcard_address; iface->normalize_contact_uri = normalize_contact_uri; } telepathy-qt-0.9.6~git1/tests/lib/glib/params-cm.h0000664000175000017500000000652712470405660017640 0ustar jrjr/* * params-cm.h - header for TpTestsParamConnectionManager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __TP_TESTS_PARAM_CONNECTION_MANAGER_H__ #define __TP_TESTS_PARAM_CONNECTION_MANAGER_H__ #include #include G_BEGIN_DECLS typedef struct _TpTestsParamConnectionManager TpTestsParamConnectionManager; typedef struct _TpTestsParamConnectionManagerPrivate TpTestsParamConnectionManagerPrivate; typedef struct _TpTestsParamConnectionManagerClass TpTestsParamConnectionManagerClass; typedef struct _TpTestsParamConnectionManagerClassPrivate TpTestsParamConnectionManagerClassPrivate; struct _TpTestsParamConnectionManagerClass { TpBaseConnectionManagerClass parent_class; TpTestsParamConnectionManagerClassPrivate *priv; }; struct _TpTestsParamConnectionManager { TpBaseConnectionManager parent; TpTestsParamConnectionManagerPrivate *priv; }; GType tp_tests_param_connection_manager_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_PARAM_CONNECTION_MANAGER \ (tp_tests_param_connection_manager_get_type ()) #define TP_TESTS_PARAM_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_PARAM_CONNECTION_MANAGER, \ TpTestsParamConnectionManager)) #define TP_TESTS_PARAM_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_PARAM_CONNECTION_MANAGER, \ TpTestsParamConnectionManagerClass)) #define IS_PARAM_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_PARAM_CONNECTION_MANAGER)) #define IS_PARAM_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_PARAM_CONNECTION_MANAGER)) #define TP_TESTS_PARAM_CONNECTION_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_PARAM_CONNECTION_MANAGER, \ TpTestsParamConnectionManagerClass)) typedef struct { gchar *a_string; gint a_int16; gint a_int32; guint a_uint16; guint a_uint32; gint64 a_int64; guint64 a_uint64; gboolean a_boolean; gdouble a_double; GStrv a_array_of_strings; GArray *a_array_of_bytes; gchar *a_object_path; gchar *lc_string; gchar *uc_string; gboolean would_have_been_freed; } TpTestsCMParams; TpTestsCMParams * tp_tests_param_connection_manager_steal_params_last_conn ( void); void tp_tests_param_connection_manager_free_params (TpTestsCMParams *params); G_END_DECLS #endif /* #ifndef __TP_TESTS_PARAM_CONNECTION_MANAGER_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/util.h0000664000175000017500000000474612470405660016736 0ustar jrjr/* Simple utility code used by the regression tests. * * Copyright © 2008-2010 Collabora Ltd. * Copyright © 2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_LIB_UTIL_H__ #define __TP_TESTS_LIB_UTIL_H__ #include #include TpDBusDaemon *tp_tests_dbus_daemon_dup_or_die (void); void tp_tests_proxy_run_until_dbus_queue_processed (gpointer proxy); void tp_tests_proxy_run_until_prepared (gpointer proxy, const GQuark *features); gboolean tp_tests_proxy_run_until_prepared_or_failed (gpointer proxy, const GQuark *features, GError **error); #define test_assert_empty_strv(strv) \ _test_assert_empty_strv (__FILE__, __LINE__, strv) void _test_assert_empty_strv (const char *file, int line, gconstpointer strv); #define tp_tests_assert_strv_equals(actual, expected) \ _tp_tests_assert_strv_equals (__FILE__, __LINE__, \ #actual, actual, \ #expected, expected) void _tp_tests_assert_strv_equals (const char *file, int line, const char *actual_desc, gconstpointer actual_strv, const char *expected_desc, gconstpointer expected_strv); void tp_tests_create_conn (GType conn_type, const gchar *account, gboolean connect, TpBaseConnection **service_conn, TpConnection **client_conn); void tp_tests_create_and_connect_conn (GType conn_type, const gchar *account, TpBaseConnection **service_conn, TpConnection **client_conn); gpointer tp_tests_object_new_static_class (GType type, ...) G_GNUC_NULL_TERMINATED; void tp_tests_run_until_result (GAsyncResult **result); void tp_tests_result_ready_cb (GObject *object, GAsyncResult *res, gpointer user_data); void tp_tests_abort_after (guint sec); void tp_tests_init (int *argc, char ***argv); GValue *_tp_create_local_socket (TpSocketAddressType address_type, TpSocketAccessControl access_control, GSocketService **service, gchar **unix_address, GError **error); void _tp_destroy_socket_control_list (gpointer data); void tp_tests_connection_assert_disconnect_succeeds (TpConnection *connection); TpContact *tp_tests_connection_run_until_contact_by_id ( TpConnection *connection, const gchar *id, guint n_features, const TpContactFeature *features); #endif /* #ifndef __TP_TESTS_LIB_UTIL_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/textchan-group.h0000664000175000017500000000414412470405660020721 0ustar jrjr/* * a stub anonymous MUC * * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TEST_TEXT_CHANNEL_GROUP_H__ #define __TEST_TEXT_CHANNEL_GROUP_H__ #include #include #include #include G_BEGIN_DECLS typedef struct _TpTestsTextChannelGroup TpTestsTextChannelGroup; typedef struct _TpTestsTextChannelGroupClass TpTestsTextChannelGroupClass; typedef struct _TpTestsTextChannelGroupPrivate TpTestsTextChannelGroupPrivate; GType tp_tests_text_channel_group_get_type (void); #define TP_TESTS_TYPE_TEXT_CHANNEL_GROUP \ (tp_tests_text_channel_group_get_type ()) #define TP_TESTS_TEXT_CHANNEL_GROUP(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_TEXT_CHANNEL_GROUP, \ TpTestsTextChannelGroup)) #define TP_TESTS_TEXT_CHANNEL_GROUP_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_TEXT_CHANNEL_GROUP, \ TpTestsTextChannelGroupClass)) #define TEST_IS_TEXT_CHANNEL_GROUP(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_TEXT_CHANNEL_GROUP)) #define TEST_IS_TEXT_CHANNEL_GROUP_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_TEXT_CHANNEL_GROUP)) #define TP_TESTS_TEXT_CHANNEL_GROUP_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_TEXT_CHANNEL_GROUP, \ TpTestsTextChannelGroupClass)) struct _TpTestsTextChannelGroupClass { GObjectClass parent_class; TpTextMixinClass text_class; TpGroupMixinClass group_class; TpDBusPropertiesMixinClass dbus_properties_class; }; struct _TpTestsTextChannelGroup { GObject parent; TpBaseConnection *conn; TpTextMixin text; TpGroupMixin group; TpTestsTextChannelGroupPrivate *priv; }; G_END_DECLS #endif /* #ifndef __TEST_TEXT_CHANNEL_GROUP_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/simple-manager.c0000664000175000017500000000455312470405660020651 0ustar jrjr/* * simple-manager.c - an simple connection manager * * Copyright (C) 2007-2008 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "simple-manager.h" #include #include #include #include #include "simple-conn.h" #include "util.h" G_DEFINE_TYPE (TpTestsSimpleConnectionManager, tp_tests_simple_connection_manager, TP_TYPE_BASE_CONNECTION_MANAGER) /* type definition stuff */ static void tp_tests_simple_connection_manager_init (TpTestsSimpleConnectionManager *self) { } /* private data */ typedef struct { gchar *account; } TpTestsSimpleParams; static const TpCMParamSpec simple_params[] = { { "account", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, NULL, G_STRUCT_OFFSET (TpTestsSimpleParams, account), tp_cm_param_filter_string_nonempty, NULL }, { NULL } }; static gpointer alloc_params (void) { return g_slice_new0 (TpTestsSimpleParams); } static void free_params (gpointer p) { TpTestsSimpleParams *params = p; g_free (params->account); g_slice_free (TpTestsSimpleParams, params); } static const TpCMProtocolSpec simple_protocols[] = { { "simple", simple_params, alloc_params, free_params }, { NULL, NULL } }; static TpBaseConnection * new_connection (TpBaseConnectionManager *self, const gchar *proto, TpIntSet *params_present, gpointer parsed_params, GError **error) { TpTestsSimpleParams *params = parsed_params; TpTestsSimpleConnection *conn = TP_TESTS_SIMPLE_CONNECTION ( tp_tests_object_new_static_class (TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", params->account, "protocol", proto, NULL)); return (TpBaseConnection *) conn; } static void tp_tests_simple_connection_manager_class_init ( TpTestsSimpleConnectionManagerClass *klass) { TpBaseConnectionManagerClass *base_class = (TpBaseConnectionManagerClass *) klass; base_class->new_connection = new_connection; base_class->cm_dbus_name = "simple"; base_class->protocol_params = simple_protocols; } telepathy-qt-0.9.6~git1/tests/lib/glib/textchan-null.c0000664000175000017500000004232212470405660020532 0ustar jrjr/* * /dev/null as a text channel * * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ //TODO This either needs to be ported away from TpTextMixin, //or we need to use another test CM instead of this one on the tests where it is used. //tp-glib has not ported it because it is used in TpTextMixin tests. #define _TP_IGNORE_DEPRECATIONS #include "textchan-null.h" #include #include #include #include #include #include #include static void text_iface_init (gpointer iface, gpointer data); static void channel_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (TpTestsTextChannelNull, tp_tests_text_channel_null, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, text_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)) G_DEFINE_TYPE_WITH_CODE (TpTestsPropsTextChannel, tp_tests_props_text_channel, TP_TESTS_TYPE_TEXT_CHANNEL_NULL, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init)) G_DEFINE_TYPE_WITH_CODE (TpTestsPropsGroupTextChannel, tp_tests_props_group_text_channel, TP_TESTS_TYPE_PROPS_TEXT_CHANNEL, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, tp_group_mixin_iface_init)) static const char *tp_tests_text_channel_null_interfaces[] = { NULL }; /* type definition stuff */ enum { PROP_OBJECT_PATH = 1, PROP_CHANNEL_TYPE, PROP_HANDLE_TYPE, PROP_HANDLE, PROP_TARGET_ID, PROP_CONNECTION, PROP_INTERFACES, PROP_REQUESTED, PROP_INITIATOR_HANDLE, PROP_INITIATOR_ID, N_PROPS }; struct _TpTestsTextChannelNullPrivate { TpBaseConnection *conn; gchar *object_path; TpHandle handle; unsigned closed:1; unsigned disposed:1; }; static void tp_tests_text_channel_null_init (TpTestsTextChannelNull *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_TEXT_CHANNEL_NULL, TpTestsTextChannelNullPrivate); } static void tp_tests_props_text_channel_init (TpTestsPropsTextChannel *self) { self->dbus_property_interfaces_retrieved = g_hash_table_new (NULL, NULL); } static GObject * constructor (GType type, guint n_props, GObjectConstructParam *props) { GObject *object = G_OBJECT_CLASS (tp_tests_text_channel_null_parent_class)->constructor (type, n_props, props); TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); tp_dbus_daemon_register_object ( tp_base_connection_get_dbus_daemon (self->priv->conn), self->priv->object_path, self); tp_text_mixin_init (object, G_STRUCT_OFFSET (TpTestsTextChannelNull, text), contact_repo); tp_text_mixin_set_message_types (object, TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION, TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE, G_MAXUINT); return object; } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object); TpTestsTextChannelNullClass *klass = TP_TESTS_TEXT_CHANNEL_NULL_GET_CLASS (self); switch (property_id) { case PROP_OBJECT_PATH: g_value_set_string (value, self->priv->object_path); break; case PROP_CHANNEL_TYPE: g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT); break; case PROP_HANDLE_TYPE: g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); break; case PROP_HANDLE: g_value_set_uint (value, self->priv->handle); break; case PROP_TARGET_ID: { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( self->priv->conn, TP_HANDLE_TYPE_CONTACT); g_value_set_string (value, tp_handle_inspect (contact_repo, self->priv->handle)); } break; case PROP_REQUESTED: g_value_set_boolean (value, TRUE); break; case PROP_INITIATOR_HANDLE: g_value_set_uint (value, self->priv->conn->self_handle); break; case PROP_INITIATOR_ID: { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( self->priv->conn, TP_HANDLE_TYPE_CONTACT); g_value_set_string (value, tp_handle_inspect (contact_repo, self->priv->conn->self_handle)); } break; case PROP_INTERFACES: g_value_set_boxed (value, klass->interfaces); break; case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object); switch (property_id) { case PROP_OBJECT_PATH: g_free (self->priv->object_path); self->priv->object_path = g_value_dup_string (value); break; case PROP_HANDLE: /* we don't ref it here because we don't necessarily have access to the * contact repo yet - instead we ref it in the constructor. */ self->priv->handle = g_value_get_uint (value); break; case PROP_HANDLE_TYPE: case PROP_CHANNEL_TYPE: /* these properties are writable in the interface, but not actually * meaningfully changable on this channel, so we do nothing */ break; case PROP_CONNECTION: self->priv->conn = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } void tp_tests_text_channel_null_close (TpTestsTextChannelNull *self) { if (!self->priv->closed) { self->priv->closed = TRUE; tp_svc_channel_emit_closed (self); tp_dbus_daemon_unregister_object ( tp_base_connection_get_dbus_daemon (self->priv->conn), self); } } static void dispose (GObject *object) { TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object); if (self->priv->disposed) return; self->priv->disposed = TRUE; tp_tests_text_channel_null_close (self); ((GObjectClass *) tp_tests_text_channel_null_parent_class)->dispose (object); } static void finalize (GObject *object) { TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object); g_free (self->priv->object_path); tp_text_mixin_finalize (object); ((GObjectClass *) tp_tests_text_channel_null_parent_class)->finalize (object); } static void tp_tests_text_channel_null_class_init (TpTestsTextChannelNullClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (TpTestsTextChannelNullPrivate)); klass->interfaces = tp_tests_text_channel_null_interfaces; object_class->constructor = constructor; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path"); g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type"); g_object_class_override_property (object_class, PROP_HANDLE, "handle"); param_spec = g_param_spec_object ("connection", "TpBaseConnection object", "Connection object that owns this channel", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "Additional Channel.Interface.* interfaces", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_string ("target-id", "Peer's ID", "The string obtained by inspecting the target handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", "The contact who initiated the channel", 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, param_spec); param_spec = g_param_spec_string ("initiator-id", "Initiator's ID", "The string obtained by inspecting the initiator-handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_ID, param_spec); param_spec = g_param_spec_boolean ("requested", "Requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); tp_text_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsTextChannelNullClass, text_class)); } static void tp_tests_props_text_channel_getter_gobject_properties (GObject *object, GQuark interface, GQuark name, GValue *value, gpointer getter_data) { TpTestsPropsTextChannel *self = TP_TESTS_PROPS_TEXT_CHANNEL (object); g_hash_table_insert (self->dbus_property_interfaces_retrieved, GUINT_TO_POINTER (interface), GUINT_TO_POINTER (interface)); tp_dbus_properties_mixin_getter_gobject_properties (object, interface, name, value, getter_data); } static void props_finalize (GObject *object) { TpTestsPropsTextChannel *self = TP_TESTS_PROPS_TEXT_CHANNEL (object); g_hash_table_unref (self->dbus_property_interfaces_retrieved); ((GObjectClass *) tp_tests_props_text_channel_parent_class)->finalize (object); } static void tp_tests_props_text_channel_class_init (TpTestsPropsTextChannelClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; static TpDBusPropertiesMixinPropImpl channel_props[] = { { "TargetHandleType", "handle-type", NULL }, { "TargetHandle", "handle", NULL }, { "ChannelType", "channel-type", NULL }, { "Interfaces", "interfaces", NULL }, { "TargetID", "target-id", NULL }, { "Requested", "requested", NULL }, { "InitiatorHandle", "initiator-handle", NULL }, { "InitiatorID", "initiator-id", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CHANNEL, tp_tests_props_text_channel_getter_gobject_properties, NULL, channel_props, }, { NULL } }; object_class->finalize = props_finalize; klass->dbus_properties_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsPropsTextChannelClass, dbus_properties_class)); } static const char *tp_tests_props_group_text_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_GROUP, NULL }; static void tp_tests_props_group_text_channel_init (TpTestsPropsGroupTextChannel *self) { } static void group_constructed (GObject *self) { TpBaseConnection *conn = TP_TESTS_TEXT_CHANNEL_NULL (self)->priv->conn; void (*chain_up) (GObject *) = ((GObjectClass *) tp_tests_props_group_text_channel_parent_class)->constructed; if (chain_up != NULL) chain_up (self); tp_group_mixin_init (self, G_STRUCT_OFFSET (TpTestsPropsGroupTextChannel, group), tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT), tp_base_connection_get_self_handle (conn)); tp_group_mixin_change_flags (self, TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0); } static void group_finalize (GObject *self) { tp_group_mixin_finalize (self); ((GObjectClass *) tp_tests_props_group_text_channel_parent_class)->finalize (self); } static gboolean dummy_add_remove_member (GObject *obj, TpHandle handle, const gchar *message, GError **error) { return TRUE; } static void group_iface_props_getter (GObject *object, GQuark interface, GQuark name, GValue *value, gpointer getter_data) { TpTestsPropsTextChannel *self = TP_TESTS_PROPS_TEXT_CHANNEL (object); g_hash_table_insert (self->dbus_property_interfaces_retrieved, GUINT_TO_POINTER (interface), GUINT_TO_POINTER (interface)); tp_group_mixin_get_dbus_property (object, interface, name, value, getter_data); } static void tp_tests_props_group_text_channel_class_init (TpTestsPropsGroupTextChannelClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpTestsTextChannelNullClass *null_class = (TpTestsTextChannelNullClass *) klass; static TpDBusPropertiesMixinPropImpl group_props[] = { { "GroupFlags", NULL, NULL }, { "HandleOwners", NULL, NULL }, { "LocalPendingMembers", NULL, NULL }, { "Members", NULL, NULL }, { "RemotePendingMembers", NULL, NULL }, { "SelfHandle", NULL, NULL }, { NULL } }; null_class->interfaces = tp_tests_props_group_text_channel_interfaces; object_class->constructed = group_constructed; object_class->finalize = group_finalize; tp_group_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsPropsGroupTextChannelClass, group_class), dummy_add_remove_member, dummy_add_remove_member); tp_dbus_properties_mixin_implement_interface (object_class, TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP, group_iface_props_getter, NULL, group_props); } static void channel_close (TpSvcChannel *iface, DBusGMethodInvocation *context) { TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface); tp_tests_text_channel_null_close (self); tp_svc_channel_return_from_close (context); } static void channel_get_channel_type (TpSvcChannel *iface, DBusGMethodInvocation *context) { TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface); self->get_channel_type_called++; tp_svc_channel_return_from_get_channel_type (context, TP_IFACE_CHANNEL_TYPE_TEXT); } static void channel_get_handle (TpSvcChannel *iface, DBusGMethodInvocation *context) { TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface); self->get_handle_called++; tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT, self->priv->handle); } static void channel_get_interfaces (TpSvcChannel *iface, DBusGMethodInvocation *context) { TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface); TpTestsTextChannelNullClass *klass = TP_TESTS_TEXT_CHANNEL_NULL_GET_CLASS (self); self->get_interfaces_called++; tp_svc_channel_return_from_get_interfaces (context, klass->interfaces); } static void channel_iface_init (gpointer iface, gpointer data) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x) IMPLEMENT (close); IMPLEMENT (get_channel_type); IMPLEMENT (get_handle); IMPLEMENT (get_interfaces); #undef IMPLEMENT } static void text_send (TpSvcChannelTypeText *iface, guint type, const gchar *text, DBusGMethodInvocation *context) { /* silently swallow the message */ tp_svc_channel_type_text_return_from_send (context); } static void text_iface_init (gpointer iface, gpointer data) { TpSvcChannelTypeTextClass *klass = iface; tp_text_mixin_iface_init (iface, data); #define IMPLEMENT(x) tp_svc_channel_type_text_implement_##x (klass, text_##x) IMPLEMENT (send); #undef IMPLEMENT } GHashTable * tp_tests_text_channel_get_props (TpTestsTextChannelNull *self) { GHashTable *props; TpHandleType handle_type; TpHandle handle; gchar *target_id; gboolean requested; TpHandle initiator_handle; gchar *initiator_id; GStrv interfaces; g_object_get (self, "handle-type", &handle_type, "handle", &handle, "target-id", &target_id, "requested", &requested, "initiator-handle", &initiator_handle, "initiator-id", &initiator_id, "interfaces", &interfaces, NULL); props = tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, handle_type, TP_PROP_CHANNEL_TARGET_HANDLE, G_TYPE_UINT, handle, TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING, target_id, TP_PROP_CHANNEL_REQUESTED, G_TYPE_BOOLEAN, requested, TP_PROP_CHANNEL_INITIATOR_HANDLE, G_TYPE_UINT, initiator_handle, TP_PROP_CHANNEL_INITIATOR_ID, G_TYPE_STRING, initiator_id, TP_PROP_CHANNEL_INTERFACES, G_TYPE_STRV, interfaces, NULL); g_free (target_id); g_free (initiator_id); g_strfreev (interfaces); return props; } telepathy-qt-0.9.6~git1/tests/lib/glib/captcha-chan.h0000664000175000017500000000435212470405660020264 0ustar jrjr/* * captcha-chan.h - Simple captcha authentication channel * * Copyright (C) 2012 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_CAPTCHA_CHAN_H__ #define __TP_CAPTCHA_CHAN_H__ #include #include #include #include G_BEGIN_DECLS /* Base Class */ typedef struct _TpTestsCaptchaChannel TpTestsCaptchaChannel; typedef struct _TpTestsCaptchaChannelClass TpTestsCaptchaChannelClass; typedef struct _TpTestsCaptchaChannelPrivate TpTestsCaptchaChannelPrivate; GType tp_tests_captcha_channel_get_type (void); #define TP_TESTS_TYPE_CAPTCHA_CHANNEL \ (tp_tests_captcha_channel_get_type ()) #define TP_TESTS_CAPTCHA_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_CAPTCHA_CHANNEL, \ TpTestsCaptchaChannel)) #define TP_TESTS_CAPTCHA_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_CAPTCHA_CHANNEL, \ TpTestsCaptchaChannelClass)) #define TP_TESTS_IS_CAPTCHA_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_CAPTCHA_CHANNEL)) #define TP_TESTS_IS_CAPTCHA_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_CAPTCHA_CHANNEL)) #define TP_TESTS_CAPTCHA_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_CAPTCHA_CHANNEL, \ TpTestsCaptchaChannelClass)) #define EXAMPLE_IS_ECHO_2_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_CAPTCHA_CHANNEL)) #define EXAMPLE_IS_ECHO_2_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_CAPTCHA_CHANNEL)) #define QUAD_CAPTCHA_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_CAPTCHA_CHANNEL, \ TpTestsCaptchaChannelClass)) struct _TpTestsCaptchaChannelClass { TpBaseChannelClass parent_class; }; struct _TpTestsCaptchaChannel { TpBaseChannel parent; TpTestsCaptchaChannelPrivate *priv; }; G_END_DECLS #endif /* #ifndef __TP_CAPTCHA_CHAN_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/future/0000775000175000017500000000000012470405660017107 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/future/extensions/0000775000175000017500000000000012470405660021306 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/future/extensions/misc.xml0000664000175000017500000000102512470405660022761 0ustar jrjr Miscellaneous extensions from the future telepathy-qt-0.9.6~git1/tests/lib/glib/future/extensions/channel.xml0000664000175000017500000000064512470405660023445 0ustar jrjr Channel extensions from the future telepathy-qt-0.9.6~git1/tests/lib/glib/future/extensions/extensions.c0000664000175000017500000000030612470405660023650 0ustar jrjr#include "extensions.h" /* include auto-generated stubs for things common to service and client */ #include "_gen/gtypes-body.h" #include "_gen/interfaces-body.h" #include "_gen/signals-marshal.h" telepathy-qt-0.9.6~git1/tests/lib/glib/future/extensions/extensions.h0000664000175000017500000000106112470405660023654 0ustar jrjr#ifndef FUTURE_EXTENSIONS_H #define FUTURE_EXTENSIONS_H #include #include #include #include "tests/lib/glib/future/extensions/_gen/enums.h" #include "tests/lib/glib/future/extensions/_gen/svc-channel.h" #include "tests/lib/glib/future/extensions/_gen/svc-connection.h" #include "tests/lib/glib/future/extensions/_gen/svc-misc.h" G_BEGIN_DECLS #include "tests/lib/glib/future/extensions/_gen/gtypes.h" #include "tests/lib/glib/future/extensions/_gen/interfaces.h" G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/future/extensions/connection.xml0000664000175000017500000000043012470405660024164 0ustar jrjr Connections extensions from the future telepathy-qt-0.9.6~git1/tests/lib/glib/future/extensions/CMakeLists.txt0000664000175000017500000001333012470405660024046 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_gen") set(tp_glib_tests_future_extensions_SRCS extensions.c extensions.h) set(gen_all_xml ${CMAKE_CURRENT_BINARY_DIR}/_gen/all.xml) add_custom_command(OUTPUT ${gen_all_xml} COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/xincludator.py ${CMAKE_CURRENT_SOURCE_DIR}/all.xml > ${CMAKE_CURRENT_BINARY_DIR}/_gen/all.xml DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/all.xml ${CMAKE_CURRENT_SOURCE_DIR}/channel.xml ${CMAKE_CURRENT_SOURCE_DIR}/connection.xml ${CMAKE_CURRENT_SOURCE_DIR}/misc.xml ${CMAKE_SOURCE_DIR}/tools/xincludator.py) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/gtypes.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/gtypes-body.h COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/glib-gtypes-generator.py ${CMAKE_CURRENT_BINARY_DIR}/_gen/all.xml _gen/gtypes Future DEPENDS ${gen_all_xml} ${CMAKE_SOURCE_DIR}/tools/glib-gtypes-generator.py) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.list COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/glib-signals-marshal-gen.py ${CMAKE_CURRENT_BINARY_DIR}/_gen/all.xml > _gen/signals-marshal.list DEPENDS ${gen_all_xml}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.h COMMAND ${GLIB_GENMARSHAL} --header --prefix=_future_ext_marshal ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.list > _gen/signals-marshal.h DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.list) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gen-signals-marshal-c.sh " echo '#include \"_gen/signals-marshal.h\"' > _gen/signals-marshal.c ${GLIB_GENMARSHAL} --body --prefix=_future_ext_marshal ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.list >> _gen/signals-marshal.c ") set(gen_signals_marshal_c ${SH} ${CMAKE_CURRENT_BINARY_DIR}/gen-signals-marshal-c.sh) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.c COMMAND ${gen_signals_marshal_c} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.list) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/enums.h COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/c-constants-gen.py Future ${CMAKE_CURRENT_BINARY_DIR}/_gen/all.xml > _gen/enums.h DEPENDS ${gen_all_xml} ${CMAKE_SOURCE_DIR}/tools/c-constants-gen.py) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/interfaces-body.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/interfaces.h COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/glib-interfaces-gen.py Future ${CMAKE_CURRENT_BINARY_DIR}/_gen/interfaces-body.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/interfaces.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/all.xml DEPENDS ${gen_all_xml} ${CMAKE_SOURCE_DIR}/tools/glib-interfaces-gen.py) set(SPECS connection channel misc) foreach(spec ${SPECS}) add_custom_command(OUTPUT "_gen/${spec}.xml" COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/xincludator.py ${CMAKE_CURRENT_SOURCE_DIR}/${spec}.xml > ${CMAKE_CURRENT_BINARY_DIR}/_gen/${spec}.xml DEPENDS ${spec}.xml ${CMAKE_SOURCE_DIR}/tools/xincludator.py) endforeach(spec ${SPECS}) function(SVC_GENERATOR spec) set(ARGS ${CMAKE_SOURCE_DIR}/tools/glib-ginterface-gen.py --filename=${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-${spec} --signal-marshal-prefix=_future_ext --include='' --include='_gen/signals-marshal.h' --not-implemented-func='tp_dbus_g_method_return_not_implemented' --allow-unstable ${CMAKE_CURRENT_BINARY_DIR}/_gen/${spec}.xml Future_Svc_) add_custom_command(OUTPUT _gen/svc-${spec}.c _gen/svc-${spec}.h COMMAND ${PYTHON_EXECUTABLE} ARGS ${ARGS} DEPENDS ${CMAKE_SOURCE_DIR}/tools/glib-ginterface-gen.py ${CMAKE_CURRENT_BINARY_DIR}/_gen/${spec}.xml WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endfunction(SVC_GENERATOR spec) svc_generator(channel) svc_generator(connection) svc_generator(misc) set(NEW_FILES ${CMAKE_CURRENT_BINARY_DIR}/_gen/enums.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/gtypes.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/gtypes-body.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/interfaces.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/interfaces-body.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.c ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/signals-marshal.list ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-channel.c ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-channel.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-connection.c ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-connection.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-misc.c ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-misc.h) list(APPEND tp_glib_tests_future_extensions_SRCS ${NEW_FILES}) set_source_files_properties(${NEW_FILES} PROPERTIES GENERATED true) add_library(tp-glib-tests-future-extensions STATIC ${tp_glib_tests_future_extensions_SRCS}) target_link_libraries(tp-glib-tests-future-extensions ${TPGLIB_LIBRARIES}) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/future/extensions/all.xml0000664000175000017500000000053512470405660022603 0ustar jrjr Extensions from the future telepathy-qt-0.9.6~git1/tests/lib/glib/future/conn-addressing/0000775000175000017500000000000012470405660022165 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/future/conn-addressing/conn.h0000664000175000017500000000377512470405660023307 0ustar jrjr/* * conn.h - header for a connection that implements Conn.I.Addressing * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_ADDRESSING_CONN_H__ #define __TP_TESTS_ADDRESSING_CONN_H__ #include #include #include "contacts-conn.h" G_BEGIN_DECLS typedef struct _TpTestsAddressingConnection TpTestsAddressingConnection; typedef struct _TpTestsAddressingConnectionClass TpTestsAddressingConnectionClass; typedef struct _TpTestsAddressingConnectionPrivate TpTestsAddressingConnectionPrivate; struct _TpTestsAddressingConnectionClass { TpTestsContactsConnectionClass parent_class; }; struct _TpTestsAddressingConnection { TpTestsContactsConnection parent; TpTestsAddressingConnectionPrivate *priv; }; GType tp_tests_addressing_connection_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_ADDRESSING_CONNECTION \ (tp_tests_addressing_connection_get_type ()) #define TP_TESTS_ADDRESSING_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_ADDRESSING_CONNECTION, \ TpTestsAddressingConnection)) #define TP_TESTS_ADDRESSING_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_ADDRESSING_CONNECTION, \ TpTestsAddressingConnectionClass)) #define TP_TESTS_ADDRESSING_IS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_ADDRESSING_CONNECTION)) #define TP_TESTS_ADDRESSING_IS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_ADDRESSING_CONNECTION)) #define TP_TESTS_ADDRESSING_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_ADDRESSING_CONNECTION, \ TpTestsAddressingConnectionClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/future/conn-addressing/CMakeLists.txt0000664000175000017500000000105112470405660024722 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) include_directories( ${CMAKE_SOURCE_DIR}/tests/lib/glib ${CMAKE_SOURCE_DIR}/tests/lib/glib/future ${DBUS_GLIB_INCLUDE_DIRS}) set(future_example_conn_addressing_SRCS conn.c conn.h) add_library(future-example-conn-addressing STATIC ${future_example_conn_addressing_SRCS}) target_link_libraries(future-example-conn-addressing ${TPGLIB_LIBRARIES} tp-glib-tests tp-glib-tests-future-extensions) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/future/conn-addressing/conn.c0000664000175000017500000002403312470405660023270 0ustar jrjr/* * conn.c - connection implementing Conn.I.Addressing * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "conn.h" #include #include #include #include #include #include #include "extensions/extensions.h" #include static void addressing_fill_contact_attributes (GObject *obj, const GArray *contacts, GHashTable *attributes_hash); static void addressing_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (TpTestsAddressingConnection, tp_tests_addressing_connection, TP_TESTS_TYPE_CONTACTS_CONNECTION, G_IMPLEMENT_INTERFACE (FUTURE_TYPE_SVC_CONNECTION_INTERFACE_ADDRESSING, addressing_iface_init); ); struct _TpTestsAddressingConnectionPrivate { }; static const gchar *addressable_vcard_fields[] = {"x-addr", NULL}; static const gchar *addressable_uri_schemes[] = {"addr", NULL}; static const char *assumed_interfaces[] = { TP_IFACE_CONNECTION, FUTURE_IFACE_CONNECTION_INTERFACE_ADDRESSING, NULL }; static void constructed (GObject *object) { TpTestsAddressingConnection *self = TP_TESTS_ADDRESSING_CONNECTION (object); void (*parent_impl) (GObject *) = G_OBJECT_CLASS (tp_tests_addressing_connection_parent_class)->constructed; if (parent_impl != NULL) parent_impl (object); tp_contacts_mixin_add_contact_attributes_iface (G_OBJECT (self), FUTURE_IFACE_CONNECTION_INTERFACE_ADDRESSING, addressing_fill_contact_attributes); } static void tp_tests_addressing_connection_init (TpTestsAddressingConnection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_ADDRESSING_CONNECTION, TpTestsAddressingConnectionPrivate); } static void finalize (GObject *object) { G_OBJECT_CLASS (tp_tests_addressing_connection_parent_class)->finalize (object); } static void tp_tests_addressing_connection_class_init (TpTestsAddressingConnectionClass *klass) { TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_ALIASING, TP_IFACE_CONNECTION_INTERFACE_AVATARS, TP_IFACE_CONNECTION_INTERFACE_CONTACTS, TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST, TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS, TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_LOCATION, TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES, TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, FUTURE_IFACE_CONNECTION_INTERFACE_ADDRESSING, NULL }; object_class->constructed = constructed; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (TpTestsAddressingConnectionPrivate)); base_class->interfaces_always_present = interfaces_always_present; } static gchar ** uris_for_handle (TpHandleRepoIface *contact_repo, TpHandle contact) { GPtrArray *uris = g_ptr_array_new (); const gchar * const *scheme; for (scheme = addressable_uri_schemes; *scheme != NULL; scheme++) { const gchar *identifier = tp_handle_inspect (contact_repo, contact); gchar *uri = g_strdup_printf ("%s:%s", *scheme, identifier); if (uri != NULL) { g_ptr_array_add (uris, uri); } } g_ptr_array_add (uris, NULL); return (gchar **) g_ptr_array_free (uris, FALSE); } static GHashTable * vcard_addresses_for_handle (TpHandleRepoIface *contact_repo, TpHandle contact) { GHashTable *addresses = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_free); const gchar * const *field; for (field = addressable_vcard_fields; *field != NULL; field++) { const gchar *identifier = tp_handle_inspect (contact_repo, contact); if (identifier != NULL) { g_hash_table_insert (addresses, (gpointer) *field, g_strdup (identifier)); } } return addresses; } static void addressing_fill_contact_attributes (GObject *obj, const GArray *contacts, GHashTable *attributes_hash) { guint i; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) obj, TP_HANDLE_TYPE_CONTACT); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, TpHandle, i); gchar **uris = uris_for_handle (contact_repo, contact); GHashTable *addresses = vcard_addresses_for_handle (contact_repo, contact); tp_contacts_mixin_set_contact_attribute (attributes_hash, contact, FUTURE_IFACE_CONNECTION_INTERFACE_ADDRESSING"/uris", tp_g_value_slice_new_take_boxed (G_TYPE_STRV, uris)); tp_contacts_mixin_set_contact_attribute (attributes_hash, contact, FUTURE_IFACE_CONNECTION_INTERFACE_ADDRESSING"/addresses", tp_g_value_slice_new_take_boxed (TP_HASH_TYPE_STRING_STRING_MAP, addresses)); } } static gchar * uri_to_id (const gchar *uri, GError **error) { gchar *scheme; gchar *normalized_id = NULL; g_return_val_if_fail (uri != NULL, NULL); scheme = g_uri_parse_scheme (uri); if (scheme == NULL) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid URI", uri); goto OUT; } else if (g_ascii_strcasecmp (scheme, "addr") == 0) { normalized_id = g_strdup (uri + strlen (scheme) + 1); /* Strip the scheme */ } else { g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' URI scheme is not supported by this protocol", scheme); goto OUT; } OUT: g_free (scheme); return normalized_id; } static TpHandle ensure_handle_from_uri (TpHandleRepoIface *repo, const gchar *uri, GError **error) { TpHandle handle; gchar *id = uri_to_id (uri, error); if (id == NULL) return 0; handle = tp_handle_ensure (repo, id, NULL, error); g_free (id); return handle; } static void addressing_get_contacts_by_uri (FutureSvcConnectionInterfaceAddressing *iface, const gchar **uris, const gchar **interfaces, DBusGMethodInvocation *context) { const gchar **uri; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) iface, TP_HANDLE_TYPE_CONTACT); GHashTable *attributes; GHashTable *requested = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); GArray *handles = g_array_sized_new (TRUE, TRUE, sizeof (TpHandle), g_strv_length ((gchar **) uris)); gchar *sender = dbus_g_method_get_sender (context); for (uri = uris; *uri != NULL; uri++) { TpHandle h = ensure_handle_from_uri (contact_repo, *uri, NULL); if (h == 0) continue; g_hash_table_insert (requested, g_strdup (*uri), GUINT_TO_POINTER (h)); g_array_append_val (handles, h); } attributes = tp_contacts_mixin_get_contact_attributes (G_OBJECT (iface), handles, interfaces, assumed_interfaces, sender); future_svc_connection_interface_addressing_return_from_get_contacts_by_uri ( context, requested, attributes); g_hash_table_unref (requested); g_hash_table_unref (attributes); g_free (sender); } static gchar * vcard_address_to_id (const gchar *vcard_field, const gchar *vcard_address, GError **error) { gchar *normalized_id = NULL; g_return_val_if_fail (vcard_field != NULL, NULL); g_return_val_if_fail (vcard_address != NULL, NULL); if (g_ascii_strcasecmp (vcard_field, "x-addr") == 0) { normalized_id = g_strdup (vcard_address); } else { g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' vCard field is not supported by this protocol", vcard_field); } return normalized_id; } static TpHandle ensure_handle_from_vcard_address (TpHandleRepoIface *repo, const gchar *vcard_field, const gchar *vcard_address, GError **error) { TpHandle handle; gchar *normalized_id; normalized_id = vcard_address_to_id (vcard_field, vcard_address, error); if (normalized_id == NULL) return 0; handle = tp_handle_ensure (repo, normalized_id, NULL, error); g_free (normalized_id); return handle; } static void addressing_get_contacts_by_vcard_field (FutureSvcConnectionInterfaceAddressing *iface, const gchar *field, const gchar **addresses, const gchar **interfaces, DBusGMethodInvocation *context) { const gchar **address; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) iface, TP_HANDLE_TYPE_CONTACT); GHashTable *attributes; GHashTable *requested = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); GArray *handles = g_array_sized_new (TRUE, TRUE, sizeof (TpHandle), g_strv_length ((gchar **) addresses)); gchar *sender = dbus_g_method_get_sender (context); for (address = addresses; *address != NULL; address++) { TpHandle h = ensure_handle_from_vcard_address (contact_repo, field, *address, NULL); if (h == 0) continue; g_hash_table_insert (requested, g_strdup (*address), GUINT_TO_POINTER (h)); g_array_append_val (handles, h); } attributes = tp_contacts_mixin_get_contact_attributes (G_OBJECT (iface), handles, interfaces, assumed_interfaces, sender); future_svc_connection_interface_addressing_return_from_get_contacts_by_vcard_field ( context, requested, attributes); g_hash_table_unref (requested); g_hash_table_unref (attributes); g_free (sender); } static void addressing_iface_init (gpointer g_iface, gpointer iface_data) { #define IMPLEMENT(x) \ future_svc_connection_interface_addressing_implement_##x (\ g_iface, addressing_##x) IMPLEMENT(get_contacts_by_uri); IMPLEMENT(get_contacts_by_vcard_field); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/future/conference/0000775000175000017500000000000012470405660021216 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/future/conference/CMakeLists.txt0000664000175000017500000000072412470405660023761 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) include_directories( ${CMAKE_SOURCE_DIR}/tests/lib/glib/future) set(future_example_cm_conference_SRCS chan.c chan.h) add_library(future-example-cm-conference STATIC ${future_example_cm_conference_SRCS}) target_link_libraries(future-example-cm-conference ${TPGLIB_LIBRARIES} tp-glib-tests tp-glib-tests-future-extensions) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/future/conference/chan.h0000664000175000017500000000545712470405660022313 0ustar jrjr/* * conference-channel.h - header for an tp_tests conference channel * * Copyright © 2010 Collabora Ltd. * Copyright © 2010 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TP_TESTS_CONFERENCE_CHANNEL_H #define TP_TESTS_CONFERENCE_CHANNEL_H #include #include #include G_BEGIN_DECLS typedef struct _TpTestsConferenceChannel TpTestsConferenceChannel; typedef struct _TpTestsConferenceChannelPrivate TpTestsConferenceChannelPrivate; typedef struct _TpTestsConferenceChannelClass TpTestsConferenceChannelClass; typedef struct _TpTestsConferenceChannelClassPrivate TpTestsConferenceChannelClassPrivate; GType tp_tests_conference_channel_get_type (void); #define TP_TESTS_TYPE_CONFERENCE_CHANNEL \ (tp_tests_conference_channel_get_type ()) #define TP_TESTS_CONFERENCE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_CONFERENCE_CHANNEL, \ TpTestsConferenceChannel)) #define TP_TESTS_CONFERENCE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_CONFERENCE_CHANNEL, \ TpTestsConferenceChannelClass)) #define TP_TESTS_IS_CONFERENCE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_CONFERENCE_CHANNEL)) #define TP_TESTS_IS_CONFERENCE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_CONFERENCE_CHANNEL)) #define TP_TESTS_CONFERENCE_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_CONFERENCE_CHANNEL, \ TpTestsConferenceChannelClass)) struct _TpTestsConferenceChannelClass { GObjectClass parent_class; TpDBusPropertiesMixinClass dbus_properties_class; TpGroupMixinClass group_class; TpTestsConferenceChannelClassPrivate *priv; }; struct _TpTestsConferenceChannel { GObject parent; TpGroupMixin group; TpTestsConferenceChannelPrivate *priv; }; void tp_tests_conference_channel_remove_channel (TpTestsConferenceChannel *self, const gchar *channel); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/future/conference/chan.c0000664000175000017500000005303212470405660022276 0ustar jrjr/* * conference-channel.c - an tp_tests conference channel * * Copyright © 2010 Collabora Ltd. * Copyright © 2010 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "chan.h" #include #include #include #include #include #include #include #include #include "extensions/extensions.h" /* TODO: * Simulate Conference.ChannelRemoved */ static void mergeable_conference_iface_init (gpointer iface, gpointer data); static void channel_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (TpTestsConferenceChannel, tp_tests_conference_channel, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, tp_group_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CONFERENCE, NULL); G_IMPLEMENT_INTERFACE (FUTURE_TYPE_SVC_CHANNEL_INTERFACE_MERGEABLE_CONFERENCE, mergeable_conference_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL)) enum { PROP_OBJECT_PATH = 1, PROP_CHANNEL_TYPE, PROP_HANDLE_TYPE, PROP_HANDLE, PROP_TARGET_ID, PROP_REQUESTED, PROP_INITIATOR_HANDLE, PROP_INITIATOR_ID, PROP_CONNECTION, PROP_INTERFACES, PROP_CHANNEL_DESTROYED, PROP_CHANNEL_PROPERTIES, PROP_CONFERENCE_CHANNELS, PROP_CONFERENCE_INITIAL_CHANNELS, PROP_CONFERENCE_INITIAL_INVITEE_HANDLES, PROP_CONFERENCE_INITIAL_INVITEE_IDS, PROP_CONFERENCE_INVITATION_MESSAGE, PROP_CONFERENCE_ORIGINAL_CHANNELS, N_PROPS }; struct _TpTestsConferenceChannelPrivate { TpBaseConnection *conn; gchar *object_path; guint handle_type; GPtrArray *conference_initial_channels; GPtrArray *conference_channels; GArray *conference_initial_invitee_handles; gchar **conference_initial_invitee_ids; gchar *conference_invitation_message; GHashTable *conference_original_channels; gboolean disposed; gboolean closed; }; static const gchar * tp_tests_conference_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_GROUP, TP_IFACE_CHANNEL_INTERFACE_CONFERENCE, FUTURE_IFACE_CHANNEL_INTERFACE_MERGEABLE_CONFERENCE, NULL }; static void tp_tests_conference_channel_init (TpTestsConferenceChannel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_CONFERENCE_CHANNEL, TpTestsConferenceChannelPrivate); self->priv->handle_type = (guint) -1; } static void constructed (GObject *object) { void (*chain_up) (GObject *) = ((GObjectClass *) tp_tests_conference_channel_parent_class)->constructed; TpTestsConferenceChannel *self = TP_TESTS_CONFERENCE_CHANNEL (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); TpDBusDaemon *bus; if (chain_up != NULL) { chain_up (object); } bus = tp_dbus_daemon_dup (NULL); tp_dbus_daemon_register_object (bus, self->priv->object_path, object); tp_group_mixin_init (object, G_STRUCT_OFFSET (TpTestsConferenceChannel, group), contact_repo, self->priv->conn->self_handle); if (self->priv->handle_type == (guint) -1) { self->priv->handle_type = TP_HANDLE_TYPE_NONE; } if (!self->priv->conference_channels) { self->priv->conference_channels = g_ptr_array_new (); } if (!self->priv->conference_initial_channels) { self->priv->conference_initial_channels = g_ptr_array_new (); } if (!self->priv->conference_initial_invitee_handles) { self->priv->conference_initial_invitee_handles = g_array_new (FALSE, TRUE, sizeof (guint)); } if (!self->priv->conference_initial_invitee_ids) { self->priv->conference_initial_invitee_ids = g_new0 (gchar *, 1); } if (!self->priv->conference_invitation_message) { self->priv->conference_invitation_message = g_strdup (""); } if (!self->priv->conference_original_channels) { self->priv->conference_original_channels = dbus_g_type_specialized_construct ( TP_HASH_TYPE_CHANNEL_ORIGINATOR_MAP); } } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { TpTestsConferenceChannel *self = TP_TESTS_CONFERENCE_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: g_value_set_string (value, self->priv->object_path); break; case PROP_CHANNEL_TYPE: g_value_set_static_string (value, TP_IFACE_CHANNEL); break; case PROP_HANDLE_TYPE: g_value_set_uint (value, self->priv->handle_type); break; case PROP_HANDLE: g_value_set_uint (value, 0); break; case PROP_TARGET_ID: g_value_set_string (value, ""); break; case PROP_REQUESTED: g_value_set_boolean (value, TRUE); break; case PROP_INITIATOR_HANDLE: g_value_set_uint (value, 0); break; case PROP_INITIATOR_ID: g_value_set_string (value, ""); break; case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; case PROP_INTERFACES: g_value_set_boxed (value, tp_tests_conference_channel_interfaces); break; case PROP_CHANNEL_DESTROYED: g_value_set_boolean (value, self->priv->closed); break; case PROP_CHANNEL_PROPERTIES: g_value_take_boxed (value, tp_dbus_properties_mixin_make_properties_hash (object, TP_IFACE_CHANNEL, "ChannelType", TP_IFACE_CHANNEL, "TargetHandleType", TP_IFACE_CHANNEL, "TargetHandle", TP_IFACE_CHANNEL, "TargetID", TP_IFACE_CHANNEL, "InitiatorHandle", TP_IFACE_CHANNEL, "InitiatorID", TP_IFACE_CHANNEL, "Requested", TP_IFACE_CHANNEL, "Interfaces", TP_IFACE_CHANNEL_INTERFACE_CONFERENCE, "Channels", TP_IFACE_CHANNEL_INTERFACE_CONFERENCE, "InitialChannels", TP_IFACE_CHANNEL_INTERFACE_CONFERENCE, "InitialInviteeHandles", TP_IFACE_CHANNEL_INTERFACE_CONFERENCE, "InitialInviteeIDs", TP_IFACE_CHANNEL_INTERFACE_CONFERENCE, "InvitationMessage", TP_IFACE_CHANNEL_INTERFACE_CONFERENCE, "OriginalChannels", NULL)); break; case PROP_CONFERENCE_CHANNELS: g_value_set_boxed (value, self->priv->conference_channels); g_assert (G_VALUE_HOLDS (value, TP_ARRAY_TYPE_OBJECT_PATH_LIST)); break; case PROP_CONFERENCE_INITIAL_CHANNELS: g_value_set_boxed (value, self->priv->conference_initial_channels); g_assert (G_VALUE_HOLDS (value, TP_ARRAY_TYPE_OBJECT_PATH_LIST)); break; case PROP_CONFERENCE_INITIAL_INVITEE_HANDLES: g_value_set_boxed (value, self->priv->conference_initial_invitee_handles); g_assert (G_VALUE_HOLDS (value, DBUS_TYPE_G_UINT_ARRAY)); break; case PROP_CONFERENCE_INITIAL_INVITEE_IDS: g_value_set_boxed (value, self->priv->conference_initial_invitee_ids); g_assert (G_VALUE_HOLDS (value, G_TYPE_STRV)); break; case PROP_CONFERENCE_INVITATION_MESSAGE: g_value_set_string (value, self->priv->conference_invitation_message); g_assert (G_VALUE_HOLDS (value, G_TYPE_STRING)); break; case PROP_CONFERENCE_ORIGINAL_CHANNELS: g_value_set_boxed (value, self->priv->conference_original_channels); g_assert (G_VALUE_HOLDS (value, TP_HASH_TYPE_CHANNEL_ORIGINATOR_MAP)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { TpTestsConferenceChannel *self = TP_TESTS_CONFERENCE_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: self->priv->object_path = g_value_dup_string (value); break; case PROP_HANDLE_TYPE: self->priv->handle_type = g_value_get_uint (value); break; case PROP_CONNECTION: self->priv->conn = g_value_get_object (value); break; case PROP_CONFERENCE_INITIAL_CHANNELS: g_ptr_array_free(self->priv->conference_initial_channels, TRUE); self->priv->conference_initial_channels = g_value_dup_boxed (value); g_ptr_array_free(self->priv->conference_channels, TRUE); self->priv->conference_channels = g_value_dup_boxed (value); break; case PROP_CONFERENCE_INITIAL_INVITEE_HANDLES: self->priv->conference_initial_invitee_handles = g_value_dup_boxed (value); break; case PROP_CONFERENCE_INITIAL_INVITEE_IDS: self->priv->conference_initial_invitee_ids = g_value_dup_boxed (value); break; case PROP_CONFERENCE_INVITATION_MESSAGE: self->priv->conference_invitation_message = g_value_dup_string (value); break; case PROP_CHANNEL_TYPE: case PROP_HANDLE: case PROP_TARGET_ID: case PROP_REQUESTED: case PROP_INITIATOR_HANDLE: case PROP_INITIATOR_ID: case PROP_CONFERENCE_CHANNELS: /* these properties are not actually meaningfully changeable on this * channel, so we do nothing */ break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dispose (GObject *object) { TpTestsConferenceChannel *self = TP_TESTS_CONFERENCE_CHANNEL (object); if (self->priv->disposed) { return; } self->priv->disposed = TRUE; g_ptr_array_free (self->priv->conference_channels, TRUE); self->priv->conference_channels = NULL; g_ptr_array_free (self->priv->conference_initial_channels, TRUE); self->priv->conference_initial_channels = NULL; if (self->priv->conference_initial_invitee_handles) { g_array_free (self->priv->conference_initial_invitee_handles, FALSE); } self->priv->conference_initial_invitee_handles = NULL; g_strfreev (self->priv->conference_initial_invitee_ids); self->priv->conference_initial_invitee_ids = NULL; g_free (self->priv->conference_invitation_message); self->priv->conference_invitation_message = NULL; g_boxed_free (TP_HASH_TYPE_CHANNEL_ORIGINATOR_MAP, self->priv->conference_original_channels); self->priv->conference_original_channels = NULL; if (!self->priv->closed) { self->priv->closed = TRUE; tp_svc_channel_emit_closed (self); } ((GObjectClass *) tp_tests_conference_channel_parent_class)->dispose (object); } static void finalize (GObject *object) { TpTestsConferenceChannel *self = TP_TESTS_CONFERENCE_CHANNEL (object); g_free (self->priv->object_path); tp_group_mixin_finalize (object); ((GObjectClass *) tp_tests_conference_channel_parent_class)->finalize (object); } static gboolean add_member (GObject *obj, TpHandle handle, const gchar *message, GError **error) { TpTestsConferenceChannel *self = TP_TESTS_CONFERENCE_CHANNEL (obj); TpIntSet *add = tp_intset_new (); tp_intset_add (add, handle); tp_group_mixin_change_members (obj, message, add, NULL, NULL, NULL, self->priv->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (add); return TRUE; } static void tp_tests_conference_channel_class_init (TpTestsConferenceChannelClass *klass) { static TpDBusPropertiesMixinPropImpl channel_props[] = { { "TargetHandleType", "handle-type", NULL }, { "TargetHandle", "handle", NULL }, { "ChannelType", "channel-type", NULL }, { "Interfaces", "interfaces", NULL }, { "TargetID", "target-id", NULL }, { "Requested", "requested", NULL }, { "InitiatorHandle", "initiator-handle", NULL }, { "InitiatorID", "initiator-id", NULL }, { NULL } }; static TpDBusPropertiesMixinPropImpl conference_props[] = { { "Channels", "channels", NULL }, { "InitialChannels", "initial-channels", NULL }, { "InitialInviteeHandles", "initial-invitee-handles", NULL }, { "InitialInviteeIDs", "initial-invitee-ids", NULL }, { "InvitationMessage", "invitation-message", NULL }, { "OriginalChannels", "original-channels", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CHANNEL, tp_dbus_properties_mixin_getter_gobject_properties, NULL, channel_props, }, { TP_IFACE_CHANNEL_INTERFACE_CONFERENCE, tp_dbus_properties_mixin_getter_gobject_properties, NULL, conference_props, }, { NULL } }; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (TpTestsConferenceChannelPrivate)); object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path"); g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type"); g_object_class_override_property (object_class, PROP_HANDLE, "handle"); g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, "channel-destroyed"); g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, "channel-properties"); param_spec = g_param_spec_object ("connection", "TpBaseConnection object", "Connection object that owns this channel", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "Additional Channel.Interface.* interfaces", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_string ("target-id", "Peer's ID", "The string obtained by inspecting the target handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", "The contact who initiated the channel", 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, param_spec); param_spec = g_param_spec_string ("initiator-id", "Initiator's ID", "The string obtained by inspecting the initiator-handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_ID, param_spec); param_spec = g_param_spec_boolean ("requested", "Requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); param_spec = g_param_spec_boxed ("channels", "Channel paths", "A list of the object paths of channels", TP_ARRAY_TYPE_OBJECT_PATH_LIST, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONFERENCE_CHANNELS, param_spec); param_spec = g_param_spec_boxed ("initial-channels", "Initial Channel paths", "A list of the object paths of initial channels", TP_ARRAY_TYPE_OBJECT_PATH_LIST, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONFERENCE_INITIAL_CHANNELS, param_spec); param_spec = g_param_spec_boxed ("initial-invitee-handles", "Initial Invitee Handles", "A list of additional contacts invited to this conference when it was created", DBUS_TYPE_G_UINT_ARRAY, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONFERENCE_INITIAL_INVITEE_HANDLES, param_spec); param_spec = g_param_spec_boxed ("initial-invitee-ids", "Initial Invitee IDs", "A list of additional contacts invited to this conference when it was created", G_TYPE_STRV, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONFERENCE_INITIAL_INVITEE_IDS, param_spec); param_spec = g_param_spec_string ("invitation-message", "Invitation message", "The message that was sent to the InitialInviteeHandles when they were invited", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONFERENCE_INVITATION_MESSAGE, param_spec); param_spec = g_param_spec_boxed ("original-channels", "Original Channels", "A map of channel specific handles to channels", TP_HASH_TYPE_CHANNEL_ORIGINATOR_MAP, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONFERENCE_ORIGINAL_CHANNELS, param_spec); klass->dbus_properties_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsConferenceChannelClass, dbus_properties_class)); tp_group_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsConferenceChannelClass, group_class), add_member, NULL); tp_group_mixin_init_dbus_properties (object_class); } static void channel_close (TpSvcChannel *iface, DBusGMethodInvocation *context) { TpTestsConferenceChannel *self = TP_TESTS_CONFERENCE_CHANNEL (iface); if (!self->priv->closed) { self->priv->closed = TRUE; tp_svc_channel_emit_closed (self); } tp_svc_channel_return_from_close (context); } static void channel_get_channel_type (TpSvcChannel *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_channel_type (context, TP_IFACE_CHANNEL); } static void channel_get_handle (TpSvcChannel *iface, DBusGMethodInvocation *context) { TpTestsConferenceChannel *self = TP_TESTS_CONFERENCE_CHANNEL (iface); tp_svc_channel_return_from_get_handle (context, self->priv->handle_type, 0); } static void channel_get_interfaces (TpSvcChannel *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_interfaces (context, tp_tests_conference_channel_interfaces); } static void channel_iface_init (gpointer iface, gpointer data) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x) IMPLEMENT (close); IMPLEMENT (get_channel_type); IMPLEMENT (get_handle); IMPLEMENT (get_interfaces); #undef IMPLEMENT } static void mergeable_conference_merge (FutureSvcChannelInterfaceMergeableConference *iface G_GNUC_UNUSED, const gchar *channel, DBusGMethodInvocation *context) { TpTestsConferenceChannel *self = TP_TESTS_CONFERENCE_CHANNEL (iface); GHashTable *immutable_props = g_hash_table_new (NULL, NULL); g_ptr_array_add (self->priv->conference_channels, g_strdup (channel)); tp_svc_channel_interface_conference_emit_channel_merged (self, channel, 0, immutable_props); g_hash_table_destroy (immutable_props); future_svc_channel_interface_mergeable_conference_return_from_merge (context); } static void mergeable_conference_iface_init (gpointer iface, gpointer data) { FutureSvcChannelInterfaceMergeableConferenceClass *klass = iface; #define IMPLEMENT(x) future_svc_channel_interface_mergeable_conference_implement_##x (klass, mergeable_conference_##x) IMPLEMENT (merge); #undef IMPLEMENT } void tp_tests_conference_channel_remove_channel (TpTestsConferenceChannel *self, const gchar *channel) { guint i; for (i = 0; i < self->priv->conference_channels->len; i++) { gchar *path = g_ptr_array_index (self->priv->conference_channels, i); if (strcmp (path, channel) == 0) { GHashTable *details = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); g_ptr_array_remove (self->priv->conference_channels, (gpointer) path); g_free (path); g_hash_table_insert (details, "actor", tp_g_value_slice_new_uint (self->priv->conn->self_handle)); g_hash_table_insert (details, "domain-specific-detail-uint", tp_g_value_slice_new_uint (3)); tp_svc_channel_interface_conference_emit_channel_removed (self, channel, details); g_hash_table_destroy (details); } } } telepathy-qt-0.9.6~git1/tests/lib/glib/future/CMakeLists.txt0000664000175000017500000000023512470405660021647 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) add_subdirectory(extensions) add_subdirectory(conference) add_subdirectory(conn-addressing) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/contacts-noroster-conn.h0000664000175000017500000000377312470405660022402 0ustar jrjr/* * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_CONTACTS_NOROSTER_CONN_H__ #define __TP_TESTS_CONTACTS_NOROSTER_CONN_H__ #include #include #include "simple-conn.h" G_BEGIN_DECLS typedef struct _TpTestsContactsNorosterConnection TpTestsContactsNorosterConnection; typedef struct _TpTestsContactsNorosterConnectionClass TpTestsContactsNorosterConnectionClass; struct _TpTestsContactsNorosterConnectionClass { TpTestsSimpleConnectionClass parent_class; }; struct _TpTestsContactsNorosterConnection { TpTestsSimpleConnection parent; }; GType tp_tests_contacts_noroster_connection_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_CONTACTS_NOROSTER_CONNECTION \ (tp_tests_contacts_noroster_connection_get_type ()) #define TP_TESTS_CONTACTS_NOROSTER_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_CONTACTS_NOROSTER_CONNECTION, \ TpTestsContactsNorosterConnection)) #define TP_TESTS_CONTACTS_NOROSTER_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_CONTACTS_NOROSTER_CONNECTION, \ TpTestsContactsNorosterConnectionClass)) #define TP_TESTS_CONTACTS_NOROSTER_IS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_CONTACTS_NOROSTER_CONNECTION)) #define TP_TESTS_CONTACTS_NOROSTER_IS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_CONTACTS_NOROSTER_CONNECTION)) #define TP_TESTS_CONTACTS_NOROSTER_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_CONTACTS_NOROSTER_CONNECTION, \ TpTestsContactsNorosterConnectionClass)) G_END_DECLS #endif /* #ifndef __TP_TESTS_CONTACTS_NOROSTER_CONN_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/debug.h0000664000175000017500000000013612470405660017034 0ustar jrjr#undef DEBUG #define DEBUG(format, ...) \ g_debug ("%s: " format, G_STRFUNC, ##__VA_ARGS__) telepathy-qt-0.9.6~git1/tests/lib/glib/simple-account-manager.h0000664000175000017500000000404712470405660022306 0ustar jrjr/* * simple-account-manager.h - header for a simple account manager service. * * Copyright (C) 2007-2009 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_SIMPLE_ACCOUNT_MANAGER_H__ #define __TP_TESTS_SIMPLE_ACCOUNT_MANAGER_H__ #include #include G_BEGIN_DECLS typedef struct _TpTestsSimpleAccountManager TpTestsSimpleAccountManager; typedef struct _TpTestsSimpleAccountManagerClass TpTestsSimpleAccountManagerClass; typedef struct _TpTestsSimpleAccountManagerPrivate TpTestsSimpleAccountManagerPrivate; struct _TpTestsSimpleAccountManagerClass { GObjectClass parent_class; TpDBusPropertiesMixinClass dbus_props_class; }; struct _TpTestsSimpleAccountManager { GObject parent; TpTestsSimpleAccountManagerPrivate *priv; }; GType tp_tests_simple_account_manager_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_SIMPLE_ACCOUNT_MANAGER \ (tp_tests_simple_account_manager_get_type ()) #define SIMPLE_ACCOUNT_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_SIMPLE_ACCOUNT_MANAGER, \ TpTestsSimpleAccountManager)) #define SIMPLE_ACCOUNT_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_SIMPLE_ACCOUNT_MANAGER, \ TpTestsSimpleAccountManagerClass)) #define SIMPLE_IS_ACCOUNT_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_SIMPLE_ACCOUNT_MANAGER)) #define SIMPLE_IS_ACCOUNT_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_SIMPLE_ACCOUNT_MANAGER)) #define SIMPLE_ACCOUNT_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_SIMPLE_ACCOUNT_MANAGER, \ TpTestsSimpleAccountManagerClass)) G_END_DECLS #endif /* #ifndef __TP_TESTS_SIMPLE_ACCOUNT_MANAGER_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/contact-list-manager.c0000664000175000017500000004734512470405660021772 0ustar jrjr/* * Example channel manager for contact lists * * Copyright © 2007-2010 Collabora Ltd. * Copyright © 2007-2010 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "contact-list-manager.h" #include #include struct _TestContactListManagerPrivate { TpBaseConnection *conn; gulong status_changed_id; /* TpHandle => ContactDetails */ GHashTable *contact_details; TpHandleRepoIface *contact_repo; TpHandleRepoIface *group_repo; TpHandleSet *groups; }; static void contact_groups_iface_init (TpContactGroupListInterface *iface); static void mutable_contact_groups_iface_init ( TpMutableContactGroupListInterface *iface); G_DEFINE_TYPE_WITH_CODE (TestContactListManager, test_contact_list_manager, TP_TYPE_BASE_CONTACT_LIST, G_IMPLEMENT_INTERFACE (TP_TYPE_CONTACT_GROUP_LIST, contact_groups_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_MUTABLE_CONTACT_GROUP_LIST, mutable_contact_groups_iface_init)) typedef struct { TpSubscriptionState subscribe; TpSubscriptionState publish; gchar *publish_request; TpHandleSet *groups; TpHandle handle; TpHandleRepoIface *contact_repo; } ContactDetails; static void contact_detail_destroy (gpointer p) { ContactDetails *d = p; g_free (d->publish_request); tp_handle_set_destroy (d->groups); g_slice_free (ContactDetails, d); } static ContactDetails * lookup_contact (TestContactListManager *self, TpHandle handle) { return g_hash_table_lookup (self->priv->contact_details, GUINT_TO_POINTER (handle)); } static ContactDetails * ensure_contact (TestContactListManager *self, TpHandle handle) { ContactDetails *d = lookup_contact (self, handle); if (d == NULL) { d = g_slice_new0 (ContactDetails); d->subscribe = TP_SUBSCRIPTION_STATE_NO; d->publish = TP_SUBSCRIPTION_STATE_NO; d->publish_request = NULL; d->groups = tp_handle_set_new (self->priv->group_repo); d->handle = handle; d->contact_repo = self->priv->contact_repo; g_hash_table_insert (self->priv->contact_details, GUINT_TO_POINTER (handle), d); } return d; } static void test_contact_list_manager_init (TestContactListManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TEST_TYPE_CONTACT_LIST_MANAGER, TestContactListManagerPrivate); self->priv->contact_details = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, contact_detail_destroy); } static void close_all (TestContactListManager *self) { if (self->priv->status_changed_id != 0) { g_signal_handler_disconnect (self->priv->conn, self->priv->status_changed_id); self->priv->status_changed_id = 0; } tp_clear_pointer (&self->priv->contact_details, g_hash_table_unref); tp_clear_pointer (&self->priv->groups, tp_handle_set_destroy); } static void dispose (GObject *object) { TestContactListManager *self = TEST_CONTACT_LIST_MANAGER (object); close_all (self); ((GObjectClass *) test_contact_list_manager_parent_class)->dispose ( object); } static TpHandleSet * contact_list_dup_contacts (TpBaseContactList *base) { TestContactListManager *self = TEST_CONTACT_LIST_MANAGER (base); TpHandleSet *set; GHashTableIter iter; gpointer k, v; set = tp_handle_set_new (self->priv->contact_repo); g_hash_table_iter_init (&iter, self->priv->contact_details); while (g_hash_table_iter_next (&iter, &k, &v)) { ContactDetails *d = v; /* add all the interesting items */ if (d->subscribe != TP_SUBSCRIPTION_STATE_NO || d->publish != TP_SUBSCRIPTION_STATE_NO) tp_handle_set_add (set, GPOINTER_TO_UINT (k)); } return set; } static void contact_list_dup_states (TpBaseContactList *base, TpHandle contact, TpSubscriptionState *subscribe, TpSubscriptionState *publish, gchar **publish_request) { TestContactListManager *self = TEST_CONTACT_LIST_MANAGER (base); ContactDetails *d = lookup_contact (self, contact); if (d == NULL) { if (subscribe != NULL) *subscribe = TP_SUBSCRIPTION_STATE_NO; if (publish != NULL) *publish = TP_SUBSCRIPTION_STATE_NO; if (publish_request != NULL) *publish_request = NULL; } else { if (subscribe != NULL) *subscribe = d->subscribe; if (publish != NULL) *publish = d->publish; if (publish_request != NULL) *publish_request = g_strdup (d->publish_request); } } static GStrv contact_list_dup_groups (TpBaseContactList *base) { TestContactListManager *self = TEST_CONTACT_LIST_MANAGER (base); GPtrArray *ret; if (self->priv->groups != NULL) { TpIntSetFastIter iter; TpHandle group; ret = g_ptr_array_sized_new (tp_handle_set_size (self->priv->groups) + 1); tp_intset_fast_iter_init (&iter, tp_handle_set_peek (self->priv->groups)); while (tp_intset_fast_iter_next (&iter, &group)) { g_ptr_array_add (ret, g_strdup (tp_handle_inspect ( self->priv->group_repo, group))); } } else { ret = g_ptr_array_sized_new (1); } g_ptr_array_add (ret, NULL); return (GStrv) g_ptr_array_free (ret, FALSE); } static GStrv contact_list_dup_contact_groups (TpBaseContactList *base, TpHandle contact) { TestContactListManager *self = TEST_CONTACT_LIST_MANAGER (base); ContactDetails *d = lookup_contact (self, contact); GPtrArray *ret; if (d != NULL && d->groups != NULL) { TpIntSetFastIter iter; TpHandle group; ret = g_ptr_array_sized_new (tp_handle_set_size (d->groups) + 1); tp_intset_fast_iter_init (&iter, tp_handle_set_peek (d->groups)); while (tp_intset_fast_iter_next (&iter, &group)) { g_ptr_array_add (ret, g_strdup (tp_handle_inspect ( self->priv->group_repo, group))); } } else { ret = g_ptr_array_sized_new (1); } g_ptr_array_add (ret, NULL); return (GStrv) g_ptr_array_free (ret, FALSE); } static TpHandleSet * contact_list_dup_group_members (TpBaseContactList *base, const gchar *group) { TestContactListManager *self = TEST_CONTACT_LIST_MANAGER (base); TpHandleSet *set; TpHandle group_handle; GHashTableIter iter; gpointer k, v; set = tp_handle_set_new (self->priv->contact_repo); group_handle = tp_handle_lookup (self->priv->group_repo, group, NULL, NULL); if (G_UNLIKELY (group_handle == 0)) { /* clearly it doesn't have members */ return set; } g_hash_table_iter_init (&iter, self->priv->contact_details); while (g_hash_table_iter_next (&iter, &k, &v)) { ContactDetails *d = v; if (d->groups != NULL && tp_handle_set_is_member (d->groups, group_handle)) tp_handle_set_add (set, GPOINTER_TO_UINT (k)); } return set; } static void contact_list_set_contact_groups_async (TpBaseContactList *base, TpHandle contact, const gchar * const *names, gsize n, GAsyncReadyCallback callback, gpointer user_data) { TestContactListManager *self = TEST_CONTACT_LIST_MANAGER (base); ContactDetails *d; TpIntset *set, *added_set, *removed_set; GPtrArray *added_names, *removed_names; TpIntSetFastIter iter; TpHandle group_handle; guint i; d = ensure_contact (self, contact); set = tp_intset_new (); for (i = 0; i < n; i++) { group_handle = tp_handle_ensure (self->priv->group_repo, names[i], NULL, NULL); tp_intset_add (set, group_handle); } added_set = tp_intset_difference (set, tp_handle_set_peek (d->groups)); added_names = g_ptr_array_sized_new (tp_intset_size (added_set)); tp_intset_fast_iter_init (&iter, added_set); while (tp_intset_fast_iter_next (&iter, &group_handle)) { g_ptr_array_add (added_names, (gchar *) tp_handle_inspect ( self->priv->group_repo, group_handle)); } tp_intset_destroy (added_set); removed_set = tp_intset_difference (tp_handle_set_peek (d->groups), set); removed_names = g_ptr_array_sized_new (tp_intset_size (removed_set)); tp_intset_fast_iter_init (&iter, removed_set); while (tp_intset_fast_iter_next (&iter, &group_handle)) { g_ptr_array_add (removed_names, (gchar *) tp_handle_inspect ( self->priv->group_repo, group_handle)); } tp_intset_destroy (removed_set); tp_handle_set_destroy (d->groups); d->groups = tp_handle_set_new_from_intset (self->priv->group_repo, set); tp_intset_destroy (set); tp_base_contact_list_one_contact_groups_changed (base, contact, (const gchar * const *) added_names->pdata, added_names->len, (const gchar * const *) removed_names->pdata, removed_names->len); tp_simple_async_report_success_in_idle ((GObject *) self, callback, user_data, contact_list_set_contact_groups_async); g_ptr_array_unref (added_names); g_ptr_array_unref (removed_names); } static void contact_list_set_group_members_async (TpBaseContactList *base, const gchar *normalized_group, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *simple; simple = g_simple_async_result_new_error ((GObject *) base, callback, user_data, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Not implemented"); g_simple_async_result_complete_in_idle (simple); g_object_unref (simple); } static void contact_list_add_to_group_async (TpBaseContactList *base, const gchar *group, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *simple; simple = g_simple_async_result_new_error ((GObject *) base, callback, user_data, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Not implemented"); g_simple_async_result_complete_in_idle (simple); g_object_unref (simple); } static void contact_list_remove_from_group_async (TpBaseContactList *base, const gchar *group, TpHandleSet *contacts, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *simple; simple = g_simple_async_result_new_error ((GObject *) base, callback, user_data, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Not implemented"); g_simple_async_result_complete_in_idle (simple); g_object_unref (simple); } static void contact_list_remove_group_async (TpBaseContactList *base, const gchar *group, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *simple; simple = g_simple_async_result_new_error ((GObject *) base, callback, user_data, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Not implemented"); g_simple_async_result_complete_in_idle (simple); g_object_unref (simple); } static void status_changed_cb (TpBaseConnection *conn, guint status, guint reason, TestContactListManager *self) { switch (status) { case TP_CONNECTION_STATUS_CONNECTED: { tp_base_contact_list_set_list_received (TP_BASE_CONTACT_LIST (self)); } break; case TP_CONNECTION_STATUS_DISCONNECTED: { close_all (self); } break; } } static void constructed (GObject *object) { TestContactListManager *self = TEST_CONTACT_LIST_MANAGER (object); void (*chain_up) (GObject *) = ((GObjectClass *) test_contact_list_manager_parent_class)->constructed; if (chain_up != NULL) { chain_up (object); } self->priv->conn = tp_base_contact_list_get_connection ( TP_BASE_CONTACT_LIST (self), NULL); self->priv->status_changed_id = g_signal_connect (self->priv->conn, "status-changed", G_CALLBACK (status_changed_cb), self); self->priv->contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); self->priv->group_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_GROUP); self->priv->groups = tp_handle_set_new (self->priv->group_repo); } static void contact_groups_iface_init (TpContactGroupListInterface *iface) { iface->dup_groups = contact_list_dup_groups; iface->dup_contact_groups = contact_list_dup_contact_groups; iface->dup_group_members = contact_list_dup_group_members; } static void mutable_contact_groups_iface_init ( TpMutableContactGroupListInterface *iface) { iface->set_contact_groups_async = contact_list_set_contact_groups_async; iface->set_group_members_async = contact_list_set_group_members_async; iface->add_to_group_async = contact_list_add_to_group_async; iface->remove_from_group_async = contact_list_remove_from_group_async; iface->remove_group_async = contact_list_remove_group_async; } static void test_contact_list_manager_class_init (TestContactListManagerClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseContactListClass *base_class =(TpBaseContactListClass *) klass; g_type_class_add_private (klass, sizeof (TestContactListManagerPrivate)); object_class->constructed = constructed; object_class->dispose = dispose; base_class->dup_states = contact_list_dup_states; base_class->dup_contacts = contact_list_dup_contacts; } void test_contact_list_manager_add_to_group (TestContactListManager *self, const gchar *group_name, TpHandle member) { TpBaseContactList *base = TP_BASE_CONTACT_LIST (self); ContactDetails *d = ensure_contact (self, member); TpHandle group_handle; group_handle = tp_handle_ensure (self->priv->group_repo, group_name, NULL, NULL); tp_handle_set_add (d->groups, group_handle); tp_base_contact_list_one_contact_groups_changed (base, member, &group_name, 1, NULL, 0); } void test_contact_list_manager_remove_from_group (TestContactListManager *self, const gchar *group_name, TpHandle member) { TpBaseContactList *base = TP_BASE_CONTACT_LIST (self); ContactDetails *d = lookup_contact (self, member); TpHandle group_handle; if (d == NULL) return; group_handle = tp_handle_ensure (self->priv->group_repo, group_name, NULL, NULL); tp_handle_set_remove (d->groups, group_handle); tp_base_contact_list_one_contact_groups_changed (base, member, NULL, 0, &group_name, 1); } typedef struct { TestContactListManager *self; TpHandleSet *handles; } SelfAndContact; static SelfAndContact * self_and_contact_new (TestContactListManager *self, TpHandleSet *handles) { SelfAndContact *ret = g_slice_new0 (SelfAndContact); ret->self = g_object_ref (self); ret->handles = tp_handle_set_copy (handles); return ret; } static void self_and_contact_destroy (gpointer p) { SelfAndContact *s = p; tp_handle_set_destroy (s->handles); g_object_unref (s->self); g_slice_free (SelfAndContact, s); } static gboolean receive_authorized (gpointer p) { SelfAndContact *s = p; GArray *handles_array; guint i; handles_array = tp_handle_set_to_array (s->handles); for (i = 0; i < handles_array->len; i++) { ContactDetails *d = lookup_contact (s->self, g_array_index (handles_array, TpHandle, i)); if (d == NULL) continue; d->subscribe = TP_SUBSCRIPTION_STATE_YES; /* if we're not publishing to them, also pretend they have asked us to do so */ if (d->publish != TP_SUBSCRIPTION_STATE_YES) { d->publish = TP_SUBSCRIPTION_STATE_ASK; tp_clear_pointer (&d->publish_request, g_free); d->publish_request = g_strdup ("automatic publish request"); } } g_array_unref (handles_array); tp_base_contact_list_contacts_changed (TP_BASE_CONTACT_LIST (s->self), s->handles, NULL); return FALSE; } static gboolean receive_unauthorized (gpointer p) { SelfAndContact *s = p; GArray *handles_array; guint i; handles_array = tp_handle_set_to_array (s->handles); for (i = 0; i < handles_array->len; i++) { ContactDetails *d = lookup_contact (s->self, g_array_index (handles_array, TpHandle, i)); if (d == NULL) continue; d->subscribe = TP_SUBSCRIPTION_STATE_REMOVED_REMOTELY; } g_array_unref (handles_array); tp_base_contact_list_contacts_changed (TP_BASE_CONTACT_LIST (s->self), s->handles, NULL); return FALSE; } void test_contact_list_manager_request_subscription (TestContactListManager *self, guint n_members, TpHandle *members, const gchar *message) { TpHandleSet *handles; guint i; gchar *message_lc; handles = tp_handle_set_new (self->priv->contact_repo); for (i = 0; i < n_members; i++) { ContactDetails *d = ensure_contact (self, members[i]); if (d->subscribe == TP_SUBSCRIPTION_STATE_YES) continue; d->subscribe = TP_SUBSCRIPTION_STATE_ASK; tp_handle_set_add (handles, members[i]); } tp_base_contact_list_contacts_changed (TP_BASE_CONTACT_LIST (self), handles, NULL); message_lc = g_ascii_strdown (message, -1); if (strstr (message_lc, "please") != NULL) { g_idle_add_full (G_PRIORITY_DEFAULT, receive_authorized, self_and_contact_new (self, handles), self_and_contact_destroy); } else if (strstr (message_lc, "no") != NULL) { g_idle_add_full (G_PRIORITY_DEFAULT, receive_unauthorized, self_and_contact_new (self, handles), self_and_contact_destroy); } g_free (message_lc); tp_handle_set_destroy (handles); } void test_contact_list_manager_unsubscribe (TestContactListManager *self, guint n_members, TpHandle *members) { TpHandleSet *handles; guint i; handles = tp_handle_set_new (self->priv->contact_repo); for (i = 0; i < n_members; i++) { ContactDetails *d = lookup_contact (self, members[i]); if (d == NULL || d->subscribe == TP_SUBSCRIPTION_STATE_NO) continue; d->subscribe = TP_SUBSCRIPTION_STATE_NO; tp_handle_set_add (handles, members[i]); } tp_base_contact_list_contacts_changed (TP_BASE_CONTACT_LIST (self), handles, NULL); tp_handle_set_destroy (handles); } void test_contact_list_manager_authorize_publication (TestContactListManager *self, guint n_members, TpHandle *members) { TpHandleSet *handles; guint i; handles = tp_handle_set_new (self->priv->contact_repo); for (i = 0; i < n_members; i++) { ContactDetails *d = lookup_contact (self, members[i]); if (d == NULL || d->publish != TP_SUBSCRIPTION_STATE_ASK) continue; d->publish = TP_SUBSCRIPTION_STATE_YES; tp_clear_pointer (&d->publish_request, g_free); tp_handle_set_add (handles, members[i]); } tp_base_contact_list_contacts_changed (TP_BASE_CONTACT_LIST (self), handles, NULL); tp_handle_set_destroy (handles); } void test_contact_list_manager_unpublish (TestContactListManager *self, guint n_members, TpHandle *members) { TpHandleSet *handles; guint i; handles = tp_handle_set_new (self->priv->contact_repo); for (i = 0; i < n_members; i++) { ContactDetails *d = lookup_contact (self, members[i]); if (d == NULL || d->publish == TP_SUBSCRIPTION_STATE_NO) continue; d->publish = TP_SUBSCRIPTION_STATE_NO; tp_clear_pointer (&d->publish_request, g_free); tp_handle_set_add (handles, members[i]); } tp_base_contact_list_contacts_changed (TP_BASE_CONTACT_LIST (self), handles, NULL); tp_handle_set_destroy (handles); } void test_contact_list_manager_remove (TestContactListManager *self, guint n_members, TpHandle *members) { TpHandleSet *handles; guint i; handles = tp_handle_set_new (self->priv->contact_repo); for (i = 0; i < n_members; i++) { ContactDetails *d = lookup_contact (self, members[i]); if (d == NULL) continue; g_hash_table_remove (self->priv->contact_details, GUINT_TO_POINTER (members[i])); tp_handle_set_add (handles, members[i]); } tp_base_contact_list_contacts_changed (TP_BASE_CONTACT_LIST (self), NULL, handles); tp_handle_set_destroy (handles); } telepathy-qt-0.9.6~git1/tests/lib/glib/simple-client.c0000664000175000017500000001511512470405660020511 0ustar jrjr/* * simple-client.c - a simple client * * Copyright © 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "simple-client.h" #include #include #include #include #include #include #include #include #include "util.h" G_DEFINE_TYPE (TpTestsSimpleClient, tp_tests_simple_client, TP_TYPE_BASE_CLIENT) static void simple_observe_channels ( TpBaseClient *client, TpAccount *account, TpConnection *connection, GList *channels, TpChannelDispatchOperation *dispatch_operation, GList *requests, TpObserveChannelsContext *context) { TpTestsSimpleClient *self = TP_TESTS_SIMPLE_CLIENT (client); GHashTable *info; gboolean fail; GList *l; /* Fail if caller set the fake "FAIL" info */ g_object_get (context, "observer-info", &info, NULL); fail = tp_asv_get_boolean (info, "FAIL", NULL); g_hash_table_unref (info); if (self->observe_ctx != NULL) { g_object_unref (self->observe_ctx); self->observe_ctx = NULL; } if (fail) { GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "No observation for you!" }; tp_observe_channels_context_fail (context, &error); return; } g_assert (TP_IS_ACCOUNT (account)); g_assert (tp_proxy_is_prepared (account, TP_ACCOUNT_FEATURE_CORE)); g_assert (TP_IS_CONNECTION (connection)); g_assert (tp_proxy_is_prepared (connection, TP_CONNECTION_FEATURE_CORE)); g_assert_cmpuint (g_list_length (channels), >, 0); for (l = channels; l != NULL; l = g_list_next (l)) { TpChannel *channel = l->data; g_assert (TP_IS_CHANNEL (channel)); g_assert (tp_proxy_is_prepared (channel, TP_CHANNEL_FEATURE_CORE) || tp_proxy_get_invalidated (channel) != NULL); } if (dispatch_operation != NULL) g_assert (TP_IS_CHANNEL_DISPATCH_OPERATION (dispatch_operation)); for (l = requests; l != NULL; l = g_list_next (l)) { TpChannelRequest *request = l->data; g_assert (TP_IS_CHANNEL_REQUEST (request)); } self->observe_ctx = g_object_ref (context); tp_observe_channels_context_accept (context); } static void simple_add_dispatch_operation ( TpBaseClient *client, TpAccount *account, TpConnection *connection, GList *channels, TpChannelDispatchOperation *dispatch_operation, TpAddDispatchOperationContext *context) { TpTestsSimpleClient *self = TP_TESTS_SIMPLE_CLIENT (client); GList *l; g_assert (TP_IS_ACCOUNT (account)); g_assert (tp_proxy_is_prepared (account, TP_ACCOUNT_FEATURE_CORE)); g_assert (TP_IS_CONNECTION (connection)); g_assert (tp_proxy_is_prepared (connection, TP_CONNECTION_FEATURE_CORE)); g_assert (TP_IS_CHANNEL_DISPATCH_OPERATION (dispatch_operation)); g_assert (tp_proxy_is_prepared (dispatch_operation, TP_CHANNEL_DISPATCH_OPERATION_FEATURE_CORE) || tp_proxy_get_invalidated (dispatch_operation) != NULL); if (self->add_dispatch_ctx != NULL) { g_object_unref (self->add_dispatch_ctx); self->add_dispatch_ctx = NULL; } g_assert_cmpuint (g_list_length (channels), >, 0); for (l = channels; l != NULL; l = g_list_next (l)) { TpChannel *channel = l->data; g_assert (TP_IS_CHANNEL (channel)); g_assert (tp_proxy_is_prepared (channel, TP_CHANNEL_FEATURE_CORE) || tp_proxy_get_invalidated (channel) != NULL); } self->add_dispatch_ctx = g_object_ref (context); tp_add_dispatch_operation_context_accept (context); } static void simple_handle_channels (TpBaseClient *client, TpAccount *account, TpConnection *connection, GList *channels, GList *requests_satisfied, gint64 user_action_time, TpHandleChannelsContext *context) { TpTestsSimpleClient *self = TP_TESTS_SIMPLE_CLIENT (client); GList *l; if (self->handle_channels_ctx != NULL) { g_object_unref (self->handle_channels_ctx); self->handle_channels_ctx = NULL; } g_assert (TP_IS_ACCOUNT (account)); g_assert (tp_proxy_is_prepared (account, TP_ACCOUNT_FEATURE_CORE)); g_assert (TP_IS_CONNECTION (connection)); g_assert (tp_proxy_is_prepared (connection, TP_CONNECTION_FEATURE_CORE)); g_assert_cmpuint (g_list_length (channels), >, 0); for (l = channels; l != NULL; l = g_list_next (l)) { TpChannel *channel = l->data; g_assert (TP_IS_CHANNEL (channel)); g_assert (tp_proxy_is_prepared (channel, TP_CHANNEL_FEATURE_CORE) || tp_proxy_get_invalidated (channel) != NULL); } for (l = requests_satisfied; l != NULL; l = g_list_next (l)) { TpChannelRequest *request = l->data; g_assert (TP_IS_CHANNEL_REQUEST (request)); } self->handle_channels_ctx = g_object_ref (context); tp_handle_channels_context_accept (context); } static void tp_tests_simple_client_init (TpTestsSimpleClient *self) { } static void tp_tests_simple_client_dispose (GObject *object) { TpTestsSimpleClient *self = TP_TESTS_SIMPLE_CLIENT (object); void (*dispose) (GObject *) = G_OBJECT_CLASS (tp_tests_simple_client_parent_class)->dispose; if (self->observe_ctx != NULL) { g_object_unref (self->observe_ctx); self->observe_ctx = NULL; } if (self->add_dispatch_ctx != NULL) { g_object_unref (self->add_dispatch_ctx); self->add_dispatch_ctx = NULL; } if (self->handle_channels_ctx != NULL) { g_object_unref (self->handle_channels_ctx); self->handle_channels_ctx = NULL; } if (dispose != NULL) dispose (object); } static void tp_tests_simple_client_class_init (TpTestsSimpleClientClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); TpBaseClientClass *base_class = TP_BASE_CLIENT_CLASS (klass); object_class->dispose = tp_tests_simple_client_dispose; tp_base_client_implement_observe_channels (base_class, simple_observe_channels); tp_base_client_implement_add_dispatch_operation (base_class, simple_add_dispatch_operation); tp_base_client_implement_handle_channels (base_class, simple_handle_channels); } TpTestsSimpleClient * tp_tests_simple_client_new (TpDBusDaemon *dbus_daemon, const gchar *name, gboolean uniquify_name) { return tp_tests_object_new_static_class (TP_TESTS_TYPE_SIMPLE_CLIENT, "dbus-daemon", dbus_daemon, "name", name, "uniquify-name", uniquify_name, NULL); } telepathy-qt-0.9.6~git1/tests/lib/glib/simple-conn.c0000664000175000017500000003131512470405660020170 0ustar jrjr/* * simple-conn.c - a simple connection * * Copyright (C) 2007-2010 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "simple-conn.h" #include #include #include #include #include #include #include #include #include "textchan-null.h" #include "util.h" static void conn_iface_init (TpSvcConnectionClass *); G_DEFINE_TYPE_WITH_CODE (TpTestsSimpleConnection, tp_tests_simple_connection, TP_TYPE_BASE_CONNECTION, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION, conn_iface_init)) /* type definition stuff */ enum { PROP_ACCOUNT = 1, PROP_BREAK_PROPS = 2, PROP_DBUS_STATUS = 3, N_PROPS }; enum { SIGNAL_GOT_SELF_HANDLE, N_SIGNALS }; static guint signals[N_SIGNALS] = {0}; struct _TpTestsSimpleConnectionPrivate { gchar *account; guint connect_source; guint disconnect_source; gboolean break_fastpath_props; /* TpHandle => reffed TpTestsTextChannelNull */ GHashTable *channels; GError *get_self_handle_error /* initially NULL */ ; }; static void tp_tests_simple_connection_init (TpTestsSimpleConnection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_SIMPLE_CONNECTION, TpTestsSimpleConnectionPrivate); self->priv->channels = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_value_set_string (value, self->priv->account); break; case PROP_BREAK_PROPS: g_value_set_boolean (value, self->priv->break_fastpath_props); break; case PROP_DBUS_STATUS: if (self->priv->break_fastpath_props) { g_debug ("returning broken value for Connection.Status"); g_value_set_uint (value, 0xdeadbeefU); } else { guint32 status = TP_BASE_CONNECTION (self)->status; if (status == TP_INTERNAL_CONNECTION_STATUS_NEW) g_value_set_uint (value, TP_CONNECTION_STATUS_DISCONNECTED); else g_value_set_uint (value, status); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *spec) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_free (self->priv->account); self->priv->account = g_utf8_strdown (g_value_get_string (value), -1); break; case PROP_BREAK_PROPS: self->priv->break_fastpath_props = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void dispose (GObject *object) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (object); g_hash_table_unref (self->priv->channels); G_OBJECT_CLASS (tp_tests_simple_connection_parent_class)->dispose (object); } static void finalize (GObject *object) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (object); if (self->priv->connect_source != 0) { g_source_remove (self->priv->connect_source); } if (self->priv->disconnect_source != 0) { g_source_remove (self->priv->disconnect_source); } g_clear_error (&self->priv->get_self_handle_error); g_free (self->priv->account); G_OBJECT_CLASS (tp_tests_simple_connection_parent_class)->finalize (object); } static gchar * get_unique_connection_name (TpBaseConnection *conn) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (conn); return g_strdup (self->priv->account); } static gchar * tp_tests_simple_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error) { if (id[0] == '\0') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "ID must not be empty"); return NULL; } if (strchr (id, ' ') != NULL) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "ID must not contain spaces"); return NULL; } return g_utf8_strdown (id, -1); } static void create_handle_repos (TpBaseConnection *conn, TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]) { repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_CONTACT, tp_tests_simple_normalize_contact, NULL); repos[TP_HANDLE_TYPE_ROOM] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_ROOM, NULL, NULL); } static GPtrArray * create_channel_factories (TpBaseConnection *conn) { return g_ptr_array_sized_new (0); } void tp_tests_simple_connection_inject_disconnect (TpTestsSimpleConnection *self) { tp_base_connection_change_status ((TpBaseConnection *) self, TP_CONNECTION_STATUS_DISCONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); } static gboolean pretend_connected (gpointer data) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (data); TpBaseConnection *conn = (TpBaseConnection *) self; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); conn->self_handle = tp_handle_ensure (contact_repo, self->priv->account, NULL, NULL); if (conn->status == TP_CONNECTION_STATUS_CONNECTING) { tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); } self->priv->connect_source = 0; return FALSE; } static gboolean start_connecting (TpBaseConnection *conn, GError **error) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (conn); tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTING, TP_CONNECTION_STATUS_REASON_REQUESTED); /* In a real connection manager we'd ask the underlying implementation to * start connecting, then go to state CONNECTED when finished. Here there * isn't actually a connection, so we'll fake a connection process that * takes time. */ self->priv->connect_source = g_timeout_add (0, pretend_connected, self); return TRUE; } static gboolean pretend_disconnected (gpointer data) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (data); /* We are disconnected, all our channels are invalidated */ g_hash_table_remove_all (self->priv->channels); tp_base_connection_finish_shutdown (TP_BASE_CONNECTION (data)); self->priv->disconnect_source = 0; return FALSE; } static void shut_down (TpBaseConnection *conn) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (conn); /* In a real connection manager we'd ask the underlying implementation to * start shutting down, then call this function when finished. Here there * isn't actually a connection, so we'll fake a disconnection process that * takes time. */ self->priv->disconnect_source = g_timeout_add (0, pretend_disconnected, conn); } static void tp_tests_simple_connection_class_init (TpTestsSimpleConnectionClass *klass) { TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_REQUESTS, NULL }; object_class->get_property = get_property; object_class->set_property = set_property; object_class->dispose = dispose; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (TpTestsSimpleConnectionPrivate)); base_class->create_handle_repos = create_handle_repos; base_class->get_unique_connection_name = get_unique_connection_name; base_class->create_channel_factories = create_channel_factories; base_class->start_connecting = start_connecting; base_class->shut_down = shut_down; base_class->interfaces_always_present = interfaces_always_present; param_spec = g_param_spec_string ("account", "Account name", "The username of this user", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); param_spec = g_param_spec_boolean ("break-0192-properties", "Break 0.19.2 properties", "Break Connection D-Bus properties introduced in spec 0.19.2", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_BREAK_PROPS, param_spec); param_spec = g_param_spec_uint ("dbus-status", "Connection.Status", "The connection status as visible on D-Bus (overridden so can break it)", TP_CONNECTION_STATUS_CONNECTED, G_MAXUINT, TP_CONNECTION_STATUS_DISCONNECTED, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_DBUS_STATUS, param_spec); signals[SIGNAL_GOT_SELF_HANDLE] = g_signal_new ("got-self-handle", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } void tp_tests_simple_connection_set_identifier (TpTestsSimpleConnection *self, const gchar *identifier) { TpBaseConnection *conn = (TpBaseConnection *) self; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); TpHandle handle = tp_handle_ensure (contact_repo, identifier, NULL, NULL); /* if this fails then the identifier was bad - caller error */ g_return_if_fail (handle != 0); tp_base_connection_set_self_handle (conn, handle); } TpTestsSimpleConnection * tp_tests_simple_connection_new (const gchar *account, const gchar *protocol) { return TP_TESTS_SIMPLE_CONNECTION (g_object_new ( TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", account, "protocol", protocol, NULL)); } gchar * tp_tests_simple_connection_ensure_text_chan (TpTestsSimpleConnection *self, const gchar *target_id, GHashTable **props) { TpTestsTextChannelNull *chan; gchar *chan_path; TpHandleRepoIface *contact_repo; TpHandle handle; static guint count = 0; TpBaseConnection *base_conn = (TpBaseConnection *) self; /* Get contact handle */ contact_repo = tp_base_connection_get_handles (base_conn, TP_HANDLE_TYPE_CONTACT); g_assert (contact_repo != NULL); handle = tp_handle_ensure (contact_repo, target_id, NULL, NULL); chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle)); if (chan != NULL) { /* Channel already exist, reuse it */ g_object_get (chan, "object-path", &chan_path, NULL); } else { chan_path = g_strdup_printf ("%s/Channel%u", base_conn->object_path, count++); chan = TP_TESTS_TEXT_CHANNEL_NULL ( tp_tests_object_new_static_class ( TP_TESTS_TYPE_TEXT_CHANNEL_NULL, "connection", self, "object-path", chan_path, "handle", handle, NULL)); g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle), chan); } if (props != NULL) *props = tp_tests_text_channel_get_props (chan); return chan_path; } void tp_tests_simple_connection_set_get_self_handle_error ( TpTestsSimpleConnection *self, GQuark domain, gint code, const gchar *message) { self->priv->get_self_handle_error = g_error_new_literal (domain, code, message); } static void get_self_handle (TpSvcConnection *iface, DBusGMethodInvocation *context) { TpTestsSimpleConnection *self = TP_TESTS_SIMPLE_CONNECTION (iface); TpBaseConnection *base = TP_BASE_CONNECTION (iface); g_assert (TP_IS_BASE_CONNECTION (base)); TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); if (self->priv->get_self_handle_error != NULL) { dbus_g_method_return_error (context, self->priv->get_self_handle_error); return; } tp_svc_connection_return_from_get_self_handle (context, base->self_handle); g_signal_emit (self, signals[SIGNAL_GOT_SELF_HANDLE], 0); } static void conn_iface_init (TpSvcConnectionClass *iface) { #define IMPLEMENT(prefix,x) \ tp_svc_connection_implement_##x (iface, prefix##x) IMPLEMENT(,get_self_handle); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/simple-channel-dispatch-operation.h0000664000175000017500000000556612470405660024454 0ustar jrjr/* * simple-channel-dispatch-operation.h - a simple channel dispatch operation * service. * * Copyright © 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION_H__ #define __TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION_H__ #include #include #include G_BEGIN_DECLS typedef struct _SimpleChannelDispatchOperation TpTestsSimpleChannelDispatchOperation; typedef struct _SimpleChannelDispatchOperationClass TpTestsSimpleChannelDispatchOperationClass; typedef struct _SimpleChannelDispatchOperationPrivate TpTestsSimpleChannelDispatchOperationPrivate; struct _SimpleChannelDispatchOperationClass { GObjectClass parent_class; TpDBusPropertiesMixinClass dbus_props_class; }; struct _SimpleChannelDispatchOperation { GObject parent; TpTestsSimpleChannelDispatchOperationPrivate *priv; }; GType tp_tests_simple_channel_dispatch_operation_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCH_OPERATION \ (tp_tests_simple_channel_dispatch_operation_get_type ()) #define TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCH_OPERATION, \ TpTestsSimpleChannelDispatchOperation)) #define TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCH_OPERATION, \ TpTestsSimpleChannelDispatchOperationClass)) #define SIMPLE_IS_CHANNEL_DISPATCH_OPERATION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCH_OPERATION)) #define SIMPLE_IS_CHANNEL_DISPATCH_OPERATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCH_OPERATION)) #define TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCH_OPERATION, \ TpTestsSimpleChannelDispatchOperationClass)) void tp_tests_simple_channel_dispatch_operation_set_conn_path ( TpTestsSimpleChannelDispatchOperation *self, const gchar *conn_path); void tp_tests_simple_channel_dispatch_operation_add_channel ( TpTestsSimpleChannelDispatchOperation *self, TpChannel *chan); void tp_tests_simple_channel_dispatch_operation_lost_channel ( TpTestsSimpleChannelDispatchOperation *self, TpChannel *chan); void tp_tests_simple_channel_dispatch_operation_set_account_path ( TpTestsSimpleChannelDispatchOperation *self, const gchar *account_path); G_END_DECLS #endif /* #ifndef __TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/contacts-noroster-conn.c0000664000175000017500000000264412470405660022371 0ustar jrjr/* * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "contacts-noroster-conn.h" #include #include #include #include #include G_DEFINE_TYPE_WITH_CODE (TpTestsContactsNorosterConnection, tp_tests_contacts_noroster_connection, TP_TESTS_TYPE_SIMPLE_CONNECTION, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, NULL); ); static void tp_tests_contacts_noroster_connection_init (TpTestsContactsNorosterConnection *self) { } static void finalize (GObject *object) { G_OBJECT_CLASS (tp_tests_contacts_noroster_connection_parent_class)->finalize (object); } static void tp_tests_contacts_noroster_connection_class_init (TpTestsContactsNorosterConnectionClass *klass) { TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_CONTACTS, NULL }; object_class->finalize = finalize; base_class->interfaces_always_present = interfaces_always_present; } telepathy-qt-0.9.6~git1/tests/lib/glib/bug16307-conn.c0000664000175000017500000001452712470405660020063 0ustar jrjr/* * bug16307-conn.c - connection that reproduces the #15307 bug * * Copyright (C) 2007-2008 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "bug16307-conn.h" #include #include #include #include #include #include #include static void service_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (TpTestsBug16307Connection, tp_tests_bug16307_connection, TP_TESTS_TYPE_SIMPLE_CONNECTION, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION, service_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING, NULL); ); /* type definition stuff */ enum { SIGNAL_GET_STATUS_RECEIVED, N_SIGNALS }; static guint signals[N_SIGNALS] = {0}; struct _TpTestsBug16307ConnectionPrivate { /* In a real connection manager, the underlying implementation start * connecting, then go to state CONNECTED when finished. Here there isn't * actually a connection, so the connection process is fake and the time * when it connects is, for this test purpose, when the D-Bus method GetStatus * is called. * * Also, the GetStatus D-Bus reply is delayed until * tp_tests_bug16307_connection_inject_get_status_return() is called */ DBusGMethodInvocation *get_status_invocation; }; static void tp_tests_bug16307_connection_init (TpTestsBug16307Connection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_BUG16307_CONNECTION, TpTestsBug16307ConnectionPrivate); } static void finalize (GObject *object) { G_OBJECT_CLASS (tp_tests_bug16307_connection_parent_class)->finalize (object); } static gboolean pretend_connected (gpointer data) { TpTestsBug16307Connection *self = TP_TESTS_BUG16307_CONNECTION (data); TpBaseConnection *conn = (TpBaseConnection *) self; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); gchar *account; g_object_get (self, "account", &account, NULL); conn->self_handle = tp_handle_ensure (contact_repo, account, NULL, NULL); g_free (account); tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); return FALSE; } void tp_tests_bug16307_connection_inject_get_status_return (TpTestsBug16307Connection *self) { TpBaseConnection *self_base = TP_BASE_CONNECTION (self); DBusGMethodInvocation *context; gulong get_signal_id; /* if we don't have a pending get_status yet, wait for it */ if (self->priv->get_status_invocation == NULL) { GMainLoop *loop = g_main_loop_new (NULL, FALSE); get_signal_id = g_signal_connect_swapped (self, "get-status-received", G_CALLBACK (g_main_loop_quit), loop); g_main_loop_run (loop); g_signal_handler_disconnect (self, get_signal_id); g_main_loop_unref (loop); } context = self->priv->get_status_invocation; g_assert (context != NULL); if (self_base->status == TP_INTERNAL_CONNECTION_STATUS_NEW) { tp_svc_connection_return_from_get_status ( context, TP_CONNECTION_STATUS_DISCONNECTED); } else { tp_svc_connection_return_from_get_status ( context, self_base->status); } self->priv->get_status_invocation = NULL; } static gboolean start_connecting (TpBaseConnection *conn, GError **error) { tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTING, TP_CONNECTION_STATUS_REASON_REQUESTED); return TRUE; } static void tp_tests_bug16307_connection_class_init (TpTestsBug16307ConnectionClass *klass) { TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_ALIASING, TP_IFACE_CONNECTION_INTERFACE_CAPABILITIES, TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_AVATARS, NULL }; static TpDBusPropertiesMixinPropImpl connection_properties[] = { { "Status", "dbus-status-except-i-broke-it", NULL }, { NULL } }; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (TpTestsBug16307ConnectionPrivate)); base_class->start_connecting = start_connecting; base_class->interfaces_always_present = interfaces_always_present; signals[SIGNAL_GET_STATUS_RECEIVED] = g_signal_new ("get-status-received", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /* break the Connection D-Bus properties implementation, so that we always * cause the slower introspection codepath (the one that actually calls * GetStatus) in TpConnection to be invoked */ tp_dbus_properties_mixin_implement_interface (object_class, TP_IFACE_QUARK_CONNECTION, NULL, NULL, connection_properties); } /** * tp_tests_bug16307_connection_get_status * * Implements D-Bus method GetStatus * on interface org.freedesktop.Telepathy.Connection */ static void tp_tests_bug16307_connection_get_status (TpSvcConnection *iface, DBusGMethodInvocation *context) { TpBaseConnection *self_base = TP_BASE_CONNECTION (iface); TpTestsBug16307Connection *self = TP_TESTS_BUG16307_CONNECTION (iface); /* auto-connect on get_status */ if ((self_base->status == TP_INTERNAL_CONNECTION_STATUS_NEW || self_base->status == TP_CONNECTION_STATUS_DISCONNECTED)) { pretend_connected (self); } /* D-Bus return call later */ g_assert (self->priv->get_status_invocation == NULL); g_assert (context != NULL); self->priv->get_status_invocation = context; g_signal_emit (self, signals[SIGNAL_GET_STATUS_RECEIVED], 0); } static void service_iface_init (gpointer g_iface, gpointer iface_data) { TpSvcConnectionClass *klass = g_iface; #define IMPLEMENT(prefix,x) tp_svc_connection_implement_##x (klass, \ tp_tests_bug16307_connection_##prefix##x) IMPLEMENT(,get_status); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/callable/0000775000175000017500000000000012470405660017334 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib/callable/connection-manager.h0000664000175000017500000000552112470405660023257 0ustar jrjr/* * manager.h - header for an example connection manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __EXAMPLE_CALLABLE_CONNECTION_MANAGER_H__ #define __EXAMPLE_CALLABLE_CONNECTION_MANAGER_H__ #include #include G_BEGIN_DECLS typedef struct _ExampleCallableConnectionManager ExampleCallableConnectionManager; typedef struct _ExampleCallableConnectionManagerPrivate ExampleCallableConnectionManagerPrivate; typedef struct _ExampleCallableConnectionManagerClass ExampleCallableConnectionManagerClass; typedef struct _ExampleCallableConnectionManagerClassPrivate ExampleCallableConnectionManagerClassPrivate; struct _ExampleCallableConnectionManagerClass { TpBaseConnectionManagerClass parent_class; ExampleCallableConnectionManagerClassPrivate *priv; }; struct _ExampleCallableConnectionManager { TpBaseConnectionManager parent; ExampleCallableConnectionManagerPrivate *priv; }; GType example_callable_connection_manager_get_type (void); /* TYPE MACROS */ #define EXAMPLE_TYPE_CALLABLE_CONNECTION_MANAGER \ (example_callable_connection_manager_get_type ()) #define EXAMPLE_CALLABLE_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CALLABLE_CONNECTION_MANAGER, \ ExampleCallableConnectionManager)) #define EXAMPLE_CALLABLE_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CALLABLE_CONNECTION_MANAGER, \ ExampleCallableConnectionManagerClass)) #define EXAMPLE_IS_CALLABLE_CONNECTION_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CALLABLE_CONNECTION_MANAGER)) #define EXAMPLE_IS_CALLABLE_CONNECTION_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CALLABLE_CONNECTION_MANAGER)) #define EXAMPLE_CALLABLE_CONNECTION_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALLABLE_CONNECTION_MANAGER, \ ExampleCallableConnectionManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/callable/media-manager.c0000664000175000017500000003510412470405660022172 0ustar jrjr/* * media-manager.c - an example channel manager for StreamedMedia calls. * This channel manager emulates a protocol like XMPP Jingle, where you can * make several simultaneous calls to the same or different contacts. * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "media-manager.h" #include #include #include #include #include #include #include "media-channel.h" static void channel_manager_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (ExampleCallableMediaManager, example_callable_media_manager, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, channel_manager_iface_init)) /* type definition stuff */ enum { PROP_CONNECTION = 1, PROP_SIMULATION_DELAY, N_PROPS }; struct _ExampleCallableMediaManagerPrivate { TpBaseConnection *conn; guint simulation_delay; /* Map from reffed ExampleCallableMediaChannel to the same pointer; used as a * set. */ GHashTable *channels; /* Next channel will be ("MediaChannel%u", next_channel_index) */ guint next_channel_index; gulong status_changed_id; gulong available_id; }; static void example_callable_media_manager_init (ExampleCallableMediaManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALLABLE_MEDIA_MANAGER, ExampleCallableMediaManagerPrivate); self->priv->conn = NULL; self->priv->channels = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL); self->priv->status_changed_id = 0; self->priv->available_id = 0; } static void example_callable_media_manager_close_all (ExampleCallableMediaManager *self) { if (self->priv->channels != NULL) { GHashTable *tmp = self->priv->channels; self->priv->channels = NULL; g_hash_table_unref (tmp); } if (self->priv->available_id != 0) { g_signal_handler_disconnect (self->priv->conn, self->priv->available_id); self->priv->available_id = 0; } if (self->priv->status_changed_id != 0) { g_signal_handler_disconnect (self->priv->conn, self->priv->status_changed_id); self->priv->status_changed_id = 0; } } static void dispose (GObject *object) { ExampleCallableMediaManager *self = EXAMPLE_CALLABLE_MEDIA_MANAGER (object); example_callable_media_manager_close_all (self); g_assert (self->priv->channels == NULL); ((GObjectClass *) example_callable_media_manager_parent_class)->dispose ( object); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleCallableMediaManager *self = EXAMPLE_CALLABLE_MEDIA_MANAGER (object); switch (property_id) { case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleCallableMediaManager *self = EXAMPLE_CALLABLE_MEDIA_MANAGER (object); switch (property_id) { case PROP_CONNECTION: /* We don't ref the connection, because it owns a reference to the * channel manager, and it guarantees that the manager's lifetime is * less than its lifetime */ self->priv->conn = g_value_get_object (value); break; case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } static void status_changed_cb (TpBaseConnection *conn, guint status, guint reason, ExampleCallableMediaManager *self) { switch (status) { case TP_CONNECTION_STATUS_DISCONNECTED: { example_callable_media_manager_close_all (self); } break; default: break; } } static ExampleCallableMediaChannel *new_channel ( ExampleCallableMediaManager *self, TpHandle handle, TpHandle initiator, gpointer request_token, gboolean initial_audio, gboolean initial_video); static gboolean simulate_incoming_call_cb (gpointer p) { ExampleCallableMediaManager *self = p; TpHandleRepoIface *contact_repo; TpHandle caller; /* do nothing if we've been disconnected while waiting for the contact to * call us */ if (self->priv->available_id == 0) return FALSE; /* We're called by someone whose ID on the IM service is "caller" */ contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); caller = tp_handle_ensure (contact_repo, "caller", NULL, NULL); new_channel (self, caller, caller, NULL, TRUE, FALSE); return FALSE; } /* Whenever our presence changes from away to available, and whenever our * presence message changes while remaining available, simulate a call from * a contact */ static void available_cb (GObject *conn G_GNUC_UNUSED, const gchar *message, ExampleCallableMediaManager *self) { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_incoming_call_cb, g_object_ref (self), g_object_unref); } static void constructed (GObject *object) { ExampleCallableMediaManager *self = EXAMPLE_CALLABLE_MEDIA_MANAGER (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_callable_media_manager_parent_class)->constructed; if (chain_up != NULL) { chain_up (object); } self->priv->status_changed_id = g_signal_connect (self->priv->conn, "status-changed", (GCallback) status_changed_cb, self); self->priv->available_id = g_signal_connect (self->priv->conn, "available", (GCallback) available_cb, self); } static void example_callable_media_manager_class_init ( ExampleCallableMediaManagerClass *klass) { GParamSpec *param_spec; GObjectClass *object_class = (GObjectClass *) klass; object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; param_spec = g_param_spec_object ("connection", "Connection object", "The connection that owns this channel manager", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); g_type_class_add_private (klass, sizeof (ExampleCallableMediaManagerPrivate)); } static void example_callable_media_manager_foreach_channel ( TpChannelManager *iface, TpExportableChannelFunc callback, gpointer user_data) { ExampleCallableMediaManager *self = EXAMPLE_CALLABLE_MEDIA_MANAGER (iface); GHashTableIter iter; gpointer chan; g_hash_table_iter_init (&iter, self->priv->channels); while (g_hash_table_iter_next (&iter, &chan, NULL)) callback (chan, user_data); } static void channel_closed_cb (ExampleCallableMediaChannel *chan, ExampleCallableMediaManager *self) { tp_channel_manager_emit_channel_closed_for_object (self, TP_EXPORTABLE_CHANNEL (chan)); if (self->priv->channels != NULL) g_hash_table_remove (self->priv->channels, chan); } static ExampleCallableMediaChannel * new_channel (ExampleCallableMediaManager *self, TpHandle handle, TpHandle initiator, gpointer request_token, gboolean initial_audio, gboolean initial_video) { ExampleCallableMediaChannel *chan; gchar *object_path; GSList *requests = NULL; /* FIXME: This could potentially wrap around, but only after 4 billion * calls, which is probably plenty. */ object_path = g_strdup_printf ("%s/MediaChannel%u", self->priv->conn->object_path, self->priv->next_channel_index++); chan = g_object_new (EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL, "connection", self->priv->conn, "object-path", object_path, "handle", handle, "initiator-handle", initiator, "requested", (self->priv->conn->self_handle == initiator), "simulation-delay", self->priv->simulation_delay, "initial-audio", initial_audio, "initial-video", initial_video, NULL); g_free (object_path); g_signal_connect (chan, "closed", G_CALLBACK (channel_closed_cb), self); g_hash_table_insert (self->priv->channels, chan, chan); if (request_token != NULL) requests = g_slist_prepend (requests, request_token); tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan), requests); g_slist_free (requests); return chan; } static const gchar * const fixed_properties[] = { TP_PROP_CHANNEL_CHANNEL_TYPE, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL }; static const gchar * const allowed_properties[] = { TP_PROP_CHANNEL_TARGET_HANDLE, TP_PROP_CHANNEL_TARGET_ID, NULL }; static void example_callable_media_manager_foreach_channel_class ( TpChannelManager *manager, TpChannelManagerChannelClassFunc func, gpointer user_data) { GHashTable *table = tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, NULL); func (manager, table, allowed_properties, user_data); g_hash_table_destroy (table); } static gboolean example_callable_media_manager_request (ExampleCallableMediaManager *self, gpointer request_token, GHashTable *request_properties, gboolean require_new) { TpHandle handle; GError *error = NULL; if (tp_strdiff (tp_asv_get_string (request_properties, TP_PROP_CHANNEL_CHANNEL_TYPE), TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) { return FALSE; } if (tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != TP_HANDLE_TYPE_CONTACT) { return FALSE; } handle = tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE, NULL); g_assert (handle != 0); if (tp_channel_manager_asv_has_unknown_properties (request_properties, fixed_properties, allowed_properties, &error)) { goto error; } if (handle == self->priv->conn->self_handle) { /* In protocols with a concept of multiple "resources" signed in to * one account (XMPP, and possibly MSN) it is technically possible to * call yourself - e.g. if you're signed in on two PCs, you can call one * from the other. For simplicity, this example simulates a protocol * where this is not the case. */ g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "In this protocol, you can't call yourself"); goto error; } if (!require_new) { /* see if we're already calling that handle */ GHashTableIter iter; gpointer chan; g_hash_table_iter_init (&iter, self->priv->channels); while (g_hash_table_iter_next (&iter, &chan, NULL)) { guint its_handle; g_object_get (chan, "handle", &its_handle, NULL); if (its_handle == handle) { tp_channel_manager_emit_request_already_satisfied (self, request_token, TP_EXPORTABLE_CHANNEL (chan)); return TRUE; } } } new_channel (self, handle, self->priv->conn->self_handle, request_token, FALSE, FALSE); return TRUE; error: tp_channel_manager_emit_request_failed (self, request_token, error->domain, error->code, error->message); g_error_free (error); return TRUE; } static gboolean example_callable_media_manager_create_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_callable_media_manager_request ( EXAMPLE_CALLABLE_MEDIA_MANAGER (manager), request_token, request_properties, TRUE); } static gboolean example_callable_media_manager_ensure_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { return example_callable_media_manager_request ( EXAMPLE_CALLABLE_MEDIA_MANAGER (manager), request_token, request_properties, FALSE); } static void channel_manager_iface_init (gpointer g_iface, gpointer iface_data G_GNUC_UNUSED) { TpChannelManagerIface *iface = g_iface; iface->foreach_channel = example_callable_media_manager_foreach_channel; iface->foreach_channel_class = example_callable_media_manager_foreach_channel_class; iface->create_channel = example_callable_media_manager_create_channel; iface->ensure_channel = example_callable_media_manager_ensure_channel; /* In this channel manager, RequestChannel is not supported (it's new * code so there's no reason to be backwards compatible). The requirements * for RequestChannel are somewhat complicated for backwards compatibility * reasons: see telepathy-gabble or * http://telepathy.freedesktop.org/wiki/Requesting%20StreamedMedia%20channels * for the gory details. */ iface->request_channel = NULL; } telepathy-qt-0.9.6~git1/tests/lib/glib/callable/conn.h0000664000175000017500000000524012470405660020443 0ustar jrjr/* * conn.h - header for an example connection * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __EXAMPLE_CALLABLE_CONN_H__ #define __EXAMPLE_CALLABLE_CONN_H__ #include #include #include #include G_BEGIN_DECLS typedef struct _ExampleCallableConnection ExampleCallableConnection; typedef struct _ExampleCallableConnectionPrivate ExampleCallableConnectionPrivate; typedef struct _ExampleCallableConnectionClass ExampleCallableConnectionClass; typedef struct _ExampleCallableConnectionClassPrivate ExampleCallableConnectionClassPrivate; struct _ExampleCallableConnectionClass { TpBaseConnectionClass parent_class; TpPresenceMixinClass presence_mixin; TpContactsMixinClass contacts_mixin; ExampleCallableConnectionClassPrivate *priv; }; struct _ExampleCallableConnection { TpBaseConnection parent; TpPresenceMixin presence_mixin; TpContactsMixin contacts_mixin; ExampleCallableConnectionPrivate *priv; }; GType example_callable_connection_get_type (void); #define EXAMPLE_TYPE_CALLABLE_CONNECTION \ (example_callable_connection_get_type ()) #define EXAMPLE_CALLABLE_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CALLABLE_CONNECTION, \ ExampleCallableConnection)) #define EXAMPLE_CALLABLE_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CALLABLE_CONNECTION, \ ExampleCallableConnectionClass)) #define EXAMPLE_IS_CALLABLE_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CALLABLE_CONNECTION)) #define EXAMPLE_IS_CALLABLE_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CALLABLE_CONNECTION)) #define EXAMPLE_CALLABLE_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALLABLE_CONNECTION, \ ExampleCallableConnectionClass)) gchar *example_callable_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error); /* Must be kept in sync with the array presence_statuses in conn.c */ typedef enum { EXAMPLE_CALLABLE_PRESENCE_OFFLINE = 0, EXAMPLE_CALLABLE_PRESENCE_UNKNOWN, EXAMPLE_CALLABLE_PRESENCE_ERROR, EXAMPLE_CALLABLE_PRESENCE_AWAY, EXAMPLE_CALLABLE_PRESENCE_AVAILABLE } ExampleCallablePresence; G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/callable/CMakeLists.txt0000664000175000017500000000110312470405660022067 0ustar jrjrif(ENABLE_TP_GLIB_TESTS) set(example_cm_callable_SRCS conn.c conn.h connection-manager.c connection-manager.h media-channel.c media-channel.h media-manager.c media-manager.h media-stream.c media-stream.h) add_library(example-cm-callable STATIC ${example_cm_callable_SRCS}) target_link_libraries(example-cm-callable ${TPGLIB_LIBRARIES}) tpqt_generate_manager_file(${CMAKE_CURRENT_SOURCE_DIR}/manager-file.py example_callable.manager connection-manager.c) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib/callable/manager-file.py0000664000175000017500000000115612470405660022240 0ustar jrjr# Input for tools/manager-file.py MANAGER = 'example_callable' PARAMS = { 'example' : { 'account': { 'dtype': 's', 'flags': 'required register', 'filter': 'account_param_filter', # 'filter_data': 'NULL', # 'default': ..., # 'struct_field': '...', # 'setter_data': 'NULL', }, 'simulation-delay': { 'dtype': 'u', 'default': 1000, }, }, } STRUCTS = { 'example': 'ExampleParams' } telepathy-qt-0.9.6~git1/tests/lib/glib/callable/media-manager.h0000664000175000017500000000514612470405660022202 0ustar jrjr/* * media-manager.h - header for an example channel manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __EXAMPLE_CALLABLE_MEDIA_MANAGER_H__ #define __EXAMPLE_CALLABLE_MEDIA_MANAGER_H__ #include G_BEGIN_DECLS typedef struct _ExampleCallableMediaManager ExampleCallableMediaManager; typedef struct _ExampleCallableMediaManagerPrivate ExampleCallableMediaManagerPrivate; typedef struct _ExampleCallableMediaManagerClass ExampleCallableMediaManagerClass; typedef struct _ExampleCallableMediaManagerClassPrivate ExampleCallableMediaManagerClassPrivate; struct _ExampleCallableMediaManagerClass { GObjectClass parent_class; ExampleCallableMediaManagerClassPrivate *priv; }; struct _ExampleCallableMediaManager { GObject parent; ExampleCallableMediaManagerPrivate *priv; }; GType example_callable_media_manager_get_type (void); /* TYPE MACROS */ #define EXAMPLE_TYPE_CALLABLE_MEDIA_MANAGER \ (example_callable_media_manager_get_type ()) #define EXAMPLE_CALLABLE_MEDIA_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_MANAGER, \ ExampleCallableMediaManager)) #define EXAMPLE_CALLABLE_MEDIA_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_CALLABLE_MEDIA_MANAGER, \ ExampleCallableMediaManagerClass)) #define EXAMPLE_IS_CALLABLE_MEDIA_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_MANAGER)) #define EXAMPLE_IS_CALLABLE_MEDIA_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_CALLABLE_MEDIA_MANAGER)) #define EXAMPLE_CALLABLE_MEDIA_MANAGER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_MANAGER, \ ExampleCallableMediaManagerClass)) G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/callable/media-stream.h0000664000175000017500000000652112470405660022061 0ustar jrjr/* * media-stream.h - header for an example stream * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __EXAMPLE_CALLABLE_MEDIA_STREAM_H__ #define __EXAMPLE_CALLABLE_MEDIA_STREAM_H__ #include #include G_BEGIN_DECLS typedef struct _ExampleCallableMediaStream ExampleCallableMediaStream; typedef struct _ExampleCallableMediaStreamPrivate ExampleCallableMediaStreamPrivate; typedef struct _ExampleCallableMediaStreamClass ExampleCallableMediaStreamClass; typedef struct _ExampleCallableMediaStreamClassPrivate ExampleCallableMediaStreamClassPrivate; GType example_callable_media_stream_get_type (void); #define EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM \ (example_callable_media_stream_get_type ()) #define EXAMPLE_CALLABLE_MEDIA_STREAM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM, \ ExampleCallableMediaStream)) #define EXAMPLE_CALLABLE_MEDIA_STREAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM, \ ExampleCallableMediaStreamClass)) #define EXAMPLE_IS_CALLABLE_MEDIA_STREAM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM)) #define EXAMPLE_IS_CALLABLE_MEDIA_STREAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM)) #define EXAMPLE_CALLABLE_MEDIA_STREAM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM, \ ExampleCallableMediaStreamClass)) struct _ExampleCallableMediaStreamClass { GObjectClass parent_class; ExampleCallableMediaStreamClassPrivate *priv; }; struct _ExampleCallableMediaStream { GObject parent; ExampleCallableMediaStreamPrivate *priv; }; void example_callable_media_stream_close (ExampleCallableMediaStream *self); gboolean example_callable_media_stream_change_direction ( ExampleCallableMediaStream *self, TpMediaStreamDirection direction, GError **error); void example_callable_media_stream_accept_proposed_direction ( ExampleCallableMediaStream *self); void example_callable_media_stream_connect (ExampleCallableMediaStream *self); /* This controls receiving emulated network events, so it wouldn't exist in * a real connection manager */ void example_callable_media_stream_simulate_contact_agreed_to_send ( ExampleCallableMediaStream *self); void example_callable_media_stream_receive_direction_request ( ExampleCallableMediaStream *self, TpMediaStreamDirection direction); G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/callable/conn.c0000664000175000017500000003104612470405660020441 0ustar jrjr/* * conn.c - an example connection * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "conn.h" #include #include #include #include #include #include "media-manager.h" G_DEFINE_TYPE_WITH_CODE (ExampleCallableConnection, example_callable_connection, TP_TYPE_BASE_CONNECTION, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, tp_contacts_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE, tp_presence_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE, tp_presence_mixin_simple_presence_iface_init)) enum { PROP_ACCOUNT = 1, PROP_SIMULATION_DELAY, N_PROPS }; enum { SIGNAL_AVAILABLE, N_SIGNALS }; static guint signals[N_SIGNALS] = { 0 }; struct _ExampleCallableConnectionPrivate { gchar *account; guint simulation_delay; gboolean away; gchar *presence_message; }; static void example_callable_connection_init (ExampleCallableConnection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALLABLE_CONNECTION, ExampleCallableConnectionPrivate); self->priv->away = FALSE; self->priv->presence_message = g_strdup (""); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { ExampleCallableConnection *self = EXAMPLE_CALLABLE_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_value_set_string (value, self->priv->account); break; case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *spec) { ExampleCallableConnection *self = EXAMPLE_CALLABLE_CONNECTION (object); switch (property_id) { case PROP_ACCOUNT: g_free (self->priv->account); self->priv->account = g_value_dup_string (value); break; case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); } } static void finalize (GObject *object) { ExampleCallableConnection *self = EXAMPLE_CALLABLE_CONNECTION (object); tp_contacts_mixin_finalize (object); g_free (self->priv->account); g_free (self->priv->presence_message); G_OBJECT_CLASS (example_callable_connection_parent_class)->finalize (object); } static gchar * get_unique_connection_name (TpBaseConnection *conn) { ExampleCallableConnection *self = EXAMPLE_CALLABLE_CONNECTION (conn); return g_strdup_printf ("%s@%p", self->priv->account, self); } gchar * example_callable_normalize_contact (TpHandleRepoIface *repo, const gchar *id, gpointer context, GError **error) { if (id[0] == '\0') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "Contact ID must not be empty"); return NULL; } return g_utf8_normalize (id, -1, G_NORMALIZE_ALL_COMPOSE); } static void create_handle_repos (TpBaseConnection *conn, TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]) { repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_CONTACT, example_callable_normalize_contact, NULL); } static GPtrArray * create_channel_managers (TpBaseConnection *conn) { ExampleCallableConnection *self = EXAMPLE_CALLABLE_CONNECTION (conn); GPtrArray *ret = g_ptr_array_sized_new (1); g_ptr_array_add (ret, g_object_new (EXAMPLE_TYPE_CALLABLE_MEDIA_MANAGER, "connection", conn, "simulation-delay", self->priv->simulation_delay, NULL)); return ret; } static gboolean start_connecting (TpBaseConnection *conn, GError **error) { ExampleCallableConnection *self = EXAMPLE_CALLABLE_CONNECTION (conn); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT); /* In a real connection manager we'd ask the underlying implementation to * start connecting, then go to state CONNECTED when finished, but here * we can do it immediately. */ conn->self_handle = tp_handle_ensure (contact_repo, self->priv->account, NULL, error); if (conn->self_handle == 0) return FALSE; tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); return TRUE; } static void shut_down (TpBaseConnection *conn) { /* In a real connection manager we'd ask the underlying implementation to * start shutting down, then call this function when finished, but here * we can do it immediately. */ tp_base_connection_finish_shutdown (conn); } static void constructed (GObject *object) { TpBaseConnection *base = TP_BASE_CONNECTION (object); void (*chain_up) (GObject *) = G_OBJECT_CLASS (example_callable_connection_parent_class)->constructed; if (chain_up != NULL) chain_up (object); tp_contacts_mixin_init (object, G_STRUCT_OFFSET (ExampleCallableConnection, contacts_mixin)); tp_base_connection_register_with_contacts_mixin (base); tp_presence_mixin_init (object, G_STRUCT_OFFSET (ExampleCallableConnection, presence_mixin)); tp_presence_mixin_simple_presence_register_with_contacts_mixin (object); } static gboolean status_available (GObject *object, guint index_) { TpBaseConnection *base = TP_BASE_CONNECTION (object); if (base->status != TP_CONNECTION_STATUS_CONNECTED) return FALSE; return TRUE; } static GHashTable * get_contact_statuses (GObject *object, const GArray *contacts, GError **error) { ExampleCallableConnection *self = EXAMPLE_CALLABLE_CONNECTION (object); TpBaseConnection *base = TP_BASE_CONNECTION (object); guint i; GHashTable *result = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) tp_presence_status_free); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, guint, i); ExampleCallablePresence presence; GHashTable *parameters; parameters = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); /* we know our own status from the connection; for this example CM, * everyone else's status is assumed to be "available" */ if (contact == base->self_handle) { presence = (self->priv->away ? EXAMPLE_CALLABLE_PRESENCE_AWAY : EXAMPLE_CALLABLE_PRESENCE_AVAILABLE); if (self->priv->presence_message[0] != '\0') g_hash_table_insert (parameters, "message", tp_g_value_slice_new_string (self->priv->presence_message)); } else { presence = EXAMPLE_CALLABLE_PRESENCE_AVAILABLE; } g_hash_table_insert (result, GUINT_TO_POINTER (contact), tp_presence_status_new (presence, parameters)); g_hash_table_destroy (parameters); } return result; } static gboolean set_own_status (GObject *object, const TpPresenceStatus *status, GError **error) { ExampleCallableConnection *self = EXAMPLE_CALLABLE_CONNECTION (object); TpBaseConnection *base = TP_BASE_CONNECTION (object); GHashTable *presences; const gchar *message = ""; if (status->optional_arguments != NULL) { GValue *v = g_hash_table_lookup (status->optional_arguments, "message"); if (v != NULL && G_VALUE_HOLDS_STRING (v)) { message = g_value_get_string (v); if (message == NULL) message = ""; } } if (status->index == EXAMPLE_CALLABLE_PRESENCE_AWAY) { if (self->priv->away && !tp_strdiff (message, self->priv->presence_message)) return TRUE; self->priv->away = TRUE; } else { if (!self->priv->away && !tp_strdiff (message, self->priv->presence_message)) return TRUE; self->priv->away = FALSE; } g_free (self->priv->presence_message); self->priv->presence_message = g_strdup (message); presences = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); g_hash_table_insert (presences, GUINT_TO_POINTER (base->self_handle), (gpointer) status); tp_presence_mixin_emit_presence_update (object, presences); g_hash_table_destroy (presences); if (!self->priv->away) { g_signal_emit (self, signals[SIGNAL_AVAILABLE], 0, message); } return TRUE; } static const TpPresenceStatusOptionalArgumentSpec can_have_message[] = { { "message", "s", NULL, NULL }, { NULL } }; /* Must be kept in sync with ExampleCallablePresence enum in header */ static const TpPresenceStatusSpec presence_statuses[] = { { "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, NULL }, { "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, NULL }, { "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, NULL }, { "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, can_have_message }, { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE, can_have_message }, { NULL } }; static void example_callable_connection_class_init ( ExampleCallableConnectionClass *klass) { static const gchar *interfaces_always_present[] = { TP_IFACE_CONNECTION_INTERFACE_CONTACTS, TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_REQUESTS, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, NULL }; TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; object_class->get_property = get_property; object_class->set_property = set_property; object_class->constructed = constructed; object_class->finalize = finalize; g_type_class_add_private (klass, sizeof (ExampleCallableConnectionPrivate)); base_class->create_handle_repos = create_handle_repos; base_class->get_unique_connection_name = get_unique_connection_name; base_class->create_channel_managers = create_channel_managers; base_class->start_connecting = start_connecting; base_class->shut_down = shut_down; base_class->interfaces_always_present = interfaces_always_present; param_spec = g_param_spec_string ("account", "Account name", "The username of this user", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); /* Used in the media manager, to simulate an incoming call when we become * available */ signals[SIGNAL_AVAILABLE] = g_signal_new ("available", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); tp_contacts_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleCallableConnectionClass, contacts_mixin)); tp_presence_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleCallableConnectionClass, presence_mixin), status_available, get_contact_statuses, set_own_status, presence_statuses); tp_presence_mixin_simple_presence_init_dbus_properties (object_class); } telepathy-qt-0.9.6~git1/tests/lib/glib/callable/media-channel.h0000664000175000017500000000535312470405660022200 0ustar jrjr/* * media-channel.h - header for an example channel * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __EXAMPLE_CALLABLE_MEDIA_CHANNEL_H__ #define __EXAMPLE_CALLABLE_MEDIA_CHANNEL_H__ #include #include G_BEGIN_DECLS typedef struct _ExampleCallableMediaChannel ExampleCallableMediaChannel; typedef struct _ExampleCallableMediaChannelPrivate ExampleCallableMediaChannelPrivate; typedef struct _ExampleCallableMediaChannelClass ExampleCallableMediaChannelClass; typedef struct _ExampleCallableMediaChannelClassPrivate ExampleCallableMediaChannelClassPrivate; GType example_callable_media_channel_get_type (void); #define EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL \ (example_callable_media_channel_get_type ()) #define EXAMPLE_CALLABLE_MEDIA_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL, \ ExampleCallableMediaChannel)) #define EXAMPLE_CALLABLE_MEDIA_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL, \ ExampleCallableMediaChannelClass)) #define EXAMPLE_IS_CALLABLE_MEDIA_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL)) #define EXAMPLE_IS_CALLABLE_MEDIA_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL)) #define EXAMPLE_CALLABLE_MEDIA_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL, \ ExampleCallableMediaChannelClass)) struct _ExampleCallableMediaChannelClass { GObjectClass parent_class; TpGroupMixinClass group_class; TpDBusPropertiesMixinClass dbus_properties_class; ExampleCallableMediaChannelClassPrivate *priv; }; struct _ExampleCallableMediaChannel { GObject parent; TpGroupMixin group; ExampleCallableMediaChannelPrivate *priv; }; G_END_DECLS #endif telepathy-qt-0.9.6~git1/tests/lib/glib/callable/connection-manager.c0000664000175000017500000000661412470405660023256 0ustar jrjr/* * manager.c - an example connection manager * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "connection-manager.h" #include #include #include #include "conn.h" G_DEFINE_TYPE (ExampleCallableConnectionManager, example_callable_connection_manager, TP_TYPE_BASE_CONNECTION_MANAGER) struct _ExampleCallableConnectionManagerPrivate { int dummy; }; static void example_callable_connection_manager_init ( ExampleCallableConnectionManager *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALLABLE_CONNECTION_MANAGER, ExampleCallableConnectionManagerPrivate); } typedef struct { gchar *account; guint simulation_delay; } ExampleParams; static gboolean account_param_filter (const TpCMParamSpec *paramspec, GValue *value, GError **error) { const gchar *id = g_value_get_string (value); g_value_take_string (value, example_callable_normalize_contact (NULL, id, NULL, error)); if (g_value_get_string (value) == NULL) return FALSE; return TRUE; } #include "_gen/param-spec-struct.h" static gpointer alloc_params (void) { ExampleParams *params = g_slice_new0 (ExampleParams); params->simulation_delay = 1000; return params; } static void free_params (gpointer p) { ExampleParams *params = p; g_free (params->account); g_slice_free (ExampleParams, params); } static const TpCMProtocolSpec example_protocols[] = { { "example", example_callable_example_params, alloc_params, free_params }, { NULL, NULL } }; static TpBaseConnection * new_connection (TpBaseConnectionManager *self, const gchar *proto, TpIntSet *params_present, gpointer parsed_params, GError **error) { ExampleParams *params = parsed_params; ExampleCallableConnection *conn; conn = EXAMPLE_CALLABLE_CONNECTION (g_object_new (EXAMPLE_TYPE_CALLABLE_CONNECTION, "account", params->account, "simulation-delay", params->simulation_delay, "protocol", proto, NULL)); return (TpBaseConnection *) conn; } static void example_callable_connection_manager_class_init ( ExampleCallableConnectionManagerClass *klass) { TpBaseConnectionManagerClass *base_class = (TpBaseConnectionManagerClass *) klass; g_type_class_add_private (klass, sizeof (ExampleCallableConnectionManagerPrivate)); base_class->new_connection = new_connection; base_class->cm_dbus_name = "example_callable"; base_class->protocol_params = example_protocols; } telepathy-qt-0.9.6~git1/tests/lib/glib/callable/media-channel.c0000664000175000017500000013162612470405660022176 0ustar jrjr/* * media-channel.c - an example 1-1 streamed media call. * * For simplicity, this channel emulates a device with its own * audio/video user interface, like a video-equipped form of the phones * manipulated by telepathy-snom or gnome-phone-manager. * * As a result, this channel does not have the MediaSignalling interface, and * clients should not attempt to do their own streaming using * telepathy-farsight, telepathy-stream-engine or maemo-stream-engine. * * In practice, nearly all connection managers also have the MediaSignalling * interface on their streamed media channels. Usage for those CMs is the * same, except that whichever client is the primary handler for the channel * should also hand the channel over to telepathy-farsight or * telepathy-stream-engine to implement the actual streaming. * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "media-channel.h" #include "media-stream.h" #include #include #include #include #include #include #include #include static void media_iface_init (gpointer iface, gpointer data); static void channel_iface_init (gpointer iface, gpointer data); static void hold_iface_init (gpointer iface, gpointer data); static void dtmf_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (ExampleCallableMediaChannel, example_callable_media_channel, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_STREAMED_MEDIA, media_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, tp_group_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_HOLD, hold_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DTMF, dtmf_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL)) enum { PROP_OBJECT_PATH = 1, PROP_CHANNEL_TYPE, PROP_HANDLE_TYPE, PROP_HANDLE, PROP_TARGET_ID, PROP_REQUESTED, PROP_INITIATOR_HANDLE, PROP_INITIATOR_ID, PROP_CONNECTION, PROP_INTERFACES, PROP_CHANNEL_DESTROYED, PROP_CHANNEL_PROPERTIES, PROP_SIMULATION_DELAY, PROP_INITIAL_AUDIO, PROP_INITIAL_VIDEO, N_PROPS }; enum { SIGNAL_CALL_TERMINATED, N_SIGNALS }; typedef enum { PROGRESS_NONE, PROGRESS_CALLING, PROGRESS_ACTIVE, PROGRESS_ENDED } ExampleCallableCallProgress; static guint signals[N_SIGNALS] = { 0 }; struct _ExampleCallableMediaChannelPrivate { TpBaseConnection *conn; gchar *object_path; TpHandle handle; TpHandle initiator; ExampleCallableCallProgress progress; guint simulation_delay; guint next_stream_id; GHashTable *streams; guint hold_state; guint hold_state_reason; gboolean locally_requested; gboolean initial_audio; gboolean initial_video; gboolean disposed; }; static const char * example_callable_media_channel_interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_GROUP, TP_IFACE_CHANNEL_INTERFACE_HOLD, TP_IFACE_CHANNEL_INTERFACE_DTMF, NULL }; static void example_callable_media_channel_init (ExampleCallableMediaChannel *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL, ExampleCallableMediaChannelPrivate); self->priv->next_stream_id = 1; self->priv->streams = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); self->priv->hold_state = TP_LOCAL_HOLD_STATE_UNHELD; self->priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_NONE; } static ExampleCallableMediaStream *example_callable_media_channel_add_stream ( ExampleCallableMediaChannel *self, TpMediaStreamType media_type, gboolean locally_requested); static void constructed (GObject *object) { void (*chain_up) (GObject *) = ((GObjectClass *) example_callable_media_channel_parent_class)->constructed; ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); TpIntSet *members; TpIntSet *local_pending; if (chain_up != NULL) chain_up (object); tp_dbus_daemon_register_object ( tp_base_connection_get_dbus_daemon (self->priv->conn), self->priv->object_path, self); tp_group_mixin_init (object, G_STRUCT_OFFSET (ExampleCallableMediaChannel, group), contact_repo, self->priv->conn->self_handle); /* Initially, the channel contains the initiator as a member; they are also * the actor for the change that adds any initial members. */ members = tp_intset_new_containing (self->priv->initiator); if (self->priv->locally_requested) { /* Nobody is locally pending. The remote peer will turn up in * remote-pending state when we actually contact them, which is done * in RequestStreams */ self->priv->progress = PROGRESS_NONE; local_pending = NULL; } else { /* This is an incoming call, so the self-handle is locally * pending, to indicate that we need to answer. */ self->priv->progress = PROGRESS_CALLING; local_pending = tp_intset_new_containing (self->priv->conn->self_handle); } tp_group_mixin_change_members (object, "", members /* added */, NULL /* nobody removed */, local_pending, /* added to local-pending */ NULL /* nobody added to remote-pending */, self->priv->initiator /* actor */, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (members); if (local_pending != NULL) tp_intset_destroy (local_pending); /* We don't need to allow adding or removing members to this Group in ways * that need flags set, so the only flag we set is to say we support the * Properties interface to the Group. * * It doesn't make sense to add anyone to the Group, since we already know * who we're going to call (or were called by). The only call to AddMembers * we need to support is to move ourselves from local-pending to member in * the incoming call case, and that's always allowed anyway. * * (Connection managers that support the various backwards-compatible * ways to make an outgoing StreamedMedia channel have to support adding the * peer to remote-pending, but that has no actual effect other than to * obscure what's going on; in this one, there's no need to support that * usage.) * * Similarly, it doesn't make sense to remove anyone from this Group apart * from ourselves (to hang up), and removing the SelfHandle is always * allowed anyway. */ tp_group_mixin_change_flags (object, TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0); /* Future versions of telepathy-spec will allow a channel request to * say "initially include an audio stream" and/or "initially include a video * stream", which would be represented like this; we don't support this * usage yet, though, so ExampleCallableMediaManager will never invoke * our constructor in this way. */ g_assert (!(self->priv->locally_requested && self->priv->initial_audio)); g_assert (!(self->priv->locally_requested && self->priv->initial_video)); if (!self->priv->locally_requested) { /* the caller has almost certainly asked us for some streams - there's * not much point in having a call otherwise */ if (self->priv->initial_audio) { g_message ("Channel initially has an audio stream"); example_callable_media_channel_add_stream (self, TP_MEDIA_STREAM_TYPE_AUDIO, FALSE); } if (self->priv->initial_video) { g_message ("Channel initially has a video stream"); example_callable_media_channel_add_stream (self, TP_MEDIA_STREAM_TYPE_VIDEO, FALSE); } } } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: g_value_set_string (value, self->priv->object_path); break; case PROP_CHANNEL_TYPE: g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); break; case PROP_HANDLE_TYPE: g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); break; case PROP_HANDLE: g_value_set_uint (value, self->priv->handle); break; case PROP_TARGET_ID: { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( self->priv->conn, TP_HANDLE_TYPE_CONTACT); g_value_set_string (value, tp_handle_inspect (contact_repo, self->priv->handle)); } break; case PROP_REQUESTED: g_value_set_boolean (value, self->priv->locally_requested); break; case PROP_INITIATOR_HANDLE: g_value_set_uint (value, self->priv->initiator); break; case PROP_INITIATOR_ID: { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( self->priv->conn, TP_HANDLE_TYPE_CONTACT); g_value_set_string (value, tp_handle_inspect (contact_repo, self->priv->initiator)); } break; case PROP_CONNECTION: g_value_set_object (value, self->priv->conn); break; case PROP_INTERFACES: g_value_set_boxed (value, example_callable_media_channel_interfaces); break; case PROP_CHANNEL_DESTROYED: g_value_set_boolean (value, (self->priv->progress == PROGRESS_ENDED)); break; case PROP_CHANNEL_PROPERTIES: g_value_take_boxed (value, tp_dbus_properties_mixin_make_properties_hash (object, TP_IFACE_CHANNEL, "ChannelType", TP_IFACE_CHANNEL, "TargetHandleType", TP_IFACE_CHANNEL, "TargetHandle", TP_IFACE_CHANNEL, "TargetID", TP_IFACE_CHANNEL, "InitiatorHandle", TP_IFACE_CHANNEL, "InitiatorID", TP_IFACE_CHANNEL, "Requested", TP_IFACE_CHANNEL, "Interfaces", NULL)); break; case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; case PROP_INITIAL_AUDIO: g_value_set_boolean (value, self->priv->initial_audio); break; case PROP_INITIAL_VIDEO: g_value_set_boolean (value, self->priv->initial_video); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (object); switch (property_id) { case PROP_OBJECT_PATH: g_assert (self->priv->object_path == NULL); self->priv->object_path = g_value_dup_string (value); break; case PROP_HANDLE: /* we don't ref it here because we don't necessarily have access to the * contact repo yet - instead we ref it in the constructor. */ self->priv->handle = g_value_get_uint (value); break; case PROP_INITIATOR_HANDLE: /* likewise */ self->priv->initiator = g_value_get_uint (value); break; case PROP_REQUESTED: self->priv->locally_requested = g_value_get_boolean (value); break; case PROP_HANDLE_TYPE: case PROP_CHANNEL_TYPE: /* these properties are writable in the interface, but not actually * meaningfully changable on this channel, so we do nothing */ break; case PROP_CONNECTION: self->priv->conn = g_value_get_object (value); break; case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; case PROP_INITIAL_AUDIO: self->priv->initial_audio = g_value_get_boolean (value); break; case PROP_INITIAL_VIDEO: self->priv->initial_video = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void example_callable_media_channel_close (ExampleCallableMediaChannel *self, TpHandle actor, TpChannelGroupChangeReason reason) { if (self->priv->progress != PROGRESS_ENDED) { TpIntSet *everyone; self->priv->progress = PROGRESS_ENDED; if (actor == self->group.self_handle) { const gchar *send_reason; /* In a real protocol these would be some sort of real protocol * construct, like an XMPP error stanza or a SIP error code */ switch (reason) { case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY: send_reason = ""; break; case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER: send_reason = ""; break; default: send_reason = ""; } g_message ("SIGNALLING: send: Terminating call: %s", send_reason); } everyone = tp_intset_new_containing (self->priv->handle); tp_intset_add (everyone, self->group.self_handle); tp_group_mixin_change_members ((GObject *) self, "", NULL /* nobody added */, everyone /* removed */, NULL /* nobody locally pending */, NULL /* nobody remotely pending */, actor, reason); tp_intset_destroy (everyone); g_signal_emit (self, signals[SIGNAL_CALL_TERMINATED], 0); tp_svc_channel_emit_closed (self); } } static void dispose (GObject *object) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (object); if (self->priv->disposed) return; self->priv->disposed = TRUE; g_hash_table_destroy (self->priv->streams); self->priv->streams = NULL; example_callable_media_channel_close (self, self->group.self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); ((GObjectClass *) example_callable_media_channel_parent_class)->dispose (object); } static void finalize (GObject *object) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (object); g_free (self->priv->object_path); tp_group_mixin_finalize (object); ((GObjectClass *) example_callable_media_channel_parent_class)->finalize (object); } static gboolean add_member (GObject *object, TpHandle member, const gchar *message, GError **error) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); /* In connection managers that supported the RequestChannel method for * streamed media channels, it would be necessary to support adding the * called contact to the members of an outgoing call. However, in this * legacy-free example, we don't support that usage, so the only use for * AddMembers is to accept an incoming call. */ if (member == self->group.self_handle && tp_handle_set_is_member (self->group.local_pending, member)) { /* We're in local-pending, move to members to accept. */ TpIntSet *set = tp_intset_new_containing (member); GHashTableIter iter; gpointer v; g_assert (self->priv->progress == PROGRESS_CALLING); g_message ("SIGNALLING: send: Accepting incoming call from %s", tp_handle_inspect (contact_repo, self->priv->handle)); self->priv->progress = PROGRESS_ACTIVE; tp_group_mixin_change_members (object, "", set /* added */, NULL /* nobody removed */, NULL /* nobody added to local pending */, NULL /* nobody added to remote pending */, member /* actor */, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); g_hash_table_iter_init (&iter, self->priv->streams); while (g_hash_table_iter_next (&iter, NULL, &v)) { /* we accept the proposed stream direction... */ example_callable_media_stream_accept_proposed_direction (v); /* ... and the stream tries to connect */ example_callable_media_stream_connect (v); } return TRUE; } /* Otherwise it's a meaningless request, so reject it. */ g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Cannot add handle %u to channel", member); return FALSE; } static gboolean remove_member_with_reason (GObject *object, TpHandle member, const gchar *message, guint reason, GError **error) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (object); /* The TpGroupMixin won't call this unless removing the member is allowed * by the group flags, which in this case means it must be our own handle * (because the other user never appears in local-pending). */ g_assert (member == self->group.self_handle); example_callable_media_channel_close (self, self->group.self_handle, reason); return TRUE; } static void example_callable_media_channel_class_init (ExampleCallableMediaChannelClass *klass) { static TpDBusPropertiesMixinPropImpl channel_props[] = { { "TargetHandleType", "handle-type", NULL }, { "TargetHandle", "handle", NULL }, { "ChannelType", "channel-type", NULL }, { "Interfaces", "interfaces", NULL }, { "TargetID", "target-id", NULL }, { "Requested", "requested", NULL }, { "InitiatorHandle", "initiator-handle", NULL }, { "InitiatorID", "initiator-id", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_CHANNEL, tp_dbus_properties_mixin_getter_gobject_properties, NULL, channel_props, }, { NULL } }; GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (ExampleCallableMediaChannelPrivate)); object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path"); g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type"); g_object_class_override_property (object_class, PROP_HANDLE, "handle"); g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, "channel-destroyed"); g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, "channel-properties"); param_spec = g_param_spec_object ("connection", "TpBaseConnection object", "Connection object that owns this channel", TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "Additional Channel.Interface.* interfaces", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_string ("target-id", "Peer's ID", "The string obtained by inspecting the target handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", "The contact who initiated the channel", 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, param_spec); param_spec = g_param_spec_string ("initiator-id", "Initiator's ID", "The string obtained by inspecting the initiator-handle", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIATOR_ID, param_spec); param_spec = g_param_spec_boolean ("requested", "Requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); param_spec = g_param_spec_boolean ("initial-audio", "Initial audio?", "True if this channel had an audio stream when first announced", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIAL_AUDIO, param_spec); param_spec = g_param_spec_boolean ("initial-video", "Initial video?", "True if this channel had a video stream when first announced", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INITIAL_VIDEO, param_spec); signals[SIGNAL_CALL_TERMINATED] = g_signal_new ("call-terminated", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); klass->dbus_properties_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleCallableMediaChannelClass, dbus_properties_class)); tp_group_mixin_class_init (object_class, G_STRUCT_OFFSET (ExampleCallableMediaChannelClass, group_class), add_member, NULL); tp_group_mixin_class_allow_self_removal (object_class); tp_group_mixin_class_set_remove_with_reason_func (object_class, remove_member_with_reason); tp_group_mixin_init_dbus_properties (object_class); } static void channel_close (TpSvcChannel *iface, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); example_callable_media_channel_close (self, self->group.self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_svc_channel_return_from_close (context); } static void channel_get_channel_type (TpSvcChannel *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_channel_type (context, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); } static void channel_get_handle (TpSvcChannel *iface, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT, self->priv->handle); } static void channel_get_interfaces (TpSvcChannel *iface G_GNUC_UNUSED, DBusGMethodInvocation *context) { tp_svc_channel_return_from_get_interfaces (context, example_callable_media_channel_interfaces); } static void channel_iface_init (gpointer iface, gpointer data) { TpSvcChannelClass *klass = iface; #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x) IMPLEMENT (close); IMPLEMENT (get_channel_type); IMPLEMENT (get_handle); IMPLEMENT (get_interfaces); #undef IMPLEMENT } static void media_list_streams (TpSvcChannelTypeStreamedMedia *iface, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); GPtrArray *array = g_ptr_array_sized_new (g_hash_table_size ( self->priv->streams)); GHashTableIter iter; gpointer v; g_hash_table_iter_init (&iter, self->priv->streams); while (g_hash_table_iter_next (&iter, NULL, &v)) { ExampleCallableMediaStream *stream = v; GValueArray *va; g_object_get (stream, "stream-info", &va, NULL); g_ptr_array_add (array, va); } tp_svc_channel_type_streamed_media_return_from_list_streams (context, array); g_ptr_array_foreach (array, (GFunc) g_value_array_free, NULL); g_ptr_array_free (array, TRUE); } static void media_remove_streams (TpSvcChannelTypeStreamedMedia *iface, const GArray *stream_ids, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); guint i; for (i = 0; i < stream_ids->len; i++) { guint id = g_array_index (stream_ids, guint, i); if (g_hash_table_lookup (self->priv->streams, GUINT_TO_POINTER (id)) == NULL) { GError *error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "No stream with ID %u in this channel", id); dbus_g_method_return_error (context, error); g_error_free (error); return; } } for (i = 0; i < stream_ids->len; i++) { guint id = g_array_index (stream_ids, guint, i); example_callable_media_stream_close ( g_hash_table_lookup (self->priv->streams, GUINT_TO_POINTER (id))); } tp_svc_channel_type_streamed_media_return_from_remove_streams (context); } static void media_request_stream_direction (TpSvcChannelTypeStreamedMedia *iface, guint stream_id, guint stream_direction, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); ExampleCallableMediaStream *stream = g_hash_table_lookup ( self->priv->streams, GUINT_TO_POINTER (stream_id)); GError *error = NULL; if (stream == NULL) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "No stream with ID %u in this channel", stream_id); goto error; } if (stream_direction > TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Stream direction %u is not valid", stream_direction); goto error; } /* In some protocols, streams cannot be neither sending nor receiving, so * if a stream is set to TP_MEDIA_STREAM_DIRECTION_NONE, this is equivalent * to removing it with RemoveStreams. (This is true in XMPP, for instance.) * * If this was the case, there would be code like this here: * * if (stream_direction == TP_MEDIA_STREAM_DIRECTION_NONE) * { * example_callable_media_stream_close (stream); * tp_svc_channel_type_streamed_media_return_from_request_stream_direction ( * context); * return; * } * * However, for this example we'll emulate a protocol where streams can be * directionless. */ if (!example_callable_media_stream_change_direction (stream, stream_direction, &error)) goto error; tp_svc_channel_type_streamed_media_return_from_request_stream_direction ( context); return; error: dbus_g_method_return_error (context, error); g_error_free (error); } static void stream_removed_cb (ExampleCallableMediaStream *stream, ExampleCallableMediaChannel *self) { guint id; g_object_get (stream, "id", &id, NULL); g_signal_handlers_disconnect_matched (stream, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); g_hash_table_remove (self->priv->streams, GUINT_TO_POINTER (id)); tp_svc_channel_type_streamed_media_emit_stream_removed (self, id); if (g_hash_table_size (self->priv->streams) == 0) { /* no streams left, so the call terminates */ example_callable_media_channel_close (self, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); } } static void stream_direction_changed_cb (ExampleCallableMediaStream *stream, ExampleCallableMediaChannel *self) { guint id, direction, pending; g_object_get (stream, "id", &id, "direction", &direction, "pending-send", &pending, NULL); tp_svc_channel_type_streamed_media_emit_stream_direction_changed (self, id, direction, pending); } static void stream_state_changed_cb (ExampleCallableMediaStream *stream, GParamSpec *spec G_GNUC_UNUSED, ExampleCallableMediaChannel *self) { guint id, state; g_object_get (stream, "id", &id, "state", &state, NULL); tp_svc_channel_type_streamed_media_emit_stream_state_changed (self, id, state); } static gboolean simulate_contact_ended_cb (gpointer p) { ExampleCallableMediaChannel *self = p; /* if the call has been cancelled while we were waiting for the * contact to do so, do nothing! */ if (self->priv->progress == PROGRESS_ENDED) return FALSE; g_message ("SIGNALLING: receive: call terminated: "); example_callable_media_channel_close (self, self->priv->handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); return FALSE; } static gboolean simulate_contact_answered_cb (gpointer p) { ExampleCallableMediaChannel *self = p; TpIntSet *peer_set; GHashTableIter iter; gpointer v; TpHandleRepoIface *contact_repo; const gchar *peer; /* if the call has been cancelled while we were waiting for the * contact to answer, do nothing */ if (self->priv->progress == PROGRESS_ENDED) return FALSE; /* otherwise, we're waiting for a response from the contact, which now * arrives */ g_assert (self->priv->progress == PROGRESS_CALLING); g_message ("SIGNALLING: receive: contact answered our call"); self->priv->progress = PROGRESS_ACTIVE; peer_set = tp_intset_new_containing (self->priv->handle); tp_group_mixin_change_members ((GObject *) self, "", peer_set /* added */, NULL /* nobody removed */, NULL /* nobody added to local-pending */, NULL /* nobody added to remote-pending */, self->priv->handle /* actor */, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (peer_set); g_hash_table_iter_init (&iter, self->priv->streams); while (g_hash_table_iter_next (&iter, NULL, &v)) { /* remote contact accepts our proposed stream direction... */ example_callable_media_stream_simulate_contact_agreed_to_send (v); /* ... and the stream tries to connect */ example_callable_media_stream_connect (v); } contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); peer = tp_handle_inspect (contact_repo, self->priv->handle); /* If the contact's ID contains the magic string "(terminate)", simulate * them hanging up after a moment. */ if (strstr (peer, "(terminate)") != NULL) { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_contact_ended_cb, g_object_ref (self), g_object_unref); } return FALSE; } static gboolean simulate_contact_busy_cb (gpointer p) { ExampleCallableMediaChannel *self = p; /* if the call has been cancelled while we were waiting for the * contact to answer, do nothing */ if (self->priv->progress == PROGRESS_ENDED) return FALSE; /* otherwise, we're waiting for a response from the contact, which now * arrives */ g_assert (self->priv->progress == PROGRESS_CALLING); g_message ("SIGNALLING: receive: call terminated: "); example_callable_media_channel_close (self, self->priv->handle, TP_CHANNEL_GROUP_CHANGE_REASON_BUSY); return FALSE; } static ExampleCallableMediaStream * example_callable_media_channel_add_stream (ExampleCallableMediaChannel *self, TpMediaStreamType media_type, gboolean locally_requested) { ExampleCallableMediaStream *stream; guint id = self->priv->next_stream_id++; guint state, direction, pending_send; if (locally_requested) { g_message ("SIGNALLING: send: new %s stream", media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video"); } stream = g_object_new (EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM, "channel", self, "id", id, "handle", self->priv->handle, "type", media_type, "locally-requested", locally_requested, "simulation-delay", self->priv->simulation_delay, NULL); g_hash_table_insert (self->priv->streams, GUINT_TO_POINTER (id), stream); tp_svc_channel_type_streamed_media_emit_stream_added (self, id, self->priv->handle, media_type); g_object_get (stream, "state", &state, "direction", &direction, "pending-send", &pending_send, NULL); /* this is the "implicit" initial state mandated by telepathy-spec */ if (state != TP_MEDIA_STREAM_STATE_DISCONNECTED) { tp_svc_channel_type_streamed_media_emit_stream_state_changed (self, id, state); } /* this is the "implicit" initial direction mandated by telepathy-spec */ if (direction != TP_MEDIA_STREAM_DIRECTION_RECEIVE || pending_send != TP_MEDIA_STREAM_PENDING_LOCAL_SEND) { tp_svc_channel_type_streamed_media_emit_stream_direction_changed (self, id, direction, pending_send); } g_signal_connect (stream, "removed", G_CALLBACK (stream_removed_cb), self); g_signal_connect (stream, "notify::state", G_CALLBACK (stream_state_changed_cb), self); g_signal_connect (stream, "direction-changed", G_CALLBACK (stream_direction_changed_cb), self); if (self->priv->progress == PROGRESS_ACTIVE) { example_callable_media_stream_connect (stream); } return stream; } static void media_request_streams (TpSvcChannelTypeStreamedMedia *iface, guint contact_handle, const GArray *media_types, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); GPtrArray *array; guint i; GError *error = NULL; if (!tp_handle_is_valid (contact_repo, contact_handle, &error)) goto error; if (contact_handle != self->priv->handle) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "This channel is for handle #%u, we can't make a stream to #%u", self->priv->handle, contact_handle); goto error; } if (self->priv->progress == PROGRESS_ENDED) { g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Call has terminated"); goto error; } for (i = 0; i < media_types->len; i++) { guint media_type = g_array_index (media_types, guint, i); switch (media_type) { case TP_MEDIA_STREAM_TYPE_AUDIO: case TP_MEDIA_STREAM_TYPE_VIDEO: break; default: g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%u is not a valid Media_Stream_Type", media_type); goto error; } } array = g_ptr_array_sized_new (media_types->len); for (i = 0; i < media_types->len; i++) { guint media_type = g_array_index (media_types, guint, i); ExampleCallableMediaStream *stream; GValueArray *info; if (self->priv->progress < PROGRESS_CALLING) { TpIntSet *peer_set = tp_intset_new_containing (self->priv->handle); const gchar *peer; g_message ("SIGNALLING: send: new streamed media call"); self->priv->progress = PROGRESS_CALLING; tp_group_mixin_change_members ((GObject *) self, "", NULL /* nobody added */, NULL /* nobody removed */, NULL /* nobody added to local-pending */, peer_set /* added to remote-pending */, self->group.self_handle /* actor */, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (peer_set); /* In this example there is no real contact, so just simulate them * answering after a short time - unless the contact's name * contains "(no answer)" or "(busy)" */ peer = tp_handle_inspect (contact_repo, self->priv->handle); if (strstr (peer, "(busy)") != NULL) { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_contact_busy_cb, g_object_ref (self), g_object_unref); } else if (strstr (peer, "(no answer)") != NULL) { /* do nothing - the call just rings forever */ } else { g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_contact_answered_cb, g_object_ref (self), g_object_unref); } } stream = example_callable_media_channel_add_stream (self, media_type, TRUE); g_object_get (stream, "stream-info", &info, NULL); g_ptr_array_add (array, info); } tp_svc_channel_type_streamed_media_return_from_request_streams (context, array); g_boxed_free (TP_ARRAY_TYPE_MEDIA_STREAM_INFO_LIST, array); return; error: dbus_g_method_return_error (context, error); g_error_free (error); } static void media_iface_init (gpointer iface, gpointer data) { TpSvcChannelTypeStreamedMediaClass *klass = iface; #define IMPLEMENT(x) \ tp_svc_channel_type_streamed_media_implement_##x (klass, media_##x) IMPLEMENT (list_streams); IMPLEMENT (remove_streams); IMPLEMENT (request_stream_direction); IMPLEMENT (request_streams); #undef IMPLEMENT } static gboolean simulate_hold (gpointer p) { ExampleCallableMediaChannel *self = p; self->priv->hold_state = TP_LOCAL_HOLD_STATE_HELD; g_message ("SIGNALLING: hold state changed to held"); tp_svc_channel_interface_hold_emit_hold_state_changed (self, self->priv->hold_state, self->priv->hold_state_reason); return FALSE; } static gboolean simulate_unhold (gpointer p) { ExampleCallableMediaChannel *self = p; self->priv->hold_state = TP_LOCAL_HOLD_STATE_UNHELD; g_message ("SIGNALLING: hold state changed to unheld"); tp_svc_channel_interface_hold_emit_hold_state_changed (self, self->priv->hold_state, self->priv->hold_state_reason); return FALSE; } static gboolean simulate_inability_to_unhold (gpointer p) { ExampleCallableMediaChannel *self = p; self->priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_HOLD; g_message ("SIGNALLING: unable to unhold - hold state changed to " "pending hold"); tp_svc_channel_interface_hold_emit_hold_state_changed (self, self->priv->hold_state, self->priv->hold_state_reason); /* hold again */ g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_hold, g_object_ref (self), g_object_unref); return FALSE; } static void hold_get_hold_state (TpSvcChannelInterfaceHold *iface, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); tp_svc_channel_interface_hold_return_from_get_hold_state (context, self->priv->hold_state, self->priv->hold_state_reason); } static void hold_request_hold (TpSvcChannelInterfaceHold *iface, gboolean hold, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; const gchar *peer; GSourceFunc callback; if ((hold && self->priv->hold_state == TP_LOCAL_HOLD_STATE_HELD) || (!hold && self->priv->hold_state == TP_LOCAL_HOLD_STATE_UNHELD)) { tp_svc_channel_interface_hold_return_from_request_hold (context); return; } peer = tp_handle_inspect (contact_repo, self->priv->handle); if (!hold && strstr (peer, "(no unhold)") != NULL) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "unable to unhold"); goto error; } self->priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_REQUESTED; if (hold) { self->priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_HOLD; callback = simulate_hold; } else { self->priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_UNHOLD; peer = tp_handle_inspect (contact_repo, self->priv->handle); if (strstr (peer, "(inability to unhold)") != NULL) { callback = simulate_inability_to_unhold; } else { callback = simulate_unhold; } } g_message ("SIGNALLING: hold state changed to pending %s", (hold ? "hold" : "unhold")); tp_svc_channel_interface_hold_emit_hold_state_changed (iface, self->priv->hold_state, self->priv->hold_state_reason); g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, callback, g_object_ref (self), g_object_unref); tp_svc_channel_interface_hold_return_from_request_hold (context); return; error: dbus_g_method_return_error (context, error); g_error_free (error); } void hold_iface_init (gpointer iface, gpointer data) { TpSvcChannelInterfaceHoldClass *klass = iface; #define IMPLEMENT(x) \ tp_svc_channel_interface_hold_implement_##x (klass, hold_##x) IMPLEMENT (get_hold_state); IMPLEMENT (request_hold); #undef IMPLEMENT } static void dtmf_start_tone (TpSvcChannelInterfaceDTMF *iface, guint stream_id, guchar event, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); ExampleCallableMediaStream *stream = g_hash_table_lookup (self->priv->streams, GUINT_TO_POINTER (stream_id)); GError *error = NULL; guint media_type; if (stream == NULL) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "No stream with ID %u in this channel", stream_id); goto error; } g_object_get (G_OBJECT (stream), "type", &media_type, NULL); if (media_type != TP_MEDIA_STREAM_TYPE_AUDIO) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "DTMF is only supported by audio streams"); goto error; } tp_svc_channel_interface_dtmf_return_from_start_tone (context); return; error: dbus_g_method_return_error (context, error); g_error_free (error); } static void dtmf_stop_tone (TpSvcChannelInterfaceDTMF *iface, guint stream_id, DBusGMethodInvocation *context) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (iface); ExampleCallableMediaStream *stream = g_hash_table_lookup (self->priv->streams, GUINT_TO_POINTER (stream_id)); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); GError *error = NULL; const gchar *peer; guint media_type; if (stream == NULL) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "No stream with ID %u in this channel", stream_id); goto error; } g_object_get (G_OBJECT (stream), "type", &media_type, NULL); if (media_type != TP_MEDIA_STREAM_TYPE_AUDIO) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "DTMF is only supported by audio streams"); goto error; } peer = tp_handle_inspect (contact_repo, self->priv->handle); if (strstr (peer, "(no continuous tone)") != NULL) { g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Continuous tones are not supported by this stream"); goto error; } tp_svc_channel_interface_dtmf_return_from_stop_tone (context); return; error: dbus_g_method_return_error (context, error); g_error_free (error); } static void dtmf_iface_init (gpointer iface, gpointer data) { TpSvcChannelInterfaceDTMFClass *klass = iface; #define IMPLEMENT(x) \ tp_svc_channel_interface_dtmf_implement_##x (klass, dtmf_##x) IMPLEMENT (start_tone); IMPLEMENT (stop_tone); #undef IMPLEMENT } telepathy-qt-0.9.6~git1/tests/lib/glib/callable/media-stream.c0000664000175000017500000004560012470405660022055 0ustar jrjr/* * media-stream.c - a stream in a streamed media call. * * In connection managers with MediaSignalling, this object would be a D-Bus * object in its own right. In this CM, MediaSignalling is not used, and this * object just represents internal state of the MediaChannel. * * Copyright © 2007-2009 Collabora Ltd. * Copyright © 2007-2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "media-stream.h" #include #include #include "media-channel.h" G_DEFINE_TYPE (ExampleCallableMediaStream, example_callable_media_stream, G_TYPE_OBJECT) enum { PROP_CHANNEL = 1, PROP_ID, PROP_HANDLE, PROP_TYPE, PROP_STATE, PROP_PENDING_SEND, PROP_DIRECTION, PROP_STREAM_INFO, PROP_SIMULATION_DELAY, PROP_LOCALLY_REQUESTED, N_PROPS }; enum { SIGNAL_REMOVED, SIGNAL_DIRECTION_CHANGED, N_SIGNALS }; static guint signals[N_SIGNALS] = { 0 }; struct _ExampleCallableMediaStreamPrivate { TpBaseConnection *conn; ExampleCallableMediaChannel *channel; guint id; TpHandle handle; TpMediaStreamType type; TpMediaStreamState state; TpMediaStreamDirection direction; TpMediaStreamPendingSend pending_send; guint simulation_delay; gulong call_terminated_id; guint connected_event_id; gboolean locally_requested; gboolean removed; }; static void example_callable_media_stream_init (ExampleCallableMediaStream *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM, ExampleCallableMediaStreamPrivate); /* start off directionless */ self->priv->direction = TP_MEDIA_STREAM_DIRECTION_NONE; self->priv->pending_send = 0; self->priv->state = TP_MEDIA_STREAM_STATE_DISCONNECTED; } static void call_terminated_cb (ExampleCallableMediaChannel *channel, ExampleCallableMediaStream *self) { g_signal_handler_disconnect (channel, self->priv->call_terminated_id); self->priv->call_terminated_id = 0; example_callable_media_stream_close (self); } static void constructed (GObject *object) { ExampleCallableMediaStream *self = EXAMPLE_CALLABLE_MEDIA_STREAM (object); void (*chain_up) (GObject *) = ((GObjectClass *) example_callable_media_stream_parent_class)->constructed; if (chain_up != NULL) chain_up (object); g_object_get (self->priv->channel, "connection", &self->priv->conn, NULL); self->priv->call_terminated_id = g_signal_connect (self->priv->channel, "call-terminated", G_CALLBACK (call_terminated_cb), self); } static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { ExampleCallableMediaStream *self = EXAMPLE_CALLABLE_MEDIA_STREAM (object); switch (property_id) { case PROP_ID: g_value_set_uint (value, self->priv->id); break; case PROP_HANDLE: g_value_set_uint (value, self->priv->handle); break; case PROP_TYPE: g_value_set_uint (value, self->priv->type); break; case PROP_STATE: g_value_set_uint (value, self->priv->state); break; case PROP_PENDING_SEND: g_value_set_uint (value, self->priv->pending_send); break; case PROP_DIRECTION: g_value_set_uint (value, self->priv->direction); break; case PROP_CHANNEL: g_value_set_object (value, self->priv->channel); break; case PROP_STREAM_INFO: { GValueArray *va = g_value_array_new (6); guint i; for (i = 0; i < 6; i++) { g_value_array_append (va, NULL); g_value_init (va->values + i, G_TYPE_UINT); } g_value_set_uint (va->values + 0, self->priv->id); g_value_set_uint (va->values + 1, self->priv->handle); g_value_set_uint (va->values + 2, self->priv->type); g_value_set_uint (va->values + 3, self->priv->state); g_value_set_uint (va->values + 4, self->priv->direction); g_value_set_uint (va->values + 5, self->priv->pending_send); g_value_take_boxed (value, va); } break; case PROP_SIMULATION_DELAY: g_value_set_uint (value, self->priv->simulation_delay); break; case PROP_LOCALLY_REQUESTED: g_value_set_boolean (value, self->priv->locally_requested); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { ExampleCallableMediaStream *self = EXAMPLE_CALLABLE_MEDIA_STREAM (object); switch (property_id) { case PROP_ID: self->priv->id = g_value_get_uint (value); break; case PROP_HANDLE: self->priv->handle = g_value_get_uint (value); break; case PROP_TYPE: self->priv->type = g_value_get_uint (value); break; case PROP_CHANNEL: g_assert (self->priv->channel == NULL); self->priv->channel = g_value_dup_object (value); break; case PROP_SIMULATION_DELAY: self->priv->simulation_delay = g_value_get_uint (value); break; case PROP_LOCALLY_REQUESTED: self->priv->locally_requested = g_value_get_boolean (value); if (self->priv->locally_requested) { example_callable_media_stream_change_direction (self, TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, NULL); } else { example_callable_media_stream_receive_direction_request (self, TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void dispose (GObject *object) { ExampleCallableMediaStream *self = EXAMPLE_CALLABLE_MEDIA_STREAM (object); example_callable_media_stream_close (self); if (self->priv->channel != NULL) { if (self->priv->call_terminated_id != 0) { g_signal_handler_disconnect (self->priv->channel, self->priv->call_terminated_id); self->priv->call_terminated_id = 0; } g_object_unref (self->priv->channel); self->priv->channel = NULL; } if (self->priv->conn != NULL) { g_object_unref (self->priv->conn); self->priv->conn = NULL; } ((GObjectClass *) example_callable_media_stream_parent_class)->dispose (object); } static void example_callable_media_stream_class_init (ExampleCallableMediaStreamClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; g_type_class_add_private (klass, sizeof (ExampleCallableMediaStreamPrivate)); object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; param_spec = g_param_spec_object ("channel", "ExampleCallableMediaChannel", "Media channel that owns this stream", EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CHANNEL, param_spec); param_spec = g_param_spec_uint ("id", "Stream ID", "ID of this stream", 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ID, param_spec); param_spec = g_param_spec_uint ("handle", "Peer's TpHandle", "The handle with which this stream communicates or 0 if not applicable", 0, G_MAXUINT32, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_HANDLE, param_spec); param_spec = g_param_spec_uint ("type", "TpMediaStreamType", "Media stream type", 0, NUM_TP_MEDIA_STREAM_TYPES - 1, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_TYPE, param_spec); param_spec = g_param_spec_uint ("state", "TpMediaStreamState", "Media stream connection state", 0, NUM_TP_MEDIA_STREAM_STATES - 1, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_STATE, param_spec); param_spec = g_param_spec_uint ("direction", "TpMediaStreamDirection", "Media stream direction", 0, NUM_TP_MEDIA_STREAM_DIRECTIONS - 1, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_DIRECTION, param_spec); param_spec = g_param_spec_uint ("pending-send", "TpMediaStreamPendingSend", "Requested media stream directions pending approval", 0, TP_MEDIA_STREAM_PENDING_LOCAL_SEND | TP_MEDIA_STREAM_PENDING_REMOTE_SEND, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_PENDING_SEND, param_spec); param_spec = g_param_spec_boxed ("stream-info", "Stream info", "6-entry GValueArray as returned by ListStreams and RequestStreams", TP_STRUCT_TYPE_MEDIA_STREAM_INFO, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_STREAM_INFO, param_spec); param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay", "Delay between simulated network events", 0, G_MAXUINT32, 1000, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SIMULATION_DELAY, param_spec); param_spec = g_param_spec_boolean ("locally-requested", "Locally requested?", "True if this channel was requested by the local user", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_LOCALLY_REQUESTED, param_spec); signals[SIGNAL_REMOVED] = g_signal_new ("removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[SIGNAL_DIRECTION_CHANGED] = g_signal_new ("direction-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } void example_callable_media_stream_close (ExampleCallableMediaStream *self) { if (!self->priv->removed) { self->priv->removed = TRUE; g_message ("Sending to server: Closing stream %u", self->priv->id); if (self->priv->connected_event_id != 0) { g_source_remove (self->priv->connected_event_id); } /* this has to come last, because the MediaChannel may unref us in * response to the removed signal */ g_signal_emit (self, signals[SIGNAL_REMOVED], 0); } } void example_callable_media_stream_accept_proposed_direction ( ExampleCallableMediaStream *self) { if (self->priv->removed || !(self->priv->pending_send & TP_MEDIA_STREAM_PENDING_LOCAL_SEND)) return; g_message ("SIGNALLING: send: OK, I'll send you media on stream %u", self->priv->id); self->priv->direction |= TP_MEDIA_STREAM_DIRECTION_SEND; self->priv->pending_send &= ~TP_MEDIA_STREAM_PENDING_LOCAL_SEND; g_signal_emit (self, signals[SIGNAL_DIRECTION_CHANGED], 0); } void example_callable_media_stream_simulate_contact_agreed_to_send ( ExampleCallableMediaStream *self) { if (self->priv->removed || !(self->priv->pending_send & TP_MEDIA_STREAM_PENDING_REMOTE_SEND)) return; g_message ("SIGNALLING: receive: OK, I'll send you media on stream %u", self->priv->id); self->priv->direction |= TP_MEDIA_STREAM_DIRECTION_RECEIVE; self->priv->pending_send &= ~TP_MEDIA_STREAM_PENDING_REMOTE_SEND; g_signal_emit (self, signals[SIGNAL_DIRECTION_CHANGED], 0); } static gboolean simulate_contact_agreed_to_send_cb (gpointer p) { example_callable_media_stream_simulate_contact_agreed_to_send (p); return FALSE; } gboolean example_callable_media_stream_change_direction ( ExampleCallableMediaStream *self, TpMediaStreamDirection direction, GError **error) { gboolean sending = ((self->priv->direction & TP_MEDIA_STREAM_DIRECTION_SEND) != 0); gboolean receiving = ((self->priv->direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) != 0); gboolean want_to_send = ((direction & TP_MEDIA_STREAM_DIRECTION_SEND) != 0); gboolean want_to_receive = ((direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) != 0); gboolean pending_remote_send = ((self->priv->pending_send & TP_MEDIA_STREAM_PENDING_REMOTE_SEND) != 0); gboolean pending_local_send = ((self->priv->pending_send & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0); gboolean changed = FALSE; if (want_to_send) { if (!sending) { if (pending_local_send) { g_message ("SIGNALLING: send: I will now send you media on " "stream %u", self->priv->id); } g_message ("MEDIA: Sending media to peer for stream %u", self->priv->id); changed = TRUE; self->priv->direction |= TP_MEDIA_STREAM_DIRECTION_SEND; } } else { if (sending) { g_message ("SIGNALLING: send: I will no longer send you media on " "stream %u", self->priv->id); g_message ("MEDIA: No longer sending media to peer for stream %u", self->priv->id); changed = TRUE; self->priv->direction &= ~TP_MEDIA_STREAM_DIRECTION_SEND; } else if (pending_local_send) { g_message ("SIGNALLING: send: No, I refuse to send you media on " "stream %u", self->priv->id); changed = TRUE; self->priv->pending_send &= ~TP_MEDIA_STREAM_PENDING_LOCAL_SEND; } } if (want_to_receive) { if (!receiving && !pending_remote_send) { g_message ("SIGNALLING: send: Please start sending me stream %u", self->priv->id); changed = TRUE; self->priv->pending_send |= TP_MEDIA_STREAM_PENDING_REMOTE_SEND; g_timeout_add_full (G_PRIORITY_DEFAULT, self->priv->simulation_delay, simulate_contact_agreed_to_send_cb, g_object_ref (self), g_object_unref); } } else { if (receiving) { g_message ("SIGNALLING: send: Please stop sending me stream %u", self->priv->id); g_message ("MEDIA: Suppressing output of stream %u", self->priv->id); changed = TRUE; self->priv->direction &= ~TP_MEDIA_STREAM_DIRECTION_RECEIVE; } } if (changed) g_signal_emit (self, signals[SIGNAL_DIRECTION_CHANGED], 0); return TRUE; } static gboolean simulate_stream_connected_cb (gpointer p) { ExampleCallableMediaStream *self = EXAMPLE_CALLABLE_MEDIA_STREAM (p); g_message ("MEDIA: stream connected"); self->priv->state = TP_MEDIA_STREAM_STATE_CONNECTED; g_object_notify ((GObject *) self, "state"); return FALSE; } void example_callable_media_stream_connect (ExampleCallableMediaStream *self) { /* if already trying to connect, do nothing */ if (self->priv->connected_event_id != 0) return; /* simulate it taking a short time to connect */ self->priv->connected_event_id = g_timeout_add (self->priv->simulation_delay, simulate_stream_connected_cb, self); } void example_callable_media_stream_receive_direction_request ( ExampleCallableMediaStream *self, TpMediaStreamDirection direction) { /* The remote user wants to change the direction of this stream to * @direction. Shall we let him? */ gboolean sending = ((self->priv->direction & TP_MEDIA_STREAM_DIRECTION_SEND) != 0); gboolean receiving = ((self->priv->direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) != 0); gboolean send_requested = ((direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) != 0); gboolean receive_requested = ((direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) != 0); gboolean pending_remote_send = ((self->priv->pending_send & TP_MEDIA_STREAM_PENDING_REMOTE_SEND) != 0); gboolean pending_local_send = ((self->priv->pending_send & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0); gboolean changed = FALSE; if (send_requested) { g_message ("SIGNALLING: receive: Please start sending me stream %u", self->priv->id); if (!sending) { /* ask the user for permission */ self->priv->pending_send |= TP_MEDIA_STREAM_PENDING_LOCAL_SEND; changed = TRUE; } else { /* nothing to do, we're already sending on that stream */ } } else { g_message ("SIGNALLING: receive: Please stop sending me stream %u", self->priv->id); g_message ("SIGNALLING: send: OK, not sending stream %u", self->priv->id); if (sending) { g_message ("MEDIA: No longer sending media to peer for stream %u", self->priv->id); self->priv->direction &= ~TP_MEDIA_STREAM_DIRECTION_SEND; changed = TRUE; } else if (pending_local_send) { self->priv->pending_send &= ~TP_MEDIA_STREAM_PENDING_LOCAL_SEND; changed = TRUE; } else { /* nothing to do, we're not sending on that stream anyway */ } } if (receive_requested) { g_message ("SIGNALLING: receive: I will now send you media on stream %u", self->priv->id); if (!receiving) { self->priv->pending_send &= ~TP_MEDIA_STREAM_PENDING_REMOTE_SEND; self->priv->direction |= TP_MEDIA_STREAM_DIRECTION_RECEIVE; changed = TRUE; } } else { if (pending_remote_send) { g_message ("SIGNALLING: receive: No, I refuse to send you media on " "stream %u", self->priv->id); self->priv->pending_send &= ~TP_MEDIA_STREAM_PENDING_REMOTE_SEND; changed = TRUE; } else if (receiving) { g_message ("SIGNALLING: receive: I will no longer send you media on " "stream %u", self->priv->id); self->priv->direction &= ~TP_MEDIA_STREAM_DIRECTION_RECEIVE; changed = TRUE; } } if (changed) g_signal_emit (self, signals[SIGNAL_DIRECTION_CHANGED], 0); } telepathy-qt-0.9.6~git1/tests/lib/glib/stream-tube-chan.h0000664000175000017500000001254512470405660021114 0ustar jrjr/* * stream-tube-chan.h - Simple stream tube channel * * Copyright (C) 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_STREAM_TUBE_CHAN_H__ #define __TP_STREAM_TUBE_CHAN_H__ #include #include #include G_BEGIN_DECLS /* Base Class */ typedef struct _TpTestsStreamTubeChannel TpTestsStreamTubeChannel; typedef struct _TpTestsStreamTubeChannelClass TpTestsStreamTubeChannelClass; typedef struct _TpTestsStreamTubeChannelPrivate TpTestsStreamTubeChannelPrivate; GType tp_tests_stream_tube_channel_get_type (void); #define TP_TESTS_TYPE_STREAM_TUBE_CHANNEL \ (tp_tests_stream_tube_channel_get_type ()) #define TP_TESTS_STREAM_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_STREAM_TUBE_CHANNEL, \ TpTestsStreamTubeChannel)) #define TP_TESTS_STREAM_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_STREAM_TUBE_CHANNEL, \ TpTestsStreamTubeChannelClass)) #define TP_TESTS_IS_STREAM_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_STREAM_TUBE_CHANNEL)) #define TP_TESTS_IS_STREAM_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_STREAM_TUBE_CHANNEL)) #define TP_TESTS_STREAM_TUBE_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_STREAM_TUBE_CHANNEL, \ TpTestsStreamTubeChannelClass)) struct _TpTestsStreamTubeChannelClass { TpBaseChannelClass parent_class; TpDBusPropertiesMixinClass dbus_properties_class; }; struct _TpTestsStreamTubeChannel { TpBaseChannel parent; TpTestsStreamTubeChannelPrivate *priv; }; GSocketAddress * tp_tests_stream_tube_channel_get_server_address ( TpTestsStreamTubeChannel *self); void tp_tests_stream_tube_channel_peer_connected ( TpTestsStreamTubeChannel *self, GIOStream *stream, TpHandle handle); void tp_tests_stream_tube_channel_peer_connected_no_stream (TpTestsStreamTubeChannel *self, const GValue *connection_param, TpHandle handle); void tp_tests_stream_tube_channel_last_connection_disconnected ( TpTestsStreamTubeChannel *self, const gchar *error); void tp_tests_stream_tube_channel_set_close_on_accept ( TpTestsStreamTubeChannel *self, gboolean close_on_accept); /* Contact Stream Tube */ typedef struct _TpTestsContactStreamTubeChannel TpTestsContactStreamTubeChannel; typedef struct _TpTestsContactStreamTubeChannelClass TpTestsContactStreamTubeChannelClass; GType tp_tests_contact_stream_tube_channel_get_type (void); #define TP_TESTS_TYPE_CONTACT_STREAM_TUBE_CHANNEL \ (tp_tests_contact_stream_tube_channel_get_type ()) #define TP_TESTS_CONTACT_STREAM_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_CONTACT_STREAM_TUBE_CHANNEL, \ TpTestsContactStreamTubeChannel)) #define TP_TESTS_CONTACT_STREAM_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_CONTACT_STREAM_TUBE_CHANNEL, \ TpTestsContactStreamTubeChannelClass)) #define TP_TESTS_IS_CONTACT_STREAM_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_CONTACT_STREAM_TUBE_CHANNEL)) #define TP_TESTS_IS_CONTACT_STREAM_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_CONTACT_STREAM_TUBE_CHANNEL)) #define TP_TESTS_CONTACT_STREAM_TUBE_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_CONTACT_STREAM_TUBE_CHANNEL, \ TpTestsContactStreamTubeChannelClass)) struct _TpTestsContactStreamTubeChannelClass { TpTestsStreamTubeChannelClass parent_class; }; struct _TpTestsContactStreamTubeChannel { TpTestsStreamTubeChannel parent; }; /* Room Stream Tube */ typedef struct _TpTestsRoomStreamTubeChannel TpTestsRoomStreamTubeChannel; typedef struct _TpTestsRoomStreamTubeChannelClass TpTestsRoomStreamTubeChannelClass; GType tp_tests_room_stream_tube_channel_get_type (void); #define TP_TESTS_TYPE_ROOM_STREAM_TUBE_CHANNEL \ (tp_tests_room_stream_tube_channel_get_type ()) #define TP_TESTS_ROOM_STREAM_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TESTS_TYPE_ROOM_STREAM_TUBE_CHANNEL, \ TpTestsRoomStreamTubeChannel)) #define TP_TESTS_ROOM_STREAM_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TESTS_TYPE_ROOM_STREAM_TUBE_CHANNEL, \ TpTestsRoomStreamTubeChannelClass)) #define TP_TESTS_IS_ROOM_STREAM_TUBE_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TESTS_TYPE_ROOM_STREAM_TUBE_CHANNEL)) #define TP_TESTS_IS_ROOM_STREAM_TUBE_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TESTS_TYPE_ROOM_STREAM_TUBE_CHANNEL)) #define TP_TESTS_ROOM_STREAM_TUBE_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_ROOM_STREAM_TUBE_CHANNEL, \ TpTestsRoomStreamTubeChannelClass)) struct _TpTestsRoomStreamTubeChannelClass { TpTestsStreamTubeChannelClass parent_class; }; struct _TpTestsRoomStreamTubeChannel { TpTestsStreamTubeChannel parent; }; G_END_DECLS #endif /* #ifndef __TP_STREAM_TUBE_CHAN_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/contacts-conn.h0000664000175000017500000001647312470405660020532 0ustar jrjr/* * contacts-conn.h - header for a connection with contact info * * Copyright (C) 2007-2008 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #ifndef __TP_TESTS_CONTACTS_CONN_H__ #define __TP_TESTS_CONTACTS_CONN_H__ #include #include #include #include #include "simple-conn.h" #include "contact-list-manager.h" G_BEGIN_DECLS typedef struct _TpTestsContactsConnection TpTestsContactsConnection; typedef struct _TpTestsContactsConnectionClass TpTestsContactsConnectionClass; typedef struct _TpTestsContactsConnectionPrivate TpTestsContactsConnectionPrivate; struct _TpTestsContactsConnectionClass { TpTestsSimpleConnectionClass parent_class; TpPresenceMixinClass presence_mixin; TpContactsMixinClass contacts_mixin; TpDBusPropertiesMixinClass properties_class; }; struct _TpTestsContactsConnection { TpTestsSimpleConnection parent; TpPresenceMixin presence_mixin; TpContactsMixin contacts_mixin; guint refresh_contact_info_called; TpTestsContactsConnectionPrivate *priv; }; GType tp_tests_contacts_connection_get_type (void); /* Must match my_statuses in the .c */ typedef enum { TP_TESTS_CONTACTS_CONNECTION_STATUS_AVAILABLE, TP_TESTS_CONTACTS_CONNECTION_STATUS_BUSY, TP_TESTS_CONTACTS_CONNECTION_STATUS_AWAY, TP_TESTS_CONTACTS_CONNECTION_STATUS_OFFLINE, TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN, TP_TESTS_CONTACTS_CONNECTION_STATUS_ERROR } TpTestsContactsConnectionPresenceStatusIndex; /* TYPE MACROS */ #define TP_TESTS_TYPE_CONTACTS_CONNECTION \ (tp_tests_contacts_connection_get_type ()) #define TP_TESTS_CONTACTS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_CONTACTS_CONNECTION, \ TpTestsContactsConnection)) #define TP_TESTS_CONTACTS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_CONTACTS_CONNECTION, \ TpTestsContactsConnectionClass)) #define TP_TESTS_IS_CONTACTS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_CONTACTS_CONNECTION)) #define TP_TESTS_IS_CONTACTS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_CONTACTS_CONNECTION)) #define TP_TESTS_CONTACTS_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_CONTACTS_CONNECTION, \ TpTestsContactsConnectionClass)) TestContactListManager *tp_tests_contacts_connection_get_contact_list_manager ( TpTestsContactsConnection *self); void tp_tests_contacts_connection_change_aliases ( TpTestsContactsConnection *self, guint n, const TpHandle *handles, const gchar * const *aliases); void tp_tests_contacts_connection_change_presences ( TpTestsContactsConnection *self, guint n, const TpHandle *handles, const TpTestsContactsConnectionPresenceStatusIndex *indexes, const gchar * const *messages); void tp_tests_contacts_connection_change_avatar_tokens ( TpTestsContactsConnection *self, guint n, const TpHandle *handles, const gchar * const *tokens); void tp_tests_contacts_connection_change_avatar_data ( TpTestsContactsConnection *self, TpHandle handle, GArray *data, const gchar *mime_type, const gchar *token, gboolean emit_avatar_updated); void tp_tests_contacts_connection_change_locations ( TpTestsContactsConnection *self, guint n, const TpHandle *handles, GHashTable **locations); void tp_tests_contacts_connection_change_capabilities ( TpTestsContactsConnection *self, GHashTable *capabilities); void tp_tests_contacts_connection_change_contact_info ( TpTestsContactsConnection *self, TpHandle handle, GPtrArray *info); void tp_tests_contacts_connection_set_default_contact_info ( TpTestsContactsConnection *self, GPtrArray *info); void tp_tests_contacts_connection_change_client_types ( TpTestsContactsConnection *self, TpHandle handle, gchar **client_types); /* Legacy version (no Contacts interface, and no immortal handles) */ typedef struct _TpTestsLegacyContactsConnection TpTestsLegacyContactsConnection; typedef struct _TpTestsLegacyContactsConnectionClass TpTestsLegacyContactsConnectionClass; typedef struct _TpTestsLegacyContactsConnectionPrivate TpTestsLegacyContactsConnectionPrivate; struct _TpTestsLegacyContactsConnectionClass { TpTestsContactsConnectionClass parent_class; }; struct _TpTestsLegacyContactsConnection { TpTestsContactsConnection parent; TpTestsLegacyContactsConnectionPrivate *priv; }; GType tp_tests_legacy_contacts_connection_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION \ (tp_tests_legacy_contacts_connection_get_type ()) #define LEGACY_TP_TESTS_CONTACTS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION, \ TpTestsLegacyContactsConnection)) #define LEGACY_TP_TESTS_CONTACTS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION, \ TpTestsLegacyContactsConnectionClass)) #define TP_TESTS_LEGACY_CONTACTS_IS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION)) #define TP_TESTS_LEGACY_CONTACTS_IS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION)) #define LEGACY_TP_TESTS_CONTACTS_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_LEGACY_CONTACTS_CONNECTION, \ TpTestsLegacyContactsConnectionClass)) /* No Requests version */ typedef struct _TpTestsNoRequestsConnection TpTestsNoRequestsConnection; typedef struct _TpTestsNoRequestsConnectionClass TpTestsNoRequestsConnectionClass; typedef struct _TpTestsNoRequestsConnectionPrivate TpTestsNoRequestsConnectionPrivate; struct _TpTestsNoRequestsConnectionClass { TpTestsContactsConnectionClass parent_class; }; struct _TpTestsNoRequestsConnection { TpTestsContactsConnection parent; TpTestsNoRequestsConnectionPrivate *priv; }; GType tp_tests_no_requests_connection_get_type (void); /* TYPE MACROS */ #define TP_TESTS_TYPE_NO_REQUESTS_CONNECTION \ (tp_tests_no_requests_connection_get_type ()) #define TP_TESTS_NO_REQUESTS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION, \ TpTestsNoRequestsConnection)) #define TP_TESTS_NO_REQUESTS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION, \ TpTestsNoRequestsConnectionClass)) #define TP_TESTS_NO_REQUESTS_IS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION)) #define TP_TESTS_NO_REQUESTS_IS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION)) #define TP_TESTS_NO_REQUESTS_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_NO_REQUESTS_CONNECTION, \ TpTestsNoRequestsConnectionClass)) G_END_DECLS #endif /* ifndef __TP_TESTS_CONTACTS_CONN_H__ */ telepathy-qt-0.9.6~git1/tests/lib/glib/simple-account.c0000664000175000017500000002327712470405660020677 0ustar jrjr/* * simple-account.c - a simple account service. * * Copyright (C) 2010 Collabora Ltd. * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "simple-account.h" #include #include #include #include #include #include #include #include static void account_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (TpTestsSimpleAccount, tp_tests_simple_account, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_ACCOUNT, account_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init) ) /* TP_IFACE_ACCOUNT is implied */ static const char *ACCOUNT_INTERFACES[] = { NULL }; enum { PROP_0, PROP_INTERFACES, PROP_DISPLAY_NAME, PROP_ICON, PROP_VALID, PROP_ENABLED, PROP_NICKNAME, PROP_PARAMETERS, PROP_AUTOMATIC_PRESENCE, PROP_CONNECT_AUTO, PROP_CONNECTION, PROP_CONNECTION_STATUS, PROP_CONNECTION_STATUS_REASON, PROP_CURRENT_PRESENCE, PROP_REQUESTED_PRESENCE, PROP_NORMALIZED_NAME, PROP_HAS_BEEN_ONLINE, }; struct _TpTestsSimpleAccountPrivate { gpointer unused; }; static void account_iface_init (gpointer klass, gpointer unused G_GNUC_UNUSED) { #define IMPLEMENT(x) tp_svc_account_implement_##x (\ klass, tp_tests_simple_account_##x) /* TODO */ #undef IMPLEMENT } static void tp_tests_simple_account_init (TpTestsSimpleAccount *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_SIMPLE_ACCOUNT, TpTestsSimpleAccountPrivate); } static void tp_tests_simple_account_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec) { GValueArray *presence; presence = tp_value_array_build (3, G_TYPE_UINT, TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, G_TYPE_STRING, "available", G_TYPE_STRING, "", G_TYPE_INVALID); switch (property_id) { case PROP_INTERFACES: g_value_set_boxed (value, ACCOUNT_INTERFACES); break; case PROP_DISPLAY_NAME: g_value_set_string (value, "Fake Account"); break; case PROP_ICON: g_value_set_string (value, ""); break; case PROP_VALID: g_value_set_boolean (value, TRUE); break; case PROP_ENABLED: g_value_set_boolean (value, TRUE); break; case PROP_NICKNAME: g_value_set_string (value, "badger"); break; case PROP_PARAMETERS: g_value_take_boxed (value, g_hash_table_new (NULL, NULL)); break; case PROP_AUTOMATIC_PRESENCE: g_value_set_boxed (value, presence); break; case PROP_CONNECT_AUTO: g_value_set_boolean (value, FALSE); break; case PROP_CONNECTION: g_value_set_boxed (value, "/"); break; case PROP_CONNECTION_STATUS: g_value_set_uint (value, TP_CONNECTION_STATUS_CONNECTED); break; case PROP_CONNECTION_STATUS_REASON: g_value_set_uint (value, TP_CONNECTION_STATUS_REASON_REQUESTED); break; case PROP_CURRENT_PRESENCE: g_value_set_boxed (value, presence); break; case PROP_REQUESTED_PRESENCE: g_value_set_boxed (value, presence); break; case PROP_NORMALIZED_NAME: g_value_set_string (value, ""); break; case PROP_HAS_BEEN_ONLINE: g_value_set_boolean (value, TRUE); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec); break; } g_boxed_free (TP_STRUCT_TYPE_SIMPLE_PRESENCE, presence); } /** * This class currently only provides the minimum for * tp_account_prepare to succeed. This turns out to be only a working * Properties.GetAll(). */ static void tp_tests_simple_account_class_init (TpTestsSimpleAccountClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; GParamSpec *param_spec; static TpDBusPropertiesMixinPropImpl a_props[] = { { "Interfaces", "interfaces", NULL }, { "DisplayName", "display-name", NULL }, { "Icon", "icon", NULL }, { "Valid", "valid", NULL }, { "Enabled", "enabled", NULL }, { "Nickname", "nickname", NULL }, { "Parameters", "parameters", NULL }, { "AutomaticPresence", "automatic-presence", NULL }, { "ConnectAutomatically", "connect-automatically", NULL }, { "Connection", "connection", NULL }, { "ConnectionStatus", "connection-status", NULL }, { "ConnectionStatusReason", "connection-status-reason", NULL }, { "CurrentPresence", "current-presence", NULL }, { "RequestedPresence", "requested-presence", NULL }, { "NormalizedName", "normalized-name", NULL }, { "HasBeenOnline", "has-been-online", NULL }, { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { { TP_IFACE_ACCOUNT, tp_dbus_properties_mixin_getter_gobject_properties, NULL, a_props }, { NULL }, }; g_type_class_add_private (klass, sizeof (TpTestsSimpleAccountPrivate)); object_class->get_property = tp_tests_simple_account_get_property; param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", "In this case we only implement Account, so none.", G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); param_spec = g_param_spec_string ("display-name", "display name", "DisplayName property", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_DISPLAY_NAME, param_spec); param_spec = g_param_spec_string ("icon", "icon", "Icon property", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ICON, param_spec); param_spec = g_param_spec_boolean ("valid", "valid", "Valid property", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_VALID, param_spec); param_spec = g_param_spec_boolean ("enabled", "enabled", "Enabled property", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ENABLED, param_spec); param_spec = g_param_spec_string ("nickname", "nickname", "Nickname property", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_NICKNAME, param_spec); param_spec = g_param_spec_boxed ("parameters", "parameters", "Parameters property", TP_HASH_TYPE_STRING_VARIANT_MAP, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_PARAMETERS, param_spec); param_spec = g_param_spec_boxed ("automatic-presence", "automatic presence", "AutomaticPresence property", TP_STRUCT_TYPE_SIMPLE_PRESENCE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_AUTOMATIC_PRESENCE, param_spec); param_spec = g_param_spec_boolean ("connect-automatically", "connect automatically", "ConnectAutomatically property", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECT_AUTO, param_spec); param_spec = g_param_spec_boxed ("connection", "connection", "Connection property", DBUS_TYPE_G_OBJECT_PATH, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); param_spec = g_param_spec_uint ("connection-status", "connection status", "ConnectionStatus property", 0, NUM_TP_CONNECTION_STATUSES, TP_CONNECTION_STATUS_DISCONNECTED, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION_STATUS, param_spec); param_spec = g_param_spec_uint ("connection-status-reason", "connection status reason", "ConnectionStatusReason property", 0, NUM_TP_CONNECTION_STATUS_REASONS, TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CONNECTION_STATUS_REASON, param_spec); param_spec = g_param_spec_boxed ("current-presence", "current presence", "CurrentPresence property", TP_STRUCT_TYPE_SIMPLE_PRESENCE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_CURRENT_PRESENCE, param_spec); param_spec = g_param_spec_boxed ("requested-presence", "requested presence", "RequestedPresence property", TP_STRUCT_TYPE_SIMPLE_PRESENCE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_REQUESTED_PRESENCE, param_spec); param_spec = g_param_spec_string ("normalized-name", "normalized name", "NormalizedName property", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_NORMALIZED_NAME, param_spec); param_spec = g_param_spec_boolean ("has-been-online", "has been online", "HasBeenOnline property", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_HAS_BEEN_ONLINE, param_spec); klass->dbus_props_class.interfaces = prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (TpTestsSimpleAccountClass, dbus_props_class)); } telepathy-qt-0.9.6~git1/tests/lib/test-thread-helper.h0000664000175000017500000000336112470405660020535 0ustar jrjr#ifndef _TelepathyQt_tests_lib_test_thread_helper_h_HEADER_GUARD_ #define _TelepathyQt_tests_lib_test_thread_helper_h_HEADER_GUARD_ #include #include #include #include class ThreadObjectBase : public QObject { Q_OBJECT public Q_SLOTS: virtual void executeCallback() = 0; Q_SIGNALS: void callbackExecutionFinished(); }; template class ThreadObject : public ThreadObjectBase { public: typedef Tp::Callback1 Callback; Callback mCallback; virtual void executeCallback() { Q_ASSERT(mCallback.isValid()); Q_ASSERT(QThread::currentThread() != QCoreApplication::instance()->thread()); mCallback(mContext); Q_EMIT callbackExecutionFinished(); } private: Context mContext; }; class TestThreadHelperBase { public: virtual ~TestThreadHelperBase(); protected: TestThreadHelperBase(ThreadObjectBase *threadObject); void executeCallback(); protected: QThread *mThread; ThreadObjectBase *mThreadObject; }; template class TestThreadHelper : public TestThreadHelperBase { public: TestThreadHelper() : TestThreadHelperBase(new ThreadObject()) { } void executeCallback(typename ThreadObject::Callback const & cb) { static_cast*>(mThreadObject)->mCallback = cb; TestThreadHelperBase::executeCallback(); } }; #define TEST_THREAD_HELPER_EXECUTE(helper, callback) \ do { \ (helper)->executeCallback(Tp::ptrFun(callback)); \ if (QTest::currentTestFailed()) { \ return; \ } \ } while(0) #endif // _TelepathyQt_tests_lib_test_thread_helper_h_HEADER_GUARD_ telepathy-qt-0.9.6~git1/tests/lib/glib-helpers/0000775000175000017500000000000012470405660017235 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/lib/glib-helpers/test-conn-helper.cpp0000664000175000017500000003227512470405660023141 0ustar jrjr#include "tests/lib/glib-helpers/test-conn-helper.h" #include "tests/lib/glib-helpers/_gen/test-conn-helper.moc.hpp" #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include TestConnHelper::TestConnHelper(Test *parent, GType gType, const QString &account, const QString &protocol) : QObject(parent) { Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus()); Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create(); init(parent, channelFactory, contactFactory, gType, "account", account.toLatin1().constData(), "protocol", protocol.toLatin1().constData(), NULL); } TestConnHelper::TestConnHelper(Test *parent, GType gType, const char *firstPropertyName, ...) : QObject(parent) { Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus()); Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create(); va_list varArgs; va_start(varArgs, firstPropertyName); init(parent, channelFactory, contactFactory, gType, firstPropertyName, varArgs); va_end(varArgs); } TestConnHelper::TestConnHelper(Test *parent, const Tp::ChannelFactoryConstPtr &channelFactory, const Tp::ContactFactoryConstPtr &contactFactory, GType gType, const QString &account, const QString &protocol) : QObject(parent) { init(parent, channelFactory, contactFactory, gType, "account", account.toLatin1().constData(), "protocol", protocol.toLatin1().constData(), NULL); } TestConnHelper::TestConnHelper(Test *parent, const Tp::ChannelFactoryConstPtr &channelFactory, const Tp::ContactFactoryConstPtr &contactFactory, GType gType, const char *firstPropertyName, ...) : QObject(parent) { va_list varArgs; va_start(varArgs, firstPropertyName); init(parent, channelFactory, contactFactory, gType, firstPropertyName, varArgs); va_end(varArgs); } TestConnHelper::~TestConnHelper() { disconnect(); if (mService != 0) { g_object_unref(mService); mService = 0; } } void TestConnHelper::init(Test *parent, const Tp::ChannelFactoryConstPtr &channelFactory, const Tp::ContactFactoryConstPtr &contactFactory, GType gType, const char *firstPropertyName, ...) { va_list varArgs; va_start(varArgs, firstPropertyName); init(parent, channelFactory, contactFactory, gType, firstPropertyName, varArgs); va_end(varArgs); } void TestConnHelper::init(Test *parent, const Tp::ChannelFactoryConstPtr &channelFactory, const Tp::ContactFactoryConstPtr &contactFactory, GType gType, const char *firstPropertyName, va_list varArgs) { mParent = parent; mLoop = parent->mLoop; mService = g_object_new_valist(gType, firstPropertyName, varArgs); QVERIFY(mService != 0); gchar *connBusName; gchar *connPath; GError *error = 0; QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mService), "testcm", &connBusName, &connPath, &error)); QVERIFY(error == 0); QVERIFY(connBusName != 0); QVERIFY(connPath != 0); mClient = Tp::Connection::create(QLatin1String(connBusName), QLatin1String(connPath), channelFactory, contactFactory); QCOMPARE(mClient->isReady(), false); g_free(connBusName); g_free(connPath); } QString TestConnHelper::objectPath() const { return mClient->objectPath(); } bool TestConnHelper::isValid() const { return mClient->isValid(); } bool TestConnHelper::isReady(const Tp::Features &features) const { return mClient->isReady(features); } bool TestConnHelper::enableFeatures(const Tp::Features &features) { mLoop->processEvents(); QObject::connect(mClient->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), mParent, SLOT(expectSuccessfulCall(Tp::PendingOperation*))); return ((mLoop->exec() == 0) && mClient->isReady(features)); } bool TestConnHelper::connect(const Tp::Features &features) { mLoop->processEvents(); QObject::connect(mClient->lowlevel()->requestConnect(features), SIGNAL(finished(Tp::PendingOperation*)), mParent, SLOT(expectSuccessfulCall(Tp::PendingOperation*))); return ((mLoop->exec() == 0) && (mClient->status() == Tp::ConnectionStatusConnected) && mClient->isReady(features)); } bool TestConnHelper::disconnect() { if (!mClient->isValid()) { return false; } mLoop->processEvents(); QObject::connect(mClient.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(expectConnInvalidated())); tp_base_connection_change_status(TP_BASE_CONNECTION(mService), TP_CONNECTION_STATUS_DISCONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); return ((mLoop->exec() == 0) && !mClient->isValid() && (mClient->status() == Tp::ConnectionStatusDisconnected)); } QList TestConnHelper::contacts(const QStringList &ids, const Tp::Features &features) { mLoop->processEvents(); QList ret; Tp::PendingContacts *pc = mClient->contactManager()->contactsForIdentifiers(ids, features); mContactFeatures = features; QObject::connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectContactsForIdentifiersFinished(Tp::PendingOperation*))); if (mLoop->exec() == 0) { ret = mContacts; } mContactFeatures.clear(); mContacts.clear(); return ret; } QList TestConnHelper::contacts(const Tp::UIntList &handles, const Tp::Features &features) { mLoop->processEvents(); QList ret; Tp::PendingContacts *pc = mClient->contactManager()->contactsForHandles(handles, features); mContactFeatures = features; QObject::connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectContactsForHandlesFinished(Tp::PendingOperation*))); if (mLoop->exec() == 0) { ret = mContacts; } mContactFeatures.clear(); mContacts.clear(); return ret; } QList TestConnHelper::upgradeContacts(const QList &contacts, const Tp::Features &features) { mLoop->processEvents(); QList ret; Tp::PendingContacts *pc = mClient->contactManager()->upgradeContacts(contacts, features); mContactFeatures = features; QObject::connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectUpgradeContactsFinished(Tp::PendingOperation*))); if (mLoop->exec() == 0) { ret = mContacts; } mContactFeatures.clear(); mContacts.clear(); return ret; } Tp::ChannelPtr TestConnHelper::createChannel(const QVariantMap &request) { mLoop->processEvents(); Tp::ChannelPtr ret; Tp::PendingChannel *pc = mClient->lowlevel()->createChannel(request); QObject::connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectCreateChannelFinished(Tp::PendingOperation*))); if (mLoop->exec() == 0) { ret = mChannel; } mChannel.reset(); return ret; } Tp::ChannelPtr TestConnHelper::createChannel(const QString &channelType, const Tp::ContactPtr &target) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), channelType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), target->handle()[0]); return createChannel(request); } Tp::ChannelPtr TestConnHelper::createChannel(const QString &channelType, Tp::HandleType targetHandleType, uint targetHandle) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), channelType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) targetHandleType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), targetHandle); return createChannel(request); } Tp::ChannelPtr TestConnHelper::createChannel(const QString &channelType, Tp::HandleType targetHandleType, const QString &targetID) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), channelType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) targetHandleType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), targetID); return ensureChannel(request); } Tp::ChannelPtr TestConnHelper::ensureChannel(const QVariantMap &request) { mLoop->processEvents(); Tp::ChannelPtr ret; Tp::PendingChannel *pc = mClient->lowlevel()->ensureChannel(request); QObject::connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectEnsureChannelFinished(Tp::PendingOperation*))); if (mLoop->exec() == 0) { ret = mChannel; } mChannel.reset(); return ret; } Tp::ChannelPtr TestConnHelper::ensureChannel(const QString &channelType, const Tp::ContactPtr &target) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), channelType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), target->handle()[0]); return ensureChannel(request); } Tp::ChannelPtr TestConnHelper::ensureChannel(const QString &channelType, Tp::HandleType targetHandleType, uint targetHandle) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), channelType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) targetHandleType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), targetHandle); return ensureChannel(request); } Tp::ChannelPtr TestConnHelper::ensureChannel(const QString &channelType, Tp::HandleType targetHandleType, const QString &targetID) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), channelType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) targetHandleType); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), targetID); return ensureChannel(request); } void TestConnHelper::expectConnInvalidated() { mLoop->exit(0); } void TestConnHelper::expectContactsForIdentifiersFinished(Tp::PendingOperation *op) { Tp::PendingContacts *pc = qobject_cast(op); QCOMPARE(pc->isForHandles(), false); QCOMPARE(pc->isForIdentifiers(), true); QCOMPARE(pc->isUpgrade(), false); expectPendingContactsFinished(pc); } void TestConnHelper::expectContactsForHandlesFinished(Tp::PendingOperation *op) { Tp::PendingContacts *pc = qobject_cast(op); QCOMPARE(pc->isForHandles(), true); QCOMPARE(pc->isForIdentifiers(), false); QCOMPARE(pc->isUpgrade(), false); expectPendingContactsFinished(pc); } void TestConnHelper::expectUpgradeContactsFinished(Tp::PendingOperation *op) { Tp::PendingContacts *pc = qobject_cast(op); QCOMPARE(pc->isUpgrade(), true); expectPendingContactsFinished(pc); } void TestConnHelper::expectPendingContactsFinished(Tp::PendingContacts *pc) { QCOMPARE(pc->manager(), mClient->contactManager()); if (pc->isError()) { qWarning().nospace() << pc->errorName() << ": " << pc->errorMessage(); mContacts.clear(); mLoop->exit(1); } else { mContacts = pc->contacts(); Q_FOREACH (const Tp::ContactPtr &contact, mContacts) { QVERIFY(contact->requestedFeatures().contains(mContactFeatures)); } mLoop->exit(0); } } void TestConnHelper::expectCreateChannelFinished(Tp::PendingOperation *op) { if (op->isError()) { qWarning().nospace() << op->errorName() << ": " << op->errorMessage(); mChannel.reset(); mLoop->exit(1); } else { Tp::PendingChannel *pc = qobject_cast(op); QCOMPARE(pc->yours(), true); mChannel = pc->channel(); mLoop->exit(0); } } void TestConnHelper::expectEnsureChannelFinished(Tp::PendingOperation *op) { if (op->isError()) { qWarning().nospace() << op->errorName() << ": " << op->errorMessage(); mChannel.reset(); mLoop->exit(1); } else { Tp::PendingChannel *pc = qobject_cast(op); QCOMPARE(pc->yours(), false); mChannel = pc->channel(); mLoop->exit(0); } } telepathy-qt-0.9.6~git1/tests/lib/glib-helpers/CMakeLists.txt0000664000175000017500000000145112470405660021776 0ustar jrjrinclude_directories( ${CMAKE_CURRENT_BINARY_DIR} ${TELEPATHY_GLIB_INCLUDE_DIR} ${GLIB2_INCLUDE_DIR} ${GOBJECT_INCLUDE_DIR} ${DBUS_INCLUDE_DIR}) add_definitions(-DQT_NO_KEYWORDS) if(ENABLE_TP_GLIB_TESTS) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_gen") tpqt_generate_moc_i(test-conn-helper.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/test-conn-helper.moc.hpp) add_library(tp-qt-tests-glib-helpers test-conn-helper.cpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/test-conn-helper.moc.hpp) target_link_libraries(tp-qt-tests-glib-helpers ${TELEPATHY_GLIB_LIBRARIES} ${GOBJECT_LIBRARIES} ${GLIB2_LIBRARIES} ${DBUS_GLIB_LIBRARIES} ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} telepathy-qt${QT_VERSION_MAJOR}) endif(ENABLE_TP_GLIB_TESTS) telepathy-qt-0.9.6~git1/tests/lib/glib-helpers/test-conn-helper.h0000664000175000017500000001001212470405660022567 0ustar jrjr#ifndef _TelepathyQt_tests_lib_glib_helpers_test_conn_helper_h_HEADER_GUARD_ #define _TelepathyQt_tests_lib_glib_helpers_test_conn_helper_h_HEADER_GUARD_ #include #include #include #include #include #include namespace Tp { class PendingContacts; } class TestConnHelper : public QObject { Q_OBJECT public: TestConnHelper(Test *parent, GType gType, const QString &account, const QString &protocol); TestConnHelper(Test *parent, GType gType, const char *firstPropertyName, ...); TestConnHelper(Test *parent, const Tp::ChannelFactoryConstPtr &channelFactory, const Tp::ContactFactoryConstPtr &contactFactory, GType gType, const QString &account, const QString &protocol); TestConnHelper(Test *parent, const Tp::ChannelFactoryConstPtr &channelFactory, const Tp::ContactFactoryConstPtr &contactFactory, GType gType, const char *firstPropertyName, ...); virtual ~TestConnHelper(); GObject *service() const { return mService; } Tp::ConnectionPtr client() const { return mClient; } QString objectPath() const; bool isValid() const; bool isReady(const Tp::Features &features = Tp::Features()) const; bool enableFeatures(const Tp::Features &features); bool connect(const Tp::Features &features = Tp::Features()); bool disconnect(); QList contacts(const QStringList &ids, const Tp::Features &features = Tp::Features()); QList contacts(const Tp::UIntList &handles, const Tp::Features &features = Tp::Features()); QList upgradeContacts(const QList &contacts, const Tp::Features &features = Tp::Features()); Tp::ChannelPtr createChannel(const QVariantMap &request); Tp::ChannelPtr createChannel(const QString &channelType, const Tp::ContactPtr &target); Tp::ChannelPtr createChannel(const QString &channelType, Tp::HandleType targetHandleType, uint targetHandle); Tp::ChannelPtr createChannel(const QString &channelType, Tp::HandleType targetHandleType, const QString &targetID); Tp::ChannelPtr ensureChannel(const QVariantMap &request); Tp::ChannelPtr ensureChannel(const QString &channelType, const Tp::ContactPtr &target); Tp::ChannelPtr ensureChannel(const QString &channelType, Tp::HandleType targetHandleType, uint targetHandle); Tp::ChannelPtr ensureChannel(const QString &channelType, Tp::HandleType targetHandleType, const QString &targetID); private Q_SLOTS: void expectConnInvalidated(); void expectContactsForIdentifiersFinished(Tp::PendingOperation *op); void expectContactsForHandlesFinished(Tp::PendingOperation *op); void expectUpgradeContactsFinished(Tp::PendingOperation *op); void expectCreateChannelFinished(Tp::PendingOperation *op); void expectEnsureChannelFinished(Tp::PendingOperation *op); private: void init(Test *parent, const Tp::ChannelFactoryConstPtr &channelFactory, const Tp::ContactFactoryConstPtr &contactFactory, GType gType, const char *firstPropertyName, ...); void init(Test *parent, const Tp::ChannelFactoryConstPtr &channelFactory, const Tp::ContactFactoryConstPtr &contactFactory, GType gType, const char *firstPropertyName, va_list varArgs); void expectPendingContactsFinished(Tp::PendingContacts *pc); Test *mParent; QEventLoop *mLoop; GObject *mService; Tp::ConnectionPtr mClient; // The property retrieved by expectPendingContactsFinished() QList mContacts; // Property used by expectPendingContactsFinished() Tp::Features mContactFeatures; // The property retrieved by expectCreate/EnsureChannelFinished() Tp::ChannelPtr mChannel; }; #endif // _TelepathyQt_tests_lib_glib_helpers_test_conn_helper_h_HEADER_GUARD_ telepathy-qt-0.9.6~git1/tests/lib/test.h0000664000175000017500000000404612470405660016014 0ustar jrjr#ifndef _TelepathyQt_tests_lib_test_h_HEADER_GUARD_ #define _TelepathyQt_tests_lib_test_h_HEADER_GUARD_ #include #include #include #include #include namespace Tp { class DBusProxy; } class Test : public QObject { Q_OBJECT public: Test(QObject *parent = 0); virtual ~Test(); QEventLoop *mLoop; void processDBusQueue(Tp::DBusProxy *proxy); // The last error received in expectFailure() QString mLastError; QString mLastErrorMessage; protected: template bool waitForProperty(Tp::PendingVariant *pv, T *value); protected Q_SLOTS: void expectSuccessfulCall(QDBusPendingCallWatcher*); void expectSuccessfulCall(Tp::PendingOperation*); void expectFailure(Tp::PendingOperation*); void expectSuccessfulProperty(Tp::PendingOperation *op); void onWatchdog(); virtual void initTestCaseImpl(); virtual void initImpl(); virtual void cleanupImpl(); virtual void cleanupTestCaseImpl(); private: // The property retrieved by expectSuccessfulProperty() QVariant mPropertyValue; }; template bool Test::waitForProperty(Tp::PendingVariant *pv, T *value) { connect(pv, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulProperty(Tp::PendingOperation*))); if (mLoop->exec() == 1000) { *value = qdbus_cast(mPropertyValue); return true; } else { *value = T(); return false; } } #define TEST_VERIFY_OP(op) \ if (!op->isFinished()) { \ qWarning() << "unfinished"; \ mLoop->exit(1); \ return; \ } \ if (op->isError()) { \ qWarning().nospace() << op->errorName() << ": " << op->errorMessage(); \ mLoop->exit(2); \ return; \ } \ if (!op->isValid()) { \ qWarning() << "inconsistent results"; \ mLoop->exit(3); \ return; \ } \ qDebug() << "finished"; #endif // _TelepathyQt_tests_lib_test_h_HEADER_GUARD_ telepathy-qt-0.9.6~git1/tests/lib/test-thread-helper.cpp0000664000175000017500000000173712470405660021075 0ustar jrjr#include "tests/lib/test-thread-helper.h" #include #include TestThreadHelperBase::TestThreadHelperBase(ThreadObjectBase *threadObject) { Q_ASSERT(threadObject); mThread = new QThread; mThreadObject = threadObject; mThreadObject->moveToThread(mThread); QEventLoop loop; QObject::connect(mThread, SIGNAL(started()), &loop, SLOT(quit())); QTimer::singleShot(0, mThread, SLOT(start())); loop.exec(); } TestThreadHelperBase::~TestThreadHelperBase() { QMetaObject::invokeMethod(mThreadObject, "deleteLater"); mThread->quit(); mThread->wait(); mThread->deleteLater(); QCoreApplication::processEvents(); } void TestThreadHelperBase::executeCallback() { QEventLoop loop; QObject::connect(mThreadObject, SIGNAL(callbackExecutionFinished()), &loop, SLOT(quit())); QMetaObject::invokeMethod(mThreadObject, "executeCallback"); loop.exec(); } #include "_gen/test-thread-helper.h.moc.hpp" telepathy-qt-0.9.6~git1/tests/profile.cpp0000664000175000017500000001242212470405660016257 0ustar jrjr#include #include #include using namespace Tp; class TestProfile : public QObject { Q_OBJECT public: TestProfile(QObject *parent = 0); private Q_SLOTS: void testProfile(); }; TestProfile::TestProfile(QObject *parent) : QObject(parent) { Tp::enableDebug(true); Tp::enableWarnings(true); } void TestProfile::testProfile() { QString top_srcdir = QString::fromLocal8Bit(::getenv("abs_top_srcdir")); if (!top_srcdir.isEmpty()) { QDir::setCurrent(top_srcdir + QLatin1String("/tests")); } ProfilePtr profile = Profile::createForServiceName(QLatin1String("test-profile-file-not-found")); QCOMPARE(profile->isValid(), false); profile = Profile::createForServiceName(QLatin1String("test-profile-malformed")); QCOMPARE(profile->isValid(), false); profile = Profile::createForServiceName(QLatin1String("test-profile-invalid-service-id")); QCOMPARE(profile->isValid(), false); profile = Profile::createForServiceName(QLatin1String("test-profile-non-im-type")); QCOMPARE(profile->isValid(), false); profile = Profile::createForFileName(QLatin1String("telepathy/profiles/test-profile-non-im-type.profile")); QCOMPARE(profile->isValid(), true); profile = Profile::createForServiceName(QLatin1String("test-profile")); QCOMPARE(profile->isValid(), true); QCOMPARE(profile->serviceName(), QLatin1String("test-profile")); QCOMPARE(profile->type(), QLatin1String("IM")); QCOMPARE(profile->provider(), QLatin1String("TestProfileProvider")); QCOMPARE(profile->name(), QLatin1String("TestProfile")); QCOMPARE(profile->cmName(), QLatin1String("testprofilecm")); QCOMPARE(profile->protocolName(), QLatin1String("testprofileproto")); QCOMPARE(profile->parameters().isEmpty(), false); QCOMPARE(profile->parameters().count(), 2); QCOMPARE(profile->hasParameter(QLatin1String("foo")), false); QCOMPARE(profile->hasParameter(QLatin1String("server")), true); Profile::Parameter param = profile->parameter(QLatin1String("server")); QCOMPARE(param.name(), QLatin1String("server")); QCOMPARE(param.dbusSignature(), QDBusSignature(QLatin1String("s"))); QCOMPARE(param.type(), QVariant::String); QCOMPARE(param.value(), QVariant(QLatin1String("profile.com"))); QCOMPARE(param.label(), QString()); QCOMPARE(param.isMandatory(), true); QCOMPARE(profile->hasParameter(QLatin1String("port")), true); param = profile->parameter(QLatin1String("port")); QCOMPARE(param.name(), QLatin1String("port")); QCOMPARE(param.dbusSignature(), QDBusSignature(QLatin1String("u"))); QCOMPARE(param.type(), QVariant::UInt); QCOMPARE(param.value(), QVariant(QLatin1String("1111"))); QCOMPARE(param.label(), QString()); QCOMPARE(param.isMandatory(), true); QCOMPARE(profile->presences().isEmpty(), false); QCOMPARE(profile->presences().count(), 5); QCOMPARE(profile->hasPresence(QLatin1String("foo")), false); QCOMPARE(profile->hasPresence(QLatin1String("available")), true); Profile::Presence presence = profile->presence(QLatin1String("available")); QCOMPARE(presence.id(), QLatin1String("available")); QCOMPARE(presence.label(), QLatin1String("Online")); QCOMPARE(presence.iconName(), QLatin1String("online")); QCOMPARE(presence.isDisabled(), false); QCOMPARE(profile->hasPresence(QLatin1String("offline")), true); presence = profile->presence(QLatin1String("offline")); QCOMPARE(presence.id(), QLatin1String("offline")); QCOMPARE(presence.label(), QLatin1String("Offline")); QCOMPARE(presence.iconName(), QString()); QCOMPARE(presence.isDisabled(), false); QCOMPARE(profile->hasPresence(QLatin1String("away")), true); presence = profile->presence(QLatin1String("away")); QCOMPARE(presence.id(), QLatin1String("away")); QCOMPARE(presence.label(), QLatin1String("Gone")); QCOMPARE(presence.iconName(), QString()); QCOMPARE(presence.isDisabled(), false); QCOMPARE(profile->hasPresence(QLatin1String("hidden")), true); presence = profile->presence(QLatin1String("hidden")); QCOMPARE(presence.id(), QLatin1String("hidden")); QCOMPARE(presence.label(), QString()); QCOMPARE(presence.iconName(), QString()); QCOMPARE(presence.isDisabled(), true); QCOMPARE(profile->unsupportedChannelClassSpecs().isEmpty(), false); QCOMPARE(profile->unsupportedChannelClassSpecs().count(), 2); RequestableChannelClassSpec rccSpec = profile->unsupportedChannelClassSpecs().first(); QCOMPARE(rccSpec.hasTargetHandleType(), true); QCOMPARE(rccSpec.targetHandleType(), HandleTypeContact); QCOMPARE(rccSpec.channelType(), QLatin1String("org.freedesktop.Telepathy.Channel.Type.Text")); profile = Profile::createForServiceName(QLatin1String("test-profile-no-icon-and-provider")); QCOMPARE(profile->isValid(), true); QCOMPARE(profile->serviceName(), QLatin1String("test-profile-no-icon-and-provider")); QCOMPARE(profile->type(), QLatin1String("IM")); QCOMPARE(profile->provider().isEmpty(), true); QCOMPARE(profile->cmName(), QLatin1String("testprofilecm")); QCOMPARE(profile->protocolName(), QLatin1String("testprofileproto")); QCOMPARE(profile->iconName().isEmpty(), true); } QTEST_MAIN(TestProfile) #include "_gen/profile.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/ptr.cpp0000664000175000017500000002103412470405660015423 0ustar jrjr#include #include #include using namespace Tp; class TestSharedPtr : public QObject { Q_OBJECT private Q_SLOTS: void testSharedPtrDict(); void testSharedPtrBoolConversion(); void testWeakPtrBoolConversion(); void testThreadSafety(); }; class Data; typedef SharedPtr DataPtr; class Data : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(Data); public: static DataPtr create() { return DataPtr(new Data()); } static DataPtr createNull() { return DataPtr(0); } private: Data() {} }; void TestSharedPtr::testSharedPtrDict() { QHash dict; DataPtr nullPtr = Data::createNull(); dict[nullPtr] = 1; QCOMPARE(dict.size(), 1); QCOMPARE(dict[nullPtr], 1); DataPtr validPtr1 = Data::create(); QCOMPARE(qHash(validPtr1.data()), qHash(validPtr1)); dict[validPtr1] = 2; QCOMPARE(dict.size(), 2); QCOMPARE(dict[nullPtr], 1); QCOMPARE(dict[validPtr1], 2); DataPtr validPtr2 = validPtr1; QCOMPARE(validPtr1.data(), validPtr2.data()); QCOMPARE(qHash(validPtr1), qHash(validPtr2)); dict[validPtr2] = 3; QCOMPARE(dict.size(), 2); QCOMPARE(dict[nullPtr], 1); QCOMPARE(dict[validPtr1], 3); QCOMPARE(dict[validPtr2], 3); DataPtr validPtrAlternative = Data::create(); QVERIFY(validPtr1.data() != validPtrAlternative.data()); QVERIFY(validPtr1 != validPtrAlternative); QVERIFY(qHash(validPtr1) != qHash(validPtrAlternative)); dict[validPtrAlternative] = 4; QCOMPARE(dict.size(), 3); QCOMPARE(dict[nullPtr], 1); QCOMPARE(dict[validPtr1], 3); QCOMPARE(dict[validPtr2], 3); QCOMPARE(dict[validPtrAlternative], 4); } void TestSharedPtr::testSharedPtrBoolConversion() { DataPtr nullPtr1; DataPtr nullPtr2 = Data::createNull(); DataPtr validPtr1 = Data::create(); DataPtr validPtr2 = validPtr1; DataPtr validPtrAlternative = Data::create(); // Boolean conditions QVERIFY(!validPtr1.isNull()); QVERIFY(nullPtr1.isNull()); QVERIFY(validPtr1 ? true : false); QVERIFY(!validPtr1 ? false : true); QVERIFY(nullPtr1 ? false : true); QVERIFY(!nullPtr1 ? true : false); QVERIFY(validPtr1); QVERIFY(!!validPtr1); QVERIFY(!nullPtr1); // Supported operators QVERIFY(nullPtr1 == nullPtr1); QVERIFY(nullPtr1 == nullPtr2); QVERIFY(validPtr1 == validPtr1); QVERIFY(validPtr1 == validPtr2); QVERIFY(validPtr1 != validPtrAlternative); QCOMPARE(validPtr1 == validPtrAlternative, false); QVERIFY(validPtr1 != nullPtr1); QCOMPARE(validPtr1 == nullPtr1, false); // Supported conversions, constructors and copy operators bool trueBool1 = validPtr1; QVERIFY(trueBool1); bool trueBool2(validPtr2); QVERIFY(trueBool2); trueBool1 = validPtrAlternative; QVERIFY(trueBool1); bool falseBool1 = nullPtr1; QVERIFY(!falseBool1); bool falseBool2(nullPtr2); QVERIFY(!falseBool2); falseBool1 = nullPtr1; QVERIFY(!falseBool1); #if 0 // Unsupported operators, this should not compile bool condition; condition = validPtr1 > nullPtr1; condition = validPtr1 + nullPtr1; // Unsupported conversions, this should not compile int validInt1 = validPtr1; int validInt2(validPtr1); validInt1 = validPtr1; int nullInt1 = nullPtr1; int nullInt2(nullPtr1); nullInt1 = nullPtr1; float validFloat1 = validPtr1; float validFloat2(validPtr1); validFloat1 = validPtr1; float nullFloat1 = nullPtr1; float nullFloat2(nullPtr1); nullFloat1 = nullPtr1; Q_UNUSED(validInt1); Q_UNUSED(validInt2); Q_UNUSED(nullInt1); Q_UNUSED(nullInt2); Q_UNUSED(validFloat1); Q_UNUSED(validFloat2); Q_UNUSED(nullFloat1); Q_UNUSED(nullFloat2); #endif } void TestSharedPtr::testWeakPtrBoolConversion() { WeakPtr nullPtr1; DataPtr strongNullPtr2 = Data::createNull(); WeakPtr nullPtr2 = strongNullPtr2; DataPtr strongValidPtr1 = Data::create(); WeakPtr validPtr1 = strongValidPtr1; WeakPtr validPtr2 = validPtr1; DataPtr strongValidPtrAlternative = Data::create(); WeakPtr validPtrAlternative = strongValidPtrAlternative; // Boolean conditions QVERIFY(!validPtr1.isNull()); QVERIFY(nullPtr1.isNull()); QVERIFY(validPtr1 ? true : false); QVERIFY(!validPtr1 ? false : true); QVERIFY(nullPtr1 ? false : true); QVERIFY(!nullPtr1 ? true : false); QVERIFY(validPtr1); QVERIFY(!!validPtr1); QVERIFY(!nullPtr1); // Supported operators QVERIFY(nullPtr1 == nullPtr1); QVERIFY(nullPtr1 == nullPtr2); QVERIFY(validPtr1 == validPtr1); QVERIFY(validPtr1 == validPtr2); // XXX why not comparison operator? //QVERIFY(validPtr1 != validPtrAlternative); //QCOMPARE(validPtr1 == validPtrAlternative, false); QVERIFY(validPtr1 != nullPtr1); QCOMPARE(validPtr1 == nullPtr1, false); // Supported conversions, constructors and copy operators bool trueBool1 = validPtr1; QVERIFY(trueBool1); bool trueBool2(validPtr2); QVERIFY(trueBool2); trueBool1 = validPtrAlternative; QVERIFY(trueBool1); bool falseBool1 = nullPtr1; QVERIFY(!falseBool1); bool falseBool2(nullPtr2); QVERIFY(!falseBool2); falseBool1 = nullPtr1; QVERIFY(!falseBool1); #if 0 // Unsupported operators, this should not compile bool condition; condition = validPtr1 > nullPtr1; condition = validPtr1 + nullPtr1; // Unsupported conversions, this should not compile int validInt1 = validPtr1; int validInt2(validPtr1); validInt1 = validPtr1; int nullInt1 = nullPtr1; int nullInt2(nullPtr1); nullInt1 = nullPtr1; float validFloat1 = validPtr1; float validFloat2(validPtr1); validFloat1 = validPtr1; float nullFloat1 = nullPtr1; float nullFloat2(nullPtr1); nullFloat1 = nullPtr1; Q_UNUSED(validInt1); Q_UNUSED(validInt2); Q_UNUSED(nullInt1); Q_UNUSED(nullInt2); Q_UNUSED(validFloat1); Q_UNUSED(validFloat2); Q_UNUSED(nullFloat1); Q_UNUSED(nullFloat2); #endif // Test the boolean operations after the main SharedPtr is gone strongValidPtrAlternative.reset(); QVERIFY(validPtrAlternative.isNull()); QVERIFY(validPtrAlternative ? false : true); QVERIFY(!validPtrAlternative ? true : false); } class Thread : public QThread { public: Thread(const DataPtr &ptr, QObject *parent = 0) : QThread(parent), mPtr(ptr) {} void run() { QVERIFY(!mPtr.isNull()); for (int i = 0; i < 200; ++i) { WeakPtr wptrtmp(mPtr); QVERIFY(!wptrtmp.isNull()); DataPtr ptrtmp(wptrtmp); wptrtmp = WeakPtr(); QVERIFY(!ptrtmp.isNull()); DataPtr ptrtmp2(ptrtmp); ptrtmp.reset(); QVERIFY(!ptrtmp2.isNull()); WeakPtr wptrtmp2 = ptrtmp2; ptrtmp2.reset(); QVERIFY(!wptrtmp2.isNull()); WeakPtr wptrtmp3(wptrtmp2); QVERIFY(!wptrtmp3.isNull()); wptrtmp3 = wptrtmp2; wptrtmp2 = WeakPtr(); QVERIFY(!wptrtmp3.isNull()); DataPtr ptrtmp3(wptrtmp3); wptrtmp3 = WeakPtr(); QCOMPARE(ptrtmp3.data(), mPtr.data()); QVERIFY(!ptrtmp3.isNull()); WeakPtr wptrtmp4(ptrtmp3.data()); ptrtmp3.reset(); QVERIFY(!wptrtmp4.isNull()); } } private: DataPtr mPtr; }; void TestSharedPtr::testThreadSafety() { DataPtr ptr = Data::create(); WeakPtr weakPtr(ptr); Data *savedData = ptr.data(); QVERIFY(savedData != NULL); QVERIFY(!ptr.isNull()); QVERIFY(!weakPtr.isNull()); Thread *t[5]; for (int i = 0; i < 5; ++i) { t[i] = new Thread(ptr, this); t[i]->start(); } for (int i = 0; i < 5; ++i) { t[i]->wait(); delete t[i]; } QCOMPARE(ptr.data(), savedData); QVERIFY(!ptr.isNull()); QVERIFY(!weakPtr.isNull()); for (int i = 0; i < 5; ++i) { t[i] = new Thread(ptr, this); t[i]->start(); } QVERIFY(!ptr.isNull()); QVERIFY(!weakPtr.isNull()); ptr.reset(); QVERIFY(ptr.isNull()); for (int i = 0; i < 5; ++i) { t[i]->wait(); delete t[i]; } QVERIFY(!ptr.data()); QVERIFY(ptr.isNull()); QVERIFY(weakPtr.isNull()); DataPtr promotedPtr(weakPtr); QVERIFY(!promotedPtr.data()); QVERIFY(promotedPtr.isNull()); } QTEST_MAIN(TestSharedPtr) #include "_gen/ptr.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/manager-file.cpp0000664000175000017500000002345012470405660017151 0ustar jrjr#include #include #include #include "TelepathyQt/manager-file.h" using namespace Tp; namespace { bool containsParam(const ParamSpecList ¶ms, const char *name) { Q_FOREACH (const ParamSpec ¶m, params) { if (param.name == QLatin1String(name)) { return true; } } return false; } const ParamSpec *getParam(const ParamSpecList ¶ms, const QString &name) { Q_FOREACH (const ParamSpec ¶m, params) { if (param.name == name) { return ¶m; } } return NULL; } PresenceSpec getPresenceSpec(const PresenceSpecList &specs, const QString &status) { foreach (const PresenceSpec &spec, specs) { if (spec.presence().status() == status) { return spec; } } return PresenceSpec(); } } class TestManagerFile : public QObject { Q_OBJECT public: TestManagerFile(QObject *parent = 0); private Q_SLOTS: void testManagerFile(); }; TestManagerFile::TestManagerFile(QObject *parent) : QObject(parent) { Tp::enableDebug(true); Tp::enableWarnings(true); } void TestManagerFile::testManagerFile() { ManagerFile notFoundManagerFile(QLatin1String("test-manager-file-not-found")); QCOMPARE(notFoundManagerFile.isValid(), false); ManagerFile invalidManagerFile(QLatin1String("test-manager-file-malformed-keyfile")); QCOMPARE(invalidManagerFile.isValid(), false); ManagerFile invalidManagerFile2(QLatin1String("test-manager-file-invalid-signature")); QCOMPARE(invalidManagerFile2.isValid(), false); ManagerFile managerFile(QLatin1String("test-manager-file")); QCOMPARE(managerFile.isValid(), true); QStringList protocols = managerFile.protocols(); protocols.sort(); QCOMPARE(protocols, QStringList() << QLatin1String("bar") << QLatin1String("foo") << QLatin1String("somewhat-pathological")); ParamSpecList params = managerFile.parameters(QLatin1String("foo")); QCOMPARE(containsParam(params, "account"), true); QCOMPARE(containsParam(params, "encryption-key"), true); QCOMPARE(containsParam(params, "password"), true); QCOMPARE(containsParam(params, "port"), true); QCOMPARE(containsParam(params, "register"), true); QCOMPARE(containsParam(params, "server-list"), true); QCOMPARE(containsParam(params, "non-existant"), false); QCOMPARE(QLatin1String("x-foo"), managerFile.vcardField(QLatin1String("foo"))); QCOMPARE(QLatin1String("Foo"), managerFile.englishName(QLatin1String("foo"))); QCOMPARE(QLatin1String("im-foo"), managerFile.iconName(QLatin1String("foo"))); QStringList addressableVCardFields = managerFile.addressableVCardFields(QLatin1String("foo")); QCOMPARE(addressableVCardFields, QStringList() << QLatin1String("x-foo")); QStringList addressableUriSchemes = managerFile.addressableUriSchemes(QLatin1String("foo")); QCOMPARE(addressableUriSchemes, QStringList() << QLatin1String("foo")); RequestableChannelClass ftRcc; ftRcc.fixedProperties.insert( TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER); ftRcc.fixedProperties.insert( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), HandleTypeContact); ftRcc.fixedProperties.insert( TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER + QLatin1String(".ContentHashType"), FileHashTypeMD5); ftRcc.allowedProperties.append( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")); ftRcc.allowedProperties.append( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")); RequestableChannelClass fooTextRcc; fooTextRcc.fixedProperties.insert( TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); fooTextRcc.fixedProperties.insert( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), HandleTypeContact); fooTextRcc.allowedProperties.append( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")); fooTextRcc.allowedProperties.append( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")); RequestableChannelClassList expectedRccs; expectedRccs.append(ftRcc); expectedRccs.append(fooTextRcc); QCOMPARE(expectedRccs.size(), managerFile.requestableChannelClasses(QLatin1String("foo")).size()); qDebug() << managerFile.requestableChannelClasses(QLatin1String("foo"))[0].fixedProperties; qDebug() << managerFile.requestableChannelClasses(QLatin1String("foo"))[1].fixedProperties; QCOMPARE(ftRcc, managerFile.requestableChannelClasses(QLatin1String("foo"))[0]); QCOMPARE(fooTextRcc, managerFile.requestableChannelClasses(QLatin1String("foo"))[1]); const ParamSpec *param; param = getParam(params, QLatin1String("account")); QCOMPARE(param->flags, (uint) ConnMgrParamFlagRequired | ConnMgrParamFlagHasDefault); QCOMPARE(param->signature, QString(QLatin1String("s"))); param = getParam(params, QLatin1String("password")); QCOMPARE(param->flags, (uint) ConnMgrParamFlagRequired | ConnMgrParamFlagSecret); QCOMPARE(param->signature, QString(QLatin1String("s"))); param = getParam(params, QLatin1String("encryption-key")); QCOMPARE(param->flags, (uint) ConnMgrParamFlagSecret); QCOMPARE(param->signature, QString(QLatin1String("s"))); PresenceSpecList statuses = managerFile.allowedPresenceStatuses(QLatin1String("foo")); QCOMPARE(statuses.size(), 3); PresenceSpec spec; spec = getPresenceSpec(statuses, QLatin1String("offline")); QCOMPARE(spec.isValid(), true); QVERIFY(spec.presence().type() == ConnectionPresenceTypeOffline); QCOMPARE(spec.maySetOnSelf(), false); QCOMPARE(spec.canHaveStatusMessage(), false); spec = getPresenceSpec(statuses, QLatin1String("dnd")); QCOMPARE(spec.isValid(), true); QVERIFY(spec.presence().type() == ConnectionPresenceTypeBusy); QCOMPARE(spec.maySetOnSelf(), true); QCOMPARE(spec.canHaveStatusMessage(), false); spec = getPresenceSpec(statuses, QLatin1String("available")); QCOMPARE(spec.isValid(), true); QVERIFY(spec.presence().type() == ConnectionPresenceTypeAvailable); QCOMPARE(spec.maySetOnSelf(), true); QCOMPARE(spec.canHaveStatusMessage(), true); AvatarSpec avatarReqs = managerFile.avatarRequirements(QLatin1String("foo")); QStringList supportedMimeTypes = avatarReqs.supportedMimeTypes(); supportedMimeTypes.sort(); QCOMPARE(supportedMimeTypes, QStringList() << QLatin1String("image/gif") << QLatin1String("image/jpeg") << QLatin1String("image/png")); QCOMPARE(avatarReqs.minimumHeight(), (uint) 32); QCOMPARE(avatarReqs.maximumHeight(), (uint) 96); QCOMPARE(avatarReqs.recommendedHeight(), (uint) 64); QCOMPARE(avatarReqs.minimumWidth(), (uint) 32); QCOMPARE(avatarReqs.maximumWidth(), (uint) 96); QCOMPARE(avatarReqs.recommendedWidth(), (uint) 64); QCOMPARE(avatarReqs.maximumBytes(), (uint) 8192); params = managerFile.parameters(QLatin1String("somewhat-pathological")); QCOMPARE(containsParam(params, "foo"), true); QCOMPARE(containsParam(params, "semicolons"), true); QCOMPARE(containsParam(params, "list"), true); QCOMPARE(containsParam(params, "unterminated-list"), true); QCOMPARE(containsParam(params, "spaces-in-list"), true); QCOMPARE(containsParam(params, "escaped-semicolon-in-list"), true); QCOMPARE(containsParam(params, "doubly-escaped-semicolon-in-list"), true); QCOMPARE(containsParam(params, "triply-escaped-semicolon-in-list"), true); QCOMPARE(containsParam(params, "empty-list"), true); QCOMPARE(containsParam(params, "escaped-semicolon"), true); QCOMPARE(containsParam(params, "object"), true); QCOMPARE(containsParam(params, "non-existant"), false); param = getParam(params, QLatin1String("foo")); QCOMPARE(param->flags, (uint) ConnMgrParamFlagRequired | ConnMgrParamFlagHasDefault); QCOMPARE(param->signature, QString(QLatin1String("s"))); param = getParam(params, QLatin1String("semicolons")); QCOMPARE(param->flags, (uint) ConnMgrParamFlagSecret | ConnMgrParamFlagHasDefault); QCOMPARE(param->signature, QString(QLatin1String("s"))); param = getParam(params, QLatin1String("list")); QCOMPARE(param->signature, QString(QLatin1String("as"))); QCOMPARE(param->defaultValue.variant().toStringList(), QStringList() << QLatin1String("list") << QLatin1String("of") << QLatin1String("misc")); param = getParam(params, QLatin1String("escaped-semicolon-in-list")); QCOMPARE(param->signature, QString(QLatin1String("as"))); QCOMPARE(param->defaultValue.variant().toStringList(), QStringList() << QLatin1String("list;of") << QLatin1String("misc")); param = getParam(params, QLatin1String("doubly-escaped-semicolon-in-list")); QCOMPARE(param->signature, QString(QLatin1String("as"))); QCOMPARE(param->defaultValue.variant().toStringList(), QStringList() << QLatin1String("list\\") << QLatin1String("of") << QLatin1String("misc")); param = getParam(params, QLatin1String("triply-escaped-semicolon-in-list")); QCOMPARE(param->signature, QString(QLatin1String("as"))); QCOMPARE(param->defaultValue.variant().toStringList(), QStringList() << QLatin1String("list\\;of") << QLatin1String("misc")); param = getParam(params, QLatin1String("empty-list")); QCOMPARE(param->signature, QString(QLatin1String("as"))); QCOMPARE(param->defaultValue.variant().toStringList(), QStringList()); param = getParam(params, QLatin1String("list-of-empty-string")); QCOMPARE(param->signature, QString(QLatin1String("as"))); QCOMPARE(param->defaultValue.variant().toStringList(), QStringList() << QString()); } QTEST_MAIN(TestManagerFile) #include "_gen/manager-file.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/channel-class-spec.cpp0000664000175000017500000001160312470405660020262 0ustar jrjr#include #include #include #include #include using namespace Tp; namespace { ChannelClassSpecList reverse(const ChannelClassSpecList &list) { ChannelClassSpecList ret(list); for (int k = 0; k < (list.size() / 2); k++) { ret.swap(k, list.size() - (1 + k)); } return ret; } }; class TestChannelClassSpec : public QObject { Q_OBJECT public: TestChannelClassSpec(QObject *parent = 0); private Q_SLOTS: void testChannelClassSpecHash(); void testServiceLeaks(); }; TestChannelClassSpec::TestChannelClassSpec(QObject *parent) : QObject(parent) { Tp::enableDebug(true); Tp::enableWarnings(true); } void TestChannelClassSpec::testChannelClassSpecHash() { ChannelClassSpec st1 = ChannelClassSpec::textChat(); ChannelClassSpec st2 = ChannelClassSpec::textChat(); ChannelClassSpec ssm1 = ChannelClassSpec::streamedMediaCall(); ChannelClassSpec ssm2 = ChannelClassSpec::streamedMediaCall(); QCOMPARE(qHash(st1), qHash(st2)); QCOMPARE(qHash(ssm1), qHash(ssm2)); QVERIFY(qHash(st1) != qHash(ssm1)); // hash of list with duplicated elements should be the same as hash of the list of same items // but with no duplicates ChannelClassSpecList sl1; sl1 << st1 << st2; ChannelClassSpecList sl2; sl2 << st1; QCOMPARE(qHash(sl1), qHash(sl2)); // hash of list with same elements but different order should be the same sl1.clear(); sl2.clear(); sl1 << st1 << ssm1; sl2 << ssm1 << st1; QCOMPARE(qHash(sl1), qHash(sl2)); // still the same but with duplicated elements sl2 << ssm2 << st2; QCOMPARE(qHash(sl1), qHash(sl2)); sl1 << st2; QCOMPARE(qHash(sl1), qHash(sl2)); // now sl2 is different from sl1, hash should be different sl2 << ChannelClassSpec::unnamedTextChat(); QVERIFY(qHash(sl1) != qHash(sl2)); // same again sl1.prepend(ChannelClassSpec::unnamedTextChat()); QCOMPARE(qHash(sl1), qHash(sl2)); sl1.clear(); sl2.clear(); for (int i = 0; i < 100; ++i) { sl1 << ChannelClassSpec::textChat() << ChannelClassSpec::streamedMediaCall() << ChannelClassSpec::unnamedTextChat(); } ChannelClassSpec specs[3] = { ChannelClassSpec::textChat(), ChannelClassSpec::streamedMediaCall(), ChannelClassSpec::unnamedTextChat() }; for (int i = 0; i < 3; ++i) { ChannelClassSpec spec = specs[i]; for (int j = 0; j < 100; ++j) { sl2 << spec; } } QCOMPARE(qHash(sl1), qHash(ChannelClassSpecList() << ChannelClassSpec::unnamedTextChat() << ChannelClassSpec::streamedMediaCall() << ChannelClassSpec::textChat())); for (int i = 0; i < 1000; ++i) { ChannelClassSpec spec = ChannelClassSpec::outgoingStreamTube(QString::number(i)); sl1 << spec; sl2.prepend(spec); } QCOMPARE(qHash(sl1), qHash(sl2)); sl1 = reverse(sl1); sl2 = reverse(sl2); QCOMPARE(qHash(sl1), qHash(sl2)); sl2 << ChannelClassSpec::outgoingFileTransfer(); QVERIFY(qHash(sl1) != qHash(sl2)); } void TestChannelClassSpec::testServiceLeaks() { ChannelClassSpec bareTube = ChannelClassSpec::outgoingStreamTube(); QVERIFY(!bareTube.allProperties().contains(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QString::fromLatin1(".Service"))); ChannelClassSpec ftpTube = ChannelClassSpec::outgoingStreamTube(QLatin1String("ftp")); QVERIFY(ftpTube.allProperties().contains(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QString::fromLatin1(".Service"))); QCOMPARE(ftpTube.allProperties().value(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QString::fromLatin1(".Service")).toString(), QString::fromLatin1("ftp")); QVERIFY(!bareTube.allProperties().contains(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QString::fromLatin1(".Service"))); ChannelClassSpec httpTube = ChannelClassSpec::outgoingStreamTube(QLatin1String("http")); QVERIFY(httpTube.allProperties().contains(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QString::fromLatin1(".Service"))); QVERIFY(ftpTube.allProperties().contains(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QString::fromLatin1(".Service"))); QCOMPARE(httpTube.allProperties().value(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QString::fromLatin1(".Service")).toString(), QString::fromLatin1("http")); QCOMPARE(ftpTube.allProperties().value(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QString::fromLatin1(".Service")).toString(), QString::fromLatin1("ftp")); QVERIFY(!bareTube.allProperties().contains(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QString::fromLatin1(".Service"))); } QTEST_MAIN(TestChannelClassSpec) #include "_gen/channel-class-spec.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/file-transfer-channel-creation-properties.cpp0000664000175000017500000001343412470405660024766 0ustar jrjr#include #include using namespace Tp; class TestFileTransferCreationProperties : public QObject { Q_OBJECT private Q_SLOTS: void testFileTransferCreationPropertiesDefaultConstructor(); void testFileTransferCreationPropertiesDefaultByMandatoryProperties(); void testFileTransferCreationPropertiesDefaultByPath(); void testFileTransferCreationPropertiesDefaultByPathFail(); }; void TestFileTransferCreationProperties::testFileTransferCreationPropertiesDefaultConstructor() { FileTransferChannelCreationProperties ftprops; QVERIFY(!ftprops.isValid()); QVERIFY(ftprops.suggestedFileName().isEmpty()); QVERIFY(ftprops.contentType().isEmpty()); QCOMPARE(ftprops.size(), (qulonglong)0); QVERIFY(!ftprops.hasContentHash()); QCOMPARE(ftprops.contentHashType(), FileHashTypeNone); QVERIFY(ftprops.contentHash().isEmpty()); ftprops.setContentHash(FileHashTypeMD5, QLatin1String("ffffffffffffffff")); QVERIFY(!ftprops.isValid()); QVERIFY(!ftprops.hasContentHash()); QCOMPARE(ftprops.contentHashType(), FileHashTypeNone); QVERIFY(ftprops.contentHash().isEmpty()); QVERIFY(!ftprops.hasDescription()); QVERIFY(ftprops.description().isEmpty()); ftprops.setDescription(QLatin1String("description")); QVERIFY(!ftprops.isValid()); QVERIFY(!ftprops.hasDescription()); QVERIFY(ftprops.description().isEmpty()); QVERIFY(!ftprops.hasLastModificationTime()); QVERIFY(!ftprops.lastModificationTime().isValid()); ftprops.setLastModificationTime(QDateTime::currentDateTime()); QVERIFY(!ftprops.isValid()); QVERIFY(!ftprops.hasLastModificationTime()); QVERIFY(!ftprops.lastModificationTime().isValid()); QVERIFY(!ftprops.hasUri()); QVERIFY(ftprops.uri().isEmpty()); ftprops.setUri(QLatin1String("file:///path/filename")); QVERIFY(!ftprops.isValid()); QVERIFY(!ftprops.hasUri()); QVERIFY(ftprops.uri().isEmpty()); } void TestFileTransferCreationProperties::testFileTransferCreationPropertiesDefaultByMandatoryProperties() { FileTransferChannelCreationProperties ftprops(QLatin1String("suggestedFileName"), QLatin1String("application/octet-stream"), (qulonglong)10000); QCOMPARE(ftprops.isValid(), true); QCOMPARE(ftprops.suggestedFileName(), QLatin1String("suggestedFileName")); QCOMPARE(ftprops.contentType(), QLatin1String("application/octet-stream")); QCOMPARE(ftprops.size(), (qulonglong)10000); QVERIFY(!ftprops.hasContentHash()); QCOMPARE(ftprops.contentHashType(), FileHashTypeNone); QVERIFY(ftprops.contentHash().isEmpty()); ftprops.setContentHash(FileHashTypeMD5, QLatin1String("ffffffffffffffff")); QVERIFY(ftprops.isValid()); QVERIFY(ftprops.hasContentHash()); QCOMPARE(ftprops.contentHashType(), FileHashTypeMD5); QCOMPARE(ftprops.contentHash(), QLatin1String("ffffffffffffffff")); QVERIFY(!ftprops.hasDescription()); QVERIFY(ftprops.description().isEmpty()); ftprops.setDescription(QLatin1String("description")); QVERIFY(ftprops.isValid()); QVERIFY(ftprops.hasDescription()); QCOMPARE(ftprops.description(), QLatin1String("description")); QVERIFY(!ftprops.hasLastModificationTime()); QVERIFY(!ftprops.lastModificationTime().isValid()); QDateTime now = QDateTime::currentDateTime(); ftprops.setLastModificationTime(now); QVERIFY(ftprops.hasLastModificationTime()); QCOMPARE(ftprops.lastModificationTime(), now); QVERIFY(!ftprops.hasUri()); QVERIFY(ftprops.uri().isEmpty()); ftprops.setUri(QLatin1String("file:///path/filename")); QVERIFY(ftprops.isValid()); QVERIFY(ftprops.hasUri()); QCOMPARE(ftprops.uri(), QLatin1String("file:///path/filename")); } void TestFileTransferCreationProperties::testFileTransferCreationPropertiesDefaultByPath() { // Test constructor by local file path with existing file QString filePath = QCoreApplication::applicationFilePath(); QFileInfo fileInfo(filePath); QUrl fileUri = QUrl::fromLocalFile(filePath); FileTransferChannelCreationProperties ftprops(filePath, QLatin1String("application/octet-stream")); QVERIFY(ftprops.isValid()); QCOMPARE(ftprops.suggestedFileName(), fileInfo.fileName()); QCOMPARE(ftprops.contentType(), QLatin1String("application/octet-stream")); QCOMPARE(ftprops.size(), (quint64)fileInfo.size()); QVERIFY(!ftprops.hasContentHash()); QCOMPARE(ftprops.contentHashType(), FileHashTypeNone); QVERIFY(ftprops.contentHash().isEmpty()); QVERIFY(!ftprops.hasDescription()); QVERIFY(ftprops.description().isEmpty()); QVERIFY(ftprops.hasLastModificationTime()); QCOMPARE(ftprops.lastModificationTime(), fileInfo.lastModified()); QVERIFY(ftprops.hasUri()); QCOMPARE(ftprops.uri(), fileUri.toString()); } void TestFileTransferCreationProperties::testFileTransferCreationPropertiesDefaultByPathFail() { // Test constructor by local file path with non-existing file FileTransferChannelCreationProperties ftprops(QLatin1String("/non-existent-path/non-existent-filename"), QLatin1String("application/octet-stream")); QVERIFY(!ftprops.isValid()); QVERIFY(ftprops.suggestedFileName().isEmpty()); QVERIFY(ftprops.contentType().isEmpty()); QCOMPARE(ftprops.size(), (qulonglong)0); QVERIFY(!ftprops.hasContentHash()); QCOMPARE(ftprops.contentHashType(), FileHashTypeNone); QVERIFY(ftprops.contentHash().isEmpty()); QVERIFY(!ftprops.hasDescription()); QVERIFY(ftprops.description().isEmpty()); QVERIFY(!ftprops.hasLastModificationTime()); QVERIFY(!ftprops.lastModificationTime().isValid()); QVERIFY(!ftprops.hasUri()); QVERIFY(ftprops.uri().isEmpty()); } QTEST_MAIN(TestFileTransferCreationProperties) #include "_gen/file-transfer-channel-creation-properties.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/test-key-file.ini0000664000175000017500000000011612470405660017273 0ustar jrjra=1 b=2 [test group 1] c=\s\t\n\r\\ d=true [test group 2] e = space telepathy-qt-0.9.6~git1/tests/dbus/0000775000175000017500000000000012470405660015047 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/dbus/conn-roster-legacy.cpp0000664000175000017500000004343512470405660021277 0ustar jrjr#include #include #include #include #include #include #include #include using namespace Tp; class TestConnRosterLegacy : public Test { Q_OBJECT public: TestConnRosterLegacy(QObject *parent = 0) : Test(parent), mConn(0), mBlockingContactsFinished(false), mHowManyKnownContacts(0), mGotPresenceStateChanged(false) { } protected Q_SLOTS: void expectBlockingContactsFinished(Tp::PendingOperation *op); void expectBlockStatusChanged(bool blocked); void expectBlockedContactsChanged(const Tp::Contacts &added, const Tp::Contacts &removed, const Tp::Channel::GroupMemberChangeDetails &details); void expectPresenceStateChanged(Tp::Contact::PresenceState); void expectAllKnownContactsChanged(const Tp::Contacts &added, const Tp::Contacts &removed, const Tp::Channel::GroupMemberChangeDetails &details); private Q_SLOTS: void initTestCase(); void init(); void testRoster(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; QSet mContactsExpectingBlockStatusChange; bool mBlockingContactsFinished; int mHowManyKnownContacts; bool mGotPresenceStateChanged; }; void TestConnRosterLegacy::expectBlockingContactsFinished(Tp::PendingOperation *op) { TEST_VERIFY_OP(op); qDebug() << "blocking contacts finished"; mBlockingContactsFinished = true; if (mContactsExpectingBlockStatusChange.isEmpty()) { mLoop->exit(0); } } void TestConnRosterLegacy::expectBlockStatusChanged(bool blocked) { Q_UNUSED(blocked); Contact *c = qobject_cast(sender()); QVERIFY(c); ContactPtr contact(c); mContactsExpectingBlockStatusChange.remove(contact->id()); if (mContactsExpectingBlockStatusChange.isEmpty() && mBlockingContactsFinished) { mLoop->exit(0); } } // This connects to allKnownContactsChanged() but it is only used in the last contact blocking test void TestConnRosterLegacy::expectBlockedContactsChanged(const Tp::Contacts &added, const Tp::Contacts &removed, const Tp::Channel::GroupMemberChangeDetails &details) { Q_UNUSED(details); Q_FOREACH(const ContactPtr &contact, added) { mContactsExpectingBlockStatusChange.remove(contact->id()); } Q_FOREACH(const ContactPtr &contact, removed) { mContactsExpectingBlockStatusChange.remove(contact->id()); } if (mContactsExpectingBlockStatusChange.isEmpty() && mBlockingContactsFinished) { mLoop->exit(0); } } void TestConnRosterLegacy::expectAllKnownContactsChanged(const Tp::Contacts& added, const Tp::Contacts& removed, const Tp::Channel::GroupMemberChangeDetails &details) { qDebug() << added.size() << " contacts added, " << removed.size() << " contacts removed"; mHowManyKnownContacts += added.size(); mHowManyKnownContacts -= removed.size(); if (details.hasMessage()) { QCOMPARE(details.message(), QLatin1String("add me now")); } if (mConn->client()->contactManager()->allKnownContacts().size() != mHowManyKnownContacts) { qWarning() << "Contacts number mismatch! Watched value: " << mHowManyKnownContacts << "allKnownContacts(): " << mConn->client()->contactManager()->allKnownContacts().size(); mLoop->exit(1); } else { mLoop->exit(0); } } void TestConnRosterLegacy::expectPresenceStateChanged(Contact::PresenceState state) { mGotPresenceStateChanged = true; } void TestConnRosterLegacy::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("conn-roster-legacy"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, "account", "me@example.com", "protocol", "contactlist", "simulation-delay", 1, NULL); QCOMPARE(mConn->connect(), true); } void TestConnRosterLegacy::init() { initImpl(); } void TestConnRosterLegacy::testRoster() { Features features = Features() << Connection::FeatureRoster; QCOMPARE(mConn->enableFeatures(features), true); ContactManagerPtr contactManager = mConn->client()->contactManager(); QCOMPARE(contactManager->state(), ContactListStateSuccess); QStringList toCheck = QStringList() << QLatin1String("sjoerd@example.com") << QLatin1String("travis@example.com") << QLatin1String("wim@example.com") << QLatin1String("olivier@example.com") << QLatin1String("helen@example.com") << QLatin1String("geraldine@example.com") << QLatin1String("guillaume@example.com") << QLatin1String("christian@example.com") << QLatin1String("bill@example.com") << QLatin1String("steve@example.com"); QStringList ids; QList pendingSubscription; QList pendingPublish; Q_FOREACH (const ContactPtr &contact, contactManager->allKnownContacts()) { qDebug() << " contact:" << contact->id() << "- subscription:" << contact->subscriptionState() << "- publish:" << contact->publishState(); ids << contact->id(); if (contact->subscriptionState() == Contact::PresenceStateAsk) { pendingSubscription.append(contact); } else if (contact->publishState() == Contact::PresenceStateAsk) { pendingPublish.append(contact); } } ids.sort(); toCheck.sort(); QCOMPARE(ids, toCheck); QCOMPARE(pendingSubscription.size(), 2); QCOMPARE(pendingPublish.size(), 2); // Wait for the contacts to be built ids = QStringList() << QString(QLatin1String("john@example.com")) << QString(QLatin1String("mary@example.com")); QList contacts = mConn->contacts(ids); QCOMPARE(contacts.size(), ids.size()); int i = 0; Q_FOREACH (const ContactPtr &contact, contacts) { mGotPresenceStateChanged = false; QVERIFY(connect(contact.data(), SIGNAL(subscriptionStateChanged(Tp::Contact::PresenceState)), SLOT(expectPresenceStateChanged(Tp::Contact::PresenceState)))); QVERIFY(connect(contact.data(), SIGNAL(publishStateChanged(Tp::Contact::PresenceState, QString)), SLOT(expectPresenceStateChanged(Tp::Contact::PresenceState)))); if ((i % 2) == 0) { contact->requestPresenceSubscription(QLatin1String("please add me")); } else { contact->requestPresenceSubscription(QLatin1String("add me now")); } while (!mGotPresenceStateChanged) { mLoop->processEvents(); } if ((i % 2) == 0) { // I asked to see his presence - he might have already accepted it, though QVERIFY(contact->subscriptionState() == Contact::PresenceStateAsk || contact->subscriptionState() == Contact::PresenceStateYes); // if he accepted it already, one iteration won't be enough as the // first iteration will just flush the subscription -> Yes event while (contact->publishState() != Contact::PresenceStateAsk) { mLoop->processEvents(); } contact->authorizePresencePublication(); while (contact->publishState() != Contact::PresenceStateYes) { mLoop->processEvents(); } // I authorized him to see my presence QCOMPARE(static_cast(contact->publishState()), static_cast(Contact::PresenceStateYes)); // He replied the presence request QCOMPARE(static_cast(contact->subscriptionState()), static_cast(Contact::PresenceStateYes)); contact->removePresenceSubscription(); while (contact->subscriptionState() != Contact::PresenceStateNo) { mLoop->processEvents(); } } else { // I asked to see her presence - she might have already rejected it, though QVERIFY(contact->subscriptionState() == Contact::PresenceStateAsk || contact->subscriptionState() == Contact::PresenceStateNo); // If she didn't already reject it, wait until she does while (contact->subscriptionState() != Contact::PresenceStateNo) { mLoop->processEvents(); } } ++i; // Disconnect the signals so the contacts doing something won't early-exit future mainloop // iterations (the simulation CM does things like - after a delay since we removed them, try // to re-add us - and such, which mess up the test if the simulated network event happens // before we've finished with the next contact) QVERIFY(contact->disconnect(this)); // TODO: The roster API, frankly speaking, seems rather error/race prone, as evidenced by // this test. Should we perhaps change its semantics? Then again, this test also simulates // the remote user accepting/rejecting the request with a quite unpredictable timer delay, // while real-world applications don't do any such assumptions about the timing of the // remote user actions, so most of the problems won't be applicable there. } i = 0; Contact::PresenceState expectedPresenceState; Q_FOREACH (const ContactPtr &contact, pendingPublish) { mGotPresenceStateChanged = false; QVERIFY(connect(contact.data(), SIGNAL(publishStateChanged(Tp::Contact::PresenceState, QString)), SLOT(expectPresenceStateChanged(Tp::Contact::PresenceState)))); if ((i++ % 2) == 0) { expectedPresenceState = Contact::PresenceStateYes; contact->authorizePresencePublication(); } else { expectedPresenceState = Contact::PresenceStateNo; contact->removePresencePublication(); } while (!mGotPresenceStateChanged) { mLoop->processEvents(); } QCOMPARE(static_cast(contact->publishState()), static_cast(expectedPresenceState)); } // Test allKnownContactsChanged. // In this test, everytime a subscription is requested or rejected, allKnownContacts changes // Cache the current value mHowManyKnownContacts = contactManager->allKnownContacts().size(); // Watch for contacts changed QVERIFY(connect(contactManager.data(), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)), SLOT(expectAllKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)))); // Wait for the contacts to be built ids = QStringList() << QString(QLatin1String("kctest1@example.com")) << QString(QLatin1String("kctest2@example.com")); contacts = mConn->contacts(ids); QCOMPARE(contacts.size(), ids.size()); Q_FOREACH (const ContactPtr &contact, contacts) { contact->requestPresenceSubscription(QLatin1String("add me now")); // allKnownContacts is supposed to change here. QCOMPARE(mLoop->exec(), 0); } QVERIFY(disconnect(contactManager.data(), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)), this, SLOT(expectAllKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)))); // verify that the CM supports contact blocking QVERIFY(contactManager->canBlockContacts()); // check if the initially blocked contacts are there ids.clear(); toCheck = QStringList() << QLatin1String("bill@example.com") << QLatin1String("steve@example.com"); Q_FOREACH (const ContactPtr &contact, contactManager->allKnownContacts()) { if (contact->isBlocked()) { qDebug() << "blocked contact:" << contact->id(); ids << contact->id(); } } ids.sort(); toCheck.sort(); QCOMPARE(ids, toCheck); // block all contacts QList contactsList = contactManager->allKnownContacts().toList(); QSet contactIdsList; Q_FOREACH (const ContactPtr &contact, contactsList) { QVERIFY(connect(contact.data(), SIGNAL(blockStatusChanged(bool)), SLOT(expectBlockStatusChanged(bool)))); contactIdsList.insert(contact->id()); } mBlockingContactsFinished = false; mContactsExpectingBlockStatusChange = contactIdsList; // those are already blocked; do not expect their status to change mContactsExpectingBlockStatusChange.remove(QLatin1String("bill@example.com")); mContactsExpectingBlockStatusChange.remove(QLatin1String("steve@example.com")); QVERIFY(connect(contactManager->blockContacts(contactsList), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectBlockingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // verify all contacts have been blocked Q_FOREACH (const ContactPtr &contact, contactsList) { QCOMPARE(contact->isBlocked(), true); QVERIFY(contactManager->allKnownContacts().contains(contact)); } // now remove kctest1 from the server ContactPtr kctest1; Q_FOREACH (const ContactPtr &contact, contactsList) { if (contact->id() == QLatin1String("kctest1@example.com")) { kctest1 = contact; } } QVERIFY(!kctest1.isNull()); QVERIFY(connect(contactManager->removeContacts(QList() << kctest1), SIGNAL(finished(Tp::PendingOperation*)), mLoop, SLOT(quit()))); QCOMPARE(mLoop->exec(), 0); // allKnownContacts must still contain kctest1, since it is in the deny list QVERIFY(contactManager->allKnownContacts().contains(kctest1)); kctest1.reset(); //no longer needed // unblock all contacts mBlockingContactsFinished = false; mContactsExpectingBlockStatusChange = contactIdsList; QVERIFY(connect(contactManager->unblockContacts(contactsList), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectBlockingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // verify all contacts have been unblocked Q_FOREACH (const ContactPtr &contact, contactsList) { QCOMPARE(contact->isBlocked(), false); // ...and that bill, steve and kctest1 have also been removed from allKnownContacts() // note: allKnownContacts() changes here because bill, steve and kctest, // which were only in the deny list, do not exist in any other list, so // they are removed as soon as they get unblocked. if (contact->id() == QLatin1String("bill@example.com") || contact->id() == QLatin1String("steve@example.com") || contact->id() == QLatin1String("kctest1@example.com")) { QVERIFY(!contactManager->allKnownContacts().contains(contact)); } else { QVERIFY(contactManager->allKnownContacts().contains(contact)); } } // block some contacts that are not already known ids = QStringList() << QLatin1String("blocktest1@example.com") << QLatin1String("blocktest2@example.com"); contacts = mConn->contacts(ids); // Watch changes in allKnownContacts() instead of watching the Contacts' block status // as we want to destroy the Contact objects and verify that they are being re-created correctly QVERIFY(connect(contactManager.data(), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)), SLOT(expectBlockedContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)))); mBlockingContactsFinished = false; mContactsExpectingBlockStatusChange = ids.toSet(); QVERIFY(connect(contactManager->blockContacts(contacts), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectBlockingContactsFinished(Tp::PendingOperation*)))); // destroy the Contact objects to let them be re-created when the block operation finishes contacts.clear(); QCOMPARE(mLoop->exec(), 0); // construct the same contacts again and verify that they are blocked contacts = mConn->contacts(ids); Q_FOREACH (const ContactPtr &contact, contacts) { QCOMPARE(contact->isBlocked(), true); QVERIFY(contactManager->allKnownContacts().contains(contact)); } // now unblock them again mBlockingContactsFinished = false; mContactsExpectingBlockStatusChange = ids.toSet(); QVERIFY(connect(contactManager->unblockContacts(contacts), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectBlockingContactsFinished(Tp::PendingOperation*)))); // note: allKnownContacts() is expected to change again, so we expect // to quit from expectBlockedContactsChanged() QCOMPARE(mLoop->exec(), 0); // and verify that they are not in allKnownContacts() Q_FOREACH (const ContactPtr &contact, contacts) { QCOMPARE(contact->isBlocked(), false); QVERIFY(!contactManager->allKnownContacts().contains(contact)); } } void TestConnRosterLegacy::cleanup() { cleanupImpl(); } void TestConnRosterLegacy::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestConnRosterLegacy) #include "_gen/conn-roster-legacy.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/streamed-media-chan.cpp0000664000175000017500000016343412470405660021356 0ustar jrjr#include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include using namespace Tp; class TestStreamedMediaChan : public Test { Q_OBJECT public: TestStreamedMediaChan(QObject *parent = 0) : Test(parent), mConn(0) { } protected Q_SLOTS: void expectRequestStreamsFinished(Tp::PendingOperation *); void expectBusyRequestStreamsFinished(Tp::PendingOperation *); // Special event handlers for the OutgoingCall state-machine void expectOutgoingRequestStreamsFinished(Tp::PendingOperation *); void onOutgoingGroupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &); void onGroupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &); void onStreamRemoved(const Tp::StreamedMediaStreamPtr &); void onStreamDirectionChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamDirection, Tp::MediaStreamPendingSend); void onLSSChanged(Tp::StreamedMediaStream::SendingState); void onRSSChanged(Tp::StreamedMediaStream::SendingState); void onStreamStateChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamState); void onChanInvalidated(Tp::DBusProxy *, const QString &, const QString &); // Special event handlers for the OutgoingCallTerminate state-machine void expectTerminateRequestStreamsFinished(Tp::PendingOperation *); void onTerminateGroupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &); void onTerminateChanInvalidated(Tp::DBusProxy *, const QString &, const QString &); void onNewChannels(const Tp::ChannelDetailsList &); void onLocalHoldStateChanged(Tp::LocalHoldState, Tp::LocalHoldStateReason); private Q_SLOTS: void initTestCase(); void init(); void testOutgoingCall(); void testOutgoingCallBusy(); void testOutgoingCallNoAnswer(); void testOutgoingCallTerminate(); void testIncomingCall(); void testHold(); void testHoldNoUnhold(); void testHoldInabilityUnhold(); void testDTMF(); void testDTMFNoContinuousTone(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; StreamedMediaChannelPtr mChan; QList mContacts; StreamedMediaStreams mRequestStreamsReturn; Contacts mChangedCurrent; Contacts mChangedLP; Contacts mChangedRP; Contacts mChangedRemoved; Channel::GroupMemberChangeDetails mDetails; StreamedMediaStreamPtr mStreamRemovedReturn; StreamedMediaStreamPtr mSDCStreamReturn; Tp::MediaStreamDirection mSDCDirectionReturn; Tp::MediaStreamPendingSend mSDCPendingReturn; StreamedMediaStreamPtr mSSCStreamReturn; Tp::StreamedMediaStream::SendingState mChangedLSS; Tp::StreamedMediaStream::SendingState mChangedRSS; Tp::MediaStreamState mSSCStateReturn; QQueue mLocalHoldStates; QQueue mLocalHoldStateReasons; // state machine for the OutgoingCall test-case enum { OutgoingStateInitial, OutgoingStateRequested, OutgoingStateRinging, OutgoingStateDone } mOutgoingState; bool mOutgoingGotRequestStreamsFinished; bool mOutgoingAudioDone; // state machine for the OutgoingCallTerminate test-case enum { TerminateStateInitial, TerminateStateRequested, TerminateStateRinging, TerminateStateAnswered, TerminateStateTerminated } mTerminateState; }; void TestStreamedMediaChan::expectRequestStreamsFinished(PendingOperation *op) { mRequestStreamsReturn.clear(); TEST_VERIFY_OP(op); qDebug() << "request streams finished successfully"; PendingStreamedMediaStreams *pms = qobject_cast(op); mRequestStreamsReturn = pms->streams(); mLoop->exit(0); } void TestStreamedMediaChan::expectBusyRequestStreamsFinished(PendingOperation *op) { if (!op->isFinished()) { qWarning() << "unfinished"; mLoop->exit(1); return; } if (op->isError()) { // The service signaled busy even before tp-qt finished introspection. // FIXME: should the error be something else, actually? Such as, perchance, // org.freedesktop.Telepathy.Error.Busy? (fd.o #29757). QCOMPARE(op->errorName(), QLatin1String("org.freedesktop.Telepathy.Error.Cancelled")); qDebug() << "request streams finished already busy"; mLoop->exit(0); return; } qDebug() << "request streams finished successfully"; PendingStreamedMediaStreams *pms = qobject_cast(op); mRequestStreamsReturn = pms->streams(); mLoop->exit(0); } void TestStreamedMediaChan::expectOutgoingRequestStreamsFinished(PendingOperation *op) { QVERIFY(op->isFinished()); QVERIFY(!op->isError()); QVERIFY(op->isValid()); PendingStreamedMediaStreams *pms = qobject_cast(op); mRequestStreamsReturn = pms->streams(); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); QCOMPARE(mContacts.size(), 1); StreamedMediaStreamPtr stream = mRequestStreamsReturn.first(); QCOMPARE(stream->contact(), otherContact); QCOMPARE(stream->type(), Tp::MediaStreamTypeAudio); // These checks can't work reliably, unless we add some complex backdoors to the test service, // to only start changing state / direction when we explicitly tell it so (not automatically // when we have requested the stream) // QCOMPARE(stream->state(), Tp::MediaStreamStateDisconnected); // QCOMPARE(stream->direction(), Tp::MediaStreamDirectionBidirectional); QCOMPARE(mChan->streams().size(), 1); QVERIFY(mChan->streams().contains(stream)); qDebug() << "stream requested successfully"; // Only advance to Requested if the remote moving to RP hasn't already advanced it to Ringing or // even Answered - tbf it seems the StreamedMediaChannel semantics are quite hard for // application code to get right because the events can happen in whichever order. Should this // be considered a bug by itself? It'd probably be pretty hard to fix so I hope not :D if (mOutgoingState == OutgoingStateInitial) { mOutgoingState = OutgoingStateRequested; } if (mOutgoingState == OutgoingStateDone) { // finished later than the membersChanged() - exit mainloop now mLoop->exit(0); } else { // finished earlier than membersChanged() - it will exit mOutgoingGotRequestStreamsFinished = true; } } void TestStreamedMediaChan::onOutgoingGroupMembersChanged( const Contacts &groupMembersAdded, const Contacts &groupLocalPendingMembersAdded, const Contacts &groupRemotePendingMembersAdded, const Contacts &groupMembersRemoved, const Channel::GroupMemberChangeDetails &details) { // At this point, mContacts should still contain the contact we requested the // stream for ContactPtr otherContact = mContacts.first(); if (mOutgoingState == OutgoingStateInitial || mOutgoingState == OutgoingStateRequested) { // The target should have become remote pending now QVERIFY(groupMembersAdded.isEmpty()); QVERIFY(groupLocalPendingMembersAdded.isEmpty()); QCOMPARE(groupRemotePendingMembersAdded.size(), 1); QVERIFY(groupMembersRemoved.isEmpty()); QVERIFY(mChan->groupRemotePendingContacts().contains(otherContact)); QCOMPARE(mChan->awaitingRemoteAnswer(), true); qDebug() << "call now ringing"; mOutgoingState = OutgoingStateRinging; } else if (mOutgoingState == OutgoingStateRinging) { QCOMPARE(groupMembersAdded.size(), 1); QVERIFY(groupLocalPendingMembersAdded.isEmpty()); QVERIFY(groupRemotePendingMembersAdded.isEmpty()); QVERIFY(groupMembersRemoved.isEmpty()); QCOMPARE(mChan->groupContacts().size(), 2); QVERIFY(mChan->groupContacts().contains(otherContact)); QCOMPARE(mChan->awaitingRemoteAnswer(), false); qDebug() << "call now answered"; mOutgoingState = OutgoingStateDone; mOutgoingAudioDone = true; // Exit if we already got finished() from requestStreams() - otherwise the finish callback // will exit if (mOutgoingGotRequestStreamsFinished) { mLoop->exit(0); } } qDebug() << "group members changed"; mChangedCurrent = groupMembersAdded; mChangedLP = groupLocalPendingMembersAdded; mChangedRP = groupRemotePendingMembersAdded; mChangedRemoved = groupMembersRemoved; mDetails = details; } void TestStreamedMediaChan::onGroupMembersChanged( const Contacts &groupMembersAdded, const Contacts &groupLocalPendingMembersAdded, const Contacts &groupRemotePendingMembersAdded, const Contacts &groupMembersRemoved, const Channel::GroupMemberChangeDetails &details) { qDebug() << "group members changed"; mChangedCurrent = groupMembersAdded; mChangedLP = groupLocalPendingMembersAdded; mChangedRP = groupRemotePendingMembersAdded; mChangedRemoved = groupMembersRemoved; mDetails = details; } void TestStreamedMediaChan::onStreamRemoved(const StreamedMediaStreamPtr &stream) { qDebug() << "stream" << stream.data() << "removed"; mStreamRemovedReturn = stream; mLoop->exit(0); } void TestStreamedMediaChan::onStreamDirectionChanged(const StreamedMediaStreamPtr &stream, Tp::MediaStreamDirection direction, Tp::MediaStreamPendingSend pendingSend) { qDebug() << "stream" << stream.data() << "direction changed to" << direction; mSDCStreamReturn = stream; mSDCDirectionReturn = direction; mSDCPendingReturn = pendingSend; mLoop->exit(0); } void TestStreamedMediaChan::onLSSChanged(Tp::StreamedMediaStream::SendingState state) { qDebug() << "onLSSChanged: " << static_cast(state); mChangedLSS = state; mLoop->exit(0); } void TestStreamedMediaChan::onRSSChanged(Tp::StreamedMediaStream::SendingState state) { qDebug() << "onRSSChanged: " << static_cast(state); mChangedRSS = state; mLoop->exit(0); } void TestStreamedMediaChan::onStreamStateChanged(const StreamedMediaStreamPtr &stream, Tp::MediaStreamState state) { qDebug() << "stream" << stream.data() << "state changed to" << state; mSSCStreamReturn = stream; mSSCStateReturn = state; mLoop->exit(0); } void TestStreamedMediaChan::onChanInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { qDebug() << "chan invalidated:" << errorName << "-" << errorMessage; mLoop->exit(0); } void TestStreamedMediaChan::expectTerminateRequestStreamsFinished(PendingOperation *op) { QVERIFY(op->isFinished()); if (op->isError()) { // FIXME: should the error be something else, actually? Such as, perchance, // org.freedesktop.Telepathy.Error.Terminated? (fd.o #29757). QCOMPARE(op->errorName(), QLatin1String("org.freedesktop.Telepathy.Error.Cancelled")); qDebug() << "The remote hung up before we even got to take a look at the stream!"; mTerminateState = TerminateStateTerminated; mLoop->exit(0); return; } QVERIFY(op->isValid()); PendingStreamedMediaStreams *pms = qobject_cast(op); mRequestStreamsReturn = pms->streams(); qDebug() << "stream requested successfully"; // Only advance to Requested if the remote moving to RP hasn't already advanced it to Ringing or // even Answered - tbf it seems the StreamedMediaChannel semantics are quite hard for // application code to get right because the events can happen in whichever order. Should this // be considered a bug by itself? It'd probably be pretty hard to fix so I hope not :D if (mTerminateState == TerminateStateInitial) { mTerminateState = TerminateStateRequested; } } void TestStreamedMediaChan::onTerminateGroupMembersChanged( const Contacts &groupMembersAdded, const Contacts &groupLocalPendingMembersAdded, const Contacts &groupRemotePendingMembersAdded, const Contacts &groupMembersRemoved, const Channel::GroupMemberChangeDetails &details) { // At this point, mContacts should still contain the contact we requested the // stream for ContactPtr otherContact = mContacts.first(); if (mTerminateState == TerminateStateInitial || mTerminateState == TerminateStateRequested) { // The target should have become remote pending now QVERIFY(groupMembersAdded.isEmpty()); QVERIFY(groupLocalPendingMembersAdded.isEmpty()); QCOMPARE(groupRemotePendingMembersAdded.size(), 1); QVERIFY(groupMembersRemoved.isEmpty()); QVERIFY(mChan->groupRemotePendingContacts().contains(otherContact)); QCOMPARE(mChan->awaitingRemoteAnswer(), true); qDebug() << "call now ringing"; mTerminateState = TerminateStateRinging; } else if (mTerminateState == TerminateStateRinging) { QCOMPARE(groupMembersAdded.size(), 1); QVERIFY(groupLocalPendingMembersAdded.isEmpty()); QVERIFY(groupRemotePendingMembersAdded.isEmpty()); QVERIFY(groupMembersRemoved.isEmpty()); QCOMPARE(mChan->groupContacts().size(), 2); QVERIFY(mChan->groupContacts().contains(otherContact)); QCOMPARE(mChan->awaitingRemoteAnswer(), false); qDebug() << "call now answered"; mTerminateState = TerminateStateAnswered; } else if (mTerminateState == TerminateStateAnswered) { // It might be actually that currently this won't happen before invalidated() is emitted, so // we'll never reach this due to having exited the mainloop already - but it's entirely // valid for the library to signal either the invalidation or removing the members first, so // let's verify the member change in case it does that first. qDebug() << "membersChanged() after the call was answered - the remote probably hung up"; QVERIFY(groupMembersAdded.isEmpty()); QVERIFY(groupLocalPendingMembersAdded.isEmpty()); QVERIFY(groupRemotePendingMembersAdded.isEmpty()); QVERIFY(groupMembersRemoved.contains(otherContact) || groupMembersRemoved.contains(mChan->groupSelfContact())); // can be either, or both // the invalidated handler will change state due to the fact that we might get 0-2 of these, // but always exactly one invalidated() } qDebug() << "group members changed"; mChangedCurrent = groupMembersAdded; mChangedLP = groupLocalPendingMembersAdded; mChangedRP = groupRemotePendingMembersAdded; mChangedRemoved = groupMembersRemoved; mDetails = details; } void TestStreamedMediaChan::onTerminateChanInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { qDebug() << "chan invalidated:" << errorName << "-" << errorMessage; mTerminateState = TerminateStateTerminated; mLoop->exit(0); } void TestStreamedMediaChan::onNewChannels(const Tp::ChannelDetailsList &channels) { qDebug() << "new channels"; Q_FOREACH (const Tp::ChannelDetails &details, channels) { QString channelType = details.properties.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString(); bool requested = details.properties.value(TP_QT_IFACE_CHANNEL + QLatin1String(".Requested")).toBool(); qDebug() << " channelType:" << channelType; qDebug() << " requested :" << requested; if (channelType == TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA && !requested) { mChan = StreamedMediaChannel::create(mConn->client(), details.channel.path(), details.properties); mLoop->exit(0); } } } void TestStreamedMediaChan::onLocalHoldStateChanged(Tp::LocalHoldState localHoldState, Tp::LocalHoldStateReason localHoldStateReason) { qDebug() << "local hold state changed:" << localHoldState << localHoldStateReason; mLocalHoldStates.append(localHoldState); mLocalHoldStateReasons.append(localHoldStateReason); mLoop->exit(0); } void TestStreamedMediaChan::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("streamed-media-chan"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, EXAMPLE_TYPE_CALLABLE_CONNECTION, "account", "me@example.com", "protocol", "example", "simulation-delay", 1, NULL); QCOMPARE(mConn->connect(Connection::FeatureSelfContact), true); } void TestStreamedMediaChan::init() { initImpl(); mContacts.clear(); mRequestStreamsReturn.clear(); mChangedCurrent.clear(); mChangedLP.clear(); mChangedRP.clear(); mChangedRemoved.clear(); mStreamRemovedReturn.reset(); mSDCStreamReturn.reset(); mSDCDirectionReturn = (Tp::MediaStreamDirection) -1; mSDCPendingReturn = (Tp::MediaStreamPendingSend) -1; mSSCStateReturn = (Tp::MediaStreamState) -1; mChangedLSS = (Tp::StreamedMediaStream::SendingState) -1; mChangedRSS = (Tp::StreamedMediaStream::SendingState) -1; mSSCStreamReturn.reset(); mLocalHoldStates.clear(); mLocalHoldStateReasons.clear(); } void TestStreamedMediaChan::testOutgoingCall() { mContacts = mConn->contacts(QStringList() << QLatin1String("alice")); QCOMPARE(mContacts.size(), 1); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); mChan = StreamedMediaChannelPtr::qObjectCast( mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, otherContact)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureStreams)); QCOMPARE(mChan->streams().size(), 0); QCOMPARE(mChan->groupContacts().size(), 1); QCOMPARE(mChan->groupLocalPendingContacts().size(), 0); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QCOMPARE(mChan->awaitingLocalAnswer(), false); QVERIFY(mChan->groupContacts().contains(mConn->client()->selfContact())); QVERIFY(connect(mChan.data(), SIGNAL(groupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), SLOT(onGroupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)))); // RequestStreams with bad type must fail QVERIFY(connect(mChan->requestStream(otherContact, (Tp::MediaStreamType) -1), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 2); QCOMPARE(mRequestStreamsReturn.size(), 0); // Request audio stream, and wait for: // - the request to finish // - the contact to appear on RP // - the contact to accept the call mOutgoingState = OutgoingStateInitial; mOutgoingAudioDone = false; mOutgoingGotRequestStreamsFinished = false; QVERIFY(connect(mChan.data(), SIGNAL(groupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), SLOT(onOutgoingGroupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)))); qDebug() << "requesting audio stream"; QVERIFY(connect(mChan->requestStreams(otherContact, QList() << Tp::MediaStreamTypeAudio), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectOutgoingRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(static_cast(mOutgoingState), static_cast(OutgoingStateDone)); QCOMPARE(mOutgoingAudioDone, true); qDebug() << "requesting video stream"; // Request video stream QVERIFY(connect(mChan->requestStream(otherContact, Tp::MediaStreamTypeVideo), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mRequestStreamsReturn.size(), 1); StreamedMediaStreamPtr stream = mRequestStreamsReturn.first(); QCOMPARE(stream->contact(), otherContact); QCOMPARE(stream->type(), Tp::MediaStreamTypeVideo); // These checks can't work reliably, unless we add some complex backdoors to the test service, // to only start changing state / direction when we explicitly tell it so (not automatically // when we have requested the stream) // QCOMPARE(stream->state(), Tp::MediaStreamStateDisconnected); // QCOMPARE(stream->direction(), Tp::MediaStreamDirectionBidirectional); QCOMPARE(mChan->streams().size(), 2); QVERIFY(mChan->streams().contains(stream)); QCOMPARE(mChan->streamsForType(Tp::MediaStreamTypeAudio).size(), 1); QCOMPARE(mChan->streamsForType(Tp::MediaStreamTypeVideo).size(), 1); // test stream removal stream = mChan->streamsForType(Tp::MediaStreamTypeAudio).first(); QVERIFY(stream); qDebug() << "removing audio stream"; QVERIFY(connect(mChan.data(), SIGNAL(streamRemoved(const Tp::StreamedMediaStreamPtr &)), SLOT(onStreamRemoved(const Tp::StreamedMediaStreamPtr &)))); QVERIFY(connect(mChan->removeStream(stream), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); if (mChan->streams().size() == 2) { qDebug() << "re-entering mainloop to wait for stream removal being signaled"; // wait stream removed signal QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mStreamRemovedReturn, stream); QCOMPARE(mChan->streams().size(), 1); QCOMPARE(mChan->streamsForType(Tp::MediaStreamTypeAudio).size(), 0); QCOMPARE(mChan->streamsForType(Tp::MediaStreamTypeVideo).size(), 1); // test stream direction/state changed stream = mChan->streamsForType(Tp::MediaStreamTypeVideo).first(); QVERIFY(stream); qDebug() << "changing stream direction, currently" << stream->direction(); qDebug() << "state currently" << stream->state(); if (stream->state() != Tp::MediaStreamStateConnected) { QVERIFY(connect(mChan.data(), SIGNAL(streamStateChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamState)), SLOT(onStreamStateChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamState)))); } else { // Pretend that we saw the SSC to Connected (although it might have happened even before the // stream request finished, in which case we have no change of catching it, because we don't // have the stream yet) mSSCStreamReturn = stream; mSSCStateReturn = Tp::MediaStreamStateConnected; } QCOMPARE(stream->localSendingRequested(), false); QCOMPARE(stream->remoteSendingRequested(), false); QCOMPARE(stream->sending(), true); QCOMPARE(stream->receiving(), true); /* request only receiving now */ QVERIFY(connect(mChan.data(), SIGNAL(streamDirectionChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamDirection, Tp::MediaStreamPendingSend)), SLOT(onStreamDirectionChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamDirection, Tp::MediaStreamPendingSend)))); QVERIFY(connect(stream.data(), SIGNAL(localSendingStateChanged(Tp::StreamedMediaStream::SendingState)), SLOT(onLSSChanged(Tp::StreamedMediaStream::SendingState)))); QVERIFY(connect(stream.data(), SIGNAL(remoteSendingStateChanged(Tp::StreamedMediaStream::SendingState)), SLOT(onRSSChanged(Tp::StreamedMediaStream::SendingState)))); QVERIFY(connect(stream->requestDirection(Tp::MediaStreamDirectionReceive), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (!mSDCStreamReturn || !mSSCStreamReturn || (static_cast(mChangedLSS) == -1)) { qDebug() << "re-entering mainloop to wait for stream direction change and state change"; // wait direction and state changed signal QCOMPARE(mLoop->exec(), 0); } // If this fails, we also got a remote state change signal, although we shouldn't have QCOMPARE(static_cast(mChangedRSS), -1); QCOMPARE(mSDCStreamReturn, stream); QVERIFY(mSDCDirectionReturn & Tp::MediaStreamDirectionReceive); QVERIFY(stream->direction() & Tp::MediaStreamDirectionReceive); QCOMPARE(stream->pendingSend(), mSDCPendingReturn); QCOMPARE(mSSCStreamReturn, stream); QCOMPARE(mSSCStateReturn, Tp::MediaStreamStateConnected); QCOMPARE(stream->sending(), false); QCOMPARE(stream->receiving(), true); } void TestStreamedMediaChan::testOutgoingCallBusy() { // This identifier contains the magic string (busy), which means the example // will simulate rejection of the call as busy rather than accepting it. mContacts = mConn->contacts(QStringList() << QLatin1String("alice (busy)")); QCOMPARE(mContacts.size(), 1); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); mChan = StreamedMediaChannelPtr::qObjectCast( mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, otherContact)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureStreams)); QCOMPARE(mChan->streams().size(), 0); QCOMPARE(mChan->groupContacts().size(), 1); QCOMPARE(mChan->groupLocalPendingContacts().size(), 0); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QCOMPARE(mChan->awaitingLocalAnswer(), false); QVERIFY(mChan->groupContacts().contains(mConn->client()->selfContact())); // Request audio stream QVERIFY(connect(mChan->requestStreams(otherContact, QList() << Tp::MediaStreamTypeAudio), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectBusyRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); if (mChan->isValid()) { qDebug() << "waiting for the channel to become invalidated"; QVERIFY(connect(mChan.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), SLOT(onChanInvalidated(Tp::DBusProxy *, const QString &, const QString &)))); QCOMPARE(mLoop->exec(), 0); } else { qDebug() << "not waiting for the channel to become invalidated, it has been invalidated" << "already"; } QCOMPARE(mChan->groupContacts().size(), 0); QCOMPARE(mChan->groupLocalPendingContacts().size(), 0); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QCOMPARE(mChan->streams().size(), 0); } void TestStreamedMediaChan::testOutgoingCallNoAnswer() { // This identifier contains the magic string (no answer), which means the example // will never answer. mContacts = mConn->contacts(QStringList() << QLatin1String("alice (no answer)")); QCOMPARE(mContacts.size(), 1); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); mChan = StreamedMediaChannelPtr::qObjectCast( mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, otherContact)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureStreams)); QCOMPARE(mChan->streams().size(), 0); QCOMPARE(mChan->groupContacts().size(), 1); QCOMPARE(mChan->groupLocalPendingContacts().size(), 0); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QCOMPARE(mChan->awaitingLocalAnswer(), false); QVERIFY(mChan->groupContacts().contains(mConn->client()->selfContact())); // Request audio stream QVERIFY(connect(mChan->requestStreams(otherContact, QList() << Tp::MediaStreamTypeAudio), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); /* After the initial flurry of D-Bus messages, alice still hasn't answered */ processDBusQueue(mConn->client().data()); QVERIFY(connect(mChan.data(), SIGNAL(groupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), SLOT(onGroupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)))); // wait the contact to appear on RP while (mChan->groupRemotePendingContacts().size() == 0) { mLoop->processEvents(); } QVERIFY(mChan->groupRemotePendingContacts().contains(otherContact)); QCOMPARE(mChan->awaitingRemoteAnswer(), true); QCOMPARE(mChan->groupRemotePendingContacts().size(), 1); /* assume we're never going to get an answer, and hang up */ mChan->requestClose(); QVERIFY(connect(mChan.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), SLOT(onChanInvalidated(Tp::DBusProxy *, const QString &, const QString &)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->groupContacts().size(), 0); QCOMPARE(mChan->groupLocalPendingContacts().size(), 0); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QCOMPARE(mChan->streams().size(), 0); } void TestStreamedMediaChan::testOutgoingCallTerminate() { // This identifier contains the magic string (terminate), which means the example // will simulate answering the call but then terminating it. mContacts = mConn->contacts(QStringList() << QLatin1String("alice (terminate)")); QCOMPARE(mContacts.size(), 1); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); mChan = StreamedMediaChannelPtr::qObjectCast( mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, otherContact)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureStreams)); QCOMPARE(mChan->streams().size(), 0); QCOMPARE(mChan->groupContacts().size(), 1); QCOMPARE(mChan->groupLocalPendingContacts().size(), 0); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QCOMPARE(mChan->awaitingLocalAnswer(), false); QVERIFY(mChan->groupContacts().contains(mConn->client()->selfContact())); // Request audio stream, and verify that following doing so, we get events for: // [0-2].5) the stream request finishing (sadly this can happen before, or between, any of the // following) - is this a bug? // 1) the remote appearing on the RP contacts -> should be awaitingRemoteAnswer() // 2) the remote answering the call -> should not be awaitingRemoteAnswer(), should have us and // them as the current members // 3) the channel being invalidated (due to the remote having terminated the call) -> exits the // mainloop // // Previously, this test used to spin the mainloop until each of the events had seemingly // happened, only checking for the events between the iterations. This is race-prone however, // as multiple events can happen in one mainloop iteration if the test executes slowly compared // with the simulated network events from the service (eg. in valgrind or under high system // load). mTerminateState = TerminateStateInitial; QVERIFY(connect(mChan.data(), SIGNAL(groupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), SLOT(onTerminateGroupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)))); QVERIFY(connect(mChan.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), SLOT(onTerminateChanInvalidated(Tp::DBusProxy *, const QString &, const QString &)))); qDebug() << "calling, hope somebody answers and doesn't immediately hang up!"; QVERIFY(connect(mChan->requestStreams(otherContact, QList() << Tp::MediaStreamTypeAudio), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectTerminateRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(static_cast(mTerminateState), static_cast(TerminateStateTerminated)); qDebug() << "oh crap, nobody wants to talk to me"; } void TestStreamedMediaChan::testIncomingCall() { mConn->client()->lowlevel()->setSelfPresence(QLatin1String("away"), QLatin1String("preparing for a test")); Client::ConnectionInterfaceRequestsInterface *connRequestsInterface = mConn->client()->optionalInterface(); QVERIFY(connect(connRequestsInterface, SIGNAL(NewChannels(const Tp::ChannelDetailsList&)), SLOT(onNewChannels(const Tp::ChannelDetailsList&)))); mConn->client()->lowlevel()->setSelfPresence(QLatin1String("available"), QLatin1String("call me?")); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan); QCOMPARE(mChan->streams().size(), 0); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureStreams)); QCOMPARE(mChan->streams().size(), 1); QCOMPARE(mChan->groupContacts().size(), 1); QCOMPARE(mChan->groupLocalPendingContacts().size(), 1); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QCOMPARE(mChan->awaitingLocalAnswer(), true); QCOMPARE(mChan->awaitingRemoteAnswer(), false); QVERIFY(mChan->groupLocalPendingContacts().contains(mConn->client()->selfContact())); ContactPtr otherContact = *mChan->groupContacts().begin(); QCOMPARE(otherContact, mChan->initiatorContact()); QVERIFY(connect(mChan->acceptCall(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->groupContacts().size(), 2); QCOMPARE(mChan->groupLocalPendingContacts().size(), 0); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QCOMPARE(mChan->awaitingLocalAnswer(), false); QVERIFY(mChan->groupContacts().contains(mConn->client()->selfContact())); QCOMPARE(mChan->streams().size(), 1); StreamedMediaStreamPtr stream = mChan->streams().first(); QCOMPARE(stream->channel(), mChan); QCOMPARE(stream->type(), Tp::MediaStreamTypeAudio); qDebug() << "requesting a stream with a bad type"; // RequestStreams with bad type must fail QVERIFY(connect(mChan->requestStream(otherContact, (Tp::MediaStreamType) -1), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 2); QCOMPARE(mRequestStreamsReturn.size(), 0); qDebug() << "requesting a video stream"; // Request video stream QVERIFY(connect(mChan->requestStream(otherContact, Tp::MediaStreamTypeVideo), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mRequestStreamsReturn.size(), 1); stream = mRequestStreamsReturn.first(); QCOMPARE(stream->contact(), otherContact); QCOMPARE(stream->type(), Tp::MediaStreamTypeVideo); // These checks can't work reliably, unless we add some complex backdoors to the test service, // to only start changing state / direction when we explicitly tell it so (not automatically // when we have requested the stream) // QCOMPARE(stream->state(), Tp::MediaStreamStateDisconnected); // QCOMPARE(stream->direction(), Tp::MediaStreamDirectionBidirectional); QCOMPARE(mChan->streams().size(), 2); QVERIFY(mChan->streams().contains(stream)); QCOMPARE(mChan->streamsForType(Tp::MediaStreamTypeAudio).size(), 1); QCOMPARE(mChan->streamsForType(Tp::MediaStreamTypeVideo).size(), 1); // test stream removal stream = mChan->streamsForType(Tp::MediaStreamTypeAudio).first(); QVERIFY(stream); qDebug() << "removing the audio stream"; QVERIFY(connect(mChan.data(), SIGNAL(streamRemoved(const Tp::StreamedMediaStreamPtr &)), SLOT(onStreamRemoved(const Tp::StreamedMediaStreamPtr &)))); QVERIFY(connect(mChan->removeStreams(StreamedMediaStreams() << stream), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); if (mChan->streams().size() == 2) { // wait stream removed signal QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mStreamRemovedReturn, stream); QCOMPARE(mChan->streams().size(), 1); QCOMPARE(mChan->streamsForType(Tp::MediaStreamTypeAudio).size(), 0); QCOMPARE(mChan->streamsForType(Tp::MediaStreamTypeVideo).size(), 1); // test stream direction/state changed stream = mChan->streamsForType(Tp::MediaStreamTypeVideo).first(); QVERIFY(stream); qDebug() << "requesting direction (false, true) - currently" << stream->direction(); qDebug() << "current stream state" << stream->state(); if (stream->state() != Tp::MediaStreamStateConnected) { QVERIFY(connect(mChan.data(), SIGNAL(streamStateChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamState)), SLOT(onStreamStateChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamState)))); } else { // Pretend that we saw the SSC to Connected (although it might have happened even before the // stream request finished, in which case we have no change of catching it, because we don't // have the stream yet) mSSCStreamReturn = stream; mSSCStateReturn = Tp::MediaStreamStateConnected; } QVERIFY(connect(mChan.data(), SIGNAL(streamDirectionChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamDirection, Tp::MediaStreamPendingSend)), SLOT(onStreamDirectionChanged(const Tp::StreamedMediaStreamPtr &, Tp::MediaStreamDirection, Tp::MediaStreamPendingSend)))); QVERIFY(connect(stream.data(), SIGNAL(localSendingStateChanged(Tp::StreamedMediaStream::SendingState)), SLOT(onLSSChanged(Tp::StreamedMediaStream::SendingState)))); QVERIFY(connect(stream.data(), SIGNAL(remoteSendingStateChanged(Tp::StreamedMediaStream::SendingState)), SLOT(onRSSChanged(Tp::StreamedMediaStream::SendingState)))); QVERIFY(connect(stream->requestDirection(false, true), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (!mSDCStreamReturn || !mSSCStreamReturn || (static_cast(mChangedLSS) == -1)) { // wait direction and state changed signal qDebug() << "re-entering mainloop to wait for stream direction change and state change"; QCOMPARE(mLoop->exec(), 0); } // If this fails, we also got a remote state change signal, although we shouldn't have QCOMPARE(static_cast(mChangedRSS), -1); QCOMPARE(mSDCStreamReturn, stream); QVERIFY(mSDCDirectionReturn & Tp::MediaStreamDirectionReceive); QVERIFY(stream->direction() & Tp::MediaStreamDirectionReceive); QCOMPARE(stream->pendingSend(), mSDCPendingReturn); QCOMPARE(mSSCStreamReturn, stream); QCOMPARE(mSSCStateReturn, Tp::MediaStreamStateConnected); } void TestStreamedMediaChan::testHold() { mContacts = mConn->contacts(QStringList() << QLatin1String("bob")); QCOMPARE(mContacts.size(), 1); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); mChan = StreamedMediaChannelPtr::qObjectCast( mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, otherContact)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureLocalHoldState), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureLocalHoldState)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(LocalHoldStateUnheld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(LocalHoldStateReasonNone)); QVERIFY(connect(mChan.data(), SIGNAL(localHoldStateChanged(Tp::LocalHoldState, Tp::LocalHoldStateReason)), SLOT(onLocalHoldStateChanged(Tp::LocalHoldState, Tp::LocalHoldStateReason)))); // Request hold QVERIFY(connect(mChan->requestHold(true), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mLocalHoldStates.size() != 2) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mLocalHoldStates.first(), static_cast(LocalHoldStatePendingHold)); QCOMPARE(mLocalHoldStateReasons.first(), static_cast(LocalHoldStateReasonRequested)); QCOMPARE(mLocalHoldStates.last(), static_cast(LocalHoldStateHeld)); QCOMPARE(mLocalHoldStateReasons.last(), static_cast(LocalHoldStateReasonRequested)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(LocalHoldStateHeld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(LocalHoldStateReasonRequested)); mLocalHoldStates.clear(); mLocalHoldStateReasons.clear(); // Request unhold QVERIFY(connect(mChan->requestHold(false), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mLocalHoldStates.size() != 2) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mLocalHoldStates.first(), static_cast(LocalHoldStatePendingUnhold)); QCOMPARE(mLocalHoldStateReasons.first(), static_cast(LocalHoldStateReasonRequested)); QCOMPARE(mLocalHoldStates.last(), static_cast(LocalHoldStateUnheld)); QCOMPARE(mLocalHoldStateReasons.last(), static_cast(LocalHoldStateReasonRequested)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(LocalHoldStateUnheld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(LocalHoldStateReasonRequested)); } void TestStreamedMediaChan::testHoldNoUnhold() { mContacts = mConn->contacts(QStringList() << QLatin1String("bob (no unhold)")); QCOMPARE(mContacts.size(), 1); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); mChan = StreamedMediaChannelPtr::qObjectCast( mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, otherContact)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureLocalHoldState), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureLocalHoldState)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(LocalHoldStateUnheld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(LocalHoldStateReasonNone)); QVERIFY(connect(mChan.data(), SIGNAL(localHoldStateChanged(Tp::LocalHoldState, Tp::LocalHoldStateReason)), SLOT(onLocalHoldStateChanged(Tp::LocalHoldState, Tp::LocalHoldStateReason)))); // Request hold QPointer holdOp = mChan->requestHold(true); while (mLocalHoldStates.size() != 2 || (holdOp && !holdOp.data()->isFinished())) { mLoop->processEvents(); } QCOMPARE(!holdOp || holdOp.data()->isValid(), true); QCOMPARE(mLocalHoldStates.first(), static_cast(LocalHoldStatePendingHold)); QCOMPARE(mLocalHoldStateReasons.first(), static_cast(LocalHoldStateReasonRequested)); QCOMPARE(mLocalHoldStates.last(), static_cast(LocalHoldStateHeld)); QCOMPARE(mLocalHoldStateReasons.last(), static_cast(LocalHoldStateReasonRequested)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(LocalHoldStateHeld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(LocalHoldStateReasonRequested)); mLocalHoldStates.clear(); mLocalHoldStateReasons.clear(); qDebug() << "requesting failing unhold"; // Request unhold (fail) QVERIFY(connect(mChan->requestHold(false), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 1); QCOMPARE(mLocalHoldStates.size(), 0); QCOMPARE(mLocalHoldStateReasons.size(), 0); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(LocalHoldStateHeld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(LocalHoldStateReasonRequested)); } void TestStreamedMediaChan::testHoldInabilityUnhold() { mContacts = mConn->contacts( QStringList() << QLatin1String("bob (inability to unhold)")); QCOMPARE(mContacts.size(), 1); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); mChan = StreamedMediaChannelPtr::qObjectCast( mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, otherContact)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureLocalHoldState), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureLocalHoldState)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(LocalHoldStateUnheld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(LocalHoldStateReasonNone)); QVERIFY(connect(mChan.data(), SIGNAL(localHoldStateChanged(Tp::LocalHoldState, Tp::LocalHoldStateReason)), SLOT(onLocalHoldStateChanged(Tp::LocalHoldState, Tp::LocalHoldStateReason)))); // Request hold QVERIFY(connect(mChan->requestHold(true), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mLocalHoldStates.size() != 2) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mLocalHoldStates.first(), static_cast(LocalHoldStatePendingHold)); QCOMPARE(mLocalHoldStateReasons.first(), static_cast(LocalHoldStateReasonRequested)); QCOMPARE(mLocalHoldStates.last(), static_cast(LocalHoldStateHeld)); QCOMPARE(mLocalHoldStateReasons.last(), static_cast(LocalHoldStateReasonRequested)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(LocalHoldStateHeld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(LocalHoldStateReasonRequested)); mLocalHoldStates.clear(); mLocalHoldStateReasons.clear(); // Request unhold (fail - back to hold) QVERIFY(connect(mChan->requestHold(false), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mLocalHoldStates.size() != 3) { QCOMPARE(mLoop->exec(), 0); } LocalHoldState state = static_cast(mLocalHoldStates.dequeue()); LocalHoldStateReason stateReason = static_cast(mLocalHoldStateReasons.dequeue()); QCOMPARE(state, LocalHoldStatePendingUnhold); QCOMPARE(stateReason, LocalHoldStateReasonRequested); state = static_cast(mLocalHoldStates.dequeue()); stateReason = static_cast(mLocalHoldStateReasons.dequeue()); QCOMPARE(state, LocalHoldStatePendingHold); QCOMPARE(stateReason, LocalHoldStateReasonRequested); state = static_cast(mLocalHoldStates.dequeue()); stateReason = static_cast(mLocalHoldStateReasons.dequeue()); QCOMPARE(state, LocalHoldStateHeld); QCOMPARE(stateReason, LocalHoldStateReasonRequested); QCOMPARE(mChan->localHoldState(), LocalHoldStateHeld); QCOMPARE(mChan->localHoldStateReason(), LocalHoldStateReasonRequested); } void TestStreamedMediaChan::testDTMF() { mContacts = mConn->contacts(QStringList() << QLatin1String("john")); QCOMPARE(mContacts.size(), 1); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); mChan = StreamedMediaChannelPtr::qObjectCast( mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, otherContact)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureStreams)); // Request audio stream QVERIFY(connect(mChan->requestStreams(otherContact, QList() << Tp::MediaStreamTypeAudio), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mRequestStreamsReturn.size(), 1); StreamedMediaStreamPtr stream = mRequestStreamsReturn.first(); QCOMPARE(stream->contact(), otherContact); QCOMPARE(stream->type(), Tp::MediaStreamTypeAudio); QCOMPARE(mChan->streams().size(), 1); QVERIFY(mChan->streams().contains(stream)); // start dtmf QVERIFY(connect(stream->startDTMFTone(DTMFEventDigit0), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // stop dtmf QVERIFY(connect(stream->stopDTMFTone(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // stop dtmf again (should succeed) QVERIFY(connect(stream->stopDTMFTone(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Request video stream QVERIFY(connect(mChan->requestStream(otherContact, Tp::MediaStreamTypeVideo), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mRequestStreamsReturn.size(), 1); stream = mRequestStreamsReturn.first(); QCOMPARE(stream->contact(), otherContact); QCOMPARE(stream->type(), Tp::MediaStreamTypeVideo); QCOMPARE(mChan->streams().size(), 2); QVERIFY(mChan->streams().contains(stream)); // start dtmf (must fail) QVERIFY(connect(stream->startDTMFTone(DTMFEventDigit0), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 1); // stop dtmf (must fail) QVERIFY(connect(stream->stopDTMFTone(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 1); } void TestStreamedMediaChan::testDTMFNoContinuousTone() { mContacts = mConn->contacts( QStringList() << QLatin1String("john (no continuous tone)")); QCOMPARE(mContacts.size(), 1); ContactPtr otherContact = mContacts.first(); QVERIFY(otherContact); mChan = StreamedMediaChannelPtr::qObjectCast( mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, otherContact)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(StreamedMediaChannel::FeatureStreams)); // Request audio stream QVERIFY(connect(mChan->requestStreams(otherContact, QList() << Tp::MediaStreamTypeAudio), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestStreamsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mRequestStreamsReturn.size(), 1); StreamedMediaStreamPtr stream = mRequestStreamsReturn.first(); QCOMPARE(stream->contact(), otherContact); QCOMPARE(stream->type(), Tp::MediaStreamTypeAudio); QCOMPARE(mChan->streams().size(), 1); QVERIFY(mChan->streams().contains(stream)); // start dtmf QVERIFY(connect(stream->startDTMFTone(DTMFEventDigit0), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // stop dtmf (must fail) QVERIFY(connect(stream->stopDTMFTone(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 1); } void TestStreamedMediaChan::cleanup() { mChan.reset(); mContacts.clear(); mRequestStreamsReturn.clear(); mStreamRemovedReturn.reset(); mChangedCurrent.clear(); mChangedLP.clear(); mChangedRP.clear(); mChangedRemoved.clear(); mDetails = Channel::GroupMemberChangeDetails(); mSDCStreamReturn.reset(); mSSCStreamReturn.reset(); cleanupImpl(); } void TestStreamedMediaChan::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestStreamedMediaChan) #include "_gen/streamed-media-chan.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/contacts-info.cpp0000664000175000017500000001741612470405660020333 0ustar jrjr#include #include #include #include #include #include #include #include #include using namespace Tp; class TestContactsInfo : public Test { Q_OBJECT public: TestContactsInfo(QObject *parent = 0) : Test(parent), mConn(0), mContactsInfoFieldsUpdated(0), mRefreshInfoFinished(0) { } protected Q_SLOTS: void onContactInfoFieldsChanged(const Tp::Contact::InfoFields &); void onRefreshInfoFinished(Tp::PendingOperation *); private Q_SLOTS: void initTestCase(); void init(); void testInfo(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; int mContactsInfoFieldsUpdated; int mRefreshInfoFinished; }; void TestContactsInfo::onContactInfoFieldsChanged(const Tp::Contact::InfoFields &info) { Q_UNUSED(info); mContactsInfoFieldsUpdated++; } void TestContactsInfo::onRefreshInfoFinished(PendingOperation *op) { if (op->isError()) { mLoop->exit(1); return; } mRefreshInfoFinished++; mLoop->exit(0); } void TestContactsInfo::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("contacts-info"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "foo", NULL); QCOMPARE(mConn->connect(), true); } void TestContactsInfo::init() { initImpl(); mContactsInfoFieldsUpdated = 0; mRefreshInfoFinished = 0; } void TestContactsInfo::testInfo() { ContactManagerPtr contactManager = mConn->client()->contactManager(); QVERIFY(contactManager->supportedFeatures().contains(Contact::FeatureInfo)); QStringList validIDs = QStringList() << QLatin1String("foo") << QLatin1String("bar"); QList contacts = mConn->contacts(validIDs, Contact::FeatureInfo); QCOMPARE(contacts.size(), validIDs.size()); for (int i = 0; i < contacts.size(); i++) { ContactPtr contact = contacts[i]; QCOMPARE(contact->requestedFeatures().contains(Contact::FeatureInfo), true); QCOMPARE(contact->actualFeatures().contains(Contact::FeatureInfo), true); QVERIFY(contact->infoFields().allFields().isEmpty()); QVERIFY(connect(contact.data(), SIGNAL(infoFieldsChanged(const Tp::Contact::InfoFields &)), SLOT(onContactInfoFieldsChanged(const Tp::Contact::InfoFields &)))); } GPtrArray *info_default = (GPtrArray *) dbus_g_type_specialized_construct ( TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST); { const gchar * const field_values[2] = { "FooBar", NULL }; g_ptr_array_add (info_default, tp_value_array_build (3, G_TYPE_STRING, "n", G_TYPE_STRV, NULL, G_TYPE_STRV, field_values, G_TYPE_INVALID)); } tp_tests_contacts_connection_set_default_contact_info(TP_TESTS_CONTACTS_CONNECTION(mConn->service()), info_default); GPtrArray *info_1 = (GPtrArray *) dbus_g_type_specialized_construct ( TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST); { const gchar * const field_values[2] = { "Foo", NULL }; g_ptr_array_add (info_1, tp_value_array_build (3, G_TYPE_STRING, "n", G_TYPE_STRV, NULL, G_TYPE_STRV, field_values, G_TYPE_INVALID)); } GPtrArray *info_2 = (GPtrArray *) dbus_g_type_specialized_construct ( TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST); { const gchar * const field_values[2] = { "Bar", NULL }; g_ptr_array_add (info_2, tp_value_array_build (3, G_TYPE_STRING, "n", G_TYPE_STRV, NULL, G_TYPE_STRV, field_values, G_TYPE_INVALID)); } TpHandle handles[] = { 0, 0 }; TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); for (unsigned i = 0; i < 2; i++) { handles[i] = tp_handle_ensure(serviceRepo, qPrintable(validIDs[i]), NULL, NULL); } tp_tests_contacts_connection_change_contact_info(TP_TESTS_CONTACTS_CONNECTION(mConn->service()), handles[0], info_1); tp_tests_contacts_connection_change_contact_info(TP_TESTS_CONTACTS_CONNECTION(mConn->service()), handles[1], info_2); while (mContactsInfoFieldsUpdated != 2) { mLoop->processEvents(); } QCOMPARE(mContactsInfoFieldsUpdated, 2); mContactsInfoFieldsUpdated = 0; ContactPtr contactFoo = contacts[0]; ContactPtr contactBar = contacts[1]; QCOMPARE(contactFoo->infoFields().isValid(), true); QCOMPARE(contactFoo->infoFields().allFields().size(), 1); QCOMPARE(contactFoo->infoFields().allFields()[0].fieldName, QLatin1String("n")); QCOMPARE(contactFoo->infoFields().allFields()[0].fieldValue[0], QLatin1String("Foo")); QCOMPARE(contactBar->infoFields().isValid(), true); QCOMPARE(contactBar->infoFields().allFields().size(), 1); QCOMPARE(contactBar->infoFields().allFields()[0].fieldName, QLatin1String("n")); QCOMPARE(contactBar->infoFields().allFields()[0].fieldValue[0], QLatin1String("Bar")); TpTestsContactsConnection *serviceConn = TP_TESTS_CONTACTS_CONNECTION(mConn->service()); QCOMPARE(serviceConn->refresh_contact_info_called, static_cast(0)); mContactsInfoFieldsUpdated = 0; mRefreshInfoFinished = 0; Q_FOREACH (const ContactPtr &contact, contacts) { QVERIFY(connect(contact->refreshInfo(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onRefreshInfoFinished(Tp::PendingOperation*)))); } while (mRefreshInfoFinished != contacts.size()) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mRefreshInfoFinished, contacts.size()); while (mContactsInfoFieldsUpdated != contacts.size()) { mLoop->processEvents(); } QCOMPARE(mContactsInfoFieldsUpdated, contacts.size()); QCOMPARE(serviceConn->refresh_contact_info_called, static_cast(1)); for (int i = 0; i < contacts.size(); i++) { ContactPtr contact = contacts[i]; QVERIFY(disconnect(contact.data(), SIGNAL(infoFieldsChanged(const Tp::Contact::InfoFields &)), this, SLOT(onContactInfoFieldsChanged(const Tp::Contact::InfoFields &)))); } PendingContactInfo *pci = contactFoo->requestInfo(); QVERIFY(connect(pci, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); while (!pci->isFinished()) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(pci->infoFields().isValid(), true); QCOMPARE(pci->infoFields().allFields().size(), 1); QCOMPARE(pci->infoFields().allFields()[0].fieldName, QLatin1String("n")); QCOMPARE(pci->infoFields().allFields()[0].fieldValue[0], QLatin1String("FooBar")); g_boxed_free(TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST, info_default); g_boxed_free(TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST, info_1); g_boxed_free(TP_ARRAY_TYPE_CONTACT_INFO_FIELD_LIST, info_2); } void TestContactsInfo::cleanup() { cleanupImpl(); } void TestContactsInfo::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestContactsInfo) #include "_gen/contacts-info.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/base-cm.cpp0000664000175000017500000001205712470405660017067 0ustar jrjr#include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include using namespace Tp; class TestBaseCM : public Test { Q_OBJECT public: TestBaseCM(QObject *parent = 0) : Test(parent) { } private Q_SLOTS: void initTestCase(); void init(); void testNoProtocols(); void testProtocols(); void cleanup(); void cleanupTestCase(); private: static void testNoProtocolsCreateCM(BaseConnectionManagerPtr &cm); static void testProtocolsCreateCM(BaseConnectionManagerPtr &cm); }; void TestBaseCM::initTestCase() { initTestCaseImpl(); } void TestBaseCM::init() { initImpl(); } void TestBaseCM::testNoProtocolsCreateCM(BaseConnectionManagerPtr &cm) { cm = BaseConnectionManager::create(QLatin1String("testcm")); Tp::DBusError err; QVERIFY(cm->registerObject(&err)); QVERIFY(!err.isValid()); QCOMPARE(cm->protocols().size(), 0); } void TestBaseCM::testNoProtocols() { qDebug() << "Introspecting non-existing CM"; ConnectionManagerPtr cliCM = ConnectionManager::create( QLatin1String("testcm")); PendingReady *pr = cliCM->becomeReady(ConnectionManager::FeatureCore); connect(pr, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); qDebug() << "Creating CM"; TestThreadHelper helper; TEST_THREAD_HELPER_EXECUTE(&helper, &testNoProtocolsCreateCM); qDebug() << "Introspecting new CM"; cliCM = ConnectionManager::create(QLatin1String("testcm")); pr = cliCM->becomeReady(ConnectionManager::FeatureCore); connect(pr, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cliCM->supportedProtocols().size(), 0); qDebug() << "Requesting connection"; PendingConnection *pc = cliCM->lowlevel()->requestConnection( QLatin1String("jabber"), QVariantMap()); connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED); } void TestBaseCM::testProtocolsCreateCM(BaseConnectionManagerPtr &cm) { cm = BaseConnectionManager::create(QLatin1String("testcm")); BaseProtocolPtr protocol = BaseProtocol::create(QLatin1String("myprotocol")); QVERIFY(!protocol.isNull()); QVERIFY(cm->addProtocol(protocol)); QVERIFY(cm->hasProtocol(QLatin1String("myprotocol"))); QCOMPARE(cm->protocol(QLatin1String("myprotocol")), protocol); QCOMPARE(cm->protocols().size(), 1); QVERIFY(!cm->hasProtocol(QLatin1String("otherprotocol"))); QVERIFY(cm->protocol(QLatin1String("otherprotocol")).isNull()); //can't add the same protocol twice QVERIFY(!cm->addProtocol(protocol)); Tp::DBusError err; QVERIFY(cm->registerObject(&err)); QVERIFY(!err.isValid()); //can't add another protocol after registerObject() protocol = BaseProtocol::create(QLatin1String("otherprotocol")); QVERIFY(!protocol.isNull()); QVERIFY(!cm->addProtocol(protocol)); QCOMPARE(cm->protocols().size(), 1); protocol.reset(); QVariantMap props = cm->immutableProperties(); QVERIFY(props.contains(TP_QT_IFACE_CONNECTION_MANAGER + QLatin1String(".Protocols"))); ProtocolPropertiesMap protocols = qvariant_cast( props[TP_QT_IFACE_CONNECTION_MANAGER + QLatin1String(".Protocols")]); QVERIFY(protocols.contains(QLatin1String("myprotocol"))); QVERIFY(!protocols.contains(QLatin1String("otherprotocol"))); } void TestBaseCM::testProtocols() { qDebug() << "Creating CM"; TestThreadHelper helper; TEST_THREAD_HELPER_EXECUTE(&helper, &testProtocolsCreateCM); qDebug() << "Introspecting CM"; ConnectionManagerPtr cliCM = ConnectionManager::create( QLatin1String("testcm")); PendingReady *pr = cliCM->becomeReady(ConnectionManager::FeatureCore); connect(pr, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cliCM->supportedProtocols().size(), 1); QVERIFY(cliCM->hasProtocol(QLatin1String("myprotocol"))); PendingConnection *pc = cliCM->lowlevel()->requestConnection( QLatin1String("myprotocol"), QVariantMap()); connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED); } void TestBaseCM::cleanup() { cleanupImpl(); } void TestBaseCM::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestBaseCM) #include "_gen/base-cm.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/contacts-location.cpp0000664000175000017500000000764312470405660021211 0ustar jrjr#include #include #include #include #include #include #include #include #include using namespace Tp; class TestContactsLocation : public Test { Q_OBJECT public: TestContactsLocation(QObject *parent = 0) : Test(parent), mConn(0), mContactsLocationUpdated(0) { } protected Q_SLOTS: void onLocationInfoUpdated(const Tp::LocationInfo &location); private Q_SLOTS: void initTestCase(); void init(); void testLocation(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; int mContactsLocationUpdated; }; void TestContactsLocation::onLocationInfoUpdated(const Tp::LocationInfo &location) { Q_UNUSED(location); mContactsLocationUpdated++; mLoop->exit(0); } void TestContactsLocation::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("contacts-location"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "foo", NULL); QCOMPARE(mConn->connect(), true); } void TestContactsLocation::init() { initImpl(); mContactsLocationUpdated = 0; } void TestContactsLocation::testLocation() { ContactManagerPtr contactManager = mConn->client()->contactManager(); QVERIFY(contactManager->supportedFeatures().contains(Contact::FeatureLocation)); QStringList validIDs = QStringList() << QLatin1String("foo") << QLatin1String("bar"); QList contacts = mConn->contacts(validIDs, Contact::FeatureLocation); QCOMPARE(contacts.size(), validIDs.size()); for (int i = 0; i < contacts.size(); i++) { ContactPtr contact = contacts[i]; QCOMPARE(contact->requestedFeatures().contains(Contact::FeatureLocation), true); QCOMPARE(contact->actualFeatures().contains(Contact::FeatureLocation), true); QVERIFY(connect(contact.data(), SIGNAL(locationUpdated(const Tp::LocationInfo &)), SLOT(onLocationInfoUpdated(const Tp::LocationInfo &)))); } GHashTable *location_1 = tp_asv_new( "country", G_TYPE_STRING, "United-kingdoms", "lat", G_TYPE_DOUBLE, 20.0, NULL); GHashTable *location_2 = tp_asv_new( "country", G_TYPE_STRING, "Atlantis", "lat", G_TYPE_DOUBLE, 10.0, NULL); GHashTable *locations[] = { location_1, location_2 }; TpHandle handles[] = { 0, 0 }; TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); for (unsigned i = 0; i < 2; i++) { handles[i] = tp_handle_ensure(serviceRepo, qPrintable(validIDs[i]), NULL, NULL); } tp_tests_contacts_connection_change_locations(TP_TESTS_CONTACTS_CONNECTION(mConn->service()), 2, handles, locations); while (mContactsLocationUpdated != 2) { QCOMPARE(mLoop->exec(), 0); } for (int i = 0; i < contacts.size(); i++) { ContactPtr contact = contacts[i]; QCOMPARE(contact->location().country(), QLatin1String(tp_asv_get_string(locations[i], "country"))); QCOMPARE(contact->location().latitude(), tp_asv_get_double(locations[i], "lat", NULL)); } g_hash_table_unref(location_1); g_hash_table_unref(location_2); } void TestContactsLocation::cleanup() { cleanupImpl(); } void TestContactsLocation::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestContactsLocation) #include "_gen/contacts-location.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/contacts-client-types.cpp0000664000175000017500000001371612470405660022017 0ustar jrjr#include #include #include #include #include #include #include #include #include using namespace Tp; class TestContactsClientTypes : public Test { Q_OBJECT public: TestContactsClientTypes(QObject *parent = 0) : Test(parent), mConn(0), mClientTypesUpdated(0) { } protected Q_SLOTS: void onClientTypesChanged(const QStringList &clientTypes); void onRequestClientTypesFinished(Tp::PendingOperation *op); private Q_SLOTS: void initTestCase(); void init(); void testClientTypes(); void testClientTypesAttributes(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; int mClientTypesUpdated; QStringList mClientTypes; }; void TestContactsClientTypes::onClientTypesChanged(const QStringList &clientTypes) { mClientTypesUpdated++; mClientTypes = clientTypes; } void TestContactsClientTypes::onRequestClientTypesFinished(PendingOperation *op) { if (op->isError()) { mLastError = op->errorName(); mLastErrorMessage = op->errorMessage(); mLoop->exit(1); } else { PendingStringList *psl = qobject_cast(op); mClientTypes = psl->result(); mLoop->exit(0); } } void TestContactsClientTypes::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("contacts-client-types"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "foo", NULL); QCOMPARE(mConn->connect(), true); } void TestContactsClientTypes::init() { initImpl(); mClientTypesUpdated = 0; } void TestContactsClientTypes::testClientTypes() { ContactManagerPtr contactManager = mConn->client()->contactManager(); QVERIFY(contactManager->supportedFeatures().contains(Contact::FeatureClientTypes)); QStringList validIDs = QStringList() << QLatin1String("foo") << QLatin1String("bar"); QList contacts = mConn->contacts(validIDs, Contact::FeatureClientTypes); QCOMPARE(contacts.size(), validIDs.size()); for (int i = 0; i < contacts.size(); i++) { ContactPtr contact = contacts[i]; QCOMPARE(contact->requestedFeatures().contains(Contact::FeatureClientTypes), true); QCOMPARE(contact->actualFeatures().contains(Contact::FeatureClientTypes), true); QVERIFY(contact->clientTypes().isEmpty()); QVERIFY(connect(contact.data(), SIGNAL(clientTypesChanged(QStringList)), SLOT(onClientTypesChanged(QStringList)))); } ContactPtr contactFoo = contacts[0]; ContactPtr contactBar = contacts[1]; const gchar *clientTypes1[] = { "phone", "pc", NULL }; const gchar *clientTypes2[] = { "web", NULL }; tp_tests_contacts_connection_change_client_types(TP_TESTS_CONTACTS_CONNECTION(mConn->service()), contactFoo->handle()[0], g_strdupv((gchar**) clientTypes1)); while (mClientTypesUpdated != 1) { mLoop->processEvents(); } QCOMPARE(mClientTypesUpdated, 1); QCOMPARE(mClientTypes, QStringList() << QLatin1String("phone") << QLatin1String("pc")); QCOMPARE(contactFoo->clientTypes(), QStringList() << QLatin1String("phone") << QLatin1String("pc")); mClientTypes.clear(); tp_tests_contacts_connection_change_client_types(TP_TESTS_CONTACTS_CONNECTION(mConn->service()), contactBar->handle()[0], g_strdupv((gchar**) clientTypes2)); while (mClientTypesUpdated != 2) { mLoop->processEvents(); } QCOMPARE(mClientTypesUpdated, 2); QCOMPARE(mClientTypes, QStringList() << QLatin1String("web")); QCOMPARE(contactBar->clientTypes(), QStringList() << QLatin1String("web")); mClientTypesUpdated = 0; mClientTypes.clear(); connect(contactFoo->requestClientTypes(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onRequestClientTypesFinished(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClientTypes, QStringList() << QLatin1String("phone") << QLatin1String("pc")); mClientTypes.clear(); connect(contactBar->requestClientTypes(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onRequestClientTypesFinished(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClientTypes, QStringList() << QLatin1String("web")); } void TestContactsClientTypes::testClientTypesAttributes() { ContactManagerPtr contactManager = mConn->client()->contactManager(); QVERIFY(contactManager->supportedFeatures().contains(Contact::FeatureClientTypes)); const gchar *clientTypes[] = { "pc", "phone", NULL }; tp_tests_contacts_connection_change_client_types(TP_TESTS_CONTACTS_CONNECTION(mConn->service()), 2, g_strdupv((gchar**) clientTypes)); QStringList validIDs = QStringList() << QLatin1String("foo"); QList contacts = mConn->contacts(validIDs, Contact::FeatureClientTypes); QCOMPARE(contacts.size(), 1); ContactPtr contact = contacts[0]; QCOMPARE(contact->handle()[0], uint(2)); QCOMPARE(contact->requestedFeatures().contains(Contact::FeatureClientTypes), true); QCOMPARE(contact->actualFeatures().contains(Contact::FeatureClientTypes), true); QCOMPARE(contact->clientTypes(), QStringList() << QLatin1String("pc") << QLatin1String("phone")); } void TestContactsClientTypes::cleanup() { cleanupImpl(); } void TestContactsClientTypes::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestContactsClientTypes) #include "_gen/contacts-client-types.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/conn-capabilities.cpp0000664000175000017500000000650112470405660021141 0ustar jrjr#include #include #include #include #include #include using namespace Tp; class TestConnCapabilities : public Test { Q_OBJECT public: TestConnCapabilities(QObject *parent = 0) : Test(parent), conn(0) { } private Q_SLOTS: void initTestCase(); void init(); void testCapabilities(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *conn; }; void TestConnCapabilities::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("conn-capabilities"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); } void TestConnCapabilities::init() { initImpl(); } void TestConnCapabilities::testCapabilities() { TestConnHelper *conn = new TestConnHelper(this, EXAMPLE_TYPE_ECHO_2_CONNECTION, "account", "me@example.com", "protocol", "contacts", NULL); QCOMPARE(conn->isReady(), false); // Before the connection is Ready, it doesn't guarantee support for anything but doesn't crash // either if we ask it for something QCOMPARE(conn->client()->capabilities().textChats(), false); QCOMPARE(conn->client()->capabilities().textChatrooms(), false); QCOMPARE(conn->client()->capabilities().streamedMediaCalls(), false); QCOMPARE(conn->client()->capabilities().streamedMediaAudioCalls(), false); QCOMPARE(conn->client()->capabilities().streamedMediaVideoCalls(), false); QCOMPARE(conn->client()->capabilities().streamedMediaVideoCallsWithAudio(), false); QCOMPARE(conn->client()->capabilities().upgradingStreamedMediaCalls(), false); QCOMPARE(conn->connect(), true); // Now we should have the real information on what the connection supports QCOMPARE(conn->client()->capabilities().textChats(), true); QCOMPARE(conn->client()->capabilities().textChatrooms(), false); QCOMPARE(conn->client()->capabilities().streamedMediaCalls(), false); QCOMPARE(conn->client()->capabilities().streamedMediaAudioCalls(), false); QCOMPARE(conn->client()->capabilities().streamedMediaVideoCalls(), false); QCOMPARE(conn->client()->capabilities().streamedMediaVideoCallsWithAudio(), false); QCOMPARE(conn->client()->capabilities().upgradingStreamedMediaCalls(), false); // Now, invalidate the connection by disconnecting it QCOMPARE(conn->disconnect(), true); // Check that no support for anything is again reported QCOMPARE(conn->client()->capabilities().textChats(), false); QCOMPARE(conn->client()->capabilities().textChatrooms(), false); QCOMPARE(conn->client()->capabilities().streamedMediaCalls(), false); QCOMPARE(conn->client()->capabilities().streamedMediaAudioCalls(), false); QCOMPARE(conn->client()->capabilities().streamedMediaVideoCalls(), false); QCOMPARE(conn->client()->capabilities().streamedMediaVideoCallsWithAudio(), false); QCOMPARE(conn->client()->capabilities().upgradingStreamedMediaCalls(), false); delete conn; } void TestConnCapabilities::cleanup() { cleanupImpl(); } void TestConnCapabilities::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestConnCapabilities) #include "_gen/conn-capabilities.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/contacts-avatar.cpp0000664000175000017500000002444612470405660020657 0ustar jrjr#include #include #include #include #include #include #include #include #include using namespace Tp; class SmartDir : public QDir { public: SmartDir(const QString &path) : QDir(path) { } bool rmdir() { return QDir().rmdir(path()); } bool removeDirectory(); }; bool SmartDir::removeDirectory() { bool ret = true; QFileInfoList list = entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); Q_FOREACH (QFileInfo info, list) { if (info.isDir()) { SmartDir subDir(info.filePath()); if (!subDir.removeDirectory()) { ret = false; } } else { qDebug() << "deleting" << info.filePath(); if (!QFile(info.filePath()).remove()) { ret = false; } } } if (ret) { qDebug() << "deleting" << path(); ret = rmdir(); } return ret; } class TestContactsAvatar : public Test { Q_OBJECT public: TestContactsAvatar(QObject *parent = 0) : Test(parent), mConn(0), mGotAvatarRetrieved(false), mAvatarDatasChanged(0) { } protected Q_SLOTS: void onAvatarRetrieved(uint, const QString &, const QByteArray &, const QString &); void onAvatarDataChanged(const Tp::AvatarData &); void createContactWithFakeAvatar(const char *); private Q_SLOTS: void initTestCase(); void init(); void testAvatar(); void testRequestAvatars(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; QList mContacts; bool mGotAvatarRetrieved; int mAvatarDatasChanged; }; void TestContactsAvatar::onAvatarRetrieved(uint handle, const QString &token, const QByteArray &data, const QString &mimeType) { Q_UNUSED(handle); Q_UNUSED(token); Q_UNUSED(data); Q_UNUSED(mimeType); mGotAvatarRetrieved = true; } void TestContactsAvatar::onAvatarDataChanged(const AvatarData &avatar) { Q_UNUSED(avatar); mAvatarDatasChanged++; mLoop->exit(0); } void TestContactsAvatar::createContactWithFakeAvatar(const char *id) { TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); const gchar avatarData[] = "fake-avatar-data"; const gchar avatarToken[] = "fake-avatar-token"; const gchar avatarMimeType[] = "fake-avatar-mime-type"; TpHandle handle; GArray *array; handle = tp_handle_ensure(serviceRepo, id, NULL, NULL); array = g_array_new(FALSE, FALSE, sizeof(gchar)); g_array_append_vals(array, avatarData, strlen(avatarData)); tp_tests_contacts_connection_change_avatar_data( TP_TESTS_CONTACTS_CONNECTION(mConn->service()), handle, array, avatarMimeType, avatarToken, true); g_array_unref(array); Tp::UIntList handles = Tp::UIntList() << handle; Features features = Features() << Contact::FeatureAvatarToken << Contact::FeatureAvatarData; mContacts = mConn->contacts(handles, features); QCOMPARE(mContacts.size(), handles.size()); if (mContacts[0]->avatarData().fileName.isEmpty()) { QVERIFY(connect(mContacts[0].data(), SIGNAL(avatarDataChanged(const Tp::AvatarData &)), SLOT(onAvatarDataChanged(const Tp::AvatarData &)))); QCOMPARE(mLoop->exec(), 0); } AvatarData avatar = mContacts[0]->avatarData(); qDebug() << "Contact created:"; qDebug() << "Avatar token:" << mContacts[0]->avatarToken(); qDebug() << "Avatar file:" << avatar.fileName; qDebug() << "Avatar MimeType:" << avatar.mimeType; QFile file(avatar.fileName); file.open(QIODevice::ReadOnly); QByteArray data(file.readAll()); file.close(); QCOMPARE(mContacts[0]->avatarToken(), QString(QLatin1String(avatarToken))); QCOMPARE(data, QByteArray(avatarData)); QCOMPARE(avatar.mimeType, QString(QLatin1String(avatarMimeType))); } void TestContactsAvatar::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("contacts-avatar"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "foo", NULL); QCOMPARE(mConn->connect(), true); } void TestContactsAvatar::init() { initImpl(); mGotAvatarRetrieved = false; mAvatarDatasChanged = 0; } void TestContactsAvatar::testAvatar() { QVERIFY(mConn->client()->contactManager()->supportedFeatures().contains( Contact::FeatureAvatarData)); /* Make sure our tests does not mess up user's avatar cache */ qsrand(time(0)); static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static const int DirNameLength = 6; QString dirName; for (int i = 0; i < DirNameLength; ++i) { dirName += QLatin1Char(letters[qrand() % qstrlen(letters)]); } QString tmpDir = QString(QLatin1String("%1/%2")).arg(QDir::tempPath()).arg(dirName); QByteArray a = tmpDir.toLatin1(); setenv ("XDG_CACHE_HOME", a.constData(), true); Client::ConnectionInterfaceAvatarsInterface *connAvatarsInterface = mConn->client()->optionalInterface(); /* Check if AvatarRetrieved gets called */ connect(connAvatarsInterface, SIGNAL(AvatarRetrieved(uint, const QString &, const QByteArray &, const QString &)), SLOT(onAvatarRetrieved(uint, const QString &, const QByteArray &, const QString &))); /* First time we create a contact, avatar should not be in cache, so * AvatarRetrieved should be called */ mGotAvatarRetrieved = false; createContactWithFakeAvatar("foo"); QVERIFY(mGotAvatarRetrieved); /* Second time we create a contact, avatar should be in cache now, so * AvatarRetrieved should NOT be called */ mGotAvatarRetrieved = false; createContactWithFakeAvatar("bar"); QVERIFY(!mGotAvatarRetrieved); QVERIFY(SmartDir(tmpDir).removeDirectory()); } void TestContactsAvatar::testRequestAvatars() { TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); const gchar avatarData[] = "fake-avatar-data"; const gchar avatarToken[] = "fake-avatar-token"; const gchar avatarMimeType[] = "fake-avatar-mime-type"; TpHandle handle; GArray *array; array = g_array_new(FALSE, FALSE, sizeof(gchar)); g_array_append_vals(array, avatarData, strlen(avatarData)); // First let's create the contacts Tp::UIntList handles; for (int i = 0; i < 100; ++i) { QString contactId = QLatin1String("contact") + QString::number(i); handle = tp_handle_ensure(serviceRepo, contactId.toLatin1().constData(), NULL, NULL); handles << handle; } Features features = Features() << Contact::FeatureAvatarToken << Contact::FeatureAvatarData; QList contacts = mConn->contacts(handles, features); QCOMPARE(contacts.size(), handles.size()); // now let's update the avatar for half of them so we can later check that requestContactAvatars // actually worked for all contacts. mAvatarDatasChanged = 0; for (int i = 0; i < contacts.size(); ++i) { ContactPtr contact = contacts[i]; QVERIFY(contact->avatarData().fileName.isEmpty()); QString contactAvatarToken = QLatin1String(avatarToken) + QString::number(i); QVERIFY(connect(contact.data(), SIGNAL(avatarDataChanged(const Tp::AvatarData &)), SLOT(onAvatarDataChanged(const Tp::AvatarData &)))); tp_tests_contacts_connection_change_avatar_data( TP_TESTS_CONTACTS_CONNECTION(mConn->service()), contact->handle()[0], array, avatarMimeType, contactAvatarToken.toLatin1().constData(), (i % 2)); } processDBusQueue(mConn->client().data()); while (mAvatarDatasChanged < contacts.size() / 2) { mLoop->processEvents(); } // check the only half got the updates QCOMPARE(mAvatarDatasChanged, contacts.size() / 2); for (int i = 0; i < contacts.size(); ++i) { ContactPtr contact = contacts[i]; if (i % 2) { QVERIFY(!contact->avatarData().fileName.isEmpty()); QCOMPARE(contact->avatarData().mimeType, QLatin1String(avatarMimeType)); QString contactAvatarToken = QLatin1String(avatarToken) + QString::number(i); QCOMPARE(contact->avatarToken(), contactAvatarToken); } else { QVERIFY(contact->avatarData().fileName.isEmpty()); } } // let's call ContactManager::requestContactAvatars now, it should update all contacts mAvatarDatasChanged = 0; mConn->client()->contactManager()->requestContactAvatars(contacts); processDBusQueue(mConn->client().data()); // the other half will now receive the avatar while (mAvatarDatasChanged < contacts.size() / 2) { mLoop->processEvents(); } // check the only half got the updates QCOMPARE(mAvatarDatasChanged, contacts.size() / 2); for (int i = 0; i < contacts.size(); ++i) { ContactPtr contact = contacts[i]; QVERIFY(!contact->avatarData().fileName.isEmpty()); QCOMPARE(contact->avatarData().mimeType, QLatin1String(avatarMimeType)); QString contactAvatarToken = QLatin1String(avatarToken) + QString::number(i); QCOMPARE(contact->avatarToken(), contactAvatarToken); } mAvatarDatasChanged = 0; // empty D-DBus queue processDBusQueue(mConn->client().data()); // it should silently work, no crash mConn->client()->contactManager()->requestContactAvatars(QList()); // let the mainloop run processDBusQueue(mConn->client().data()); QCOMPARE(mAvatarDatasChanged, 0); } void TestContactsAvatar::cleanup() { cleanupImpl(); } void TestContactsAvatar::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestContactsAvatar) #include "_gen/contacts-avatar.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/chan-conference.cpp0000664000175000017500000002337012470405660020576 0ustar jrjr#include #include #include #include #include #include #include #include using namespace Tp; class TestConferenceChan : public Test { Q_OBJECT public: TestConferenceChan(QObject *parent = 0) : Test(parent), mConn(0), mContactRepo(0), mTextChan1Service(0), mTextChan2Service(0), mConferenceChanService(0) { } protected Q_SLOTS: void onConferenceChannelMerged(const Tp::ChannelPtr &); void onConferenceChannelRemoved(const Tp::ChannelPtr &channel, const Tp::Channel::GroupMemberChangeDetails &details); private Q_SLOTS: void initTestCase(); void init(); void testConference(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; TpHandleRepoIface *mContactRepo; ChannelPtr mChan; QString mTextChan1Path; ExampleEchoChannel *mTextChan1Service; QString mTextChan2Path; ExampleEchoChannel *mTextChan2Service; QString mTextChan3Path; ExampleEchoChannel *mTextChan3Service; QString mConferenceChanPath; TpTestsConferenceChannel *mConferenceChanService; ChannelPtr mChannelMerged; ChannelPtr mChannelRemovedDetailed; Channel::GroupMemberChangeDetails mChannelRemovedDetailedDetails; }; void TestConferenceChan::onConferenceChannelMerged(const Tp::ChannelPtr &channel) { mChannelMerged = channel; mLoop->exit(0); } void TestConferenceChan::onConferenceChannelRemoved(const Tp::ChannelPtr &channel, const Tp::Channel::GroupMemberChangeDetails &details) { mChannelRemovedDetailed = channel; mChannelRemovedDetailedDetails = details; mLoop->exit(0); } void TestConferenceChan::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("chan-conference"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, EXAMPLE_TYPE_ECHO_CONNECTION, "account", "me@example.com", "protocol", "example", NULL); QCOMPARE(mConn->connect(), true); // create a Channel by magic, rather than doing D-Bus round-trips for it mContactRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); guint handle1 = tp_handle_ensure(mContactRepo, "someone1@localhost", 0, 0); guint handle2 = tp_handle_ensure(mContactRepo, "someone2@localhost", 0, 0); guint handle3 = tp_handle_ensure(mContactRepo, "someone3@localhost", 0, 0); QByteArray chanPath; GPtrArray *initialChannels = g_ptr_array_new(); mTextChan1Path = mConn->objectPath() + QLatin1String("/TextChannel/1"); chanPath = mTextChan1Path.toLatin1(); mTextChan1Service = EXAMPLE_ECHO_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle1, NULL)); g_ptr_array_add(initialChannels, g_strdup(chanPath.data())); mTextChan2Path = mConn->objectPath() + QLatin1String("/TextChannel/2"); chanPath = mTextChan2Path.toLatin1(); mTextChan2Service = EXAMPLE_ECHO_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle2, NULL)); g_ptr_array_add(initialChannels, g_strdup(chanPath.data())); // let's not add this one to initial channels mTextChan3Path = mConn->objectPath() + QLatin1String("/TextChannel/3"); chanPath = mTextChan3Path.toLatin1(); mTextChan3Service = EXAMPLE_ECHO_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle3, NULL)); mConferenceChanPath = mConn->objectPath() + QLatin1String("/ConferenceChannel"); chanPath = mConferenceChanPath.toLatin1(); mConferenceChanService = TP_TESTS_CONFERENCE_CHANNEL(g_object_new( TP_TESTS_TYPE_CONFERENCE_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "initial-channels", initialChannels, NULL)); g_ptr_array_foreach(initialChannels, (GFunc) g_free, NULL); g_ptr_array_free(initialChannels, TRUE); } void TestConferenceChan::init() { initImpl(); } void TestConferenceChan::testConference() { mChan = Channel::create(mConn->client(), mConferenceChanPath, QVariantMap()); QCOMPARE(mChan->isConference(), false); QVERIFY(mChan->conferenceInitialInviteeContacts().isEmpty()); QVERIFY(mChan->conferenceChannels().isEmpty()); QVERIFY(mChan->conferenceInitialChannels().isEmpty()); QVERIFY(mChan->conferenceOriginalChannels().isEmpty()); QCOMPARE(mChan->supportsConferenceMerging(), false); QCOMPARE(mChan->supportsConferenceSplitting(), false); QVERIFY(connect(mChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(), true); QStringList expectedObjectPaths; expectedObjectPaths << mTextChan1Path << mTextChan2Path; QStringList objectPaths; Q_FOREACH (const ChannelPtr &channel, mChan->conferenceInitialChannels()) { objectPaths << channel->objectPath(); } QCOMPARE(expectedObjectPaths, objectPaths); objectPaths.clear(); Q_FOREACH (const ChannelPtr &channel, mChan->conferenceChannels()) { objectPaths << channel->objectPath(); } QCOMPARE(expectedObjectPaths, objectPaths); /* // TODO - Properly check for initial invitee contacts if/when a test CM supports it QVERIFY(!mChan->isReady(Channel::FeatureConferenceInitialInviteeContacts)); QCOMPARE(mChan->conferenceInitialInviteeContacts(), Contacts()); QVERIFY(connect(mChan->becomeReady(Channel::FeatureConferenceInitialInviteeContacts), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(Channel::FeatureConferenceInitialInviteeContacts), true); QCOMPARE(mChan->conferenceInitialInviteeContacts(), Contacts()); */ QCOMPARE(mChan->supportsConferenceMerging(), true); QCOMPARE(mChan->supportsConferenceSplitting(), false); QVERIFY(connect(mChan->conferenceSplitChannel(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED); QVERIFY(!mLastErrorMessage.isEmpty()); ChannelPtr otherChannel = Channel::create(mConn->client(), mTextChan3Path, QVariantMap()); QVERIFY(connect(mChan.data(), SIGNAL(conferenceChannelMerged(const Tp::ChannelPtr &)), SLOT(onConferenceChannelMerged(const Tp::ChannelPtr &)))); QVERIFY(connect(mChan->conferenceMergeChannel(otherChannel), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(), true); while (!mChannelMerged) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mChannelMerged->objectPath(), otherChannel->objectPath()); expectedObjectPaths << mTextChan3Path; objectPaths.clear(); Q_FOREACH (const ChannelPtr &channel, mChan->conferenceChannels()) { objectPaths << channel->objectPath(); } QCOMPARE(expectedObjectPaths, objectPaths); QVERIFY(connect(mChan.data(), SIGNAL(conferenceChannelRemoved(const Tp::ChannelPtr &, const Tp::Channel::GroupMemberChangeDetails &)), SLOT(onConferenceChannelRemoved(const Tp::ChannelPtr &, const Tp::Channel::GroupMemberChangeDetails &)))); tp_tests_conference_channel_remove_channel (mConferenceChanService, mChannelMerged->objectPath().toLatin1().data()); while (!mChannelRemovedDetailed) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mChannelRemovedDetailed, mChannelMerged); QCOMPARE(mChannelRemovedDetailedDetails.allDetails().isEmpty(), false); QCOMPARE(qdbus_cast(mChannelRemovedDetailedDetails.allDetails().value( QLatin1String("domain-specific-detail-uint"))), 3); QCOMPARE(mChannelRemovedDetailedDetails.hasActor(), true); QCOMPARE(mChannelRemovedDetailedDetails.actor(), mChan->groupSelfContact()); expectedObjectPaths.clear(); expectedObjectPaths << mTextChan1Path << mTextChan2Path; objectPaths.clear(); Q_FOREACH (const ChannelPtr &channel, mChan->conferenceChannels()) { objectPaths << channel->objectPath(); } QCOMPARE(expectedObjectPaths, objectPaths); mChan.reset(); mChannelMerged.reset(); } void TestConferenceChan::cleanup() { cleanupImpl(); } void TestConferenceChan::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; if (mTextChan1Service != 0) { g_object_unref(mTextChan1Service); mTextChan1Service = 0; } if (mTextChan2Service != 0) { g_object_unref(mTextChan2Service); mTextChan2Service = 0; } if (mConferenceChanService != 0) { g_object_unref(mConferenceChanService); mConferenceChanService = 0; } cleanupTestCaseImpl(); } QTEST_MAIN(TestConferenceChan) #include "_gen/chan-conference.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/client-factories.cpp0000664000175000017500000014321512470405660021014 0ustar jrjr#include #include #include #include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; using namespace Tp::Client; class ChannelRequestAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ChannelRequest") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " " " \n" "") Q_PROPERTY(QDBusObjectPath Account READ Account) Q_PROPERTY(qulonglong UserActionTime READ UserActionTime) Q_PROPERTY(QString PreferredHandler READ PreferredHandler) Q_PROPERTY(Tp::QualifiedPropertyValueMapList Requests READ Requests) Q_PROPERTY(QStringList Interfaces READ Interfaces) public: ChannelRequestAdaptor(QDBusObjectPath account, qulonglong userActionTime, QString preferredHandler, QualifiedPropertyValueMapList requests, QStringList interfaces, QObject *parent) : QDBusAbstractAdaptor(parent), mAccount(account), mUserActionTime(userActionTime), mPreferredHandler(preferredHandler), mRequests(requests), mInterfaces(interfaces) { } virtual ~ChannelRequestAdaptor() { } public: // Properties inline QDBusObjectPath Account() const { return mAccount; } inline qulonglong UserActionTime() const { return mUserActionTime; } inline QString PreferredHandler() const { return mPreferredHandler; } inline QualifiedPropertyValueMapList Requests() const { return mRequests; } inline QStringList Interfaces() const { return mInterfaces; } public Q_SLOTS: // Methods void Proceed() { } void Cancel() { } Q_SIGNALS: // Signals void Failed(const QString &error, const QString &message); void Succeeded(); private: QDBusObjectPath mAccount; qulonglong mUserActionTime; QString mPreferredHandler; QualifiedPropertyValueMapList mRequests; QStringList mInterfaces; }; // Totally incomplete mini version of ChannelDispatchOperation class ChannelDispatchOperationAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ChannelDispatchOperation") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QDBusObjectPath Account READ Account) Q_PROPERTY(QDBusObjectPath Connection READ Connection) Q_PROPERTY(Tp::ChannelDetailsList Channels READ Channels) Q_PROPERTY(QStringList Interfaces READ Interfaces) Q_PROPERTY(QStringList PossibleHandlers READ PossibleHandlers) public: ChannelDispatchOperationAdaptor(const QDBusObjectPath &acc, const QDBusObjectPath &conn, const ChannelDetailsList &channels, const QStringList &possibleHandlers, QObject *parent) : QDBusAbstractAdaptor(parent), mAccount(acc), mConn(conn), mChannels(channels), mPossibleHandlers(possibleHandlers) { } virtual ~ChannelDispatchOperationAdaptor() { } public: // Properties inline QDBusObjectPath Account() const { return mAccount; } inline QDBusObjectPath Connection() const { return mConn; } inline ChannelDetailsList Channels() const { return mChannels; } inline QStringList Interfaces() const { return mInterfaces; } inline QStringList PossibleHandlers() const { return mPossibleHandlers; } private: QDBusObjectPath mAccount, mConn; ChannelDetailsList mChannels; QStringList mInterfaces; QStringList mPossibleHandlers; }; class MyClient : public QObject, public AbstractClientObserver, public AbstractClientApprover, public AbstractClientHandler { Q_OBJECT public: static AbstractClientPtr create(const ChannelClassSpecList &channelFilter, const AbstractClientHandler::Capabilities &capabilities, bool bypassApproval = false, bool wantsRequestNotification = false) { return AbstractClientPtr::dynamicCast(SharedPtr( new MyClient(channelFilter, capabilities, bypassApproval, wantsRequestNotification))); } MyClient(const ChannelClassSpecList &channelFilter, const AbstractClientHandler::Capabilities &capabilities, bool bypassApproval = false, bool wantsRequestNotification = false) : AbstractClientObserver(channelFilter), AbstractClientApprover(channelFilter), AbstractClientHandler(channelFilter, capabilities, wantsRequestNotification), mBypassApproval(bypassApproval) { } ~MyClient() { } void observeChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const ChannelDispatchOperationPtr &dispatchOperation, const QList &requestsSatisfied, const AbstractClientObserver::ObserverInfo &observerInfo) { mObserveChannelsAccount = account; mObserveChannelsConnection = connection; mObserveChannelsChannels = channels; mObserveChannelsDispatchOperation = dispatchOperation; mObserveChannelsRequestsSatisfied = requestsSatisfied; mObserveChannelsObserverInfo = observerInfo; context->setFinished(); QTimer::singleShot(0, this, SIGNAL(observeChannelsFinished())); } void addDispatchOperation(const MethodInvocationContextPtr<> &context, const ChannelDispatchOperationPtr &dispatchOperation) { mAddDispatchOperationChannels = dispatchOperation->channels(); mAddDispatchOperationDispatchOperation = dispatchOperation; context->setFinished(); QTimer::singleShot(0, this, SIGNAL(addDispatchOperationFinished())); } bool bypassApproval() const { return mBypassApproval; } void handleChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const QList &requestsSatisfied, const QDateTime &userActionTime, const AbstractClientHandler::HandlerInfo &handlerInfo) { mHandleChannelsAccount = account; mHandleChannelsConnection = connection; mHandleChannelsChannels = channels; mHandleChannelsRequestsSatisfied = requestsSatisfied; mHandleChannelsUserActionTime = userActionTime; mHandleChannelsHandlerInfo = handlerInfo; Q_FOREACH (const ChannelPtr &channel, channels) { connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), SIGNAL(channelClosed())); } context->setFinished(); QTimer::singleShot(0, this, SIGNAL(handleChannelsFinished())); } void addRequest(const ChannelRequestPtr &request) { mAddRequestRequest = request; Q_EMIT requestAdded(request); } void removeRequest(const ChannelRequestPtr &request, const QString &errorName, const QString &errorMessage) { mRemoveRequestRequest = request; mRemoveRequestErrorName = errorName; mRemoveRequestErrorMessage = errorMessage; Q_EMIT requestRemoved(request, errorName, errorMessage); } AccountPtr mObserveChannelsAccount; ConnectionPtr mObserveChannelsConnection; QList mObserveChannelsChannels; ChannelDispatchOperationPtr mObserveChannelsDispatchOperation; QList mObserveChannelsRequestsSatisfied; AbstractClientObserver::ObserverInfo mObserveChannelsObserverInfo; QList mAddDispatchOperationChannels; ChannelDispatchOperationPtr mAddDispatchOperationDispatchOperation; bool mBypassApproval; AccountPtr mHandleChannelsAccount; ConnectionPtr mHandleChannelsConnection; QList mHandleChannelsChannels; QList mHandleChannelsRequestsSatisfied; QDateTime mHandleChannelsUserActionTime; AbstractClientHandler::HandlerInfo mHandleChannelsHandlerInfo; ChannelRequestPtr mAddRequestRequest; ChannelRequestPtr mRemoveRequestRequest; QString mRemoveRequestErrorName; QString mRemoveRequestErrorMessage; Q_SIGNALS: void observeChannelsFinished(); void addDispatchOperationFinished(); void handleChannelsFinished(); void requestAdded(const Tp::ChannelRequestPtr &request); void requestRemoved(const Tp::ChannelRequestPtr &request, const QString &errorName, const QString &errorMessage); void channelClosed(); }; class TestClientFactories : public Test { Q_OBJECT public: TestClientFactories(QObject *parent = 0) : Test(parent), mConnService(0), mBaseConnService(0), mContactRepo(0), mText1ChanService(0) { } void testObserveChannelsCommon(const AbstractClientPtr &clientObject, const QString &clientBusName, const QString &clientObjectPath); protected Q_SLOTS: void expectSignalEmission(); private Q_SLOTS: void initTestCase(); void init(); void testFactoryAccess(); void testRegister(); void testCapabilities(); void testObserveChannels(); void testAddDispatchOperation(); void testRequests(); void testHandleChannels(); void testChannelFactoryAccessors(); void cleanup(); void cleanupTestCase(); private: TpTestsContactsConnection *mConnService; TpBaseConnection *mBaseConnService; TpHandleRepoIface *mContactRepo; ExampleEchoChannel *mText1ChanService; ExampleEchoChannel *mText2ChanService; AccountManagerPtr mAM; AccountPtr mAccount; ConnectionPtr mConn; QString mText1ChanPath; QString mText2ChanPath; QString mConnName; QString mConnPath; ClientRegistrarPtr mClientRegistrar; QString mChannelDispatcherBusName; QString mChannelRequestPath; ChannelDispatchOperationAdaptor *mCDO; QString mCDOPath; AbstractClientHandler::Capabilities mClientCapabilities; AbstractClientPtr mClientObject1; QString mClientObject1BusName; QString mClientObject1Path; AbstractClientPtr mClientObject2; QString mClientObject2BusName; QString mClientObject2Path; uint mUserActionTime; }; void TestClientFactories::expectSignalEmission() { mLoop->exit(0); } void TestClientFactories::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("client-factories"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); QDBusConnection bus = QDBusConnection::sessionBus(); ChannelFactoryPtr chanFact = ChannelFactory::create(bus); chanFact->addFeaturesForTextChats(TextChannel::FeatureChatState | TextChannel::FeatureMessageQueue); chanFact->addCommonFeatures(Channel::FeatureCore); QCOMPARE(chanFact->commonFeatures().size(), 1); QCOMPARE(chanFact->featuresForTextChats().size(), 3); QVERIFY(chanFact->featuresForTextChats().contains(TextChannel::FeatureMessageQueue)); QVERIFY(chanFact->featuresForTextChats().contains(Channel::FeatureCore)); QVERIFY(!chanFact->featuresForTextChats().contains(TextChannel::FeatureMessageSentSignal)); mAM = AccountManager::create(AccountFactory::create(bus, Account::FeatureCore), ConnectionFactory::create(bus, Connection::FeatureCore | Connection::FeatureSimplePresence), chanFact); PendingReady *amReadyOp = mAM->becomeReady(); QVERIFY(amReadyOp != NULL); QVERIFY(connect(amReadyOp, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAM->isReady(), true); QVariantMap parameters; parameters[QLatin1String("account")] = QLatin1String("foobar"); PendingAccount *pacc = mAM->createAccount(QLatin1String("foo"), QLatin1String("bar"), QLatin1String("foobar"), parameters); QVERIFY(connect(pacc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pacc->account()); mAccount = pacc->account(); gchar *name; gchar *connPath; GError *error = 0; mConnService = TP_TESTS_CONTACTS_CONNECTION(g_object_new( TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "example", NULL)); QVERIFY(mConnService != 0); mBaseConnService = TP_BASE_CONNECTION(mConnService); QVERIFY(mBaseConnService != 0); QVERIFY(tp_base_connection_register(mBaseConnService, "example", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); mConnName = QLatin1String(name); mConnPath = QLatin1String(connPath); g_free(name); g_free(connPath); mConn = ConnectionPtr::qObjectCast(mAccount->connectionFactory()->proxy(mConnName, mConnPath, ChannelFactory::create(bus), ContactFactory::create())->proxy()); QCOMPARE(mConn->isReady(), false); PendingReady *mConnReady = mConn->lowlevel()->requestConnect(); QVERIFY(mConnReady != NULL); QVERIFY(connect(mConnReady, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(), true); QCOMPARE(static_cast(mConn->status()), static_cast(ConnectionStatusConnected)); // create a Channel by magic, rather than doing D-Bus round-trips for it mContactRepo = tp_base_connection_get_handles(mBaseConnService, TP_HANDLE_TYPE_CONTACT); guint handle = tp_handle_ensure(mContactRepo, "someone@localhost", 0, 0); mText1ChanPath = mConnPath + QLatin1String("/TextChannel1"); QByteArray chanPath(mText1ChanPath.toLatin1()); mText1ChanService = EXAMPLE_ECHO_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_CHANNEL, "connection", mConnService, "object-path", chanPath.data(), "handle", handle, NULL)); mText2ChanPath = mConnPath + QLatin1String("/TextChannel2"); chanPath = mText2ChanPath.toLatin1(); mText2ChanService = EXAMPLE_ECHO_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_CHANNEL, "connection", mConnService, "object-path", chanPath.data(), "handle", handle, NULL)); mClientRegistrar = ClientRegistrar::create(mAM); // Fake ChannelRequest mChannelDispatcherBusName = TP_QT_IFACE_CHANNEL_DISPATCHER; mChannelRequestPath = QLatin1String("/org/freedesktop/Telepathy/ChannelRequest/Request1"); QObject *request = new QObject(this); mUserActionTime = QDateTime::currentDateTime().toTime_t(); new ChannelRequestAdaptor(QDBusObjectPath(mAccount->objectPath()), mUserActionTime, QString(), QualifiedPropertyValueMapList(), QStringList(), request); QVERIFY(bus.registerService(mChannelDispatcherBusName)); QVERIFY(bus.registerObject(mChannelRequestPath, request)); // Fake ChannelDispatchOperation mCDOPath = QLatin1String("/org/freedesktop/Telepathy/ChannelDispatchOperation/Operation1"); QObject *cdo = new QObject(this); // Initialize this here so we can actually set it in possibleHandlers mClientObject1Path = QLatin1String("/org/freedesktop/Telepathy/Client/foo"); ChannelDetailsList channelDetailsList; ChannelDetails channelDetails = { QDBusObjectPath(mText1ChanPath), ChannelClassSpec::textChat().allProperties() }; channelDetailsList.append(channelDetails); mCDO = new ChannelDispatchOperationAdaptor(QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mConn->objectPath()), channelDetailsList, QStringList() << mClientObject1BusName, cdo); QVERIFY(bus.registerObject(mCDOPath, cdo)); } void TestClientFactories::init() { initImpl(); } void TestClientFactories::testFactoryAccess() { AccountFactoryConstPtr accFact = mClientRegistrar->accountFactory(); QVERIFY(!accFact.isNull()); QCOMPARE(accFact.data(), mAM->accountFactory().data()); QCOMPARE(accFact->features(), Features(Account::FeatureCore)); ConnectionFactoryConstPtr connFact = mClientRegistrar->connectionFactory(); QVERIFY(!connFact.isNull()); QCOMPARE(connFact.data(), mAM->connectionFactory().data()); QCOMPARE(connFact->features(), Connection::FeatureCore | Connection::FeatureSimplePresence); ChannelFactoryConstPtr chanFact = mClientRegistrar->channelFactory(); QVERIFY(!chanFact.isNull()); QCOMPARE(chanFact.data(), mAM->channelFactory().data()); ContactFactoryConstPtr contactFact = mClientRegistrar->contactFactory(); QVERIFY(!contactFact.isNull()); QCOMPARE(contactFact.data(), mAM->contactFactory().data()); } void TestClientFactories::testRegister() { // invalid client QVERIFY(!mClientRegistrar->registerClient(AbstractClientPtr(), QLatin1String("foo"))); mClientCapabilities.setICEUDPNATTraversalToken(); mClientCapabilities.setAudioCodecToken(QLatin1String("speex")); ChannelClassSpecList filters; filters.append(ChannelClassSpec::textChat()); mClientObject1 = MyClient::create(filters, mClientCapabilities, false, true); QVERIFY(mClientRegistrar->registerClient(mClientObject1, QLatin1String("foo"))); QVERIFY(mClientRegistrar->registeredClients().contains(mClientObject1)); // no op - client already registered QVERIFY(mClientRegistrar->registerClient(mClientObject1, QLatin1String("foo"))); filters.clear(); filters.append(ChannelClassSpec::streamedMediaCall()); mClientObject2 = MyClient::create(filters, mClientCapabilities, true, true); QVERIFY(mClientRegistrar->registerClient(mClientObject2, QLatin1String("foo"), true)); QVERIFY(mClientRegistrar->registeredClients().contains(mClientObject2)); // no op - client already registered QVERIFY(mClientRegistrar->registerClient(mClientObject2, QLatin1String("foo"), true)); QDBusConnection bus = mClientRegistrar->dbusConnection(); QDBusConnectionInterface *busIface = bus.interface(); QStringList registeredServicesNames = busIface->registeredServiceNames(); QVERIFY(registeredServicesNames.filter( QRegExp(QLatin1String("^" "org.freedesktop.Telepathy.Client.foo" ".([_A-Za-z][_A-Za-z0-9]*)"))).size() == 1); mClientObject1BusName = QLatin1String("org.freedesktop.Telepathy.Client.foo"); mClientObject1Path = QLatin1String("/org/freedesktop/Telepathy/Client/foo"); mClientObject2BusName = registeredServicesNames.filter( QRegExp(QLatin1String("org.freedesktop.Telepathy.Client.foo._*"))).first(); mClientObject2Path = QString(QLatin1String("/%1")).arg(mClientObject2BusName); mClientObject2Path.replace(QLatin1String("."), QLatin1String("/")); } void TestClientFactories::testCapabilities() { QDBusConnection bus = mClientRegistrar->dbusConnection(); QStringList normalizedClientCaps = mClientCapabilities.allTokens(); normalizedClientCaps.sort(); QStringList normalizedHandlerCaps; // object 1 ClientHandlerInterface *handler1Iface = new ClientHandlerInterface(bus, mClientObject1BusName, mClientObject1Path, this); QVERIFY(waitForProperty(handler1Iface->requestPropertyCapabilities(), &normalizedHandlerCaps)); normalizedHandlerCaps.sort(); QCOMPARE(normalizedHandlerCaps, normalizedClientCaps); // object 2 ClientHandlerInterface *handler2Iface = new ClientHandlerInterface(bus, mClientObject2BusName, mClientObject2Path, this); QVERIFY(waitForProperty(handler2Iface->requestPropertyCapabilities(), &normalizedHandlerCaps)); normalizedHandlerCaps.sort(); QCOMPARE(normalizedHandlerCaps, normalizedClientCaps); } void TestClientFactories::testRequests() { QDBusConnection bus = mClientRegistrar->dbusConnection(); ClientInterfaceRequestsInterface *handlerRequestsIface = new ClientInterfaceRequestsInterface(bus, mClientObject1BusName, mClientObject1Path, this); MyClient *client = dynamic_cast(mClientObject1.data()); connect(client, SIGNAL(requestAdded(const Tp::ChannelRequestPtr &)), SLOT(expectSignalEmission())); QVariantMap requestProps; requestProps.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Account"), QVariant::fromValue(QDBusObjectPath(mAccount->objectPath()))); requestProps.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Interface.DomainSpecific.IntegerProp"), QVariant::fromValue(3)); handlerRequestsIface->AddRequest(QDBusObjectPath(mChannelRequestPath), requestProps); if (!client->mAddRequestRequest) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(client->mAddRequestRequest->objectPath(), mChannelRequestPath); QCOMPARE(client->mAddRequestRequest->account().data(), mAccount.data()); QVERIFY(client->mAddRequestRequest->immutableProperties().contains( TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Interface.DomainSpecific.IntegerProp"))); QCOMPARE(qdbus_cast(client->mAddRequestRequest->immutableProperties().value( TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Interface.DomainSpecific.IntegerProp"))), 3); QVERIFY(connect(client->mAddRequestRequest->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(client->mAddRequestRequest->immutableProperties().contains( TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".UserActionTime"))); QCOMPARE(qdbus_cast(client->mAddRequestRequest->immutableProperties().value( TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".UserActionTime"))), mUserActionTime); connect(client, SIGNAL(requestRemoved(const Tp::ChannelRequestPtr &, const QString &, const QString &)), SLOT(expectSignalEmission())); handlerRequestsIface->RemoveRequest(QDBusObjectPath(mChannelRequestPath), QLatin1String(TP_QT_ERROR_NOT_AVAILABLE), QLatin1String("Not available")); if (!client->mRemoveRequestRequest) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(client->mRemoveRequestRequest->objectPath(), mChannelRequestPath); // QCOMPARE(client->mRemoveRequestRequest->account().data(), // mAccount.data()); QCOMPARE(client->mRemoveRequestErrorName, QString(QLatin1String(TP_QT_ERROR_NOT_AVAILABLE))); QCOMPARE(client->mRemoveRequestErrorMessage, QString(QLatin1String("Not available"))); } void TestClientFactories::testObserveChannelsCommon(const AbstractClientPtr &clientObject, const QString &clientBusName, const QString &clientObjectPath) { QDBusConnection bus = mClientRegistrar->dbusConnection(); ClientObserverInterface *observeIface = new ClientObserverInterface(bus, clientBusName, clientObjectPath, this); MyClient *client = dynamic_cast(clientObject.data()); connect(client, SIGNAL(observeChannelsFinished()), SLOT(expectSignalEmission())); ChannelDetailsList channelDetailsList; ChannelDetails channelDetails = { QDBusObjectPath(mText1ChanPath), ChannelClassSpec::textChat().allProperties() }; channelDetailsList.append(channelDetails); observeIface->ObserveChannels(QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mConn->objectPath()), channelDetailsList, QDBusObjectPath(mCDOPath), ObjectPathList() << QDBusObjectPath(mChannelRequestPath), QVariantMap()); QCOMPARE(mLoop->exec(), 0); QCOMPARE(client->mObserveChannelsAccount->objectPath(), mAccount->objectPath()); QCOMPARE(client->mObserveChannelsAccount.data(), mAccount.data()); QVERIFY(client->mObserveChannelsAccount->isReady(Account::FeatureCore)); QCOMPARE(client->mObserveChannelsConnection->objectPath(), mConn->objectPath()); QCOMPARE(client->mObserveChannelsConnection.data(), mConn.data()); QVERIFY(client->mObserveChannelsConnection->isReady( Connection::FeatureCore | Connection::FeatureSimplePresence)); QCOMPARE(client->mObserveChannelsChannels.size(), 1); QCOMPARE(client->mObserveChannelsChannels.first()->objectPath(), mText1ChanPath); QVERIFY(!client->mObserveChannelsDispatchOperation.isNull()); QCOMPARE(client->mObserveChannelsDispatchOperation->account().data(), mAccount.data()); QCOMPARE(client->mObserveChannelsDispatchOperation->connection().data(), mConn.data()); QCOMPARE(client->mObserveChannelsRequestsSatisfied.size(), 1); QCOMPARE(client->mObserveChannelsRequestsSatisfied.first()->objectPath(), mChannelRequestPath); QVERIFY(client->mObserveChannelsRequestsSatisfied.first()->isReady()); QCOMPARE(client->mObserveChannelsRequestsSatisfied.first()->account().data(), mAccount.data()); } void TestClientFactories::testObserveChannels() { testObserveChannelsCommon(mClientObject1, mClientObject1BusName, mClientObject1Path); testObserveChannelsCommon(mClientObject2, mClientObject2BusName, mClientObject2Path); } void TestClientFactories::testAddDispatchOperation() { QDBusConnection bus = mClientRegistrar->dbusConnection(); ClientApproverInterface *approverIface = new ClientApproverInterface(bus, mClientObject1BusName, mClientObject1Path, this); MyClient *client = dynamic_cast(mClientObject1.data()); connect(client, SIGNAL(addDispatchOperationFinished()), SLOT(expectSignalEmission())); QVariantMap dispatchOperationProperties; dispatchOperationProperties.insert( TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".Connection"), QVariant::fromValue(mCDO->Connection())); dispatchOperationProperties.insert( TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".Account"), QVariant::fromValue(mCDO->Account())); dispatchOperationProperties.insert( TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".PossibleHandlers"), QVariant::fromValue(mCDO->PossibleHandlers())); dispatchOperationProperties.insert( TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".Interfaces"), QVariant::fromValue(mCDO->Interfaces())); approverIface->AddDispatchOperation(mCDO->Channels(), QDBusObjectPath(mCDOPath), dispatchOperationProperties); QCOMPARE(mLoop->exec(), 0); QCOMPARE(client->mAddDispatchOperationChannels.first()->objectPath(), mText1ChanPath); QCOMPARE(client->mAddDispatchOperationChannels.first()->connection().data(), mConn.data()); QVERIFY(client->mAddDispatchOperationChannels.first()->connection()->isReady( Connection::FeatureCore | Connection::FeatureSimplePresence)); QCOMPARE(client->mAddDispatchOperationDispatchOperation->channels().first().data(), client->mAddDispatchOperationChannels.first().data()); QCOMPARE(client->mAddDispatchOperationDispatchOperation->objectPath(), mCDOPath); QVERIFY(client->mAddDispatchOperationDispatchOperation->isReady()); QCOMPARE(client->mAddDispatchOperationDispatchOperation->account().data(), mAccount.data()); QCOMPARE(client->mAddDispatchOperationDispatchOperation->connection().data(), mConn.data()); QCOMPARE(client->mAddDispatchOperationDispatchOperation->possibleHandlers().size(), 1); QCOMPARE(client->mAddDispatchOperationDispatchOperation->possibleHandlers(), mCDO->PossibleHandlers()); } void TestClientFactories::testHandleChannels() { QDBusConnection bus = mClientRegistrar->dbusConnection(); // object 1 ClientHandlerInterface *handler1Iface = new ClientHandlerInterface(bus, mClientObject1BusName, mClientObject1Path, this); MyClient *client1 = dynamic_cast(mClientObject1.data()); connect(client1, SIGNAL(handleChannelsFinished()), SLOT(expectSignalEmission())); ChannelDetailsList channelDetailsList; ChannelDetails channelDetails = { QDBusObjectPath(mText1ChanPath), ChannelClassSpec::textChat().allProperties() }; channelDetailsList.append(channelDetails); handler1Iface->HandleChannels(QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mConn->objectPath()), channelDetailsList, ObjectPathList() << QDBusObjectPath(mChannelRequestPath), mUserActionTime, QVariantMap()); QCOMPARE(mLoop->exec(), 0); QCOMPARE(client1->mHandleChannelsAccount->objectPath(), mAccount->objectPath()); QCOMPARE(client1->mHandleChannelsAccount.data(), mAccount.data()); QVERIFY(client1->mHandleChannelsAccount->isReady()); QCOMPARE(client1->mHandleChannelsConnection->objectPath(), mConn->objectPath()); QCOMPARE(client1->mHandleChannelsConnection.data(), mConn.data()); QVERIFY(client1->mHandleChannelsConnection->isReady( Connection::FeatureCore | Connection::FeatureSimplePresence)); QCOMPARE(client1->mHandleChannelsChannels.first()->objectPath(), mText1ChanPath); TextChannelPtr textChan = TextChannelPtr::qObjectCast(client1->mHandleChannelsChannels.first()); QVERIFY(!textChan.isNull()); QVERIFY(textChan->isReady()); QVERIFY(textChan->isReady(Channel::FeatureCore)); QVERIFY(textChan->isReady(TextChannel::FeatureMessageQueue)); QVERIFY(textChan->isReady(TextChannel::FeatureChatState)); QCOMPARE(client1->mHandleChannelsRequestsSatisfied.first()->objectPath(), mChannelRequestPath); QVERIFY(client1->mHandleChannelsRequestsSatisfied.first()->isReady()); QCOMPARE(client1->mHandleChannelsRequestsSatisfied.first()->account().data(), mAccount.data()); QCOMPARE(client1->mHandleChannelsUserActionTime.toTime_t(), mUserActionTime); Tp::ObjectPathList handledChannels; QVERIFY(waitForProperty(handler1Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.contains(QDBusObjectPath(mText1ChanPath))); // object 2 ClientHandlerInterface *handler2Iface = new ClientHandlerInterface(bus, mClientObject2BusName, mClientObject2Path, this); MyClient *client2 = dynamic_cast(mClientObject2.data()); connect(client2, SIGNAL(handleChannelsFinished()), SLOT(expectSignalEmission())); channelDetailsList.clear(); channelDetails.channel = QDBusObjectPath(mText2ChanPath); channelDetailsList.append(channelDetails); handler2Iface->HandleChannels(QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mConn->objectPath()), channelDetailsList, ObjectPathList() << QDBusObjectPath(mChannelRequestPath), mUserActionTime, QVariantMap()); QCOMPARE(mLoop->exec(), 0); QCOMPARE(client2->mHandleChannelsAccount->objectPath(), mAccount->objectPath()); QCOMPARE(client2->mHandleChannelsAccount.data(), mAccount.data()); QVERIFY(client2->mHandleChannelsAccount->isReady()); QCOMPARE(client2->mHandleChannelsConnection->objectPath(), mConn->objectPath()); QCOMPARE(client2->mHandleChannelsConnection.data(), mConn.data()); QVERIFY(client2->mHandleChannelsConnection->isReady( Connection::FeatureCore | Connection::FeatureSimplePresence)); QCOMPARE(client2->mHandleChannelsChannels.first()->objectPath(), mText2ChanPath); QCOMPARE(client2->mHandleChannelsRequestsSatisfied.first()->objectPath(), mChannelRequestPath); QVERIFY(client2->mHandleChannelsRequestsSatisfied.first()->isReady()); QCOMPARE(client2->mHandleChannelsRequestsSatisfied.first()->account().data(), mAccount.data()); QCOMPARE(client2->mHandleChannelsUserActionTime.toTime_t(), mUserActionTime); QVERIFY(waitForProperty(handler1Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.contains(QDBusObjectPath(mText1ChanPath))); QVERIFY(handledChannels.contains(QDBusObjectPath(mText2ChanPath))); QVERIFY(waitForProperty(handler2Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.contains(QDBusObjectPath(mText1ChanPath))); QVERIFY(handledChannels.contains(QDBusObjectPath(mText2ChanPath))); // Handler.HandledChannels will now return all channels that are not invalidated/destroyed // even if the handler for such channels was already unregistered g_object_unref(mText1ChanService); connect(client1, SIGNAL(channelClosed()), SLOT(expectSignalEmission())); QCOMPARE(mLoop->exec(), 0); mClientRegistrar->unregisterClient(mClientObject1); QVERIFY(waitForProperty(handler2Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.contains(QDBusObjectPath(mText2ChanPath))); g_object_unref(mText2ChanService); connect(client2, SIGNAL(channelClosed()), SLOT(expectSignalEmission())); QCOMPARE(mLoop->exec(), 0); QVERIFY(waitForProperty(handler2Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.isEmpty()); } void TestClientFactories::testChannelFactoryAccessors() { QDBusConnection bus = QDBusConnection::sessionBus(); ChannelFactoryPtr chanFact = ChannelFactory::create(bus); QCOMPARE(chanFact->featuresForTextChats(), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::textChat()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedTextChat()), Features()); QCOMPARE(chanFact->featuresForTextChatrooms(), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::textChatroom()), Features()); QCOMPARE(chanFact->featuresForStreamedMediaCalls(), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaCall()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaAudioCall()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCall()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCallWithAudio()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaCall()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaAudioCall()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCall()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCallWithAudio()), Features()); QCOMPARE(chanFact->featuresForRoomLists(), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::roomList()), Features()); QCOMPARE(chanFact->featuresForOutgoingFileTransfers(), Features()); QCOMPARE(chanFact->featuresForIncomingFileTransfers(), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::outgoingFileTransfer()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::incomingFileTransfer()), Features()); QCOMPARE(chanFact->featuresForOutgoingStreamTubes(), Features()); QCOMPARE(chanFact->featuresForIncomingStreamTubes(), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::outgoingStreamTube()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::incomingStreamTube()), Features()); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::contactSearch()), Features()); QCOMPARE(chanFact->featuresForContactSearches(), Features()); Features commonFeatures; commonFeatures.insert(Channel::FeatureCore); chanFact->addCommonFeatures(commonFeatures); QCOMPARE(chanFact->featuresForTextChats(), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::textChat()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedTextChat()), commonFeatures); QCOMPARE(chanFact->featuresForTextChatrooms(), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::textChatroom()), commonFeatures); QCOMPARE(chanFact->featuresForStreamedMediaCalls(), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaCall()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaAudioCall()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCall()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCallWithAudio()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaCall()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaAudioCall()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCall()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCallWithAudio()), commonFeatures); QCOMPARE(chanFact->featuresForRoomLists(), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::roomList()), commonFeatures); QCOMPARE(chanFact->featuresForOutgoingFileTransfers(), commonFeatures); QCOMPARE(chanFact->featuresForIncomingFileTransfers(), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::outgoingFileTransfer()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::incomingFileTransfer()), commonFeatures); QCOMPARE(chanFact->featuresForOutgoingStreamTubes(), commonFeatures); QCOMPARE(chanFact->featuresForIncomingStreamTubes(), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::outgoingStreamTube()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::incomingStreamTube()), commonFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::contactSearch()), commonFeatures); QCOMPARE(chanFact->featuresForContactSearches(), commonFeatures); Features textChatFeatures; textChatFeatures.insert(TextChannel::FeatureCore); textChatFeatures.insert(TextChannel::FeatureMessageQueue); chanFact->addFeaturesForTextChats(textChatFeatures); textChatFeatures |= commonFeatures; Features textChatroomFeatures; textChatroomFeatures.insert(TextChannel::FeatureCore); textChatroomFeatures.insert(TextChannel::FeatureMessageCapabilities); chanFact->addFeaturesForTextChatrooms(textChatroomFeatures); textChatroomFeatures |= commonFeatures; Features streamedMediaFeatures; streamedMediaFeatures.insert(StreamedMediaChannel::FeatureStreams); chanFact->addFeaturesForStreamedMediaCalls(streamedMediaFeatures); streamedMediaFeatures |= commonFeatures; // RoomListChannel has no feature, let's use FeatureConferenceInitialInviteeContacts just for // testing purposes Features roomListFeatures; roomListFeatures.insert(Channel::FeatureConferenceInitialInviteeContacts); chanFact->addFeaturesForRoomLists(roomListFeatures); roomListFeatures |= commonFeatures; Features outFtFeatures; outFtFeatures.insert(FileTransferChannel::FeatureCore); outFtFeatures.insert(OutgoingFileTransferChannel::FeatureCore); chanFact->addFeaturesForOutgoingFileTransfers(outFtFeatures); outFtFeatures |= commonFeatures; Features inFtFeatures; inFtFeatures.insert(FileTransferChannel::FeatureCore); inFtFeatures.insert(IncomingFileTransferChannel::FeatureCore); chanFact->addFeaturesForIncomingFileTransfers(inFtFeatures); inFtFeatures |= commonFeatures; Features outStubeFeatures; outStubeFeatures.insert(StreamTubeChannel::FeatureCore); outStubeFeatures.insert(OutgoingStreamTubeChannel::FeatureCore); chanFact->addFeaturesForOutgoingStreamTubes(outStubeFeatures); outStubeFeatures |= commonFeatures; Features inStubeFeatures = commonFeatures; outStubeFeatures.insert(StreamTubeChannel::FeatureCore); outStubeFeatures.insert(IncomingStreamTubeChannel::FeatureCore); chanFact->addFeaturesForIncomingStreamTubes(inStubeFeatures); inStubeFeatures |= commonFeatures; Features contactSearchFeatures; contactSearchFeatures.insert(ContactSearchChannel::FeatureCore); chanFact->addFeaturesForContactSearches(contactSearchFeatures); contactSearchFeatures |= commonFeatures; QCOMPARE(chanFact->featuresForTextChats(), textChatFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::textChat()), textChatFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedTextChat()), textChatFeatures); QCOMPARE(chanFact->featuresForTextChatrooms(), textChatroomFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::textChatroom()), textChatroomFeatures); QCOMPARE(chanFact->featuresForStreamedMediaCalls(), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaAudioCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCallWithAudio()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaAudioCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCallWithAudio()), streamedMediaFeatures); QCOMPARE(chanFact->featuresForRoomLists(), roomListFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::roomList()), roomListFeatures); QCOMPARE(chanFact->featuresForOutgoingFileTransfers(), outFtFeatures); QCOMPARE(chanFact->featuresForIncomingFileTransfers(), inFtFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::outgoingFileTransfer()), outFtFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::incomingFileTransfer()), inFtFeatures); QCOMPARE(chanFact->featuresForOutgoingStreamTubes(), outStubeFeatures); QCOMPARE(chanFact->featuresForIncomingStreamTubes(), inStubeFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::outgoingStreamTube()), outStubeFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::incomingStreamTube()), inStubeFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::contactSearch()), contactSearchFeatures); QCOMPARE(chanFact->featuresForContactSearches(), contactSearchFeatures); Features streamedMediaAudioFeatures; streamedMediaAudioFeatures.insert(StreamedMediaChannel::FeatureStreams); chanFact->addFeaturesFor(ChannelClassSpec::streamedMediaAudioCall(), streamedMediaAudioFeatures); streamedMediaAudioFeatures |= streamedMediaFeatures; QCOMPARE(chanFact->featuresForStreamedMediaCalls(), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaAudioCall()), streamedMediaAudioFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCallWithAudio()), streamedMediaAudioFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaAudioCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCallWithAudio()), streamedMediaFeatures); Features unnamedStreamedMediaAudioFeatures; unnamedStreamedMediaAudioFeatures.insert(StreamedMediaChannel::FeatureLocalHoldState); chanFact->addFeaturesFor(ChannelClassSpec::unnamedStreamedMediaAudioCall(), unnamedStreamedMediaAudioFeatures); unnamedStreamedMediaAudioFeatures |= streamedMediaFeatures; QCOMPARE(chanFact->featuresForStreamedMediaCalls(), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaAudioCall()), streamedMediaAudioFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCallWithAudio()), streamedMediaAudioFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaAudioCall()), unnamedStreamedMediaAudioFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCallWithAudio()), unnamedStreamedMediaAudioFeatures); QVariantMap otherProps; otherProps.insert(QLatin1String("ping"), QLatin1String("pong")); Features specificUnnamedStreamedMediaFeatures; specificUnnamedStreamedMediaFeatures.insert(Feature(QLatin1String("TestClass"), 1234)); chanFact->addFeaturesFor(ChannelClassSpec::unnamedStreamedMediaCall(otherProps), specificUnnamedStreamedMediaFeatures); specificUnnamedStreamedMediaFeatures |= streamedMediaFeatures; QCOMPARE(chanFact->featuresForStreamedMediaCalls(), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaAudioCall()), streamedMediaAudioFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::streamedMediaVideoCallWithAudio()), streamedMediaAudioFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaCall(otherProps)), specificUnnamedStreamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaAudioCall()), unnamedStreamedMediaAudioFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCall()), streamedMediaFeatures); QCOMPARE(chanFact->featuresFor(ChannelClassSpec::unnamedStreamedMediaVideoCallWithAudio()), unnamedStreamedMediaAudioFeatures); } void TestClientFactories::cleanup() { cleanupImpl(); } void TestClientFactories::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestClientFactories) #include "_gen/client-factories.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/conn-roster-groups-legacy.cpp0000664000175000017500000010055112470405660022605 0ustar jrjr#include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestConnRosterGroupsLegacy : public Test { Q_OBJECT public: TestConnRosterGroupsLegacy(QObject *parent = 0) : Test(parent), mConnService(0), mContactsAddedToGroup(0), mContactsRemovedFromGroup(0) { } protected Q_SLOTS: void onGroupAdded(const QString &group); void onGroupRemoved(const QString &group); void onContactAddedToGroup(const QString &group); void onContactRemovedFromGroup(const QString &group); void expectConnInvalidated(); void expectContact(Tp::PendingOperation*); void exitOnStateSuccess(Tp::ContactListState); private Q_SLOTS: void initTestCase(); void init(); void testGroupsAfterStateChange(); void testIntrospectAfterStateChange(); void testRosterGroups(); void testNotADeathTrap(); void cleanup(); void cleanupTestCase(); private: QString mConnName, mConnPath; ExampleContactListConnection *mConnService; ConnectionPtr mConn; ContactPtr mContact; QString mGroupAdded; QString mGroupRemoved; int mContactsAddedToGroup; int mContactsRemovedFromGroup; bool mConnInvalidated; }; void TestConnRosterGroupsLegacy::onGroupAdded(const QString &group) { mGroupAdded = group; mLoop->exit(0); } void TestConnRosterGroupsLegacy::onGroupRemoved(const QString &group) { mGroupRemoved = group; mLoop->exit(0); } void TestConnRosterGroupsLegacy::onContactAddedToGroup(const QString &group) { mContactsAddedToGroup++; mLoop->exit(0); } void TestConnRosterGroupsLegacy::onContactRemovedFromGroup(const QString &group) { mContactsRemovedFromGroup++; mLoop->exit(0); } void TestConnRosterGroupsLegacy::expectConnInvalidated() { mConnInvalidated = true; mLoop->exit(0); } void TestConnRosterGroupsLegacy::expectContact(Tp::PendingOperation *op) { PendingContacts *contacts = qobject_cast(op); QVERIFY(contacts != 0); QVERIFY(contacts->isValid()); QCOMPARE(contacts->contacts().length(), 1); mContact = contacts->contacts()[0]; mLoop->exit(0); } void TestConnRosterGroupsLegacy::exitOnStateSuccess(Tp::ContactListState state) { qDebug() << "got contact list state" << state; if (state == ContactListStateSuccess) { mLoop->exit(0); } } void TestConnRosterGroupsLegacy::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("conn-roster-groups"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); } void TestConnRosterGroupsLegacy::init() { gchar *name; gchar *connPath; GError *error = 0; mConnService = EXAMPLE_CONTACT_LIST_CONNECTION(g_object_new( EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, "account", "me@example.com", "simulation-delay", 0, "protocol", "example-contact-list", NULL)); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService), "foo", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); mConnName = QLatin1String(name); mConnPath = QLatin1String(connPath); g_free(name); g_free(connPath); initImpl(); mConnInvalidated = false; } void TestConnRosterGroupsLegacy::testGroupsAfterStateChange() { // Create a conn and make the roster groups related features ready mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); ContactManagerPtr contactManager = mConn->contactManager(); Features features = Features() << Connection::FeatureRoster << Connection::FeatureRosterGroups; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), true); // Now start connecting it, and wait for the ContactManager state to turn to Success QVERIFY(connect(contactManager.data(), SIGNAL(stateChanged(Tp::ContactListState)), SLOT(exitOnStateSuccess(Tp::ContactListState)))); mConn->lowlevel()->requestConnect(); QCOMPARE(mLoop->exec(), 0); QCOMPARE(static_cast(contactManager->state()), static_cast(ContactListStateSuccess)); // The conn should be valid and have the roster groups features ready when it emits Success QVERIFY(mConn->isValid()); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), true); // We should have all the group data downloaded now, check for that QStringList expectedGroups; expectedGroups << QLatin1String("Cambridge") << QLatin1String("Francophones") << QLatin1String("Montreal"); expectedGroups.sort(); QStringList groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); // Cambridge { QStringList expectedContacts; expectedContacts << QLatin1String("geraldine@example.com") << QLatin1String("helen@example.com") << QLatin1String("guillaume@example.com") << QLatin1String("sjoerd@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Cambridge"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } // Francophones { QStringList expectedContacts; expectedContacts << QLatin1String("olivier@example.com") << QLatin1String("geraldine@example.com") << QLatin1String("guillaume@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Francophones"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } // Montreal { QStringList expectedContacts; expectedContacts << QLatin1String("olivier@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Montreal"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } } void TestConnRosterGroupsLegacy::testIntrospectAfterStateChange() { // Create a conn and make the roster feature ready mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); ContactManagerPtr contactManager = mConn->contactManager(); Features features = Features() << Connection::FeatureRoster; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), false); // Now start connecting it, and wait for the ContactManager state to turn to Success QVERIFY(connect(contactManager.data(), SIGNAL(stateChanged(Tp::ContactListState)), SLOT(exitOnStateSuccess(Tp::ContactListState)))); mConn->lowlevel()->requestConnect(); QCOMPARE(mLoop->exec(), 0); QCOMPARE(static_cast(contactManager->state()), static_cast(ContactListStateSuccess)); // The conn should be valid and have the roster feature ready when it emits Success, but not // RosterGroups because we didn't request it QVERIFY(mConn->isValid()); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), false); // We should have roster contacts now, but no groups QVERIFY(!contactManager->allKnownContacts().isEmpty()); QVERIFY(contactManager->allKnownGroups().isEmpty()); // Make RosterGroups ready too features = Features() << Connection::FeatureRosterGroups; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), true); // We should still have the contacts, and the state should be success QVERIFY(!contactManager->allKnownContacts().isEmpty()); QCOMPARE(static_cast(contactManager->state()), static_cast(ContactListStateSuccess)); // We should have all the group data downloaded now, check for that QStringList expectedGroups; expectedGroups << QLatin1String("Cambridge") << QLatin1String("Francophones") << QLatin1String("Montreal"); expectedGroups.sort(); QStringList groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); // Cambridge { QStringList expectedContacts; expectedContacts << QLatin1String("geraldine@example.com") << QLatin1String("helen@example.com") << QLatin1String("guillaume@example.com") << QLatin1String("sjoerd@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Cambridge"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } } void TestConnRosterGroupsLegacy::testRosterGroups() { mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(connect(mConn->lowlevel()->requestConnect(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(), true); QCOMPARE(mConn->status(), ConnectionStatusConnected); Features features = Features() << Connection::FeatureRoster << Connection::FeatureRosterGroups; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(features), true); ContactManagerPtr contactManager = mConn->contactManager(); QStringList expectedGroups; expectedGroups << QLatin1String("Cambridge") << QLatin1String("Francophones") << QLatin1String("Montreal"); expectedGroups.sort(); QStringList groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); // Cambridge { QStringList expectedContacts; expectedContacts << QLatin1String("geraldine@example.com") << QLatin1String("helen@example.com") << QLatin1String("guillaume@example.com") << QLatin1String("sjoerd@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Cambridge"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } // Francophones { QStringList expectedContacts; expectedContacts << QLatin1String("olivier@example.com") << QLatin1String("geraldine@example.com") << QLatin1String("guillaume@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Francophones"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } // Montreal { QStringList expectedContacts; expectedContacts << QLatin1String("olivier@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Montreal"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } QString group(QLatin1String("foo")); QVERIFY(contactManager->groupContacts(group).isEmpty()); // add group foo QVERIFY(connect(contactManager.data(), SIGNAL(groupAdded(const QString&)), SLOT(onGroupAdded(const QString&)))); QVERIFY(connect(contactManager->addGroup(group), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mGroupAdded.isEmpty()) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mGroupAdded, group); expectedGroups << group; expectedGroups.sort(); groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); // add Montreal contacts to group foo Contacts contacts = contactManager->groupContacts(QLatin1String("Montreal")); Q_FOREACH (const ContactPtr &contact, contacts) { QVERIFY(connect(contact.data(), SIGNAL(addedToGroup(const QString&)), SLOT(onContactAddedToGroup(const QString&)))); } QVERIFY(connect(contactManager->addContactsToGroup(group, contacts.toList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mContactsAddedToGroup != contacts.size()) { QCOMPARE(mLoop->exec(), 0); } Q_FOREACH (const ContactPtr &contact, contacts) { QVERIFY(contact->groups().contains(group)); } // remove all contacts from group foo contacts = contactManager->groupContacts(group); Q_FOREACH (const ContactPtr &contact, contacts) { QVERIFY(connect(contact.data(), SIGNAL(removedFromGroup(const QString&)), SLOT(onContactRemovedFromGroup(const QString&)))); } QVERIFY(connect(contactManager->removeContactsFromGroup(group, contacts.toList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mContactsRemovedFromGroup != contacts.size()) { QCOMPARE(mLoop->exec(), 0); } Q_FOREACH (const ContactPtr &contact, contacts) { QVERIFY(!contact->groups().contains(group)); } // add group foo QVERIFY(connect(contactManager.data(), SIGNAL(groupRemoved(const QString&)), SLOT(onGroupRemoved(const QString&)))); QVERIFY(connect(contactManager->removeGroup(group), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mGroupRemoved.isEmpty()) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mGroupRemoved, group); expectedGroups.removeOne(group); expectedGroups.sort(); groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); } /** * Verify that ContactManager isn't a death-trap. * * Background: Connection::contactManager() used to unpredictably waver between NULL and the real * manager when the connection was in the process of being disconnected / otherwise invalidated, * which led to a great many segfaults, which was especially unfortunate considering the * ContactManager methods didn't do much any checks at all. */ void TestConnRosterGroupsLegacy::testNotADeathTrap() { mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); // Check that the contact manager doesn't crash, but returns an error (because the conn isn't // ready) QVERIFY(!mConn->contactManager().isNull()); QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->lowlevel()->requestConnect(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(), true); QCOMPARE(mConn->status(), ConnectionStatusConnected); // As the conn is now ready, the contact building functions shouldn't return an error now QVERIFY(!mConn->contactManager().isNull()); QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->contactsForHandles(UIntList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->upgradeContacts(QList(), Features()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // In fact, let's build a contact for future use QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers( QStringList() << QLatin1String("friendorfoe@example.com")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectContact(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mContact->id() == QLatin1String("friendorfoe@example.com")); // Roster operations SHOULD still fail though, as FeatureRoster isn't ready QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription( QList() << mContact, QLatin1String("I just want to see you fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresenceSubscription( QList() << mContact, QLatin1String("I just want to see you fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->authorizePresencePublication( QList() << mContact, QLatin1String("I just want to see you fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresencePublication( QList() << mContact, QLatin1String("I just want to see you fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->blockContacts(QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Now, make Roster ready Features features = Features() << Connection::FeatureRoster; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(features), true); // The roster functions should work now QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mContact->subscriptionState() != Contact::PresenceStateNo); QVERIFY(connect(mConn->contactManager()->removePresenceSubscription( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mContact->subscriptionState(), Contact::PresenceStateNo); QVERIFY(connect(mConn->contactManager()->authorizePresencePublication( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresencePublication( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // The test CM doesn't support block, so it will never be successful // ... but still not the RosterGroup ones QVERIFY(connect(mConn->contactManager()->addGroup(QLatin1String("Those who failed")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeGroup(QLatin1String("Those who failed")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->addContactsToGroup(QLatin1String("Those who failed"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeContactsFromGroup(QLatin1String("Those who failed"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Make RosterGroups ready too features = Features() << Connection::FeatureRosterGroups; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(features), true); // Now that Core, Roster and RosterGroups are all ready, everything should work QVERIFY(!mConn->contactManager().isNull()); QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->contactsForHandles(UIntList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->upgradeContacts(QList(), Features()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mContact->subscriptionState() != Contact::PresenceStateNo); QVERIFY(connect(mConn->contactManager()->removePresenceSubscription( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mContact->subscriptionState(), Contact::PresenceStateNo); QVERIFY(connect(mConn->contactManager()->authorizePresencePublication( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresencePublication( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // The test CM doesn't support block, so it will never be successful QVERIFY(connect(mConn->contactManager()->addGroup(QLatin1String("My successful entourage")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); qDebug() << "waiting for group to be added"; // FIXME: Remove this once fd.o #29728 is fixed while (!mConn->contactManager()->allKnownGroups().contains(QLatin1String("My successful entourage"))) { mLoop->processEvents(); } qDebug() << "group has been added"; QVERIFY(connect(mConn->contactManager()->addContactsToGroup(QLatin1String("My successful entourage"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeContactsFromGroup(QLatin1String("My successful entourage"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeGroup(QLatin1String("My successful entourage")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Now, invalidate the connection by disconnecting it QVERIFY(connect(mConn.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), SLOT(expectConnInvalidated()))); mConn->lowlevel()->requestDisconnect(); // Check that contactManager doesn't go NULL in the process of the connection going invalidated do { QVERIFY(!mConn->contactManager().isNull()); mLoop->processEvents(); } while (!mConnInvalidated); QVERIFY(!mConn->isValid()); QCOMPARE(mConn->status(), ConnectionStatusDisconnected); // Now that the conn is invalidated NOTHING should work anymore QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->contactsForHandles(UIntList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->upgradeContacts(QList(), Features()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription(QList(), QLatin1String("You fail at life")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresenceSubscription(QList(), QLatin1String("You fail at life")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->authorizePresencePublication(QList(), QLatin1String("You fail at life")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresencePublication(QList(), QLatin1String("You fail at life")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->blockContacts(QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->addGroup(QLatin1String("Future failures")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeGroup(QLatin1String("Future failures")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->addContactsToGroup(QLatin1String("Future failures"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeContactsFromGroup(QLatin1String("Future failures"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); } void TestConnRosterGroupsLegacy::cleanup() { mContact.reset(); if (mConn && mConn->requestedFeatures().contains(Connection::FeatureCore)) { QVERIFY(mConnService != NULL); if (TP_BASE_CONNECTION(mConnService)->status != TP_CONNECTION_STATUS_DISCONNECTED) { tp_base_connection_change_status(TP_BASE_CONNECTION(mConnService), TP_CONNECTION_STATUS_DISCONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); } while (mConn->isValid()) { mLoop->processEvents(); } } mConn.reset(); if (mConnService != 0) { g_object_unref(mConnService); mConnService = 0; } cleanupImpl(); } void TestConnRosterGroupsLegacy::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestConnRosterGroupsLegacy) #include "_gen/conn-roster-groups-legacy.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/account-set.cpp0000664000175000017500000003702512470405660020007 0ustar jrjr#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestAccountSet : public Test { Q_OBJECT public: TestAccountSet(QObject *parent = 0) : Test(parent), mConn(0) { } protected Q_SLOTS: void onAccountAdded(const Tp::AccountPtr &); void onAccountRemoved(const Tp::AccountPtr &); void onCreateAccountFinished(Tp::PendingOperation *op); private Q_SLOTS: void initTestCase(); void init(); void testBasics(); void testFilters(); void cleanup(); void cleanupTestCase(); private: void createAccount(const char *cmName, const char *protocolName, const char *displayName, const QVariantMap ¶meters); void removeAccount(const AccountPtr &acc); QStringList pathsForAccounts(const QList &list); QStringList pathsForAccounts(const Tp::AccountSetPtr &set); AccountManagerPtr mAM; TestConnHelper *mConn; AccountPtr mAccountCreated; AccountPtr mAccountAdded; AccountPtr mAccountRemoved; }; void TestAccountSet::onAccountAdded(const Tp::AccountPtr &acc) { Q_UNUSED(acc); mAccountAdded = acc; qDebug() << "ACCOUNT ADDED:" << acc->objectPath(); } void TestAccountSet::onAccountRemoved(const Tp::AccountPtr &acc) { Q_UNUSED(acc); mAccountRemoved = acc; qDebug() << "ACCOUNT REMOVED:" << acc->objectPath(); } void TestAccountSet::onCreateAccountFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingAccount *pa = qobject_cast(op); mAccountCreated = pa->account(); // the account should appear in the valid accounts set first, so mAccountAdded must be non-null QVERIFY(mAccountAdded); QVERIFY(mAccountCreated); qDebug() << "ACCOUNT CREATED:" << mAccountAdded->objectPath(); mLoop->exit(0); } void TestAccountSet::createAccount(const char *cmName, const char *protocolName, const char *displayName, const QVariantMap ¶meters) { AccountSetPtr accounts = mAM->validAccounts(); // AccountSet listen to AM::newAccount to check for accounts matching its filter. // // PendingAccount calls AM.CreateAccount and waits for the call to finish. // Once the call is finished, if everything is fine, it checks if the account was already added // to the AM or waits till it gets added by connecting to AM::newAccount. // Once the newly created account appears in the AM, it signals PendingAccount::finished. // // So the signal ordering depends on whether the PendingAccount was created before the // AccountSet or not. // // In this case where we are creating the AccountSet before calling Am::createAccount, // the account will first appear in the set via AccountSet::accountAdded and after that the // PendingAccount operation will finish. mAccountCreated.reset(); mAccountAdded.reset(); QVERIFY(connect(accounts.data(), SIGNAL(accountAdded(Tp::AccountPtr)), SLOT(onAccountAdded(Tp::AccountPtr)))); PendingAccount *pacc = mAM->createAccount(QLatin1String(cmName), QLatin1String(protocolName), QLatin1String(displayName), parameters); QVERIFY(connect(pacc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(onCreateAccountFinished(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); // check that the added account is the same one that was created QCOMPARE(mAccountAdded, mAccountCreated); } void TestAccountSet::removeAccount(const AccountPtr &acc) { QCOMPARE(acc->isValid(), true); AccountSetPtr accounts = mAM->validAccounts(); QVERIFY(accounts->accounts().contains(acc)); int oldAccountsCount = accounts->accounts().size(); QVERIFY(connect(accounts.data(), SIGNAL(accountRemoved(Tp::AccountPtr)), SLOT(onAccountRemoved(Tp::AccountPtr)))); QVERIFY(connect(acc->remove(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); // wait the account to disappear from the set while (accounts->accounts().size() != oldAccountsCount - 1) { processDBusQueue(mConn->client().data()); QCOMPARE(mLoop->exec(), 0); } QCOMPARE(acc->isValid(), false); QCOMPARE(acc->invalidationReason(), TP_QT_ERROR_OBJECT_REMOVED); } QStringList TestAccountSet::pathsForAccounts(const QList &list) { QStringList ret; Q_FOREACH (const AccountPtr &account, list) { ret << account->objectPath(); } return ret; } QStringList TestAccountSet::pathsForAccounts(const Tp::AccountSetPtr &set) { QStringList ret; Q_FOREACH (const AccountPtr &account, set->accounts()) { ret << account->objectPath(); } return ret; } void TestAccountSet::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("account-set"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mAM = AccountManager::create(AccountFactory::create(QDBusConnection::sessionBus(), Account::FeatureCore | Account::FeatureCapabilities)); QCOMPARE(mAM->isReady(), false); QVERIFY(connect(mAM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAM->isReady(), true); QCOMPARE(mAM->allAccounts().isEmpty(), true); mConn = new TestConnHelper(this, EXAMPLE_TYPE_ECHO_2_CONNECTION, "account", "me@example.com", "protocol", "echo2", NULL); QCOMPARE(mConn->connect(), true); } void TestAccountSet::init() { mAccountAdded.reset(); mAccountRemoved.reset(); initImpl(); } void TestAccountSet::testBasics() { AccountSetPtr validAccounts = mAM->validAccounts(); // create and remove the same account twice to check whether AccountSet::accountAdded/Removed is // properly emitted and the account becomes invalid after being removed for (int i = 0; i < 2; ++i) { // create the account QVariantMap parameters; parameters[QLatin1String("account")] = QLatin1String("foobar"); createAccount("foo", "bar", "foobar", parameters); // check that the account is properly created and added to the set of valid accounts QCOMPARE(validAccounts->accounts().size(), 1); QStringList paths = QStringList() << QLatin1String("/org/freedesktop/Telepathy/Account/foo/bar/Account0"); QCOMPARE(pathsForAccounts(validAccounts), paths); QCOMPARE(pathsForAccounts(mAM->invalidAccounts()), QStringList()); QCOMPARE(pathsForAccounts(mAM->allAccounts()), paths); QCOMPARE(mAM->allAccounts(), validAccounts->accounts()); // remove the account AccountPtr acc = validAccounts->accounts().first(); QVERIFY(acc); removeAccount(acc); // check that the account is properly invalidated and removed from the set QCOMPARE(validAccounts->accounts().size(), 0); QCOMPARE(pathsForAccounts(validAccounts), QStringList()); QCOMPARE(pathsForAccounts(mAM->invalidAccounts()), QStringList()); QCOMPARE(pathsForAccounts(mAM->allAccounts()), QStringList()); QCOMPARE(mAM->allAccounts(), validAccounts->accounts()); } } void TestAccountSet::testFilters() { QVariantMap parameters; parameters[QLatin1String("account")] = QLatin1String("foobar"); createAccount("foo", "bar", "foobar", parameters); QCOMPARE(mAM->allAccounts().size(), 1); QCOMPARE(mAM->validAccounts()->accounts().size(), 1); AccountPtr fooAcc = mAM->allAccounts()[0]; parameters.clear(); parameters[QLatin1String("account")] = QLatin1String("spuriousnormal"); createAccount("spurious", "normal", "spuriousnormal", parameters); QCOMPARE(mAM->allAccounts().size(), 2); QCOMPARE(mAM->validAccounts()->accounts().size(), 2); AccountPtr spuriousAcc = *(mAM->allAccounts().toSet() -= fooAcc).begin(); Tp::AccountSetPtr filteredAccountSet; { QVariantMap filter; filter.insert(QLatin1String("protocolName"), QLatin1String("bar")); filteredAccountSet = AccountSetPtr(new AccountSet(mAM, filter)); QCOMPARE(filteredAccountSet->accounts().size(), 1); QVERIFY(filteredAccountSet->accounts().contains(fooAcc)); filter.clear(); filter.insert(QLatin1String("protocolName"), QLatin1String("normal")); filteredAccountSet = AccountSetPtr(new AccountSet(mAM, filter)); QCOMPARE(filteredAccountSet->accounts().size(), 1); QVERIFY(filteredAccountSet->accounts().contains(spuriousAcc)); } { QList filterChain; AccountPropertyFilterPtr cmNameFilter0 = AccountPropertyFilter::create(); cmNameFilter0->addProperty(QLatin1String("cmName"), QLatin1String("foo")); AccountPropertyFilterPtr cmNameFilter1 = AccountPropertyFilter::create(); cmNameFilter1->addProperty(QLatin1String("cmName"), QLatin1String("spurious")); filterChain.append(cmNameFilter0); filterChain.append(cmNameFilter1); filteredAccountSet = AccountSetPtr(new AccountSet(mAM, OrFilter::create(filterChain))); QCOMPARE(filteredAccountSet->accounts().size(), 2); QVERIFY(filteredAccountSet->accounts().contains(fooAcc)); QVERIFY(filteredAccountSet->accounts().contains(spuriousAcc)); } { QList filterChain; AccountPropertyFilterPtr cmNameFilter = AccountPropertyFilter::create(); cmNameFilter->addProperty(QLatin1String("cmName"), QLatin1String("foo")); AccountCapabilityFilterPtr capsFilter = AccountCapabilityFilter::create(); capsFilter->addRequestableChannelClassSubset(RequestableChannelClassSpec::textChat()); filterChain.append(cmNameFilter); filterChain.append(capsFilter); filteredAccountSet = AccountSetPtr(new AccountSet(mAM, AndFilter::create(filterChain))); QCOMPARE(filteredAccountSet->accounts().size(), 0); filteredAccountSet = AccountSetPtr(new AccountSet(mAM, OrFilter::create(filterChain))); QCOMPARE(filteredAccountSet->accounts().size(), 2); QVERIFY(filteredAccountSet->accounts().contains(fooAcc)); QVERIFY(filteredAccountSet->accounts().contains(spuriousAcc)); filterChain.clear(); cmNameFilter = AccountPropertyFilter::create(); cmNameFilter->addProperty(QLatin1String("cmName"), QLatin1String("spurious")); capsFilter = AccountCapabilityFilter::create(); capsFilter->setRequestableChannelClassesSubset( RequestableChannelClassSpecList() << RequestableChannelClassSpec::textChat()); filterChain.append(cmNameFilter); filterChain.append(capsFilter); filteredAccountSet = AccountSetPtr(new AccountSet(mAM, AndFilter::create(filterChain))); QCOMPARE(filteredAccountSet->accounts().size(), 1); QVERIFY(filteredAccountSet->accounts().contains(spuriousAcc)); filteredAccountSet = AccountSetPtr(new AccountSet(mAM, NotFilter::create(AndFilter::create(filterChain)))); QCOMPARE(filteredAccountSet->accounts().size(), 1); QVERIFY(filteredAccountSet->accounts().contains(fooAcc)); } { // should not match as allowedProperties has TargetFoo that is not allowed RequestableChannelClassList rccs; RequestableChannelClass rcc; rcc.fixedProperties.insert( TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); rcc.fixedProperties.insert( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetFoo")); rccs.append(rcc); filteredAccountSet = AccountSetPtr(new AccountSet(mAM, AccountCapabilityFilter::create(rccs))); QCOMPARE(filteredAccountSet->accounts().isEmpty(), true); } { // let's change a property and see AccountSetPtr enabledAccounts = mAM->enabledAccounts(); QVERIFY(connect(enabledAccounts.data(), SIGNAL(accountRemoved(Tp::AccountPtr)), SLOT(onAccountRemoved(Tp::AccountPtr)))); AccountSetPtr disabledAccounts = mAM->disabledAccounts(); QVERIFY(connect(disabledAccounts.data(), SIGNAL(accountAdded(Tp::AccountPtr)), SLOT(onAccountAdded(Tp::AccountPtr)))); QCOMPARE(enabledAccounts->accounts().size(), 2); QCOMPARE(disabledAccounts->accounts().size(), 0); QVERIFY(connect(fooAcc->setEnabled(false), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (fooAcc->isEnabled() != false) { mLoop->processEvents(); } processDBusQueue(mConn->client().data()); QVERIFY(mAccountAdded); QVERIFY(mAccountRemoved); QCOMPARE(mAccountAdded, mAccountRemoved); QCOMPARE(enabledAccounts->accounts().size(), 1); QVERIFY(enabledAccounts->accounts().contains(spuriousAcc)); QCOMPARE(disabledAccounts->accounts().size(), 1); QVERIFY(disabledAccounts->accounts().contains(fooAcc)); } { QCOMPARE(mAM->invalidAccounts()->accounts().size(), 0); QCOMPARE(mAM->onlineAccounts()->accounts().size(), 0); QCOMPARE(mAM->offlineAccounts()->accounts().size(), 2); QCOMPARE(mAM->textChatAccounts()->accounts().size(), 1); QVERIFY(mAM->textChatAccounts()->accounts().contains(spuriousAcc)); QCOMPARE(mAM->textChatroomAccounts()->accounts().size(), 0); QCOMPARE(mAM->streamedMediaCallAccounts()->accounts().size(), 0); QCOMPARE(mAM->streamedMediaAudioCallAccounts()->accounts().size(), 0); QCOMPARE(mAM->streamedMediaVideoCallAccounts()->accounts().size(), 0); QCOMPARE(mAM->streamedMediaVideoCallWithAudioAccounts()->accounts().size(), 0); QCOMPARE(mAM->fileTransferAccounts()->accounts().size(), 0); QCOMPARE(mAM->accountsByProtocol(QLatin1String("bar"))->accounts().size(), 1); QVERIFY(mAM->accountsByProtocol(QLatin1String("bar"))->accounts().contains(fooAcc)); QCOMPARE(mAM->accountsByProtocol(QLatin1String("normal"))->accounts().size(), 1); QVERIFY(mAM->accountsByProtocol(QLatin1String("normal"))->accounts().contains(spuriousAcc)); QCOMPARE(mAM->accountsByProtocol(QLatin1String("noname"))->accounts().size(), 0); } } void TestAccountSet::cleanup() { cleanupImpl(); } void TestAccountSet::cleanupTestCase() { if (mConn) { QCOMPARE(mConn->disconnect(), true); delete mConn; } cleanupTestCaseImpl(); } QTEST_MAIN(TestAccountSet) #include "_gen/account-set.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/properties.cpp0000664000175000017500000000675412470405660017763 0ustar jrjr#include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include using namespace Tp; class TestProperties : public Test { Q_OBJECT public: TestProperties(QObject *parent = 0) : Test(parent), mConnService(0) { } private Q_SLOTS: void initTestCase(); void init(); void testPropertiesMonitoring(); void cleanup(); void cleanupTestCase(); private: QString mConnName, mConnPath; TpTestsContactsConnection *mConnService; Client::ConnectionInterface *mConn; }; void TestProperties::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("properties"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); } void TestProperties::init() { initImpl(); gchar *name; gchar *connPath; GError *error = 0; mConnService = TP_TESTS_CONTACTS_CONNECTION(g_object_new( TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "contacts", NULL)); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService), "contacts", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); mConnName = QLatin1String(name); mConnPath = QLatin1String(connPath); g_free(name); g_free(connPath); mConn = new Client::ConnectionInterface(mConnName, mConnPath, this); QVERIFY(mConn->isValid()); } void TestProperties::testPropertiesMonitoring() { QCOMPARE(mConn->isMonitoringProperties(), false); mConn->setMonitorProperties(true); QSignalSpy spy(mConn, SIGNAL(propertiesChanged(QVariantMap,QStringList))); connect(mConn, SIGNAL(propertiesChanged(QVariantMap,QStringList)), mLoop, SLOT(quit())); GHashTable *changed = tp_asv_new( "test-prop", G_TYPE_STRING, "I am actually different than I used to be.", "test-again", G_TYPE_UINT, 0xff0000ffU, NULL ); tp_svc_dbus_properties_emit_properties_changed (mConnService, "a.random.interface", changed, NULL); tp_svc_dbus_properties_emit_properties_changed (mConnService, mConn->interface().toLatin1().data(), changed, NULL); QCOMPARE(spy.count(), 0); mLoop->exec(); QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); QVERIFY(arguments.at(0).type() == QVariant::Map); QVERIFY(arguments.at(1).type() == QVariant::StringList); QVariantMap resultMap = arguments.at(0).toMap(); QCOMPARE(resultMap.size(), 2); QCOMPARE(resultMap[QLatin1String("test-prop")].toString(), QLatin1String("I am actually different than I used to be.")); QCOMPARE(resultMap[QLatin1String("test-again")].toUInt(), 0xff0000ffU); QCOMPARE(spy.count(), 0); g_hash_table_destroy (changed); } void TestProperties::cleanup() { if (mConn) { mConn->deleteLater(); mConn = 0; } if (mConnService != 0) { g_object_unref(mConnService); mConnService = 0; } cleanupImpl(); } void TestProperties::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestProperties) #include "_gen/properties.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/contact-messenger.cpp0000664000175000017500000005351112470405660021201 0ustar jrjr#include #include #include #include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; using namespace Tp::Client; class TestContactMessenger; class CDMessagesAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ChannelDispatcher.Interface.Messages1") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: CDMessagesAdaptor(const QDBusConnection &bus, TestContactMessenger *test, QObject *parent) : QDBusAbstractAdaptor(parent), test(test), mBus(bus) { } virtual ~CDMessagesAdaptor() { } void setSimulatedSendError(const QString &error) { mSimulatedSendError = error; } public Q_SLOTS: // Methods QString SendMessage(const QDBusObjectPath &account, const QString &targetID, const Tp::MessagePartList &message, uint flags); private: TestContactMessenger *test; QDBusConnection mBus; QString mSimulatedSendError; }; class AccountAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Account") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QDBusObjectPath Connection READ Connection) Q_PROPERTY(QStringList Interfaces READ Interfaces) public: AccountAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent), mConnection(QLatin1String("/")) { } virtual ~AccountAdaptor() { } void setConnection(QString conn) { if (conn.isEmpty()) { conn = QLatin1String("/"); } mConnection = QDBusObjectPath(conn); QVariantMap props; props.insert(QLatin1String("Connection"), QVariant::fromValue(mConnection)); Q_EMIT AccountPropertyChanged(props); } public: // Properties inline QDBusObjectPath Connection() const { return mConnection; } inline QStringList Interfaces() const { return QStringList(); } Q_SIGNALS: // Signals void AccountPropertyChanged(const QVariantMap &properties); private: QDBusObjectPath mConnection; }; class Dispatcher : public QObject, public QDBusContext { Q_OBJECT; public: Dispatcher(QObject *parent) : QObject(parent) { } ~Dispatcher() { } }; class TestContactMessenger : public Test { Q_OBJECT public: TestContactMessenger(QObject *parent = 0) : Test(parent), mCDMessagesAdaptor(0), mAccountAdaptor(0), // service side (telepathy-glib) mConnService(0), mBaseConnService(0), mContactRepo(0), mSendFinished(false), mGotMessageSent(false) { } protected Q_SLOTS: void expectPendingContactsFinished(Tp::PendingOperation *op); void onSendFinished(Tp::PendingOperation *); void onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken, const Tp::TextChannelPtr &channel); void onMessageReceived(const Tp::ReceivedMessage &message, const Tp::TextChannelPtr &channel); private Q_SLOTS: void initTestCase(); void init(); void testNoSupport(); void testObserverRegistration(); void testSimpleSend(); void testReceived(); void testReceivedFromContact(); void cleanup(); void cleanupTestCase(); private: friend class CDMessagesAdaptor; QList ourObservers(); CDMessagesAdaptor *mCDMessagesAdaptor; AccountAdaptor *mAccountAdaptor; QString mAccountBusName, mAccountPath; AccountManagerPtr mAM; AccountPtr mAccount; ConnectionPtr mConn; TextChannelPtr mChan; TpTestsContactsConnection *mConnService; TpBaseConnection *mBaseConnService; TpHandleRepoIface *mContactRepo; ExampleEcho2Channel *mMessagesChanService; QString mConnName; QString mConnPath; QString mMessagesChanPath; bool mSendFinished, mGotMessageSent, mGotMessageReceived; QString mSendError, mSendToken, mMessageSentText, mMessageSentToken, mMessageSentChannel; QString mMessageReceivedText; ChannelPtr mMessageReceivedChan; QList mContacts; }; QString CDMessagesAdaptor::SendMessage(const QDBusObjectPath &account, const QString &targetID, const MessagePartList &message, uint flags) { if (!mSimulatedSendError.isEmpty()) { dynamic_cast(QObject::parent())->sendErrorReply(mSimulatedSendError, QLatin1String("Let's pretend this interface and method don't exist, shall we?")); return QString(); } /* * Sadly, the QDBus local-loop "optimization" prevents us from correctly waiting for the * ObserveChannels call to return, and consequently prevents us from knowing when we can call * Send, knowing that the observer has connected to the message sent signal. * * The real MC doesn't have this limitation because it actually really calls and waits our * ObserveChannels method to finish, unlike dear QDBus here. */ QList observers = test->ourObservers(); Q_FOREACH(ClientObserverInterface *iface, observers) { ChannelDetails chan = { QDBusObjectPath(test->mChan->objectPath()), test->mChan->immutableProperties() }; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(iface->ObserveChannels( QDBusObjectPath(test->mAccount->objectPath()), QDBusObjectPath(test->mChan->connection()->objectPath()), ChannelDetailsList() << chan, QDBusObjectPath(QLatin1String("/")), Tp::ObjectPathList(), QVariantMap())); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), test->mLoop, SLOT(quit())); test->mLoop->exec(); QDBusPendingReply reply = *watcher; qDebug() << reply.error(); // Always gives out "local-loop messages can't have delayed replies" delete watcher; } qDebug() << "Calling send"; // And this is always called before the observer manages to connect to messageSent. Bummer. PendingSendMessage *msg = test->mChan->send(message, static_cast(flags)); connect(msg, SIGNAL(finished(Tp::PendingOperation*)), test, SLOT(expectSuccessfulCall(Tp::PendingOperation*))); test->mLoop->exec(); return msg->sentMessageToken(); } void TestContactMessenger::expectPendingContactsFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingContacts *pending = qobject_cast(op); mContacts = pending->contacts(); mLoop->exit(0); } void TestContactMessenger::onSendFinished(Tp::PendingOperation *op) { PendingSendMessage *msg = qobject_cast(op); QVERIFY(msg != NULL); if (msg->isValid()) { qDebug() << "Send succeeded, got token" << msg->sentMessageToken(); mSendToken = msg->sentMessageToken(); } else { qDebug() << "Send failed, got error" << msg->errorName(); mSendError = msg->errorName(); } mSendFinished = true; } void TestContactMessenger::onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken, const Tp::TextChannelPtr &channel) { qDebug() << "Got ContactMessenger::messageSent()"; mGotMessageSent = true; mMessageSentToken = sentMessageToken; mMessageSentText = message.text(); } void TestContactMessenger::onMessageReceived(const Tp::ReceivedMessage &message, const Tp::TextChannelPtr &channel) { qDebug() << "Got ContactMessenger::messageReceived()"; mGotMessageReceived = true; mMessageReceivedText = message.text(); mMessageReceivedChan = channel; } void TestContactMessenger::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("contact-messenger"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); QDBusConnection bus = QDBusConnection::sessionBus(); QString channelDispatcherBusName = TP_QT_IFACE_CHANNEL_DISPATCHER; QString channelDispatcherPath = QLatin1String("/org/freedesktop/Telepathy/ChannelDispatcher"); Dispatcher *dispatcher = new Dispatcher(this); mCDMessagesAdaptor = new CDMessagesAdaptor(bus, this, dispatcher); QVERIFY(bus.registerService(channelDispatcherBusName)); QVERIFY(bus.registerObject(channelDispatcherPath, dispatcher)); mAccountBusName = TP_QT_IFACE_ACCOUNT_MANAGER; mAccountPath = QLatin1String("/org/freedesktop/Telepathy/Account/simple/simple/account"); QObject *acc = new QObject(this); mAccountAdaptor = new AccountAdaptor(acc); QVERIFY(bus.registerService(mAccountBusName)); QVERIFY(bus.registerObject(mAccountPath, acc)); mAccount = Account::create(mAccountBusName, mAccountPath); QVERIFY(connect(mAccount->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAccount->isReady(), true); QCOMPARE(mAccount->supportsRequestHints(), false); QCOMPARE(mAccount->requestsSucceedWithChannel(), false); mConnService = TP_TESTS_CONTACTS_CONNECTION(g_object_new( TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "example", NULL)); QVERIFY(mConnService != 0); mBaseConnService = TP_BASE_CONNECTION(mConnService); QVERIFY(mBaseConnService != 0); gchar *name, *connPath; GError *error = NULL; QVERIFY(tp_base_connection_register(mBaseConnService, "example", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); mConnName = QLatin1String(name); mConnPath = QLatin1String(connPath); g_free(name); g_free(connPath); mAccountAdaptor->setConnection(mConnPath); mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); QVERIFY(connect(mConn->lowlevel()->requestConnect(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(), true); QCOMPARE(static_cast(mConn->status()), static_cast(ConnectionStatusConnected)); mContactRepo = tp_base_connection_get_handles(mBaseConnService, TP_HANDLE_TYPE_CONTACT); guint handle = tp_handle_ensure(mContactRepo, "Ann", 0, 0); mMessagesChanPath = mConnPath + QLatin1String("/MessagesChannel"); QByteArray chanPath = mMessagesChanPath.toLatin1(); mMessagesChanService = EXAMPLE_ECHO_2_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_2_CHANNEL, "connection", mConnService, "object-path", chanPath.data(), "handle", handle, NULL)); QVariantMap immutableProperties; immutableProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), QLatin1String("ann")); mChan = TextChannel::create(mConn, mMessagesChanPath, immutableProperties); QVERIFY(connect(mChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); } void TestContactMessenger::init() { initImpl(); mSendFinished = false; mGotMessageSent = false; mGotMessageReceived = false; mCDMessagesAdaptor->setSimulatedSendError(QString()); } void TestContactMessenger::testNoSupport() { // We should give a descriptive error message if the CD doesn't actually support sending // messages using the new API. NotImplemented should probably be documented for the // sendMessage() methods as an indication that the CD implementation needs to be upgraded. ContactMessengerPtr messenger = ContactMessenger::create(mAccount, QLatin1String("Ann")); QVERIFY(!messenger.isNull()); mCDMessagesAdaptor->setSimulatedSendError(TP_QT_DBUS_ERROR_UNKNOWN_METHOD); PendingSendMessage *pendingSend = messenger->sendMessage(QLatin1String("Hi!")); QVERIFY(pendingSend != NULL); QVERIFY(connect(pendingSend, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pendingSend->isFinished()); QVERIFY(!pendingSend->isValid()); QCOMPARE(pendingSend->errorName(), TP_QT_ERROR_NOT_IMPLEMENTED); // Let's try using the other sendMessage overload similarly as well Message m(ChannelTextMessageTypeAction, QLatin1String("is testing!")); pendingSend = messenger->sendMessage(m.parts()); QVERIFY(pendingSend != NULL); QVERIFY(connect(pendingSend, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pendingSend->isFinished()); QVERIFY(!pendingSend->isValid()); QCOMPARE(pendingSend->errorName(), TP_QT_ERROR_NOT_IMPLEMENTED); } void TestContactMessenger::testObserverRegistration() { ContactMessengerPtr messenger = ContactMessenger::create(mAccount, QLatin1String("Ann")); // At this point, there should be a registered observer for the relevant channel class on our // unique name QList observers = ourObservers(); QVERIFY(!observers.empty()); Q_FOREACH(ClientObserverInterface *observer, observers) { // It shouldn't have recover == true, as it shouldn't be activatable at all, and hence recovery // doesn't make sense for it bool recover; QVERIFY(waitForProperty(observer->requestPropertyRecover(), &recover)); QCOMPARE(recover, true); } // If we destroy our messenger (which is the last/only one for that ID), the observers should go // away, at least in a few mainloop iterations messenger.reset(); QVERIFY(ourObservers().empty()); } void TestContactMessenger::testSimpleSend() { ContactMessengerPtr messenger = ContactMessenger::create(mAccount, QLatin1String("Ann")); QVERIFY(connect(messenger->sendMessage(QLatin1String("Hi!")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onSendFinished(Tp::PendingOperation*)))); while (!mSendFinished) { mLoop->processEvents(); } QVERIFY(mSendError.isEmpty()); } void TestContactMessenger::testReceived() { ContactMessengerPtr messenger = ContactMessenger::create(mAccount, QLatin1String("Ann")); QVERIFY(connect(messenger.data(), SIGNAL(messageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)), SLOT(onMessageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)))); QList observers = ourObservers(); Q_FOREACH(ClientObserverInterface *iface, observers) { ChannelDetails chan = { QDBusObjectPath(mChan->objectPath()), mChan->immutableProperties() }; iface->ObserveChannels( QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mChan->connection()->objectPath()), ChannelDetailsList() << chan, QDBusObjectPath(QLatin1String("/")), Tp::ObjectPathList(), QVariantMap()); } guint handle = tp_handle_ensure(mContactRepo, "Ann", 0, 0); TpMessage *msg = tp_cm_message_new_text(mBaseConnService, handle, TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, "Hi!"); tp_message_mixin_take_received(G_OBJECT(mMessagesChanService), msg); while (!mGotMessageReceived) { mLoop->processEvents(); } QCOMPARE(mMessageReceivedText, QString::fromLatin1("Hi!")); QCOMPARE(mMessageReceivedChan->objectPath(), mChan->objectPath()); } void TestContactMessenger::testReceivedFromContact() { QVERIFY(connect(mAccount->connection()->contactManager()->contactsForIdentifiers( QStringList() << QLatin1String("Ann")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); ContactPtr ann = mContacts.first(); ContactMessengerPtr messenger = ContactMessenger::create(mAccount, ann); QVERIFY(connect(messenger.data(), SIGNAL(messageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)), SLOT(onMessageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)))); QList observers = ourObservers(); Q_FOREACH(ClientObserverInterface *iface, observers) { ChannelDetails chan = { QDBusObjectPath(mChan->objectPath()), mChan->immutableProperties() }; iface->ObserveChannels( QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mChan->connection()->objectPath()), ChannelDetailsList() << chan, QDBusObjectPath(QLatin1String("/")), Tp::ObjectPathList(), QVariantMap()); } guint handle = tp_handle_ensure(mContactRepo, "Ann", 0, 0); TpMessage *msg = tp_cm_message_new_text(mBaseConnService, handle, TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, "Hi!"); tp_message_mixin_take_received(G_OBJECT(mMessagesChanService), msg); while (!mGotMessageReceived) { mLoop->processEvents(); } QCOMPARE(mMessageReceivedText, QString::fromLatin1("Hi!")); QCOMPARE(mMessageReceivedChan->objectPath(), mChan->objectPath()); } void TestContactMessenger::cleanup() { mMessageReceivedChan.reset(); cleanupImpl(); } void TestContactMessenger::cleanupTestCase() { if (mConn) { // Disconnect and wait for the readiness change QVERIFY(connect(mConn->lowlevel()->requestDisconnect(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); if (mConn->isValid()) { QVERIFY(connect(mConn.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), mLoop, SLOT(quit()))); QCOMPARE(mLoop->exec(), 0); } } mChan.reset(); if (mMessagesChanService != 0) { g_object_unref(mMessagesChanService); mMessagesChanService = 0; } if (mConnService != 0) { mBaseConnService = 0; g_object_unref(mConnService); mConnService = 0; } cleanupTestCaseImpl(); } QList TestContactMessenger::ourObservers() { QStringList registeredNames = QDBusConnection::sessionBus().interface()->registeredServiceNames(); QList observers; Q_FOREACH (QString name, registeredNames) { if (!name.startsWith(QLatin1String("org.freedesktop.Telepathy.Client."))) { continue; } if (QDBusConnection::sessionBus().interface()->serviceOwner(name).value() != QDBusConnection::sessionBus().baseService()) { continue; } QString path = QLatin1Char('/') + name; path.replace(QLatin1Char('.'), QLatin1Char('/')); ClientInterface client(name, path); QStringList ifaces; if (!waitForProperty(client.requestPropertyInterfaces(), &ifaces)) { continue; } if (!ifaces.contains(TP_QT_IFACE_CLIENT_OBSERVER)) { continue; } ClientObserverInterface *observer = new ClientObserverInterface(name, path, this); ChannelClassList filter; if (!waitForProperty(observer->requestPropertyObserverChannelFilter(), &filter)) { continue; } Q_FOREACH (ChannelClassSpec spec, filter) { if (spec.isSubsetOf(ChannelClassSpec::textChat())) { observers.push_back(observer); qDebug() << "Found our observer" << name << '\n'; break; } } } return observers; } QTEST_MAIN(TestContactMessenger) #include "_gen/contact-messenger.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/dbus-properties.cpp0000664000175000017500000001212612470405660020704 0ustar jrjr#include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestDBusProperties : public Test { Q_OBJECT public: TestDBusProperties(QObject *parent = 0) : Test(parent), mAccountsCount(0) { } protected Q_SLOTS: void onNewAccount(const Tp::AccountPtr &); void expectSuccessfulAllProperties(Tp::PendingOperation *op); private Q_SLOTS: void initTestCase(); void init(); void testDBusProperties(); void cleanup(); void cleanupTestCase(); private: AccountManagerPtr mAM; int mAccountsCount; bool mCreatingAccount; QVariantMap mAllProperties; }; void TestDBusProperties::onNewAccount(const Tp::AccountPtr &acc) { Q_UNUSED(acc); mAccountsCount++; if (!mCreatingAccount) { mLoop->exit(0); } } void TestDBusProperties::expectSuccessfulAllProperties(PendingOperation *op) { if (op->isError()) { qWarning().nospace() << op->errorName() << ": " << op->errorMessage(); mAllProperties = QVariantMap(); mLoop->exit(1); } else { Tp::PendingVariantMap *pvm = qobject_cast(op); mAllProperties = pvm->result(); mLoop->exit(0); } } void TestDBusProperties::initTestCase() { initTestCaseImpl(); mAM = AccountManager::create(AccountFactory::create(QDBusConnection::sessionBus(), Account::FeatureCore | Account::FeatureCapabilities)); QCOMPARE(mAM->isReady(), false); } void TestDBusProperties::init() { mCreatingAccount = false; initImpl(); } void TestDBusProperties::testDBusProperties() { QVERIFY(connect(mAM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAM->isReady(), true); QVERIFY(connect(mAM.data(), SIGNAL(newAccount(const Tp::AccountPtr &)), SLOT(onNewAccount(const Tp::AccountPtr &)))); QVariantMap parameters; parameters[QLatin1String("account")] = QLatin1String("foobar"); PendingAccount *pacc = mAM->createAccount(QLatin1String("foo"), QLatin1String("bar"), QLatin1String("foobar"), parameters); QVERIFY(connect(pacc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); mCreatingAccount = true; QCOMPARE(mLoop->exec(), 0); mCreatingAccount = false; QVERIFY(pacc->account()); while (mAccountsCount != 1) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mAM->interfaces(), QStringList()); AccountPtr acc = Account::create(mAM->busName(), QLatin1String("/org/freedesktop/Telepathy/Account/foo/bar/Account0")); QVERIFY(connect(acc->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); while (!acc->isReady()) { mLoop->processEvents(); } QCOMPARE(mLoop->exec(), 0); const QString oldDisplayName = QLatin1String("foobar (account 0)"); QCOMPARE(acc->displayName(), oldDisplayName); Client::AccountInterface *cliAccount = acc->interface(); QString currDisplayName; QVERIFY(waitForProperty(cliAccount->requestPropertyDisplayName(), &currDisplayName)); QCOMPARE(currDisplayName, oldDisplayName); QVERIFY(connect(cliAccount->requestAllProperties(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulAllProperties(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAllProperties[QLatin1String("DisplayName")].value(), oldDisplayName); QVERIFY(mAllProperties[QLatin1String("Interfaces")].value().contains( TP_QT_IFACE_ACCOUNT_INTERFACE_AVATAR)); const QString newDisplayName = QLatin1String("Foo bar account"); QVERIFY(connect(cliAccount->setPropertyDisplayName(newDisplayName), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(waitForProperty(cliAccount->requestPropertyDisplayName(), &currDisplayName)); QCOMPARE(currDisplayName, newDisplayName); QVERIFY(connect(cliAccount->requestAllProperties(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulAllProperties(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAllProperties[QLatin1String("DisplayName")].value(), newDisplayName); } void TestDBusProperties::cleanup() { cleanupImpl(); } void TestDBusProperties::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestDBusProperties) #include "_gen/dbus-properties.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/conn-roster.cpp0000664000175000017500000004511312470405660020030 0ustar jrjr#include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestConnRoster : public Test { Q_OBJECT public: TestConnRoster(QObject *parent = 0) : Test(parent), mConn(0), mBlockingContactsFinished(false), mHowManyKnownContacts(0), mGotPresenceStateChanged(false), mGotPPR(false) { } protected Q_SLOTS: void expectBlockingContactsFinished(Tp::PendingOperation *op); void expectBlockStatusChanged(bool blocked); void expectBlockedContactsChanged(const Tp::Contacts &added, const Tp::Contacts &removed, const Tp::Channel::GroupMemberChangeDetails &details); void expectPresencePublicationRequested(const Tp::Contacts &); void expectPresenceStateChanged(Tp::Contact::PresenceState); void expectAllKnownContactsChanged(const Tp::Contacts &added, const Tp::Contacts &removed, const Tp::Channel::GroupMemberChangeDetails &details); private Q_SLOTS: void initTestCase(); void init(); void testRoster(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; QSet mContactsExpectingBlockStatusChange; bool mBlockingContactsFinished; int mHowManyKnownContacts; bool mGotPresenceStateChanged; bool mGotPPR; }; void TestConnRoster::expectBlockingContactsFinished(Tp::PendingOperation *op) { TEST_VERIFY_OP(op); qDebug() << "blocking contacts finished"; mBlockingContactsFinished = true; if (mContactsExpectingBlockStatusChange.isEmpty()) { mLoop->exit(0); } } void TestConnRoster::expectBlockStatusChanged(bool blocked) { Q_UNUSED(blocked); Contact *c = qobject_cast(sender()); QVERIFY(c); ContactPtr contact(c); mContactsExpectingBlockStatusChange.remove(contact->id()); if (mContactsExpectingBlockStatusChange.isEmpty() && mBlockingContactsFinished) { mLoop->exit(0); } } // This connects to allKnownContactsChanged() but it is only used in the last contact blocking test void TestConnRoster::expectBlockedContactsChanged(const Tp::Contacts &added, const Tp::Contacts &removed, const Tp::Channel::GroupMemberChangeDetails &details) { Q_UNUSED(details); Q_FOREACH(const ContactPtr &contact, added) { mContactsExpectingBlockStatusChange.remove(contact->id()); } Q_FOREACH(const ContactPtr &contact, removed) { mContactsExpectingBlockStatusChange.remove(contact->id()); } if (mContactsExpectingBlockStatusChange.isEmpty() && mBlockingContactsFinished) { mLoop->exit(0); } } void TestConnRoster::expectAllKnownContactsChanged(const Tp::Contacts& added, const Tp::Contacts& removed, const Tp::Channel::GroupMemberChangeDetails &details) { qDebug() << added.size() << " contacts added, " << removed.size() << " contacts removed"; mHowManyKnownContacts += added.size(); mHowManyKnownContacts -= removed.size(); if (details.hasMessage()) { QCOMPARE(details.message(), QLatin1String("add me now")); } if (mConn->client()->contactManager()->allKnownContacts().size() != mHowManyKnownContacts) { qWarning() << "Contacts number mismatch! Watched value: " << mHowManyKnownContacts << "allKnownContacts(): " << mConn->client()->contactManager()->allKnownContacts().size(); mLoop->exit(1); } else { mLoop->exit(0); } } void TestConnRoster::expectPresencePublicationRequested(const Tp::Contacts &contacts) { Q_FOREACH(Tp::ContactPtr contact, contacts) { QCOMPARE(static_cast(contact->publishState()), static_cast(Contact::PresenceStateAsk)); } mGotPPR = true; } void TestConnRoster::expectPresenceStateChanged(Contact::PresenceState state) { mGotPresenceStateChanged = true; } void TestConnRoster::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("conn-roster"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create(Contact::FeatureAlias), EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, "account", "me@example.com", "protocol", "contactlist", "simulation-delay", 1, NULL); QCOMPARE(mConn->connect(), true); } void TestConnRoster::init() { initImpl(); } void TestConnRoster::testRoster() { Features features = Features() << Connection::FeatureRoster; QCOMPARE(mConn->enableFeatures(features), true); ContactManagerPtr contactManager = mConn->client()->contactManager(); QCOMPARE(contactManager->state(), ContactListStateSuccess); QStringList toCheck = QStringList() << QLatin1String("sjoerd@example.com") << QLatin1String("travis@example.com") << QLatin1String("wim@example.com") << QLatin1String("olivier@example.com") << QLatin1String("helen@example.com") << QLatin1String("geraldine@example.com") << QLatin1String("guillaume@example.com") << QLatin1String("christian@example.com") << QLatin1String("bill@example.com") << QLatin1String("steve@example.com"); QStringList ids; QList pendingSubscription; QList pendingPublish; Q_FOREACH (const ContactPtr &contact, contactManager->allKnownContacts()) { QVERIFY(contact->requestedFeatures().contains(Contact::FeatureAlias)); qDebug() << " contact:" << contact->id() << "- subscription:" << contact->subscriptionState() << "- publish:" << contact->publishState(); ids << contact->id(); if (contact->subscriptionState() == Contact::PresenceStateAsk) { pendingSubscription.append(contact); } else if (contact->publishState() == Contact::PresenceStateAsk) { pendingPublish.append(contact); } } ids.sort(); toCheck.sort(); QCOMPARE(ids, toCheck); QCOMPARE(pendingSubscription.size(), 2); QCOMPARE(pendingPublish.size(), 2); // Wait for the contacts to be built ids = QStringList() << QString(QLatin1String("john@example.com")) << QString(QLatin1String("mary@example.com")); QList contacts = mConn->contacts(ids); QCOMPARE(contacts.size(), ids.size()); QVERIFY(connect(contactManager.data(), SIGNAL(presencePublicationRequested(Tp::Contacts)), SLOT(expectPresencePublicationRequested(Tp::Contacts)))); int i = 0; Q_FOREACH (const ContactPtr &contact, contacts) { mGotPresenceStateChanged = false; mGotPPR = false; QVERIFY(connect(contact.data(), SIGNAL(subscriptionStateChanged(Tp::Contact::PresenceState)), SLOT(expectPresenceStateChanged(Tp::Contact::PresenceState)))); QVERIFY(connect(contact.data(), SIGNAL(publishStateChanged(Tp::Contact::PresenceState, QString)), SLOT(expectPresenceStateChanged(Tp::Contact::PresenceState)))); if ((i % 2) == 0) { contact->requestPresenceSubscription(QLatin1String("please add me")); } else { contact->requestPresenceSubscription(QLatin1String("add me now")); } while (!mGotPresenceStateChanged && !mGotPPR) { mLoop->processEvents(); } if ((i % 2) == 0) { // I asked to see his presence - he might have already accepted it, though QVERIFY(contact->subscriptionState() == Contact::PresenceStateAsk || contact->subscriptionState() == Contact::PresenceStateYes); // if he accepted it already, one iteration won't be enough as the // first iteration will just flush the subscription -> Yes event while (contact->publishState() != Contact::PresenceStateAsk) { mLoop->processEvents(); } contact->authorizePresencePublication(); while (contact->publishState() != Contact::PresenceStateYes) { mLoop->processEvents(); } // I authorized him to see my presence QCOMPARE(static_cast(contact->publishState()), static_cast(Contact::PresenceStateYes)); // He replied the presence request QCOMPARE(static_cast(contact->subscriptionState()), static_cast(Contact::PresenceStateYes)); contact->removePresenceSubscription(); while (contact->subscriptionState() != Contact::PresenceStateNo) { mLoop->processEvents(); } } else { // I asked to see her presence - she might have already rejected it, though QVERIFY(contact->subscriptionState() == Contact::PresenceStateAsk || contact->subscriptionState() == Contact::PresenceStateNo); // If she didn't already reject it, wait until she does while (contact->subscriptionState() != Contact::PresenceStateNo) { mLoop->processEvents(); } } ++i; // Disconnect the signals so the contacts doing something won't early-exit future mainloop // iterations (the simulation CM does things like - after a delay since we removed them, try // to re-add us - and such, which mess up the test if the simulated network event happens // before we've finished with the next contact) QVERIFY(contact->disconnect(this)); // TODO: The roster API, frankly speaking, seems rather error/race prone, as evidenced by // this test. Should we perhaps change its semantics? Then again, this test also simulates // the remote user accepting/rejecting the request with a quite unpredictable timer delay, // while real-world applications don't do any such assumptions about the timing of the // remote user actions, so most of the problems won't be applicable there. } i = 0; Contact::PresenceState expectedPresenceState; Q_FOREACH (const ContactPtr &contact, pendingPublish) { mGotPresenceStateChanged = false; QVERIFY(connect(contact.data(), SIGNAL(publishStateChanged(Tp::Contact::PresenceState, QString)), SLOT(expectPresenceStateChanged(Tp::Contact::PresenceState)))); if ((i++ % 2) == 0) { expectedPresenceState = Contact::PresenceStateYes; contact->authorizePresencePublication(); } else { expectedPresenceState = Contact::PresenceStateNo; contact->removePresencePublication(); } while (!mGotPresenceStateChanged) { mLoop->processEvents(); } QCOMPARE(static_cast(contact->publishState()), static_cast(expectedPresenceState)); } // Test allKnownContactsChanged. // In this test, everytime a subscription is requested or rejected, allKnownContacts changes // Cache the current value mHowManyKnownContacts = contactManager->allKnownContacts().size(); // Watch for contacts changed QVERIFY(connect(contactManager.data(), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)), SLOT(expectAllKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)))); // Wait for the contacts to be built ids = QStringList() << QString(QLatin1String("kctest1@example.com")) << QString(QLatin1String("kctest2@example.com")); contacts = mConn->contacts(ids); QCOMPARE(contacts.size(), ids.size()); Q_FOREACH (const ContactPtr &contact, contacts) { contact->requestPresenceSubscription(QLatin1String("add me now")); // allKnownContacts is supposed to change here. QCOMPARE(mLoop->exec(), 0); } QVERIFY(disconnect(contactManager.data(), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)), this, SLOT(expectAllKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)))); // verify that the CM supports contact blocking QVERIFY(contactManager->canBlockContacts()); // check if the initially blocked contacts are there ids.clear(); toCheck = QStringList() << QLatin1String("bill@example.com") << QLatin1String("steve@example.com"); Q_FOREACH (const ContactPtr &contact, contactManager->allKnownContacts()) { if (contact->isBlocked()) { qDebug() << "blocked contact:" << contact->id(); ids << contact->id(); } } ids.sort(); toCheck.sort(); QCOMPARE(ids, toCheck); // block all contacts QList contactsList = contactManager->allKnownContacts().toList(); QSet contactIdsList; Q_FOREACH (const ContactPtr &contact, contactsList) { QVERIFY(connect(contact.data(), SIGNAL(blockStatusChanged(bool)), SLOT(expectBlockStatusChanged(bool)))); contactIdsList.insert(contact->id()); } mBlockingContactsFinished = false; mContactsExpectingBlockStatusChange = contactIdsList; // those are already blocked; do not expect their status to change mContactsExpectingBlockStatusChange.remove(QLatin1String("bill@example.com")); mContactsExpectingBlockStatusChange.remove(QLatin1String("steve@example.com")); QVERIFY(connect(contactManager->blockContacts(contactsList), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectBlockingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // verify all contacts have been blocked Q_FOREACH (const ContactPtr &contact, contactsList) { QCOMPARE(contact->isBlocked(), true); QVERIFY(contactManager->allKnownContacts().contains(contact)); } // now remove kctest1 from the server ContactPtr kctest1; Q_FOREACH (const ContactPtr &contact, contactsList) { if (contact->id() == QLatin1String("kctest1@example.com")) { kctest1 = contact; } } QVERIFY(!kctest1.isNull()); QVERIFY(connect(contactManager->removeContacts(QList() << kctest1), SIGNAL(finished(Tp::PendingOperation*)), mLoop, SLOT(quit()))); QCOMPARE(mLoop->exec(), 0); // allKnownContacts must still contain kctest1, since it is in the deny list QVERIFY(contactManager->allKnownContacts().contains(kctest1)); kctest1.reset(); //no longer needed // unblock all contacts mBlockingContactsFinished = false; mContactsExpectingBlockStatusChange = contactIdsList; QVERIFY(connect(contactManager->unblockContacts(contactsList), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectBlockingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // verify all contacts have been unblocked Q_FOREACH (const ContactPtr &contact, contactsList) { QCOMPARE(contact->isBlocked(), false); // ...and that bill, steve and kctest1 have also been removed from allKnownContacts() // note: allKnownContacts() changes here because bill, steve and kctest, // which were only in the deny list, do not exist in any other list, so // they are removed as soon as they get unblocked. if (contact->id() == QLatin1String("bill@example.com") || contact->id() == QLatin1String("steve@example.com") || contact->id() == QLatin1String("kctest1@example.com")) { QVERIFY(!contactManager->allKnownContacts().contains(contact)); } else { QVERIFY(contactManager->allKnownContacts().contains(contact)); } } // block some contacts that are not already known ids = QStringList() << QLatin1String("blocktest1@example.com") << QLatin1String("blocktest2@example.com"); contacts = mConn->contacts(ids); // Watch changes in allKnownContacts() instead of watching the Contacts' block status // as we want to destroy the Contact objects and verify that they are being re-created correctly QVERIFY(connect(contactManager.data(), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)), SLOT(expectBlockedContactsChanged(Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)))); mBlockingContactsFinished = false; mContactsExpectingBlockStatusChange = ids.toSet(); QVERIFY(connect(contactManager->blockContacts(contacts), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectBlockingContactsFinished(Tp::PendingOperation*)))); // destroy the Contact objects to let them be re-created when the block operation finishes contacts.clear(); QCOMPARE(mLoop->exec(), 0); // construct the same contacts again and verify that they are blocked contacts = mConn->contacts(ids); Q_FOREACH (const ContactPtr &contact, contacts) { QCOMPARE(contact->isBlocked(), true); QVERIFY(contactManager->allKnownContacts().contains(contact)); } // now unblock them again mBlockingContactsFinished = false; mContactsExpectingBlockStatusChange = ids.toSet(); QVERIFY(connect(contactManager->unblockContacts(contacts), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectBlockingContactsFinished(Tp::PendingOperation*)))); // note: allKnownContacts() is expected to change again, so we expect // to quit from expectBlockedContactsChanged() QCOMPARE(mLoop->exec(), 0); // and verify that they are not in allKnownContacts() Q_FOREACH (const ContactPtr &contact, contacts) { QCOMPARE(contact->isBlocked(), false); QVERIFY(!contactManager->allKnownContacts().contains(contact)); } } void TestConnRoster::cleanup() { cleanupImpl(); } void TestConnRoster::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestConnRoster) #include "_gen/conn-roster.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/dbus-proxy-factory.cpp0000664000175000017500000002542412470405660021343 0ustar jrjr#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestDBusProxyFactory : public Test { Q_OBJECT public: TestDBusProxyFactory(QObject *parent = 0) : Test(parent), mConnService1(0), mConnService2(0) { } protected Q_SLOTS: void expectFinished(); private Q_SLOTS: void initTestCase(); void init(); void testCaching(); void testDropRefs(); void testInvalidate(); void testBogusService(); void cleanup(); void cleanupTestCase(); private: TpTestsContactsConnection *mConnService1, *mConnService2; QString mConnPath1, mConnPath2; QString mConnName1, mConnName2; ConnectionFactoryPtr mFactory; uint mNumFinished; }; void TestDBusProxyFactory::expectFinished() { mNumFinished++; } void TestDBusProxyFactory::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("dbus-proxy-factory"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); gchar *name; gchar *connPath; GError *error = 0; mConnService1 = TP_TESTS_CONTACTS_CONNECTION(g_object_new( TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me1@example.com", "protocol", "simple", NULL)); QVERIFY(mConnService1 != 0); QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService1), "contacts", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); mConnName1 = QLatin1String(name); mConnPath1 = QLatin1String(connPath); g_free(name); g_free(connPath); mConnService2 = TP_TESTS_CONTACTS_CONNECTION(g_object_new( TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me2@example.com", "protocol", "simple", NULL)); QVERIFY(mConnService2 != 0); QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService2), "contacts", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); mConnName2 = QLatin1String(name); mConnPath2 = QLatin1String(connPath); g_free(name); g_free(connPath); } void TestDBusProxyFactory::init() { initImpl(); mFactory = ConnectionFactory::create(QDBusConnection::sessionBus(), Connection::FeatureCore); mNumFinished = 0; } void TestDBusProxyFactory::testCaching() { PendingReady *first = mFactory->proxy(mConnName1, mConnPath1, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(first != NULL); QVERIFY(!first->proxy().isNull()); PendingReady *same = mFactory->proxy(mConnName1, mConnPath1, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(same != NULL); QVERIFY(!same->proxy().isNull()); QCOMPARE(same->proxy().data(), first->proxy().data()); PendingReady *different = mFactory->proxy(mConnName2, mConnPath2, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(different != NULL); QVERIFY(!different->proxy().isNull()); QVERIFY(different->proxy() != first->proxy()); ConnectionPtr firstProxy = ConnectionPtr::qObjectCast(first->proxy()); QVERIFY(!first->isFinished() && !same->isFinished() && !different->isFinished()); QVERIFY(connect(first, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFinished()))); QVERIFY(connect(same, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFinished()))); QVERIFY(connect(different, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFinished()))); QVERIFY(!first->isFinished() && !same->isFinished() && !different->isFinished()); while (mNumFinished < 3) { mLoop->processEvents(); } QCOMPARE(mNumFinished, 3U); PendingReady *another = mFactory->proxy(mConnName1, mConnPath1, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(another != NULL); QVERIFY(!another->proxy().isNull()); // Should still be the same even if all the initial requests already finished QCOMPARE(another->proxy().data(), firstProxy.data()); QVERIFY(connect(another, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); } void TestDBusProxyFactory::testDropRefs() { PendingReady *first = mFactory->proxy(mConnName1, mConnPath1, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(first != NULL); QVERIFY(!first->proxy().isNull()); ConnectionPtr firstProxy = ConnectionPtr::qObjectCast(first->proxy()); QVERIFY(firstProxy->isValid()); QVERIFY(connect(first, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); PendingReady *same = mFactory->proxy(mConnName1, mConnPath1, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(same != NULL); QVERIFY(!same->proxy().isNull()); // The first one is in scope so we should've got it again QCOMPARE(same->proxy().data(), firstProxy.data()); QVERIFY(connect(same, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Flush the delete event for the PendingReady, which drops the PendingReady ref to the proxy mLoop->processEvents(); // Make the Conn go out of scope Connection *firstPtr = firstProxy.data(); firstProxy.reset(); // Hopefully this prevents getting the new proxy instantiated on the very same address QScopedPointer > hole(new char[sizeof(Connection)]); PendingReady *different = mFactory->proxy(mConnName1, mConnPath1, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(different != NULL); QVERIFY(!different->proxy().isNull()); // The first one has gone out of scope and deleted so we should've got a different one QVERIFY(different->proxy().data() != firstPtr); } void TestDBusProxyFactory::testInvalidate() { PendingReady *first = mFactory->proxy(mConnName1, mConnPath1, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(first != NULL); QVERIFY(!first->proxy().isNull()); ConnectionPtr firstProxy = ConnectionPtr::qObjectCast(first->proxy()); QVERIFY(firstProxy->isValid()); QVERIFY(connect(first, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); PendingReady *same = mFactory->proxy(mConnName1, mConnPath1, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(same != NULL); QVERIFY(!same->proxy().isNull()); // The first one is in scope and valid so we should've got it again QCOMPARE(same->proxy().data(), firstProxy.data()); QVERIFY(connect(same, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Flush the delete event for the PendingReady, which drops the PendingReady ref to the proxy mLoop->processEvents(); // Synthesize an invalidation for the proxy QVERIFY(connect(firstProxy.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), mLoop, SLOT(quit()))); TestBackdoors::invalidateProxy(firstProxy.data(), QLatin1String("im.bonghits.Errors.Synthetic"), QLatin1String("")); QCOMPARE(mLoop->exec(), 0); QVERIFY(!firstProxy->isValid()); PendingReady *different = mFactory->proxy(mConnName1, mConnPath1, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(different != NULL); ConnectionPtr differentProxy = ConnectionPtr::qObjectCast(different->proxy()); QVERIFY(!differentProxy.isNull()); // The first one is invalid so we should've got a different one QVERIFY(differentProxy.data() != firstProxy.data()); QVERIFY(differentProxy->isValid()); QVERIFY(!differentProxy->isReady()); QVERIFY(connect(different, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(differentProxy->isValid()); QVERIFY(differentProxy->isReady()); } void TestDBusProxyFactory::testBogusService() { PendingReady *bogus = mFactory->proxy(QLatin1String("org.bogus.Totally"), QLatin1String("/org/bogus/Totally"), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(bogus != NULL); QVERIFY(!bogus->proxy().isNull()); QVERIFY(!ConnectionPtr::qObjectCast(bogus->proxy())->isValid()); PendingReady *another = mFactory->proxy(QLatin1String("org.bogus.Totally"), QLatin1String("/org/bogus/Totally"), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(another != NULL); QVERIFY(!another->proxy().isNull()); QVERIFY(!ConnectionPtr::qObjectCast(another->proxy())->isValid()); // We shouldn't get the same proxy twice ie. a proxy should not be cached if not present on bus // and invalidated because of that, otherwise we'll return an invalid instance from the cache // even if after the service appears on the bus QVERIFY(another->proxy() != bogus->proxy()); // The PendingReady itself should finish with failure QVERIFY(connect(another, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); } void TestDBusProxyFactory::cleanup() { mFactory.reset(); cleanupImpl(); } void TestDBusProxyFactory::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestDBusProxyFactory) #include "_gen/dbus-proxy-factory.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/types.cpp0000664000175000017500000001000512470405660016713 0ustar jrjr#include #include #include #include using namespace Tp; /* We need a interface returning a QVariantMap property where we will insert the various * combinations we are testing, so let's use Channel.Tube for that as we already have the * autogenerated interface for it */ class TubeAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Channel.Interface.Tube") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" "") Q_PROPERTY(QVariantMap Parameters READ Parameters) public: TubeAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent) {} ~TubeAdaptor() {} public: // Properties inline QVariantMap Parameters() const { QVariantMap ret; SUSocketAddress su; su.address = QLatin1String("1.1.1.1"); su.port = 1111; SocketAddressIPv4 saIPv4; saIPv4.address = QLatin1String("2.2.2.2"); saIPv4.port = 2222; SocketAddressIPv6 saIPv6; saIPv6.address = QLatin1String("3.3.3.3"); saIPv6.port = 3333; ret.insert(QLatin1String("SU"), qVariantFromValue(su)); ret.insert(QLatin1String("saIPv4"), qVariantFromValue(saIPv4)); ret.insert(QLatin1String("saIPv6"), qVariantFromValue(saIPv6)); return ret; } }; class TestTypes : public Test { Q_OBJECT public: TestTypes(QObject *parent = 0) : Test(parent) { } protected Q_SLOTS: private Q_SLOTS: void initTestCase(); void init(); void testParameters(); void cleanup(); void cleanupTestCase(); private: QVariantMap mParameters; }; void TestTypes::initTestCase() { initTestCaseImpl(); QDBusConnection bus = QDBusConnection::sessionBus(); // setup adaptor QString tubeBusName = QLatin1String("org.freedesktop.Telepathy.Test.Types"); QString tubePath = QLatin1String("/org/freedesktop/Telepathy/Test/Types"); QObject *adaptorObject = new QObject(this); (void) new TubeAdaptor(adaptorObject); QVERIFY(bus.registerService(tubeBusName)); QVERIFY(bus.registerObject(tubePath, adaptorObject)); Client::ChannelInterfaceTubeInterface *tubeIface = new Client::ChannelInterfaceTubeInterface( bus, tubeBusName, tubePath, this); QVERIFY(waitForProperty(tubeIface->requestPropertyParameters(), &mParameters)); } void TestTypes::init() { initImpl(); } void TestTypes::testParameters() { SUSocketAddress su; SocketAddressIPv4 saIPv4; SocketAddressIPv6 saIPv6; // SUSocketAddress should properly convert to SUSocketAddress itself and // SocketAddressIPv4/IPv6 su = qdbus_cast(mParameters.value(QLatin1String("SU"))); QCOMPARE(su.address, QLatin1String("1.1.1.1")); QCOMPARE(su.port, static_cast(1111)); saIPv4 = qdbus_cast(mParameters.value(QLatin1String("SU"))); QCOMPARE(saIPv4.address, QLatin1String("1.1.1.1")); QCOMPARE(saIPv4.port, static_cast(1111)); saIPv6 = qdbus_cast(mParameters.value(QLatin1String("SU"))); QCOMPARE(saIPv6.address, QLatin1String("1.1.1.1")); QCOMPARE(saIPv6.port, static_cast(1111)); // SocketAddressIPv4->SocketAddressIPv4 saIPv4 = qdbus_cast(mParameters.value(QLatin1String("saIPv4"))); QCOMPARE(saIPv4.address, QLatin1String("2.2.2.2")); QCOMPARE(saIPv4.port, static_cast(2222)); // SocketAddressIPv6->SocketAddressIPv6 saIPv6 = qdbus_cast(mParameters.value(QLatin1String("saIPv6"))); QCOMPARE(saIPv6.address, QLatin1String("3.3.3.3")); QCOMPARE(saIPv6.port, static_cast(3333)); } void TestTypes::cleanup() { cleanupImpl(); } void TestTypes::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestTypes) #include "_gen/types.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/conn-introspect-cornercases.cpp0000664000175000017500000004064212470405660023213 0ustar jrjr#include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestConnIntrospectCornercases : public Test { Q_OBJECT public: TestConnIntrospectCornercases(QObject *parent = 0) : Test(parent), mConnService(0), mNumSelfHandleChanged(0) { } protected Q_SLOTS: void expectConnInvalidated(); void onSelfHandleChanged(uint); private Q_SLOTS: void initTestCase(); void init(); void testSelfHandleChangeBeforeConnecting(); void testSelfHandleChangeWhileBuilding(); void testSlowpath(); void testStatusChange(); void testNoRoster(); void cleanup(); void cleanupTestCase(); private: TpBaseConnection *mConnService; ConnectionPtr mConn; QList mStatuses; int mNumSelfHandleChanged; }; void TestConnIntrospectCornercases::expectConnInvalidated() { qDebug() << "conn invalidated"; mLoop->exit(0); } void TestConnIntrospectCornercases::onSelfHandleChanged(uint handle) { qDebug() << "got new self handle" << handle; mNumSelfHandleChanged++; } void TestConnIntrospectCornercases::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("conn-introspect-cornercases"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); } void TestConnIntrospectCornercases::init() { initImpl(); QVERIFY(mConn.isNull()); QVERIFY(mConnService == 0); QVERIFY(mStatuses.empty()); QCOMPARE(mNumSelfHandleChanged, 0); // don't create the client- or service-side connection objects here, as it's expected that many // different types of service connections with different initial states need to be used } void TestConnIntrospectCornercases::testSelfHandleChangeBeforeConnecting() { gchar *name; gchar *connPath; GError *error = 0; TpTestsSimpleConnection *simpleConnService = TP_TESTS_SIMPLE_CONNECTION( g_object_new( TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL)); QVERIFY(simpleConnService != 0); mConnService = TP_BASE_CONNECTION(simpleConnService); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(mConnService, "simple", &name, &connPath, &error)); QVERIFY(error == 0); mConn = Connection::create(QLatin1String(name), QLatin1String(connPath), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); g_free(name); name = 0; g_free(connPath); connPath = 0; // Set the initial self handle (we're not using the conn service normally, so it doesn't do this // by itself) tp_tests_simple_connection_set_identifier(simpleConnService, "me@example.com"); // Make the conn Connecting, and with FeatureCore ready tp_base_connection_change_status(mConnService, TP_CONNECTION_STATUS_CONNECTING, TP_CONNECTION_STATUS_REASON_REQUESTED); PendingOperation *op = mConn->becomeReady(); QVERIFY(connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(op->isFinished()); QVERIFY(mConn->isValid()); QVERIFY(op->isValid()); QCOMPARE(static_cast(mConn->status()), static_cast(Tp::ConnectionStatusConnecting)); // Start introspecting the SelfContact feature op = mConn->becomeReady(Connection::FeatureSelfContact | Connection::FeatureConnected); QVERIFY(connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); // Change the self handle, before the connection is Connected tp_tests_simple_connection_set_identifier(simpleConnService, "myself@example.com"); // Now change it to Connected tp_base_connection_change_status(mConnService, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); // Try to finish the SelfContact operation, running the mainloop for a while QCOMPARE(mLoop->exec(), 0); QCOMPARE(op->isFinished(), true); QCOMPARE(mConn->isReady(Connection::FeatureCore), true); QCOMPARE(mConn->isReady(Connection::FeatureSelfContact), true); QCOMPARE(static_cast(mConn->status()), static_cast(ConnectionStatusConnected)); } void TestConnIntrospectCornercases::testSelfHandleChangeWhileBuilding() { gchar *name; gchar *connPath; GError *error = 0; TpTestsSimpleConnection *simpleConnService = TP_TESTS_SIMPLE_CONNECTION( g_object_new( TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL)); QVERIFY(simpleConnService != 0); mConnService = TP_BASE_CONNECTION(simpleConnService); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(mConnService, "simple", &name, &connPath, &error)); QVERIFY(error == 0); mConn = Connection::create(QLatin1String(name), QLatin1String(connPath), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); g_free(name); name = 0; g_free(connPath); connPath = 0; // Make the conn Connected, and with FeatureCore ready PendingOperation *op = mConn->lowlevel()->requestConnect(); QVERIFY(connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(op->isFinished()); QVERIFY(mConn->isValid()); QVERIFY(op->isValid()); QCOMPARE(static_cast(mConn->status()), static_cast(Tp::ConnectionStatusConnected)); QCOMPARE(mConn->isReady(Connection::FeatureCore), true); QVERIFY(mConn->selfHandle() != 0); // Start introspecting the SelfContact feature op = mConn->becomeReady(Connection::FeatureSelfContact); QVERIFY(connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); // Run one mainloop iteration, so ReadinessHelper calls introspectSelfContact mLoop->processEvents(); // Change the self handle, so a rebuild has to be done after the first build finishes tp_tests_simple_connection_set_identifier(simpleConnService, "myself@example.com"); // Try to finish the SelfContact operation, running the mainloop for a while QCOMPARE(mLoop->exec(), 0); QCOMPARE(op->isFinished(), true); QCOMPARE(mConn->isReady(Connection::FeatureCore), true); QCOMPARE(mConn->isReady(Connection::FeatureSelfContact), true); QCOMPARE(static_cast(mConn->status()), static_cast(ConnectionStatusConnected)); QCOMPARE(mConn->selfContact()->id(), QString::fromLatin1("me@example.com")); // We should shortly also receive a self contact change to the rebuilt contact QVERIFY(connect(mConn.data(), SIGNAL(selfContactChanged()), mLoop, SLOT(quit()))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->selfContact()->id(), QString::fromLatin1("myself@example.com")); QCOMPARE(mConn->selfContact()->handle()[0], mConn->selfHandle()); // Change the self handle yet again, which should cause a self handle and self contact change to be signalled // (in that order) QVERIFY(connect(mConn.data(), SIGNAL(selfHandleChanged(uint)), SLOT(onSelfHandleChanged(uint)))); tp_tests_simple_connection_set_identifier(simpleConnService, "irene@example.com"); QCOMPARE(mLoop->exec(), 0); QVERIFY(mConn->isValid()); QCOMPARE(mConn->isReady(Connection::FeatureCore), true); QCOMPARE(mConn->isReady(Connection::FeatureSelfContact), true); // We should've received a single self handle change and the self contact should've changed // (exiting the mainloop) QCOMPARE(mNumSelfHandleChanged, 1); QCOMPARE(mConn->selfContact()->id(), QString::fromLatin1("irene@example.com")); QCOMPARE(mConn->selfContact()->handle()[0], mConn->selfHandle()); // Last but not least, try two consequtive changes tp_tests_simple_connection_set_identifier(simpleConnService, "me@example.com"); tp_tests_simple_connection_set_identifier(simpleConnService, "myself@example.com"); // We should receive two more self handle changes in total, and one self contact change for // each mainloop run QCOMPARE(mLoop->exec(), 0); QVERIFY(mConn->isValid()); QCOMPARE(mConn->selfContact()->id(), QString::fromLatin1("me@example.com")); QCOMPARE(mLoop->exec(), 0); QVERIFY(mConn->isValid()); QCOMPARE(mConn->selfContact()->id(), QString::fromLatin1("myself@example.com")); QCOMPARE(mNumSelfHandleChanged, 3); } void TestConnIntrospectCornercases::testSlowpath() { gchar *name; gchar *connPath; GError *error = 0; TpTestsBug16307Connection *bugConnService = TP_TESTS_BUG16307_CONNECTION( g_object_new( TP_TESTS_TYPE_BUG16307_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL)); QVERIFY(bugConnService != 0); mConnService = TP_BASE_CONNECTION(bugConnService); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(mConnService, "simple", &name, &connPath, &error)); QVERIFY(error == 0); mConn = Connection::create(QLatin1String(name), QLatin1String(connPath), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); g_free(name); name = 0; g_free(connPath); connPath = 0; PendingOperation *op = mConn->becomeReady(); QVERIFY(connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); tp_tests_bug16307_connection_inject_get_status_return(bugConnService); QCOMPARE(mLoop->exec(), 0); QCOMPARE(op->isFinished(), true); QCOMPARE(mConn->isReady(Connection::FeatureCore), true); QCOMPARE(static_cast(mConn->status()), static_cast(ConnectionStatusConnected)); } void TestConnIntrospectCornercases::testStatusChange() { gchar *name; gchar *connPath; GError *error = 0; TpTestsSimpleConnection *simpleConnService = TP_TESTS_SIMPLE_CONNECTION( g_object_new( TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL)); QVERIFY(simpleConnService != 0); mConnService = TP_BASE_CONNECTION(simpleConnService); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(mConnService, "simple", &name, &connPath, &error)); QVERIFY(error == 0); mConn = Connection::create(QLatin1String(name), QLatin1String(connPath), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); g_free(name); name = 0; g_free(connPath); connPath = 0; // Make core ready first, because Connection has internal handling for the status changing // during core introspection, and we rather want to test the more general ReadinessHelper // mechanism PendingOperation *op = mConn->becomeReady(); QVERIFY(connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(op->isFinished(), true); QCOMPARE(mConn->isReady(Connection::FeatureCore), true); QCOMPARE(static_cast(mConn->status()), static_cast(ConnectionStatusDisconnected)); // Now, begin making Connected ready op = mConn->becomeReady(Connection::FeatureConnected); QVERIFY(connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); mLoop->processEvents(); // But disturb it by changing the status! TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(mConnService, TP_HANDLE_TYPE_CONTACT); mConnService->self_handle = tp_handle_ensure(contact_repo, "me@example.com", NULL, NULL); tp_base_connection_change_status(mConnService, TP_CONNECTION_STATUS_CONNECTING, TP_CONNECTION_STATUS_REASON_REQUESTED); // Do that again! (The earlier op stil hasn't finished by definition) mConn->becomeReady(Features() << Connection::FeatureConnected); tp_base_connection_change_status(mConnService, TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); QCOMPARE(mLoop->exec(), 0); QCOMPARE(op->isFinished(), true); QCOMPARE(mConn->isReady(Connection::FeatureCore), true); QCOMPARE(mConn->isReady(Connection::FeatureConnected), true); QCOMPARE(static_cast(mConn->status()), static_cast(ConnectionStatusConnected)); } void TestConnIntrospectCornercases::testNoRoster() { gchar *name; gchar *connPath; GError *error = 0; TpTestsContactsNorosterConnection *connService = TP_TESTS_CONTACTS_NOROSTER_CONNECTION( g_object_new( TP_TESTS_TYPE_CONTACTS_NOROSTER_CONNECTION, "account", "me@example.com", "protocol", "contacts-noroster", NULL)); QVERIFY(connService != 0); mConnService = TP_BASE_CONNECTION(connService); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(mConnService, "simple", &name, &connPath, &error)); QVERIFY(error == 0); mConn = Connection::create(QLatin1String(name), QLatin1String(connPath), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); g_free(name); name = 0; g_free(connPath); connPath = 0; PendingOperation *op = mConn->lowlevel()->requestConnect(); QVERIFY(connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->status(), Tp::ConnectionStatusConnected); op = mConn->becomeReady(Connection::FeatureRoster); QVERIFY(connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(op->isFinished()); QVERIFY(mConn->isReady(Connection::FeatureRoster)); QVERIFY(!mConn->actualFeatures().contains(Connection::FeatureRoster)); } void TestConnIntrospectCornercases::cleanup() { if (mConn) { QVERIFY(mConnService != 0); // Disconnect and wait for invalidation tp_base_connection_change_status( mConnService, TP_CONNECTION_STATUS_DISCONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); QVERIFY(connect(mConn.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), SLOT(expectConnInvalidated()))); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mConn->isValid()); processDBusQueue(mConn.data()); mConn.reset(); } if (mConnService != 0) { g_object_unref(mConnService); mConnService = 0; } mStatuses.clear(); mNumSelfHandleChanged = 0; cleanupImpl(); } void TestConnIntrospectCornercases::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestConnIntrospectCornercases) #include "_gen/conn-introspect-cornercases.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/CMakeLists.txt0000664000175000017500000001446712470405660017623 0ustar jrjrfile(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_gen") tpqt_setup_dbus_test_environment() if(HAVE_TEST_PYTHON) tpqt_add_dbus_unit_test(DBusProperties dbus-properties "") endif(HAVE_TEST_PYTHON) if(ENABLE_TP_GLIB_TESTS) include_directories(${CMAKE_SOURCE_DIR}/tests/lib/glib ${TELEPATHY_GLIB_INCLUDE_DIR} ${GLIB2_INCLUDE_DIR} ${DBUS_INCLUDE_DIR}) add_definitions(-DQT_NO_KEYWORDS) if (${QT_VERSION_MAJOR} EQUAL 4) if (NOT ${QT_VERSION_MINOR} EQUAL 6) # >= qt 4.7 # FIXME - Re-enable racy tests once https://bugs.freedesktop.org/show_bug.cgi?id=43356 is # fixed SET(ENABLE_TESTS_WITH_RACES_IN_QT_4_6 TRUE) SET(ENABLE_TESTS_WITH_ISSUES_IN_QT_5 TRUE) endif (NOT ${QT_VERSION_MINOR} EQUAL 6) else (${QT_VERSION_MAJOR} EQUAL 4) # Currently none - this variable is here in case some issues arise SET(ENABLE_TESTS_WITH_ISSUES_IN_QT_5 FALSE) SET(ENABLE_TESTS_WITH_RACES_IN_QT_4_6 TRUE) endif (${QT_VERSION_MAJOR} EQUAL 4) if(HAVE_TEST_PYTHON) tpqt_add_dbus_unit_test(AccountBasics account-basics tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(AccountSet account-set tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(AccountChannelDispatcher account-channel-dispatcher tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(Client client tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ClientFactories client-factories tp-glib-tests) endif(HAVE_TEST_PYTHON) tpqt_add_dbus_unit_test(AccountConnectionFactory account-connection-factory tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(CallChannel call-channel tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(CaptchaAuthentication captcha-authentication tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ChannelBasics chan-basics tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ChannelConference chan-conference tp-glib-tests future-example-cm-conference tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ChannelGroup chan-group tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ConnectionManagerBasics cm-basics tp-glib-tests) tpqt_add_dbus_unit_test(ConnectionAddressing conn-addressing tp-glib-tests future-example-conn-addressing tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ConnectionBasics conn-basics tp-glib-tests) tpqt_add_dbus_unit_test(ConnectionCapabilities conn-capabilities tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ConnectionIntrospectCornercases conn-introspect-cornercases tp-glib-tests) tpqt_add_dbus_unit_test(ConnectionRequests conn-requests tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ConnectionRosterLegacy conn-roster-legacy tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ConnectionRoster conn-roster example-cm-contactlist2 tp-qt-tests-glib-helpers ${GLIB2_LIBRARIES} ${GOBJECT_LIBRARIES} ${DBUS_GLIB_LIBRARIES} ${TELEPATHY_GLIB_LIBRARIES}) tpqt_add_dbus_unit_test(ConnectionRosterGroupsLegacy conn-roster-groups-legacy tp-glib-tests) tpqt_add_dbus_unit_test(ConnectionRosterGroups conn-roster-groups example-cm-contactlist2 ${GLIB2_LIBRARIES} ${GOBJECT_LIBRARIES} ${DBUS_GLIB_LIBRARIES} ${TELEPATHY_GLIB_LIBRARIES}) tpqt_add_dbus_unit_test(ContactFactory contact-factory tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ContactMessenger contact-messenger tp-glib-tests) tpqt_add_dbus_unit_test(ContactSearchChannel contact-search-chan tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(Contacts contacts tp-glib-tests) tpqt_add_dbus_unit_test(ContactsAvatar contacts-avatar tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ContactsCapabilities contacts-capabilities tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ContactsClientTypes contacts-client-types tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ContactsInfo contacts-info tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(ContactsLocation contacts-location tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(DBusProxyFactory dbus-proxy-factory tp-glib-tests telepathy-qt-test-backdoors) tpqt_add_dbus_unit_test(Handles handles tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(Properties properties tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(SimpleObserver simple-observer tp-glib-tests) tpqt_add_dbus_unit_test(StatefulProxy stateful-proxy tp-glib-tests) tpqt_add_dbus_unit_test(StreamedMediaChannel streamed-media-chan tp-glib-tests tp-qt-tests-glib-helpers) if (ENABLE_TESTS_WITH_RACES_IN_QT_4_6) tpqt_add_dbus_unit_test(TextChannel text-chan tp-glib-tests tp-qt-tests-glib-helpers) tpqt_add_dbus_unit_test(StreamTubeHandlers stream-tube-handlers tp-glib-tests tp-qt-tests-glib-helpers) if(ENABLE_TP_GLIB_GIO_TESTS) tpqt_add_dbus_unit_test(StreamTubeChannel stream-tube-chan tp-glib-tests tp-qt-tests-glib-helpers) endif(ENABLE_TP_GLIB_GIO_TESTS) endif (ENABLE_TESTS_WITH_RACES_IN_QT_4_6) if(NOT (${QT_VERSION_MAJOR} EQUAL 4 AND ${QT_VERSION_MINOR} LESS 8)) message(STATUS "Enabling Qt 4.8+ tests") tpqt_add_dbus_unit_test(DBusTubeChannel dbus-tube-chan tp-glib-tests tp-qt-tests-glib-helpers) endif(NOT (${QT_VERSION_MAJOR} EQUAL 4 AND ${QT_VERSION_MINOR} LESS 8)) endif(ENABLE_TP_GLIB_TESTS) tpqt_add_dbus_unit_test(CmProtocol cm-protocol) tpqt_add_dbus_unit_test(ProfileManager profile-manager) tpqt_add_dbus_unit_test(Types types) if(ENABLE_SERVICE_SUPPORT) tpqt_add_dbus_unit_test(BaseConnectionManager base-cm telepathy-qt${QT_VERSION_MAJOR}-service) tpqt_add_dbus_unit_test(BaseProtocol base-protocol telepathy-qt${QT_VERSION_MAJOR}-service) endif(ENABLE_SERVICE_SUPPORT) # Make check target. In case of check, output on failure and put it into a log # This target has to stay here for catching all of the tests add_custom_target(check ctest --output-on-failure -O test.log WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests) add_dependencies(check check-local ${_telepathy_qt_test_cases}) telepathy-qt-0.9.6~git1/tests/dbus/handles.cpp0000664000175000017500000000651712470405660017202 0ustar jrjr#include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include using namespace Tp; class TestHandles : public Test { Q_OBJECT public: TestHandles(QObject *parent = 0) : Test(parent), mConn(0) { } protected Q_SLOTS: void expectPendingHandlesFinished(Tp::PendingOperation*); private Q_SLOTS: void initTestCase(); void init(); void testRequestAndRelease(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; ReferencedHandles mHandles; }; void TestHandles::expectPendingHandlesFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingHandles *pending = qobject_cast(op); mHandles = pending->handles(); mLoop->exit(0); } void TestHandles::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("handles"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL); QCOMPARE(mConn->connect(), true); } void TestHandles::init() { initImpl(); } void TestHandles::testRequestAndRelease() { // Test identifiers QStringList ids = QStringList() << QLatin1String("alice") << QLatin1String("bob") << QLatin1String("chris"); // Request handles for the identifiers and wait for the request to process PendingHandles *pending = mConn->client()->lowlevel()->requestHandles(Tp::HandleTypeContact, ids); QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingHandlesFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(disconnect(pending, SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(expectPendingHandlesFinished(Tp::PendingOperation*)))); ReferencedHandles handles = mHandles; mHandles = ReferencedHandles(); // Verify that the closure indicates correctly which names we requested QCOMPARE(pending->namesRequested(), ids); // Verify by directly poking the service that the handles correspond to the requested IDs TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); for (int i = 0; i < 3; i++) { uint handle = handles[i]; QCOMPARE(QString::fromUtf8(tp_handle_inspect(serviceRepo, handle)), ids[i]); } // Save the handles to a non-referenced normal container Tp::UIntList saveHandles = handles.toList(); // Start releasing the handles, RAII style, and complete the asynchronous process doing that handles = ReferencedHandles(); mLoop->processEvents(); processDBusQueue(mConn->client().data()); } void TestHandles::cleanup() { cleanupImpl(); } void TestHandles::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestHandles) #include "_gen/handles.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/text-chan.cpp0000664000175000017500000005063112470405660017453 0ustar jrjr// We need to use the deprecated TpTextMixin here to test compatibility functionality #define _TP_IGNORE_DEPRECATIONS #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; struct SentMessageDetails { SentMessageDetails(const Message &message, const Tp::MessageSendingFlags flags, const QString &token) : message(message), flags(flags), token(token) { } Message message; Tp::MessageSendingFlags flags; QString token; }; class TestTextChan : public Test { Q_OBJECT public: TestTextChan(QObject *parent = 0) : Test(parent), mConn(0), mContactRepo(0), mTextChanService(0), mMessagesChanService(0), mGotChatStateChanged(false), mChatStateChangedState((ChannelChatState) -1) { } protected Q_SLOTS: void onMessageReceived(const Tp::ReceivedMessage &); void onMessageRemoved(const Tp::ReceivedMessage &); void onMessageSent(const Tp::Message &, Tp::MessageSendingFlags, const QString &); void onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state); private Q_SLOTS: void initTestCase(); void init(); void testMessages(); void testLegacyText(); void cleanup(); void cleanupTestCase(); private: void commonTest(bool withMessages); void sendText(const char *text); TestConnHelper *mConn; TpHandleRepoIface *mContactRepo; ContactPtr mContact; TextChannelPtr mChan; ExampleEchoChannel *mTextChanService; QString mTextChanPath; ExampleEcho2Channel *mMessagesChanService; QString mMessagesChanPath; QList sent; QList received; QList removed; bool mGotChatStateChanged; ContactPtr mChatStateChangedContact; ChannelChatState mChatStateChangedState; }; void TestTextChan::onMessageReceived(const ReceivedMessage &message) { qDebug() << "message received"; received << message; mLoop->exit(0); } void TestTextChan::onMessageRemoved(const ReceivedMessage &message) { qDebug() << "message removed"; removed << message; } void TestTextChan::onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &token) { qDebug() << "message sent"; sent << SentMessageDetails(message, flags, token); } void TestTextChan::onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state) { mGotChatStateChanged = true; mChatStateChangedContact = contact; mChatStateChangedState = state; } void TestTextChan::sendText(const char *text) { qDebug() << "sending message:" << text; QVERIFY(connect(mChan->send(QLatin1String(text), Tp::ChannelTextMessageTypeNormal), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); qDebug() << "message send mainloop finished"; } void TestTextChan::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("text-chan"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "example", NULL); QCOMPARE(mConn->connect(), true); mContactRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); guint handle = tp_handle_ensure(mContactRepo, "someone@localhost", 0, 0); mContact = mConn->contacts(UIntList() << handle).first(); QVERIFY(mContact); // create a Channel by magic, rather than doing D-Bus round-trips for it mTextChanPath = mConn->objectPath() + QLatin1String("/TextChannel"); QByteArray chanPath(mTextChanPath.toLatin1()); mTextChanService = EXAMPLE_ECHO_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle, NULL)); mMessagesChanPath = mConn->objectPath() + QLatin1String("/MessagesChannel"); chanPath = mMessagesChanPath.toLatin1(); mMessagesChanService = EXAMPLE_ECHO_2_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_2_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle, NULL)); } void TestTextChan::init() { initImpl(); mChan.reset(); mGotChatStateChanged = false; mChatStateChangedState = (ChannelChatState) -1; } void TestTextChan::commonTest(bool withMessages) { Q_ASSERT(mChan); ChannelPtr asChannel = ChannelPtr(dynamic_cast(mChan.data())); QVERIFY(connect(asChannel->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(asChannel->isReady()); QVERIFY(mChan->isReady()); // hasChatStateInterface requires FeatureCore only if (withMessages) { QVERIFY(mChan->hasChatStateInterface()); } else { QVERIFY(!mChan->hasChatStateInterface()); } QVERIFY(!mChan->isReady(TextChannel::FeatureChatState)); QCOMPARE(mChan->chatState(mContact), ChannelChatStateInactive); QCOMPARE(mChan->chatState(ContactPtr()), ChannelChatStateInactive); QVERIFY(connect(asChannel->becomeReady(TextChannel::FeatureChatState), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(TextChannel::FeatureChatState)); if (withMessages) { QVERIFY(mChan->hasChatStateInterface()); } else { QVERIFY(!mChan->hasChatStateInterface()); } QCOMPARE(mChan->chatState(mContact), ChannelChatStateInactive); QCOMPARE(mChan->chatState(ContactPtr()), ChannelChatStateInactive); QCOMPARE(mChan->chatState(mChan->groupSelfContact()), ChannelChatStateInactive); QVERIFY(connect(mChan.data(), SIGNAL(chatStateChanged(Tp::ContactPtr,Tp::ChannelChatState)), SLOT(onChatStateChanged(Tp::ContactPtr,Tp::ChannelChatState)))); if (withMessages) { QVERIFY(connect(mChan->requestChatState(ChannelChatStateActive), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); while (!mGotChatStateChanged) { mLoop->processEvents(); } QCOMPARE(mChatStateChangedContact, mChan->groupSelfContact()); QCOMPARE(mChatStateChangedState, mChan->chatState(mChan->groupSelfContact())); QCOMPARE(mChatStateChangedState, ChannelChatStateActive); } else { QVERIFY(connect(mChan->requestChatState(ChannelChatStateActive), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED); QVERIFY(!mLastErrorMessage.isEmpty()); } QVERIFY(!mChan->canInviteContacts()); Features features = Features() << TextChannel::FeatureMessageQueue; QVERIFY(!mChan->isReady(features)); // Implementation detail: in legacy text channels, capabilities arrive // early, so don't assert about that QVERIFY(!mChan->isReady(features)); QVERIFY(connect(mChan.data(), SIGNAL(messageReceived(const Tp::ReceivedMessage &)), SLOT(onMessageReceived(const Tp::ReceivedMessage &)))); QCOMPARE(received.size(), 0); QVERIFY(connect(mChan.data(), SIGNAL(pendingMessageRemoved(const Tp::ReceivedMessage &)), SLOT(onMessageRemoved(const Tp::ReceivedMessage &)))); QCOMPARE(removed.size(), 0); QVERIFY(connect(mChan.data(), SIGNAL(messageSent(const Tp::Message &, Tp::MessageSendingFlags, const QString &)), SLOT(onMessageSent(const Tp::Message &, Tp::MessageSendingFlags, const QString &)))); QCOMPARE(sent.size(), 0); sendText("One"); // Flush the D-Bus queue to make sure we've got the Sent signal the service will send, even if // we are scheduled to execute between the time it calls return_from_send and emit_sent processDBusQueue(mChan.data()); qDebug() << "making the Sent signal ready"; // Make the Sent signal become ready features = Features() << TextChannel::FeatureMessageSentSignal; QVERIFY(connect(mChan->becomeReady(features), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(asChannel->isReady()); QVERIFY(mChan->isReady()); features = Features() << TextChannel::FeatureMessageSentSignal; QVERIFY(mChan->isReady(features)); features = Features() << TextChannel::FeatureMessageQueue; QVERIFY(!mChan->isReady(features)); qDebug() << "the Sent signal is ready"; sendText("Two"); // Flush the D-Bus queue to make sure we've got the Sent signal the service will send, even if // we are scheduled to execute between the time it calls return_from_send and emit_sent processDBusQueue(mChan.data()); // We should have received "Two", but not "One" QCOMPARE(sent.size(), 1); QCOMPARE(static_cast(sent.at(0).flags), 0U); QCOMPARE(sent.at(0).token, QLatin1String("")); Message m(sent.at(0).message); QCOMPARE(static_cast(m.messageType()), static_cast(Tp::ChannelTextMessageTypeNormal)); QVERIFY(!m.isTruncated()); QVERIFY(!m.hasNonTextContent()); QCOMPARE(m.messageToken(), QLatin1String("")); QVERIFY(!m.isSpecificToDBusInterface()); QCOMPARE(m.dbusInterface(), QLatin1String("")); QCOMPARE(m.size(), 2); QCOMPARE(m.header().value(QLatin1String("message-type")).variant().toUInt(), 0U); QCOMPARE(m.part(1).value(QLatin1String("content-type")).variant().toString(), QLatin1String("text/plain")); QCOMPARE(m.text(), QLatin1String("Two")); // Make capabilities become ready features = Features() << TextChannel::FeatureMessageCapabilities; QVERIFY(connect(mChan->becomeReady(features), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(asChannel->isReady()); QVERIFY(mChan->isReady()); features = Features() << TextChannel::FeatureMessageCapabilities; QVERIFY(mChan->isReady(features)); features = Features() << TextChannel::FeatureMessageQueue; QVERIFY(!mChan->isReady(features)); if (withMessages) { QCOMPARE(mChan->supportedContentTypes(), QStringList() << QLatin1String("*/*")); QCOMPARE(static_cast(mChan->messagePartSupport()), static_cast(Tp::MessagePartSupportFlagOneAttachment | Tp::MessagePartSupportFlagMultipleAttachments)); QCOMPARE(mChan->deliveryReportingSupport(), DeliveryReportingSupportFlagReceiveFailures); QCOMPARE(mChan->supportedMessageTypes().size(), 3); // Supports normal, action, notice QVERIFY(mChan->supportsMessageType(Tp::ChannelTextMessageTypeNormal)); QVERIFY(mChan->supportsMessageType(Tp::ChannelTextMessageTypeAction)); QVERIFY(mChan->supportsMessageType(Tp::ChannelTextMessageTypeNotice)); QVERIFY(!mChan->supportsMessageType(Tp::ChannelTextMessageTypeAutoReply)); QVERIFY(!mChan->supportsMessageType(Tp::ChannelTextMessageTypeDeliveryReport)); } else { QCOMPARE(mChan->supportedContentTypes(), QStringList() << QLatin1String("text/plain")); QCOMPARE(static_cast(mChan->messagePartSupport()), 0U); QCOMPARE(static_cast(mChan->deliveryReportingSupport()), 0U); } // Make the message queue become ready too QCOMPARE(received.size(), 0); QCOMPARE(mChan->messageQueue().size(), 0); features = Features() << TextChannel::FeatureMessageQueue; QVERIFY(connect(mChan->becomeReady(features), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(asChannel->isReady()); QVERIFY(mChan->isReady()); features = Features() << TextChannel::FeatureMessageQueue << TextChannel::FeatureMessageCapabilities; QVERIFY(mChan->isReady(features)); // Assert that both our sent messages were echoed by the remote contact while (received.size() != 2) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(received.size(), 2); QCOMPARE(mChan->messageQueue().size(), 2); QVERIFY(mChan->messageQueue().at(0) == received.at(0)); QVERIFY(mChan->messageQueue().at(1) == received.at(1)); QVERIFY(received.at(0) != received.at(1)); ReceivedMessage r(received.at(0)); QVERIFY(r == received.at(0)); QCOMPARE(static_cast(r.messageType()), static_cast(Tp::ChannelTextMessageTypeNormal)); QVERIFY(!r.isTruncated()); QVERIFY(!r.hasNonTextContent()); if (withMessages) { QCOMPARE(r.messageToken(), QLatin1String("0000")); QCOMPARE(r.supersededToken(), QLatin1String("1234")); } else { QCOMPARE(r.messageToken(), QLatin1String("")); QCOMPARE(r.supersededToken(), QString()); } QVERIFY(!r.isSpecificToDBusInterface()); QCOMPARE(r.dbusInterface(), QLatin1String("")); QCOMPARE(r.size(), 2); QCOMPARE(r.header().value(QLatin1String("message-type")).variant().toUInt(), 0U); QCOMPARE(r.part(1).value(QLatin1String("content-type")).variant().toString(), QLatin1String("text/plain")); QCOMPARE(r.sender()->id(), QLatin1String("someone@localhost")); QCOMPARE(r.senderNickname(), QLatin1String("someone@localhost")); if (withMessages) { QVERIFY(r.isScrollback()); } else { QVERIFY(!r.isScrollback()); } QVERIFY(!r.isRescued()); QVERIFY(!r.isDeliveryReport()); // one "echo" implementation echoes the message literally, the other edits // it slightly if (withMessages) { QCOMPARE(r.text(), QLatin1String("One")); } else { QCOMPARE(r.text(), QLatin1String("You said: One")); } r = received.at(1); QCOMPARE(static_cast(r.messageType()), static_cast(Tp::ChannelTextMessageTypeNormal)); QVERIFY(!r.isTruncated()); QVERIFY(!r.hasNonTextContent()); if (withMessages) { QCOMPARE(r.messageToken(), QLatin1String("0000")); QCOMPARE(r.supersededToken(), QLatin1String("1234")); } else { QCOMPARE(r.messageToken(), QLatin1String("")); QCOMPARE(r.supersededToken(), QString()); } QVERIFY(!r.isSpecificToDBusInterface()); QCOMPARE(r.dbusInterface(), QLatin1String("")); QCOMPARE(r.size(), 2); QCOMPARE(r.header().value(QLatin1String("message-type")).variant().toUInt(), 0U); QCOMPARE(r.part(1).value(QLatin1String("content-type")).variant().toString(), QLatin1String("text/plain")); QCOMPARE(r.sender()->id(), QLatin1String("someone@localhost")); QVERIFY(!r.isScrollback()); QVERIFY(!r.isRescued()); if (withMessages) { QCOMPARE(r.text(), QLatin1String("Two")); } else { QCOMPARE(r.text(), QLatin1String("You said: Two")); } // go behind the TextChannel's back to acknowledge the first message: // this emulates another client doing so QVERIFY(connect(mChan.data(), SIGNAL(pendingMessageRemoved(Tp::ReceivedMessage)), mLoop, SLOT(quit()))); mChan->acknowledge(QList< ReceivedMessage >() << received.at(0)); QCOMPARE(mLoop->exec(), 0); QVERIFY(disconnect(mChan.data(), SIGNAL(pendingMessageRemoved(Tp::ReceivedMessage)), mLoop, SLOT(quit()))); QCOMPARE(mChan->messageQueue().size(), 1); QVERIFY(mChan->messageQueue().at(0) == received.at(1)); QCOMPARE(removed.size(), 1); QVERIFY(removed.at(0) == received.at(0)); // In the Messages case this will ack one message, successfully. In the // Text case it will fail to ack two messages, fall back to one call // per message, and fail one while succeeding with the other. mChan->acknowledge(mChan->messageQueue()); if (withMessages) { sendText("Three (fail)"); // Flush the D-Bus queue to make sure we've got the Sent signal the service will send, even if // we are scheduled to execute between the time it calls return_from_send and emit_sent processDBusQueue(mChan.data()); // Assert that both our sent messages were echoed by the remote contact while (received.size() != 3) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(received.size(), 3); QCOMPARE(mChan->messageQueue().size(), 1); QVERIFY(mChan->messageQueue().at(0) == received.at(2)); r = received.at(2); QVERIFY(r == received.at(2)); QCOMPARE(r.messageType(), Tp::ChannelTextMessageTypeDeliveryReport); QVERIFY(!r.isTruncated()); QVERIFY(r.hasNonTextContent()); QCOMPARE(r.messageToken(), QLatin1String("")); QVERIFY(!r.isSpecificToDBusInterface()); QCOMPARE(r.dbusInterface(), QLatin1String("")); QCOMPARE(r.size(), 1); QCOMPARE(r.header().value(QLatin1String("message-type")).variant().toUInt(), static_cast(Tp::ChannelTextMessageTypeDeliveryReport)); QCOMPARE(r.sender()->id(), QLatin1String("someone@localhost")); QCOMPARE(r.senderNickname(), QLatin1String("someone@localhost")); QVERIFY(!r.isScrollback()); QVERIFY(!r.isRescued()); QCOMPARE(r.supersededToken(), QString()); QVERIFY(r.isDeliveryReport()); QVERIFY(r.deliveryDetails().isValid()); QVERIFY(r.deliveryDetails().hasOriginalToken()); QCOMPARE(r.deliveryDetails().originalToken(), QLatin1String("1111")); QCOMPARE(r.deliveryDetails().status(), Tp::DeliveryStatusPermanentlyFailed); QVERIFY(r.deliveryDetails().isError()); QCOMPARE(r.deliveryDetails().error(), Tp::ChannelTextSendErrorPermissionDenied); QVERIFY(r.deliveryDetails().hasDebugMessage()); QCOMPARE(r.deliveryDetails().debugMessage(), QLatin1String("You asked for it")); QCOMPARE(r.deliveryDetails().dbusError(), TP_QT_ERROR_PERMISSION_DENIED); QVERIFY(r.deliveryDetails().hasEchoedMessage()); QCOMPARE(r.deliveryDetails().echoedMessage().text(), QLatin1String("Three (fail)")); mChan->acknowledge(QList() << received.at(2)); } // wait for everything to settle down while (tp_text_mixin_has_pending_messages( G_OBJECT(mTextChanService), 0) || tp_message_mixin_has_pending_messages( G_OBJECT(mMessagesChanService), 0)) { QTest::qWait(1); } QVERIFY(!tp_text_mixin_has_pending_messages( G_OBJECT(mTextChanService), 0)); QVERIFY(!tp_message_mixin_has_pending_messages( G_OBJECT(mMessagesChanService), 0)); } void TestTextChan::testMessages() { mChan = TextChannel::create(mConn->client(), mMessagesChanPath, QVariantMap()); commonTest(true); } void TestTextChan::testLegacyText() { mChan = TextChannel::create(mConn->client(), mTextChanPath, QVariantMap()); commonTest(false); } void TestTextChan::cleanup() { received.clear(); removed.clear(); sent.clear(); cleanupImpl(); } void TestTextChan::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; if (mTextChanService != 0) { g_object_unref(mTextChanService); mTextChanService = 0; } if (mMessagesChanService != 0) { g_object_unref(mMessagesChanService); mMessagesChanService = 0; } cleanupTestCaseImpl(); } QTEST_MAIN(TestTextChan) #include "_gen/text-chan.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/conn-roster-groups.cpp0000664000175000017500000007774612470405660021366 0ustar jrjr#include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestConnRosterGroups : public Test { Q_OBJECT public: TestConnRosterGroups(QObject *parent = 0) : Test(parent), mConnService(0), mContactsAddedToGroup(0), mContactsRemovedFromGroup(0) { } private: void causeCongestion(const ConnectionPtr &conn, const ContactPtr &contact); protected Q_SLOTS: void onGroupAdded(const QString &group); void onGroupRemoved(const QString &group); void onContactAddedToGroup(const QString &group); void onContactRemovedFromGroup(const QString &group); void expectConnInvalidated(); void expectContact(Tp::PendingOperation*); void exitOnStateSuccess(Tp::ContactListState); private Q_SLOTS: void initTestCase(); void init(); void testGroupsAfterStateChange(); void testIntrospectAfterStateChange(); void testRosterGroups(); void testNotADeathTrap(); void cleanup(); void cleanupTestCase(); private: QString mConnName, mConnPath; ExampleContactListConnection *mConnService; ConnectionPtr mConn; ContactPtr mContact; QString mGroupAdded; QString mGroupRemoved; int mContactsAddedToGroup; int mContactsRemovedFromGroup; bool mConnInvalidated; }; void TestConnRosterGroups::causeCongestion(const ConnectionPtr &conn, const ContactPtr &contact) { // Cause some congestion in the roster events queue so we can check that it doesn't cause // inconsistent event reordering for (int i = 0; i < 5; i++) { QString name = QString(QLatin1String("Rush%1")).arg(i); conn->contactManager()->addGroup(name); conn->contactManager()->addContactsToGroup(name, QList() << contact); contact->requestPresenceSubscription(); contact->removePresenceSubscription(); conn->contactManager()->removeGroup(name); } } void TestConnRosterGroups::onGroupAdded(const QString &group) { if (group.startsWith(QLatin1String("Rush"))) { return; } mGroupAdded = group; } void TestConnRosterGroups::onGroupRemoved(const QString &group) { if (group.startsWith(QLatin1String("Rush"))) { return; } mGroupRemoved = group; } void TestConnRosterGroups::onContactAddedToGroup(const QString &group) { if (group.startsWith(QLatin1String("Rush"))) { return; } mContactsAddedToGroup++; } void TestConnRosterGroups::onContactRemovedFromGroup(const QString &group) { if (group.startsWith(QLatin1String("Rush"))) { return; } mContactsRemovedFromGroup++; } void TestConnRosterGroups::expectConnInvalidated() { mConnInvalidated = true; mLoop->exit(0); } void TestConnRosterGroups::expectContact(Tp::PendingOperation *op) { PendingContacts *contacts = qobject_cast(op); QVERIFY(contacts != 0); QVERIFY(contacts->isValid()); QCOMPARE(contacts->contacts().length(), 1); mContact = contacts->contacts()[0]; mLoop->exit(0); } void TestConnRosterGroups::exitOnStateSuccess(Tp::ContactListState state) { qDebug() << "got contact list state" << state; if (state == ContactListStateSuccess) { mLoop->exit(0); } } void TestConnRosterGroups::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("conn-roster-groups"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); } void TestConnRosterGroups::init() { gchar *name; gchar *connPath; GError *error = 0; mConnService = EXAMPLE_CONTACT_LIST_CONNECTION(g_object_new( EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, "account", "me@example.com", "simulation-delay", 0, "protocol", "example-contact-list", NULL)); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService), "foo", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); mConnName = QLatin1String(name); mConnPath = QLatin1String(connPath); g_free(name); g_free(connPath); initImpl(); mConnInvalidated = false; } void TestConnRosterGroups::testGroupsAfterStateChange() { // Create a conn and make the roster groups related features ready mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); ContactManagerPtr contactManager = mConn->contactManager(); Features features = Features() << Connection::FeatureRoster << Connection::FeatureRosterGroups; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), true); // Now start connecting it, and wait for the ContactManager state to turn to Success QVERIFY(connect(contactManager.data(), SIGNAL(stateChanged(Tp::ContactListState)), SLOT(exitOnStateSuccess(Tp::ContactListState)))); mConn->lowlevel()->requestConnect(); QCOMPARE(mLoop->exec(), 0); QCOMPARE(static_cast(contactManager->state()), static_cast(ContactListStateSuccess)); // The conn should be valid and have the roster groups features ready when it emits Success QVERIFY(mConn->isValid()); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), true); // We should have all the group data downloaded now, check for that QStringList expectedGroups; expectedGroups << QLatin1String("Cambridge") << QLatin1String("Francophones") << QLatin1String("Montreal"); expectedGroups.sort(); QStringList groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); // Cambridge { QStringList expectedContacts; expectedContacts << QLatin1String("geraldine@example.com") << QLatin1String("helen@example.com") << QLatin1String("guillaume@example.com") << QLatin1String("sjoerd@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Cambridge"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } // Francophones { QStringList expectedContacts; expectedContacts << QLatin1String("olivier@example.com") << QLatin1String("geraldine@example.com") << QLatin1String("guillaume@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Francophones"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } // Montreal { QStringList expectedContacts; expectedContacts << QLatin1String("olivier@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Montreal"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } } void TestConnRosterGroups::testIntrospectAfterStateChange() { // Create a conn and make the roster feature ready mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); ContactManagerPtr contactManager = mConn->contactManager(); Features features = Features() << Connection::FeatureRoster; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), false); // Now start connecting it, and wait for the ContactManager state to turn to Success QVERIFY(connect(contactManager.data(), SIGNAL(stateChanged(Tp::ContactListState)), SLOT(exitOnStateSuccess(Tp::ContactListState)))); mConn->lowlevel()->requestConnect(); QCOMPARE(mLoop->exec(), 0); QCOMPARE(static_cast(contactManager->state()), static_cast(ContactListStateSuccess)); // The conn should be valid and have the roster feature ready when it emits Success, but not // RosterGroups because we didn't request it QVERIFY(mConn->isValid()); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), false); // We should have roster contacts now, but no groups QVERIFY(!contactManager->allKnownContacts().isEmpty()); QVERIFY(contactManager->allKnownGroups().isEmpty()); // Make RosterGroups ready too features = Features() << Connection::FeatureRosterGroups; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(Connection::FeatureRoster), true); QCOMPARE(mConn->isReady(Connection::FeatureRosterGroups), true); // We should still have the contacts, and the state should be success QVERIFY(!contactManager->allKnownContacts().isEmpty()); QCOMPARE(static_cast(contactManager->state()), static_cast(ContactListStateSuccess)); // We should have all the group data downloaded now, check for that QStringList expectedGroups; expectedGroups << QLatin1String("Cambridge") << QLatin1String("Francophones") << QLatin1String("Montreal"); expectedGroups.sort(); QStringList groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); // Cambridge { QStringList expectedContacts; expectedContacts << QLatin1String("geraldine@example.com") << QLatin1String("helen@example.com") << QLatin1String("guillaume@example.com") << QLatin1String("sjoerd@example.com"); expectedContacts.sort(); QStringList contacts; Q_FOREACH (const ContactPtr &contact, contactManager->groupContacts(QLatin1String("Cambridge"))) { contacts << contact->id(); } contacts.sort(); QCOMPARE(contacts, expectedContacts); } } void TestConnRosterGroups::testRosterGroups() { mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(connect(mConn->lowlevel()->requestConnect(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(), true); QCOMPARE(mConn->status(), ConnectionStatusConnected); Features features = Features() << Connection::FeatureRoster << Connection::FeatureRosterGroups << Connection::FeatureSelfContact; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(features), true); QCOMPARE(static_cast(mConn->contactManager()->state()), static_cast(ContactListStateSuccess)); ContactManagerPtr contactManager = mConn->contactManager(); QStringList expectedGroups; expectedGroups << QLatin1String("Cambridge") << QLatin1String("Francophones") << QLatin1String("Montreal"); expectedGroups.sort(); QStringList groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); QString group(QLatin1String("foo")); QVERIFY(contactManager->groupContacts(group).isEmpty()); causeCongestion(mConn, mConn->selfContact()); // add group foo QVERIFY(connect(contactManager.data(), SIGNAL(groupAdded(const QString&)), SLOT(onGroupAdded(const QString&)))); causeCongestion(mConn, mConn->selfContact()); QVERIFY(connect(contactManager->addGroup(group), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mGroupAdded.isEmpty()); QCOMPARE(mGroupAdded, group); expectedGroups << group; expectedGroups.sort(); groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); causeCongestion(mConn, mConn->selfContact()); // add Montreal contacts to group foo Contacts contacts = contactManager->groupContacts(QLatin1String("Montreal")); Q_FOREACH (const ContactPtr &contact, contacts) { QVERIFY(connect(contact.data(), SIGNAL(addedToGroup(const QString&)), SLOT(onContactAddedToGroup(const QString&)))); } causeCongestion(mConn, mConn->selfContact()); QVERIFY(connect(contactManager->addContactsToGroup(group, contacts.toList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mContactsAddedToGroup, contacts.size()); Q_FOREACH (const ContactPtr &contact, contacts) { QVERIFY(contact->groups().contains(group)); } causeCongestion(mConn, mConn->selfContact()); // remove all contacts from group foo contacts = contactManager->groupContacts(group); Q_FOREACH (const ContactPtr &contact, contacts) { QVERIFY(connect(contact.data(), SIGNAL(removedFromGroup(const QString&)), SLOT(onContactRemovedFromGroup(const QString&)))); } causeCongestion(mConn, mConn->selfContact()); QVERIFY(connect(contactManager->removeContactsFromGroup(group, contacts.toList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mContactsRemovedFromGroup, contacts.size()); Q_FOREACH (const ContactPtr &contact, contacts) { QVERIFY(!contact->groups().contains(group)); } causeCongestion(mConn, mConn->selfContact()); // remove group foo QVERIFY(connect(contactManager.data(), SIGNAL(groupRemoved(const QString&)), SLOT(onGroupRemoved(const QString&)))); causeCongestion(mConn, mConn->selfContact()); QVERIFY(connect(contactManager->removeGroup(group), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mGroupRemoved.isEmpty()); QCOMPARE(mGroupRemoved, group); expectedGroups.removeOne(group); expectedGroups.sort(); groups = contactManager->allKnownGroups(); groups.sort(); QCOMPARE(groups, expectedGroups); } /** * Verify that ContactManager isn't a death-trap. * * Background: Connection::contactManager() used to unpredictably waver between NULL and the real * manager when the connection was in the process of being disconnected / otherwise invalidated, * which led to a great many segfaults, which was especially unfortunate considering the * ContactManager methods didn't do much any checks at all. */ void TestConnRosterGroups::testNotADeathTrap() { mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); // Check that the contact manager doesn't crash, but returns an error (because the conn isn't // ready) QVERIFY(!mConn->contactManager().isNull()); QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->lowlevel()->requestConnect(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(), true); QCOMPARE(mConn->status(), ConnectionStatusConnected); // As the conn is now ready, the contact building functions shouldn't return an error now QVERIFY(!mConn->contactManager().isNull()); QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->contactsForHandles(UIntList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->upgradeContacts(QList(), Features()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // In fact, let's build a contact for future use QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers( QStringList() << QLatin1String("friendorfoe@example.com")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectContact(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mContact->id() == QLatin1String("friendorfoe@example.com")); // Roster operations SHOULD still fail though, as FeatureRoster isn't ready QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription( QList() << mContact, QLatin1String("I just want to see you fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresenceSubscription( QList() << mContact, QLatin1String("I just want to see you fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->authorizePresencePublication( QList() << mContact, QLatin1String("I just want to see you fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresencePublication( QList() << mContact, QLatin1String("I just want to see you fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Now, make Roster ready Features features = Features() << Connection::FeatureRoster; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(features), true); causeCongestion(mConn, mContact); // The roster functions should work now QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mContact->subscriptionState() != Contact::PresenceStateNo); causeCongestion(mConn, mContact); QVERIFY(connect(mConn->contactManager()->removePresenceSubscription( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mContact->subscriptionState(), Contact::PresenceStateNo); causeCongestion(mConn, mContact); QVERIFY(connect(mConn->contactManager()->authorizePresencePublication( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); causeCongestion(mConn, mContact); QVERIFY(connect(mConn->contactManager()->removePresencePublication( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // ... but still not the RosterGroup ones QVERIFY(connect(mConn->contactManager()->addGroup(QLatin1String("Those who failed")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeGroup(QLatin1String("Those who failed")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->addContactsToGroup(QLatin1String("Those who failed"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeContactsFromGroup(QLatin1String("Those who failed"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Make RosterGroups ready too features = Features() << Connection::FeatureRosterGroups; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(features), true); // Now that Core, Roster and RosterGroups are all ready, everything should work QVERIFY(!mConn->contactManager().isNull()); QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->contactsForHandles(UIntList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->upgradeContacts(QList(), Features()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); causeCongestion(mConn, mContact); QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mContact->subscriptionState() != Contact::PresenceStateNo); causeCongestion(mConn, mContact); QVERIFY(connect(mConn->contactManager()->removePresenceSubscription( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mContact->subscriptionState(), Contact::PresenceStateNo); QVERIFY(connect(mConn->contactManager()->authorizePresencePublication( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresencePublication( QList() << mContact, QLatin1String("Please don't fail")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); causeCongestion(mConn, mContact); QVERIFY(connect(mConn->contactManager()->addGroup(QLatin1String("My successful entourage")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mConn->contactManager()->allKnownGroups().contains(QLatin1String("My successful entourage"))); causeCongestion(mConn, mContact); QVERIFY(connect(mConn->contactManager()->addContactsToGroup(QLatin1String("My successful entourage"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mConn->contactManager()-> groupContacts(QLatin1String("My successful entourage")).contains(mContact)); causeCongestion(mConn, mContact); QVERIFY(connect(mConn->contactManager()->removeContactsFromGroup(QLatin1String("My successful entourage"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mConn->contactManager()-> groupContacts(QLatin1String("My successful entourage")).contains(mContact)); causeCongestion(mConn, mContact); QVERIFY(connect(mConn->contactManager()->removeGroup(QLatin1String("My successful entourage")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mConn->contactManager()->allKnownGroups().contains(QLatin1String("My successful entourage"))); // Now, invalidate the connection by disconnecting it QVERIFY(connect(mConn.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), SLOT(expectConnInvalidated()))); mConn->lowlevel()->requestDisconnect(); // Check that contactManager doesn't go NULL in the process of the connection going invalidated do { QVERIFY(!mConn->contactManager().isNull()); mLoop->processEvents(); } while (!mConnInvalidated); QVERIFY(!mConn->isValid()); QCOMPARE(mConn->status(), ConnectionStatusDisconnected); // Now that the conn is invalidated NOTHING should work anymore QVERIFY(connect(mConn->contactManager()->contactsForIdentifiers(QStringList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->contactsForHandles(UIntList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->upgradeContacts(QList(), Features()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->requestPresenceSubscription(QList(), QLatin1String("You fail at life")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresenceSubscription(QList(), QLatin1String("You fail at life")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->authorizePresencePublication(QList(), QLatin1String("You fail at life")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removePresencePublication(QList(), QLatin1String("You fail at life")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->addGroup(QLatin1String("Future failures")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeGroup(QLatin1String("Future failures")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->addContactsToGroup(QLatin1String("Future failures"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mConn->contactManager()->removeContactsFromGroup(QLatin1String("Future failures"), QList() << mContact), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); } void TestConnRosterGroups::cleanup() { mContact.reset(); if (mConn && mConn->requestedFeatures().contains(Connection::FeatureCore)) { QVERIFY(mConnService != NULL); if (TP_BASE_CONNECTION(mConnService)->status != TP_CONNECTION_STATUS_DISCONNECTED) { tp_base_connection_change_status(TP_BASE_CONNECTION(mConnService), TP_CONNECTION_STATUS_DISCONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); } while (mConn->isValid()) { mLoop->processEvents(); } } mConn.reset(); if (mConnService != 0) { g_object_unref(mConnService); mConnService = 0; } cleanupImpl(); } void TestConnRosterGroups::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestConnRosterGroups) #include "_gen/conn-roster-groups.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/do-nothing.cpp0000664000175000017500000000173612470405660017630 0ustar jrjr#include #include #include #include #include #include class TestDoNothing : public Test { Q_OBJECT public: TestDoNothing(QObject *parent = 0) : Test(parent) { } private Q_SLOTS: void initTestCase(); void init(); void doNothing(); void doNothing2(); void cleanup(); void cleanupTestCase(); }; void TestDoNothing::initTestCase() { initTestCaseImpl(); } void TestDoNothing::init() { initImpl(); } void TestDoNothing::doNothing() { QTimer::singleShot(0, mLoop, SLOT(quit())); QCOMPARE(mLoop->exec(), 0); } void TestDoNothing::doNothing2() { QTimer::singleShot(0, mLoop, SLOT(quit())); QCOMPARE(mLoop->exec(), 0); } void TestDoNothing::cleanup() { cleanupImpl(); } void TestDoNothing::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestDoNothing) #include "_gen/do-nothing.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/cm-basics.cpp0000664000175000017500000003053612470405660017423 0ustar jrjr#include #include #include #include #include #include #include #include #include #include using namespace Tp; namespace { PresenceSpec getPresenceSpec(const PresenceSpecList &specs, const QString &status) { Q_FOREACH (const PresenceSpec &spec, specs) { if (spec.presence().status() == status) { return spec; } } return PresenceSpec(); } } class TestCmBasics : public Test { Q_OBJECT public: TestCmBasics(QObject *parent = 0) : Test(parent), mCMService(0) { } protected Q_SLOTS: void expectListNamesFinished(Tp::PendingOperation *); void expectPendingStringFinished(Tp::PendingOperation *); private Q_SLOTS: void initTestCase(); void init(); void testBasics(); void testLegacy(); void testListNames(); void cleanup(); void cleanupTestCase(); private: TpBaseConnectionManager *mCMService; Tp::ConnectionManagerPtr mCM; TpBaseConnectionManager *mCMServiceLegacy; Tp::ConnectionManagerPtr mCMLegacy; QStringList mCMNames; QString mPendingStringResult; }; void TestCmBasics::expectListNamesFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingStringList *ps = qobject_cast(op); mCMNames = ps->result(); mLoop->exit(0); } void TestCmBasics::expectPendingStringFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingString *ps = qobject_cast(op); mPendingStringResult = ps->result(); mLoop->exit(0); } void TestCmBasics::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("cm-basics"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mCMService = TP_BASE_CONNECTION_MANAGER(g_object_new( EXAMPLE_TYPE_ECHO_2_CONNECTION_MANAGER, NULL)); QVERIFY(mCMService != 0); mCMServiceLegacy = TP_BASE_CONNECTION_MANAGER(g_object_new( TP_TESTS_TYPE_SIMPLE_CONNECTION_MANAGER, NULL)); QVERIFY(mCMServiceLegacy != 0); QVERIFY(tp_base_connection_manager_register(mCMService)); QVERIFY(tp_base_connection_manager_register(mCMServiceLegacy)); } void TestCmBasics::init() { initImpl(); } void TestCmBasics::testBasics() { mCM = ConnectionManager::create(QLatin1String("example_echo_2")); QCOMPARE(mCM->isReady(), false); QVERIFY(connect(mCM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCM->isReady(), true); // calling becomeReady() twice is a no-op QVERIFY(connect(mCM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCM->isReady(), true); QCOMPARE(mCM->interfaces(), QStringList()); QCOMPARE(mCM->supportedProtocols(), QStringList() << QLatin1String("example")); QVERIFY(mCM->hasProtocol(QLatin1String("example"))); QVERIFY(!mCM->hasProtocol(QLatin1String("not-there"))); ProtocolInfo info = mCM->protocol(QLatin1String("example")); QVERIFY(info.isValid()); QCOMPARE(info.cmName(), QLatin1String("example_echo_2")); QCOMPARE(info.name(), QLatin1String("example")); QCOMPARE(info.hasParameter(QLatin1String("account")), true); QCOMPARE(info.hasParameter(QLatin1String("not-there")), false); QCOMPARE(info.parameters().size(), 1); ProtocolParameter param = info.parameters().at(0); QCOMPARE(param.name(), QLatin1String("account")); QCOMPARE(static_cast(param.type()), static_cast(QVariant::String)); QCOMPARE(param.defaultValue().isNull(), true); QCOMPARE(param.dbusSignature().signature(), QLatin1String("s")); QCOMPARE(param.isRequired(), true); QCOMPARE(param.isRequiredForRegistration(), true); // though it can't register! QCOMPARE(param.isSecret(), false); QVERIFY(param == QLatin1String("account")); ProtocolParameter otherParam = info.parameters().value(1); QVERIFY(!otherParam.isValid()); QCOMPARE(otherParam.name(), QString()); QCOMPARE(otherParam.dbusSignature(), QDBusSignature()); QCOMPARE(otherParam.type(), QVariant::Invalid); QCOMPARE(otherParam.defaultValue(), QVariant()); QCOMPARE(otherParam.isRequired(), false); QCOMPARE(otherParam.isSecret(), false); QCOMPARE(otherParam.isRequiredForRegistration(), false); QCOMPARE(info.canRegister(), false); QCOMPARE(info.capabilities().isSpecificToContact(), false); QCOMPARE(info.capabilities().textChatrooms(), false); QCOMPARE(info.capabilities().textChats(), true); QCOMPARE(info.capabilities().streamedMediaCalls(), false); QCOMPARE(info.capabilities().streamedMediaAudioCalls(), false); QCOMPARE(info.capabilities().streamedMediaVideoCalls(), false); QCOMPARE(info.capabilities().streamedMediaVideoCallsWithAudio(), false); QCOMPARE(info.capabilities().upgradingStreamedMediaCalls(), false); QCOMPARE(info.vcardField(), QLatin1String("x-telepathy-example")); QCOMPARE(info.englishName(), QLatin1String("Echo II example")); QCOMPARE(info.iconName(), QLatin1String("im-icq")); PresenceSpecList statuses = info.allowedPresenceStatuses(); QCOMPARE(statuses.size(), 3); PresenceSpec spec; spec = getPresenceSpec(statuses, QLatin1String("offline")); QCOMPARE(spec.isValid(), true); QVERIFY(spec.presence().type() == ConnectionPresenceTypeOffline); QCOMPARE(spec.maySetOnSelf(), false); QCOMPARE(spec.canHaveStatusMessage(), false); spec = getPresenceSpec(statuses, QLatin1String("dnd")); QCOMPARE(spec.isValid(), true); QVERIFY(spec.presence().type() == ConnectionPresenceTypeBusy); QCOMPARE(spec.maySetOnSelf(), true); QCOMPARE(spec.canHaveStatusMessage(), false); spec = getPresenceSpec(statuses, QLatin1String("available")); QCOMPARE(spec.isValid(), true); QVERIFY(spec.presence().type() == ConnectionPresenceTypeAvailable); QCOMPARE(spec.maySetOnSelf(), true); QCOMPARE(spec.canHaveStatusMessage(), true); AvatarSpec avatarReqs = info.avatarRequirements(); QStringList supportedMimeTypes = avatarReqs.supportedMimeTypes(); supportedMimeTypes.sort(); QCOMPARE(supportedMimeTypes, QStringList() << QLatin1String("image/gif") << QLatin1String("image/jpeg") << QLatin1String("image/png")); QCOMPARE(avatarReqs.minimumHeight(), (uint) 32); QCOMPARE(avatarReqs.maximumHeight(), (uint) 96); QCOMPARE(avatarReqs.recommendedHeight(), (uint) 64); QCOMPARE(avatarReqs.minimumWidth(), (uint) 32); QCOMPARE(avatarReqs.maximumWidth(), (uint) 96); QCOMPARE(avatarReqs.recommendedWidth(), (uint) 64); QCOMPARE(avatarReqs.maximumBytes(), (uint) 37748736); QStringList addressableVCardFields = info.addressableVCardFields(); QCOMPARE(addressableVCardFields, QStringList() << QLatin1String("x-echo2")); QStringList addressableUriSchemes = info.addressableUriSchemes(); QCOMPARE(addressableUriSchemes, QStringList() << QLatin1String("echo2")); mPendingStringResult = QString(); QVERIFY(connect(info.normalizeVCardAddress(QLatin1String("x-EcHo2"), QLatin1String("EcHo2")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectPendingStringFinished(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mPendingStringResult, QLatin1String("echo2")); mPendingStringResult = QString(); QVERIFY(connect(info.normalizeVCardAddress(QLatin1String("x-unsupported"), QLatin1String("EcHo2")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); mPendingStringResult = QString(); QVERIFY(connect(info.normalizeContactUri(QLatin1String("eCho2:FooBaR")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectPendingStringFinished(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mPendingStringResult, QLatin1String("echo2:foobar")); mPendingStringResult = QString(); QVERIFY(connect(info.normalizeContactUri(QLatin1String("unsupported:echo2")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCM->supportedProtocols(), QStringList() << QLatin1String("example")); } // Test for a CM which doesn't implement Protocol objects void TestCmBasics::testLegacy() { mCMLegacy = ConnectionManager::create(QLatin1String("simple")); QCOMPARE(mCMLegacy->isReady(), false); QVERIFY(connect(mCMLegacy->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCMLegacy->isReady(), true); QCOMPARE(mCMLegacy->interfaces(), QStringList()); QCOMPARE(mCMLegacy->supportedProtocols(), QStringList() << QLatin1String("simple")); QVERIFY(mCMLegacy->hasProtocol(QLatin1String("simple"))); QVERIFY(!mCMLegacy->hasProtocol(QLatin1String("not-there"))); ProtocolInfo info = mCMLegacy->protocol(QLatin1String("simple")); QVERIFY(info.isValid()); QCOMPARE(info.cmName(), QLatin1String("simple")); QCOMPARE(info.name(), QLatin1String("simple")); QCOMPARE(info.hasParameter(QLatin1String("account")), true); QCOMPARE(info.hasParameter(QLatin1String("not-there")), false); QCOMPARE(info.parameters().size(), 1); ProtocolParameter param = info.parameters().at(0); QCOMPARE(param.name(), QLatin1String("account")); QCOMPARE(static_cast(param.type()), static_cast(QVariant::String)); QCOMPARE(param.defaultValue().isNull(), true); QCOMPARE(param.dbusSignature().signature(), QLatin1String("s")); QCOMPARE(param.isRequired(), true); QCOMPARE(param.isRequiredForRegistration(), true); QCOMPARE(param.isSecret(), false); QVERIFY(param == QLatin1String("account")); QCOMPARE(info.canRegister(), false); // Protocol capabilities semantics is "an actual connection supports whatever I claim, or // less", so for a service with no actual Protocol implementation everything should be // assumed to be possible at this point QCOMPARE(info.capabilities().isSpecificToContact(), false); QCOMPARE(info.capabilities().textChatrooms(), true); QCOMPARE(info.capabilities().textChats(), true); QCOMPARE(info.capabilities().streamedMediaCalls(), true); QCOMPARE(info.capabilities().streamedMediaAudioCalls(), true); QCOMPARE(info.capabilities().streamedMediaVideoCalls(), true); QCOMPARE(info.capabilities().streamedMediaVideoCallsWithAudio(), true); QCOMPARE(info.capabilities().upgradingStreamedMediaCalls(), true); QCOMPARE(info.vcardField(), QLatin1String("")); QCOMPARE(info.englishName(), QLatin1String("Simple")); QCOMPARE(info.iconName(), QLatin1String("im-simple")); QCOMPARE(mCMLegacy->supportedProtocols(), QStringList() << QLatin1String("simple")); } // TODO add a test for the case of getting the information from a .manager file, and if possible, // also for using the fallbacks for the CM::Protocols property not being present. void TestCmBasics::testListNames() { QVERIFY(connect(ConnectionManager::listNames(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectListNamesFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCMNames.size(), 3); QVERIFY(mCMNames.contains(QLatin1String("simple"))); QVERIFY(mCMNames.contains(QLatin1String("example_echo_2"))); QVERIFY(mCMNames.contains(QLatin1String("spurious"))); } void TestCmBasics::cleanup() { mCM.reset(); mCMLegacy.reset(); cleanupImpl(); } void TestCmBasics::cleanupTestCase() { if (mCMService) { g_object_unref(mCMService); mCMService = 0; } if (mCMServiceLegacy) { g_object_unref(mCMServiceLegacy); mCMServiceLegacy = 0; } cleanupTestCaseImpl(); } QTEST_MAIN(TestCmBasics) #include "_gen/cm-basics.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/contacts.cpp0000664000175000017500000007366712470405660017414 0ustar jrjr#include #include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestContacts : public Test { Q_OBJECT public: TestContacts(QObject *parent = 0) : Test(parent), mConnService(0) { } protected Q_SLOTS: void expectConnReady(Tp::ConnectionStatus, Tp::ConnectionStatusReason); void expectConnInvalidated(); void expectPendingContactsFinished(Tp::PendingOperation *); private Q_SLOTS: void initTestCase(); void init(); void testSupport(); void testSelfContact(); void testForHandles(); void testForIdentifiers(); void testFeatures(); void testFeaturesNotRequested(); void testUpgrade(); void testSelfContactFallback(); void cleanup(); void cleanupTestCase(); private: QString mConnName, mConnPath; TpTestsContactsConnection *mConnService; ConnectionPtr mConn; QList mContacts; Tp::UIntList mInvalidHandles; }; void TestContacts::expectConnReady(Tp::ConnectionStatus newStatus, Tp::ConnectionStatusReason newStatusReason) { switch (newStatus) { case ConnectionStatusDisconnected: qWarning() << "Disconnected"; mLoop->exit(1); break; case ConnectionStatusConnecting: /* do nothing */ break; case ConnectionStatusConnected: qDebug() << "Ready"; mLoop->exit(0); break; default: qWarning().nospace() << "What sort of status is " << newStatus << "?!"; mLoop->exit(2); break; } } void TestContacts::expectConnInvalidated() { mLoop->exit(0); } void TestContacts::expectPendingContactsFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingContacts *pending = qobject_cast(op); mContacts = pending->contacts(); if (pending->isForHandles()) { mInvalidHandles = pending->invalidHandles(); } mLoop->exit(0); } void TestContacts::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("contacts"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); gchar *name; gchar *connPath; GError *error = 0; mConnService = TP_TESTS_CONTACTS_CONNECTION(g_object_new( TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL)); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService), "contacts", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); mConnName = QLatin1String(name); mConnPath = QLatin1String(connPath); g_free(name); g_free(connPath); mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); mConn->lowlevel()->requestConnect(); Features features = Features() << Connection::FeatureSelfContact; QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(features), true); if (mConn->status() != ConnectionStatusConnected) { QVERIFY(connect(mConn.data(), SIGNAL(statusChanged(Tp::ConnectionStatus, Tp::ConnectionStatusReason)), SLOT(expectConnReady(Tp::ConnectionStatus, Tp::ConnectionStatusReason)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(disconnect(mConn.data(), SIGNAL(statusChanged(Tp::ConnectionStatus, Tp::ConnectionStatusReason)), this, SLOT(expectConnReady(Tp::ConnectionStatus, Tp::ConnectionStatusReason)))); QCOMPARE(mConn->status(), ConnectionStatusConnected); } } void TestContacts::init() { initImpl(); } void TestContacts::testSupport() { QCOMPARE(mConn->contactManager()->connection(), mConn); QVERIFY(!mConn->lowlevel()->contactAttributeInterfaces().isEmpty()); QVERIFY(mConn->lowlevel()->contactAttributeInterfaces().contains( TP_QT_IFACE_CONNECTION)); QVERIFY(mConn->lowlevel()->contactAttributeInterfaces().contains( TP_QT_IFACE_CONNECTION_INTERFACE_ALIASING)); QVERIFY(mConn->lowlevel()->contactAttributeInterfaces().contains( TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS)); QVERIFY(mConn->lowlevel()->contactAttributeInterfaces().contains( TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE)); QVERIFY(!mConn->lowlevel()->contactAttributeInterfaces().contains( QLatin1String("org.freedesktop.Telepathy.Connection.Interface.Addressing.DRAFT"))); Features supportedFeatures = mConn->contactManager()->supportedFeatures(); QVERIFY(!supportedFeatures.isEmpty()); QVERIFY(supportedFeatures.contains(Contact::FeatureAlias)); QVERIFY(supportedFeatures.contains(Contact::FeatureAvatarToken)); QVERIFY(supportedFeatures.contains(Contact::FeatureSimplePresence)); QVERIFY(!supportedFeatures.contains(Contact::FeatureAddresses)); } void TestContacts::testSelfContact() { ContactPtr selfContact = mConn->selfContact(); QVERIFY(selfContact != 0); QCOMPARE(selfContact->handle()[0], mConn->selfHandle()); QCOMPARE(selfContact->id(), QString(QLatin1String("me@example.com"))); Features features = Features() << Contact::FeatureAlias << Contact::FeatureAvatarToken << Contact::FeatureSimplePresence; QVERIFY(connect(selfContact->manager()->upgradeContacts( QList() << selfContact, features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(selfContact->alias(), QString(QLatin1String("me@example.com"))); QVERIFY(!selfContact->isAvatarTokenKnown()); QCOMPARE(selfContact->presence().status(), QString(QLatin1String("available"))); QCOMPARE(selfContact->presence().type(), Tp::ConnectionPresenceTypeAvailable); QCOMPARE(selfContact->presence().statusMessage(), QString(QLatin1String(""))); features << Contact::FeatureInfo; QVERIFY(connect(selfContact->manager()->upgradeContacts( QList() << selfContact, features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(selfContact->alias(), QString(QLatin1String("me@example.com"))); QVERIFY(!selfContact->isAvatarTokenKnown()); QCOMPARE(selfContact->presence().status(), QString(QLatin1String("available"))); QCOMPARE(selfContact->presence().type(), Tp::ConnectionPresenceTypeAvailable); QCOMPARE(selfContact->presence().statusMessage(), QString(QLatin1String(""))); } void TestContacts::testForHandles() { Tp::UIntList handles; TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConnService), TP_HANDLE_TYPE_CONTACT); // Set up a few valid handles handles << tp_handle_ensure(serviceRepo, "alice", NULL, NULL); QVERIFY(handles[0] != 0); handles << tp_handle_ensure(serviceRepo, "bob", NULL, NULL); QVERIFY(handles[1] != 0); // Put one probably invalid one in between handles << 31337; QVERIFY(!tp_handle_is_valid(serviceRepo, handles[2], NULL)); // Then another valid one handles << tp_handle_ensure(serviceRepo, "chris", NULL, NULL); QVERIFY(handles[3] != 0); // And yet another invalid one handles << 12345; QVERIFY(!tp_handle_is_valid(serviceRepo, handles[4], NULL)); // Get contacts for the mixture of valid and invalid handles PendingContacts *pending = mConn->contactManager()->contactsForHandles(handles); // Test the closure accessors QCOMPARE(pending->manager(), mConn->contactManager()); QCOMPARE(pending->features(), Features()); QVERIFY(pending->isForHandles()); QVERIFY(!pending->isForIdentifiers()); QVERIFY(!pending->isUpgrade()); QCOMPARE(pending->handles(), handles); // Wait for the contacts to be built QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // There should be 3 resulting contacts and 2 handles found to be invalid QCOMPARE(mContacts.size(), 3); QCOMPARE(mInvalidHandles.size(), 2); QCOMPARE(mInvalidHandles[0], handles[2]); QCOMPARE(mInvalidHandles[1], handles[4]); // Check the contact contents for (int i = 0; i < 3; i++) { QVERIFY(mContacts[i] != NULL); QCOMPARE(mContacts[i]->manager(), mConn->contactManager()); QCOMPARE(mContacts[i]->requestedFeatures(), Features()); QCOMPARE(mContacts[i]->actualFeatures(), Features()); } QCOMPARE(mContacts[0]->handle()[0], handles[0]); QCOMPARE(mContacts[1]->handle()[0], handles[1]); QCOMPARE(mContacts[2]->handle()[0], handles[3]); QCOMPARE(mContacts[0]->id(), QString(QLatin1String("alice"))); QCOMPARE(mContacts[1]->id(), QString(QLatin1String("bob"))); QCOMPARE(mContacts[2]->id(), QString(QLatin1String("chris"))); // Save the contacts, and make a new request, replacing one of the invalid handles with a valid // one QList saveContacts = mContacts; handles[2] = tp_handle_ensure(serviceRepo, "dora", NULL, NULL); QVERIFY(handles[2] != 0); pending = mConn->contactManager()->contactsForHandles(handles); QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Check that we got the correct number of contacts back QCOMPARE(mContacts.size(), 4); QCOMPARE(mInvalidHandles.size(), 1); // Check that the contacts we already had were returned for the initial three QCOMPARE(saveContacts[0], mContacts[0]); QCOMPARE(saveContacts[1], mContacts[1]); QCOMPARE(saveContacts[2], mContacts[3]); // Check that the new contact is OK too QCOMPARE(mContacts[2]->handle()[0], handles[2]); QCOMPARE(mContacts[2]->id(), QString(QLatin1String("dora"))); // Make the contacts go out of scope, starting releasing their handles, and finish that saveContacts.clear(); mContacts.clear(); mLoop->processEvents(); processDBusQueue(mConn.data()); } void TestContacts::testForIdentifiers() { QStringList validIDs = QStringList() << QLatin1String("Alice") << QLatin1String("Bob") << QLatin1String("Chris"); QStringList invalidIDs = QStringList() << QLatin1String("Not valid") << QLatin1String("Not valid either"); TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConnService), TP_HANDLE_TYPE_CONTACT); QStringList toCheck; // Check that a request with just the invalid IDs fails PendingContacts *fails = mConn->contactManager()->contactsForIdentifiers(invalidIDs); QVERIFY(connect(fails, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); toCheck = fails->invalidIdentifiers().keys(); toCheck.sort(); invalidIDs.sort(); QCOMPARE(toCheck, invalidIDs); // A request with both valid and invalid IDs should succeed fails = mConn->contactManager()->contactsForIdentifiers(invalidIDs + validIDs + invalidIDs); QVERIFY(connect(fails, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(fails->validIdentifiers(), validIDs); toCheck = fails->invalidIdentifiers().keys(); toCheck.sort(); invalidIDs.sort(); QCOMPARE(toCheck, invalidIDs); // Go on to the meat: valid IDs PendingContacts *pending = mConn->contactManager()->contactsForIdentifiers(validIDs); // Test the closure accessors QCOMPARE(pending->manager(), mConn->contactManager()); QCOMPARE(pending->features(), Features()); QVERIFY(!pending->isForHandles()); QVERIFY(pending->isForIdentifiers()); QVERIFY(!pending->isUpgrade()); QCOMPARE(pending->identifiers(), validIDs); // Finish it QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Check that there are 3 contacts consistent with the request QCOMPARE(mContacts.size(), 3); for (int i = 0; i < mContacts.size(); i++) { QVERIFY(mContacts[i] != NULL); QCOMPARE(mContacts[i]->manager(), mConn->contactManager()); QVERIFY(tp_handle_is_valid(serviceRepo, mContacts[i]->handle()[0], NULL)); QCOMPARE(mContacts[i]->requestedFeatures(), Features()); QCOMPARE(mContacts[i]->actualFeatures(), Features()); } QCOMPARE(mContacts[0]->id(), QString(QLatin1String("alice"))); QCOMPARE(mContacts[1]->id(), QString(QLatin1String("bob"))); QCOMPARE(mContacts[2]->id(), QString(QLatin1String("chris"))); // Make the contacts go out of scope, starting releasing their handles, and finish that (but // save their handles first) Tp::UIntList saveHandles = Tp::UIntList() << mContacts[0]->handle()[0] << mContacts[1]->handle()[0] << mContacts[2]->handle()[0]; mContacts.clear(); mLoop->processEvents(); processDBusQueue(mConn.data()); } void TestContacts::testFeatures() { QStringList ids = QStringList() << QLatin1String("alice") << QLatin1String("bob") << QLatin1String("chris"); const char *initialAliases[] = { "Alice in Wonderland", "Bob the Builder", "Chris Sawyer" }; const char *latterAliases[] = { "Alice Through the Looking Glass", "Bob the Pensioner" }; const char *initialTokens[] = { "bbbbb", "ccccc" }; const char *latterTokens[] = { "AAAA", "BBBB" }; static TpTestsContactsConnectionPresenceStatusIndex initialStatuses[] = { TP_TESTS_CONTACTS_CONNECTION_STATUS_AVAILABLE, TP_TESTS_CONTACTS_CONNECTION_STATUS_BUSY, TP_TESTS_CONTACTS_CONNECTION_STATUS_AWAY }; static TpTestsContactsConnectionPresenceStatusIndex latterStatuses[] = { TP_TESTS_CONTACTS_CONNECTION_STATUS_AWAY, TP_TESTS_CONTACTS_CONNECTION_STATUS_AVAILABLE, }; const char *initialMessages[] = { "", "Fixing it", "GON OUT BACKSON" }; const char *latterMessages[] = { "Having some carrots", "Done building for life, yay", }; Features features = Features() << Contact::FeatureAlias << Contact::FeatureAvatarToken << Contact::FeatureSimplePresence; TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConnService), TP_HANDLE_TYPE_CONTACT); // Get test handles Tp::UIntList handles; for (int i = 0; i < 3; i++) { handles.push_back(tp_handle_ensure(serviceRepo, ids[i].toLatin1().constData(), NULL, NULL)); QVERIFY(handles[i] != 0); } // Set the initial attributes tp_tests_contacts_connection_change_aliases(mConnService, 3, handles.toVector().constData(), initialAliases); tp_tests_contacts_connection_change_avatar_tokens(mConnService, 2, handles.toVector().constData() + 1, initialTokens); tp_tests_contacts_connection_change_presences(mConnService, 3, handles.toVector().constData(), initialStatuses, initialMessages); // Build contacts PendingContacts *pending = mConn->contactManager()->contactsForHandles(handles, features); QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Check the contact contents QCOMPARE(mContacts.size(), 3); for (int i = 0; i < 3; i++) { QCOMPARE(mContacts[i]->handle()[0], handles[i]); QCOMPARE(mContacts[i]->id(), ids[i]); QVERIFY((features - mContacts[i]->requestedFeatures()).isEmpty()); QVERIFY((mContacts[i]->actualFeatures() - mContacts[i]->requestedFeatures()).isEmpty()); QVERIFY(mContacts[i]->actualFeatures().contains(Contact::FeatureAlias)); QCOMPARE(mContacts[i]->alias(), QString(QLatin1String(initialAliases[i]))); QVERIFY(mContacts[i]->actualFeatures().contains(Contact::FeatureAvatarToken)); QVERIFY(mContacts[i]->actualFeatures().contains(Contact::FeatureSimplePresence)); QCOMPARE(mContacts[i]->presence().statusMessage(), QString(QLatin1String(initialMessages[i]))); } // Check that there's no known avatar token for the first contact, but that there is for the // two others QVERIFY(!mContacts[0]->isAvatarTokenKnown()); QVERIFY(mContacts[1]->isAvatarTokenKnown()); QVERIFY(mContacts[2]->isAvatarTokenKnown()); QCOMPARE(mContacts[0]->avatarToken(), QString(QLatin1String(""))); QCOMPARE(mContacts[1]->avatarToken(), QString(QLatin1String(initialTokens[0]))); QCOMPARE(mContacts[2]->avatarToken(), QString(QLatin1String(initialTokens[1]))); QCOMPARE(mContacts[0]->presence().status(), QString(QLatin1String("available"))); QCOMPARE(mContacts[1]->presence().status(), QString(QLatin1String("busy"))); QCOMPARE(mContacts[2]->presence().status(), QString(QLatin1String("away"))); QCOMPARE(mContacts[0]->presence().type(), Tp::ConnectionPresenceTypeAvailable); QCOMPARE(mContacts[1]->presence().type(), Tp::ConnectionPresenceTypeBusy); QCOMPARE(mContacts[2]->presence().type(), Tp::ConnectionPresenceTypeAway); // Change some of the contacts to a new set of attributes tp_tests_contacts_connection_change_aliases(mConnService, 2, handles.toVector().constData(), latterAliases); tp_tests_contacts_connection_change_avatar_tokens(mConnService, 2, handles.toVector().constData(), latterTokens); tp_tests_contacts_connection_change_presences(mConnService, 2, handles.toVector().constData(), latterStatuses, latterMessages); mLoop->processEvents(); processDBusQueue(mConn.data()); // Check that the attributes were updated in the Contact objects for (int i = 0; i < 3; i++) { QCOMPARE(mContacts[i]->handle()[0], handles[i]); QCOMPARE(mContacts[i]->id(), ids[i]); QVERIFY((features - mContacts[i]->requestedFeatures()).isEmpty()); QVERIFY((mContacts[i]->actualFeatures() - mContacts[i]->requestedFeatures()).isEmpty()); QVERIFY(mContacts[i]->actualFeatures().contains(Contact::FeatureAlias)); QVERIFY(mContacts[i]->actualFeatures().contains(Contact::FeatureAvatarToken)); QVERIFY(mContacts[i]->actualFeatures().contains(Contact::FeatureSimplePresence)); QVERIFY(mContacts[i]->isAvatarTokenKnown()); } QCOMPARE(mContacts[0]->alias(), QString(QLatin1String(latterAliases[0]))); QCOMPARE(mContacts[1]->alias(), QString(QLatin1String(latterAliases[1]))); QCOMPARE(mContacts[2]->alias(), QString(QLatin1String(initialAliases[2]))); QCOMPARE(mContacts[0]->avatarToken(), QString(QLatin1String(latterTokens[0]))); QCOMPARE(mContacts[1]->avatarToken(), QString(QLatin1String(latterTokens[1]))); QCOMPARE(mContacts[2]->avatarToken(), QString(QLatin1String(initialTokens[1]))); QCOMPARE(mContacts[0]->presence().status(), QString(QLatin1String("away"))); QCOMPARE(mContacts[1]->presence().status(), QString(QLatin1String("available"))); QCOMPARE(mContacts[2]->presence().status(), QString(QLatin1String("away"))); QCOMPARE(mContacts[0]->presence().type(), Tp::ConnectionPresenceTypeAway); QCOMPARE(mContacts[1]->presence().type(), Tp::ConnectionPresenceTypeAvailable); QCOMPARE(mContacts[2]->presence().type(), Tp::ConnectionPresenceTypeAway); QCOMPARE(mContacts[0]->presence().statusMessage(), QString(QLatin1String(latterMessages[0]))); QCOMPARE(mContacts[1]->presence().statusMessage(), QString(QLatin1String(latterMessages[1]))); QCOMPARE(mContacts[2]->presence().statusMessage(), QString(QLatin1String(initialMessages[2]))); // Make the contacts go out of scope, starting releasing their handles, and finish that mContacts.clear(); mLoop->processEvents(); processDBusQueue(mConn.data()); } void TestContacts::testFeaturesNotRequested() { // Test ids and corresponding handles QStringList ids = QStringList() << QLatin1String("alice") << QLatin1String("bob") << QLatin1String("chris"); TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConnService), TP_HANDLE_TYPE_CONTACT); Tp::UIntList handles; for (int i = 0; i < 3; i++) { handles.push_back(tp_handle_ensure(serviceRepo, ids[i].toLatin1().constData(), NULL, NULL)); QVERIFY(handles[i] != 0); } // Build contacts (note: no features) PendingContacts *pending = mConn->contactManager()->contactsForHandles(handles); QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Check that the feature accessors return sensible fallback values (note: the warnings are // intentional - however, I'm not quite sure if they should be just debug (like in tp-glib)) QCOMPARE(mContacts.size(), 3); for (int i = 0; i < 3; i++) { ContactPtr contact = mContacts[i]; QVERIFY(contact->requestedFeatures().isEmpty()); QVERIFY(contact->actualFeatures().isEmpty()); QCOMPARE(contact->alias(), contact->id()); QVERIFY(!contact->isAvatarTokenKnown()); QCOMPARE(contact->avatarToken(), QString(QLatin1String(""))); QCOMPARE(contact->presence().isValid(), false); } // Make the contacts go out of scope, starting releasing their handles, and finish that mContacts.clear(); mLoop->processEvents(); processDBusQueue(mConn.data()); } void TestContacts::testUpgrade() { QStringList ids = QStringList() << QLatin1String("alice") << QLatin1String("bob") << QLatin1String("chris"); const char *aliases[] = { "Alice in Wonderland", "Bob The Builder", "Chris Sawyer" }; const char *tokens[] = { "aaaaa", "bbbbb", "ccccc" }; static TpTestsContactsConnectionPresenceStatusIndex statuses[] = { TP_TESTS_CONTACTS_CONNECTION_STATUS_AVAILABLE, TP_TESTS_CONTACTS_CONNECTION_STATUS_BUSY, TP_TESTS_CONTACTS_CONNECTION_STATUS_AWAY }; const char *messages[] = { "", "Fixing it", "GON OUT BACKSON" }; TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConnService), TP_HANDLE_TYPE_CONTACT); Tp::UIntList handles; for (int i = 0; i < 3; i++) { handles.push_back(tp_handle_ensure(serviceRepo, ids[i].toLatin1().constData(), NULL, NULL)); QVERIFY(handles[i] != 0); } tp_tests_contacts_connection_change_aliases(mConnService, 3, handles.toVector().constData(), aliases); tp_tests_contacts_connection_change_avatar_tokens(mConnService, 3, handles.toVector().constData(), tokens); tp_tests_contacts_connection_change_presences(mConnService, 3, handles.toVector().constData(), statuses, messages); PendingContacts *pending = mConn->contactManager()->contactsForHandles(handles); // Wait for the contacts to be built QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // There should be 3 resulting contacts - save them for future reference QCOMPARE(mContacts.size(), 3); QList saveContacts = mContacts; // Upgrade them Features features = Features() << Contact::FeatureAlias << Contact::FeatureAvatarToken << Contact::FeatureSimplePresence; pending = mConn->contactManager()->upgradeContacts(saveContacts, features); // Test the closure accessors QCOMPARE(pending->manager(), mConn->contactManager()); QCOMPARE(pending->features(), features); QVERIFY(!pending->isForHandles()); QVERIFY(!pending->isForIdentifiers()); QVERIFY(pending->isUpgrade()); QCOMPARE(pending->contactsToUpgrade(), saveContacts); // Wait for the contacts to be built QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Check that we got the correct contacts back QCOMPARE(mContacts, saveContacts); // Check the contact contents for (int i = 0; i < 3; i++) { QCOMPARE(mContacts[i]->handle()[0], handles[i]); QCOMPARE(mContacts[i]->id(), ids[i]); QVERIFY((features - mContacts[i]->requestedFeatures()).isEmpty()); QVERIFY((mContacts[i]->actualFeatures() - mContacts[i]->requestedFeatures()).isEmpty()); QVERIFY(mContacts[i]->actualFeatures().contains(Contact::FeatureAlias)); QCOMPARE(mContacts[i]->alias(), QString(QLatin1String(aliases[i]))); QVERIFY(mContacts[i]->actualFeatures().contains(Contact::FeatureAvatarToken)); QVERIFY(mContacts[i]->isAvatarTokenKnown()); QCOMPARE(mContacts[i]->avatarToken(), QString(QLatin1String(tokens[i]))); QVERIFY(mContacts[i]->actualFeatures().contains(Contact::FeatureSimplePresence)); QCOMPARE(mContacts[i]->presence().statusMessage(), QString(QLatin1String(messages[i]))); } QCOMPARE(mContacts[0]->presence().status(), QString(QLatin1String("available"))); QCOMPARE(mContacts[1]->presence().status(), QString(QLatin1String("busy"))); QCOMPARE(mContacts[2]->presence().status(), QString(QLatin1String("away"))); QCOMPARE(mContacts[0]->presence().type(), Tp::ConnectionPresenceTypeAvailable); QCOMPARE(mContacts[1]->presence().type(), Tp::ConnectionPresenceTypeBusy); QCOMPARE(mContacts[2]->presence().type(), Tp::ConnectionPresenceTypeAway); // Make the contacts go out of scope, starting releasing their handles, and finish that saveContacts.clear(); mContacts.clear(); mLoop->processEvents(); processDBusQueue(mConn.data()); } void TestContacts::testSelfContactFallback() { gchar *name; gchar *connPath; GError *error = 0; TpTestsSimpleConnection *connService; connService = TP_TESTS_SIMPLE_CONNECTION(g_object_new( TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL)); QVERIFY(connService != 0); QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(connService), "simple", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); ConnectionPtr conn = Connection::create(QLatin1String(name), QLatin1String(connPath), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); g_free(name); g_free(connPath); QCOMPARE(conn->isReady(), false); Features features = Features() << Connection::FeatureSelfContact; QVERIFY(connect(conn->lowlevel()->requestConnect(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(conn->isReady(features), true); ContactPtr selfContact = conn->selfContact(); QVERIFY(selfContact != 0); QCOMPARE(selfContact->handle()[0], conn->selfHandle()); QCOMPARE(selfContact->id(), QString(QLatin1String("me@example.com"))); QCOMPARE(selfContact->alias(), QString(QLatin1String("me@example.com"))); QVERIFY(!selfContact->isAvatarTokenKnown()); QCOMPARE(selfContact->presence().isValid(), false); tp_tests_simple_connection_inject_disconnect(connService); if (conn->isValid()) { QVERIFY(connect(conn.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), mLoop, SLOT(quit()))); QCOMPARE(mLoop->exec(), 0); } g_object_unref(connService); } void TestContacts::cleanup() { cleanupImpl(); } void TestContacts::cleanupTestCase() { if (!mContacts.isEmpty()) { mContacts.clear(); } if (!mInvalidHandles.isEmpty()) { mInvalidHandles.clear(); } if (mConn) { // Disconnect and wait for the readiness change QVERIFY(connect(mConn->lowlevel()->requestDisconnect(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); if (mConn->isValid()) { QVERIFY(connect(mConn.data(), SIGNAL(invalidated(Tp::DBusProxy *, QString, QString)), SLOT(expectConnInvalidated()))); QCOMPARE(mLoop->exec(), 0); } } if (mConnService != 0) { g_object_unref(mConnService); mConnService = 0; } cleanupTestCaseImpl(); } QTEST_MAIN(TestContacts) #include "_gen/contacts.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/chan-basics.cpp0000664000175000017500000002274512470405660017740 0ustar jrjr#include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestChanBasics : public Test { Q_OBJECT public: TestChanBasics(QObject *parent = 0) : Test(parent), mConn(0), mHandle(0) { } protected Q_SLOTS: void expectInvalidated(); void expectPendingHandleFinished(Tp::PendingOperation *); private Q_SLOTS: void initTestCase(); void init(); void testRequestHandle(); void testCreateChannel(); void testEnsureChannel(); void testFallback(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; ChannelPtr mChan; QString mChanObjectPath; uint mHandle; }; void TestChanBasics::expectInvalidated() { mLoop->exit(0); } void TestChanBasics::expectPendingHandleFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingHandles *pending = qobject_cast(op); mHandle = pending->handles().at(0); mLoop->exit(0); } void TestChanBasics::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("chan-basics"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, EXAMPLE_TYPE_ECHO_2_CONNECTION, "account", "me@example.com", "protocol", "contacts", NULL); QCOMPARE(mConn->connect(), true); QCOMPARE(mConn->enableFeatures(Connection::FeatureSelfContact), true); } void TestChanBasics::init() { initImpl(); mChan.reset(); } void TestChanBasics::testRequestHandle() { // Test identifiers QStringList ids = QStringList() << QLatin1String("alice"); // Request handles for the identifiers and wait for the request to process PendingHandles *pending = mConn->client()->lowlevel()->requestHandles(Tp::HandleTypeContact, ids); QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingHandleFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(disconnect(pending, SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(expectPendingHandleFinished(Tp::PendingOperation*)))); QVERIFY(mHandle != 0); } void TestChanBasics::testCreateChannel() { mChan = mConn->createChannel(TP_QT_IFACE_CHANNEL_TYPE_TEXT, Tp::HandleTypeContact, mHandle); QVERIFY(mChan); mChanObjectPath = mChan->objectPath(); QVERIFY(connect(mChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(), true); QCOMPARE(mChan->isRequested(), true); QCOMPARE(mChan->channelType(), TP_QT_IFACE_CHANNEL_TYPE_TEXT); QCOMPARE(mChan->groupCanAddContacts(), false); QCOMPARE(mChan->groupCanRemoveContacts(), false); QCOMPARE(mChan->initiatorContact()->id(), QString(QLatin1String("me@example.com"))); QCOMPARE(mChan->groupSelfContact()->id(), QString(QLatin1String("me@example.com"))); QCOMPARE(mChan->groupSelfContact(), mConn->client()->selfContact()); QCOMPARE(mChan->targetId(), QString::fromLatin1("alice")); QVERIFY(!mChan->targetContact().isNull()); QCOMPARE(mChan->targetContact()->id(), QString::fromLatin1("alice")); QStringList ids; Q_FOREACH (const ContactPtr &contact, mChan->groupContacts()) { ids << contact->id(); QVERIFY(contact == mChan->groupSelfContact() || contact == mChan->targetContact()); } ids.sort(); QStringList toCheck = QStringList() << QLatin1String("me@example.com") << QLatin1String("alice"); toCheck.sort(); QCOMPARE(ids, toCheck); ChannelPtr chan = Channel::create(mConn->client(), mChan->objectPath(), mChan->immutableProperties()); QVERIFY(chan); QVERIFY(chan->isValid()); QVERIFY(connect(chan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(chan->isReady(), true); QCOMPARE(chan->channelType(), TP_QT_IFACE_CHANNEL_TYPE_TEXT); // create an invalid connection to use as the channel connection ConnectionPtr conn = Connection::create(QLatin1String(""), QLatin1String("/"), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QVERIFY(conn); QVERIFY(!conn->isValid()); chan = Channel::create(conn, mChan->objectPath(), mChan->immutableProperties()); QVERIFY(chan); QVERIFY(!chan->isValid()); QVERIFY(connect(chan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, chan->invalidationReason()); QCOMPARE(mLastErrorMessage, chan->invalidationMessage()); QCOMPARE(chan->channelType(), QString()); } void TestChanBasics::testEnsureChannel() { ChannelPtr chan = mConn->ensureChannel(TP_QT_IFACE_CHANNEL_TYPE_TEXT, Tp::HandleTypeContact, mHandle); QVERIFY(chan); QCOMPARE(chan->objectPath(), mChanObjectPath); mChan = chan; QVERIFY(connect(mChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(), true); QCOMPARE(mChan->isRequested(), true); QCOMPARE(mChan->groupCanAddContacts(), false); QCOMPARE(mChan->groupCanRemoveContacts(), false); QCOMPARE(mChan->initiatorContact()->id(), QString(QLatin1String("me@example.com"))); QCOMPARE(mChan->groupSelfContact()->id(), QString(QLatin1String("me@example.com"))); QCOMPARE(mChan->groupSelfContact(), mConn->client()->selfContact()); QStringList ids; Q_FOREACH (const ContactPtr &contact, mChan->groupContacts()) { ids << contact->id(); } ids.sort(); QStringList toCheck = QStringList() << QLatin1String("me@example.com") << QLatin1String("alice"); toCheck.sort(); QCOMPARE(ids, toCheck); QVERIFY(connect(mChan->requestClose(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isValid(), false); // calling requestClose again should be no-op QVERIFY(connect(mChan->requestClose(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isValid(), false); } void TestChanBasics::testFallback() { TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); guint handle = tp_handle_ensure(contactRepo, "someone@localhost", 0, 0); QString textChanPath = mConn->objectPath() + QLatin1String("/Channel"); QByteArray chanPath(textChanPath.toLatin1()); TpTestsTextChannelNull *textChanService = TP_TESTS_TEXT_CHANNEL_NULL (g_object_new ( TP_TESTS_TYPE_TEXT_CHANNEL_NULL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle, NULL)); TextChannelPtr textChan = TextChannel::create(mConn->client(), textChanPath, QVariantMap()); QVERIFY(connect(textChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(textChan->isReady(), true); QCOMPARE(textChanService->get_channel_type_called, static_cast(1)); QCOMPARE(textChanService->get_interfaces_called, static_cast(1)); QCOMPARE(textChanService->get_handle_called, static_cast(1)); QCOMPARE(textChan->channelType(), TP_QT_IFACE_CHANNEL_TYPE_TEXT); QVERIFY(textChan->interfaces().isEmpty()); QCOMPARE(textChan->targetHandleType(), Tp::HandleTypeContact); QCOMPARE(textChan->targetHandle(), handle); // we have no Group support, groupAddContacts should fail QVERIFY(connect(textChan->groupAddContacts(QList() << mConn->client()->selfContact()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED); QVERIFY(!mLastErrorMessage.isEmpty()); } void TestChanBasics::cleanup() { cleanupImpl(); } void TestChanBasics::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; if (mChan) { QVERIFY(!mChan->isValid()); QVERIFY(mChan->invalidationReason() == TP_QT_ERROR_CANCELLED || mChan->invalidationReason() == TP_QT_ERROR_ORPHANED); } cleanupTestCaseImpl(); } QTEST_MAIN(TestChanBasics) #include "_gen/chan-basics.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/call-channel.cpp0000664000175000017500000011126112470405660020076 0ustar jrjr#include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include using namespace Tp; class TestCallChannel : public Test { Q_OBJECT public: TestCallChannel(QObject *parent = 0) : Test(parent), mConn(0) { } protected Q_SLOTS: void expectRequestContentFinished(Tp::PendingOperation *op); void expectSuccessfulRequestReceiving(Tp::PendingOperation *op); void onContentRemoved(const Tp::CallContentPtr &content, const Tp::CallStateReason &reason); void onCallStateChanged(Tp::CallState newState); void onCallFlagsChanged(Tp::CallFlags newFlags); void onRemoteMemberFlagsChanged( const QHash &remoteMemberFlags, const Tp::CallStateReason &reason); void onRemoteMembersRemoved(const Tp::Contacts &remoteMembers, const Tp::CallStateReason &reason); void onLocalSendingStateChanged(Tp::SendingState localSendingState, const Tp::CallStateReason &reason); void onRemoteSendingStateChanged( const QHash &remoteSendingStates, const Tp::CallStateReason &reason); void onLocalHoldStateChanged(Tp::LocalHoldState state, Tp::LocalHoldStateReason reason); void onNewChannels(const Tp::ChannelDetailsList &details); private Q_SLOTS: void initTestCase(); void init(); void testOutgoingCall(); void testIncomingCall(); void testHold(); void testHangup(); void testCallMembers(); void testDTMF(); void testFeatureCore(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; CallChannelPtr mChan; CallContentPtr mRequestContentReturn; CallContentPtr mContentRemoved; CallStateReason mCallStateReason; CallState mCallState; CallFlags mCallFlags; QHash mRemoteMemberFlags; Contacts mRemoteMembersRemoved; SendingState mLSSCReturn; QQueue mLocalHoldStates; QQueue mLocalHoldStateReasons; // Remote sending state changed state-machine enum { RSSCStateInitial, RSSCStatePendingSend, RSSCStateSending, RSSCStateDone } mRSSCState; int mSuccessfulRequestReceivings; }; void TestCallChannel::expectRequestContentFinished(Tp::PendingOperation *op) { if (!op->isFinished()) { qWarning() << "unfinished"; mLoop->exit(1); return; } if (op->isError()) { qWarning().nospace() << op->errorName() << ": " << op->errorMessage(); mLoop->exit(2); return; } if (!op->isValid()) { qWarning() << "inconsistent results"; mLoop->exit(3); return; } PendingCallContent *pmc = qobject_cast(op); mRequestContentReturn = pmc->content(); mLoop->exit(0); } void TestCallChannel::onLocalSendingStateChanged(Tp::SendingState state, const Tp::CallStateReason &reason) { qDebug() << "local sending state changed"; mLSSCReturn = state; mCallStateReason = reason; mLoop->exit(0); } void TestCallChannel::expectSuccessfulRequestReceiving(Tp::PendingOperation *op) { if (!op->isFinished()) { qWarning() << "unfinished"; mLoop->exit(1); return; } if (op->isError()) { qWarning().nospace() << op->errorName() << ": " << op->errorMessage(); mLoop->exit(2); return; } if (!op->isValid()) { qWarning() << "inconsistent results"; mLoop->exit(3); return; } if (++mSuccessfulRequestReceivings == 2 && mRSSCState == RSSCStateDone) { mLoop->exit(0); } } void TestCallChannel::onContentRemoved(const CallContentPtr &content, const Tp::CallStateReason &reason) { mContentRemoved = content; mCallStateReason = reason; mLoop->exit(0); } void TestCallChannel::onCallStateChanged(CallState newState) { mCallState = newState; mLoop->exit(0); } void TestCallChannel::onCallFlagsChanged(CallFlags newFlags) { mCallFlags = newFlags; } void TestCallChannel::onRemoteMemberFlagsChanged( const QHash &remoteMemberFlags, const CallStateReason &reason) { mRemoteMemberFlags = remoteMemberFlags; mLoop->exit(0); } void TestCallChannel::onRemoteMembersRemoved(const Tp::Contacts &remoteMembers, const Tp::CallStateReason &reason) { mRemoteMembersRemoved = remoteMembers; } void TestCallChannel::onRemoteSendingStateChanged( const QHash &states, const Tp::CallStateReason &reason) { // There should be no further events QVERIFY(mRSSCState != RSSCStateDone); QCOMPARE(states.size(), 1); Tp::ContactPtr otherContact = states.keys().first(); CallContentPtr content = mChan->contentsForType(Tp::MediaStreamTypeVideo).first(); QVERIFY(content); CallStreamPtr stream = content->streams().first(); QVERIFY(stream); if (mRSSCState == RSSCStateInitial) { QCOMPARE(states[otherContact], SendingStatePendingSend); mRSSCState = RSSCStatePendingSend; } else if (mRSSCState == RSSCStatePendingSend) { QCOMPARE(states[otherContact], SendingStateSending); mRSSCState = RSSCStateSending; QVERIFY(connect(stream->requestReceiving(otherContact, false), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulRequestReceiving(Tp::PendingOperation*)))); } else if (mRSSCState == RSSCStateSending) { QCOMPARE(states[otherContact], SendingStateNone); mRSSCState = RSSCStateDone; if (mSuccessfulRequestReceivings == 2) { mLoop->exit(0); } } qDebug() << "remote sending state changed to" << states[otherContact]; } void TestCallChannel::onLocalHoldStateChanged(Tp::LocalHoldState localHoldState, Tp::LocalHoldStateReason localHoldStateReason) { mLocalHoldStates.append(localHoldState); mLocalHoldStateReasons.append(localHoldStateReason); mLoop->exit(0); } void TestCallChannel::onNewChannels(const Tp::ChannelDetailsList &channels) { qDebug() << "new channels"; Q_FOREACH (const Tp::ChannelDetails &details, channels) { QString channelType = details.properties.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString(); bool requested = details.properties.value(TP_QT_IFACE_CHANNEL + QLatin1String(".Requested")).toBool(); qDebug() << " channelType:" << channelType; qDebug() << " requested :" << requested; if (channelType == TP_QT_IFACE_CHANNEL_TYPE_CALL && !requested) { mChan = CallChannel::create(mConn->client(), details.channel.path(), details.properties); mLoop->exit(0); } } } void TestCallChannel::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("call-channel"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, EXAMPLE_TYPE_CALL_CONNECTION, "account", "me@example.com", "protocol", "example", "simulation-delay", 1, NULL); QCOMPARE(mConn->connect(Connection::FeatureSelfContact), true); } void TestCallChannel::init() { initImpl(); mRequestContentReturn.reset(); mContentRemoved.reset(); mCallStateReason = CallStateReason(); mCallState = CallStateUnknown; mCallFlags = (CallFlags) 0; mRemoteMemberFlags.clear(); mRemoteMembersRemoved.clear(); mLSSCReturn = (Tp::SendingState) -1; mLocalHoldStates.clear(); mLocalHoldStateReasons.clear(); } void TestCallChannel::testOutgoingCall() { qDebug() << "requesting contact for alice"; QList contacts = mConn->contacts(QStringList() << QLatin1String("alice")); QCOMPARE(contacts.size(), 1); ContactPtr otherContact = contacts.at(0); QVERIFY(otherContact); qDebug() << "creating the channel"; QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), otherContact->handle()[0]); request.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"), true); mChan = CallChannelPtr::qObjectCast(mConn->createChannel(request)); QVERIFY(mChan); qDebug() << "making the channel ready"; Features features; features << CallChannel::FeatureCallState << CallChannel::FeatureContents; QVERIFY(connect(mChan->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureCallState)); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureContents)); QCOMPARE(mChan->callState(), CallStatePendingInitiator); QVERIFY(connect(mChan->accept(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->callState(), CallStateInitialised); QCOMPARE(mChan->callStateReason().reason, (uint) CallStateChangeReasonUserRequested); QVERIFY(connect(mChan.data(), SIGNAL(callStateChanged(Tp::CallState)), SLOT(onCallStateChanged(Tp::CallState)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCallState, CallStateAccepted); QCOMPARE(mChan->callState(), CallStateAccepted); QCOMPARE(mChan->contents().size(), 1); Tp::CallContentPtr content; content = mChan->contents().first(); QVERIFY(content); QCOMPARE(content->name(), QString::fromLatin1("audio")); QCOMPARE(content->type(), Tp::MediaStreamTypeAudio); QCOMPARE(content->disposition(), Tp::CallContentDispositionInitial); QVERIFY(mChan->contentByName(QLatin1String("audio"))); /* QCOMPARE(mChan->groupContacts().size(), 2); QCOMPARE(mChan->groupLocalPendingContacts().size(), 0); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QVERIFY(mChan->groupContacts().contains(mConn->client()->selfContact())); QVERIFY(mChan->groupContacts().contains(otherContact)); */ qDebug() << "calling requestContent with a bad type"; // RequestContent with bad type must fail QVERIFY(connect(mChan->requestContent(QLatin1String("content1"), (Tp::MediaStreamType) -1, Tp::MediaStreamDirectionNone), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestContentFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 2); QVERIFY(!mRequestContentReturn); qDebug() << "calling requestContent with Audio"; QCOMPARE(mChan->contentsForType(Tp::MediaStreamTypeAudio).size(), 1); mRequestContentReturn.reset(); QVERIFY(connect(mChan->requestContent(QLatin1String("content1"), Tp::MediaStreamTypeAudio, Tp::MediaStreamDirectionBidirectional), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestContentFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mRequestContentReturn.isNull()); QCOMPARE(mRequestContentReturn->name(), QString(QLatin1String("content1"))); QCOMPARE(mRequestContentReturn->type(), Tp::MediaStreamTypeAudio); QCOMPARE(mRequestContentReturn->disposition(), Tp::CallContentDispositionNone); QCOMPARE(mChan->contentsForType(Tp::MediaStreamTypeAudio).size(), 2); qDebug() << "calling requestContent with Video"; mRequestContentReturn.reset(); QVERIFY(connect(mChan->requestContent(QLatin1String("content2"), Tp::MediaStreamTypeVideo, Tp::MediaStreamDirectionBidirectional), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestContentFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mRequestContentReturn.isNull()); QCOMPARE(mRequestContentReturn->name(), QString(QLatin1String("content2"))); QCOMPARE(mRequestContentReturn->type(), Tp::MediaStreamTypeVideo); // test content removal QCOMPARE(mChan->contentsForType(Tp::MediaStreamTypeAudio).size(), 2); content = mChan->contentsForType(Tp::MediaStreamTypeAudio).first(); QVERIFY(content); QVERIFY(connect(mChan.data(), SIGNAL(contentRemoved(Tp::CallContentPtr,Tp::CallStateReason)), SLOT(onContentRemoved(Tp::CallContentPtr,Tp::CallStateReason)))); QVERIFY(connect(content->remove(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); while (mContentRemoved.isNull()) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mChan->contentsForType(Tp::MediaStreamTypeAudio).size(), 1); QCOMPARE(mContentRemoved, content); QCOMPARE(mCallStateReason.reason, (uint) Tp::CallStateChangeReasonUserRequested); // test content sending changed content = mChan->contentsForType(Tp::MediaStreamTypeVideo).first(); Tp::CallStreamPtr stream = content->streams().first(); QVERIFY(content); QVERIFY(connect(stream.data(), SIGNAL(localSendingStateChanged(Tp::SendingState,Tp::CallStateReason)), SLOT(onLocalSendingStateChanged(Tp::SendingState,Tp::CallStateReason)))); qDebug() << "stopping sending"; QCOMPARE(stream->localSendingState(), Tp::SendingStateSending); QVERIFY(stream->remoteMembers().contains(otherContact)); QVERIFY(connect(stream->requestSending(false), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); qDebug() << "stopping receiving"; QVERIFY(connect(stream->requestReceiving(otherContact, false), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); qDebug() << "waiting until we're not sending and not receiving"; while (stream->localSendingState() != Tp::SendingStateNone || stream->remoteSendingState(otherContact) != Tp::SendingStateNone) { qDebug() << "re-entering mainloop to wait for local and remote SSC -> None"; // wait local and remote sending state change QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mLSSCReturn, Tp::SendingStateNone); QCOMPARE(stream->localSendingState(), Tp::SendingStateNone); QCOMPARE(stream->remoteSendingState(otherContact), Tp::SendingStateNone); qDebug() << "re-enabling sending"; mLSSCReturn = (Tp::SendingState) -1; QVERIFY(connect(stream->requestSending(true), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mLSSCReturn == (Tp::SendingState) -1) { qDebug() << "re-entering mainloop to wait for SSC -> Sending"; // wait sending state change QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mLSSCReturn, Tp::SendingStateSending); qDebug() << "flushing D-Bus events"; processDBusQueue(mChan.data()); qDebug() << "enabling receiving"; mRSSCState = RSSCStateInitial; mSuccessfulRequestReceivings = 0; QVERIFY(connect(stream.data(), SIGNAL(remoteSendingStateChanged(QHash,Tp::CallStateReason)), SLOT(onRemoteSendingStateChanged(QHash,Tp::CallStateReason)))); // test content receiving changed QVERIFY(connect(stream->requestReceiving(otherContact, true), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulRequestReceiving(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(static_cast(mRSSCState), static_cast(RSSCStateDone)); } void TestCallChannel::testIncomingCall() { mConn->client()->lowlevel()->setSelfPresence(QLatin1String("away"), QLatin1String("preparing for a test")); Tp::Client::ConnectionInterfaceRequestsInterface *connRequestsInterface = mConn->client()->optionalInterface(); QVERIFY(connect(connRequestsInterface, SIGNAL(NewChannels(const Tp::ChannelDetailsList&)), SLOT(onNewChannels(const Tp::ChannelDetailsList&)))); mConn->client()->lowlevel()->setSelfPresence(QLatin1String("available"), QLatin1String("call me?")); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan); QCOMPARE(mChan->contents().size(), 0); Features features; features << CallChannel::FeatureCallState << CallChannel::FeatureContents; QVERIFY(connect(mChan->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureCallState)); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureContents)); Tp::ContactPtr otherContact = mChan->initiatorContact(); QVERIFY(otherContact); QCOMPARE(mChan->callState(), CallStateInitialised); QVERIFY(connect(mChan.data(), SIGNAL(callFlagsChanged(Tp::CallFlags)), SLOT(onCallFlagsChanged(Tp::CallFlags)))); QVERIFY(connect(mChan->setRinging(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mCallFlags.testFlag(CallFlagLocallyRinging)); QVERIFY(mChan->callFlags().testFlag(CallFlagLocallyRinging)); QVERIFY(connect(mChan->setQueued(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mCallFlags.testFlag(CallFlagLocallyQueued)); QVERIFY(mChan->callFlags().testFlag(CallFlagLocallyQueued)); QVERIFY(connect(mChan->accept(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->callState(), CallStateAccepted); QVERIFY(!mCallFlags.testFlag(CallFlagLocallyQueued)); QVERIFY(!mCallFlags.testFlag(CallFlagLocallyRinging)); QVERIFY(!mChan->callFlags().testFlag(CallFlagLocallyRinging)); QVERIFY(!mChan->callFlags().testFlag(CallFlagLocallyQueued)); /* QCOMPARE(mChan->groupContacts().size(), 2); QCOMPARE(mChan->groupLocalPendingContacts().size(), 0); QCOMPARE(mChan->groupRemotePendingContacts().size(), 0); QVERIFY(mChan->groupContacts().contains(mConn->selfContact())); */ QCOMPARE(mChan->contents().size(), 1); Tp::CallContentPtr content = mChan->contents().first(); QCOMPARE(content->channel(), mChan); QCOMPARE(content->type(), Tp::MediaStreamTypeAudio); qDebug() << "requesting a video stream"; // Request video stream QVERIFY(connect(mChan->requestContent(QLatin1String("video_content"), Tp::MediaStreamTypeVideo, Tp::MediaStreamDirectionBidirectional), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestContentFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); content = mRequestContentReturn; QCOMPARE(content->type(), Tp::MediaStreamTypeVideo); QCOMPARE(mChan->contents().size(), 2); QVERIFY(mChan->contents().contains(content)); QCOMPARE(mChan->contentsForType(Tp::MediaStreamTypeAudio).size(), 1); QCOMPARE(mChan->contentsForType(Tp::MediaStreamTypeVideo).size(), 1); // test content removal content = mChan->contentsForType(Tp::MediaStreamTypeAudio).first(); QVERIFY(content); qDebug() << "removing the audio content"; // call does not have the concept of removing streams, it will remove the content the stream // belongs QVERIFY(connect(mChan.data(), SIGNAL(contentRemoved(Tp::CallContentPtr,Tp::CallStateReason)), SLOT(onContentRemoved(Tp::CallContentPtr,Tp::CallStateReason)))); QVERIFY(connect(content->remove(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); while (mContentRemoved.isNull()) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mContentRemoved, content); } void TestCallChannel::testHold() { QList contacts = mConn->contacts(QStringList() << QLatin1String("bob")); QCOMPARE(contacts.size(), 1); ContactPtr otherContact = contacts.at(0); QVERIFY(otherContact); QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), otherContact->handle()[0]); request.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"), true); mChan = CallChannelPtr::qObjectCast(mConn->createChannel(request)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(Tp::CallChannel::FeatureLocalHoldState), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureLocalHoldState)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(Tp::LocalHoldStateUnheld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(Tp::LocalHoldStateReasonNone)); QVERIFY(connect(mChan.data(), SIGNAL(localHoldStateChanged(Tp::LocalHoldState, Tp::LocalHoldStateReason)), SLOT(onLocalHoldStateChanged(Tp::LocalHoldState, Tp::LocalHoldStateReason)))); // Request hold QVERIFY(connect(mChan->requestHold(true), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mLocalHoldStates.size() != 2) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mLocalHoldStates.first(), static_cast(Tp::LocalHoldStatePendingHold)); QCOMPARE(mLocalHoldStateReasons.first(), static_cast(Tp::LocalHoldStateReasonRequested)); QCOMPARE(mLocalHoldStates.last(), static_cast(Tp::LocalHoldStateHeld)); QCOMPARE(mLocalHoldStateReasons.last(), static_cast(Tp::LocalHoldStateReasonRequested)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(Tp::LocalHoldStateHeld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(Tp::LocalHoldStateReasonRequested)); mLocalHoldStates.clear(); mLocalHoldStateReasons.clear(); // Request unhold QVERIFY(connect(mChan->requestHold(false), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); while (mLocalHoldStates.size() != 2) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mLocalHoldStates.first(), static_cast(Tp::LocalHoldStatePendingUnhold)); QCOMPARE(mLocalHoldStateReasons.first(), static_cast(Tp::LocalHoldStateReasonRequested)); QCOMPARE(mLocalHoldStates.last(), static_cast(Tp::LocalHoldStateUnheld)); QCOMPARE(mLocalHoldStateReasons.last(), static_cast(Tp::LocalHoldStateReasonRequested)); QCOMPARE(static_cast(mChan->localHoldState()), static_cast(Tp::LocalHoldStateUnheld)); QCOMPARE(static_cast(mChan->localHoldStateReason()), static_cast(Tp::LocalHoldStateReasonRequested)); } void TestCallChannel::testHangup() { qDebug() << "requesting contact for alice"; QList contacts = mConn->contacts(QStringList() << QLatin1String("alice")); QCOMPARE(contacts.size(), 1); ContactPtr otherContact = contacts.at(0); QVERIFY(otherContact); qDebug() << "creating the channel"; QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), otherContact->handle()[0]); request.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo"), true); mChan = CallChannelPtr::qObjectCast(mConn->createChannel(request)); QVERIFY(mChan); qDebug() << "making the channel ready"; QVERIFY(connect(mChan->becomeReady(CallChannel::FeatureCallState), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureCallState)); QCOMPARE(mChan->callState(), CallStatePendingInitiator); QVERIFY(connect(mChan->hangup(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->callState(), CallStateEnded); QCOMPARE(mChan->callStateReason().reason, (uint) CallStateChangeReasonUserRequested); } void TestCallChannel::testCallMembers() { qDebug() << "requesting contact for john"; QList contacts = mConn->contacts(QStringList() << QLatin1String("john")); QCOMPARE(contacts.size(), 1); ContactPtr otherContact = contacts.at(0); QVERIFY(otherContact); qDebug() << "creating the channel"; QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), otherContact->handle()[0]); request.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo"), true); mChan = CallChannelPtr::qObjectCast(mConn->createChannel(request)); QVERIFY(mChan); qDebug() << "making the channel ready"; Features features; features << CallChannel::FeatureCallState << CallChannel::FeatureCallMembers << CallChannel::FeatureContents; QVERIFY(connect(mChan->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureCallMembers)); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureContents)); qDebug() << "accepting the call"; QCOMPARE(mChan->callState(), CallStatePendingInitiator); QCOMPARE(mChan->remoteMembers().size(), 1); QVERIFY(connect(mChan->accept(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->callState(), CallStateInitialised); QCOMPARE(mChan->callStateReason().reason, (uint) CallStateChangeReasonUserRequested); qDebug() << "ringing on the remote side"; QVERIFY(connect(mChan.data(), SIGNAL(remoteMemberFlagsChanged(QHash,Tp::CallStateReason)), SLOT(onRemoteMemberFlagsChanged(QHash,Tp::CallStateReason)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->callState(), CallStateInitialised); QCOMPARE(mRemoteMemberFlags.size(), 1); QCOMPARE(mChan->remoteMembers().size(), 1); QVERIFY(mRemoteMemberFlags.constBegin().value().testFlag(CallMemberFlagRinging)); QVERIFY(mChan->remoteMemberFlags(otherContact).testFlag(CallMemberFlagRinging)); QVERIFY(disconnect(mChan.data(), SIGNAL(remoteMemberFlagsChanged(QHash,Tp::CallStateReason)), this, SLOT(onRemoteMemberFlagsChanged(QHash,Tp::CallStateReason)))); qDebug() << "remote contact answers"; QVERIFY(connect(mChan.data(), SIGNAL(callStateChanged(Tp::CallState)), SLOT(onCallStateChanged(Tp::CallState)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCallState, CallStateAccepted); QCOMPARE(mChan->callState(), CallStateAccepted); QVERIFY(disconnect(mChan.data(), SIGNAL(callStateChanged(Tp::CallState)), this, SLOT(onCallStateChanged(Tp::CallState)))); qDebug() << "testing members"; QCOMPARE(mChan->contents().size(), 1); CallContentPtr content = mChan->contents().at(0); QCOMPARE(content->streams().size(), 1); QCOMPARE(mChan->remoteMembers().size(), 1); QCOMPARE(content->streams().at(0)->remoteMembers().size(), 1); ContactPtr contact1 = *mChan->remoteMembers().constBegin(); ContactPtr contact2 = *content->streams().at(0)->remoteMembers().constBegin(); QCOMPARE(contact1->id(), QString::fromLatin1("john")); QCOMPARE(contact2->id(), QString::fromLatin1("john")); qDebug() << "hanging up"; QVERIFY(connect(mChan.data(), SIGNAL(remoteMembersRemoved(Tp::Contacts,Tp::CallStateReason)), SLOT(onRemoteMembersRemoved(Tp::Contacts,Tp::CallStateReason)))); QVERIFY(connect(mChan->hangup(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->callState(), CallStateEnded); QCOMPARE(mChan->callStateReason().reason, (uint) CallStateChangeReasonUserRequested); QCOMPARE(mRemoteMembersRemoved.size(), 1); QCOMPARE((*mRemoteMembersRemoved.constBegin())->id(), QString::fromLatin1("john")); QCOMPARE(mChan->remoteMembers().size(), 0); QCOMPARE(mChan->contents().size(), 0); } void TestCallChannel::testDTMF() { mConn->client()->lowlevel()->setSelfPresence(QLatin1String("away"), QLatin1String("preparing for a test")); Tp::Client::ConnectionInterfaceRequestsInterface *connRequestsInterface = mConn->client()->optionalInterface(); QVERIFY(connect(connRequestsInterface, SIGNAL(NewChannels(const Tp::ChannelDetailsList&)), SLOT(onNewChannels(const Tp::ChannelDetailsList&)))); mConn->client()->lowlevel()->setSelfPresence(QLatin1String("available"), QLatin1String("call me?")); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan); qDebug() << "making the channel ready"; QVERIFY(connect(mChan->becomeReady(CallChannel::FeatureContents), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureContents)); QVERIFY(connect(mChan->accept(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->contents().size(), 1); Tp::CallContentPtr content = mChan->contents().first(); QCOMPARE(content->channel(), mChan); QCOMPARE(content->type(), Tp::MediaStreamTypeAudio); /* TODO enable when/if the example call CM actually supports DTMF QVERIFY(content->supportsDTMF()); QVERIFY(connect(content->startDTMFTone(DTMFEventDigit0), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(content->stopDTMFTone(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(content->startDTMFTone((DTMFEvent) 1234), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, QString(TP_QT_ERROR_INVALID_ARGUMENT)); */ qDebug() << "requesting video content"; QVERIFY(connect(mChan->requestContent(QLatin1String("video_content"), Tp::MediaStreamTypeVideo, Tp::MediaStreamDirectionBidirectional), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectRequestContentFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); content = mRequestContentReturn; QCOMPARE(content->type(), Tp::MediaStreamTypeVideo); QVERIFY(!content->supportsDTMF()); QVERIFY(connect(content->startDTMFTone(DTMFEventDigit0), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, QString(TP_QT_ERROR_NOT_IMPLEMENTED)); QVERIFY(connect(content->stopDTMFTone(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, QString(TP_QT_ERROR_NOT_IMPLEMENTED)); } void TestCallChannel::testFeatureCore() { qDebug() << "requesting contact for alice"; QList contacts = mConn->contacts(QStringList() << QLatin1String("alice")); QCOMPARE(contacts.size(), 1); ContactPtr otherContact = contacts.at(0); QVERIFY(otherContact); qDebug() << "creating the channel"; QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), otherContact->handle()[0]); request.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"), true); mChan = CallChannelPtr::qObjectCast(mConn->createChannel(request)); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(Tp::CallChannel::FeatureCore)); QVERIFY(mChan->hasInitialAudio()); QCOMPARE(mChan->initialAudioName(), QString::fromLatin1("audio")); QVERIFY(!mChan->hasInitialVideo()); QCOMPARE(mChan->initialVideoName(), QString::fromLatin1("video")); QVERIFY(mChan->hasMutableContents()); QVERIFY(mChan->handlerStreamingRequired()); qDebug() << "creating second CallChannel object"; //this object is not passed immutable properties on //the constructor, so it will have to introspect them. CallChannelPtr chan2 = CallChannel::create(mConn->client(), mChan->objectPath(), QVariantMap()); QVERIFY(connect(chan2->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(chan2->isReady(Tp::CallChannel::FeatureCore)); QVERIFY(chan2->hasInitialAudio()); QCOMPARE(chan2->initialAudioName(), QString::fromLatin1("audio")); QVERIFY(!chan2->hasInitialVideo()); QCOMPARE(chan2->initialVideoName(), QString::fromLatin1("video")); QVERIFY(chan2->hasMutableContents()); QVERIFY(chan2->handlerStreamingRequired()); } void TestCallChannel::cleanup() { mChan.reset(); cleanupImpl(); } void TestCallChannel::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestCallChannel) #include "_gen/call-channel.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/base-protocol.cpp0000664000175000017500000006536512470405660020343 0ustar jrjr#include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include using namespace Tp; class TestBaseProtocolCM; typedef SharedPtr TestBaseProtocolCMPtr; class TestBaseProtocolCM : public BaseConnectionManager { public: TestBaseProtocolCM(const QDBusConnection &conn, const QString & name) : BaseConnectionManager(conn, name) { } static void createCM(TestBaseProtocolCMPtr &cm); private: static BaseConnectionPtr createConnectionCb(const QVariantMap ¶meters, Tp::DBusError *error); static QString identifyAccountCb(const QVariantMap ¶meters, Tp::DBusError *error); static QString normalizeContactCb(const QString &contactId, Tp::DBusError *error); static QString normalizeVCardAddressCb(const QString &vcardField, const QString &vcardAddress, Tp::DBusError *error); static QString normalizeContactUriCb(const QString &uri, Tp::DBusError *error); }; class TestBaseProtocol : public Test { Q_OBJECT public: TestBaseProtocol(QObject *parent = 0) : Test(parent) { } private: static void protocolObjectSvcSideCb(TestBaseProtocolCMPtr &cm); static void addressingIfaceSvcSideCb(TestBaseProtocolCMPtr &cm); static void avatarsIfaceSvcSideCb(TestBaseProtocolCMPtr &cm); static void presenceIfaceSvcSideCb(TestBaseProtocolCMPtr &cm); private Q_SLOTS: void initTestCase(); void init(); void protocolObjectSvcSide(); void protocolObjectClientSide(); void addressingIfaceSvcSide(); void addressingIfaceClientSide(); void avatarsIfaceSvcSide(); void avatarsIfaceClientSide(); void presenceIfaceSvcSide(); void presenceIfaceClientSide(); void cleanup(); void cleanupTestCase(); private: TestThreadHelper *mThreadHelper; }; void TestBaseProtocolCM::createCM(TestBaseProtocolCMPtr &cm) { cm = BaseConnectionManager::create(QLatin1String("testcm")); BaseProtocolPtr protocol = BaseProtocol::create(QLatin1String("example")); protocol->setConnectionInterfaces(QStringList() << TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST); protocol->setParameters(ProtocolParameterList() << ProtocolParameter(QLatin1String("account"), QDBusSignature("s"), Tp::ConnMgrParamFlagRequired | Tp::ConnMgrParamFlagRegister)); protocol->setRequestableChannelClasses(RequestableChannelClassSpec::textChat()); protocol->setVCardField(QLatin1String("x-telepathy-example")); protocol->setEnglishName(QLatin1String("Test CM")); protocol->setIconName(QLatin1String("im-icq")); protocol->setAuthenticationTypes(QStringList() << TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION); protocol->setCreateConnectionCallback(ptrFun(&TestBaseProtocolCM::createConnectionCb)); protocol->setIdentifyAccountCallback(ptrFun(&TestBaseProtocolCM::identifyAccountCb)); protocol->setNormalizeContactCallback(ptrFun(&TestBaseProtocolCM::normalizeContactCb)); BaseProtocolAddressingInterfacePtr addressingIface = BaseProtocolAddressingInterface::create(); addressingIface->setAddressableUriSchemes(QStringList() << QLatin1String("xmpp") << QLatin1String("tel")); addressingIface->setAddressableVCardFields(QStringList() << QLatin1String("x-jabber") << QLatin1String("tel")); addressingIface->setNormalizeVCardAddressCallback( ptrFun(&TestBaseProtocolCM::normalizeVCardAddressCb)); addressingIface->setNormalizeContactUriCallback( ptrFun(&TestBaseProtocolCM::normalizeContactUriCb)); QVERIFY(protocol->plugInterface(addressingIface)); BaseProtocolAvatarsInterfacePtr avatarsIface = BaseProtocolAvatarsInterface::create(); avatarsIface->setAvatarDetails( AvatarSpec(QStringList() << QLatin1String("image/png") << QLatin1String("image/jpeg") << QLatin1String("image/gif"), 32, 96, 64, 32, 96, 64, 37748736)); QVERIFY(protocol->plugInterface(avatarsIface)); BaseProtocolPresenceInterfacePtr presenceIface = BaseProtocolPresenceInterface::create(); presenceIface->setStatuses(PresenceSpecList() << PresenceSpec::available() << PresenceSpec::away() << PresenceSpec::busy() << PresenceSpec::offline()); QVERIFY(protocol->plugInterface(presenceIface)); QVERIFY(cm->addProtocol(protocol)); Tp::DBusError err; QVERIFY(cm->registerObject(&err)); QVERIFY(!err.isValid()); QVERIFY(cm->isRegistered()); } BaseConnectionPtr TestBaseProtocolCM::createConnectionCb(const QVariantMap ¶meters, Tp::DBusError *error) { if (parameters.contains(QLatin1String("account"))) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, parameters.value(QLatin1String("account")).toString()); } else { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("This test doesn't create connections")); } return BaseConnectionPtr(); } QString TestBaseProtocolCM::identifyAccountCb(const QVariantMap ¶meters, Tp::DBusError *error) { QString account = parameters.value(QLatin1String("account")).toString(); if (account.isEmpty()) { error->set(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("'account' parameter not given")); } return account; } QString TestBaseProtocolCM::normalizeContactCb(const QString &contactId, Tp::DBusError *error) { if (contactId.isEmpty()) { error->set(TP_QT_ERROR_INVALID_HANDLE, QLatin1String("ID must not be empty")); return QString(); } return contactId.toLower(); } QString TestBaseProtocolCM::normalizeVCardAddressCb(const QString &vcardField, const QString &vcardAddress, Tp::DBusError *error) { if (vcardField == QLatin1String("x-jabber")) { return vcardAddress.toLower() + QLatin1String("@wonderland"); } else { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Invalid VCard field")); return QString(); } } QString TestBaseProtocolCM::normalizeContactUriCb(const QString &uri, Tp::DBusError *error) { if (uri.startsWith(QLatin1String("xmpp:"))) { if (uri.contains(QLatin1Char('/'))) { return uri.left(uri.indexOf(QLatin1Char('/'))); } else { return uri; } } else { error->set(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid URI")); return QString(); } } void TestBaseProtocol::initTestCase() { initTestCaseImpl(); } void TestBaseProtocol::init() { initImpl(); mThreadHelper = new TestThreadHelper(); TEST_THREAD_HELPER_EXECUTE(mThreadHelper, &TestBaseProtocolCM::createCM); } void TestBaseProtocol::protocolObjectSvcSideCb(TestBaseProtocolCMPtr &cm) { QCOMPARE(cm->name(), QLatin1String("testcm")); QVERIFY(cm->hasProtocol(QLatin1String("example"))); QCOMPARE(cm->protocols().size(), 1); BaseProtocolPtr protocol = cm->protocols().at(0); QVERIFY(protocol); //basic properties QCOMPARE(protocol->name(), QLatin1String("example")); QCOMPARE(protocol->vcardField(), QLatin1String("x-telepathy-example")); QCOMPARE(protocol->englishName(), QLatin1String("Test CM")); QCOMPARE(protocol->iconName(), QLatin1String("im-icq")); QCOMPARE(protocol->connectionInterfaces(), QStringList() << TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST); QCOMPARE(protocol->authenticationTypes(), QStringList() << TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION); QCOMPARE(protocol->requestableChannelClasses().size(), 1); QCOMPARE(protocol->requestableChannelClasses().at(0), RequestableChannelClassSpec::textChat()); //parameters QCOMPARE(protocol->parameters().size(), 1); QCOMPARE(protocol->parameters().at(0).name(), QLatin1String("account")); QCOMPARE(protocol->parameters().at(0).dbusSignature(), QDBusSignature("s")); QVERIFY(protocol->parameters().at(0).isRequired()); QVERIFY(protocol->parameters().at(0).isRequiredForRegistration()); QVERIFY(!protocol->parameters().at(0).isSecret()); //interfaces QCOMPARE(protocol->interfaces().size(), 3); //immutable props QVariantMap props = protocol->immutableProperties(); QVERIFY(props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".Interfaces"))); QStringList sl = props.value( TP_QT_IFACE_PROTOCOL + QLatin1String(".Interfaces")).toStringList(); QVERIFY(sl.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING)); QVERIFY(sl.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS)); QVERIFY(sl.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE)); QVERIFY(props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".Parameters"))); ParamSpecList params = qvariant_cast(props.value( TP_QT_IFACE_PROTOCOL + QLatin1String(".Parameters"))); QCOMPARE(params.size(), 1); QCOMPARE(params.at(0).name, QLatin1String("account")); QCOMPARE(params.at(0).signature, QLatin1String("s")); QCOMPARE(params.at(0).flags, uint(ConnMgrParamFlagRequired | ConnMgrParamFlagRegister)); QVERIFY(props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".VCardField"))); QCOMPARE(props.value(TP_QT_IFACE_PROTOCOL + QLatin1String(".VCardField")).toString(), QLatin1String("x-telepathy-example")); QVERIFY(props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".EnglishName"))); QCOMPARE(props.value(TP_QT_IFACE_PROTOCOL + QLatin1String(".EnglishName")).toString(), QLatin1String("Test CM")); QVERIFY(props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".Icon"))); QCOMPARE(props.value(TP_QT_IFACE_PROTOCOL + QLatin1String(".Icon")).toString(), QLatin1String("im-icq")); QVERIFY(props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".RequestableChannelClasses"))); RequestableChannelClassList rcc = qvariant_cast(props.value( TP_QT_IFACE_PROTOCOL + QLatin1String(".RequestableChannelClasses"))); QCOMPARE(rcc.size(), 1); QCOMPARE(RequestableChannelClassSpec(rcc.at(0)), RequestableChannelClassSpec::textChat()); QVERIFY(props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".ConnectionInterfaces"))); sl = props.value(TP_QT_IFACE_PROTOCOL + QLatin1String(".ConnectionInterfaces")).toStringList(); QCOMPARE(sl, QStringList() << TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST); QVERIFY(props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".AuthenticationTypes"))); sl = props.value(TP_QT_IFACE_PROTOCOL + QLatin1String(".AuthenticationTypes")).toStringList(); QCOMPARE(sl, QStringList() << TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION); //interface immutable properties should also be here //test only one - the rest later QVERIFY(props.contains( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarHeight"))); QCOMPARE(props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarHeight")).toInt(), 32); //methods { Tp::DBusError err; QString normalizedContact = protocol->normalizeContact(QLatin1String("BoB"), &err); QVERIFY(!err.isValid()); QCOMPARE(normalizedContact, QLatin1String("bob")); } { Tp::DBusError err; QString account = protocol->identifyAccount(QVariantMap(), &err); QVERIFY(err.isValid()); QVERIFY(account.isEmpty()); QCOMPARE(err.name(), TP_QT_ERROR_INVALID_ARGUMENT); QCOMPARE(err.message(), QLatin1String("'account' parameter not given")); } { Tp::DBusError err; BaseConnectionPtr conn = protocol->createConnection(QVariantMap(), &err); QVERIFY(err.isValid()); QVERIFY(conn.isNull()); QCOMPARE(err.name(), TP_QT_ERROR_NOT_IMPLEMENTED); QCOMPARE(err.message(), QLatin1String("This test doesn't create connections")); } } void TestBaseProtocol::protocolObjectSvcSide() { TEST_THREAD_HELPER_EXECUTE(mThreadHelper, &TestBaseProtocol::protocolObjectSvcSideCb); } void TestBaseProtocol::protocolObjectClientSide() { ConnectionManagerPtr cliCM = ConnectionManager::create(QLatin1String("testcm")); PendingReady *pr = cliCM->becomeReady(ConnectionManager::FeatureCore); connect(pr, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cliCM->supportedProtocols().size(), 1); QVERIFY(cliCM->hasProtocol(QLatin1String("example"))); ProtocolInfo protocol = cliCM->protocol(QLatin1String("example")); QVERIFY(protocol.isValid()); Tp::Client::ProtocolInterface protocolIface(cliCM->busName(), cliCM->objectPath() + QLatin1String("/example")); //basic properties QCOMPARE(protocol.vcardField(), QLatin1String("x-telepathy-example")); QCOMPARE(protocol.englishName(), QLatin1String("Test CM")); QCOMPARE(protocol.iconName(), QLatin1String("im-icq")); QCOMPARE(protocol.capabilities().allClassSpecs().size(), 1); QVERIFY(protocol.capabilities().textChats()); PendingVariant *pv = protocolIface.requestPropertyConnectionInterfaces(); connect(pv, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(pv->result().toStringList(), QStringList() << TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST); pv = protocolIface.requestPropertyAuthenticationTypes(); connect(pv, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(pv->result().toStringList(), QStringList() << TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION); //parameters QVERIFY(protocol.hasParameter(QLatin1String("account"))); ProtocolParameterList params = protocol.parameters(); QCOMPARE(params.size(), 1); QCOMPARE(params.at(0).name(), QLatin1String("account")); QCOMPARE(params.at(0).dbusSignature(), QDBusSignature("s")); QVERIFY(params.at(0).isRequired()); QVERIFY(params.at(0).isRequiredForRegistration()); QVERIFY(!params.at(0).isSecret()); //methods { QDBusPendingReply reply = protocolIface.NormalizeContact(QLatin1String("ALiCe")); reply.waitForFinished(); QVERIFY(!reply.isError()); QCOMPARE(reply.value(), QLatin1String("alice")); } QVariantMap map; map.insert(QLatin1String("account"), QLatin1String("example@nowhere.com")); { QDBusPendingReply reply = protocolIface.IdentifyAccount(map); reply.waitForFinished(); QVERIFY(!reply.isError()); QCOMPARE(reply.value(), QLatin1String("example@nowhere.com")); } PendingConnection *pc = cliCM->lowlevel()->requestConnection(QLatin1String("example"), map); connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED); QCOMPARE(mLastErrorMessage, QLatin1String("example@nowhere.com")); } void TestBaseProtocol::addressingIfaceSvcSideCb(TestBaseProtocolCMPtr &cm) { QCOMPARE(cm->name(), QLatin1String("testcm")); QVERIFY(cm->hasProtocol(QLatin1String("example"))); QCOMPARE(cm->protocols().size(), 1); Tp::BaseProtocolPtr protocol = cm->protocols().at(0); QVERIFY(protocol); Tp::BaseProtocolAddressingInterfacePtr iface = Tp::BaseProtocolAddressingInterfacePtr::qObjectCast( protocol->interface(TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING)); QVERIFY(iface); //properties QStringList uriSchemes = iface->addressableUriSchemes(); QCOMPARE(uriSchemes.size(), 2); QVERIFY(uriSchemes.contains(QLatin1String("xmpp"))); QVERIFY(uriSchemes.contains(QLatin1String("tel"))); QStringList vcardFields = iface->addressableVCardFields(); QCOMPARE(vcardFields.size(), 2); QVERIFY(vcardFields.contains(QLatin1String("x-jabber"))); QVERIFY(vcardFields.contains(QLatin1String("tel"))); //no immutable properties QVERIFY(iface->immutableProperties().isEmpty()); //methods { Tp::DBusError err; QString result = iface->normalizeVCardAddress(QLatin1String("x-msn"), QLatin1String("Alice"), &err); QVERIFY(err.isValid()); QVERIFY(result.isEmpty()); QCOMPARE(err.name(), TP_QT_ERROR_NOT_IMPLEMENTED); QCOMPARE(err.message(), QLatin1String("Invalid VCard field")); } { Tp::DBusError err; QString result = iface->normalizeContactUri( QLatin1String("xmpp:alice@wonderland/Mobile"), &err); QVERIFY(!err.isValid()); QCOMPARE(result, QLatin1String("xmpp:alice@wonderland")); } } void TestBaseProtocol::addressingIfaceSvcSide() { TEST_THREAD_HELPER_EXECUTE(mThreadHelper, &TestBaseProtocol::addressingIfaceSvcSideCb); } void TestBaseProtocol::addressingIfaceClientSide() { ConnectionManagerPtr cliCM = ConnectionManager::create(QLatin1String("testcm")); PendingReady *pr = cliCM->becomeReady(ConnectionManager::FeatureCore); connect(pr, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cliCM->supportedProtocols().size(), 1); QVERIFY(cliCM->hasProtocol(QLatin1String("example"))); ProtocolInfo protocol = cliCM->protocol(QLatin1String("example")); QVERIFY(protocol.isValid()); //properties QStringList uriSchemes = protocol.addressableUriSchemes(); QCOMPARE(uriSchemes.size(), 2); QVERIFY(uriSchemes.contains(QLatin1String("xmpp"))); QVERIFY(uriSchemes.contains(QLatin1String("tel"))); QStringList vcardFields = protocol.addressableVCardFields(); QCOMPARE(vcardFields.size(), 2); QVERIFY(vcardFields.contains(QLatin1String("x-jabber"))); QVERIFY(vcardFields.contains(QLatin1String("tel"))); //methods PendingString *str = protocol.normalizeVCardAddress(QLatin1String("x-jabber"), QLatin1String("Alice")); connect(str, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(str->result(), QLatin1String("alice@wonderland")); str = protocol.normalizeContactUri(QLatin1String("invalid")); connect(str, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_INVALID_ARGUMENT); QCOMPARE(mLastErrorMessage, QLatin1String("Invalid URI")); } void TestBaseProtocol::avatarsIfaceSvcSideCb(TestBaseProtocolCMPtr &cm) { QCOMPARE(cm->name(), QLatin1String("testcm")); QVERIFY(cm->hasProtocol(QLatin1String("example"))); QCOMPARE(cm->protocols().size(), 1); Tp::BaseProtocolPtr protocol = cm->protocols().at(0); QVERIFY(protocol); Tp::BaseProtocolAvatarsInterfacePtr iface = Tp::BaseProtocolAvatarsInterfacePtr::qObjectCast( protocol->interface(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS)); QVERIFY(iface); //avatar details property AvatarSpec avatarSpec = iface->avatarDetails(); QVERIFY(avatarSpec.isValid()); QStringList mimeTypes = avatarSpec.supportedMimeTypes(); QCOMPARE(mimeTypes.size(), 3); QVERIFY(mimeTypes.contains(QLatin1String("image/png"))); QVERIFY(mimeTypes.contains(QLatin1String("image/jpeg"))); QVERIFY(mimeTypes.contains(QLatin1String("image/gif"))); QCOMPARE(avatarSpec.minimumWidth(), 32U); QCOMPARE(avatarSpec.maximumWidth(), 96U); QCOMPARE(avatarSpec.recommendedWidth(), 64U); QCOMPARE(avatarSpec.minimumHeight(), 32U); QCOMPARE(avatarSpec.maximumHeight(), 96U); QCOMPARE(avatarSpec.recommendedHeight(), 64U); QCOMPARE(avatarSpec.maximumBytes(), 37748736U); //immutable properties QVariantMap props = protocol->immutableProperties(); QVERIFY(props.contains( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".SupportedAvatarMIMETypes"))); mimeTypes = props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".SupportedAvatarMIMETypes")) .toStringList(); QCOMPARE(mimeTypes.size(), 3); QVERIFY(mimeTypes.contains(QLatin1String("image/png"))); QVERIFY(mimeTypes.contains(QLatin1String("image/jpeg"))); QVERIFY(mimeTypes.contains(QLatin1String("image/gif"))); QVERIFY(props.contains( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarHeight"))); QCOMPARE(props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarHeight")).toInt(), 32); QVERIFY(props.contains( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarWidth"))); QCOMPARE(props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarWidth")).toInt(), 32); QVERIFY(props.contains( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarHeight"))); QCOMPARE(props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarHeight")).toInt(), 64); QVERIFY(props.contains( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarWidth"))); QCOMPARE(props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarWidth")).toInt(), 64); QVERIFY(props.contains( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarHeight"))); QCOMPARE(props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarHeight")).toInt(), 96); QVERIFY(props.contains( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarWidth"))); QCOMPARE(props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarWidth")).toInt(), 96); QVERIFY(props.contains( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarBytes"))); QCOMPARE(props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarBytes")).toInt(), 37748736); } void TestBaseProtocol::avatarsIfaceSvcSide() { TEST_THREAD_HELPER_EXECUTE(mThreadHelper, &TestBaseProtocol::avatarsIfaceSvcSideCb); } void TestBaseProtocol::avatarsIfaceClientSide() { ConnectionManagerPtr cliCM = ConnectionManager::create(QLatin1String("testcm")); PendingReady *pr = cliCM->becomeReady(ConnectionManager::FeatureCore); connect(pr, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cliCM->supportedProtocols().size(), 1); QVERIFY(cliCM->hasProtocol(QLatin1String("example"))); ProtocolInfo protocol = cliCM->protocol(QLatin1String("example")); QVERIFY(protocol.isValid()); //avatar iface AvatarSpec avatarSpec = protocol.avatarRequirements(); QVERIFY(avatarSpec.isValid()); QStringList mimeTypes = avatarSpec.supportedMimeTypes(); QCOMPARE(mimeTypes.size(), 3); QVERIFY(mimeTypes.contains(QLatin1String("image/png"))); QVERIFY(mimeTypes.contains(QLatin1String("image/jpeg"))); QVERIFY(mimeTypes.contains(QLatin1String("image/gif"))); QCOMPARE(avatarSpec.minimumWidth(), 32U); QCOMPARE(avatarSpec.maximumWidth(), 96U); QCOMPARE(avatarSpec.recommendedWidth(), 64U); QCOMPARE(avatarSpec.minimumHeight(), 32U); QCOMPARE(avatarSpec.maximumHeight(), 96U); QCOMPARE(avatarSpec.recommendedHeight(), 64U); QCOMPARE(avatarSpec.maximumBytes(), 37748736U); } void TestBaseProtocol::presenceIfaceSvcSideCb(TestBaseProtocolCMPtr &cm) { QCOMPARE(cm->name(), QLatin1String("testcm")); QVERIFY(cm->hasProtocol(QLatin1String("example"))); QCOMPARE(cm->protocols().size(), 1); Tp::BaseProtocolPtr protocol = cm->protocols().at(0); QVERIFY(protocol); Tp::BaseProtocolPresenceInterfacePtr iface = Tp::BaseProtocolPresenceInterfacePtr::qObjectCast( protocol->interface(TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE)); QVERIFY(iface); //presence interface PresenceSpecList statuses = iface->statuses(); QCOMPARE(statuses.size(), 4); QVERIFY(statuses.contains(PresenceSpec::available())); QVERIFY(statuses.contains(PresenceSpec::away())); QVERIFY(statuses.contains(PresenceSpec::busy())); QVERIFY(statuses.contains(PresenceSpec::offline())); QVERIFY(!statuses.contains(PresenceSpec::xa())); //immutable properties QVariantMap props = protocol->immutableProperties(); QVERIFY(props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE + QLatin1String(".Statuses"))); statuses = PresenceSpecList(qvariant_cast(props.value( TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE + QLatin1String(".Statuses")))); QCOMPARE(statuses.size(), 4); QVERIFY(statuses.contains(PresenceSpec::available())); QVERIFY(statuses.contains(PresenceSpec::away())); QVERIFY(statuses.contains(PresenceSpec::busy())); QVERIFY(statuses.contains(PresenceSpec::offline())); QVERIFY(!statuses.contains(PresenceSpec::xa())); } void TestBaseProtocol::presenceIfaceSvcSide() { TEST_THREAD_HELPER_EXECUTE(mThreadHelper, &TestBaseProtocol::presenceIfaceSvcSideCb); } void TestBaseProtocol::presenceIfaceClientSide() { ConnectionManagerPtr cliCM = ConnectionManager::create(QLatin1String("testcm")); PendingReady *pr = cliCM->becomeReady(ConnectionManager::FeatureCore); connect(pr, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cliCM->supportedProtocols().size(), 1); QVERIFY(cliCM->hasProtocol(QLatin1String("example"))); ProtocolInfo protocol = cliCM->protocol(QLatin1String("example")); QVERIFY(protocol.isValid()); //presence interface PresenceSpecList statuses = protocol.allowedPresenceStatuses(); QCOMPARE(statuses.size(), 4); QVERIFY(statuses.contains(PresenceSpec::available())); QVERIFY(statuses.contains(PresenceSpec::away())); QVERIFY(statuses.contains(PresenceSpec::busy())); QVERIFY(statuses.contains(PresenceSpec::offline())); QVERIFY(!statuses.contains(PresenceSpec::xa())); } void TestBaseProtocol::cleanup() { delete mThreadHelper; cleanupImpl(); } void TestBaseProtocol::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestBaseProtocol) #include "_gen/base-protocol.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/client.cpp0000664000175000017500000010102612470405660017031 0ustar jrjr#include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; using namespace Tp::Client; class ChannelRequestAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ChannelRequest") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " " " \n" "") Q_PROPERTY(QDBusObjectPath Account READ Account) Q_PROPERTY(qulonglong UserActionTime READ UserActionTime) Q_PROPERTY(QString PreferredHandler READ PreferredHandler) Q_PROPERTY(Tp::QualifiedPropertyValueMapList Requests READ Requests) Q_PROPERTY(QStringList Interfaces READ Interfaces) public: ChannelRequestAdaptor(QDBusObjectPath account, qulonglong userActionTime, QString preferredHandler, QualifiedPropertyValueMapList requests, QStringList interfaces, QObject *parent) : QDBusAbstractAdaptor(parent), mAccount(account), mUserActionTime(userActionTime), mPreferredHandler(preferredHandler), mRequests(requests), mInterfaces(interfaces) { } virtual ~ChannelRequestAdaptor() { } public: // Properties inline QDBusObjectPath Account() const { return mAccount; } inline qulonglong UserActionTime() const { return mUserActionTime; } inline QString PreferredHandler() const { return mPreferredHandler; } inline QualifiedPropertyValueMapList Requests() const { return mRequests; } inline QStringList Interfaces() const { return mInterfaces; } public Q_SLOTS: // Methods void Proceed() { } void Cancel() { } Q_SIGNALS: // Signals void Failed(const QString &error, const QString &message); void Succeeded(); private: QDBusObjectPath mAccount; qulonglong mUserActionTime; QString mPreferredHandler; QualifiedPropertyValueMapList mRequests; QStringList mInterfaces; }; // Totally incomplete mini version of ChannelDispatchOperation class ChannelDispatchOperationAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ChannelDispatchOperation") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QDBusObjectPath Account READ Account) Q_PROPERTY(QDBusObjectPath Connection READ Connection) Q_PROPERTY(Tp::ChannelDetailsList Channels READ Channels) Q_PROPERTY(QStringList Interfaces READ Interfaces) Q_PROPERTY(QStringList PossibleHandlers READ PossibleHandlers) public: ChannelDispatchOperationAdaptor(const QDBusObjectPath &acc, const QDBusObjectPath &conn, const ChannelDetailsList &channels, const QStringList &possibleHandlers, QObject *parent) : QDBusAbstractAdaptor(parent), mAccount(acc), mConn(conn), mChannels(channels), mPossibleHandlers(possibleHandlers) { } virtual ~ChannelDispatchOperationAdaptor() { } public: // Properties inline QDBusObjectPath Account() const { return mAccount; } inline QDBusObjectPath Connection() const { return mConn; } inline ChannelDetailsList Channels() const { return mChannels; } inline QStringList Interfaces() const { return mInterfaces; } inline QStringList PossibleHandlers() const { return mPossibleHandlers; } public Q_SLOTS: inline void Claim() { // do nothing = no fail } private: QDBusObjectPath mAccount, mConn; ChannelDetailsList mChannels; QStringList mInterfaces; QStringList mPossibleHandlers; }; class MyClient : public QObject, public AbstractClientObserver, public AbstractClientApprover, public AbstractClientHandler { Q_OBJECT public: static AbstractClientPtr create(const ChannelClassSpecList &channelFilter, const AbstractClientHandler::Capabilities &capabilities, bool bypassApproval = false, bool wantsRequestNotification = false) { return AbstractClientPtr::dynamicCast(SharedPtr( new MyClient(channelFilter, capabilities, bypassApproval, wantsRequestNotification))); } MyClient(const ChannelClassSpecList &channelFilter, const AbstractClientHandler::Capabilities &capabilities, bool bypassApproval = false, bool wantsRequestNotification = false) : AbstractClientObserver(channelFilter), AbstractClientApprover(channelFilter), AbstractClientHandler(channelFilter, capabilities, wantsRequestNotification), mBypassApproval(bypassApproval) { } ~MyClient() { } void observeChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const ChannelDispatchOperationPtr &dispatchOperation, const QList &requestsSatisfied, const AbstractClientObserver::ObserverInfo &observerInfo) { mObserveChannelsAccount = account; mObserveChannelsConnection = connection; mObserveChannelsChannels = channels; mObserveChannelsDispatchOperation = dispatchOperation; mObserveChannelsRequestsSatisfied = requestsSatisfied; mObserveChannelsObserverInfo = observerInfo; context->setFinished(); QTimer::singleShot(0, this, SIGNAL(observeChannelsFinished())); } void addDispatchOperation(const MethodInvocationContextPtr<> &context, const ChannelDispatchOperationPtr &dispatchOperation) { mAddDispatchOperationChannels = dispatchOperation->channels(); mAddDispatchOperationDispatchOperation = dispatchOperation; QVERIFY(connect(dispatchOperation->claim(AbstractClientHandlerPtr(this)), SIGNAL(finished(Tp::PendingOperation*)), SIGNAL(claimFinished()))); context->setFinished(); QTimer::singleShot(0, this, SIGNAL(addDispatchOperationFinished())); } bool bypassApproval() const { return mBypassApproval; } void handleChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const QList &requestsSatisfied, const QDateTime &userActionTime, const AbstractClientHandler::HandlerInfo &handlerInfo) { mHandleChannelsAccount = account; mHandleChannelsConnection = connection; mHandleChannelsChannels = channels; mHandleChannelsRequestsSatisfied = requestsSatisfied; mHandleChannelsUserActionTime = userActionTime; mHandleChannelsHandlerInfo = handlerInfo; Q_FOREACH (const ChannelPtr &channel, channels) { connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), SIGNAL(channelClosed())); } context->setFinished(); QTimer::singleShot(0, this, SIGNAL(handleChannelsFinished())); } void addRequest(const ChannelRequestPtr &request) { mAddRequestRequest = request; Q_EMIT requestAdded(request); } void removeRequest(const ChannelRequestPtr &request, const QString &errorName, const QString &errorMessage) { mRemoveRequestRequest = request; mRemoveRequestErrorName = errorName; mRemoveRequestErrorMessage = errorMessage; Q_EMIT requestRemoved(request, errorName, errorMessage); } AccountPtr mObserveChannelsAccount; ConnectionPtr mObserveChannelsConnection; QList mObserveChannelsChannels; ChannelDispatchOperationPtr mObserveChannelsDispatchOperation; QList mObserveChannelsRequestsSatisfied; AbstractClientObserver::ObserverInfo mObserveChannelsObserverInfo; QList mAddDispatchOperationChannels; ChannelDispatchOperationPtr mAddDispatchOperationDispatchOperation; bool mBypassApproval; AccountPtr mHandleChannelsAccount; ConnectionPtr mHandleChannelsConnection; QList mHandleChannelsChannels; QList mHandleChannelsRequestsSatisfied; QDateTime mHandleChannelsUserActionTime; AbstractClientHandler::HandlerInfo mHandleChannelsHandlerInfo; ChannelRequestPtr mAddRequestRequest; ChannelRequestPtr mRemoveRequestRequest; QString mRemoveRequestErrorName; QString mRemoveRequestErrorMessage; Q_SIGNALS: void observeChannelsFinished(); void addDispatchOperationFinished(); void handleChannelsFinished(); void claimFinished(); void requestAdded(const Tp::ChannelRequestPtr &request); void requestRemoved(const Tp::ChannelRequestPtr &request, const QString &errorName, const QString &errorMessage); void channelClosed(); }; class TestClient : public Test { Q_OBJECT public: TestClient(QObject *parent = 0) : Test(parent), mConn(0), mContactRepo(0), mText1ChanService(0), mText2ChanService(0), mCDO(0), mClaimFinished(false) { } void testObserveChannelsCommon(const AbstractClientPtr &clientObject, const QString &clientBusName, const QString &clientObjectPath); protected Q_SLOTS: void expectSignalEmission(); void onClaimFinished(); private Q_SLOTS: void initTestCase(); void init(); void testRegister(); void testCapabilities(); void testObserveChannels(); void testAddDispatchOperation(); void testRequests(); void testHandleChannels(); void cleanup(); void cleanupTestCase(); private: AccountManagerPtr mAM; AccountPtr mAccount; TestConnHelper *mConn; TpHandleRepoIface *mContactRepo; ExampleEchoChannel *mText1ChanService; ExampleEchoChannel *mText2ChanService; QString mText1ChanPath; QString mText2ChanPath; ClientRegistrarPtr mClientRegistrar; QString mChannelDispatcherBusName; QString mChannelRequestPath; QVariantMap mHandlerInfo; ChannelDispatchOperationAdaptor *mCDO; QString mCDOPath; AbstractClientHandler::Capabilities mClientCapabilities; AbstractClientPtr mClientObject1; QString mClientObject1BusName; QString mClientObject1Path; AbstractClientPtr mClientObject2; QString mClientObject2BusName; QString mClientObject2Path; uint mUserActionTime; bool mClaimFinished; }; void TestClient::expectSignalEmission() { mLoop->exit(0); } void TestClient::onClaimFinished() { mClaimFinished = true; } void TestClient::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("client"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mAM = AccountManager::create(); QVERIFY(connect(mAM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAM->isReady(), true); QVariantMap parameters; parameters[QLatin1String("account")] = QLatin1String("foobar"); PendingAccount *pacc = mAM->createAccount(QLatin1String("foo"), QLatin1String("bar"), QLatin1String("foobar"), parameters); QVERIFY(connect(pacc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pacc->account()); mAccount = pacc->account(); mConn = new TestConnHelper(this, TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "example", NULL); QCOMPARE(mConn->connect(), true); mContactRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); guint handle = tp_handle_ensure(mContactRepo, "someone@localhost", 0, 0); // create a Channel by magic, rather than doing D-Bus round-trips for it mText1ChanPath = mConn->objectPath() + QLatin1String("/TextChannel1"); QByteArray chanPath(mText1ChanPath.toLatin1()); mText1ChanService = EXAMPLE_ECHO_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle, NULL)); mText2ChanPath = mConn->objectPath() + QLatin1String("/TextChannel2"); chanPath = mText2ChanPath.toLatin1(); mText2ChanService = EXAMPLE_ECHO_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle, NULL)); mClientRegistrar = ClientRegistrar::create(); QDBusConnection bus = mClientRegistrar->dbusConnection(); // Fake ChannelRequest mChannelDispatcherBusName = TP_QT_IFACE_CHANNEL_DISPATCHER; mChannelRequestPath = QLatin1String("/org/freedesktop/Telepathy/ChannelRequest/Request1"); QObject *request = new QObject(this); mUserActionTime = QDateTime::currentDateTime().toTime_t(); ChannelRequestAdaptor *channelRequest = new ChannelRequestAdaptor(QDBusObjectPath(mAccount->objectPath()), mUserActionTime, QString(), QualifiedPropertyValueMapList(), QStringList(), request); QVERIFY(bus.registerService(mChannelDispatcherBusName)); QVERIFY(bus.registerObject(mChannelRequestPath, request)); ObjectImmutablePropertiesMap channelRequestProperties; QVariantMap currentChannelRequestProperties; currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Account"), QVariant::fromValue(channelRequest->Account())); currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".UserActionTime"), channelRequest->UserActionTime()); currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".PreferredHandler"), channelRequest->PreferredHandler()); currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Requests"), QVariant::fromValue(channelRequest->Requests())); currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Interfaces"), QVariant::fromValue(channelRequest->Interfaces())); channelRequestProperties[QDBusObjectPath(mChannelRequestPath)] = currentChannelRequestProperties; mHandlerInfo.insert(QLatin1String("request-properties"), QVariant::fromValue(channelRequestProperties)); // Fake ChannelDispatchOperation mCDOPath = QLatin1String("/org/freedesktop/Telepathy/ChannelDispatchOperation/Operation1"); QObject *cdo = new QObject(this); // Initialize this here so we can actually set it in possibleHandlers mClientObject1BusName = QLatin1String("org.freedesktop.Telepathy.Client.foo"); ChannelDetailsList channelDetailsList; ChannelDetails channelDetails = { QDBusObjectPath(mText1ChanPath), QVariantMap() }; channelDetailsList.append(channelDetails); mCDO = new ChannelDispatchOperationAdaptor(QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mConn->objectPath()), channelDetailsList, QStringList() << mClientObject1BusName, cdo); QVERIFY(bus.registerObject(mCDOPath, cdo)); } void TestClient::init() { initImpl(); mClaimFinished = false; } void TestClient::testRegister() { // invalid client QVERIFY(!mClientRegistrar->registerClient(AbstractClientPtr(), QLatin1String("foo"))); mClientCapabilities.setICEUDPNATTraversalToken(); mClientCapabilities.setToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/audio/speex=true")); ChannelClassSpecList filters; filters.append(ChannelClassSpec::textChat()); mClientObject1 = MyClient::create(filters, mClientCapabilities, false, true); MyClient *client = dynamic_cast(mClientObject1.data()); QVERIFY(!client->isRegistered()); QVERIFY(mClientRegistrar->registerClient(mClientObject1, QLatin1String("foo"))); QVERIFY(client->isRegistered()); QVERIFY(mClientRegistrar->registeredClients().contains(mClientObject1)); AbstractClientPtr clientObjectRedundant = MyClient::create( filters, mClientCapabilities, false, true); client = dynamic_cast(clientObjectRedundant.data()); QVERIFY(!client->isRegistered()); // try to register using a name already registered and a different object, it should fail // and not report isRegistered QVERIFY(!mClientRegistrar->registerClient(clientObjectRedundant, QLatin1String("foo"))); QVERIFY(!client->isRegistered()); QVERIFY(!mClientRegistrar->registeredClients().contains(clientObjectRedundant)); client = dynamic_cast(mClientObject1.data()); // no op - client already registered with same object and name QVERIFY(mClientRegistrar->registerClient(mClientObject1, QLatin1String("foo"))); // unregister client QVERIFY(mClientRegistrar->unregisterClient(mClientObject1)); QVERIFY(!client->isRegistered()); // register again QVERIFY(mClientRegistrar->registerClient(mClientObject1, QLatin1String("foo"))); QVERIFY(client->isRegistered()); filters.clear(); filters.append(ChannelClassSpec::streamedMediaCall()); mClientObject2 = MyClient::create(filters, mClientCapabilities, true, true); QVERIFY(mClientRegistrar->registerClient(mClientObject2, QLatin1String("foo"), true)); QVERIFY(mClientRegistrar->registeredClients().contains(mClientObject2)); // no op - client already registered QVERIFY(mClientRegistrar->registerClient(mClientObject2, QLatin1String("foo"), true)); QDBusConnection bus = mClientRegistrar->dbusConnection(); QDBusConnectionInterface *busIface = bus.interface(); QStringList registeredServicesNames = busIface->registeredServiceNames(); QVERIFY(registeredServicesNames.filter( QRegExp(QLatin1String("^" "org.freedesktop.Telepathy.Client.foo" ".([_A-Za-z][_A-Za-z0-9]*)"))).size() == 1); mClientObject1BusName = QLatin1String("org.freedesktop.Telepathy.Client.foo"); mClientObject1Path = QLatin1String("/org/freedesktop/Telepathy/Client/foo"); mClientObject2BusName = registeredServicesNames.filter( QRegExp(QLatin1String("org.freedesktop.Telepathy.Client.foo._*"))).first(); mClientObject2Path = QString(QLatin1String("/%1")).arg(mClientObject2BusName); mClientObject2Path.replace(QLatin1String("."), QLatin1String("/")); } void TestClient::testCapabilities() { QDBusConnection bus = mClientRegistrar->dbusConnection(); QStringList normalizedClientCaps = mClientCapabilities.allTokens(); normalizedClientCaps.sort(); QStringList normalizedHandlerCaps; // object 1 ClientHandlerInterface *handler1Iface = new ClientHandlerInterface(bus, mClientObject1BusName, mClientObject1Path, this); QVERIFY(waitForProperty(handler1Iface->requestPropertyCapabilities(), &normalizedHandlerCaps)); normalizedHandlerCaps.sort(); QCOMPARE(normalizedHandlerCaps, normalizedClientCaps); // object 2 ClientHandlerInterface *handler2Iface = new ClientHandlerInterface(bus, mClientObject2BusName, mClientObject2Path, this); QVERIFY(waitForProperty(handler2Iface->requestPropertyCapabilities(), &normalizedHandlerCaps)); normalizedHandlerCaps.sort(); QCOMPARE(normalizedHandlerCaps, normalizedClientCaps); } void TestClient::testRequests() { QDBusConnection bus = mClientRegistrar->dbusConnection(); ClientInterfaceRequestsInterface *handlerRequestsIface = new ClientInterfaceRequestsInterface(bus, mClientObject1BusName, mClientObject1Path, this); MyClient *client = dynamic_cast(mClientObject1.data()); connect(client, SIGNAL(requestAdded(const Tp::ChannelRequestPtr &)), SLOT(expectSignalEmission())); handlerRequestsIface->AddRequest(QDBusObjectPath(mChannelRequestPath), QVariantMap()); if (!client->mAddRequestRequest) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(client->mAddRequestRequest->objectPath(), mChannelRequestPath); connect(client, SIGNAL(requestRemoved(const Tp::ChannelRequestPtr &, const QString &, const QString &)), SLOT(expectSignalEmission())); handlerRequestsIface->RemoveRequest(QDBusObjectPath(mChannelRequestPath), QLatin1String(TP_QT_ERROR_NOT_AVAILABLE), QLatin1String("Not available")); if (!client->mRemoveRequestRequest) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(client->mRemoveRequestRequest->objectPath(), mChannelRequestPath); QCOMPARE(client->mRemoveRequestErrorName, QString(QLatin1String(TP_QT_ERROR_NOT_AVAILABLE))); QCOMPARE(client->mRemoveRequestErrorMessage, QString(QLatin1String("Not available"))); } void TestClient::testObserveChannelsCommon(const AbstractClientPtr &clientObject, const QString &clientBusName, const QString &clientObjectPath) { QDBusConnection bus = mClientRegistrar->dbusConnection(); ClientObserverInterface *observeIface = new ClientObserverInterface(bus, clientBusName, clientObjectPath, this); MyClient *client = dynamic_cast(clientObject.data()); connect(client, SIGNAL(observeChannelsFinished()), SLOT(expectSignalEmission())); ChannelDetailsList channelDetailsList; ChannelDetails channelDetails = { QDBusObjectPath(mText1ChanPath), QVariantMap() }; channelDetailsList.append(channelDetails); QVariantMap observerInfo; ObjectImmutablePropertiesMap reqPropsMap; QVariantMap channelReqImmutableProps; channelReqImmutableProps.insert( TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Interface.DomainSpecific.IntegerProp"), 3); channelReqImmutableProps.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Account"), qVariantFromValue(QDBusObjectPath(mAccount->objectPath()))); reqPropsMap.insert(QDBusObjectPath(mChannelRequestPath), channelReqImmutableProps); observerInfo.insert(QLatin1String("request-properties"), qVariantFromValue(reqPropsMap)); observeIface->ObserveChannels(QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mConn->objectPath()), channelDetailsList, QDBusObjectPath("/"), ObjectPathList() << QDBusObjectPath(mChannelRequestPath), observerInfo); QCOMPARE(mLoop->exec(), 0); QCOMPARE(client->mObserveChannelsAccount->objectPath(), mAccount->objectPath()); QCOMPARE(client->mObserveChannelsConnection->objectPath(), mConn->objectPath()); QCOMPARE(client->mObserveChannelsChannels.first()->objectPath(), mText1ChanPath); QVERIFY(client->mObserveChannelsDispatchOperation.isNull()); QCOMPARE(client->mObserveChannelsRequestsSatisfied.first()->objectPath(), mChannelRequestPath); QCOMPARE(client->mObserveChannelsRequestsSatisfied.first()->immutableProperties().contains( TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Interface.DomainSpecific.IntegerProp")), true); QCOMPARE(qdbus_cast(client->mObserveChannelsRequestsSatisfied.first()->immutableProperties().value( TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Interface.DomainSpecific.IntegerProp"))), 3); } void TestClient::testObserveChannels() { testObserveChannelsCommon(mClientObject1, mClientObject1BusName, mClientObject1Path); testObserveChannelsCommon(mClientObject2, mClientObject2BusName, mClientObject2Path); } void TestClient::testAddDispatchOperation() { QDBusConnection bus = mClientRegistrar->dbusConnection(); ClientApproverInterface *approverIface = new ClientApproverInterface(bus, mClientObject1BusName, mClientObject1Path, this); ClientHandlerInterface *handler1Iface = new ClientHandlerInterface(bus, mClientObject1BusName, mClientObject1Path, this); MyClient *client = dynamic_cast(mClientObject1.data()); connect(client, SIGNAL(addDispatchOperationFinished()), SLOT(expectSignalEmission())); connect(client, SIGNAL(claimFinished()), SLOT(onClaimFinished())); QVariantMap dispatchOperationProperties; dispatchOperationProperties.insert( TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".Connection"), QVariant::fromValue(QDBusObjectPath(mConn->objectPath()))); dispatchOperationProperties.insert( TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".Account"), QVariant::fromValue(QDBusObjectPath(mAccount->objectPath()))); dispatchOperationProperties.insert( TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".PossibleHandlers"), QVariant::fromValue(ObjectPathList() << QDBusObjectPath(mClientObject1Path) << QDBusObjectPath(mClientObject2Path))); // Handler.HandledChannels should be empty here, CDO::claim(handler) will populate it on // success Tp::ObjectPathList handledChannels; QVERIFY(waitForProperty(handler1Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.isEmpty()); approverIface->AddDispatchOperation(mCDO->Channels(), QDBusObjectPath(mCDOPath), dispatchOperationProperties); QCOMPARE(mLoop->exec(), 0); while (!mClaimFinished) { mLoop->processEvents(); } QCOMPARE(client->mAddDispatchOperationChannels.first()->objectPath(), mText1ChanPath); QCOMPARE(client->mAddDispatchOperationDispatchOperation->objectPath(), mCDOPath); // Claim finished, Handler.HandledChannels should be populated now handledChannels.clear(); QVERIFY(waitForProperty(handler1Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(!handledChannels.isEmpty()); qSort(handledChannels); Tp::ObjectPathList expectedHandledChannels; Q_FOREACH (const ChannelDetails &details, mCDO->Channels()) { expectedHandledChannels << details.channel; } qSort(expectedHandledChannels); QCOMPARE(handledChannels, expectedHandledChannels); } void TestClient::testHandleChannels() { QDBusConnection bus = mClientRegistrar->dbusConnection(); // object 1 ClientHandlerInterface *handler1Iface = new ClientHandlerInterface(bus, mClientObject1BusName, mClientObject1Path, this); MyClient *client1 = dynamic_cast(mClientObject1.data()); connect(client1, SIGNAL(handleChannelsFinished()), SLOT(expectSignalEmission())); ChannelDetailsList channelDetailsList; ChannelDetails channelDetails = { QDBusObjectPath(mText1ChanPath), QVariantMap() }; channelDetailsList.append(channelDetails); handler1Iface->HandleChannels(QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mConn->objectPath()), channelDetailsList, ObjectPathList() << QDBusObjectPath(mChannelRequestPath), mUserActionTime, mHandlerInfo); QCOMPARE(mLoop->exec(), 0); QCOMPARE(client1->mHandleChannelsAccount->objectPath(), mAccount->objectPath()); QCOMPARE(client1->mHandleChannelsConnection->objectPath(), mConn->objectPath()); QCOMPARE(client1->mHandleChannelsChannels.first()->objectPath(), mText1ChanPath); QCOMPARE(client1->mHandleChannelsRequestsSatisfied.first()->objectPath(), mChannelRequestPath); QCOMPARE(client1->mHandleChannelsUserActionTime.toTime_t(), mUserActionTime); Tp::ObjectPathList handledChannels; QVERIFY(waitForProperty(handler1Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.contains(QDBusObjectPath(mText1ChanPath))); // object 2 ClientHandlerInterface *handler2Iface = new ClientHandlerInterface(bus, mClientObject2BusName, mClientObject2Path, this); MyClient *client2 = dynamic_cast(mClientObject2.data()); connect(client2, SIGNAL(handleChannelsFinished()), SLOT(expectSignalEmission())); channelDetailsList.clear(); channelDetails.channel = QDBusObjectPath(mText2ChanPath); channelDetailsList.append(channelDetails); handler2Iface->HandleChannels(QDBusObjectPath(mAccount->objectPath()), QDBusObjectPath(mConn->objectPath()), channelDetailsList, ObjectPathList() << QDBusObjectPath(mChannelRequestPath), mUserActionTime, mHandlerInfo); QCOMPARE(mLoop->exec(), 0); QCOMPARE(client2->mHandleChannelsAccount->objectPath(), mAccount->objectPath()); QCOMPARE(client2->mHandleChannelsConnection->objectPath(), mConn->objectPath()); QCOMPARE(client2->mHandleChannelsChannels.first()->objectPath(), mText2ChanPath); QCOMPARE(client2->mHandleChannelsRequestsSatisfied.first()->objectPath(), mChannelRequestPath); QCOMPARE(client2->mHandleChannelsUserActionTime.toTime_t(), mUserActionTime); QVERIFY(waitForProperty(handler1Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.contains(QDBusObjectPath(mText1ChanPath))); QVERIFY(handledChannels.contains(QDBusObjectPath(mText2ChanPath))); QVERIFY(waitForProperty(handler2Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.contains(QDBusObjectPath(mText1ChanPath))); QVERIFY(handledChannels.contains(QDBusObjectPath(mText2ChanPath))); // Handler.HandledChannels will now return all channels that are not invalidated/destroyed // even if the handler for such channels was already unregistered g_object_unref(mText1ChanService); connect(client1, SIGNAL(channelClosed()), SLOT(expectSignalEmission())); QCOMPARE(mLoop->exec(), 0); mClientRegistrar->unregisterClient(mClientObject1); QVERIFY(waitForProperty(handler2Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.contains(QDBusObjectPath(mText2ChanPath))); g_object_unref(mText2ChanService); connect(client2, SIGNAL(channelClosed()), SLOT(expectSignalEmission())); QCOMPARE(mLoop->exec(), 0); QVERIFY(waitForProperty(handler2Iface->requestPropertyHandledChannels(), &handledChannels)); QVERIFY(handledChannels.isEmpty()); } void TestClient::cleanup() { cleanupImpl(); } void TestClient::cleanupTestCase() { if (mConn) { QCOMPARE(mConn->disconnect(), true); delete mConn; } cleanupTestCaseImpl(); } QTEST_MAIN(TestClient) #include "_gen/client.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/captcha-authentication.cpp0000664000175000017500000002471212470405660022201 0ustar jrjr#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestCaptchaAuthentication : public Test { Q_OBJECT public: TestCaptchaAuthentication(QObject *parent = 0) : Test(parent), mConn(0), mChanService(0) { } private Q_SLOTS: void initTestCase(); void init(); void testCreation(); void testCaptchaSuccessful(); void testCaptchaRetry(); void testCaptchaCancel(); void testNoCaptcha(); void cleanup(); void cleanupTestCase(); private: void createCaptchaChannel(bool canRetry = false); TestConnHelper *mConn; TpTestsCaptchaChannel *mChanService; ServerAuthenticationChannelPtr mChan; CaptchaAuthenticationPtr mCaptcha; }; void TestCaptchaAuthentication::createCaptchaChannel(bool canRetry) { mChan.reset(); mLoop->processEvents(); tp_clear_object(&mChanService); /* Create service-side tube channel object */ QString chanPath = QString(QLatin1String("%1/Channel")).arg(mConn->objectPath()); mChanService = TP_TESTS_CAPTCHA_CHANNEL(g_object_new( TP_TESTS_TYPE_CAPTCHA_CHANNEL, "connection", mConn->service(), "requested", FALSE, "object-path", chanPath.toLatin1().constData(), "can-retry-captcha", canRetry, NULL)); /* Create client-side tube channel object */ mChan = ServerAuthenticationChannel::create(mConn->client(), chanPath, QVariantMap()); // Verify features shouldn't be Ready QVERIFY(mChan->captchaAuthentication().isNull()); QVERIFY(!mChan->hasCaptchaInterface()); //QVERIFY(!mChan->hasSaslInterface()); QVERIFY(connect(mChan->becomeReady(ServerAuthenticationChannel::FeatureCore), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->isReady(ServerAuthenticationChannel::FeatureCore)); QVERIFY(mChan->hasCaptchaInterface()); //QVERIFY(!mChan->hasSaslInterface()); mCaptcha = mChan->captchaAuthentication(); QCOMPARE(mCaptcha.isNull(), false); } void TestCaptchaAuthentication::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("captcha-authentication"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "example", NULL); QCOMPARE(mConn->connect(), true); } void TestCaptchaAuthentication::init() { initImpl(); } void TestCaptchaAuthentication::testCreation() { createCaptchaChannel(); QCOMPARE(mCaptcha->status(), Tp::CaptchaStatusLocalPending); QCOMPARE(mCaptcha->canRetry(), false); QVERIFY(mCaptcha->error().isEmpty()); QVERIFY(mCaptcha->errorDetails().allDetails().isEmpty()); } void TestCaptchaAuthentication::testCaptchaSuccessful() { createCaptchaChannel(); QSignalSpy spy(mCaptcha.data(), SIGNAL(statusChanged(Tp::CaptchaStatus))); PendingCaptchas *pendingCaptchas = mCaptcha->requestCaptchas(QStringList() << QLatin1String("image/png")); QVERIFY(connect(pendingCaptchas, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(pendingCaptchas->requiresMultipleCaptchas(), false); QCOMPARE(pendingCaptchas->captchaList().size(), 1); Captcha captchaData = pendingCaptchas->captcha(); QCOMPARE(captchaData.mimeType(), QLatin1String("image/png")); QCOMPARE(captchaData.label(), QLatin1String("Enter the text displayed")); QCOMPARE(captchaData.data(), QByteArray("This is a fake payload")); QCOMPARE(captchaData.type(), CaptchaAuthentication::OCRChallenge); QCOMPARE(captchaData.id(), (uint)42); QVERIFY(connect(mCaptcha->answer(42, QLatin1String("This is the right answer")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(spy.size(), 2); QCOMPARE(mCaptcha->status(), CaptchaStatusSucceeded); } void TestCaptchaAuthentication::testCaptchaRetry() { createCaptchaChannel(true); QSignalSpy spy(mCaptcha.data(), SIGNAL(statusChanged(Tp::CaptchaStatus))); PendingCaptchas *pendingCaptchas = mCaptcha->requestCaptchas(QStringList() << QLatin1String("image/png")); QVERIFY(connect(pendingCaptchas, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mCaptcha->answer(42, QLatin1String("What is this I don't even")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCaptcha->status(), CaptchaStatusTryAgain); pendingCaptchas = mCaptcha->requestCaptchas(QStringList() << QLatin1String("image/png")); QVERIFY(connect(pendingCaptchas, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(pendingCaptchas->requiresMultipleCaptchas(), false); QCOMPARE(pendingCaptchas->captchaList().size(), 1); Captcha captchaData = pendingCaptchas->captcha(); QCOMPARE(captchaData.mimeType(), QLatin1String("image/png")); QCOMPARE(captchaData.label(), QLatin1String("Enter the text displayed")); QCOMPARE(captchaData.data(), QByteArray("This is a reloaded payload")); QCOMPARE(captchaData.type(), CaptchaAuthentication::OCRChallenge); QCOMPARE(captchaData.id(), (uint)42); QVERIFY(connect(mCaptcha->answer(42, QLatin1String("This is the right answer")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCaptcha->status(), CaptchaStatusSucceeded); // Check signals now QCOMPARE(spy.size(), 5); } void TestCaptchaAuthentication::testCaptchaCancel() { createCaptchaChannel(); PendingCaptchas *pendingCaptchas = mCaptcha->requestCaptchas(QStringList() << QLatin1String("image/png")); QVERIFY(connect(pendingCaptchas, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); // Check that the result is not still available QCOMPARE(pendingCaptchas->captchaList().size(), 0); QCOMPARE(pendingCaptchas->captcha().id(), (uint)0); QCOMPARE(mLoop->exec(), 0); // Cancel now QVERIFY(connect(mCaptcha->cancel(CaptchaCancelReasonUserCancelled), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mCaptcha->status(), CaptchaStatusFailed); // Now try performing random actions which should fail QVERIFY(connect(mCaptcha->answer(42, QLatin1String("This is the right answer")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mCaptcha->answer(CaptchaAnswers()), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mCaptcha->requestCaptchas(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); } void TestCaptchaAuthentication::testNoCaptcha() { createCaptchaChannel(); PendingCaptchas *pendingCaptchas = mCaptcha->requestCaptchas(QStringList(), CaptchaAuthentication::AudioRecognitionChallenge); QVERIFY(connect(pendingCaptchas, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); pendingCaptchas = mCaptcha->requestCaptchas(QStringList() << QLatin1String("nosuchtype"), CaptchaAuthentication::SpeechRecognitionChallenge | CaptchaAuthentication::SpeechQuestionChallenge); QVERIFY(connect(pendingCaptchas, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); // Get the qa one pendingCaptchas = mCaptcha->requestCaptchas(QStringList(), CaptchaAuthentication::TextQuestionChallenge); QVERIFY(connect(pendingCaptchas, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); Captcha data = pendingCaptchas->captcha(); Captcha data2(pendingCaptchas->captcha()); QCOMPARE(data.id(), pendingCaptchas->captcha().id()); QCOMPARE(data.id(), data2.id()); // Get the video one to fail utterly pendingCaptchas = mCaptcha->requestCaptchas(QStringList(), CaptchaAuthentication::VideoRecognitionChallenge); QVERIFY(connect(pendingCaptchas, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); } void TestCaptchaAuthentication::cleanup() { cleanupImpl(); if (mChan && mChan->isValid()) { qDebug() << "waiting for the channel to become invalidated"; QVERIFY(connect(mChan.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), mLoop, SLOT(quit()))); tp_base_channel_close(TP_BASE_CHANNEL(mChanService)); QCOMPARE(mLoop->exec(), 0); } mChan.reset(); if (mChanService != 0) { g_object_unref(mChanService); mChanService = 0; } mLoop->processEvents(); } void TestCaptchaAuthentication::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestCaptchaAuthentication) #include "_gen/captcha-authentication.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/stateful-proxy.cpp0000664000175000017500000002327212470405660020567 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include "tests/lib/test.h" using namespace Tp; using namespace Tp; using Tp::Client::DBus::IntrospectableInterface; // expose protected functions for testing class MyStatefulDBusProxy : public StatefulDBusProxy { public: MyStatefulDBusProxy(const QDBusConnection &dbusConnection, const QString &busName, const QString &objectPath) : StatefulDBusProxy(dbusConnection, busName, objectPath, Feature()) { } using StatefulDBusProxy::invalidate; }; class ObjectAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "com.example.Foo") public: ObjectAdaptor(Test *test) : QDBusAbstractAdaptor(test) { } }; class TestStatefulProxy : public Test { Q_OBJECT public: TestStatefulProxy(QObject *parent = 0); private Q_SLOTS: void initTestCase(); void init(); void testBasics(); void testNameOwnerChanged(); void cleanup(); void cleanupTestCase(); protected Q_SLOTS: // these would be public, but then QtTest would think they were tests void expectInvalidated(Tp::DBusProxy *, const QString &, const QString &); // anything other than 0 or 1 is OK # define EXPECT_INVALIDATED_SUCCESS 111 private: MyStatefulDBusProxy *mProxy; ObjectAdaptor *mAdaptor; int mInvalidated; QString mSignalledInvalidationReason; QString mSignalledInvalidationMessage; static QString wellKnownName(); static QString objectPath(); static QString uniqueName(); }; QString TestStatefulProxy::wellKnownName() { return QLatin1String("org.freedesktop.Telepathy.Qt.TestStatefulProxy"); } QString TestStatefulProxy::objectPath() { return QLatin1String("/org/freedesktop/Telepathy/Qt/TestStatefulProxy/Object"); } TestStatefulProxy::TestStatefulProxy(QObject *parent) : Test(parent), mProxy(0), mAdaptor(new ObjectAdaptor(this)) { } QString TestStatefulProxy::uniqueName() { return QDBusConnection::sessionBus().baseService(); } void TestStatefulProxy::initTestCase() { initTestCaseImpl(); QVERIFY(QDBusConnection::sessionBus().registerService(wellKnownName())); QDBusConnection::sessionBus().registerObject(objectPath(), this); } void TestStatefulProxy::init() { initImpl(); mInvalidated = 0; } void TestStatefulProxy::testBasics() { mProxy = new MyStatefulDBusProxy(QDBusConnection::sessionBus(), wellKnownName(), objectPath()); IntrospectableInterface ifaceFromProxy(mProxy); IntrospectableInterface ifaceFromWellKnown(wellKnownName(), objectPath()); IntrospectableInterface ifaceFromUnique(uniqueName(), objectPath()); QVERIFY(mProxy); QCOMPARE(mProxy->dbusConnection().baseService(), uniqueName()); QCOMPARE(mProxy->busName(), uniqueName()); QCOMPARE(mProxy->objectPath(), objectPath()); QVERIFY(mProxy->isValid()); QCOMPARE(mProxy->invalidationReason(), QString()); QCOMPARE(mProxy->invalidationMessage(), QString()); QDBusPendingReply reply; QDBusPendingCallWatcher *watcher; reply = ifaceFromUnique.Introspect(); if (!reply.isValid()) { watcher = new QDBusPendingCallWatcher(reply); QVERIFY(connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(expectSuccessfulCall(QDBusPendingCallWatcher *)))); QCOMPARE(mLoop->exec(), 0); delete watcher; } reply = ifaceFromWellKnown.Introspect(); if (!reply.isValid()) { watcher = new QDBusPendingCallWatcher(reply); QVERIFY(connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(expectSuccessfulCall(QDBusPendingCallWatcher *)))); QCOMPARE(mLoop->exec(), 0); delete watcher; } reply = ifaceFromProxy.Introspect(); if (!reply.isValid()) { watcher = new QDBusPendingCallWatcher(reply); QVERIFY(connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(expectSuccessfulCall(QDBusPendingCallWatcher *)))); QCOMPARE(mLoop->exec(), 0); delete watcher; } QVERIFY(connect(mProxy, SIGNAL(invalidated( Tp::DBusProxy *, const QString &, const QString &)), this, SLOT(expectInvalidated( Tp::DBusProxy *, const QString &, const QString &)))); mProxy->invalidate(QLatin1String("com.example.DomainSpecificError"), QLatin1String("Because I said so")); QVERIFY(!mProxy->isValid()); QCOMPARE(mProxy->invalidationReason(), QLatin1String("com.example.DomainSpecificError")); QCOMPARE(mProxy->invalidationMessage(), QLatin1String("Because I said so")); // FIXME: ideally, the method call would already fail synchronously at // this point - after all, the proxy already knows it's dead reply = ifaceFromProxy.Introspect(); if (reply.isValid()) { qWarning() << "reply is valid"; } else if (reply.isError()) { qDebug() << "reply is error" << reply.error().name() << reply.error().message(); } else { qWarning() << "no reply yet"; } // the signal doesn't arrive instantly QCOMPARE(mLoop->exec(), EXPECT_INVALIDATED_SUCCESS); QVERIFY(disconnect(mProxy, SIGNAL(invalidated( Tp::DBusProxy *, const QString &, const QString &)), this, SLOT(expectInvalidated( Tp::DBusProxy *, const QString &, const QString &)))); QCOMPARE(mInvalidated, 1); QCOMPARE(mSignalledInvalidationReason, QLatin1String("com.example.DomainSpecificError")); QCOMPARE(mSignalledInvalidationMessage, QLatin1String("Because I said so")); // low-level proxies with no knowledge of the high-level DBusProxy are // unaffected reply = ifaceFromUnique.Introspect(); if (!reply.isValid()) { watcher = new QDBusPendingCallWatcher(reply); QVERIFY(connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(expectSuccessfulCall(QDBusPendingCallWatcher *)))); QCOMPARE(mLoop->exec(), 0); delete watcher; } reply = ifaceFromWellKnown.Introspect(); if (!reply.isValid()) { watcher = new QDBusPendingCallWatcher(reply); QVERIFY(connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(expectSuccessfulCall(QDBusPendingCallWatcher *)))); QCOMPARE(mLoop->exec(), 0); delete watcher; } } void TestStatefulProxy::expectInvalidated(DBusProxy *proxy, const QString &reason, const QString &message) { mInvalidated++; mSignalledInvalidationReason = reason; mSignalledInvalidationMessage = message; mLoop->exit(EXPECT_INVALIDATED_SUCCESS); } void TestStatefulProxy::testNameOwnerChanged() { QString otherUniqueName = QDBusConnection::connectToBus( QDBusConnection::SessionBus, QLatin1String("another unique name")).baseService(); mProxy = new MyStatefulDBusProxy(QDBusConnection::sessionBus(), otherUniqueName, objectPath()); QVERIFY(mProxy->isValid()); QCOMPARE(mProxy->invalidationReason(), QString()); QCOMPARE(mProxy->invalidationMessage(), QString()); QVERIFY(connect(mProxy, SIGNAL(invalidated( Tp::DBusProxy *, const QString &, const QString &)), this, SLOT(expectInvalidated( Tp::DBusProxy *, const QString &, const QString &)))); QDBusConnection::disconnectFromBus(QLatin1String("another unique name")); QCOMPARE(mLoop->exec(), EXPECT_INVALIDATED_SUCCESS); QVERIFY(disconnect(mProxy, SIGNAL(invalidated( Tp::DBusProxy *, const QString &, const QString &)), this, SLOT(expectInvalidated( Tp::DBusProxy *, const QString &, const QString &)))); QCOMPARE(mInvalidated, 1); QVERIFY(!mProxy->isValid()); QCOMPARE(mProxy->invalidationReason(), TP_QT_DBUS_ERROR_NAME_HAS_NO_OWNER); QCOMPARE(mSignalledInvalidationReason, TP_QT_DBUS_ERROR_NAME_HAS_NO_OWNER); QVERIFY(!mProxy->invalidationMessage().isEmpty()); QCOMPARE(mProxy->invalidationMessage(), mSignalledInvalidationMessage); } void TestStatefulProxy::cleanup() { if (mProxy) { delete mProxy; mProxy = 0; } cleanupImpl(); } void TestStatefulProxy::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestStatefulProxy) #include "_gen/stateful-proxy.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/profile-manager.cpp0000664000175000017500000000706012470405660020626 0ustar jrjr#include #include #include #include using namespace Tp; class TestProfileManager : public Test { Q_OBJECT private Q_SLOTS: void testProfileManager(); }; void TestProfileManager::testProfileManager() { ProfileManagerPtr pm = ProfileManager::create(QDBusConnection::sessionBus()); QVERIFY(connect(pm->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(pm->isReady(), true); QCOMPARE(pm->profiles().isEmpty(), false); QCOMPARE(pm->profiles().count(), 2); QCOMPARE(pm->profileForService(QLatin1String("test-profile")).isNull(), false); QCOMPARE(pm->profileForService(QLatin1String("test-profile-file-not-found")).isNull(), true); QCOMPARE(pm->profileForService(QLatin1String("test-profile-non-im-type")).isNull(), true); QCOMPARE(pm->profilesForCM(QLatin1String("testprofilecm")).isEmpty(), false); QCOMPARE(pm->profilesForCM(QLatin1String("testprofilecm")).count(), 2); QCOMPARE(pm->profilesForProtocol(QLatin1String("testprofileproto")).isEmpty(), false); QCOMPARE(pm->profilesForProtocol(QLatin1String("testprofileproto")).count(), 2); QVERIFY(connect(pm->becomeReady(ProfileManager::FeatureFakeProfiles), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(pm->isReady(ProfileManager::FeatureFakeProfiles), true); QCOMPARE(pm->profiles().isEmpty(), false); QCOMPARE(pm->profiles().count(), 4); QCOMPARE(pm->profileForService(QLatin1String("spurious-normal")).isNull(), false); QCOMPARE(pm->profileForService(QLatin1String("spurious-weird")).isNull(), false); QCOMPARE(pm->profilesForCM(QLatin1String("spurious")).isEmpty(), false); QCOMPARE(pm->profilesForCM(QLatin1String("spurious")).count(), 2); QCOMPARE(pm->profilesForProtocol(QLatin1String("normal")).isEmpty(), false); QCOMPARE(pm->profilesForProtocol(QLatin1String("weird")).isEmpty(), false); ProfilePtr profile = pm->profileForService(QLatin1String("spurious-normal")); QCOMPARE(profile->type(), QLatin1String("IM")); QCOMPARE(profile->provider(), QString()); QCOMPARE(profile->name(), QLatin1String("normal")); QCOMPARE(profile->cmName(), QLatin1String("spurious")); QCOMPARE(profile->protocolName(), QLatin1String("normal")); QCOMPARE(profile->presences().isEmpty(), true); QCOMPARE(profile->parameters().isEmpty(), false); QCOMPARE(profile->parameters().count(), 1); QCOMPARE(profile->hasParameter(QLatin1String("not-found")), false); /* profile will only return CM default params, account is ignored */ QCOMPARE(profile->hasParameter(QLatin1String("account")), false); /* profile will only return CM default params, password is ignored */ QCOMPARE(profile->hasParameter(QLatin1String("password")), false); Profile::Parameter param = profile->parameter(QLatin1String("register")); QCOMPARE(param.name(), QLatin1String("register")); QCOMPARE(param.dbusSignature(), QDBusSignature(QLatin1String("b"))); QCOMPARE(param.type(), QVariant::Bool); QCOMPARE(param.value(), QVariant(true)); QCOMPARE(param.label(), QString()); QCOMPARE(param.isMandatory(), false); // Allow the PendingReadys to delete themselves mLoop->processEvents(); } QTEST_MAIN(TestProfileManager) #include "_gen/profile-manager.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/contact-search-chan.cpp0000664000175000017500000002564012470405660021367 0ustar jrjr#include #include #include #include #include #include #include #include using namespace Tp; class TestContactSearchChan : public Test { Q_OBJECT public: TestContactSearchChan(QObject *parent = 0) : Test(parent), mConn(0), mChan1Service(0), mChan2Service(0), mSearchReturned(false) { } protected Q_SLOTS: void onSearchStateChanged(Tp::ChannelContactSearchState state, const QString &errorName, const Tp::ContactSearchChannel::SearchStateChangeDetails &details); void onSearchResultReceived(const Tp::ContactSearchChannel::SearchResult &result); void onSearchReturned(Tp::PendingOperation *op); private Q_SLOTS: void initTestCase(); void init(); void testContactSearch(); void testContactSearchEmptyResult(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; TpHandleRepoIface *mContactRepo; ContactSearchChannelPtr mChan; ContactSearchChannelPtr mChan1; ContactSearchChannelPtr mChan2; QString mChan1Path; TpTestsContactSearchChannel *mChan1Service; QString mChan2Path; TpTestsContactSearchChannel *mChan2Service; ContactSearchChannel::SearchResult mSearchResult; bool mSearchReturned; struct SearchStateChangeInfo { SearchStateChangeInfo(ChannelContactSearchState state, const QString &errorName, const Tp::ContactSearchChannel::SearchStateChangeDetails &details) : state(state), errorName(errorName), details(details) { } ChannelContactSearchState state; QString errorName; ContactSearchChannel::SearchStateChangeDetails details; }; QList mSearchStateChangeInfoList; }; void TestContactSearchChan::onSearchStateChanged(Tp::ChannelContactSearchState state, const QString &errorName, const Tp::ContactSearchChannel::SearchStateChangeDetails &details) { mSearchStateChangeInfoList.append(SearchStateChangeInfo(state, errorName, details)); mLoop->exit(0); } void TestContactSearchChan::onSearchResultReceived( const Tp::ContactSearchChannel::SearchResult &result) { QCOMPARE(mChan->searchState(), ChannelContactSearchStateInProgress); mSearchResult = result; mLoop->exit(0); } void TestContactSearchChan::onSearchReturned(Tp::PendingOperation *op) { TEST_VERIFY_OP(op); QVERIFY(mChan->searchState() != ChannelContactSearchStateNotStarted); mSearchReturned = true; mLoop->exit(0); } void TestContactSearchChan::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("contact-search-chan"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, EXAMPLE_TYPE_ECHO_CONNECTION, "account", "me@example.com", "protocol", "example", NULL); QCOMPARE(mConn->connect(), true); QByteArray chan1Path; mChan1Path = mConn->objectPath() + QLatin1String("/ContactSearchChannel/1"); chan1Path = mChan1Path.toLatin1(); mChan1Service = TP_TESTS_CONTACT_SEARCH_CHANNEL(g_object_new( TP_TESTS_TYPE_CONTACT_SEARCH_CHANNEL, "connection", mConn->service(), "object-path", chan1Path.data(), NULL)); QByteArray chan2Path; mChan2Path = mConn->objectPath() + QLatin1String("/ContactSearchChannel/2"); chan2Path = mChan2Path.toLatin1(); mChan2Service = TP_TESTS_CONTACT_SEARCH_CHANNEL(g_object_new( TP_TESTS_TYPE_CONTACT_SEARCH_CHANNEL, "connection", mConn->service(), "object-path", chan2Path.data(), NULL)); } void TestContactSearchChan::init() { initImpl(); mSearchResult.clear(); mSearchStateChangeInfoList.clear(); mSearchReturned = false; } void TestContactSearchChan::testContactSearch() { mChan1 = ContactSearchChannel::create(mConn->client(), mChan1Path, QVariantMap()); mChan = mChan1; // becomeReady with no args should implicitly enable ContactSearchChannel::FeatureCore QVERIFY(connect(mChan1->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan1->isReady(ContactSearchChannel::FeatureCore), true); QCOMPARE(mChan1->searchState(), ChannelContactSearchStateNotStarted); QCOMPARE(mChan1->limit(), static_cast(0)); QCOMPARE(mChan1->availableSearchKeys().isEmpty(), false); QCOMPARE(mChan1->availableSearchKeys().count(), 1); QCOMPARE(mChan1->availableSearchKeys().first(), QLatin1String("employer")); QCOMPARE(mChan1->server(), QLatin1String("characters.shakespeare.lit")); QVERIFY(connect(mChan1.data(), SIGNAL(searchStateChanged(Tp::ChannelContactSearchState, const QString &, const Tp::ContactSearchChannel::SearchStateChangeDetails &)), SLOT(onSearchStateChanged(Tp::ChannelContactSearchState, const QString &, const Tp::ContactSearchChannel::SearchStateChangeDetails &)))); QVERIFY(connect(mChan1.data(), SIGNAL(searchResultReceived(const Tp::ContactSearchChannel::SearchResult &)), SLOT(onSearchResultReceived(const Tp::ContactSearchChannel::SearchResult &)))); QVERIFY(connect(mChan1->search(QLatin1String("employer"), QLatin1String("Collabora")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onSearchReturned(Tp::PendingOperation *)))); while (!mSearchReturned) { QCOMPARE(mLoop->exec(), 0); } while (mChan1->searchState() != ChannelContactSearchStateCompleted) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mSearchReturned, true); QCOMPARE(mSearchStateChangeInfoList.count(), 2); SearchStateChangeInfo info = mSearchStateChangeInfoList.at(0); QCOMPARE(info.state, ChannelContactSearchStateInProgress); QCOMPARE(info.errorName, QLatin1String("")); QCOMPARE(info.details.hasDebugMessage(), true); QCOMPARE(info.details.debugMessage(), QLatin1String("in progress")); info = mSearchStateChangeInfoList.at(1); QCOMPARE(info.state, ChannelContactSearchStateCompleted); QCOMPARE(info.errorName, QLatin1String("")); QCOMPARE(info.details.hasDebugMessage(), true); QCOMPARE(info.details.debugMessage(), QLatin1String("completed")); QCOMPARE(mSearchResult.isEmpty(), false); QCOMPARE(mSearchResult.size(), 3); QStringList expectedIds; expectedIds << QLatin1String("oggis") << QLatin1String("andrunko") << QLatin1String("wjt"); expectedIds.sort(); QStringList expectedFns; expectedFns << QLatin1String("Olli Salli") << QLatin1String("Andre Moreira Magalhaes") << QLatin1String("Will Thompson"); expectedFns.sort(); QStringList ids; QStringList fns; for (ContactSearchChannel::SearchResult::const_iterator it = mSearchResult.constBegin(); it != mSearchResult.constEnd(); ++it) { QCOMPARE(it.key().isNull(), false); ids << it.key()->id(); QCOMPARE(it.value().isValid(), true); QCOMPARE(it.value().allFields().isEmpty(), false); Q_FOREACH (const ContactInfoField &contactInfo, it.value().allFields()) { QCOMPARE(contactInfo.fieldName, QLatin1String("fn")); fns.append(contactInfo.fieldValue.first()); } } ids.sort(); QCOMPARE(ids, expectedIds); fns.sort(); QCOMPARE(fns, expectedFns); mChan1.reset(); } void TestContactSearchChan::testContactSearchEmptyResult() { mChan2 = ContactSearchChannel::create(mConn->client(), mChan2Path, QVariantMap()); mChan = mChan2; QVERIFY(connect(mChan2->becomeReady(ContactSearchChannel::FeatureCore), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan2->isReady(), true); QCOMPARE(mChan2->searchState(), ChannelContactSearchStateNotStarted); QCOMPARE(mChan2->limit(), static_cast(0)); QCOMPARE(mChan2->availableSearchKeys().isEmpty(), false); QCOMPARE(mChan2->availableSearchKeys().count(), 1); QCOMPARE(mChan2->availableSearchKeys().first(), QLatin1String("employer")); QCOMPARE(mChan2->server(), QLatin1String("characters.shakespeare.lit")); QVERIFY(connect(mChan2.data(), SIGNAL(searchStateChanged(Tp::ChannelContactSearchState, const QString &, const Tp::ContactSearchChannel::SearchStateChangeDetails &)), SLOT(onSearchStateChanged(Tp::ChannelContactSearchState, const QString &, const Tp::ContactSearchChannel::SearchStateChangeDetails &)))); QVERIFY(connect(mChan2.data(), SIGNAL(searchResultReceived(const Tp::ContactSearchChannel::SearchResult &)), SLOT(onSearchResultReceived(const Tp::ContactSearchChannel::SearchResult &)))); ContactSearchMap searchTerms; searchTerms.insert(QLatin1String("employer"), QLatin1String("FooBar")); QVERIFY(connect(mChan2->search(searchTerms), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onSearchReturned(Tp::PendingOperation *)))); while (!mSearchReturned) { QCOMPARE(mLoop->exec(), 0); } while (mChan2->searchState() != ChannelContactSearchStateCompleted) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mSearchReturned, true); QCOMPARE(mSearchResult.isEmpty(), true); QCOMPARE(mSearchStateChangeInfoList.count(), 2); SearchStateChangeInfo info = mSearchStateChangeInfoList.at(0); QCOMPARE(info.state, ChannelContactSearchStateInProgress); QCOMPARE(info.errorName, QLatin1String("")); QCOMPARE(info.details.hasDebugMessage(), true); QCOMPARE(info.details.debugMessage(), QLatin1String("in progress")); info = mSearchStateChangeInfoList.at(1); QCOMPARE(info.state, ChannelContactSearchStateCompleted); QCOMPARE(info.errorName, QLatin1String("")); QCOMPARE(info.details.hasDebugMessage(), true); QCOMPARE(info.details.debugMessage(), QLatin1String("completed")); mChan2.reset(); } void TestContactSearchChan::cleanup() { cleanupImpl(); } void TestContactSearchChan::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; if (mChan1Service != 0) { g_object_unref(mChan1Service); mChan1Service = 0; } if (mChan2Service != 0) { g_object_unref(mChan2Service); mChan2Service = 0; } cleanupTestCaseImpl(); } QTEST_MAIN(TestContactSearchChan) #include "_gen/contact-search-chan.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/dbus-tube-chan.cpp0000664000175000017500000007015312470405660020362 0ustar jrjr#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; namespace { struct TestContext { bool withContact; TpSocketAddressType addressType; TpSocketAccessControl accessControl; }; TestContext contexts[] = { { FALSE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, { FALSE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_CREDENTIALS }, { TRUE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, { TRUE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_CREDENTIALS }, { FALSE, (TpSocketAddressType) NUM_TP_SOCKET_ADDRESS_TYPES, (TpSocketAccessControl) NUM_TP_SOCKET_ACCESS_CONTROLS } }; } class TestDBusTubeChan : public Test { Q_OBJECT public: TestDBusTubeChan(QObject *parent = 0) : Test(parent), mConn(0), mChanService(0), mBusNameWasAdded(false), mBusNameWasRemoved(false), mOfferFinished(false), mAllowsOtherUsers(false) { } protected Q_SLOTS: void onBusNameAdded(const QString &busName, const Tp::ContactPtr &contact); void onBusNameRemoved(const QString &busName, const Tp::ContactPtr &contact); void onOfferFinished(Tp::PendingOperation *op); void expectPendingTubeConnectionFinished(Tp::PendingOperation *op); private Q_SLOTS: void initTestCase(); void init(); void testCreation(); void testAcceptSuccess(); void testAcceptFail(); void testOfferSuccess(); void testOutgoingBusNameMonitoring(); void testExtractBusNameMonitoring(); void testAcceptCornerCases(); void testOfferCornerCases(); void cleanup(); void cleanupTestCase(); private: void createTubeChannel(bool requested, TpSocketAddressType addressType, TpSocketAccessControl accessControl, bool withContact); TestConnHelper *mConn; TpTestsDBusTubeChannel *mChanService; DBusTubeChannelPtr mChan; uint mCurrentContext; QHash mCurrentContactsForBusNames; bool mBusNameWasAdded; bool mBusNameWasRemoved; bool mOfferFinished; bool mAllowsOtherUsers; uint mExpectedHandle; QString mExpectedBusName; }; void TestDBusTubeChan::onBusNameAdded(const QString &busName, const Tp::ContactPtr &contact) { mCurrentContactsForBusNames.insert(busName, contact); mBusNameWasAdded = true; qDebug() << "Adding bus name" << busName << "for" << contact->id(); QCOMPARE(busName, mExpectedBusName); QCOMPARE(contact->handle().first(), mExpectedHandle); QCOMPARE(mChan->contactsForBusNames().size(), mCurrentContactsForBusNames.size()); mLoop->quit(); } void TestDBusTubeChan::onBusNameRemoved(const QString &busName, const Tp::ContactPtr &contact) { QVERIFY(mCurrentContactsForBusNames.contains(busName)); mCurrentContactsForBusNames.remove(busName); mBusNameWasRemoved = true; qDebug() << "Removing bus name" << busName << "for" << contact->id(); QCOMPARE(contact->handle().first(), mExpectedHandle); QCOMPARE(mChan->contactsForBusNames().size(), mCurrentContactsForBusNames.size()); mLoop->quit(); } void TestDBusTubeChan::onOfferFinished(Tp::PendingOperation *op) { TEST_VERIFY_OP(op); mOfferFinished = true; mLoop->exit(0); } void TestDBusTubeChan::expectPendingTubeConnectionFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingDBusTubeConnection *pdt = qobject_cast(op); mAllowsOtherUsers = pdt->allowsOtherUsers(); // Check the addresses match QCOMPARE(mChan->address(), pdt->address()); mLoop->exit(0); } void TestDBusTubeChan::createTubeChannel(bool requested, TpSocketAddressType addressType, TpSocketAccessControl accessControl, bool withContact) { mChan.reset(); mLoop->processEvents(); tp_clear_object(&mChanService); /* Create service-side tube channel object */ QString chanPath = QString(QLatin1String("%1/Channel")).arg(mConn->objectPath()); TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandleRepoIface *roomRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_ROOM); TpHandle handle; GType type; if (withContact) { handle = tp_handle_ensure(contactRepo, "bob", NULL, NULL); type = TP_TESTS_TYPE_CONTACT_DBUS_TUBE_CHANNEL; } else { handle = tp_handle_ensure(roomRepo, "#test", NULL, NULL); type = TP_TESTS_TYPE_ROOM_DBUS_TUBE_CHANNEL; } TpHandle alfHandle = tp_handle_ensure(contactRepo, "alf", NULL, NULL); GArray *acontrols; TpSocketAccessControl a; if (accessControl != TP_SOCKET_ACCESS_CONTROL_LOCALHOST) { acontrols = g_array_sized_new (FALSE, FALSE, sizeof (guint), 2); a = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; acontrols = g_array_append_val (acontrols, a); a = TP_SOCKET_ACCESS_CONTROL_CREDENTIALS; acontrols = g_array_append_val (acontrols, a); } else { acontrols = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); a = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; acontrols = g_array_append_val (acontrols, a); } mChanService = TP_TESTS_DBUS_TUBE_CHANNEL(g_object_new( type, "connection", mConn->service(), "handle", handle, "requested", requested, "object-path", chanPath.toLatin1().constData(), "supported-access-controls", acontrols, "initiator-handle", alfHandle, NULL)); /* Create client-side tube channel object */ GHashTable *props; g_object_get(mChanService, "channel-properties", &props, NULL); if (requested) { mChan = OutgoingDBusTubeChannel::create(mConn->client(), chanPath, QVariantMap()); } else { mChan = IncomingDBusTubeChannel::create(mConn->client(), chanPath, QVariantMap()); } g_hash_table_unref(props); g_array_unref(acontrols); } void TestDBusTubeChan::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("dbus-tube-chan"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "example", NULL); QCOMPARE(mConn->connect(), true); } void TestDBusTubeChan::init() { initImpl(); mCurrentContext = -1; mBusNameWasAdded = false; mBusNameWasRemoved = false; mOfferFinished = false; mAllowsOtherUsers = false; mExpectedHandle = -1; mExpectedBusName = QString(); } void TestDBusTubeChan::testCreation() { /* Outgoing tube */ createTubeChannel(true, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, true); QVERIFY(connect(mChan->becomeReady(OutgoingDBusTubeChannel::FeatureCore), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(OutgoingDBusTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), false); QCOMPARE(mChan->state(), TubeChannelStateNotOffered); QCOMPARE(mChan->parameters().isEmpty(), true); QCOMPARE(mChan->serviceName(), QLatin1String("com.test.Test")); QCOMPARE(mChan->supportsRestrictingToCurrentUser(), false); QCOMPARE(mChan->contactsForBusNames().isEmpty(), true); QCOMPARE(mChan->address(), QString()); /* incoming tube */ createTubeChannel(false, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); QVERIFY(connect(mChan->becomeReady(IncomingDBusTubeChannel::FeatureCore), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(IncomingDBusTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), false); QCOMPARE(mChan->state(), TubeChannelStateLocalPending); QCOMPARE(mChan->parameters().isEmpty(), false); QCOMPARE(mChan->parameters().size(), 1); QCOMPARE(mChan->parameters().contains(QLatin1String("badger")), true); QCOMPARE(mChan->parameters().value(QLatin1String("badger")), QVariant(42)); QCOMPARE(mChan->serviceName(), QLatin1String("com.test.Test")); QCOMPARE(mChan->supportsRestrictingToCurrentUser(), false); QCOMPARE(mChan->contactsForBusNames().isEmpty(), true); QCOMPARE(mChan->address(), QString()); } void TestDBusTubeChan::testAcceptSuccess() { /* incoming tube */ for (int i = 0; contexts[i].addressType != NUM_TP_SOCKET_ADDRESS_TYPES; i++) { /* as we run several tests here, let's init/cleanup properly */ init(); qDebug() << "Testing context:" << i; mCurrentContext = i; createTubeChannel(false, contexts[i].addressType, contexts[i].accessControl, contexts[i].withContact); QVERIFY(connect(mChan->becomeReady(IncomingDBusTubeChannel::FeatureCore | DBusTubeChannel::FeatureBusNameMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(IncomingDBusTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), true); QCOMPARE(mChan->state(), TubeChannelStateLocalPending); QVERIFY(connect(mChan.data(), SIGNAL(busNameAdded(QString,Tp::ContactPtr)), SLOT(onBusNameAdded(QString,Tp::ContactPtr)))); QVERIFY(connect(mChan.data(), SIGNAL(busNameRemoved(QString,Tp::ContactPtr)), SLOT(onBusNameRemoved(QString,Tp::ContactPtr)))); bool allowsOtherUsers = ((contexts[i].accessControl == TP_SOCKET_ACCESS_CONTROL_LOCALHOST) ? true : false); IncomingDBusTubeChannelPtr chan = IncomingDBusTubeChannelPtr::qObjectCast(mChan); if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { QVERIFY(connect(chan->acceptTube(allowsOtherUsers), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectPendingTubeConnectionFinished(Tp::PendingOperation *)))); } else { // Should never happen QVERIFY(false); } QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->state(), TubeChannelStateOpen); QCOMPARE(mAllowsOtherUsers, allowsOtherUsers); if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { qDebug() << "Connecting to bus" << mChan->address(); QDBusConnection conn = QDBusConnection::connectToPeer(mChan->address(), mChan->serviceName()); QCOMPARE(conn.isConnected(), true); qDebug() << "Connected to host"; } else { QVERIFY(false); } /* as we run several tests here, let's init/cleanup properly */ cleanup(); } } void TestDBusTubeChan::testAcceptFail() { /* incoming tube */ createTubeChannel(false, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); QVERIFY(connect(mChan->becomeReady(IncomingDBusTubeChannel::FeatureCore | DBusTubeChannel::FeatureBusNameMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(IncomingDBusTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), true); QCOMPARE(mChan->state(), TubeChannelStateLocalPending); /* when accept is called the channel will be closed service side */ tp_tests_dbus_tube_channel_set_close_on_accept (mChanService, TRUE); /* calling accept should fail */ IncomingDBusTubeChannelPtr chan = IncomingDBusTubeChannelPtr::qObjectCast(mChan); QVERIFY(connect(chan->acceptTube(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isValid(), false); /* trying to accept again should fail immediately */ QVERIFY(connect(chan->acceptTube(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); } void TestDBusTubeChan::testOfferSuccess() { /* incoming tube */ for (int i = 0; contexts[i].addressType != NUM_TP_SOCKET_ADDRESS_TYPES; i++) { /* as we run several tests here, let's init/cleanup properly */ init(); qDebug() << "Testing context:" << i; mCurrentContext = i; createTubeChannel(true, contexts[i].addressType, contexts[i].accessControl, contexts[i].withContact); QVERIFY(connect(mChan->becomeReady(OutgoingDBusTubeChannel::FeatureCore | DBusTubeChannel::FeatureBusNameMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(OutgoingDBusTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), true); QCOMPARE(mChan->state(), TubeChannelStateNotOffered); QCOMPARE(mChan->parameters().isEmpty(), true); mBusNameWasAdded = false; QVERIFY(connect(mChan.data(), SIGNAL(busNameAdded(QString,Tp::ContactPtr)), SLOT(onBusNameAdded(QString,Tp::ContactPtr)))); QVERIFY(connect(mChan.data(), SIGNAL(busNameRemoved(QString,Tp::ContactPtr)), SLOT(onBusNameRemoved(QString,Tp::ContactPtr)))); bool allowsOtherUsers = ((contexts[i].accessControl == TP_SOCKET_ACCESS_CONTROL_LOCALHOST) ? true : false); mExpectedHandle = -1; mExpectedBusName = QString(); mOfferFinished = false; OutgoingDBusTubeChannelPtr chan = OutgoingDBusTubeChannelPtr::qObjectCast(mChan); QVariantMap offerParameters; offerParameters.insert(QLatin1String("mushroom"), 44); qDebug() << "About to offer tube"; if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { QVERIFY(connect(chan->offerTube(offerParameters, allowsOtherUsers), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onOfferFinished(Tp::PendingOperation *)))); } else { QVERIFY(false); } qDebug() << "Tube offered"; while (mChan->state() != TubeChannelStateRemotePending) { qDebug() << mLoop; mLoop->processEvents(); } // A client now connects to the tube if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { QDBusConnection conn = QDBusConnection::connectToPeer(mChan->address(), mChan->serviceName()); QCOMPARE(conn.isConnected(), true); } else { QVERIFY(false); } qDebug() << "Connected"; TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandle bobHandle = tp_handle_ensure(contactRepo, "bob", NULL, NULL); gchar *bobService = g_strdup("org.bob.test"); tp_tests_dbus_tube_channel_peer_connected_no_stream(mChanService, bobService, bobHandle); mExpectedHandle = bobHandle; mExpectedBusName = QLatin1String("org.bob.test"); QCOMPARE(mChan->state(), TubeChannelStateRemotePending); qDebug() << "Waiting for offer finished"; while (!mOfferFinished) { QCOMPARE(mLoop->exec(), 0); } qDebug() << "Offer finished"; QCOMPARE(mChan->state(), TubeChannelStateOpen); QCOMPARE(mChan->parameters().isEmpty(), false); QCOMPARE(mChan->parameters().size(), 1); QCOMPARE(mChan->parameters().contains(QLatin1String("mushroom")), true); QCOMPARE(mChan->parameters().value(QLatin1String("mushroom")), QVariant(44)); // This section makes sense just in a room environment if (!contexts[i].withContact) { if (!mBusNameWasAdded) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mBusNameWasAdded, true); qDebug() << "Connected to host"; mBusNameWasRemoved = false; tp_tests_dbus_tube_channel_peer_disconnected(mChanService, mExpectedHandle); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mBusNameWasRemoved, true); /* let the internal DBusTubeChannel::onBusNamesChanged slot be called before * checking the data for that connection */ mLoop->processEvents(); QCOMPARE(chan->contactsForBusNames().isEmpty(), true); } /* as we run several tests here, let's init/cleanup properly */ cleanup(); g_free (bobService); } } void TestDBusTubeChan::testOutgoingBusNameMonitoring() { mCurrentContext = 0; // should point to room, localhost createTubeChannel(true, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); QVERIFY(connect(mChan->becomeReady(OutgoingDBusTubeChannel::FeatureCore | DBusTubeChannel::FeatureBusNameMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mChan.data(), SIGNAL(busNameAdded(QString,Tp::ContactPtr)), SLOT(onBusNameAdded(QString,Tp::ContactPtr)))); QVERIFY(connect(mChan.data(), SIGNAL(busNameRemoved(QString,Tp::ContactPtr)), SLOT(onBusNameRemoved(QString,Tp::ContactPtr)))); OutgoingDBusTubeChannelPtr chan = OutgoingDBusTubeChannelPtr::qObjectCast(mChan); QVERIFY(connect(chan->offerTube(QVariantMap()), // DISCARD SIGNAL(finished(Tp::PendingOperation *)), SLOT(onOfferFinished(Tp::PendingOperation *)))); while (mChan->state() != TubeChannelStateRemotePending) { mLoop->processEvents(); } // Simulate a peer connection from someone we don't have a prebuilt contact for yet, and // immediately drop it TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandle handle = tp_handle_ensure(contactRepo, "YouHaventSeenMeYet", NULL, NULL); gchar *service = g_strdup("org.not.seen.yet"); mExpectedHandle = handle; mExpectedBusName = QLatin1String("org.not.seen.yet"); tp_tests_dbus_tube_channel_peer_connected_no_stream(mChanService, service, handle); tp_tests_dbus_tube_channel_peer_disconnected(mChanService, handle); // Test that we get the events in the right sequence while (!mOfferFinished || !mBusNameWasAdded) { QVERIFY(!mBusNameWasRemoved || !mOfferFinished); QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mChan->contactsForBusNames().size(), 1); // The busNameRemoved emission should finally exit the main loop QCOMPARE(mLoop->exec(), 0); QVERIFY(mBusNameWasRemoved); QCOMPARE(mChan->contactsForBusNames().size(), 0); g_free (service); } void TestDBusTubeChan::testExtractBusNameMonitoring() { mCurrentContext = 0; // should point to room, localhost createTubeChannel(true, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); QVERIFY(connect(mChan->becomeReady(OutgoingDBusTubeChannel::FeatureCore), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mChan.data(), SIGNAL(busNameAdded(QString,Tp::ContactPtr)), SLOT(onBusNameAdded(QString,Tp::ContactPtr)))); QVERIFY(connect(mChan.data(), SIGNAL(busNameRemoved(QString,Tp::ContactPtr)), SLOT(onBusNameRemoved(QString,Tp::ContactPtr)))); OutgoingDBusTubeChannelPtr chan = OutgoingDBusTubeChannelPtr::qObjectCast(mChan); QVERIFY(connect(chan->offerTube(QVariantMap()), // DISCARD SIGNAL(finished(Tp::PendingOperation *)), SLOT(onOfferFinished(Tp::PendingOperation *)))); while (mChan->state() != TubeChannelStateRemotePending) { mLoop->processEvents(); } // Simulate a peer connection from someone TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandle handle = tp_handle_ensure(contactRepo, "YouHaventSeenMeYet", NULL, NULL); gchar *service = g_strdup("org.not.seen.yet"); mExpectedHandle = handle; mExpectedBusName = QLatin1String("org.not.seen.yet"); tp_tests_dbus_tube_channel_peer_connected_no_stream(mChanService, service, handle); while (mChan->state() != TubeChannelStateOpen) { mLoop->processEvents(); } // Test that we didn't get a remote connection while (!mOfferFinished) { QCOMPARE(mLoop->exec(), 0); } QVERIFY(!mBusNameWasRemoved); QVERIFY(!mBusNameWasAdded); // This should also trigger a warning QCOMPARE(mChan->contactsForBusNames().size(), 0); // Now, enable the feature, and let it extract participants QVERIFY(connect(mChan->becomeReady(OutgoingDBusTubeChannel::FeatureBusNameMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); // This should now be fine QCOMPARE(mChan->contactsForBusNames().size(), 1); // The name should match QCOMPARE(mChan->contactsForBusNames().keys().first(), QLatin1String("org.not.seen.yet")); // And the signal shouldn't have been called QVERIFY(!mBusNameWasRemoved); QVERIFY(!mBusNameWasAdded); g_free (service); } void TestDBusTubeChan::testAcceptCornerCases() { /* incoming tube */ createTubeChannel(false, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); // These should not be ready yet QCOMPARE(mChan->serviceName(), QString()); QCOMPARE(mChan->supportsRestrictingToCurrentUser(), false); QCOMPARE(mChan->state(), TubeChannelStateNotOffered); QCOMPARE(mChan->parameters(), QVariantMap()); IncomingDBusTubeChannelPtr chan = IncomingDBusTubeChannelPtr::qObjectCast(mChan); // Fail as features are not ready QVERIFY(connect(chan->acceptTube(), // DISCARD SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Become ready QVERIFY(connect(mChan->becomeReady(IncomingDBusTubeChannel::FeatureCore), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(IncomingDBusTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), false); QCOMPARE(mChan->state(), TubeChannelStateLocalPending); // Accept using unsupported method PendingDBusTubeConnection *connection = chan->acceptTube(); // As credentials are not supported, our connection should report we've fallen back. QVERIFY(connection->allowsOtherUsers()); QVERIFY(connect(connection, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->state(), TubeChannelStateOpen); /* try to re-accept the tube */ QVERIFY(connect(chan->acceptTube(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->state(), TubeChannelStateOpen); } void TestDBusTubeChan::testOfferCornerCases() { mCurrentContext = 0; // should point to room, localhost createTubeChannel(true, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); // These should not be ready yet QCOMPARE(mChan->serviceName(), QString()); QCOMPARE(mChan->supportsRestrictingToCurrentUser(), false); QCOMPARE(mChan->state(), TubeChannelStateNotOffered); QCOMPARE(mChan->parameters(), QVariantMap()); OutgoingDBusTubeChannelPtr chan = OutgoingDBusTubeChannelPtr::qObjectCast(mChan); // Fail as features are not ready QVERIFY(connect(chan->offerTube(QVariantMap()), // DISCARD SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // Make them ready QVERIFY(connect(mChan->becomeReady(OutgoingDBusTubeChannel::FeatureCore), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(IncomingDBusTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(DBusTubeChannel::FeatureBusNameMonitoring), false); QCOMPARE(mChan->state(), TubeChannelStateNotOffered); // Offer using unsupported method PendingDBusTubeConnection *connection = chan->offerTube(QVariantMap()); // As credentials are not supported, our connection should report we've fallen back. QVERIFY(connection->allowsOtherUsers()); QVERIFY(connect(connection, // DISCARD SIGNAL(finished(Tp::PendingOperation *)), SLOT(onOfferFinished(Tp::PendingOperation *)))); while (mChan->state() != TubeChannelStateRemotePending) { mLoop->processEvents(); } // Simulate a peer connection from someone TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandle handle = tp_handle_ensure(contactRepo, "YouHaventSeenMeYet", NULL, NULL); gchar *service = g_strdup("org.not.seen.yet"); mExpectedHandle = handle; mExpectedBusName = QLatin1String("org.not.seen.yet"); tp_tests_dbus_tube_channel_peer_connected_no_stream(mChanService, service, handle); while (mChan->state() != TubeChannelStateOpen) { mLoop->processEvents(); } // Get to the connection while (!mOfferFinished) { QCOMPARE(mLoop->exec(), 0); } // Test offering twice QVERIFY(connect(chan->offerTube(QVariantMap()), // DISCARD SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); g_free (service); } void TestDBusTubeChan::cleanup() { cleanupImpl(); if (mChan && mChan->isValid()) { qDebug() << "waiting for the channel to become invalidated"; QVERIFY(connect(mChan.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), mLoop, SLOT(quit()))); tp_base_channel_close(TP_BASE_CHANNEL(mChanService)); QCOMPARE(mLoop->exec(), 0); } mChan.reset(); if (mChanService != 0) { g_object_unref(mChanService); mChanService = 0; } mLoop->processEvents(); } void TestDBusTubeChan::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestDBusTubeChan) #include "_gen/dbus-tube-chan.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/chan-group.cpp0000664000175000017500000004421212470405660017621 0ustar jrjr#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestChanGroup : public Test { Q_OBJECT public: TestChanGroup(QObject *parent = 0) : Test(parent), mConn(0), mChanService(0), mGotGroupFlagsChanged(false), mGroupFlags((ChannelGroupFlags) 0), mGroupFlagsAdded((ChannelGroupFlags) 0), mGroupFlagsRemoved((ChannelGroupFlags) 0) { } protected Q_SLOTS: void onGroupMembersChanged( const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupLocalPendingMembersAdded, const Tp::Contacts &groupRemotePendingMembersAdded, const Tp::Contacts &groupMembersRemoved, const Tp::Channel::GroupMemberChangeDetails &details); void onGroupFlagsChanged(Tp::ChannelGroupFlags flags, Tp::ChannelGroupFlags added, Tp::ChannelGroupFlags removed); private Q_SLOTS: void initTestCase(); void init(); void testCreateChannel(); void testMCDGroup(); void testPropertylessGroup(); void testLeave(); void testLeaveWithFallback(); void testGroupFlagsChange(); void cleanup(); void cleanupTestCase(); private: void debugContacts(); void commonTest(gboolean properties); TestConnHelper *mConn; TpTestsTextChannelGroup *mChanService; ChannelPtr mChan; QString mChanObjectPath; QList mContacts; Contacts mChangedCurrent; Contacts mChangedLP; Contacts mChangedRP; Contacts mChangedRemoved; Channel::GroupMemberChangeDetails mDetails; UIntList mInitialMembers; bool mGotGroupFlagsChanged; ChannelGroupFlags mGroupFlags; ChannelGroupFlags mGroupFlagsAdded; ChannelGroupFlags mGroupFlagsRemoved; }; void TestChanGroup::onGroupMembersChanged( const Contacts &groupMembersAdded, const Contacts &groupLocalPendingMembersAdded, const Contacts &groupRemotePendingMembersAdded, const Contacts &groupMembersRemoved, const Channel::GroupMemberChangeDetails &details) { qDebug() << "group members changed"; mChangedCurrent = groupMembersAdded; mChangedLP = groupLocalPendingMembersAdded; mChangedRP = groupRemotePendingMembersAdded; mChangedRemoved = groupMembersRemoved; mDetails = details; debugContacts(); mLoop->exit(0); } void TestChanGroup::onGroupFlagsChanged(Tp::ChannelGroupFlags flags, Tp::ChannelGroupFlags added, Tp::ChannelGroupFlags removed) { qDebug() << "group flags changed"; mGotGroupFlagsChanged = true; mGroupFlags = flags; mGroupFlagsAdded = added; mGroupFlagsRemoved = removed; } void TestChanGroup::debugContacts() { qDebug() << "contacts on group:"; Q_FOREACH (const ContactPtr &contact, mChan->groupContacts()) { qDebug() << " " << contact->id(); } qDebug() << "local pending contacts on group:"; Q_FOREACH (const ContactPtr &contact, mChan->groupLocalPendingContacts()) { qDebug() << " " << contact->id(); } qDebug() << "remote pending contacts on group:"; Q_FOREACH (const ContactPtr &contact, mChan->groupRemotePendingContacts()) { qDebug() << " " << contact->id(); } } void TestChanGroup::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("chan-group"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, EXAMPLE_TYPE_CONTACT_LIST_CONNECTION, "account", "me@example.com", "protocol", "example-contact-list", "simulation-delay", 1, NULL); QCOMPARE(mConn->connect(Connection::FeatureSelfContact), true); QStringList ids; ids << QLatin1String("sjoerd@example.com"); // Check that the contact is properly built mContacts = mConn->contacts(ids); QCOMPARE(mContacts.size(), 1); QVERIFY(!mContacts.first().isNull()); } void TestChanGroup::init() { initImpl(); mChangedCurrent.clear(); mChangedLP.clear(); mChangedRP.clear(); mChangedRemoved.clear(); mDetails = Channel::GroupMemberChangeDetails(); mGotGroupFlagsChanged = false; mGroupFlags = (ChannelGroupFlags) 0; mGroupFlagsAdded = (ChannelGroupFlags) 0; mGroupFlagsRemoved = (ChannelGroupFlags) 0; } void TestChanGroup::testCreateChannel() { mChan = mConn->ensureChannel(TP_QT_IFACE_CHANNEL_TYPE_CONTACT_LIST, Tp::HandleTypeGroup, QLatin1String("Cambridge")); QVERIFY(mChan); mChanObjectPath = mChan->objectPath(); QVERIFY(connect(mChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(), true); QCOMPARE(static_cast(mChan->targetHandleType()), static_cast(Tp::HandleTypeGroup)); QVERIFY(mChan->targetContact().isNull()); QCOMPARE(mChan->isRequested(), false); QVERIFY(mChan->groupContacts().contains(mContacts.first())); Q_FOREACH (ContactPtr contact, mChan->groupContacts()) mInitialMembers.push_back(contact->handle()[0]); QCOMPARE(mChan->groupFlags(), ChannelGroupFlagCanAdd | ChannelGroupFlagCanRemove | ChannelGroupFlagProperties | ChannelGroupFlagMembersChangedDetailed); QCOMPARE(mChan->groupCanAddContacts(), true); QCOMPARE(mChan->groupCanAddContactsWithMessage(), false); QCOMPARE(mChan->groupCanAcceptContactsWithMessage(), false); QCOMPARE(mChan->groupCanRescindContacts(), false); QCOMPARE(mChan->groupCanRescindContactsWithMessage(), false); QCOMPARE(mChan->groupCanRemoveContacts(), true); QCOMPARE(mChan->groupCanRemoveContactsWithMessage(), false); QCOMPARE(mChan->groupCanRejectContactsWithMessage(), false); QCOMPARE(mChan->groupCanDepartWithMessage(), false); QCOMPARE(mChan->groupIsSelfContactTracked(), true); debugContacts(); QCOMPARE(mChan->groupContacts().count(), 4); QVERIFY(connect(mChan.data(), SIGNAL(groupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), SLOT(onGroupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)))); QList toRemove; toRemove.append(mContacts[0]); connect(mChan->groupRemoveContacts(toRemove, QLatin1String("I want to remove some of them")), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *))); QCOMPARE(mLoop->exec(), 0); while (mChangedRemoved.isEmpty()) { QCOMPARE(mLoop->exec(), 0); } QVERIFY(mChangedRemoved.contains(mContacts[0])); QCOMPARE(mChan->groupContacts().count(), 3); } void TestChanGroup::testMCDGroup() { commonTest(true); } void TestChanGroup::testPropertylessGroup() { commonTest(false); } void TestChanGroup::commonTest(gboolean properties) { mChanObjectPath = QString(QLatin1String("%1/ChannelForTpQtMCDTest%2")) .arg(mConn->objectPath()) .arg(QLatin1String(properties ? "props" : "")); QByteArray chanPathLatin1(mChanObjectPath.toLatin1()); mChanService = TP_TESTS_TEXT_CHANNEL_GROUP(g_object_new( TP_TESTS_TYPE_TEXT_CHANNEL_GROUP, "connection", mConn->service(), "object-path", chanPathLatin1.data(), "detailed", TRUE, "properties", properties, NULL)); QVERIFY(mChanService != 0); TpIntSet *members = tp_intset_sized_new(mInitialMembers.length()); Q_FOREACH (uint handle, mInitialMembers) tp_intset_add(members, handle); QVERIFY(tp_group_mixin_change_members(G_OBJECT(mChanService), "be there or be []", members, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE)); tp_intset_destroy(members); mChan = Channel::create(mConn->client(), mChanObjectPath, QVariantMap()); QVERIFY(mChan); QVERIFY(connect(mChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(), true); QCOMPARE(mChan->isRequested(), true); QVERIFY(mChan->groupContacts().contains(mContacts.first())); Q_FOREACH (ContactPtr contact, mChan->groupContacts()) mInitialMembers.push_back(contact->handle()[0]); QCOMPARE(mChan->groupCanAddContacts(), false); QCOMPARE(mChan->groupCanRemoveContacts(), false); debugContacts(); QCOMPARE(mChan->groupContacts().count(), 4); QVERIFY(connect(mChan.data(), SIGNAL(groupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)), SLOT(onGroupMembersChanged( const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)))); TpIntSet *remove = tp_intset_new_containing(mContacts[0]->handle()[0]); QVERIFY(tp_group_mixin_change_members(G_OBJECT(mChanService), "be a []", NULL, remove, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE)); tp_intset_destroy(remove); while (mChangedRemoved.isEmpty()) { QCOMPARE(mLoop->exec(), 0); } QVERIFY(mChangedRemoved.contains(mContacts[0])); QCOMPARE(mChan->groupContacts().count(), 3); } void TestChanGroup::testLeave() { mChan = mConn->ensureChannel(TP_QT_IFACE_CHANNEL_TYPE_CONTACT_LIST, Tp::HandleTypeGroup, QLatin1String("Cambridge")); QVERIFY(mChan); mChanObjectPath = mChan->objectPath(); // channel is not ready yet, it should fail QVERIFY(connect(mChan->groupAddContacts(QList() << mConn->client()->selfContact()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_NOT_AVAILABLE); QVERIFY(!mLastErrorMessage.isEmpty()); QVERIFY(connect(mChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(), true); // passing no contact should also fail QVERIFY(connect(mChan->groupAddContacts(QList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_INVALID_ARGUMENT); QVERIFY(!mLastErrorMessage.isEmpty()); // passing an invalid contact too QVERIFY(connect(mChan->groupAddContacts(QList() << ContactPtr()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mLastError, TP_QT_ERROR_INVALID_ARGUMENT); QVERIFY(!mLastErrorMessage.isEmpty()); // now it should work QVERIFY(connect(mChan->groupAddContacts(QList() << mConn->client()->selfContact()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mChan->groupContacts().contains(mConn->client()->selfContact())); QString leaveMessage(QLatin1String("I'm sick of this lot")); QVERIFY(connect(mChan->requestLeave(leaveMessage), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mChan->groupContacts().contains(mConn->client()->selfContact())); // We left gracefully, which we have details for. // Unfortunately, the test CM used here ignores the message and the reason specified, so can't // verify those. When the leave code was originally written however, it was able to carry out // the almost-impossible mission of delivering the message and reason to the CM admirably, as // verified by dbus-monitor. QVERIFY(mChan->groupSelfContactRemoveInfo().isValid()); QVERIFY(mChan->groupSelfContactRemoveInfo().hasActor()); QVERIFY(mChan->groupSelfContactRemoveInfo().actor() == mConn->client()->selfContact()); // Another leave should no-op succeed, because we aren't a member QVERIFY(connect(mChan->requestLeave(leaveMessage), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); } void TestChanGroup::testLeaveWithFallback() { mChanObjectPath = QString(QLatin1String("%1/ChannelForTpQtLeaveTestFallback")) .arg(mConn->objectPath()); QByteArray chanPathLatin1(mChanObjectPath.toLatin1()); // The text channel doesn't support removing, so will trigger the fallback mChanService = TP_TESTS_TEXT_CHANNEL_GROUP(g_object_new( TP_TESTS_TYPE_TEXT_CHANNEL_GROUP, "connection", mConn->service(), "object-path", chanPathLatin1.data(), "detailed", TRUE, "properties", TRUE, NULL)); QVERIFY(mChanService != 0); TpIntSet *members = tp_intset_sized_new(1); tp_intset_add(members, mConn->client()->selfHandle()); QVERIFY(tp_group_mixin_change_members(G_OBJECT(mChanService), "be there or be []", members, NULL, NULL, NULL, 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE)); tp_intset_destroy(members); mChan = Channel::create(mConn->client(), mChanObjectPath, QVariantMap()); QVERIFY(mChan); // Should fail, because not ready (and thus we can't know how to leave) QVERIFY(connect(mChan->requestLeave(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectFailure(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(), true); // Should now work QString leaveMessage(QLatin1String("I'm sick of this lot")); QVERIFY(connect(mChan->requestLeave(leaveMessage), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // The Close fallback was triggered, so we weren't removed gracefully and the details were // lost QVERIFY(!mChan->groupSelfContactRemoveInfo().hasMessage()); } void TestChanGroup::testGroupFlagsChange() { TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); guint handle = tp_handle_ensure(contactRepo, "someone@localhost", 0, 0); QString textChanPath = mConn->objectPath() + QLatin1String("/Channel"); QByteArray chanPath(textChanPath.toLatin1()); TpTestsPropsGroupTextChannel *textChanService = TP_TESTS_PROPS_GROUP_TEXT_CHANNEL(g_object_new( TP_TESTS_TYPE_PROPS_GROUP_TEXT_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle, NULL)); TextChannelPtr textChan = TextChannel::create(mConn->client(), textChanPath, QVariantMap()); QVERIFY(connect(textChan->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(textChan->isReady(), true); QVERIFY(textChan->interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)); QVERIFY(!(textChan->groupFlags() & ChannelGroupFlagCanAdd)); QVERIFY(!textChan->canInviteContacts()); QVERIFY(connect(textChan.data(), SIGNAL(groupFlagsChanged(Tp::ChannelGroupFlags,Tp::ChannelGroupFlags,Tp::ChannelGroupFlags)), SLOT(onGroupFlagsChanged(Tp::ChannelGroupFlags,Tp::ChannelGroupFlags,Tp::ChannelGroupFlags)))); tp_group_mixin_change_flags(G_OBJECT(textChanService), TP_CHANNEL_GROUP_FLAG_CAN_ADD, (TpChannelGroupFlags) 0); processDBusQueue(mConn->client().data()); while (!mGotGroupFlagsChanged) { mLoop->processEvents(); } QCOMPARE(textChan->groupFlags(), mGroupFlags); QVERIFY(textChan->groupFlags() & ChannelGroupFlagCanAdd); QVERIFY(textChan->canInviteContacts()); QCOMPARE(mGroupFlagsAdded, ChannelGroupFlagCanAdd); QCOMPARE(mGroupFlagsRemoved, (ChannelGroupFlags) 0); } void TestChanGroup::cleanup() { if (mChanService) { g_object_unref(mChanService); mChanService = 0; } // Avoid D-Bus event leak from one test case to another - I've seen this with the // testCreateChannel groupMembersChanged leaking at least processDBusQueue(mConn->client().data()); mChan.reset(); cleanupImpl(); } void TestChanGroup::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestChanGroup) #include "_gen/chan-group.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/conn-addressing.cpp0000664000175000017500000003270212470405660020635 0ustar jrjr#include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include using namespace Tp; class TestConnAddressing : public Test { Q_OBJECT public: TestConnAddressing(QObject *parent = 0) : Test(parent) { } protected Q_SLOTS: void expectPendingContactsFinished(Tp::PendingOperation *); private Q_SLOTS: void initTestCase(); void init(); void testSupport(); void testRequest(); void testRequestNoFeatures(); void testRequestEmpty(); void cleanup(); void cleanupTestCase(); private: void commonTestRequest(bool withFeatures); TestConnHelper *mConn; QList mContacts; Tp::UIntList mInvalidHandles; QStringList mValidIds; QHash > mInvalidIds; QStringList mValidVCardAddresses; QStringList mInvalidVCardAddresses; QStringList mValidUris; QStringList mInvalidUris; }; void TestConnAddressing::expectPendingContactsFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingContacts *pc = qobject_cast(op); mContacts = pc->contacts(); mInvalidHandles = pc->invalidHandles(); mValidIds = pc->validIdentifiers(); mInvalidIds = pc->invalidIdentifiers(); mValidVCardAddresses = pc->validVCardAddresses(); mInvalidVCardAddresses = pc->invalidVCardAddresses(); mValidUris = pc->validUris(); mInvalidUris = pc->invalidUris(); mLoop->exit(0); } void TestConnAddressing::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("conn-addressing"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_ADDRESSING_CONNECTION, "account", "me@example.com", "protocol", "addressing", NULL); QVERIFY(mConn->connect()); } void TestConnAddressing::init() { initImpl(); mContacts.clear(); mInvalidHandles.clear(); mValidIds.clear(); mInvalidIds.clear(); mValidVCardAddresses.clear(); mInvalidVCardAddresses.clear(); mValidUris.clear(); mInvalidUris.clear(); } void TestConnAddressing::testSupport() { ConnectionPtr conn = mConn->client(); QVERIFY(!conn->lowlevel()->contactAttributeInterfaces().isEmpty()); QVERIFY(conn->lowlevel()->contactAttributeInterfaces().contains( TP_QT_IFACE_CONNECTION)); QVERIFY(conn->lowlevel()->contactAttributeInterfaces().contains( TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING)); Features supportedFeatures = conn->contactManager()->supportedFeatures(); QVERIFY(!supportedFeatures.isEmpty()); QVERIFY(supportedFeatures.contains(Contact::FeatureAddresses)); } void TestConnAddressing::commonTestRequest(bool withFeatures) { ConnectionPtr conn = mConn->client(); Features features; if (withFeatures) { features << Contact::FeatureInfo << Contact::FeatureAddresses; } QStringList validUris; validUris << QLatin1String("addr:foo"); QStringList invalidUris; invalidUris << QLatin1String("invalid_uri:bar"); QStringList uris(validUris); uris.append(invalidUris); PendingContacts *pc = conn->contactManager()->contactsForUris(uris, features); // Test the closure accessors QCOMPARE(pc->manager(), conn->contactManager()); QCOMPARE(pc->features(), features); QVERIFY(pc->isForUris()); QCOMPARE(pc->uris(), uris); QVERIFY(!pc->isForHandles()); QVERIFY(pc->handles().isEmpty()); QVERIFY(!pc->isForIdentifiers()); QVERIFY(pc->identifiers().isEmpty()); QVERIFY(!pc->isForVCardAddresses()); QVERIFY(pc->vcardField().isEmpty()); QVERIFY(pc->vcardAddresses().isEmpty()); QVERIFY(!pc->isUpgrade()); QVERIFY(pc->contactsToUpgrade().isEmpty()); // Wait for the contacts to be built QVERIFY(connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // There should be 1 resulting contact ("foo") and 1 uri found to be invalid QCOMPARE(mContacts.size(), 1); QCOMPARE(mContacts[0]->id(), QLatin1String("foo")); if (withFeatures) { QVERIFY(!mContacts[0]->actualFeatures().contains(Contact::FeatureLocation)); QVERIFY(mContacts[0]->actualFeatures().contains(Contact::FeatureInfo)); QVERIFY(mContacts[0]->actualFeatures().contains(Contact::FeatureAddresses)); QMap vcardAddresses; vcardAddresses.insert(QLatin1String("x-addr"), QLatin1String("foo")); QStringList uris; uris.append(QLatin1String("addr:foo")); QCOMPARE(mContacts[0]->vcardAddresses(), vcardAddresses); QCOMPARE(mContacts[0]->uris(), uris); } else { QVERIFY(!mContacts[0]->actualFeatures().contains(Contact::FeatureLocation)); QVERIFY(!mContacts[0]->actualFeatures().contains(Contact::FeatureInfo)); // FeatureAddresses will be enabled even if not requested when // ContactManager::contactsForUris/VCardAddresses is used, // but we don't want to guarantee that, implementation detail } QCOMPARE(mValidUris, validUris); QCOMPARE(mInvalidUris, invalidUris); QVERIFY(mInvalidHandles.isEmpty()); QVERIFY(mValidIds.isEmpty()); QVERIFY(mInvalidIds.isEmpty()); QVERIFY(mValidVCardAddresses.isEmpty()); QVERIFY(mInvalidVCardAddresses.isEmpty()); QStringList ids; ids << QLatin1String("foo"); QList contacts = mConn->contacts(ids); QCOMPARE(contacts.size(), 1); QCOMPARE(mContacts[0], contacts[0]); // let's test for vCard now QString vcardField(QLatin1String("x-addr")); QStringList vcardAddresses; vcardAddresses << QLatin1String("foo") << QLatin1String("bar"); vcardAddresses.sort(); pc = conn->contactManager()->contactsForVCardAddresses(vcardField, vcardAddresses, features); // Test the closure accessors QCOMPARE(pc->manager(), conn->contactManager()); QCOMPARE(pc->features(), features); QVERIFY(pc->isForVCardAddresses()); QCOMPARE(pc->vcardField(), vcardField); QCOMPARE(pc->vcardAddresses(), vcardAddresses); QVERIFY(!pc->isForHandles()); QVERIFY(pc->handles().isEmpty()); QVERIFY(!pc->isForIdentifiers()); QVERIFY(pc->identifiers().isEmpty()); QVERIFY(!pc->isForUris()); QVERIFY(pc->uris().isEmpty()); QVERIFY(!pc->isUpgrade()); QVERIFY(pc->contactsToUpgrade().isEmpty()); // Wait for the contacts to be built QVERIFY(connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); // There should be 1 resulting contact ("foo") and 1 uri found to be invalid QCOMPARE(mContacts.size(), 2); if (withFeatures) { QVERIFY(!mContacts[0]->actualFeatures().contains(Contact::FeatureLocation)); QVERIFY(mContacts[0]->actualFeatures().contains(Contact::FeatureInfo)); QVERIFY(mContacts[0]->actualFeatures().contains(Contact::FeatureAddresses)); QVERIFY(!mContacts[1]->actualFeatures().contains(Contact::FeatureLocation)); QVERIFY(mContacts[1]->actualFeatures().contains(Contact::FeatureInfo)); QVERIFY(mContacts[1]->actualFeatures().contains(Contact::FeatureAddresses)); } else { QVERIFY(!mContacts[0]->actualFeatures().contains(Contact::FeatureLocation)); QVERIFY(!mContacts[0]->actualFeatures().contains(Contact::FeatureInfo)); QVERIFY(!mContacts[1]->actualFeatures().contains(Contact::FeatureLocation)); QVERIFY(!mContacts[1]->actualFeatures().contains(Contact::FeatureInfo)); // FeatureAddresses will be enabled even if not requested when // ContactManager::contactsForUris/VCardAddresses is used, // but we don't want to guarantee that, implementation detail } mValidVCardAddresses.sort(); QCOMPARE(mValidVCardAddresses, vcardAddresses); QVERIFY(mInvalidVCardAddresses.isEmpty()); QVERIFY(mInvalidHandles.isEmpty()); QVERIFY(mValidIds.isEmpty()); QVERIFY(mInvalidIds.isEmpty()); QVERIFY(mValidUris.isEmpty()); QVERIFY(mInvalidUris.isEmpty()); // contact "foo" should be one of the returned contacts QVERIFY(mContacts[0] != mContacts[1]); QVERIFY(mContacts.contains(contacts[0])); contacts.clear(); ids.clear(); ids << QLatin1String("foo") << QLatin1String("bar"); contacts = mConn->contacts(ids); QCOMPARE(contacts.size(), 2); QVERIFY(contacts.contains(mContacts[0])); QVERIFY(contacts.contains(mContacts[1])); } void TestConnAddressing::testRequest() { commonTestRequest(true); } void TestConnAddressing::testRequestNoFeatures() { commonTestRequest(false); } void TestConnAddressing::testRequestEmpty() { ConnectionPtr conn = mConn->client(); PendingContacts *pc = conn->contactManager()->contactsForHandles(UIntList()); QVERIFY(connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pc->isForHandles()); QVERIFY(pc->handles().isEmpty()); QVERIFY(!pc->isForIdentifiers()); QVERIFY(pc->identifiers().isEmpty()); QVERIFY(!pc->isForUris()); QVERIFY(pc->uris().isEmpty()); QVERIFY(!pc->isForVCardAddresses()); QVERIFY(pc->vcardField().isEmpty()); QVERIFY(pc->vcardAddresses().isEmpty()); QVERIFY(!pc->isUpgrade()); QVERIFY(pc->contactsToUpgrade().isEmpty()); QVERIFY(pc->contacts().isEmpty()); QVERIFY(mInvalidHandles.isEmpty()); QVERIFY(mValidIds.isEmpty()); QVERIFY(mInvalidIds.isEmpty()); QVERIFY(mValidUris.isEmpty()); QVERIFY(mInvalidUris.isEmpty()); QVERIFY(mValidVCardAddresses.isEmpty()); QVERIFY(mInvalidVCardAddresses.isEmpty()); pc = conn->contactManager()->contactsForUris(QStringList()); QVERIFY(connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pc->isForUris()); QVERIFY(pc->uris().isEmpty()); QVERIFY(!pc->isForHandles()); QVERIFY(pc->handles().isEmpty()); QVERIFY(!pc->isForIdentifiers()); QVERIFY(pc->identifiers().isEmpty()); QVERIFY(!pc->isForVCardAddresses()); QVERIFY(pc->vcardField().isEmpty()); QVERIFY(pc->vcardAddresses().isEmpty()); QVERIFY(!pc->isUpgrade()); QVERIFY(pc->contactsToUpgrade().isEmpty()); QVERIFY(pc->contacts().isEmpty()); QVERIFY(mValidUris.isEmpty()); QVERIFY(mInvalidUris.isEmpty()); QVERIFY(mInvalidHandles.isEmpty()); QVERIFY(mValidIds.isEmpty()); QVERIFY(mInvalidIds.isEmpty()); QVERIFY(mValidVCardAddresses.isEmpty()); QVERIFY(mInvalidVCardAddresses.isEmpty()); pc = conn->contactManager()->contactsForVCardAddresses(QString(), QStringList()); QVERIFY(connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pc->isForVCardAddresses()); QVERIFY(pc->vcardField().isEmpty()); QVERIFY(pc->vcardAddresses().isEmpty()); QVERIFY(!pc->isForHandles()); QVERIFY(pc->handles().isEmpty()); QVERIFY(!pc->isForIdentifiers()); QVERIFY(pc->identifiers().isEmpty()); QVERIFY(!pc->isForUris()); QVERIFY(pc->uris().isEmpty()); QVERIFY(!pc->isUpgrade()); QVERIFY(pc->contactsToUpgrade().isEmpty()); QVERIFY(pc->contacts().isEmpty()); QVERIFY(mValidVCardAddresses.isEmpty()); QVERIFY(mInvalidVCardAddresses.isEmpty()); QVERIFY(mInvalidHandles.isEmpty()); QVERIFY(mValidIds.isEmpty()); QVERIFY(mInvalidIds.isEmpty()); QVERIFY(mValidUris.isEmpty()); QVERIFY(mInvalidUris.isEmpty()); pc = conn->contactManager()->contactsForVCardAddresses(QLatin1String("x-unsupported"), QStringList()); QVERIFY(connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingContactsFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pc->isForVCardAddresses()); QCOMPARE(pc->vcardField(), QLatin1String("x-unsupported")); QVERIFY(pc->vcardAddresses().isEmpty()); QVERIFY(!pc->isForHandles()); QVERIFY(pc->handles().isEmpty()); QVERIFY(!pc->isForIdentifiers()); QVERIFY(pc->identifiers().isEmpty()); QVERIFY(!pc->isForUris()); QVERIFY(pc->uris().isEmpty()); QVERIFY(!pc->isUpgrade()); QVERIFY(pc->contactsToUpgrade().isEmpty()); QVERIFY(pc->contacts().isEmpty()); QVERIFY(mValidVCardAddresses.isEmpty()); QVERIFY(mInvalidVCardAddresses.isEmpty()); QVERIFY(mInvalidHandles.isEmpty()); QVERIFY(mValidIds.isEmpty()); QVERIFY(mInvalidIds.isEmpty()); QVERIFY(mValidUris.isEmpty()); QVERIFY(mInvalidUris.isEmpty()); } void TestConnAddressing::cleanup() { cleanupImpl(); } void TestConnAddressing::cleanupTestCase() { if (!mContacts.isEmpty()) { mContacts.clear(); } if (mConn) { QVERIFY(mConn->disconnect()); delete mConn; } cleanupTestCaseImpl(); } QTEST_MAIN(TestConnAddressing) #include "_gen/conn-addressing.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/account-basics.cpp0000664000175000017500000005763512470405660020471 0ustar jrjr#include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestAccountBasics : public Test { Q_OBJECT public: TestAccountBasics(QObject *parent = 0) : Test(parent), mConn(0), mAccountsCount(0) { } protected Q_SLOTS: void onNewAccount(const Tp::AccountPtr &); void onAccountServiceNameChanged(const QString &); void onAccountDisplayNameChanged(const QString &); void onAccountIconNameChanged(const QString &); void onAccountNicknameChanged(const QString &); void onAccountAvatarChanged(const Tp::Avatar &); void onAccountParametersChanged(const QVariantMap &); void onAccountCapabilitiesChanged(const Tp::ConnectionCapabilities &); void onAccountConnectsAutomaticallyChanged(bool); void onAccountAutomaticPresenceChanged(const Tp::Presence &); void onAccountRequestedPresenceChanged(const Tp::Presence &); void onAccountCurrentPresenceChanged(const Tp::Presence &); private Q_SLOTS: void initTestCase(); void init(); void testBasics(); void cleanup(); void cleanupTestCase(); private: QStringList pathsForAccounts(const QList &list); QStringList pathsForAccounts(const AccountSetPtr &set); Tp::AccountManagerPtr mAM; TestConnHelper *mConn; int mAccountsCount; bool mCreatingAccount; QHash mProps; }; #define TEST_VERIFY_PROPERTY_CHANGE(acc, Type, PropertyName, propertyName, expectedValue) \ TEST_VERIFY_PROPERTY_CHANGE_EXTENDED(acc, Type, PropertyName, propertyName, \ propertyName ## Changed, acc->set ## PropertyName(expectedValue), expectedValue) #define TEST_VERIFY_PROPERTY_CHANGE_EXTENDED(acc, Type, PropertyName, propertyName, signalName, po, expectedValue) \ { \ mProps.clear(); \ qDebug().nospace() << "connecting to " << #propertyName << "Changed()"; \ QVERIFY(connect(acc.data(), \ SIGNAL(signalName(Type)), \ SLOT(onAccount ## PropertyName ## Changed(Type)))); \ qDebug().nospace() << "setting " << #propertyName; \ QVERIFY(connect(po, \ SIGNAL(finished(Tp::PendingOperation*)), \ SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); \ QCOMPARE(mLoop->exec(), 0); \ \ if (!mProps.contains(QLatin1String(#PropertyName))) { \ qDebug().nospace() << "waiting for the " << #propertyName << "Changed signal"; \ QCOMPARE(mLoop->exec(), 0); \ } else { \ qDebug().nospace() << "not waiting for " << #propertyName << "Changed because we already got it"; \ } \ \ QCOMPARE(acc->propertyName(), expectedValue); \ QCOMPARE(acc->propertyName(), \ mProps[QLatin1String(#PropertyName)].value< Type >()); \ \ QVERIFY(disconnect(acc.data(), \ SIGNAL(signalName(Type)), \ this, \ SLOT(onAccount ## PropertyName ## Changed(Type)))); \ processDBusQueue(acc.data()); \ } #define TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(Type, PropertyName) \ void TestAccountBasics::onAccount ## PropertyName ## Changed(Type value) \ { \ mProps[QLatin1String(#PropertyName)] = qVariantFromValue(value); \ mLoop->exit(0); \ } void TestAccountBasics::onNewAccount(const Tp::AccountPtr &acc) { Q_UNUSED(acc); mAccountsCount++; if (!mCreatingAccount) { mLoop->exit(0); } } TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const QString &, ServiceName) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const QString &, DisplayName) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const QString &, IconName) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const QString &, Nickname) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const Avatar &, Avatar) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const QVariantMap &, Parameters) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const ConnectionCapabilities &, Capabilities) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(bool, ConnectsAutomatically) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const Presence &, AutomaticPresence) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const Presence &, RequestedPresence) TEST_IMPLEMENT_PROPERTY_CHANGE_SLOT(const Presence &, CurrentPresence) QStringList TestAccountBasics::pathsForAccounts(const QList &list) { QStringList ret; Q_FOREACH (const AccountPtr &account, list) { ret << account->objectPath(); } return ret; } QStringList TestAccountBasics::pathsForAccounts(const AccountSetPtr &set) { QStringList ret; Q_FOREACH (const AccountPtr &account, set->accounts()) { ret << account->objectPath(); } return ret; } void TestAccountBasics::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("account-basics"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mAM = AccountManager::create(AccountFactory::create(QDBusConnection::sessionBus(), Account::FeatureCore | Account::FeatureCapabilities)); QVERIFY(!mAM->isReady()); mConn = new TestConnHelper(this, EXAMPLE_TYPE_ECHO_2_CONNECTION, "account", "me@example.com", "protocol", "echo2", NULL); QVERIFY(mConn->connect()); } void TestAccountBasics::init() { mProps.clear(); mCreatingAccount = false; initImpl(); } void TestAccountBasics::testBasics() { QVERIFY(connect(mAM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mAM->isReady()); QCOMPARE(mAM->interfaces(), QStringList()); QCOMPARE(mAM->supportedAccountProperties(), QStringList() << QLatin1String("org.freedesktop.Telepathy.Account.Enabled")); QVERIFY(connect(mAM.data(), SIGNAL(newAccount(const Tp::AccountPtr &)), SLOT(onNewAccount(const Tp::AccountPtr &)))); QVariantMap parameters; parameters[QLatin1String("account")] = QLatin1String("foobar"); PendingAccount *pacc = mAM->createAccount(QLatin1String("foo"), QLatin1String("bar"), QLatin1String("foobar"), parameters); QVERIFY(connect(pacc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); mCreatingAccount = true; QCOMPARE(mLoop->exec(), 0); mCreatingAccount = false; QVERIFY(pacc->account()); while (mAccountsCount != 1) { QCOMPARE(mLoop->exec(), 0); } processDBusQueue(mConn->client().data()); QStringList paths; QString accPath(QLatin1String("/org/freedesktop/Telepathy/Account/foo/bar/Account0")); QCOMPARE(pathsForAccounts(mAM->allAccounts()), QStringList() << accPath); QList accs = mAM->accountsForObjectPaths( QStringList() << accPath << QLatin1String("/invalid/path")); QCOMPARE(accs.size(), 2); QCOMPARE(accs[0]->objectPath(), accPath); QVERIFY(!accs[1]); QVERIFY(mAM->allAccounts()[0]->isReady( Account::FeatureCore | Account::FeatureCapabilities)); AccountPtr acc = Account::create(mAM->dbusConnection(), mAM->busName(), QLatin1String("/org/freedesktop/Telepathy/Account/foo/bar/Account0"), mAM->connectionFactory(), mAM->channelFactory(), mAM->contactFactory()); QVERIFY(connect(acc->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(acc->isReady()); QCOMPARE(acc->connectionFactory(), mAM->connectionFactory()); QCOMPARE(acc->channelFactory(), mAM->channelFactory()); QCOMPARE(acc->contactFactory(), mAM->contactFactory()); QVERIFY(acc->isValidAccount()); QVERIFY(acc->isEnabled()); QCOMPARE(acc->cmName(), QLatin1String("foo")); QCOMPARE(acc->protocolName(), QLatin1String("bar")); // Service name is empty, fallback to protocol name QCOMPARE(acc->serviceName(), QLatin1String("bar")); // FeatureProfile not ready yet QVERIFY(!acc->profile()); QCOMPARE(acc->displayName(), QString(QLatin1String("foobar (account 0)"))); QCOMPARE(acc->iconName(), QLatin1String("bob.png")); QCOMPARE(acc->nickname(), QLatin1String("Bob")); // FeatureProtocolInfo not ready yet QVERIFY(!acc->avatarRequirements().isValid()); // FeatureAvatar not ready yet QVERIFY(acc->avatar().avatarData.isEmpty()); QVERIFY(acc->avatar().MIMEType.isEmpty()); QCOMPARE(acc->parameters().size(), 1); QVERIFY(acc->parameters().contains(QLatin1String("account"))); QCOMPARE(qdbus_cast(acc->parameters().value(QLatin1String("account"))), QLatin1String("foobar")); // FeatureProtocolInfo not ready yet QVERIFY(!acc->protocolInfo().isValid()); // FeatureCapabilities not ready yet ConnectionCapabilities caps = acc->capabilities(); QVERIFY(!caps.isSpecificToContact()); QVERIFY(!caps.textChats()); QVERIFY(!caps.streamedMediaCalls()); QVERIFY(!caps.streamedMediaAudioCalls()); QVERIFY(!caps.streamedMediaVideoCalls()); QVERIFY(!caps.streamedMediaVideoCallsWithAudio()); QVERIFY(!caps.upgradingStreamedMediaCalls()); QVERIFY(!caps.fileTransfers()); QVERIFY(!caps.textChatrooms()); QVERIFY(!caps.conferenceStreamedMediaCalls()); QVERIFY(!caps.conferenceStreamedMediaCallsWithInvitees()); QVERIFY(!caps.conferenceTextChats()); QVERIFY(!caps.conferenceTextChatsWithInvitees()); QVERIFY(!caps.conferenceTextChatrooms()); QVERIFY(!caps.conferenceTextChatroomsWithInvitees()); QVERIFY(!caps.contactSearches()); QVERIFY(!caps.contactSearchesWithSpecificServer()); QVERIFY(!caps.contactSearchesWithLimit()); QVERIFY(!caps.streamTubes()); QVERIFY(caps.allClassSpecs().isEmpty()); QVERIFY(!acc->connectsAutomatically()); QVERIFY(!acc->hasBeenOnline()); QCOMPARE(acc->connectionStatus(), ConnectionStatusDisconnected); QCOMPARE(acc->connectionStatusReason(), ConnectionStatusReasonNoneSpecified); QVERIFY(acc->connectionError().isEmpty()); QVERIFY(!acc->connectionErrorDetails().isValid()); QVERIFY(acc->connectionErrorDetails().allDetails().isEmpty()); QVERIFY(!acc->connection()); QVERIFY(!acc->isChangingPresence()); // Neither FeatureProtocolInfo or FeatureProfile are ready yet and we have no connection PresenceSpecList expectedPresences; { SimpleStatusSpec prSpec = { ConnectionPresenceTypeAvailable, true, false }; expectedPresences.append(PresenceSpec(QLatin1String("available"), prSpec)); } { SimpleStatusSpec prSpec = { ConnectionPresenceTypeOffline, true, false }; expectedPresences.append(PresenceSpec(QLatin1String("offline"), prSpec)); } qSort(expectedPresences); PresenceSpecList presences = acc->allowedPresenceStatuses(false); qSort(presences); QCOMPARE(presences.size(), 2); QCOMPARE(presences, expectedPresences); presences = acc->allowedPresenceStatuses(true); qSort(presences); QCOMPARE(presences.size(), 2); QCOMPARE(presences, expectedPresences); // No connection QCOMPARE(acc->maxPresenceStatusMessageLength(), static_cast(0)); QCOMPARE(acc->automaticPresence(), Presence::available()); QCOMPARE(acc->currentPresence(), Presence::offline()); QCOMPARE(acc->requestedPresence(), Presence::offline()); QVERIFY(!acc->isOnline()); QCOMPARE(acc->uniqueIdentifier(), QLatin1String("foo/bar/Account0")); QCOMPARE(acc->normalizedName(), QLatin1String("bob")); TEST_VERIFY_PROPERTY_CHANGE(acc, QString, DisplayName, displayName, QLatin1String("foo@bar")); TEST_VERIFY_PROPERTY_CHANGE(acc, QString, IconName, iconName, QLatin1String("im-foo")); // Setting icon to an empty string should fallback to im-$protocol as FeatureProtocolInfo and // FeatureProtocolInfo are not ready yet TEST_VERIFY_PROPERTY_CHANGE_EXTENDED(acc, QString, IconName, iconName, iconNameChanged, acc->setIconName(QString()), QLatin1String("im-bar")); TEST_VERIFY_PROPERTY_CHANGE(acc, QString, Nickname, nickname, QLatin1String("Bob rocks!")); qDebug() << "making Account::FeatureAvatar ready"; QVERIFY(connect(acc->becomeReady(Account::FeatureAvatar), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(acc->isReady(Account::FeatureAvatar)); Avatar expectedAvatar = { QByteArray("asdfg"), QLatin1String("image/jpeg") }; TEST_VERIFY_PROPERTY_CHANGE(acc, Tp::Avatar, Avatar, avatar, expectedAvatar); QVariantMap expectedParameters = acc->parameters(); expectedParameters[QLatin1String("foo")] = QLatin1String("bar"); TEST_VERIFY_PROPERTY_CHANGE_EXTENDED(acc, QVariantMap, Parameters, parameters, parametersChanged, acc->updateParameters(expectedParameters, QStringList()), expectedParameters); TEST_VERIFY_PROPERTY_CHANGE_EXTENDED(acc, bool, ConnectsAutomatically, connectsAutomatically, connectsAutomaticallyPropertyChanged, acc->setConnectsAutomatically(true), true); TEST_VERIFY_PROPERTY_CHANGE(acc, Tp::Presence, AutomaticPresence, automaticPresence, Presence::busy()); // Changing requested presence will also change hasBeenOnline/isOnline/currentPresence Presence expectedPresence = Presence::busy(); TEST_VERIFY_PROPERTY_CHANGE(acc, Tp::Presence, RequestedPresence, requestedPresence, expectedPresence); QVERIFY(acc->hasBeenOnline()); QVERIFY(acc->isOnline()); QCOMPARE(acc->currentPresence(), expectedPresence); qDebug() << "creating another account"; pacc = mAM->createAccount(QLatin1String("spurious"), QLatin1String("normal"), QLatin1String("foobar"), QVariantMap()); QVERIFY(connect(pacc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); mCreatingAccount = true; QCOMPARE(mLoop->exec(), 0); mCreatingAccount = false; while (mAccountsCount != 2) { QCOMPARE(mLoop->exec(), 0); } processDBusQueue(mConn->client().data()); acc = Account::create(mAM->dbusConnection(), mAM->busName(), QLatin1String("/org/freedesktop/Telepathy/Account/spurious/normal/Account0"), mAM->connectionFactory(), mAM->channelFactory(), mAM->contactFactory()); QVERIFY(connect(acc->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(acc->isReady()); QCOMPARE(acc->iconName(), QLatin1String("bob.png")); // Setting icon to an empty string should fallback to Profile/ProtocolInfo/im-$protocol TEST_VERIFY_PROPERTY_CHANGE_EXTENDED(acc, QString, IconName, iconName, iconNameChanged, acc->setIconName(QString()), QLatin1String("im-normal")); QVERIFY(connect(acc->becomeReady(Account::FeatureProtocolInfo), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(acc->isReady(Account::FeatureProtocolInfo)); // This time it's fetched from the protocol object (although it probably internally just // infers it from the protocol name too) QCOMPARE(acc->iconName(), QLatin1String("im-normal")); ProtocolInfo protocolInfo = acc->protocolInfo(); QVERIFY(protocolInfo.isValid()); QCOMPARE(protocolInfo.iconName(), QLatin1String("im-normal")); QVERIFY(protocolInfo.hasParameter(QLatin1String("account"))); QVERIFY(protocolInfo.hasParameter(QLatin1String("password"))); QVERIFY(protocolInfo.hasParameter(QLatin1String("register"))); QVERIFY(!protocolInfo.hasParameter(QLatin1String("bogusparam"))); QCOMPARE(protocolInfo.parameters().size(), 3); QVERIFY(connect(acc->becomeReady(Account::FeatureProfile), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(acc->isReady(Account::FeatureProfile)); ProfilePtr profile = acc->profile(); QVERIFY(!profile.isNull()); QVERIFY(profile->isFake()); QVERIFY(profile->isValid()); QCOMPARE(profile->serviceName(), QString(QLatin1String("%1-%2")) .arg(acc->cmName()).arg(acc->serviceName())); QCOMPARE(profile->type(), QLatin1String("IM")); QCOMPARE(profile->provider(), QString()); QCOMPARE(profile->name(), acc->protocolName()); QCOMPARE(profile->cmName(), acc->cmName()); QCOMPARE(profile->protocolName(), acc->protocolName()); QVERIFY(!profile->parameters().isEmpty()); QVERIFY(profile->allowOtherPresences()); QVERIFY(profile->presences().isEmpty()); QVERIFY(profile->unsupportedChannelClassSpecs().isEmpty()); QCOMPARE(acc->serviceName(), acc->protocolName()); TEST_VERIFY_PROPERTY_CHANGE(acc, QString, ServiceName, serviceName, QLatin1String("spurious-service")); QVERIFY(connect(acc->becomeReady(Account::FeatureAvatar), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(acc->isReady(Account::FeatureAvatar)); QVERIFY(acc->avatar().avatarData.isEmpty()); QCOMPARE(acc->avatar().MIMEType, QString(QLatin1String("image/png"))); // make redundant becomeReady calls QVERIFY(connect(acc->becomeReady(Account::FeatureAvatar | Account::FeatureProtocolInfo), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(acc->isReady(Account::FeatureAvatar | Account::FeatureProtocolInfo)); QVERIFY(acc->avatar().avatarData.isEmpty()); QCOMPARE(acc->avatar().MIMEType, QString(QLatin1String("image/png"))); protocolInfo = acc->protocolInfo(); QVERIFY(protocolInfo.isValid()); QCOMPARE(protocolInfo.iconName(), QLatin1String("im-normal")); QVERIFY(protocolInfo.hasParameter(QLatin1String("account"))); QVERIFY(protocolInfo.hasParameter(QLatin1String("password"))); QVERIFY(protocolInfo.hasParameter(QLatin1String("register"))); QVERIFY(connect(acc->becomeReady(Account::FeatureCapabilities), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(acc->isReady(Account::FeatureCapabilities)); // using protocol info caps = acc->capabilities(); QVERIFY(caps.textChats()); // set new service name will change caps, icon and serviceName QVERIFY(connect(acc.data(), SIGNAL(capabilitiesChanged(const Tp::ConnectionCapabilities &)), SLOT(onAccountCapabilitiesChanged(const Tp::ConnectionCapabilities &)))); TEST_VERIFY_PROPERTY_CHANGE(acc, QString, ServiceName, serviceName, QLatin1String("test-profile")); while (!mProps.contains(QLatin1String("IconName")) && !mProps.contains(QLatin1String("Capabilities"))) { QCOMPARE(mLoop->exec(), 0); } // Now that both FeatureProtocolInfo and FeatureProfile are ready, let's check the allowed // presences expectedPresences.clear(); { SimpleStatusSpec prSpec = { ConnectionPresenceTypeAvailable, true, true }; expectedPresences.append(PresenceSpec(QLatin1String("available"), prSpec)); } { SimpleStatusSpec prSpec = { ConnectionPresenceTypeAway, true, true }; expectedPresences.append(PresenceSpec(QLatin1String("away"), prSpec)); } { SimpleStatusSpec prSpec = { ConnectionPresenceTypeOffline, true, false }; expectedPresences.append(PresenceSpec(QLatin1String("offline"), prSpec)); } qSort(expectedPresences); presences = acc->allowedPresenceStatuses(false); qSort(presences); QCOMPARE(presences.size(), 3); QCOMPARE(presences, expectedPresences); { SimpleStatusSpec prSpec = { ConnectionPresenceTypeExtendedAway, false, false }; expectedPresences.append(PresenceSpec(QLatin1String("xa"), prSpec)); } qSort(expectedPresences); presences = acc->allowedPresenceStatuses(true); qSort(presences); QCOMPARE(presences.size(), 4); QCOMPARE(presences, expectedPresences); QCOMPARE(acc->iconName(), QLatin1String("test-profile-icon")); // using merged protocol info caps and profile caps caps = acc->capabilities(); QVERIFY(!caps.textChats()); Client::DBus::PropertiesInterface *accPropertiesInterface = acc->interface(); // simulate that the account has a connection QVERIFY(connect(new PendingVoid( accPropertiesInterface->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("Connection"), QDBusVariant(mConn->objectPath())), acc), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); // wait for the connection to be built in Account while (acc->connection().isNull()) { QCOMPARE(mLoop->exec(), 0); } QVERIFY(connect(acc->connection()->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(acc->isReady()); // once the status change the capabilities will be updated mProps.clear(); QVERIFY(connect(acc->setRequestedPresence(Presence::available()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); while (!mProps.contains(QLatin1String("Capabilities"))) { QCOMPARE(mLoop->exec(), 0); } // using connection caps now caps = acc->capabilities(); QVERIFY(caps.textChats()); QVERIFY(!caps.textChatrooms()); QVERIFY(!caps.streamedMediaCalls()); QVERIFY(!caps.streamedMediaAudioCalls()); QVERIFY(!caps.streamedMediaVideoCalls()); QVERIFY(!caps.streamedMediaVideoCallsWithAudio()); QVERIFY(!caps.upgradingStreamedMediaCalls()); // once the status change the capabilities will be updated mProps.clear(); QVERIFY(connect(new PendingVoid( accPropertiesInterface->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("Connection"), QDBusVariant(QLatin1String("/"))), acc), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QVERIFY(connect(acc->setRequestedPresence(Presence::offline()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); while (!mProps.contains(QLatin1String("Capabilities"))) { QCOMPARE(mLoop->exec(), 0); } // back to using merged protocol info caps and profile caps caps = acc->capabilities(); QVERIFY(!caps.textChats()); processDBusQueue(mConn->client().data()); } void TestAccountBasics::cleanup() { cleanupImpl(); } void TestAccountBasics::cleanupTestCase() { if (mConn) { QVERIFY(mConn->disconnect()); delete mConn; } cleanupTestCaseImpl(); } QTEST_MAIN(TestAccountBasics) #include "_gen/account-basics.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/cm-protocol.cpp0000664000175000017500000006044212470405660020017 0ustar jrjr#include #include #include #include #include #include #include #include using namespace Tp; using namespace Tp::Client; namespace { PresenceSpec getPresenceSpec(const PresenceSpecList &specs, const QString &status) { Q_FOREACH (const PresenceSpec &spec, specs) { if (spec.presence().status() == status) { return spec; } } return PresenceSpec(); } } class ConnectionManagerAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ConnectionManager") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QStringList Interfaces READ Interfaces) Q_PROPERTY(Tp::ProtocolPropertiesMap Protocols READ Protocols) public: ConnectionManagerAdaptor(ProtocolPropertiesMap &protocols, QObject *parent) : QDBusAbstractAdaptor(parent), mProtocols(protocols) { } virtual ~ConnectionManagerAdaptor() { } public: // Properties inline QStringList Interfaces() const { return QStringList(); } inline ProtocolPropertiesMap Protocols() const { return mProtocols; } private: ProtocolPropertiesMap mProtocols; ParamSpecList mParameters; }; class ProtocolAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Protocol") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QStringList Interfaces READ Interfaces) Q_PROPERTY(Tp::ParamSpecList Parameters READ Parameters) Q_PROPERTY(QStringList ConnectionInterfaces READ ConnectionInterfaces) Q_PROPERTY(Tp::RequestableChannelClassList RequestableChannelClasses READ RequestableChannelClasses) Q_PROPERTY(QString VCardField READ VCardField) Q_PROPERTY(QString EnglishName READ EnglishName) Q_PROPERTY(QString Icon READ Icon) public: ProtocolAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent), introspectionCalled(0) { mInterfaces << TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING << TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS << TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE; mConnInterfaces << TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS; mRCCs.append(RequestableChannelClassSpec::textChatroom().bareClass()); mVCardField = QLatin1String("x-adaptor"); mEnglishName = QLatin1String("Adaptor"); mIcon = QLatin1String("icon-adaptor"); } virtual ~ProtocolAdaptor() { } inline QVariantMap immutableProperties() const { QVariantMap ret; ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".Interfaces"), mInterfaces); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".Parameters"), qVariantFromValue(mParameters)); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".ConnectionInterfaces"), mConnInterfaces); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".RequestableChannelClasses"), qVariantFromValue(mRCCs)); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".VCardField"), mVCardField); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".EnglishName"), mEnglishName); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".Icon"), mIcon); return ret; } public: // Properties inline QStringList Interfaces() const { // if we request all properties we are going to get here, so marking as // introspectionCalled; introspectionCalled++; return mInterfaces; } inline Tp::ParamSpecList Parameters() const { return mParameters; } inline QStringList ConnectionInterfaces() const { return mConnInterfaces; } inline Tp::RequestableChannelClassList RequestableChannelClasses() const { return mRCCs; } inline QString VCardField() const { return mVCardField; } inline QString EnglishName() const { return mEnglishName; } inline QString Icon() const { return mIcon; } mutable int introspectionCalled; private: QStringList mInterfaces; ParamSpecList mParameters; QStringList mConnInterfaces; RequestableChannelClassList mRCCs; QString mVCardField; QString mEnglishName; QString mIcon; }; class ProtocolAddressingAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Protocol.Interface.Addressing") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QStringList AddressableVCardFields READ AddressableVCardFields) Q_PROPERTY(QStringList AddressableURISchemes READ AddressableURISchemes) public: ProtocolAddressingAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent), introspectionCalled(0) { mVCardFields << QLatin1String("x-adaptor"); mUris << QLatin1String("adaptor"); } virtual ~ProtocolAddressingAdaptor() { } inline QVariantMap immutableProperties() const { QVariantMap ret; ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING + QLatin1String(".AddressableVCardFields"), mVCardFields); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING + QLatin1String(".AddressableURISchemes"), mUris); return ret; } public: // Properties inline QStringList AddressableVCardFields() const { // if we request all properties we are going to get here, so marking as // introspectionCalled; introspectionCalled++; return mVCardFields; } inline QStringList AddressableURISchemes() const { return mUris; } mutable int introspectionCalled; private: QStringList mVCardFields; QStringList mUris; }; class ProtocolAvatarsAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Protocol.Interface.Avatars") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QStringList SupportedAvatarMIMETypes READ SupportedAvatarMIMETypes) Q_PROPERTY(uint MinimumAvatarHeight READ MinimumAvatarHeight) Q_PROPERTY(uint MinimumAvatarWidth READ MinimumAvatarWidth) Q_PROPERTY(uint RecommendedAvatarHeight READ RecommendedAvatarHeight) Q_PROPERTY(uint RecommendedAvatarWidth READ RecommendedAvatarWidth) Q_PROPERTY(uint MaximumAvatarHeight READ MaximumAvatarHeight) Q_PROPERTY(uint MaximumAvatarWidth READ MaximumAvatarWidth) Q_PROPERTY(uint MaximumAvatarBytes READ MaximumAvatarBytes) public: ProtocolAvatarsAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent), introspectionCalled(0) { mMimeTypes << QLatin1String("image/png"); mMinimumAvatarHeight = 16; mMinimumAvatarWidth = 16; mRecommendedAvatarHeight = 32; mRecommendedAvatarWidth = 32; mMaximumAvatarHeight = 64; mMaximumAvatarWidth = 64; mMaximumAvatarBytes = 4096; } virtual ~ProtocolAvatarsAdaptor() { } inline QVariantMap immutableProperties() const { QVariantMap ret; ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".SupportedAvatarMIMETypes"), mMimeTypes); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarHeight"), mMinimumAvatarHeight); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarWidth"), mMinimumAvatarWidth); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarHeight"), mMaximumAvatarHeight); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarWidth"), mMaximumAvatarWidth); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarHeight"), mRecommendedAvatarHeight); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarWidth"), mRecommendedAvatarWidth); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarBytes"), mMaximumAvatarBytes); return ret; } public: // Properties inline QStringList SupportedAvatarMIMETypes() const { // if we request all properties we are going to get here, so marking as // introspectionCalled; introspectionCalled++; return mMimeTypes; } inline uint MinimumAvatarHeight() const { return mMinimumAvatarHeight; } inline uint MinimumAvatarWidth() const { return mMinimumAvatarWidth; } inline uint RecommendedAvatarHeight() const { return mRecommendedAvatarHeight; } inline uint RecommendedAvatarWidth() const { return mRecommendedAvatarWidth; } inline uint MaximumAvatarHeight() const { return mMaximumAvatarHeight; } inline uint MaximumAvatarWidth() const { return mMaximumAvatarWidth; } inline uint MaximumAvatarBytes() const { return mMaximumAvatarBytes; } mutable int introspectionCalled; private: QStringList mMimeTypes; uint mMinimumAvatarHeight; uint mMinimumAvatarWidth; uint mRecommendedAvatarHeight; uint mRecommendedAvatarWidth; uint mMaximumAvatarHeight; uint mMaximumAvatarWidth; uint mMaximumAvatarBytes; }; class ProtocolPresenceAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Protocol.Interface.Presence") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(Tp::SimpleStatusSpecMap Statuses READ Statuses) public: ProtocolPresenceAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent), introspectionCalled(0) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeAvailable; spec.maySetOnSelf = true; spec.canHaveMessage = false; mStatuses.insert(QLatin1String("available"), spec); } virtual ~ProtocolPresenceAdaptor() { } inline QVariantMap immutableProperties() const { QVariantMap ret; ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE + QLatin1String(".Statuses"), qVariantFromValue(mStatuses)); return ret; } public: // Properties inline SimpleStatusSpecMap Statuses() const { // if we request all properties we are going to get here, so marking as // introspectionCalled; introspectionCalled++; return mStatuses; } mutable int introspectionCalled; private: SimpleStatusSpecMap mStatuses; }; struct CMHelper { CMHelper(const QString &cmName, bool withProtocolProps = false, bool withProtocolAddressingProps = false, bool withProtocolAvatarsProps = false, bool withProtocolPresenceProps = false) { QDBusConnection bus = QDBusConnection::sessionBus(); QString cmBusNameBase = TP_QT_CONNECTION_MANAGER_BUS_NAME_BASE; QString cmPathBase = TP_QT_CONNECTION_MANAGER_OBJECT_PATH_BASE; protocolObject = new QObject(); protocolAdaptor = new ProtocolAdaptor(protocolObject); protocolAddressingAdaptor = new ProtocolAddressingAdaptor(protocolObject); protocolAvatarsAdaptor = new ProtocolAvatarsAdaptor(protocolObject); protocolPresenceAdaptor = new ProtocolPresenceAdaptor(protocolObject); QVERIFY(bus.registerService(cmBusNameBase + cmName)); QVERIFY(bus.registerObject(cmPathBase + cmName + QLatin1String("/") + cmName, protocolObject)); ProtocolPropertiesMap protocols; QVariantMap immutableProperties; if (withProtocolProps) { immutableProperties.unite(protocolAdaptor->immutableProperties()); } if (withProtocolAddressingProps) { immutableProperties.unite(protocolAddressingAdaptor->immutableProperties()); } if (withProtocolAvatarsProps) { immutableProperties.unite(protocolAvatarsAdaptor->immutableProperties()); } if (withProtocolPresenceProps) { immutableProperties.unite(protocolPresenceAdaptor->immutableProperties()); } protocols.insert(cmName, immutableProperties); cmObject = new QObject(); cmAdaptor = new ConnectionManagerAdaptor(protocols, cmObject); QVERIFY(bus.registerService(cmBusNameBase + cmName)); QVERIFY(bus.registerObject(cmPathBase + cmName, cmObject)); cm = ConnectionManager::create(bus, cmName); } ~CMHelper() { delete cmObject; delete protocolObject; } ConnectionManagerPtr cm; QObject *cmObject; QObject *protocolObject; ConnectionManagerAdaptor *cmAdaptor; ProtocolAdaptor *protocolAdaptor; ProtocolAddressingAdaptor *protocolAddressingAdaptor; ProtocolAvatarsAdaptor *protocolAvatarsAdaptor; ProtocolPresenceAdaptor *protocolPresenceAdaptor; }; class TestCmProtocol : public Test { Q_OBJECT public: TestCmProtocol(QObject *parent = 0) : Test(parent), mCM(0) { } private Q_SLOTS: void initTestCase(); void init(); void testIntrospection(); void testIntrospectionWithManager(); void testIntrospectionWithProperties(); void testIntrospectionWithSomeProperties(); void cleanup(); void cleanupTestCase(); private: void testIntrospectionWithAdaptorCommon(const ConnectionManagerPtr &cm); CMHelper *mCM; }; void TestCmProtocol::initTestCase() { initTestCaseImpl(); } void TestCmProtocol::init() { initImpl(); } void TestCmProtocol::testIntrospection() { mCM = new CMHelper(QLatin1String("protocolnomanager"), false); ConnectionManagerPtr cm = mCM->cm; QVERIFY(connect(cm->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cm->isReady(), true); testIntrospectionWithAdaptorCommon(cm); QVERIFY(mCM->protocolAdaptor->introspectionCalled > 0); QVERIFY(mCM->protocolAddressingAdaptor->introspectionCalled > 0); QVERIFY(mCM->protocolAvatarsAdaptor->introspectionCalled > 0); QVERIFY(mCM->protocolPresenceAdaptor->introspectionCalled > 0); } void TestCmProtocol::testIntrospectionWithManager() { mCM = new CMHelper(QLatin1String("protocol"), false); ConnectionManagerPtr cm = mCM->cm; QVERIFY(connect(cm->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cm->isReady(), true); QCOMPARE(cm->interfaces(), QStringList()); QCOMPARE(cm->supportedProtocols(), QStringList() << QLatin1String("protocol")); QVERIFY(cm->hasProtocol(QLatin1String("protocol"))); QVERIFY(!cm->hasProtocol(QLatin1String("not-there"))); ProtocolInfo info = cm->protocol(QLatin1String("protocol")); QVERIFY(info.isValid()); QCOMPARE(info.cmName(), QLatin1String("protocol")); QCOMPARE(info.name(), QLatin1String("protocol")); QCOMPARE(info.parameters().size(), 1); ProtocolParameter param = info.parameters().at(0); QCOMPARE(param.name(), QLatin1String("account")); QCOMPARE(static_cast(param.type()), static_cast(QVariant::String)); QCOMPARE(param.defaultValue().isNull(), true); QCOMPARE(param.dbusSignature().signature(), QLatin1String("s")); QCOMPARE(param.isRequired(), true); QCOMPARE(param.isRequiredForRegistration(), true); // though it can't register! QCOMPARE(param.isSecret(), false); QVERIFY(!info.canRegister()); QVERIFY(!info.capabilities().isSpecificToContact()); QVERIFY(!info.capabilities().textChatrooms()); QVERIFY(info.capabilities().textChats()); QCOMPARE(info.vcardField(), QLatin1String("x-telepathy-protocol")); QCOMPARE(info.englishName(), QLatin1String("Telepathy Protocol")); QCOMPARE(info.iconName(), QLatin1String("im-protocol")); QStringList addressableVCardFields = info.addressableVCardFields(); QCOMPARE(addressableVCardFields, QStringList() << QLatin1String("x-protocol")); QStringList addressableUriSchemes = info.addressableUriSchemes(); QCOMPARE(addressableUriSchemes, QStringList() << QLatin1String("protocol")); AvatarSpec avatarReqs = info.avatarRequirements(); QStringList supportedMimeTypes = avatarReqs.supportedMimeTypes(); QCOMPARE(supportedMimeTypes, QStringList() << QLatin1String("image/jpeg")); QCOMPARE(avatarReqs.minimumHeight(), (uint) 32); QCOMPARE(avatarReqs.maximumHeight(), (uint) 96); QCOMPARE(avatarReqs.recommendedHeight(), (uint) 64); QCOMPARE(avatarReqs.minimumWidth(), (uint) 32); QCOMPARE(avatarReqs.maximumWidth(), (uint) 96); QCOMPARE(avatarReqs.recommendedWidth(), (uint) 64); QCOMPARE(avatarReqs.maximumBytes(), (uint) 37748736); PresenceSpecList statuses = info.allowedPresenceStatuses(); QCOMPARE(statuses.size(), 2); PresenceSpec spec = getPresenceSpec(statuses, QLatin1String("available")); QVERIFY(spec.isValid()); QVERIFY(spec.presence().type() == ConnectionPresenceTypeAvailable); QVERIFY(spec.maySetOnSelf()); QVERIFY(spec.canHaveStatusMessage()); spec = getPresenceSpec(statuses, QLatin1String("offline")); QVERIFY(spec.isValid()); QVERIFY(spec.presence().type() == ConnectionPresenceTypeOffline); QVERIFY(!spec.maySetOnSelf()); QVERIFY(!spec.canHaveStatusMessage()); QCOMPARE(mCM->protocolAdaptor->introspectionCalled, 0); QCOMPARE(mCM->protocolAddressingAdaptor->introspectionCalled, 0); QCOMPARE(mCM->protocolAvatarsAdaptor->introspectionCalled, 0); QCOMPARE(mCM->protocolPresenceAdaptor->introspectionCalled, 0); } void TestCmProtocol::testIntrospectionWithProperties() { mCM = new CMHelper(QLatin1String("protocolwithprops"), true, true, true, true); ConnectionManagerPtr cm = mCM->cm; QVERIFY(connect(cm->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cm->isReady(), true); testIntrospectionWithAdaptorCommon(cm); QCOMPARE(mCM->protocolAdaptor->introspectionCalled, 0); QCOMPARE(mCM->protocolAddressingAdaptor->introspectionCalled, 0); QCOMPARE(mCM->protocolAvatarsAdaptor->introspectionCalled, 0); QCOMPARE(mCM->protocolPresenceAdaptor->introspectionCalled, 0); } void TestCmProtocol::testIntrospectionWithSomeProperties() { mCM = new CMHelper(QLatin1String("protocolwithsomeprops"), false, false, true, true); ConnectionManagerPtr cm = mCM->cm; QVERIFY(connect(cm->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(cm->isReady(), true); testIntrospectionWithAdaptorCommon(cm); QVERIFY(mCM->protocolAdaptor->introspectionCalled > 0); QVERIFY(mCM->protocolAddressingAdaptor->introspectionCalled > 0); QCOMPARE(mCM->protocolAvatarsAdaptor->introspectionCalled, 0); QCOMPARE(mCM->protocolPresenceAdaptor->introspectionCalled, 0); } void TestCmProtocol::testIntrospectionWithAdaptorCommon(const ConnectionManagerPtr &cm) { QCOMPARE(cm->interfaces(), QStringList()); QCOMPARE(cm->supportedProtocols(), QStringList() << cm->name()); QVERIFY(cm->hasProtocol(cm->name())); QVERIFY(!cm->hasProtocol(QLatin1String("not-there"))); ProtocolInfo info = cm->protocol(cm->name()); QVERIFY(info.isValid()); QCOMPARE(info.cmName(), cm->name()); QCOMPARE(info.name(), cm->name()); QCOMPARE(info.parameters().size(), 0); QVERIFY(!info.canRegister()); QVERIFY(!info.capabilities().isSpecificToContact()); QVERIFY(info.capabilities().textChatrooms()); QVERIFY(!info.capabilities().textChats()); QCOMPARE(info.vcardField(), QLatin1String("x-adaptor")); QCOMPARE(info.englishName(), QLatin1String("Adaptor")); QCOMPARE(info.iconName(), QLatin1String("icon-adaptor")); QStringList addressableVCardFields = info.addressableVCardFields(); QCOMPARE(addressableVCardFields, QStringList() << QLatin1String("x-adaptor")); QStringList addressableUriSchemes = info.addressableUriSchemes(); QCOMPARE(addressableUriSchemes, QStringList() << QLatin1String("adaptor")); AvatarSpec avatarReqs = info.avatarRequirements(); QStringList supportedMimeTypes = avatarReqs.supportedMimeTypes(); QCOMPARE(supportedMimeTypes, QStringList() << QLatin1String("image/png")); QCOMPARE(avatarReqs.minimumHeight(), (uint) 16); QCOMPARE(avatarReqs.maximumHeight(), (uint) 64); QCOMPARE(avatarReqs.recommendedHeight(), (uint) 32); QCOMPARE(avatarReqs.minimumWidth(), (uint) 16); QCOMPARE(avatarReqs.maximumWidth(), (uint) 64); QCOMPARE(avatarReqs.recommendedWidth(), (uint) 32); QCOMPARE(avatarReqs.maximumBytes(), (uint) 4096); PresenceSpecList statuses = info.allowedPresenceStatuses(); QCOMPARE(statuses.size(), 1); PresenceSpec spec = getPresenceSpec(statuses, QLatin1String("available")); QVERIFY(spec.isValid()); QVERIFY(spec.presence().type() == ConnectionPresenceTypeAvailable); QVERIFY(spec.maySetOnSelf()); QVERIFY(!spec.canHaveStatusMessage()); spec = getPresenceSpec(statuses, QLatin1String("offline")); QVERIFY(!spec.isValid()); } void TestCmProtocol::cleanup() { cleanupImpl(); } void TestCmProtocol::cleanupTestCase() { delete mCM; cleanupTestCaseImpl(); } QTEST_MAIN(TestCmProtocol) #include "_gen/cm-protocol.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/stream-tube-chan.cpp0000664000175000017500000010306612470405660020720 0ustar jrjr#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; namespace { struct TestContext { bool withContact; TpSocketAddressType addressType; TpSocketAccessControl accessControl; }; // FIXME: Enable IPv6 and Port access control tests TestContext contexts[] = { { FALSE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, { FALSE, TP_SOCKET_ADDRESS_TYPE_IPV4, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, //{ FALSE, TP_SOCKET_ADDRESS_TYPE_IPV6, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, { FALSE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_CREDENTIALS }, { FALSE, TP_SOCKET_ADDRESS_TYPE_IPV4, TP_SOCKET_ACCESS_CONTROL_PORT }, { TRUE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, { TRUE, TP_SOCKET_ADDRESS_TYPE_IPV4, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, //{ TRUE, TP_SOCKET_ADDRESS_TYPE_IPV6, TP_SOCKET_ACCESS_CONTROL_LOCALHOST }, { TRUE, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_CREDENTIALS }, { TRUE, TP_SOCKET_ADDRESS_TYPE_IPV4, TP_SOCKET_ACCESS_CONTROL_PORT }, { FALSE, (TpSocketAddressType) NUM_TP_SOCKET_ADDRESS_TYPES, (TpSocketAccessControl) NUM_TP_SOCKET_ACCESS_CONTROLS } }; void destroySocketControlList(gpointer data) { g_array_free((GArray *) data, TRUE); } GHashTable *createSupportedSocketTypesHash(TpSocketAddressType addressType, TpSocketAccessControl accessControl) { GHashTable *ret; GArray *tab; ret = g_hash_table_new_full(NULL, NULL, NULL, destroySocketControlList); tab = g_array_sized_new(FALSE, FALSE, sizeof(TpSocketAccessControl), 1); g_array_append_val(tab, accessControl); g_hash_table_insert(ret, GUINT_TO_POINTER(addressType), tab); return ret; } GSocket *createTcpClientGSocket(TpSocketAddressType socketType) { Q_ASSERT(socketType != TP_SOCKET_ADDRESS_TYPE_UNIX); GSocketFamily family = (GSocketFamily) 0; switch (socketType) { case TP_SOCKET_ADDRESS_TYPE_UNIX: family = G_SOCKET_FAMILY_UNIX; break; case TP_SOCKET_ADDRESS_TYPE_IPV4: family = G_SOCKET_FAMILY_IPV4; break; case TP_SOCKET_ADDRESS_TYPE_IPV6: family = G_SOCKET_FAMILY_IPV6; break; default: Q_ASSERT(false); } /* Create socket to connect to the CM */ GError *error = NULL; GSocket *clientSocket = g_socket_new(family, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error); Q_ASSERT(clientSocket != NULL); if (socketType == TP_SOCKET_ADDRESS_TYPE_IPV4 || socketType == TP_SOCKET_ADDRESS_TYPE_IPV6) { /* Bind local address */ GSocketAddress *localAddress; GInetAddress *tmp; gboolean success; tmp = g_inet_address_new_loopback(family); localAddress = g_inet_socket_address_new(tmp, 0); success = g_socket_bind(clientSocket, localAddress, TRUE, &error); g_object_unref(tmp); g_object_unref(localAddress); Q_ASSERT(success); } return clientSocket; } } class TestStreamTubeChan : public Test { Q_OBJECT public: TestStreamTubeChan(QObject *parent = 0) : Test(parent), mConn(0), mChanService(0), mLocalConnectionId(-1), mRemoteConnectionId(-1), mGotLocalConnection(false), mGotRemoteConnection(false), mGotSocketConnection(false), mGotConnectionClosed(false), mOfferFinished(false), mRequiresCredentials(false), mCredentialByte(0) { } protected Q_SLOTS: void onNewLocalConnection(uint connectionId); void onNewRemoteConnection(uint connectionId); void onNewSocketConnection(); void onConnectionClosed(uint connectionId, const QString &errorName, const QString &errorMesssage); void onOfferFinished(Tp::PendingOperation *op); void expectPendingTubeConnectionFinished(Tp::PendingOperation *op); private Q_SLOTS: void initTestCase(); void init(); void testCreation(); void testAcceptTwice(); void testAcceptSuccess(); void testAcceptFail(); void testOfferSuccess(); void testOutgoingConnectionMonitoring(); void cleanup(); void cleanupTestCase(); private: void testCheckRemoteConnectionsCommon(); void createTubeChannel(bool requested, TpSocketAddressType addressType, TpSocketAccessControl accessControl, bool withContact); TestConnHelper *mConn; TpTestsStreamTubeChannel *mChanService; StreamTubeChannelPtr mChan; uint mCurrentContext; uint mLocalConnectionId; uint mRemoteConnectionId; bool mGotLocalConnection; bool mGotRemoteConnection; bool mGotSocketConnection; bool mGotConnectionClosed; bool mOfferFinished; bool mRequiresCredentials; uchar mCredentialByte; QHostAddress mExpectedAddress; uint mExpectedPort; uint mExpectedHandle; QString mExpectedId; }; void TestStreamTubeChan::onNewLocalConnection(uint connectionId) { qDebug() << "Got local connection with id:" << connectionId; mLocalConnectionId = connectionId; mGotLocalConnection = true; QVERIFY(mChan->connections().contains(connectionId)); mLoop->exit(0); } void TestStreamTubeChan::onNewRemoteConnection(uint connectionId) { qDebug() << "Got remote connection with id:" << connectionId; mRemoteConnectionId = connectionId; mGotRemoteConnection = true; QVERIFY(mChan->connections().contains(connectionId)); testCheckRemoteConnectionsCommon(); } void TestStreamTubeChan::onNewSocketConnection() { qDebug() << "Got new socket connection"; mGotSocketConnection = true; mLoop->exit(0); } void TestStreamTubeChan::onConnectionClosed(uint connectionId, const QString &errorName, const QString &errorMesssage) { qDebug() << "Got connetion closed for connection" << connectionId; mGotConnectionClosed = true; QVERIFY(!mChan->connections().contains(connectionId)); if (mChan->isRequested()) { testCheckRemoteConnectionsCommon(); } mLoop->exit(0); } void TestStreamTubeChan::onOfferFinished(Tp::PendingOperation *op) { TEST_VERIFY_OP(op); mOfferFinished = true; mLoop->exit(0); } void TestStreamTubeChan::expectPendingTubeConnectionFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingStreamTubeConnection *pstc = qobject_cast(op); mRequiresCredentials = pstc->requiresCredentials(); mCredentialByte = pstc->credentialByte(); mLoop->exit(0); } void TestStreamTubeChan::createTubeChannel(bool requested, TpSocketAddressType addressType, TpSocketAccessControl accessControl, bool withContact) { mChan.reset(); mLoop->processEvents(); tp_clear_object(&mChanService); /* Create service-side tube channel object */ QString chanPath = QString(QLatin1String("%1/Channel")).arg(mConn->objectPath()); TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandleRepoIface *roomRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_ROOM); TpHandle handle; GType type; if (withContact) { handle = tp_handle_ensure(contactRepo, "bob", NULL, NULL); type = TP_TESTS_TYPE_CONTACT_STREAM_TUBE_CHANNEL; } else { handle = tp_handle_ensure(roomRepo, "#test", NULL, NULL); type = TP_TESTS_TYPE_ROOM_STREAM_TUBE_CHANNEL; } TpHandle alfHandle = tp_handle_ensure(contactRepo, "alf", NULL, NULL); GHashTable *sockets = createSupportedSocketTypesHash(addressType, accessControl); mChanService = TP_TESTS_STREAM_TUBE_CHANNEL(g_object_new( type, "connection", mConn->service(), "handle", handle, "requested", requested, "object-path", chanPath.toLatin1().constData(), "supported-socket-types", sockets, "initiator-handle", alfHandle, NULL)); /* Create client-side tube channel object */ GHashTable *props; g_object_get(mChanService, "channel-properties", &props, NULL); if (requested) { mChan = OutgoingStreamTubeChannel::create(mConn->client(), chanPath, QVariantMap()); } else { mChan = IncomingStreamTubeChannel::create(mConn->client(), chanPath, QVariantMap()); } g_hash_table_unref(props); g_hash_table_unref(sockets); } void TestStreamTubeChan::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("stream-tube-chan"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "example", NULL); QCOMPARE(mConn->connect(), true); } void TestStreamTubeChan::init() { initImpl(); mCurrentContext = -1; mLocalConnectionId = -1; mRemoteConnectionId = -1; mGotLocalConnection = false; mGotRemoteConnection = false; mGotConnectionClosed = false; mGotSocketConnection = false; mOfferFinished = false; mRequiresCredentials = false; mCredentialByte = 0; mExpectedAddress = QHostAddress(); mExpectedPort = -1; mExpectedHandle = -1; mExpectedId = QString(); } void TestStreamTubeChan::testCheckRemoteConnectionsCommon() { OutgoingStreamTubeChannelPtr chan = OutgoingStreamTubeChannelPtr::qObjectCast(mChan); QVERIFY(chan); QCOMPARE(chan->contactsForConnections().isEmpty(), false); QCOMPARE(chan->contactsForConnections().contains(mRemoteConnectionId), true); QCOMPARE(chan->contactsForConnections().value(mRemoteConnectionId)->handle()[0], mExpectedHandle); QCOMPARE(chan->contactsForConnections().value(mRemoteConnectionId)->id(), mExpectedId); if (contexts[mCurrentContext].accessControl == TP_SOCKET_ACCESS_CONTROL_PORT) { // qDebug() << "+++ conn for source addresses" << chan->connectionsForSourceAddresses(); QCOMPARE(chan->connectionsForSourceAddresses().isEmpty(), false); QCOMPARE(chan->connectionsForCredentials().isEmpty(), true); QPair srcAddr(mExpectedAddress, mExpectedPort); QCOMPARE(chan->connectionsForSourceAddresses().contains(srcAddr), true); QCOMPARE(chan->connectionsForSourceAddresses().value(srcAddr), mRemoteConnectionId); } else if (contexts[mCurrentContext].accessControl == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS) { // qDebug() << "+++ conn for credentials" << chan->connectionsForCredentials(); QCOMPARE(chan->connectionsForCredentials().isEmpty(), false); QCOMPARE(chan->connectionsForSourceAddresses().isEmpty(), true); QCOMPARE(chan->connectionsForCredentials().contains(mCredentialByte), true); QCOMPARE(chan->connectionsForCredentials().value(mCredentialByte), mRemoteConnectionId); } mLoop->exit(0); } void TestStreamTubeChan::testCreation() { /* Outgoing tube */ createTubeChannel(true, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, true); QVERIFY(connect(mChan->becomeReady(OutgoingStreamTubeChannel::FeatureCore), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(OutgoingStreamTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(StreamTubeChannel::FeatureConnectionMonitoring), false); QCOMPARE(mChan->state(), TubeChannelStateNotOffered); QCOMPARE(mChan->parameters().isEmpty(), true); QCOMPARE(mChan->service(), QLatin1String("test-service")); QCOMPARE(mChan->supportsIPv4SocketsOnLocalhost(), false); QCOMPARE(mChan->supportsIPv4SocketsWithSpecifiedAddress(), false); QCOMPARE(mChan->supportsIPv6SocketsOnLocalhost(), false); QCOMPARE(mChan->supportsIPv6SocketsWithSpecifiedAddress(), false); QCOMPARE(mChan->supportsUnixSocketsOnLocalhost(), true); QCOMPARE(mChan->supportsUnixSocketsWithCredentials(), false); QCOMPARE(mChan->supportsAbstractUnixSocketsOnLocalhost(), false); QCOMPARE(mChan->supportsAbstractUnixSocketsWithCredentials(), false); QCOMPARE(mChan->connections().isEmpty(), true); QCOMPARE(mChan->addressType(), SocketAddressTypeUnix); QCOMPARE(mChan->ipAddress().first.isNull(), true); QCOMPARE(mChan->localAddress(), QString()); /* incoming tube */ createTubeChannel(false, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); QVERIFY(connect(mChan->becomeReady(IncomingStreamTubeChannel::FeatureCore), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(IncomingStreamTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(StreamTubeChannel::FeatureConnectionMonitoring), false); QCOMPARE(mChan->state(), TubeChannelStateLocalPending); QCOMPARE(mChan->parameters().isEmpty(), false); QCOMPARE(mChan->parameters().size(), 1); QCOMPARE(mChan->parameters().contains(QLatin1String("badger")), true); QCOMPARE(mChan->parameters().value(QLatin1String("badger")), QVariant(42)); QCOMPARE(mChan->service(), QLatin1String("test-service")); QCOMPARE(mChan->supportsIPv4SocketsOnLocalhost(), false); QCOMPARE(mChan->supportsIPv4SocketsWithSpecifiedAddress(), false); QCOMPARE(mChan->supportsIPv6SocketsOnLocalhost(), false); QCOMPARE(mChan->supportsIPv6SocketsWithSpecifiedAddress(), false); QCOMPARE(mChan->supportsUnixSocketsOnLocalhost(), true); QCOMPARE(mChan->supportsUnixSocketsWithCredentials(), false); QCOMPARE(mChan->supportsAbstractUnixSocketsOnLocalhost(), false); QCOMPARE(mChan->supportsAbstractUnixSocketsWithCredentials(), false); QCOMPARE(mChan->connections().isEmpty(), true); QCOMPARE(mChan->addressType(), SocketAddressTypeUnix); QCOMPARE(mChan->ipAddress().first.isNull(), true); QCOMPARE(mChan->localAddress(), QString()); } void TestStreamTubeChan::testAcceptTwice() { /* incoming tube */ createTubeChannel(false, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); QVERIFY(connect(mChan->becomeReady(IncomingStreamTubeChannel::FeatureCore | StreamTubeChannel::FeatureConnectionMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(IncomingStreamTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(StreamTubeChannel::FeatureConnectionMonitoring), true); QCOMPARE(mChan->state(), TubeChannelStateLocalPending); IncomingStreamTubeChannelPtr chan = IncomingStreamTubeChannelPtr::qObjectCast(mChan); QVERIFY(connect(chan->acceptTubeAsUnixSocket(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->state(), TubeChannelStateOpen); /* try to re-accept the tube */ QVERIFY(connect(chan->acceptTubeAsUnixSocket(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->state(), TubeChannelStateOpen); } void TestStreamTubeChan::testAcceptSuccess() { /* incoming tube */ for (int i = 0; contexts[i].addressType != NUM_TP_SOCKET_ADDRESS_TYPES; i++) { /* as we run several tests here, let's init/cleanup properly */ init(); qDebug() << "Testing context:" << i; mCurrentContext = i; createTubeChannel(false, contexts[i].addressType, contexts[i].accessControl, contexts[i].withContact); QVERIFY(connect(mChan->becomeReady(IncomingStreamTubeChannel::FeatureCore | StreamTubeChannel::FeatureConnectionMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(IncomingStreamTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(StreamTubeChannel::FeatureConnectionMonitoring), true); QCOMPARE(mChan->state(), TubeChannelStateLocalPending); mLocalConnectionId = -1; mGotLocalConnection = false; QVERIFY(connect(mChan.data(), SIGNAL(newConnection(uint)), SLOT(onNewLocalConnection(uint)))); bool requiresCredentials = ((contexts[i].accessControl == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS) ? true : false); GSocket *gSocket = 0; QHostAddress addr; quint16 port = 0; IncomingStreamTubeChannelPtr chan = IncomingStreamTubeChannelPtr::qObjectCast(mChan); if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { QVERIFY(connect(chan->acceptTubeAsUnixSocket(requiresCredentials), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectPendingTubeConnectionFinished(Tp::PendingOperation *)))); } else { if (contexts[i].accessControl == TP_SOCKET_ACCESS_CONTROL_PORT) { gSocket = createTcpClientGSocket(contexts[i].addressType); // There is no way to bind a QTcpSocket and using // QAbstractSocket::setSocketDescriptor does not work either, so using glib sockets // for this test. See http://bugreports.qt.nokia.com/browse/QTBUG-121 GSocketAddress *localAddr; localAddr = g_socket_get_local_address(gSocket, NULL); QVERIFY(localAddr != NULL); addr = QHostAddress(QLatin1String(g_inet_address_to_string( g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(localAddr))))); port = g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(localAddr)); g_object_unref(localAddr); } else { addr = QHostAddress::Any; port = 0; } QVERIFY(connect(chan->acceptTubeAsTcpSocket(addr, port), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectPendingTubeConnectionFinished(Tp::PendingOperation *)))); } QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->state(), TubeChannelStateOpen); QCOMPARE(mRequiresCredentials, requiresCredentials); if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { qDebug() << "Connecting to host" << mChan->localAddress(); QLocalSocket *socket = new QLocalSocket(this); socket->connectToServer(mChan->localAddress()); if (requiresCredentials) { qDebug() << "Sending credential byte" << mCredentialByte; socket->write(reinterpret_cast(&mCredentialByte), 1); } QCOMPARE(mLoop->exec(), 0); QCOMPARE(mGotLocalConnection, true); qDebug() << "Connected to host"; delete socket; } else { qDebug().nospace() << "Connecting to host " << mChan->ipAddress().first << ":" << mChan->ipAddress().second; QTcpSocket *socket = 0; if (contexts[i].accessControl == TP_SOCKET_ACCESS_CONTROL_PORT) { GSocketAddress *remoteAddr = (GSocketAddress*) g_inet_socket_address_new( g_inet_address_new_from_string( mChan->ipAddress().first.toString().toLatin1().constData()), mChan->ipAddress().second); g_socket_connect(gSocket, remoteAddr, NULL, NULL); } else { socket = new QTcpSocket(); socket->connectToHost(mChan->ipAddress().first, mChan->ipAddress().second); } QCOMPARE(mLoop->exec(), 0); QCOMPARE(mGotLocalConnection, true); qDebug() << "Connected to host"; if (gSocket) { tp_clear_object(&gSocket); } delete socket; } mGotConnectionClosed = false; QVERIFY(connect(mChan.data(), SIGNAL(connectionClosed(uint,QString,QString)), SLOT(onConnectionClosed(uint,QString,QString)))); tp_tests_stream_tube_channel_last_connection_disconnected(mChanService, TP_ERROR_STR_DISCONNECTED); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mGotConnectionClosed, true); /* as we run several tests here, let's init/cleanup properly */ cleanup(); } } void TestStreamTubeChan::testAcceptFail() { /* incoming tube */ createTubeChannel(false, TP_SOCKET_ADDRESS_TYPE_UNIX, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, false); QVERIFY(connect(mChan->becomeReady(IncomingStreamTubeChannel::FeatureCore | StreamTubeChannel::FeatureConnectionMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(IncomingStreamTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(StreamTubeChannel::FeatureConnectionMonitoring), true); QCOMPARE(mChan->state(), TubeChannelStateLocalPending); /* when accept is called the channel will be closed service side */ tp_tests_stream_tube_channel_set_close_on_accept (mChanService, TRUE); /* calling accept should fail */ IncomingStreamTubeChannelPtr chan = IncomingStreamTubeChannelPtr::qObjectCast(mChan); QVERIFY(connect(chan->acceptTubeAsUnixSocket(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isValid(), false); /* trying to accept again should fail immediately */ QVERIFY(connect(chan->acceptTubeAsUnixSocket(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectFailure(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); } void TestStreamTubeChan::testOfferSuccess() { /* incoming tube */ for (int i = 0; contexts[i].addressType != NUM_TP_SOCKET_ADDRESS_TYPES; i++) { /* as we run several tests here, let's init/cleanup properly */ init(); qDebug() << "Testing context:" << i; mCurrentContext = i; createTubeChannel(true, contexts[i].addressType, contexts[i].accessControl, contexts[i].withContact); QVERIFY(connect(mChan->becomeReady(OutgoingStreamTubeChannel::FeatureCore | StreamTubeChannel::FeatureConnectionMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChan->isReady(OutgoingStreamTubeChannel::FeatureCore), true); QCOMPARE(mChan->isReady(StreamTubeChannel::FeatureConnectionMonitoring), true); QCOMPARE(mChan->state(), TubeChannelStateNotOffered); QCOMPARE(mChan->parameters().isEmpty(), true); mRemoteConnectionId = -1; mGotRemoteConnection = false; QVERIFY(connect(mChan.data(), SIGNAL(newConnection(uint)), SLOT(onNewRemoteConnection(uint)))); bool requiresCredentials = ((contexts[i].accessControl == TP_SOCKET_ACCESS_CONTROL_CREDENTIALS) ? true : false); mExpectedAddress = QHostAddress(); mExpectedPort = -1; mExpectedHandle = -1; mExpectedId = QString(); mOfferFinished = false; mGotSocketConnection = false; QLocalServer *localServer = 0; QTcpServer *tcpServer = 0; OutgoingStreamTubeChannelPtr chan = OutgoingStreamTubeChannelPtr::qObjectCast(mChan); QVariantMap offerParameters; offerParameters.insert(QLatin1String("mushroom"), 44); if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { localServer = new QLocalServer(this); localServer->listen(QLatin1String(tmpnam(NULL))); connect(localServer, SIGNAL(newConnection()), SLOT(onNewSocketConnection())); QVERIFY(connect(chan->offerUnixSocket(localServer, offerParameters, requiresCredentials), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onOfferFinished(Tp::PendingOperation *)))); } else { tcpServer = new QTcpServer(this); tcpServer->listen(QHostAddress::Any, 0); connect(tcpServer, SIGNAL(newConnection()), SLOT(onNewSocketConnection())); QVERIFY(connect(chan->offerTcpSocket(tcpServer, offerParameters), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onOfferFinished(Tp::PendingOperation *)))); } while (mChan->state() != TubeChannelStateRemotePending) { mLoop->processEvents(); } QCOMPARE(mGotSocketConnection, false); // A client now connects to the tube QLocalSocket *localSocket = 0; QTcpSocket *tcpSocket = 0; if (contexts[i].addressType == TP_SOCKET_ADDRESS_TYPE_UNIX) { qDebug() << "Connecting to host" << localServer->fullServerName(); localSocket = new QLocalSocket(this); localSocket->connectToServer(localServer->fullServerName()); } else { qDebug().nospace() << "Connecting to host" << tcpServer->serverAddress() << ":" << tcpServer->serverPort(); tcpSocket = new QTcpSocket(this); tcpSocket->connectToHost(tcpServer->serverAddress(), tcpServer->serverPort()); } QCOMPARE(mGotSocketConnection, false); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mGotSocketConnection, true); if (tcpSocket) { mExpectedAddress = tcpSocket->localAddress(); mExpectedPort = tcpSocket->localPort(); } /* simulate CM when peer connects */ GValue *connParam = 0; mCredentialByte = 0; switch (contexts[i].accessControl) { case TP_SOCKET_ACCESS_CONTROL_LOCALHOST: connParam = tp_g_value_slice_new_static_string(""); break; case TP_SOCKET_ACCESS_CONTROL_CREDENTIALS: { mCredentialByte = g_random_int_range(0, G_MAXUINT8); localSocket->write(reinterpret_cast(&mCredentialByte), 1); connParam = tp_g_value_slice_new_byte(mCredentialByte); } break; case TP_SOCKET_ACCESS_CONTROL_PORT: { connParam = tp_g_value_slice_new_take_boxed( TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4, dbus_g_type_specialized_construct(TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4)); dbus_g_type_struct_set(connParam, 0, tcpSocket->localAddress().toString().toLatin1().constData(), 1, tcpSocket->localPort(), G_MAXUINT); } break; default: Q_ASSERT(false); } TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandle bobHandle = tp_handle_ensure(contactRepo, "bob", NULL, NULL); tp_tests_stream_tube_channel_peer_connected_no_stream(mChanService, connParam, bobHandle); tp_g_value_slice_free(connParam); mExpectedHandle = bobHandle; mExpectedId = QLatin1String("bob"); QCOMPARE(mChan->state(), TubeChannelStateRemotePending); while (!mOfferFinished) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mChan->state(), TubeChannelStateOpen); QCOMPARE(mChan->parameters().isEmpty(), false); QCOMPARE(mChan->parameters().size(), 1); QCOMPARE(mChan->parameters().contains(QLatin1String("mushroom")), true); QCOMPARE(mChan->parameters().value(QLatin1String("mushroom")), QVariant(44)); if (!mGotRemoteConnection) { QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mGotRemoteConnection, true); qDebug() << "Connected to host"; mGotConnectionClosed = false; QVERIFY(connect(mChan.data(), SIGNAL(connectionClosed(uint,QString,QString)), SLOT(onConnectionClosed(uint,QString,QString)))); tp_tests_stream_tube_channel_last_connection_disconnected(mChanService, TP_ERROR_STR_DISCONNECTED); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mGotConnectionClosed, true); /* let the internal OutgoingStreamTubeChannel::onConnectionClosed slot be called before * checking the data for that connection */ mLoop->processEvents(); QCOMPARE(chan->contactsForConnections().isEmpty(), true); QCOMPARE(chan->connectionsForSourceAddresses().isEmpty(), true); QCOMPARE(chan->connectionsForCredentials().isEmpty(), true); delete localServer; delete localSocket; delete tcpServer; delete tcpSocket; /* as we run several tests here, let's init/cleanup properly */ cleanup(); } } void TestStreamTubeChan::testOutgoingConnectionMonitoring() { mCurrentContext = 3; // should point to the room, IPv4, AC port one createTubeChannel(true, TP_SOCKET_ADDRESS_TYPE_IPV4, TP_SOCKET_ACCESS_CONTROL_PORT, false); QVERIFY(connect(mChan->becomeReady(OutgoingStreamTubeChannel::FeatureCore | StreamTubeChannel::FeatureConnectionMonitoring), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(connect(mChan.data(), SIGNAL(newConnection(uint)), SLOT(onNewRemoteConnection(uint)))); QVERIFY(connect(mChan.data(), SIGNAL(connectionClosed(uint,QString,QString)), SLOT(onConnectionClosed(uint,QString,QString)))); OutgoingStreamTubeChannelPtr chan = OutgoingStreamTubeChannelPtr::qObjectCast(mChan); QVERIFY(connect(chan->offerTcpSocket(QHostAddress(QHostAddress::LocalHost), 9), // DISCARD SIGNAL(finished(Tp::PendingOperation *)), SLOT(onOfferFinished(Tp::PendingOperation *)))); while (mChan->state() != TubeChannelStateRemotePending) { mLoop->processEvents(); } /* simulate CM when peer connects */ GValue *connParam = tp_g_value_slice_new_take_boxed( TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4, dbus_g_type_specialized_construct(TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4)); mExpectedAddress.setAddress(QLatin1String("127.0.0.1")); mExpectedPort = 12345; dbus_g_type_struct_set(connParam, 0, mExpectedAddress.toString().toLatin1().constData(), 1, static_cast(mExpectedPort), G_MAXUINT); // Simulate a peer connection from someone we don't have a prebuilt contact for yet, and // immediately drop it TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandle handle = tp_handle_ensure(contactRepo, "YouHaventSeenMeYet", NULL, NULL); mExpectedHandle = handle; mExpectedId = QLatin1String("youhaventseenmeyet"); tp_tests_stream_tube_channel_peer_connected_no_stream(mChanService, connParam, handle); tp_tests_stream_tube_channel_last_connection_disconnected(mChanService, TP_ERROR_STR_DISCONNECTED); tp_g_value_slice_free(connParam); // Test that we get newConnection first and only then connectionClosed, unlike how the code has // been for a long time, queueing newConnection events and emitting connectionClosed directly while (!mOfferFinished || !mGotRemoteConnection) { QVERIFY(!mGotConnectionClosed || !mOfferFinished); QCOMPARE(mLoop->exec(), 0); } QCOMPARE(mChan->connections().size(), 1); // The connectionClosed emission should finally exit the main loop QCOMPARE(mLoop->exec(), 0); QVERIFY(mGotConnectionClosed); QCOMPARE(mChan->connections().size(), 0); } void TestStreamTubeChan::cleanup() { cleanupImpl(); if (mChan && mChan->isValid()) { qDebug() << "waiting for the channel to become invalidated"; QVERIFY(connect(mChan.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), mLoop, SLOT(quit()))); tp_base_channel_close(TP_BASE_CHANNEL(mChanService)); QCOMPARE(mLoop->exec(), 0); } mChan.reset(); if (mChanService != 0) { g_object_unref(mChanService); mChanService = 0; } mLoop->processEvents(); } void TestStreamTubeChan::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestStreamTubeChan) #include "_gen/stream-tube-chan.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/account-channel-dispatcher.cpp0000664000175000017500000013742412470405660022754 0ustar jrjr#include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; using namespace Tp::Client; class ChannelRequestAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ChannelRequest") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QDBusObjectPath Account READ Account) Q_PROPERTY(qulonglong UserActionTime READ UserActionTime) Q_PROPERTY(QString PreferredHandler READ PreferredHandler) Q_PROPERTY(QualifiedPropertyValueMapList Requests READ Requests) Q_PROPERTY(QStringList Interfaces READ Interfaces) Q_PROPERTY(QVariantMap Hints READ Hints) public: ChannelRequestAdaptor(QDBusObjectPath account, qulonglong userActionTime, QString preferredHandler, QualifiedPropertyValueMapList requests, QStringList interfaces, bool shouldFail, bool proceedNoop, QVariantMap hints, QObject *parent) : QDBusAbstractAdaptor(parent), mAccount(account), mUserActionTime(userActionTime), mPreferredHandler(preferredHandler), mRequests(requests), mInterfaces(interfaces), mShouldFail(shouldFail), mProceedNoop(proceedNoop), mHints(hints) { } virtual ~ChannelRequestAdaptor() { } void setChan(const QString &connPath, const QVariantMap &connProps, const QString &chanPath, const QVariantMap &chanProps) { mConnPath = connPath; mConnProps = connProps; mChanPath = chanPath; mChanProps = chanProps; } public: // Properties inline QDBusObjectPath Account() const { return mAccount; } inline qulonglong UserActionTime() const { return mUserActionTime; } inline QString PreferredHandler() const { return mPreferredHandler; } inline QualifiedPropertyValueMapList Requests() const { return mRequests; } inline QStringList Interfaces() const { return mInterfaces; } inline QVariantMap Hints() const { return mHints; } public Q_SLOTS: // Methods void Proceed() { if (mProceedNoop) { return; } if (mShouldFail) { QTimer::singleShot(0, this, SLOT(fail())); } else { QTimer::singleShot(0, this, SLOT(succeed())); } } void Cancel() { Q_EMIT Failed(QLatin1String(TP_QT_ERROR_CANCELLED), QLatin1String("Cancelled")); } Q_SIGNALS: // Signals void Failed(const QString &error, const QString &message); void Succeeded(); void SucceededWithChannel(const QDBusObjectPath &connPath, const QVariantMap &connProps, const QDBusObjectPath &chanPath, const QVariantMap &chanProps); private Q_SLOTS: void fail() { Q_EMIT Failed(QLatin1String(TP_QT_ERROR_NOT_AVAILABLE), QLatin1String("Not available")); } void succeed() { if (!mConnPath.isEmpty() && !mChanPath.isEmpty()) { Q_EMIT SucceededWithChannel(QDBusObjectPath(mConnPath), mConnProps, QDBusObjectPath(mChanPath), mChanProps); } Q_EMIT Succeeded(); } private: QDBusObjectPath mAccount; qulonglong mUserActionTime; QString mPreferredHandler; QualifiedPropertyValueMapList mRequests; QStringList mInterfaces; bool mShouldFail; bool mProceedNoop; QVariantMap mHints; QString mConnPath, mChanPath; QVariantMap mConnProps, mChanProps; }; class ChannelDispatcherAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ChannelDispatcher") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QStringList Interfaces READ Interfaces) Q_PROPERTY(bool SupportsRequestHints READ SupportsRequestHints) public: enum MethodCall { CC = 0, // CreateChannel/WithHints EC, // EnsureChannel/WithHints }; ChannelDispatcherAdaptor(const QDBusConnection &bus, QObject *parent) : QDBusAbstractAdaptor(parent), mBus(bus), mRequests(0), mCurRequest(0), mInvokeHandler(false), mChannelRequestShouldFail(false), mChannelRequestProceedNoop(false) { } virtual ~ChannelDispatcherAdaptor() { } void setChan(const QString &connPath, const QVariantMap &connProps, const QString &chanPath, const QVariantMap &chanProps) { mConnPath = connPath; mConnProps = connProps; mChanPath = chanPath; mChanProps = chanProps; } void clearChan() { mConnPath = QString(); mConnProps.clear(); mChanPath = QString(); mChanProps.clear(); } public: // Properties inline QStringList Interfaces() const { return QStringList(); } inline bool SupportsRequestHints() const { return true; } public Q_SLOTS: // Methods QDBusObjectPath CreateChannel(const QDBusObjectPath& account, const QVariantMap& requestedProperties, qlonglong userActionTime, const QString& preferredHandler) { lastCall = CC; return createChannel(account, requestedProperties, userActionTime, preferredHandler); } QDBusObjectPath EnsureChannel(const QDBusObjectPath& account, const QVariantMap& requestedProperties, qlonglong userActionTime, const QString& preferredHandler) { lastCall = EC; return createChannel(account, requestedProperties, userActionTime, preferredHandler); } QDBusObjectPath CreateChannelWithHints(const QDBusObjectPath &account, const QVariantMap &requestedProperties, qlonglong userActionTime, const QString &preferredHandler, const QVariantMap &hints) { lastCall = CC; return createChannel(account, requestedProperties, userActionTime, preferredHandler, hints); } QDBusObjectPath EnsureChannelWithHints(const QDBusObjectPath &account, const QVariantMap &requestedProperties, qlonglong userActionTime, const QString &preferredHandler, const QVariantMap &hints) { lastCall = EC; return createChannel(account, requestedProperties, userActionTime, preferredHandler, hints); } private: friend class TestAccountChannelDispatcher; QDBusObjectPath createChannel(const QDBusObjectPath &account, const QVariantMap &requestedProperties, qlonglong userActionTime, const QString &preferredHandler, const QVariantMap &hints = QVariantMap()) { QObject *request = new QObject(this); mCurRequest = new ChannelRequestAdaptor( account, userActionTime, preferredHandler, QualifiedPropertyValueMapList(), QStringList(), mChannelRequestShouldFail, mChannelRequestProceedNoop, hints, request); mCurRequest->setChan(mConnPath, mConnProps, mChanPath, mChanProps); mCurRequestPath = QString(QLatin1String("/org/freedesktop/Telepathy/ChannelRequest/_%1")) .arg(mRequests++); mBus.registerService(QLatin1String("org.freedesktop.Telepathy.ChannelDispatcher")); mBus.registerObject(mCurRequestPath, request); mCurPreferredHandler = preferredHandler; if (mInvokeHandler && !mConnPath.isEmpty() && !mChanPath.isEmpty()) { invokeHandler(userActionTime); } return QDBusObjectPath(mCurRequestPath); } void invokeHandler(const qulonglong &userActionTime) { QString channelHandlerPath = QString(QLatin1String("/%1")).arg(mCurPreferredHandler); channelHandlerPath.replace(QLatin1Char('.'), QLatin1Char('/')); Client::ClientHandlerInterface *clientHandlerInterface = new Client::ClientHandlerInterface(mBus, mCurPreferredHandler, channelHandlerPath, this); ChannelDetails channelDetails = { QDBusObjectPath(mChanPath), mChanProps }; ObjectImmutablePropertiesMap channelRequestProperties; QVariantMap currentChannelRequestProperties; currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Account"), QVariant::fromValue(mCurRequest->Account())); currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".UserActionTime"), mCurRequest->UserActionTime()); currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".PreferredHandler"), mCurRequest->PreferredHandler()); currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Requests"), QVariant::fromValue(mCurRequest->Requests())); currentChannelRequestProperties.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Interfaces"), QVariant::fromValue(mCurRequest->Interfaces())); channelRequestProperties[QDBusObjectPath(mCurRequestPath)] = currentChannelRequestProperties; QVariantMap handlerInfo; handlerInfo.insert(QLatin1String("request-properties"), QVariant::fromValue(channelRequestProperties)); clientHandlerInterface->HandleChannels(mCurRequest->Account(), QDBusObjectPath(mConnPath), ChannelDetailsList() << channelDetails, ObjectPathList() << QDBusObjectPath(mCurRequestPath), userActionTime, handlerInfo); } QDBusConnection mBus; uint mRequests; ChannelRequestAdaptor *mCurRequest; QString mCurRequestPath; QString mCurPreferredHandler; bool mInvokeHandler; bool mChannelRequestShouldFail; bool mChannelRequestProceedNoop; QString mConnPath, mChanPath; QVariantMap mConnProps, mChanProps; static MethodCall lastCall; }; ChannelDispatcherAdaptor::MethodCall ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; class TestAccountChannelDispatcher : public Test { Q_OBJECT public: TestAccountChannelDispatcher(QObject *parent = 0) : Test(parent), mChannelDispatcherAdaptor(0), mChannelRequestFinished(false), mChannelRequestFinishedWithError(false) { mHints = ChannelRequestHints(); mHints.setHint(QLatin1String("uk.co.willthompson"), QLatin1String("MomOrDad"), QString::fromLatin1("Mommy")); } protected Q_SLOTS: void onPendingChannelRequestFinished(Tp::PendingOperation *op); void onPendingChannelFinished(Tp::PendingOperation *op); void onChannelHandledAgain(const QDateTime &userActionTime, const Tp::ChannelRequestHints &hints); private Q_SLOTS: void initTestCase(); void init(); void testEnsureTextChat(); void testEnsureTextChatFail(); void testEnsureTextChatCancel(); void testEnsureTextChatroom(); void testEnsureTextChatroomFail(); void testEnsureTextChatroomCancel(); void testEnsureMediaCall(); void testEnsureMediaCallFail(); void testEnsureMediaCallCancel(); void testCreateChannel(); void testCreateChannelFail(); void testCreateChannelCancel(); void testEnsureChannel(); void testEnsureChannelFail(); void testEnsureChannelCancel(); void testCreateFileTransferChannel(); void testCreateFileTransferChannelFail(); void testCreateFileTransferChannelCancel(); void testCreateFileTransferChannelInvalidParameters(); void testCreateAndHandleChannel(); void testCreateAndHandleChannelNotYours(); void testCreateAndHandleChannelFail(); void testCreateAndHandleChannelHandledAgain(); void testCreateAndHandleChannelHandledChannels(); void testCreateAndHandleFileTransferChannel(); void testCreateAndHandleFileTransferChannelFail(); void testCreateAndHandleFileTransferChannelInvalidParameters(); void cleanup(); void cleanupTestCase(); private: void testPCR(PendingChannelRequest *pcr); void testPC(PendingChannel *pc, PendingChannel **pcOut = 0, ChannelPtr *channelOut = 0); QList ourHandlers(); QStringList ourHandledChannels(); void checkHandlerHandledChannels(ClientHandlerInterface *handler, const QStringList &toCompare); AccountManagerPtr mAM; AccountPtr mAccount; ChannelDispatcherAdaptor *mChannelDispatcherAdaptor; TestConnHelper *mConn; ContactPtr mContact; QDateTime mUserActionTime; ChannelRequestPtr mChannelRequest; bool mChannelRequestFinished; bool mChannelRequestFinishedWithError; QString mChannelRequestFinishedErrorName; bool mChannelRequestAndHandleFinished; bool mChannelRequestAndHandleFinishedWithError; QString mChannelRequestAndHandleFinishedErrorName; QDateTime mChannelHandledAgainActionTime; ChannelRequestHints mHints; QString mChanPath; QVariantMap mConnProps, mChanProps; QString mFilePath; }; void TestAccountChannelDispatcher::onPendingChannelRequestFinished( Tp::PendingOperation *op) { mChannelRequestFinished = true; mChannelRequestFinishedWithError = op->isError(); mChannelRequestFinishedErrorName = op->errorName(); mLoop->exit(0); } void TestAccountChannelDispatcher::onPendingChannelFinished( Tp::PendingOperation *op) { mChannelRequestAndHandleFinished = true; mChannelRequestAndHandleFinishedWithError = op->isError(); mChannelRequestAndHandleFinishedErrorName = op->errorName(); mLoop->exit(0); } void TestAccountChannelDispatcher::onChannelHandledAgain(const QDateTime &userActionTime, const Tp::ChannelRequestHints &hints) { mChannelHandledAgainActionTime = userActionTime; mLoop->exit(0); } void TestAccountChannelDispatcher::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("account-channel-dispatcher"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); // Create the CD first, because Accounts try to introspect it QDBusConnection bus = QDBusConnection::sessionBus(); QString channelDispatcherBusName = TP_QT_IFACE_CHANNEL_DISPATCHER; QString channelDispatcherPath = QLatin1String("/org/freedesktop/Telepathy/ChannelDispatcher"); QObject *dispatcher = new QObject(this); mChannelDispatcherAdaptor = new ChannelDispatcherAdaptor(bus, dispatcher); QVERIFY(bus.registerService(channelDispatcherBusName)); QVERIFY(bus.registerObject(channelDispatcherPath, dispatcher)); mAM = AccountManager::create(); QVERIFY(connect(mAM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAM->isReady(), true); QVariantMap parameters; parameters[QLatin1String("account")] = QLatin1String("foobar"); PendingAccount *pacc = mAM->createAccount(QLatin1String("foo"), QLatin1String("bar"), QLatin1String("foobar"), parameters); QVERIFY(connect(pacc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pacc->account()); mAccount = pacc->account(); QVERIFY(connect(mAccount->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAccount->isReady(), true); QCOMPARE(mAccount->supportsRequestHints(), true); QCOMPARE(mAccount->requestsSucceedWithChannel(), true); mConn = new TestConnHelper(this, EXAMPLE_TYPE_ECHO_2_CONNECTION, "account", "me@example.com", "protocol", "contacts", NULL); QCOMPARE(mConn->connect(), true); mContact = mConn->contacts(QStringList() << QLatin1String("foo@bar"))[0]; QVERIFY(mContact); } void TestAccountChannelDispatcher::init() { initImpl(); mChannelRequest.reset(); mChannelRequestFinished = false; mChannelRequestFinishedWithError = false; mChannelRequestFinishedErrorName = QString(); mChannelRequestAndHandleFinished = false; mChannelRequestAndHandleFinishedWithError = false; mChannelRequestAndHandleFinishedErrorName = QString(); mChannelHandledAgainActionTime = QDateTime(); QDateTime mUserActionTime = QDateTime::currentDateTime(); mChanPath.clear(); mChanProps.clear(); mFilePath = QCoreApplication::applicationFilePath(); } void TestAccountChannelDispatcher::testPCR(PendingChannelRequest *pcr) { QVERIFY(connect(pcr, SIGNAL(finished(Tp::PendingOperation *)), SLOT(onPendingChannelRequestFinished(Tp::PendingOperation *)))); mLoop->exec(0); mChannelRequest = pcr->channelRequest(); if (!mChanPath.isEmpty()) { QVERIFY(!mChannelRequest->channel().isNull()); QCOMPARE(mChannelRequest->channel()->connection()->objectPath(), mConn->objectPath()); QCOMPARE(mChannelRequest->channel()->objectPath(), mChanPath); QCOMPARE(mChannelRequest->channel()->immutableProperties(), mChanProps); } else { QVERIFY(mChannelRequest.isNull() || mChannelRequest->channel().isNull()); } if (!mChannelRequest.isNull()) { QVERIFY(connect(mChannelRequest->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); mLoop->exec(0); QCOMPARE(mChannelRequest->userActionTime(), mUserActionTime); QCOMPARE(mChannelRequest->account().data(), mAccount.data()); QVERIFY(mChannelRequest->hints().isValid()); QCOMPARE(mChannelRequest->hints().allHints(), mHints.allHints()); } } void TestAccountChannelDispatcher::testPC(PendingChannel *pc, PendingChannel **pcOut, ChannelPtr *channelOut) { if (pcOut) { *pcOut = pc; } QVERIFY(connect(pc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(onPendingChannelFinished(Tp::PendingOperation *)))); mLoop->exec(0); ChannelPtr channel = pc->channel(); if (channelOut) { *channelOut = channel; } if (mChannelDispatcherAdaptor->mInvokeHandler && !mChanPath.isEmpty()) { QVERIFY(!channel.isNull()); QCOMPARE(channel->connection()->objectPath(), mConn->objectPath()); QCOMPARE(channel->objectPath(), mChanPath); QCOMPARE(channel->immutableProperties(), mChanProps); } else { QVERIFY(channel.isNull()); } } QList TestAccountChannelDispatcher::ourHandlers() { QList handlers; QDBusConnection bus = QDBusConnection::sessionBus(); QStringList registeredNames = bus.interface()->registeredServiceNames(); Q_FOREACH (QString name, registeredNames) { if (!name.startsWith(QLatin1String("org.freedesktop.Telepathy.Client."))) { continue; } if (QDBusConnection::sessionBus().interface()->serviceOwner(name).value() != QDBusConnection::sessionBus().baseService()) { continue; } QString path = QLatin1Char('/') + name; path.replace(QLatin1Char('.'), QLatin1Char('/')); ClientInterface client(name, path); QStringList ifaces; if (!waitForProperty(client.requestPropertyInterfaces(), &ifaces)) { continue; } if (!ifaces.contains(TP_QT_IFACE_CLIENT_HANDLER)) { continue; } ClientHandlerInterface *handler = new ClientHandlerInterface(name, path, this); handlers.append(handler); } return handlers; } QStringList TestAccountChannelDispatcher::ourHandledChannels() { ObjectPathList handledChannels; QDBusConnection bus = QDBusConnection::sessionBus(); QStringList registeredNames = bus.interface()->registeredServiceNames(); Q_FOREACH (QString name, registeredNames) { if (!name.startsWith(QLatin1String("org.freedesktop.Telepathy.Client."))) { continue; } if (QDBusConnection::sessionBus().interface()->serviceOwner(name).value() != QDBusConnection::sessionBus().baseService()) { continue; } QString path = QLatin1Char('/') + name; path.replace(QLatin1Char('.'), QLatin1Char('/')); ClientInterface client(name, path); QStringList ifaces; if (!waitForProperty(client.requestPropertyInterfaces(), &ifaces)) { continue; } if (!ifaces.contains(TP_QT_IFACE_CLIENT_HANDLER)) { continue; } ClientHandlerInterface *handler = new ClientHandlerInterface(bus, name, path, this); handledChannels.clear(); if (waitForProperty(handler->requestPropertyHandledChannels(), &handledChannels)) { break; } } QStringList ret; Q_FOREACH (const QDBusObjectPath &objectPath, handledChannels) { ret << objectPath.path(); } return ret; } void TestAccountChannelDispatcher::checkHandlerHandledChannels(ClientHandlerInterface *handler, const QStringList &toCompare) { ObjectPathList handledChannels; QVERIFY(waitForProperty(handler->requestPropertyHandledChannels(), &handledChannels)); QStringList sortedHandledChannels; Q_FOREACH (const QDBusObjectPath &objectPath, handledChannels) { sortedHandledChannels << objectPath.path(); } sortedHandledChannels.sort(); QCOMPARE(sortedHandledChannels, toCompare); } #define TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(method_name, shouldFail, proceedNoop, expectedError) \ { \ ChannelRequestHints savedHints = mHints; \ TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_EXTENDED(method_name, QLatin1String("foo@bar"), \ ChannelRequestHints(), shouldFail, proceedNoop, expectedError) \ TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_EXTENDED(method_name, QLatin1String("foo@bar"), \ savedHints, shouldFail, proceedNoop, expectedError) \ mHints = savedHints; \ } #define TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(method_name, shouldFail, proceedNoop, expectedError) \ { \ ChannelRequestHints savedHints = mHints; \ TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_EXTENDED(method_name, mContact, \ ChannelRequestHints(), shouldFail, proceedNoop, expectedError) \ TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_EXTENDED(method_name, mContact, \ savedHints, shouldFail, proceedNoop, expectedError) \ mHints = savedHints; \ } #define TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_EXTENDED(method_name, contact, hints, shouldFail, proceedNoop, expectedError) \ { \ mHints = hints; \ mChannelDispatcherAdaptor->mInvokeHandler = false; \ mChannelDispatcherAdaptor->mChannelRequestShouldFail = shouldFail; \ mChannelDispatcherAdaptor->mChannelRequestProceedNoop = proceedNoop; \ if (!mChanPath.isEmpty()) { \ mChannelDispatcherAdaptor->setChan(mConn->objectPath(), mConnProps, mChanPath, mChanProps); \ } else { \ mChannelDispatcherAdaptor->clearChan(); \ } \ PendingChannelRequest *pcr; \ if (mHints.isValid()) { \ pcr = mAccount->method_name(contact, mUserActionTime, QString(), mHints); \ } else { \ pcr = mAccount->method_name(contact, mUserActionTime, QString()); \ } \ if (shouldFail && proceedNoop) { \ pcr->cancel(); \ } \ testPCR(pcr); \ QCOMPARE(mChannelRequestFinishedWithError, shouldFail); \ if (shouldFail) {\ QCOMPARE(mChannelRequestFinishedErrorName, QString(QLatin1String(expectedError))); \ } \ } #define TEST_CREATE_ENSURE_CHANNEL(method_name, shouldFail, proceedNoop, expectedError) \ { \ ChannelRequestHints savedHints = mHints; \ TEST_CREATE_ENSURE_CHANNEL_EXTENDED(method_name, \ ChannelRequestHints(), shouldFail, proceedNoop, expectedError) \ TEST_CREATE_ENSURE_CHANNEL_EXTENDED(method_name, \ savedHints, shouldFail, proceedNoop, expectedError) \ mHints = savedHints; \ } #define TEST_CREATE_ENSURE_CHANNEL_EXTENDED(method_name, hints, shouldFail, proceedNoop, expectedError) \ { \ mHints = hints; \ QVariantMap request; \ request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), \ TP_QT_IFACE_CHANNEL_TYPE_TEXT); \ request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), \ (uint) Tp::HandleTypeContact); \ request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), \ QLatin1String("foo@bar")); \ mChannelDispatcherAdaptor->mInvokeHandler = false; \ mChannelDispatcherAdaptor->mChannelRequestShouldFail = shouldFail; \ mChannelDispatcherAdaptor->mChannelRequestProceedNoop = proceedNoop; \ if (!mChanPath.isEmpty()) { \ mChannelDispatcherAdaptor->setChan(mConn->objectPath(), mConnProps, mChanPath, mChanProps); \ } else { \ mChannelDispatcherAdaptor->clearChan(); \ } \ PendingChannelRequest *pcr; \ if (mHints.isValid()) { \ pcr = mAccount->method_name(request, mUserActionTime, QString(), mHints); \ } else { \ pcr = mAccount->method_name(request, mUserActionTime, QString()); \ } \ if (shouldFail && proceedNoop) { \ pcr->cancel(); \ } \ testPCR(pcr); \ QCOMPARE(mChannelRequestFinishedWithError, shouldFail); \ if (shouldFail) {\ QCOMPARE(mChannelRequestFinishedErrorName, QString(QLatin1String(expectedError))); \ } \ } void TestAccountChannelDispatcher::testEnsureTextChat() { TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureTextChat, false, false, ""); TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(ensureTextChat, false, false, ""); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureTextChatFail() { TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureTextChat, true, false, TP_QT_ERROR_NOT_AVAILABLE); TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(ensureTextChat, true, false, TP_QT_ERROR_NOT_AVAILABLE); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureTextChatCancel() { TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureTextChat, true, true, TP_QT_ERROR_CANCELLED); TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(ensureTextChat, true, true, TP_QT_ERROR_CANCELLED); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureTextChatroom() { TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureTextChatroom, false, false, ""); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureTextChatroomFail() { TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureTextChatroom, true, false, TP_QT_ERROR_NOT_AVAILABLE); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureTextChatroomCancel() { TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureTextChatroom, true, true, TP_QT_ERROR_CANCELLED); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureMediaCall() { mChanPath = mConn->objectPath() + QLatin1String("/channel"); mChanProps = ChannelClassSpec::streamedMediaCall().allProperties(); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureStreamedMediaCall, false, false, ""); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(ensureStreamedMediaCall, false, false, ""); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureStreamedMediaAudioCall, false, false, ""); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(ensureStreamedMediaAudioCall, false, false, ""); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureMediaCallFail() { ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureStreamedMediaCall, true, false, TP_QT_ERROR_NOT_AVAILABLE); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(ensureStreamedMediaCall, true, false, TP_QT_ERROR_NOT_AVAILABLE); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureStreamedMediaAudioCall, true, false, TP_QT_ERROR_NOT_AVAILABLE); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(ensureStreamedMediaAudioCall, true, false, TP_QT_ERROR_NOT_AVAILABLE); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureMediaCallCancel() { ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureStreamedMediaCall, true, true, TP_QT_ERROR_CANCELLED); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(ensureStreamedMediaCall, true, true, TP_QT_ERROR_CANCELLED); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC(ensureStreamedMediaAudioCall, true, true, TP_QT_ERROR_CANCELLED); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); ChannelDispatcherAdaptor::lastCall = (ChannelDispatcherAdaptor::MethodCall) -1; TEST_CREATE_ENSURE_CHANNEL_SPECIFIC_WITH_CONTACT(ensureStreamedMediaAudioCall, true, true, TP_QT_ERROR_CANCELLED); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } #define TEST_CREATE_FILE_TRANSFER_CHANNEL(shouldFail, proceedNoop, invalidProps, expectedError) \ { \ ChannelRequestHints savedHints = mHints; \ TEST_CREATE_FILE_TRANSFER_CHANNEL_EXTENDED(QLatin1String("foo@bar"), \ ChannelRequestHints(), shouldFail, proceedNoop, invalidProps, expectedError) \ TEST_CREATE_FILE_TRANSFER_CHANNEL_EXTENDED(QLatin1String("foo@bar"), \ savedHints, shouldFail, proceedNoop, invalidProps, expectedError) \ TEST_CREATE_FILE_TRANSFER_CHANNEL_EXTENDED(mContact, \ ChannelRequestHints(), shouldFail, proceedNoop, invalidProps, expectedError) \ TEST_CREATE_FILE_TRANSFER_CHANNEL_EXTENDED(mContact, \ savedHints, shouldFail, proceedNoop, invalidProps, expectedError) \ mHints = savedHints; \ } #define TEST_CREATE_FILE_TRANSFER_CHANNEL_EXTENDED(contact, hints, shouldFail, proceedNoop, invalidProps, expectedError) \ { \ mHints = hints; \ mChannelDispatcherAdaptor->mInvokeHandler = false; \ mChannelDispatcherAdaptor->mChannelRequestShouldFail = shouldFail; \ mChannelDispatcherAdaptor->mChannelRequestProceedNoop = proceedNoop; \ if (!mChanPath.isEmpty()) { \ mChannelDispatcherAdaptor->setChan(mConn->objectPath(), mConnProps, mChanPath, mChanProps); \ } else { \ mChannelDispatcherAdaptor->clearChan(); \ } \ \ PendingChannelRequest *pcr; \ FileTransferChannelCreationProperties ftprops; \ if (!invalidProps) { \ QFileInfo fileInfo(mFilePath); \ ftprops = FileTransferChannelCreationProperties(fileInfo.fileName(), \ QLatin1String("application/octet-stream"), fileInfo.size()); \ } \ \ if (mHints.isValid()) { \ pcr = mAccount->createFileTransfer(contact, \ ftprops, mUserActionTime, QString(), mHints); \ } else { \ pcr = mAccount->createFileTransfer(contact, \ ftprops, mUserActionTime, QString()); \ } \ \ if (shouldFail && proceedNoop) { \ pcr->cancel(); \ } \ testPCR(pcr); \ QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::CC); \ QCOMPARE(mChannelRequestFinishedWithError, shouldFail); \ if (shouldFail) {\ QCOMPARE(mChannelRequestFinishedErrorName, QString(QLatin1String(expectedError))); \ } \ } void TestAccountChannelDispatcher::testCreateFileTransferChannel() { mChanPath.clear(); mChanProps = ChannelClassSpec::outgoingFileTransfer().allProperties(); TEST_CREATE_FILE_TRANSFER_CHANNEL(false, false, false, ""); } void TestAccountChannelDispatcher::testCreateFileTransferChannelFail() { TEST_CREATE_FILE_TRANSFER_CHANNEL(true, false, false, TP_QT_ERROR_NOT_AVAILABLE); } void TestAccountChannelDispatcher::testCreateFileTransferChannelCancel() { TEST_CREATE_FILE_TRANSFER_CHANNEL(true, true, false, TP_QT_ERROR_CANCELLED); } void TestAccountChannelDispatcher::testCreateFileTransferChannelInvalidParameters() { TEST_CREATE_FILE_TRANSFER_CHANNEL(true, false, true, TP_QT_ERROR_INVALID_ARGUMENT); } void TestAccountChannelDispatcher::testCreateChannel() { TEST_CREATE_ENSURE_CHANNEL(createChannel, false, false, ""); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::CC); } void TestAccountChannelDispatcher::testCreateChannelFail() { TEST_CREATE_ENSURE_CHANNEL(createChannel, true, false, TP_QT_ERROR_NOT_AVAILABLE); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::CC); } void TestAccountChannelDispatcher::testCreateChannelCancel() { TEST_CREATE_ENSURE_CHANNEL(createChannel, true, true, TP_QT_ERROR_CANCELLED); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::CC); } void TestAccountChannelDispatcher::testEnsureChannel() { TEST_CREATE_ENSURE_CHANNEL(ensureChannel, false, false, ""); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureChannelFail() { TEST_CREATE_ENSURE_CHANNEL(ensureChannel, true, false, TP_QT_ERROR_NOT_AVAILABLE); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testEnsureChannelCancel() { TEST_CREATE_ENSURE_CHANNEL(ensureChannel, true, true, TP_QT_ERROR_CANCELLED); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } #define TEST_CREATE_ENSURE_AND_HANDLE_CHANNEL(method_name, channelRequestShouldFail, shouldFail, invokeHandler, expectedError, channelOut, pcOut) \ { \ QVariantMap request; \ request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), \ TP_QT_IFACE_CHANNEL_TYPE_TEXT); \ request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), \ (uint) Tp::HandleTypeContact); \ request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), \ QLatin1String("foo@bar")); \ mChannelDispatcherAdaptor->mInvokeHandler = invokeHandler; \ mChannelDispatcherAdaptor->mChannelRequestShouldFail = channelRequestShouldFail; \ mChannelDispatcherAdaptor->mChannelRequestProceedNoop = false; \ if (!mChanPath.isEmpty()) { \ mChannelDispatcherAdaptor->setChan(mConn->objectPath(), mConnProps, mChanPath, mChanProps); \ } else { \ mChannelDispatcherAdaptor->clearChan(); \ } \ PendingChannel *pc = mAccount->method_name(request, mUserActionTime); \ testPC(pc, pcOut, channelOut); \ QCOMPARE(mChannelRequestAndHandleFinishedWithError, shouldFail); \ if (shouldFail) {\ QCOMPARE(mChannelRequestAndHandleFinishedErrorName, QString(QLatin1String(expectedError))); \ } \ } void TestAccountChannelDispatcher::testCreateAndHandleChannel() { mChanPath = mConn->objectPath() + QLatin1String("/channel"); mChanProps = ChannelClassSpec::textChat().allProperties(); TEST_CREATE_ENSURE_AND_HANDLE_CHANNEL(createAndHandleChannel, false, false, true, "", 0, 0); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::CC); } void TestAccountChannelDispatcher::testCreateAndHandleChannelNotYours() { TEST_CREATE_ENSURE_AND_HANDLE_CHANNEL(ensureAndHandleChannel, false, true, false, TP_QT_ERROR_NOT_YOURS, 0, 0); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::EC); } void TestAccountChannelDispatcher::testCreateAndHandleChannelFail() { TEST_CREATE_ENSURE_AND_HANDLE_CHANNEL(createAndHandleChannel, true, true, false, TP_QT_ERROR_NOT_AVAILABLE, 0, 0); QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::CC); } void TestAccountChannelDispatcher::testCreateAndHandleChannelHandledAgain() { // create a Channel by magic, rather than doing D-Bus round-trips for it TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); guint handle = tp_handle_ensure(contactRepo, "someone@localhost", 0, 0); mChanPath = mConn->objectPath() + QLatin1String("/TextChannel"); QByteArray chanPath(mChanPath.toLatin1()); ExampleEcho2Channel *textChanService = EXAMPLE_ECHO_2_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_2_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", handle, NULL)); PendingChannel *pcOut = 0; TEST_CREATE_ENSURE_AND_HANDLE_CHANNEL(createAndHandleChannel, false, false, true, "", 0, &pcOut); HandledChannelNotifier *notifier = pcOut->handledChannelNotifier(); connect(notifier, SIGNAL(handledAgain(QDateTime,Tp::ChannelRequestHints)), SLOT(onChannelHandledAgain(QDateTime,Tp::ChannelRequestHints))); QDateTime timestamp(QDate::currentDate()); mChannelDispatcherAdaptor->invokeHandler(timestamp.toTime_t()); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mChannelHandledAgainActionTime, timestamp); if (textChanService != 0) { g_object_unref(textChanService); textChanService = 0; } } void TestAccountChannelDispatcher::testCreateAndHandleChannelHandledChannels() { mChanPath = mConn->objectPath() + QLatin1String("/channel"); mChanProps = ChannelClassSpec::textChat().allProperties(); QVERIFY(ourHandledChannels().isEmpty()); QVERIFY(ourHandlers().isEmpty()); ChannelPtr channel; TEST_CREATE_ENSURE_AND_HANDLE_CHANNEL(createAndHandleChannel, false, false, true, "", &channel, 0); // check that the channel appears in the HandledChannels property of the first handler QVERIFY(!ourHandledChannels().isEmpty()); QCOMPARE(ourHandledChannels().size(), 1); QVERIFY(ourHandledChannels().contains(mChanPath)); QVERIFY(!ourHandlers().isEmpty()); QCOMPARE(ourHandlers().size(), 1); channel.reset(); // reseting the channel should unregister the handler while (!ourHandlers().isEmpty()) { mLoop->processEvents(); } QVERIFY(ourHandledChannels().isEmpty()); ChannelPtr channel1; TEST_CREATE_ENSURE_AND_HANDLE_CHANNEL(createAndHandleChannel, false, false, true, "", &channel1, 0); // check that the channel appears in the HandledChannels property of the first handler QVERIFY(!ourHandledChannels().isEmpty()); QCOMPARE(ourHandledChannels().size(), 1); QVERIFY(ourHandledChannels().contains(mChanPath)); QVERIFY(!ourHandlers().isEmpty()); QCOMPARE(ourHandlers().size(), 1); mChanPath = mConn->objectPath() + QLatin1String("/channelother"); mChanProps = ChannelClassSpec::textChat().allProperties(); ChannelPtr channel2; TEST_CREATE_ENSURE_AND_HANDLE_CHANNEL(createAndHandleChannel, false, false, true, "", &channel2, 0); // check that the channel appears in the HandledChannels property of some handler QVERIFY(!ourHandledChannels().isEmpty()); QCOMPARE(ourHandledChannels().size(), 2); QVERIFY(ourHandledChannels().contains(mChanPath)); QVERIFY(!ourHandlers().isEmpty()); // only one handler will stay alive to properly report HandledChannels QCOMPARE(ourHandlers().size(), 1); QStringList sortedOurHandledChannels = ourHandledChannels(); sortedOurHandledChannels.sort(); Q_FOREACH (ClientHandlerInterface *handler, ourHandlers()) { checkHandlerHandledChannels(handler, sortedOurHandledChannels); } channel1.reset(); while (ourHandledChannels().size() > 1) { mLoop->processEvents(); } QVERIFY(!ourHandledChannels().isEmpty()); QCOMPARE(ourHandledChannels().size(), 1); QVERIFY(ourHandledChannels().contains(mChanPath)); channel2.reset(); while (!ourHandlers().isEmpty()) { mLoop->processEvents(); } QVERIFY(ourHandledChannels().isEmpty()); } #define TEST_CREATE_AND_HANDLE_FILE_TRANSFER_CHANNEL(channelRequestShouldFail, shouldFail, \ invalidProps, invokeHandler, expectedError, channelOut, pcOut) \ TEST_CREATE_AND_HANDLE_FILE_TRANSFER_CHANNEL_EXTENDED(QLatin1String("foo@bar"), \ channelRequestShouldFail, shouldFail, invalidProps, invokeHandler, \ expectedError, channelOut, pcOut) \ TEST_CREATE_AND_HANDLE_FILE_TRANSFER_CHANNEL_EXTENDED(mContact, \ channelRequestShouldFail, shouldFail, invalidProps, invokeHandler, \ expectedError, channelOut, pcOut) #define TEST_CREATE_AND_HANDLE_FILE_TRANSFER_CHANNEL_EXTENDED(contact, channelRequestShouldFail, \ shouldFail, invalidProps, invokeHandler, expectedError, channelOut, pcOut) \ { \ mChannelDispatcherAdaptor->mInvokeHandler = invokeHandler; \ mChannelDispatcherAdaptor->mChannelRequestShouldFail = channelRequestShouldFail; \ mChannelDispatcherAdaptor->mChannelRequestProceedNoop = false; \ if (!mChanPath.isEmpty()) { \ mChannelDispatcherAdaptor->setChan(mConn->objectPath(), mConnProps, mChanPath, mChanProps); \ } else { \ mChannelDispatcherAdaptor->clearChan(); \ } \ PendingChannel *pc; \ if (!invalidProps) { \ QFileInfo fileInfo(mFilePath); \ FileTransferChannelCreationProperties ftprops(fileInfo.fileName(), \ QLatin1String("application/octet-stream"), fileInfo.size()); \ pc = mAccount->createAndHandleFileTransfer(contact, \ ftprops, mUserActionTime); \ } else { \ FileTransferChannelCreationProperties ftprops; \ pc = mAccount->createAndHandleFileTransfer(contact, \ ftprops, mUserActionTime); \ } \ testPC(pc, pcOut, channelOut); \ QCOMPARE(ChannelDispatcherAdaptor::lastCall, ChannelDispatcherAdaptor::CC); \ QCOMPARE(mChannelRequestAndHandleFinishedWithError, shouldFail); \ if (shouldFail) { \ QCOMPARE(mChannelRequestAndHandleFinishedErrorName, QString(QLatin1String(expectedError))); \ } \ } void TestAccountChannelDispatcher::testCreateAndHandleFileTransferChannel() { mChanPath = mConn->objectPath() + QLatin1String("/channel"); mChanProps = ChannelClassSpec::incomingFileTransfer().allProperties(); TEST_CREATE_AND_HANDLE_FILE_TRANSFER_CHANNEL(false, false, false, true, "", 0, 0); } void TestAccountChannelDispatcher::testCreateAndHandleFileTransferChannelFail() { TEST_CREATE_AND_HANDLE_FILE_TRANSFER_CHANNEL(true, true, false, true, TP_QT_ERROR_NOT_AVAILABLE, 0, 0); } void TestAccountChannelDispatcher::testCreateAndHandleFileTransferChannelInvalidParameters() { TEST_CREATE_AND_HANDLE_FILE_TRANSFER_CHANNEL(true, true, true, true, TP_QT_ERROR_INVALID_ARGUMENT, 0, 0); } void TestAccountChannelDispatcher::cleanup() { cleanupImpl(); } void TestAccountChannelDispatcher::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestAccountChannelDispatcher) #include "_gen/account-channel-dispatcher.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/stream-tube-handlers.cpp0000664000175000017500000022233112470405660021604 0ustar jrjr#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; using namespace Tp::Client; namespace { class ChannelRequestAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.ChannelRequest") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QDBusObjectPath Account READ Account) Q_PROPERTY(qulonglong UserActionTime READ UserActionTime) Q_PROPERTY(QString PreferredHandler READ PreferredHandler) Q_PROPERTY(QualifiedPropertyValueMapList Requests READ Requests) Q_PROPERTY(QStringList Interfaces READ Interfaces) Q_PROPERTY(QVariantMap Hints READ Hints) public: ChannelRequestAdaptor(QDBusObjectPath account, qulonglong userActionTime, QString preferredHandler, QualifiedPropertyValueMapList requests, QStringList interfaces, bool shouldFail, bool proceedNoop, QVariantMap hints, QObject *parent) : QDBusAbstractAdaptor(parent), mAccount(account), mUserActionTime(userActionTime), mPreferredHandler(preferredHandler), mRequests(requests), mInterfaces(interfaces), mShouldFail(shouldFail), mProceedNoop(proceedNoop), mHints(hints) { } virtual ~ChannelRequestAdaptor() { } void setChan(const QString &connPath, const QVariantMap &connProps, const QString &chanPath, const QVariantMap &chanProps) { mConnPath = connPath; mConnProps = connProps; mChanPath = chanPath; mChanProps = chanProps; } public: // Properties inline QDBusObjectPath Account() const { return mAccount; } inline qulonglong UserActionTime() const { return mUserActionTime; } inline QString PreferredHandler() const { return mPreferredHandler; } inline QualifiedPropertyValueMapList Requests() const { return mRequests; } inline QStringList Interfaces() const { return mInterfaces; } inline QVariantMap Hints() const { return mHints; } public Q_SLOTS: // Methods void Proceed() { if (mProceedNoop) { return; } if (mShouldFail) { QTimer::singleShot(0, this, SLOT(fail())); } else { QTimer::singleShot(0, this, SLOT(succeed())); } } void Cancel() { Q_EMIT Failed(QLatin1String(TP_QT_ERROR_CANCELLED), QLatin1String("Cancelled")); } Q_SIGNALS: // Signals void Failed(const QString &error, const QString &message); void Succeeded(); void SucceededWithChannel(const QDBusObjectPath &connPath, const QVariantMap &connProps, const QDBusObjectPath &chanPath, const QVariantMap &chanProps); private Q_SLOTS: void fail() { Q_EMIT Failed(QLatin1String(TP_QT_ERROR_NOT_AVAILABLE), QLatin1String("Not available")); } void succeed() { if (!mConnPath.isEmpty() && !mChanPath.isEmpty()) { Q_EMIT SucceededWithChannel(QDBusObjectPath(mConnPath), mConnProps, QDBusObjectPath(mChanPath), mChanProps); } Q_EMIT Succeeded(); } private: QDBusObjectPath mAccount; qulonglong mUserActionTime; QString mPreferredHandler; QualifiedPropertyValueMapList mRequests; QStringList mInterfaces; bool mShouldFail; bool mProceedNoop; QVariantMap mHints; QString mConnPath, mChanPath; QVariantMap mConnProps, mChanProps; }; void destroySocketControlList(gpointer data) { g_array_free(reinterpret_cast(data), TRUE); } GHashTable *createSupportedSocketTypesHash(bool supportMonitoring, bool unixOnly) { GHashTable *ret; GArray *tab; TpSocketAccessControl ac; ret = g_hash_table_new_full(NULL, NULL, NULL, destroySocketControlList); // Named UNIX tab = g_array_sized_new(FALSE, FALSE, sizeof(TpSocketAccessControl), 1); ac = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; g_array_append_val(tab, ac); if (supportMonitoring) { ac = TP_SOCKET_ACCESS_CONTROL_CREDENTIALS; g_array_append_val(tab, ac); } g_hash_table_insert(ret, GUINT_TO_POINTER(TP_SOCKET_ADDRESS_TYPE_UNIX), tab); // Abstract UNIX tab = g_array_sized_new(FALSE, FALSE, sizeof(TpSocketAccessControl), 1); ac = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; g_array_append_val(tab, ac); if (supportMonitoring) { ac = TP_SOCKET_ACCESS_CONTROL_CREDENTIALS; g_array_append_val(tab, ac); } g_hash_table_insert(ret, GUINT_TO_POINTER(TP_SOCKET_ADDRESS_TYPE_ABSTRACT_UNIX), tab); if (unixOnly) { return ret; } // IPv4 tab = g_array_sized_new(FALSE, FALSE, sizeof(TpSocketAccessControl), 1); ac = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; g_array_append_val(tab, ac); if (supportMonitoring) { ac = TP_SOCKET_ACCESS_CONTROL_PORT; g_array_append_val(tab, ac); } g_hash_table_insert(ret, GUINT_TO_POINTER(TP_SOCKET_ADDRESS_TYPE_IPV4), tab); // IPv6 tab = g_array_sized_new(FALSE, FALSE, sizeof(TpSocketAccessControl), 1); ac = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; g_array_append_val(tab, ac); if (supportMonitoring) { ac = TP_SOCKET_ACCESS_CONTROL_PORT; g_array_append_val(tab, ac); } g_hash_table_insert(ret, GUINT_TO_POINTER(TP_SOCKET_ADDRESS_TYPE_IPV6), tab); return ret; } } class TestStreamTubeHandlers : public Test { Q_OBJECT public: TestStreamTubeHandlers(QObject *parent = 0) : Test(parent) { } protected Q_SLOTS: void onTubeRequested(const Tp::AccountPtr &, const Tp::OutgoingStreamTubeChannelPtr &, const QDateTime &, const Tp::ChannelRequestHints &); void onServerTubeClosed(const Tp::AccountPtr &, const Tp::OutgoingStreamTubeChannelPtr &, const QString &, const QString &); void onNewServerConnection(const QHostAddress &, quint16, const Tp::AccountPtr &, const Tp::ContactPtr &, const Tp::OutgoingStreamTubeChannelPtr &); void onServerConnectionClosed(const QHostAddress &, quint16, const Tp::AccountPtr &, const Tp::ContactPtr &, const QString &, const QString &, const Tp::OutgoingStreamTubeChannelPtr &); void onTubeOffered(const Tp::AccountPtr &, const Tp::IncomingStreamTubeChannelPtr &); void onClientTubeClosed(const Tp::AccountPtr &, const Tp::IncomingStreamTubeChannelPtr &, const QString &, const QString &); void onClientAcceptedAsTcp(const QHostAddress &, quint16, const QHostAddress &, quint16, const Tp::AccountPtr &, const Tp::IncomingStreamTubeChannelPtr &); void onClientAcceptedAsUnix(const QString &, bool reqsCreds, uchar credByte, const Tp::AccountPtr &, const Tp::IncomingStreamTubeChannelPtr &); void onNewClientConnection(const Tp::AccountPtr &, const Tp::IncomingStreamTubeChannelPtr &, uint connectionId); void onClientConnectionClosed(const Tp::AccountPtr &, const Tp::IncomingStreamTubeChannelPtr &, uint, const QString &, const QString &); private Q_SLOTS: void initTestCase(); void init(); void testRegistration(); void testBasicTcpExport(); void testFailedExport(); void testServerConnMonitoring(); void testSSTHErrorPaths(); void testClientBasicTcp(); void testClientTcpGeneratorIgnore(); void testClientTcpUnsupported(); void testClientBasicUnix(); void testClientUnixCredsIgnore(); // the unix AF unsupported codepaths are the same, so no need to test separately void testClientConnMonitoring(); void cleanup(); void cleanupTestCase(); private: QMap ourHandlers(); QPair createTubeChannel(bool requested, HandleType type, bool supportMonitoring, bool unixOnly = false); AccountManagerPtr mAM; AccountPtr mAcc; TestConnHelper *mConn; QList mChanServices; OutgoingStreamTubeChannelPtr mRequestedTube; QDateTime mRequestTime; ChannelRequestHints mRequestHints; OutgoingStreamTubeChannelPtr mServerClosedTube; QString mServerCloseError, mServerCloseMessage; QHostAddress mNewServerConnectionAddress, mClosedServerConnectionAddress; quint16 mNewServerConnectionPort, mClosedServerConnectionPort; ContactPtr mNewServerConnectionContact, mClosedServerConnectionContact; OutgoingStreamTubeChannelPtr mNewServerConnectionTube, mServerConnectionCloseTube; QString mServerConnectionCloseError, mServerConnectionCloseMessage; IncomingStreamTubeChannelPtr mOfferedTube; IncomingStreamTubeChannelPtr mClientClosedTube; QString mClientCloseError, mClientCloseMessage; QHostAddress mClientTcpAcceptAddr, mClientTcpAcceptSrcAddr; quint16 mClientTcpAcceptPort, mClientTcpAcceptSrcPort; IncomingStreamTubeChannelPtr mClientTcpAcceptTube; QString mClientUnixAcceptAddr; bool mClientUnixReqsCreds; IncomingStreamTubeChannelPtr mClientUnixAcceptTube; IncomingStreamTubeChannelPtr mNewClientConnectionTube, mClosedClientConnectionTube; uint mNewClientConnectionId, mClosedClientConnectionId; QString mClientConnectionCloseError, mClientConnectionCloseMessage; }; QPair TestStreamTubeHandlers::createTubeChannel(bool requested, HandleType handleType, bool supportMonitoring, bool unixOnly) { mLoop->processEvents(); /* Create service-side tube channel object */ QString chanPath = QString(QLatin1String("%1/Channel%2%3%4")) .arg(mConn->objectPath()) .arg(requested) .arg(static_cast(handleType)) .arg(supportMonitoring); QVariantMap chanProps; chanProps.insert(TP_QT_IFACE_CHANNEL + QString::fromLatin1(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE); chanProps.insert(TP_QT_IFACE_CHANNEL + QString::fromLatin1(".Requested"), requested); chanProps.insert(TP_QT_IFACE_CHANNEL + QString::fromLatin1(".TargetHandleType"), static_cast(handleType)); TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandleRepoIface *roomRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_ROOM); TpHandle handle; GType type; if (handleType == HandleTypeContact) { handle = tp_handle_ensure(contactRepo, "bob", NULL, NULL); type = TP_TESTS_TYPE_CONTACT_STREAM_TUBE_CHANNEL; chanProps.insert(TP_QT_IFACE_CHANNEL + QString::fromLatin1(".TargetID"), QString::fromLatin1("bob")); } else { handle = tp_handle_ensure(roomRepo, "#test", NULL, NULL); type = TP_TESTS_TYPE_ROOM_STREAM_TUBE_CHANNEL; chanProps.insert(TP_QT_IFACE_CHANNEL + QString::fromLatin1(".TargetID"), QString::fromLatin1("#test")); } chanProps.insert(TP_QT_IFACE_CHANNEL + QString::fromLatin1(".TargetHandle"), handle); TpHandle alfHandle = tp_handle_ensure(contactRepo, "alf", NULL, NULL); GHashTable *sockets = createSupportedSocketTypesHash(supportMonitoring, unixOnly); mChanServices.push_back( TP_TESTS_STREAM_TUBE_CHANNEL(g_object_new( type, "connection", mConn->service(), "handle", handle, "requested", requested, "object-path", chanPath.toLatin1().constData(), "supported-socket-types", sockets, "initiator-handle", alfHandle, NULL))); return qMakePair(chanPath, chanProps); } QMap TestStreamTubeHandlers::ourHandlers() { QStringList registeredNames = QDBusConnection::sessionBus().interface()->registeredServiceNames(); QMap handlers; Q_FOREACH (QString name, registeredNames) { if (!name.startsWith(QLatin1String("org.freedesktop.Telepathy.Client."))) { continue; } if (QDBusConnection::sessionBus().interface()->serviceOwner(name).value() != QDBusConnection::sessionBus().baseService()) { continue; } QString path = QLatin1Char('/') + name; path.replace(QLatin1Char('.'), QLatin1Char('/')); ClientInterface client(name, path); QStringList ifaces; if (!waitForProperty(client.requestPropertyInterfaces(), &ifaces)) { continue; } if (!ifaces.contains(TP_QT_IFACE_CLIENT_HANDLER)) { continue; } handlers.insert(name.mid(std::strlen("org.freedesktop.Telepathy.Client.")), new ClientHandlerInterface(name, path, this)); } return handlers; } void TestStreamTubeHandlers::onTubeRequested( const Tp::AccountPtr &acc, const Tp::OutgoingStreamTubeChannelPtr &tube, const QDateTime &userActionTime, const Tp::ChannelRequestHints &hints) { qDebug() << "tube" << tube->objectPath() << "requested on account" << acc->objectPath(); // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } // We always set the user action time in the past, so if that's carried over correctly, it won't // be any more recent than the current time if (mRequestTime >= QDateTime::currentDateTime()) { qWarning() << "user action time later than expected"; mLoop->exit(2); return; } mRequestedTube = tube; mRequestTime = userActionTime; mRequestHints = hints; mLoop->exit(0); } void TestStreamTubeHandlers::onServerTubeClosed( const Tp::AccountPtr &acc, const Tp::OutgoingStreamTubeChannelPtr &tube, const QString &error, const QString &message) { qDebug() << "tube" << tube->objectPath() << "closed on account" << acc->objectPath(); qDebug() << "with error" << error << ':' << message; // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } mServerClosedTube = tube; mServerCloseError = error; mServerCloseMessage = message; mLoop->exit(0); } void TestStreamTubeHandlers::onClientTubeClosed( const Tp::AccountPtr &acc, const Tp::IncomingStreamTubeChannelPtr &tube, const QString &error, const QString &message) { qDebug() << "tube" << tube->objectPath() << "closed on account" << acc->objectPath(); qDebug() << "with error" << error << ':' << message; // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } mClientClosedTube = tube; mClientCloseError = error; mClientCloseMessage = message; mLoop->exit(0); } void TestStreamTubeHandlers::onNewServerConnection( const QHostAddress &sourceAddress, quint16 sourcePort, const Tp::AccountPtr &acc, const Tp::ContactPtr &contact, const Tp::OutgoingStreamTubeChannelPtr &tube) { qDebug() << "new conn" << qMakePair(sourceAddress, sourcePort) << "on tube" << tube->objectPath(); qDebug() << "from contact" << contact->id(); // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } if (!tube->connectionsForSourceAddresses().contains(qMakePair(sourceAddress, sourcePort))) { qWarning() << "the signaled tube doesn't report having that particular connection"; mLoop->exit(2); return; } mNewServerConnectionAddress = sourceAddress; mNewServerConnectionPort = sourcePort; mNewServerConnectionContact = contact; mNewServerConnectionTube = tube; mLoop->exit(0); } void TestStreamTubeHandlers::onServerConnectionClosed( const QHostAddress &sourceAddress, quint16 sourcePort, const Tp::AccountPtr &acc, const Tp::ContactPtr &contact, const QString &error, const QString &message, const Tp::OutgoingStreamTubeChannelPtr &tube) { qDebug() << "conn" << qMakePair(sourceAddress, sourcePort) << "closed on tube" << tube->objectPath(); qDebug() << "with error" << error << ':' << message; // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } mClosedServerConnectionAddress = sourceAddress; mClosedServerConnectionPort = sourcePort; mClosedServerConnectionContact = contact; mServerConnectionCloseError = error; mServerConnectionCloseMessage = message; mServerConnectionCloseTube = tube; mLoop->exit(0); } void TestStreamTubeHandlers::onTubeOffered( const Tp::AccountPtr &acc, const Tp::IncomingStreamTubeChannelPtr &tube) { qDebug() << "tube" << tube->objectPath() << "offered to account" << acc->objectPath(); // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } mOfferedTube = tube; mLoop->exit(0); } void TestStreamTubeHandlers::onClientAcceptedAsTcp( const QHostAddress &listenAddress, quint16 listenPort, const QHostAddress &sourceAddress, quint16 sourcePort, const Tp::AccountPtr &acc, const Tp::IncomingStreamTubeChannelPtr &tube) { qDebug() << "tube" << tube->objectPath() << "accepted at" << qMakePair(listenAddress, listenPort); // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } mClientTcpAcceptAddr = listenAddress; mClientTcpAcceptPort = listenPort; mClientTcpAcceptSrcAddr = sourceAddress; mClientTcpAcceptSrcPort = sourcePort; mClientTcpAcceptTube = tube; mLoop->exit(0); } void TestStreamTubeHandlers::onClientAcceptedAsUnix( const QString &listenAddress, bool reqsCreds, uchar credByte, const Tp::AccountPtr &acc, const Tp::IncomingStreamTubeChannelPtr &tube) { qDebug() << "tube" << tube->objectPath() << "accepted at" << listenAddress; qDebug() << "reqs creds:" << reqsCreds << "cred byte:" << credByte; // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } mClientUnixAcceptAddr = listenAddress; mClientUnixReqsCreds = reqsCreds; mClientUnixAcceptTube = tube; mLoop->exit(0); } void TestStreamTubeHandlers::onNewClientConnection( const Tp::AccountPtr &acc, const Tp::IncomingStreamTubeChannelPtr &tube, uint id) { qDebug() << "new conn" << id << "on tube" << tube->objectPath(); // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } mNewClientConnectionTube = tube; mNewClientConnectionId = id; mLoop->exit(0); } void TestStreamTubeHandlers::onClientConnectionClosed( const Tp::AccountPtr &acc, const Tp::IncomingStreamTubeChannelPtr &tube, uint id, const QString &error, const QString &message) { qDebug() << "conn" << id << "closed on tube" << tube->objectPath(); qDebug() << "with error" << error << ':' << message; // We don't use a shared factory here so the proxies will be different, but the object path // should be the same if (acc->objectPath() != mAcc->objectPath()) { qWarning() << "account" << acc->objectPath() << "is not the expected" << mAcc->objectPath(); mLoop->exit(1); return; } mClosedClientConnectionTube = tube; mClosedClientConnectionId = id; mClientConnectionCloseError = error; mClientConnectionCloseMessage = message; mLoop->exit(0); } void TestStreamTubeHandlers::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("stream-tube-handlers"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mAM = AccountManager::create(); QVERIFY(connect(mAM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAM->isReady(), true); QVariantMap parameters; parameters[QLatin1String("account")] = QLatin1String("foobar"); PendingAccount *pacc = mAM->createAccount(QLatin1String("foo"), QLatin1String("bar"), QLatin1String("foobar"), parameters); QVERIFY(connect(pacc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(pacc->account()); mAcc= pacc->account(); mConn = new TestConnHelper(this, TP_TESTS_TYPE_SIMPLE_CONNECTION, "account", "me@example.com", "protocol", "example", NULL); QCOMPARE(mConn->connect(), true); } void TestStreamTubeHandlers::init() { initImpl(); } void TestStreamTubeHandlers::testRegistration() { StreamTubeServerPtr httpServer = StreamTubeServer::create(QStringList() << QLatin1String("http"), QStringList()); StreamTubeServerPtr whiteboardServer = StreamTubeServer::create(QStringList() << QLatin1String("sketch"), QStringList() << QLatin1String("sketch"), QString(), true); StreamTubeServerPtr activatedServer = StreamTubeServer::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("vsftpd")); StreamTubeServerPtr preferredHandlerServer = StreamTubeServer::create(QStringList()); StreamTubeClientPtr browser = StreamTubeClient::create(QStringList() << QLatin1String("http"), QStringList(), QLatin1String("Debian.Iceweasel")); StreamTubeClientPtr collaborationTool = StreamTubeClient::create(QStringList() << QLatin1String("sketch") << QLatin1String("ftp"), QStringList() << QLatin1String("sketch"), QString(), false, true); StreamTubeClientPtr invalidBecauseNoServicesClient = StreamTubeClient::create(QStringList()); QVERIFY(!httpServer.isNull()); QVERIFY(!whiteboardServer.isNull()); QVERIFY(!activatedServer.isNull()); QVERIFY(!preferredHandlerServer.isNull()); QVERIFY(!browser.isNull()); QVERIFY(!collaborationTool.isNull()); QVERIFY(invalidBecauseNoServicesClient.isNull()); QCOMPARE(activatedServer->clientName(), QLatin1String("vsftpd")); QCOMPARE(browser->clientName(), QLatin1String("Debian.Iceweasel")); class CookieGenerator : public StreamTubeServer::ParametersGenerator { public: CookieGenerator() : serial(0) {} QVariantMap nextParameters(const AccountPtr &account, const OutgoingStreamTubeChannelPtr &tube, const ChannelRequestHints &hints) { QVariantMap params; params.insert(QLatin1String("cookie-y"), QString(QLatin1String("e982mrh2mr2h+%1")).arg(serial++)); return params; } private: uint serial; } httpGenerator; QVariantMap whiteboardParams; whiteboardParams.insert(QLatin1String("password"), QString::fromLatin1("s3kr1t")); QTcpServer server; server.listen(); httpServer->exportTcpSocket(QHostAddress::LocalHost, 80, &httpGenerator); whiteboardServer->exportTcpSocket(QHostAddress::LocalHost, 31552, whiteboardParams); activatedServer->exportTcpSocket(&server); QCOMPARE(activatedServer->exportedParameters(), QVariantMap()); preferredHandlerServer->exportTcpSocket(QHostAddress::LocalHost, 6681); browser->setToAcceptAsTcp(); collaborationTool->setToAcceptAsUnix(true); QVERIFY(httpServer->isRegistered()); QVERIFY(whiteboardServer->isRegistered()); QVERIFY(activatedServer->isRegistered()); QVERIFY(preferredHandlerServer->isRegistered()); QVERIFY(browser->isRegistered()); QVERIFY(collaborationTool->isRegistered()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); QVERIFY(handlers.contains(httpServer->clientName())); QVERIFY(handlers.contains(whiteboardServer->clientName())); QVERIFY(handlers.contains(QLatin1String("vsftpd"))); QVERIFY(handlers.contains(preferredHandlerServer->clientName())); QVERIFY(handlers.contains(QLatin1String("Debian.Iceweasel"))); QVERIFY(handlers.contains(collaborationTool->clientName())); QCOMPARE(handlers.size(), 6); // The only-to-be-used-through-preferredHandler server should have an empty filter, but still be // registered and introspectable ChannelClassList filter; QVERIFY(waitForProperty(handlers.value(preferredHandlerServer->clientName())-> requestPropertyHandlerChannelFilter(), &filter)); QVERIFY(filter.isEmpty()); // We didn't specify bypassApproval = true, so it should be false. for all we know we could be // sent some fairly NSFW stuff on a HTTP tube :> bool bypass; QVERIFY(waitForProperty(handlers.value(browser->clientName())->requestPropertyBypassApproval(), &bypass)); QVERIFY(!bypass); // here we did, though, because we want our coworkers to be able to save our ass by launching a // brainstorming UI on top of our again rather NSFW browsing habits while we're having a cup QVERIFY(waitForProperty(handlers.value(collaborationTool->clientName())-> requestPropertyBypassApproval(), &bypass)); QVERIFY(bypass); } void TestStreamTubeHandlers::testBasicTcpExport() { StreamTubeServerPtr server = StreamTubeServer::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("vsftpd")); QVariantMap params; params.insert(QLatin1String("username"), QString::fromLatin1("user")); params.insert(QLatin1String("password"), QString::fromLatin1("pass")); server->exportTcpSocket(QHostAddress::LocalHost, 22, params); QVERIFY(server->isRegistered()); QCOMPARE(server->exportedTcpSocketAddress(), qMakePair(QHostAddress(QHostAddress::LocalHost), quint16(22))); QCOMPARE(server->exportedParameters(), params); QVERIFY(!server->monitorsConnections()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(server->clientName()); QVERIFY(handler != 0); ChannelClassList filter; QVERIFY(waitForProperty(handler->requestPropertyHandlerChannelFilter(), &filter)); QCOMPARE(filter.size(), 1); QVERIFY(ChannelClassSpec(filter.first()) == ChannelClassSpec::outgoingStreamTube(QLatin1String("ftp"))); QPair chan = createTubeChannel(true, HandleTypeContact, false); QVERIFY(connect(server.data(), SIGNAL(tubeRequested(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QDateTime,Tp::ChannelRequestHints)), SLOT(onTubeRequested(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QDateTime,Tp::ChannelRequestHints)))); QDateTime userActionTime = QDateTime::currentDateTime().addDays(-1); userActionTime = userActionTime.addMSecs(-userActionTime.time().msec()); QVariantMap hints; hints.insert(QLatin1String("tp-qt-test-request-hint-herring-color-rgba"), uint(0xff000000)); QObject *request = new QObject(this); QString requestPath = QLatin1String("/org/freedesktop/Telepathy/ChannelRequest/RequestForSimpleTcpExport"); QDBusConnection bus = server->registrar()->dbusConnection(); new ChannelRequestAdaptor(QDBusObjectPath(mAcc->objectPath()), userActionTime.toTime_t(), QString(), QualifiedPropertyValueMapList(), QStringList(), false, false, hints, request); QVERIFY(bus.registerService(TP_QT_CHANNEL_DISPATCHER_BUS_NAME)); QVERIFY(bus.registerObject(requestPath, request)); // Invoke the handler, verifying that we're notified when that happens with the correct tube // details ChannelDetails details = { QDBusObjectPath(chan.first), chan.second }; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList() << QDBusObjectPath(requestPath), userActionTime.toTime_t(), QVariantMap()); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mRequestedTube.isNull()); QCOMPARE(mRequestedTube->objectPath(), chan.first); QCOMPARE(mRequestTime, userActionTime); QCOMPARE(mRequestHints.allHints(), hints); // Verify that the state recovery accessors return sensible values at this point QList serverTubes = server->tubes(); QCOMPARE(serverTubes.size(), 1); QCOMPARE(serverTubes.first().account()->objectPath(), mAcc->objectPath()); QCOMPARE(serverTubes.first().channel(), mRequestedTube); QVERIFY(server->tcpConnections().isEmpty()); // Let's run until the tube has been offered while (mRequestedTube->isValid() && mRequestedTube->state() != TubeChannelStateRemotePending) { mLoop->processEvents(); } QVERIFY(mRequestedTube->isValid()); // Simulate a peer connecting (makes the tube Open up) GValue *connParam = tp_g_value_slice_new_static_string("ignored"); tp_tests_stream_tube_channel_peer_connected_no_stream(mChanServices.back(), connParam, tp_base_channel_get_target_handle(TP_BASE_CHANNEL(mChanServices.back()))); tp_g_value_slice_free(connParam); // The params are set once the tube is open (we've picked up the first peer connection) while (mRequestedTube->isValid() && mRequestedTube->state() != TubeChannelStateOpen) { mLoop->processEvents(); } // Verify the params QVERIFY(mRequestedTube->isValid()); QCOMPARE(mRequestedTube->parameters(), params); // Now, close the tube and verify we're signaled about that QVERIFY(connect(server.data(), SIGNAL(tubeClosed(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QString,QString)), SLOT(onServerTubeClosed(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QString,QString)))); mRequestedTube->requestClose(); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mServerClosedTube, mRequestedTube); QCOMPARE(mServerCloseError, QString(TP_QT_ERROR_CANCELLED)); // == local close request } void TestStreamTubeHandlers::testFailedExport() { StreamTubeServerPtr server = StreamTubeServer::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("vsftpd")); server->exportTcpSocket(QHostAddress::LocalHost, 22); QVERIFY(server->isRegistered()); QVERIFY(connect(server.data(), SIGNAL(tubeRequested(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QDateTime,Tp::ChannelRequestHints)), SLOT(onTubeRequested(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QDateTime,Tp::ChannelRequestHints)))); QVERIFY(connect(server.data(), SIGNAL(tubeClosed(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QString,QString)), SLOT(onServerTubeClosed(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QString,QString)))); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(server->clientName()); QVERIFY(handler != 0); // To trigger the Offer error codepath, give it a channel which only supports Unix sockets // although we're exporting a TCP one - which is always supported in real CMs QPair chan = createTubeChannel(true, HandleTypeContact, false, true); ChannelDetails details = { QDBusObjectPath(chan.first), chan.second }; // We should initially get tubeRequested just fine handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), QDateTime::currentDateTime().toTime_t(), QVariantMap()); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mRequestedTube.isNull()); QCOMPARE(mRequestedTube->objectPath(), chan.first); // THEN we should get a tube close because the offer fails QCOMPARE(mLoop->exec(), 0); QCOMPARE(mServerClosedTube, mRequestedTube); QCOMPARE(mServerCloseError, QString(TP_QT_ERROR_NOT_IMPLEMENTED)); // == AF unsupported by "CM" } void TestStreamTubeHandlers::testServerConnMonitoring() { StreamTubeServerPtr server = StreamTubeServer::create(QStringList(), QStringList() << QLatin1String("multiftp"), QLatin1String("warezd"), true); server->exportTcpSocket(QHostAddress::LocalHost, 22); QVERIFY(server->isRegistered()); QVERIFY(server->monitorsConnections()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(server->clientName()); QVERIFY(handler != 0); QPair chan = createTubeChannel(true, HandleTypeRoom, true); QVERIFY(connect(server.data(), SIGNAL(tubeRequested(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QDateTime,Tp::ChannelRequestHints)), SLOT(onTubeRequested(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QDateTime,Tp::ChannelRequestHints)))); QVERIFY(connect(server.data(), SIGNAL(tubeClosed(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QString,QString)), SLOT(onServerTubeClosed(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QString,QString)))); ChannelDetails details = { QDBusObjectPath(chan.first), chan.second }; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), QDateTime::currentDateTime().toTime_t(), QVariantMap()); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mRequestedTube.isNull()); QCOMPARE(mRequestedTube->objectPath(), chan.first); // There are no connections at this point QVERIFY(server->tcpConnections().isEmpty()); // Let's run until the tube has been offered while (mRequestedTube->isValid() && mRequestedTube->state() != TubeChannelStateRemotePending) { mLoop->processEvents(); } QVERIFY(mRequestedTube->isValid()); // Still no connections QVERIFY(server->tcpConnections().isEmpty()); // Now, some connections actually start popping up QVERIFY(connect(server.data(), SIGNAL(newTcpConnection(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr,Tp::OutgoingStreamTubeChannelPtr)), SLOT(onNewServerConnection(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr,Tp::OutgoingStreamTubeChannelPtr)))); QVERIFY(connect(server.data(), SIGNAL(tcpConnectionClosed(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr,QString,QString,Tp::OutgoingStreamTubeChannelPtr)), SLOT(onServerConnectionClosed(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr,QString,QString,Tp::OutgoingStreamTubeChannelPtr)))); // Simulate the first peer connecting (makes the tube Open up) GValue *connParam = tp_g_value_slice_new_take_boxed( TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4, dbus_g_type_specialized_construct(TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4)); QHostAddress expectedAddress = QHostAddress::LocalHost; quint16 expectedPort = 1; dbus_g_type_struct_set(connParam, 0, expectedAddress.toString().toLatin1().constData(), 1, expectedPort, G_MAXUINT); TpHandleRepoIface *contactRepo = tp_base_connection_get_handles( TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandle handle = tp_handle_ensure(contactRepo, "first", NULL, NULL); tp_tests_stream_tube_channel_peer_connected_no_stream(mChanServices.back(), connParam, handle); // We should get a newTcpConnection signal now and tcpConnections() should include this new conn QCOMPARE(mLoop->exec(), 0); QCOMPARE(mNewServerConnectionAddress, expectedAddress); QCOMPARE(mNewServerConnectionPort, expectedPort); QCOMPARE(mNewServerConnectionContact->handle()[0], handle); QCOMPARE(mNewServerConnectionContact->id(), QLatin1String("first")); QCOMPARE(mNewServerConnectionTube, mRequestedTube); QHash, StreamTubeServer::RemoteContact > conns = server->tcpConnections(); QCOMPARE(conns.size(), 1); QVERIFY(conns.contains(qMakePair(expectedAddress, expectedPort))); QCOMPARE(conns.value(qMakePair(expectedAddress, expectedPort)).account()->objectPath(), mAcc->objectPath()); QCOMPARE(conns.value(qMakePair(expectedAddress, expectedPort)).contact(), mNewServerConnectionContact); // Now, close the first connection tp_tests_stream_tube_channel_last_connection_disconnected(mChanServices.back(), TP_ERROR_STR_DISCONNECTED); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClosedServerConnectionAddress, expectedAddress); QCOMPARE(mClosedServerConnectionPort, expectedPort); QCOMPARE(mClosedServerConnectionContact, mNewServerConnectionContact); QCOMPARE(mServerConnectionCloseError, QString(TP_QT_ERROR_DISCONNECTED)); QVERIFY(server->tcpConnections().isEmpty()); // Fire up two new connections handle = tp_handle_ensure(contactRepo, "second", NULL, NULL); expectedPort = 2; dbus_g_type_struct_set(connParam, 1, expectedPort, G_MAXUINT); tp_tests_stream_tube_channel_peer_connected_no_stream(mChanServices.back(), connParam, handle); handle = tp_handle_ensure(contactRepo, "third", NULL, NULL); expectedPort = 3; dbus_g_type_struct_set(connParam, 1, expectedPort, G_MAXUINT); tp_tests_stream_tube_channel_peer_connected_no_stream(mChanServices.back(), connParam, handle); // We should get two newTcpConnection signals now and tcpConnections() should include these // connections QCOMPARE(mLoop->exec(), 0); QCOMPARE(mNewServerConnectionAddress, expectedAddress); QCOMPARE(mNewServerConnectionPort, quint16(2)); QCOMPARE(mNewServerConnectionContact->id(), QLatin1String("second")); QCOMPARE(mNewServerConnectionTube, mRequestedTube); QCOMPARE(server->tcpConnections().size(), 1); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mNewServerConnectionAddress, expectedAddress); QCOMPARE(mNewServerConnectionPort, quint16(3)); QCOMPARE(mNewServerConnectionContact->id(), QLatin1String("third")); QCOMPARE(mNewServerConnectionTube, mRequestedTube); QCOMPARE(server->tcpConnections().size(), 2); // Close one of them, and check that we receive the signal for it tp_tests_stream_tube_channel_last_connection_disconnected(mChanServices.back(), TP_ERROR_STR_DISCONNECTED); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClosedServerConnectionAddress, expectedAddress); QCOMPARE(mClosedServerConnectionPort, quint16(3)); QCOMPARE(mClosedServerConnectionContact, mNewServerConnectionContact); QCOMPARE(mServerConnectionCloseError, QString(TP_QT_ERROR_DISCONNECTED)); QCOMPARE(server->tcpConnections().size(), 1); // Now, close the tube and verify we're signaled about that QVERIFY(mServerClosedTube.isNull()); QCOMPARE(server->tubes().size(), 1); mClosedServerConnectionContact.reset(); mRequestedTube->requestClose(); while (mClosedServerConnectionContact.isNull() || mServerClosedTube.isNull()) { QVERIFY(mServerClosedTube.isNull()); // we should get the conn close first, only then tube close QCOMPARE(mLoop->exec(), 0); } QVERIFY(server->tubes().isEmpty()); QVERIFY(server->tcpConnections().isEmpty()); QCOMPARE(mClosedServerConnectionAddress, expectedAddress); QCOMPARE(mClosedServerConnectionPort, quint16(2)); QCOMPARE(mClosedServerConnectionContact->id(), QLatin1String("second")); QCOMPARE(mServerConnectionCloseError, TP_QT_ERROR_ORPHANED); // parent tube died QCOMPARE(mServerClosedTube, mRequestedTube); QCOMPARE(mServerCloseError, QString(TP_QT_ERROR_CANCELLED)); // == local close request } void TestStreamTubeHandlers::testSSTHErrorPaths() { // Create and look up a handler with an incorrectly set up channel factory ChannelFactoryPtr chanFactory = ChannelFactory::create(QDBusConnection::sessionBus()); chanFactory->setSubclassForIncomingStreamTubes(); StreamTubeServerPtr server = StreamTubeServer::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("vsftpd"), false, AccountFactory::create(QDBusConnection::sessionBus()), ConnectionFactory::create(QDBusConnection::sessionBus()), chanFactory); server->exportTcpSocket(QHostAddress::LocalHost, 22); QVERIFY(server->isRegistered()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(server->clientName()); QVERIFY(handler != 0); // Pass it a text channel, and with no satisfied requests QString textChanPath = mConn->objectPath() + QLatin1String("/TextChannel"); QByteArray chanPath(textChanPath.toLatin1()); ExampleEchoChannel *textChanService = EXAMPLE_ECHO_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_CHANNEL, "connection", mConn->service(), "object-path", chanPath.data(), "handle", TpHandle(1), NULL)); ChannelDetails details = { QDBusObjectPath(textChanPath), ChannelClassSpec::textChat().allProperties() }; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), QDateTime::currentDateTime().toTime_t(), QVariantMap()); processDBusQueue(mConn->client().data()); // Now pass it an incoming stream tube chan, which will trigger the error paths for constructing // wrong subclasses for tubes QPair tubeChan = createTubeChannel(false, HandleTypeContact, false); details.channel = QDBusObjectPath(tubeChan.first); details.properties = tubeChan.second; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), QDateTime::currentDateTime().toTime_t(), QVariantMap()); processDBusQueue(mConn->client().data()); // Now pass it an outgoing stream tube chan (which we didn't set an incorrect subclass for), but // which doesn't actually exist so introspection fails details.channel = QDBusObjectPath(QString::fromLatin1("/does/not/exist")); details.properties = ChannelClassSpec::outgoingStreamTube(QLatin1String("ftp")).allProperties(); handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), QDateTime::currentDateTime().toTime_t(), QVariantMap()); processDBusQueue(mConn->client().data()); // Now pass an actual outgoing tube chan and verify it's still signaled correctly after all // these incorrect invocations of the handler QVERIFY(connect(server.data(), SIGNAL(tubeRequested(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QDateTime,Tp::ChannelRequestHints)), SLOT(onTubeRequested(Tp::AccountPtr,Tp::OutgoingStreamTubeChannelPtr,QDateTime,Tp::ChannelRequestHints)))); tubeChan = createTubeChannel(true, HandleTypeContact, false); details.channel = QDBusObjectPath(tubeChan.first); details.properties = tubeChan.second; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), QDateTime::currentDateTime().toTime_t(), QVariantMap()); processDBusQueue(mConn->client().data()); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mRequestedTube->objectPath(), tubeChan.first); // TODO: if/when the QDBus bug about not being able to wait for local loop replies even with a // main loop is fixed, wait for the HandleChannels invocations to return properly. For now just // run 100 pings to the service, during which the codepaths get run almost certainly. for (int i = 0; i < 100; i++) { processDBusQueue(mConn->client().data()); } g_object_unref(textChanService); } void TestStreamTubeHandlers::testClientBasicTcp() { StreamTubeClientPtr client = StreamTubeClient::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("ncftp")); class FakeGenerator : public StreamTubeClient::TcpSourceAddressGenerator { public: FakeGenerator() : port(0) {} QPair nextSourceAddress(const AccountPtr &account, const IncomingStreamTubeChannelPtr &tube) { return qMakePair(QHostAddress(QHostAddress::LocalHost), ++port); } quint16 port; } gen; client->setToAcceptAsTcp(&gen); QVERIFY(client->isRegistered()); QCOMPARE(client->registrar()->registeredClients().size(), 1); QVERIFY(client->acceptsAsTcp()); QVERIFY(!client->acceptsAsUnix()); QCOMPARE(client->tcpGenerator(), static_cast(&gen)); QVERIFY(!client->monitorsConnections()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(client->clientName()); QVERIFY(handler != 0); ChannelClassList filter; QVERIFY(waitForProperty(handler->requestPropertyHandlerChannelFilter(), &filter)); QCOMPARE(filter.size(), 1); QVERIFY(ChannelClassSpec(filter.first()) == ChannelClassSpec::incomingStreamTube(QLatin1String("ftp"))); QPair chan = createTubeChannel(false, HandleTypeContact, true); QVERIFY(connect(client.data(), SIGNAL(tubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onTubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); QVERIFY(connect(client.data(), SIGNAL(tubeAcceptedAsTcp(QHostAddress,quint16,QHostAddress,quint16, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onClientAcceptedAsTcp(QHostAddress,quint16,QHostAddress,quint16, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); // Invoke the handler, verifying that we're notified when that happens with the correct tube // details ChannelDetails details = { QDBusObjectPath(chan.first), chan.second }; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), 0, // not an user action QVariantMap()); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mOfferedTube.isNull()); QCOMPARE(mOfferedTube->objectPath(), chan.first); // Verify that the state recovery accessors return sensible values at this point QList clientTubes = client->tubes(); QCOMPARE(clientTubes.size(), 1); QCOMPARE(clientTubes.first().account()->objectPath(), mAcc->objectPath()); QCOMPARE(clientTubes.first().channel(), mOfferedTube); QVERIFY(client->connections().isEmpty()); // Let's run until we've accepted the tube QCOMPARE(mLoop->exec(), 0); QVERIFY(mOfferedTube->isValid()); QCOMPARE(mClientTcpAcceptAddr, QHostAddress(QHostAddress::LocalHost)); QVERIFY(mClientTcpAcceptPort != 0); QCOMPARE(mClientTcpAcceptSrcAddr, QHostAddress(QHostAddress::LocalHost)); QCOMPARE(mClientTcpAcceptSrcPort, gen.port); QCOMPARE(mClientTcpAcceptTube, mOfferedTube); // Now, close the tube and verify we're signaled about that QVERIFY(connect(client.data(), SIGNAL(tubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)), SLOT(onClientTubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)))); mOfferedTube->requestClose(); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClientClosedTube, mOfferedTube); QCOMPARE(mClientCloseError, QString(TP_QT_ERROR_CANCELLED)); // == local close request } void TestStreamTubeHandlers::testClientTcpGeneratorIgnore() { StreamTubeClientPtr client = StreamTubeClient::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("ncftp")); class FakeGenerator : public StreamTubeClient::TcpSourceAddressGenerator { public: QPair nextSourceAddress(const AccountPtr &account, const IncomingStreamTubeChannelPtr &tube) { return qMakePair(QHostAddress(QHostAddress::LocalHost), quint16(1111)); } } gen; client->setToAcceptAsTcp(&gen); QVERIFY(client->isRegistered()); QVERIFY(client->acceptsAsTcp()); QVERIFY(!client->acceptsAsUnix()); QCOMPARE(client->tcpGenerator(), static_cast(&gen)); QVERIFY(!client->monitorsConnections()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(client->clientName()); QVERIFY(handler != 0); ChannelClassList filter; QVERIFY(waitForProperty(handler->requestPropertyHandlerChannelFilter(), &filter)); QCOMPARE(filter.size(), 1); QVERIFY(ChannelClassSpec(filter.first()) == ChannelClassSpec::incomingStreamTube(QLatin1String("ftp"))); QPair chan = createTubeChannel(false, HandleTypeContact, false); QVERIFY(connect(client.data(), SIGNAL(tubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onTubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); QVERIFY(connect(client.data(), SIGNAL(tubeAcceptedAsTcp(QHostAddress,quint16,QHostAddress,quint16, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onClientAcceptedAsTcp(QHostAddress,quint16,QHostAddress,quint16, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); // Invoke the handler, verifying that we're notified when that happens with the correct tube // details ChannelDetails details = { QDBusObjectPath(chan.first), chan.second }; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), 0, // not an user action QVariantMap()); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mOfferedTube.isNull()); QCOMPARE(mOfferedTube->objectPath(), chan.first); // Verify that the state recovery accessors return sensible values at this point QList clientTubes = client->tubes(); QCOMPARE(clientTubes.size(), 1); QCOMPARE(clientTubes.first().account()->objectPath(), mAcc->objectPath()); QCOMPARE(clientTubes.first().channel(), mOfferedTube); QVERIFY(client->connections().isEmpty()); // Let's run until we've accepted the tube QCOMPARE(mLoop->exec(), 0); QVERIFY(mOfferedTube->isValid()); QCOMPARE(mClientTcpAcceptAddr, QHostAddress(QHostAddress::LocalHost)); QVERIFY(mClientTcpAcceptPort != 0); QCOMPARE(mClientTcpAcceptSrcAddr, QHostAddress(QHostAddress::Any)); QCOMPARE(mClientTcpAcceptSrcPort, quint16(0)); QCOMPARE(mClientTcpAcceptTube, mOfferedTube); // Now, close the tube and verify we're signaled about that QVERIFY(connect(client.data(), SIGNAL(tubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)), SLOT(onClientTubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)))); mOfferedTube->requestClose(); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClientClosedTube, mOfferedTube); QCOMPARE(mClientCloseError, QString(TP_QT_ERROR_CANCELLED)); // == local close request } void TestStreamTubeHandlers::testClientTcpUnsupported() { StreamTubeClientPtr client = StreamTubeClient::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("ncftp")); client->setToAcceptAsTcp(); QVERIFY(client->isRegistered()); QVERIFY(client->acceptsAsTcp()); QVERIFY(!client->acceptsAsUnix()); QVERIFY(!client->monitorsConnections()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(client->clientName()); QVERIFY(handler != 0); ChannelClassList filter; QVERIFY(waitForProperty(handler->requestPropertyHandlerChannelFilter(), &filter)); QCOMPARE(filter.size(), 1); QVERIFY(ChannelClassSpec(filter.first()) == ChannelClassSpec::incomingStreamTube(QLatin1String("ftp"))); QPair chan = createTubeChannel(false, HandleTypeContact, false, true); QVERIFY(connect(client.data(), SIGNAL(tubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onTubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); QVERIFY(connect(client.data(), SIGNAL(tubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)), SLOT(onClientTubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)))); // Invoke the handler, verifying that we're notified when that happens with the correct tube // details ChannelDetails details = { QDBusObjectPath(chan.first), chan.second }; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), 0, // not an user action QVariantMap()); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mOfferedTube.isNull()); QCOMPARE(mOfferedTube->objectPath(), chan.first); // Now, run until Accept fails (because TCP is not supported by the fake service here) and // consequently the tube is closed QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClientClosedTube, mOfferedTube); QCOMPARE(mClientCloseError, QString(TP_QT_ERROR_NOT_IMPLEMENTED)); // == AF unsupported } void TestStreamTubeHandlers::testClientBasicUnix() { StreamTubeClientPtr client = StreamTubeClient::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("ncftp")); client->setToAcceptAsUnix(true); QVERIFY(client->isRegistered()); QCOMPARE(client->registrar()->registeredClients().size(), 1); QVERIFY(!client->acceptsAsTcp()); QVERIFY(client->acceptsAsUnix()); QCOMPARE(client->tcpGenerator(), static_cast(0)); QVERIFY(!client->monitorsConnections()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(client->clientName()); QVERIFY(handler != 0); ChannelClassList filter; QVERIFY(waitForProperty(handler->requestPropertyHandlerChannelFilter(), &filter)); QCOMPARE(filter.size(), 1); QVERIFY(ChannelClassSpec(filter.first()) == ChannelClassSpec::incomingStreamTube(QLatin1String("ftp"))); QPair chan = createTubeChannel(false, HandleTypeContact, true); QVERIFY(connect(client.data(), SIGNAL(tubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onTubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); QVERIFY(connect(client.data(), SIGNAL(tubeAcceptedAsUnix(QString,bool,uchar, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onClientAcceptedAsUnix(QString,bool,uchar, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); // Invoke the handler, verifying that we're notified when that happens with the correct tube // details ChannelDetails details = { QDBusObjectPath(chan.first), chan.second }; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), 0, // not an user action QVariantMap()); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mOfferedTube.isNull()); QCOMPARE(mOfferedTube->objectPath(), chan.first); // Verify that the state recovery accessors return sensible values at this point QList clientTubes = client->tubes(); QCOMPARE(clientTubes.size(), 1); QCOMPARE(clientTubes.first().account()->objectPath(), mAcc->objectPath()); QCOMPARE(clientTubes.first().channel(), mOfferedTube); QVERIFY(client->connections().isEmpty()); // Let's run until we've accepted the tube QCOMPARE(mLoop->exec(), 0); QVERIFY(mOfferedTube->isValid()); QVERIFY(!mClientUnixAcceptAddr.isNull()); QVERIFY(mClientUnixReqsCreds); QCOMPARE(mClientUnixAcceptTube, mOfferedTube); QCOMPARE(mOfferedTube->addressType(), SocketAddressTypeUnix); // Now, close the tube and verify we're signaled about that QVERIFY(connect(client.data(), SIGNAL(tubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)), SLOT(onClientTubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)))); mOfferedTube->requestClose(); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClientClosedTube, mOfferedTube); QCOMPARE(mClientCloseError, QString(TP_QT_ERROR_CANCELLED)); // == local close request } void TestStreamTubeHandlers::testClientUnixCredsIgnore() { StreamTubeClientPtr client = StreamTubeClient::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("ncftp")); client->setToAcceptAsUnix(true); QVERIFY(client->isRegistered()); QVERIFY(!client->acceptsAsTcp()); QVERIFY(client->acceptsAsUnix()); QCOMPARE(client->tcpGenerator(), static_cast(0)); QVERIFY(!client->monitorsConnections()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(client->clientName()); QVERIFY(handler != 0); ChannelClassList filter; QVERIFY(waitForProperty(handler->requestPropertyHandlerChannelFilter(), &filter)); QCOMPARE(filter.size(), 1); QVERIFY(ChannelClassSpec(filter.first()) == ChannelClassSpec::incomingStreamTube(QLatin1String("ftp"))); QPair chan = createTubeChannel(false, HandleTypeContact, false); QVERIFY(connect(client.data(), SIGNAL(tubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onTubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); QVERIFY(connect(client.data(), SIGNAL(tubeAcceptedAsUnix(QString,bool,uchar, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onClientAcceptedAsUnix(QString,bool,uchar, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); // Invoke the handler, verifying that we're notified when that happens with the correct tube // details ChannelDetails details = { QDBusObjectPath(chan.first), chan.second }; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), 0, // not an user action QVariantMap()); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mOfferedTube.isNull()); QCOMPARE(mOfferedTube->objectPath(), chan.first); // Verify that the state recovery accessors return sensible values at this point QList clientTubes = client->tubes(); QCOMPARE(clientTubes.size(), 1); QCOMPARE(clientTubes.first().account()->objectPath(), mAcc->objectPath()); QCOMPARE(clientTubes.first().channel(), mOfferedTube); QVERIFY(client->connections().isEmpty()); // Let's run until we've accepted the tube QCOMPARE(mLoop->exec(), 0); QVERIFY(mOfferedTube->isValid()); QVERIFY(!mClientUnixAcceptAddr.isNull()); QVERIFY(!mClientUnixReqsCreds); QCOMPARE(mClientUnixAcceptTube, mOfferedTube); QCOMPARE(mOfferedTube->addressType(), SocketAddressTypeUnix); // Now, close the tube and verify we're signaled about that QVERIFY(connect(client.data(), SIGNAL(tubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)), SLOT(onClientTubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)))); mOfferedTube->requestClose(); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClientClosedTube, mOfferedTube); QCOMPARE(mClientCloseError, QString(TP_QT_ERROR_CANCELLED)); // == local close request } void TestStreamTubeHandlers::testClientConnMonitoring() { StreamTubeClientPtr client = StreamTubeClient::create(QStringList() << QLatin1String("ftp"), QStringList(), QLatin1String("ncftp"), true); client->setToAcceptAsTcp(); QVERIFY(client->isRegistered()); QVERIFY(client->acceptsAsTcp()); QVERIFY(client->monitorsConnections()); QMap handlers = ourHandlers(); QVERIFY(!handlers.isEmpty()); ClientHandlerInterface *handler = handlers.value(client->clientName()); QVERIFY(handler != 0); ChannelClassList filter; QVERIFY(waitForProperty(handler->requestPropertyHandlerChannelFilter(), &filter)); QCOMPARE(filter.size(), 1); QVERIFY(ChannelClassSpec(filter.first()) == ChannelClassSpec::incomingStreamTube(QLatin1String("ftp"))); QPair chan = createTubeChannel(false, HandleTypeContact, true); QVERIFY(connect(client.data(), SIGNAL(tubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onTubeOffered(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); QVERIFY(connect(client.data(), SIGNAL(tubeAcceptedAsTcp(QHostAddress,quint16,QHostAddress,quint16, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onClientAcceptedAsTcp(QHostAddress,quint16,QHostAddress,quint16, Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)))); ChannelDetails details = { QDBusObjectPath(chan.first), chan.second }; handler->HandleChannels( QDBusObjectPath(mAcc->objectPath()), QDBusObjectPath(mConn->objectPath()), ChannelDetailsList() << details, ObjectPathList(), QDateTime::currentDateTime().toTime_t(), QVariantMap()); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mOfferedTube.isNull()); QCOMPARE(mOfferedTube->objectPath(), chan.first); // There are no connections at this point QVERIFY(client->connections().isEmpty()); // Let's run until we've accepted the tube QCOMPARE(mLoop->exec(), 0); QVERIFY(mOfferedTube->isValid()); QCOMPARE(mClientTcpAcceptAddr, QHostAddress(QHostAddress::LocalHost)); QVERIFY(mClientTcpAcceptPort != 0); QCOMPARE(mClientTcpAcceptSrcAddr, QHostAddress(QHostAddress::Any)); QCOMPARE(mClientTcpAcceptSrcPort, quint16(0)); QCOMPARE(mClientTcpAcceptTube, mOfferedTube); // Still no connections QVERIFY(client->connections().isEmpty()); // Now, some connections actually start popping up QVERIFY(connect(client.data(), SIGNAL(newConnection(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,uint)), SLOT(onNewClientConnection(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,uint)))); QVERIFY(connect(client.data(), SIGNAL(connectionClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,uint,QString,QString)), SLOT(onClientConnectionClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,uint,QString,QString)))); QTcpSocket first; first.connectToHost(mClientTcpAcceptAddr, mClientTcpAcceptPort); first.waitForConnected(); QVERIFY(first.isValid()); QCOMPARE(first.state(), QAbstractSocket::ConnectedState); // We should get a newConnection signal now and connections() should include this new conn QCOMPARE(mLoop->exec(), 0); QCOMPARE(mNewClientConnectionTube, mOfferedTube); QHash > conns = client->connections(); QCOMPARE(conns.size(), 1); QCOMPARE(conns.values().first().size(), 1); QVERIFY(conns.values().first().contains(mNewClientConnectionId)); uint firstId = mNewClientConnectionId; // Now, close the first connection tp_tests_stream_tube_channel_last_connection_disconnected(mChanServices.back(), TP_ERROR_STR_DISCONNECTED); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClosedClientConnectionId, firstId); QCOMPARE(mClientConnectionCloseError, QString(TP_QT_ERROR_DISCONNECTED)); QVERIFY(client->connections().isEmpty()); // Fire up two new connections QTcpSocket second; second.connectToHost(mClientTcpAcceptAddr, mClientTcpAcceptPort); second.waitForConnected(); QVERIFY(second.isValid()); QCOMPARE(second.state(), QAbstractSocket::ConnectedState); QTcpSocket third; third.connectToHost(mClientTcpAcceptAddr, mClientTcpAcceptPort); third.waitForConnected(); QVERIFY(third.isValid()); QCOMPARE(third.state(), QAbstractSocket::ConnectedState); // We should get two newConnection signals now and connections() should include these // connections QCOMPARE(mLoop->exec(), 0); QCOMPARE(mNewClientConnectionTube, mOfferedTube); QCOMPARE(client->connections().size(), 1); uint secondId = mNewClientConnectionId; QCOMPARE(mLoop->exec(), 0); QCOMPARE(mNewClientConnectionTube, mOfferedTube); QCOMPARE(client->connections().size(), 1); uint thirdId = mNewClientConnectionId; conns = client->connections(); QCOMPARE(conns.size(), 1); QCOMPARE(conns.values().first().size(), 2); QVERIFY(conns.values().first().contains(secondId)); QVERIFY(conns.values().first().contains(thirdId)); // Close one of them, and check that we receive the signal for it tp_tests_stream_tube_channel_last_connection_disconnected(mChanServices.back(), TP_ERROR_STR_DISCONNECTED); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mClosedClientConnectionId, thirdId); QCOMPARE(mClientConnectionCloseError, QString(TP_QT_ERROR_DISCONNECTED)); QCOMPARE(mClosedServerConnectionContact, mNewServerConnectionContact); conns = client->connections(); QCOMPARE(conns.size(), 1); QVERIFY(!conns.values().first().contains(thirdId)); QVERIFY(conns.values().first().contains(secondId)); QCOMPARE(conns.values().first().size(), 1); // Now, close the tube and verify we're signaled about that QVERIFY(connect(client.data(), SIGNAL(tubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)), SLOT(onClientTubeClosed(Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr,QString,QString)))); mClosedClientConnectionId = 0xdeadbeefU; QVERIFY(mClientClosedTube.isNull()); QCOMPARE(client->tubes().size(), 1); mOfferedTube->requestClose(); while (mClosedClientConnectionId == 0xdeadbeefU || mClientClosedTube.isNull()) { QVERIFY(mClientClosedTube.isNull()); // we should get first conn close, then tube close QCOMPARE(mLoop->exec(), 0); } QVERIFY(client->tubes().isEmpty()); QVERIFY(client->connections().isEmpty()); QCOMPARE(mClosedClientConnectionId, secondId); QCOMPARE(mClientConnectionCloseError, TP_QT_ERROR_ORPHANED); // parent tube died QCOMPARE(mClientClosedTube, mOfferedTube); QCOMPARE(mClientCloseError, QString(TP_QT_ERROR_CANCELLED)); // == local close request } void TestStreamTubeHandlers::cleanup() { cleanupImpl(); mRequestHints = ChannelRequestHints(); if (mRequestedTube && mRequestedTube->isValid()) { qDebug() << "waiting for the reqd tube to become invalidated"; QVERIFY(connect(mRequestedTube.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), mLoop, SLOT(quit()))); mRequestedTube->requestClose(); QCOMPARE(mLoop->exec(), 0); } mRequestedTube.reset(); mServerClosedTube.reset(); mNewServerConnectionContact.reset(); mClosedServerConnectionContact.reset(); mNewServerConnectionTube.reset(); mServerConnectionCloseTube.reset(); if (mOfferedTube && mOfferedTube->isValid()) { qDebug() << "waiting for the ofrd tube to become invalidated"; QVERIFY(connect(mOfferedTube.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), mLoop, SLOT(quit()))); mOfferedTube->requestClose(); QCOMPARE(mLoop->exec(), 0); } mOfferedTube.reset(); mClientClosedTube.reset(); mClientTcpAcceptTube.reset(); mClientUnixAcceptTube.reset(); mNewClientConnectionTube.reset(); mClosedClientConnectionTube.reset(); while (!mChanServices.empty()) { g_object_unref(mChanServices.back()); mChanServices.pop_back(); } mLoop->processEvents(); } void TestStreamTubeHandlers::cleanupTestCase() { mAM.reset(); mAcc.reset(); QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestStreamTubeHandlers) #include "_gen/stream-tube-handlers.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/contacts-capabilities.cpp0000664000175000017500000001120512470405660022017 0ustar jrjr#include #include #include #include #include #include #include #include #include using namespace Tp; class TestContactsCapabilities : public Test { Q_OBJECT public: TestContactsCapabilities(QObject *parent = 0) : Test(parent), mConn(0) { } private Q_SLOTS: void initTestCase(); void init(); void testCapabilities(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; }; void TestContactsCapabilities::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("contacts-capabilities"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "foo", NULL); QCOMPARE(mConn->connect(), true); } void TestContactsCapabilities::init() { initImpl(); } static void freeRccList(GPtrArray *rccs) { g_boxed_free(TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, rccs); } static void addTextChatClass(GPtrArray *classes, TpHandleType handle_type) { GHashTable *fixed = tp_asv_new( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, handle_type, NULL); const gchar * const allowed[] = { NULL }; GValueArray *arr = tp_value_array_build(2, TP_HASH_TYPE_STRING_VARIANT_MAP, fixed, G_TYPE_STRV, allowed, G_TYPE_INVALID); g_hash_table_unref(fixed); g_ptr_array_add(classes, arr); } static GHashTable *createContactCapabilities(TpHandle *handles) { GHashTable *capabilities = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify) freeRccList); /* Support private text chats */ GPtrArray *caps1 = g_ptr_array_sized_new(2); addTextChatClass(caps1, TP_HANDLE_TYPE_CONTACT); g_hash_table_insert(capabilities, GUINT_TO_POINTER(handles[0]), caps1); /* Support text chatrooms */ GPtrArray *caps2 = g_ptr_array_sized_new(1); g_hash_table_insert(capabilities, GUINT_TO_POINTER(handles[1]), caps2); /* Don't support anything */ GPtrArray *caps3 = g_ptr_array_sized_new(0); g_hash_table_insert(capabilities, GUINT_TO_POINTER(handles[2]), caps3); return capabilities; } void TestContactsCapabilities::testCapabilities() { ContactManagerPtr contactManager = mConn->client()->contactManager(); QVERIFY(contactManager->supportedFeatures().contains(Contact::FeatureCapabilities)); QStringList ids = QStringList() << QLatin1String("alice") << QLatin1String("bob") << QLatin1String("chris"); gboolean supportTextChat[] = { TRUE, FALSE, FALSE }; TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConn->service()), TP_HANDLE_TYPE_CONTACT); TpHandle handles[] = { 0, 0, 0 }; for (int i = 0; i < 3; i++) { handles[i] = tp_handle_ensure(serviceRepo, ids[i].toLatin1().constData(), NULL, NULL); } GHashTable *capabilities = createContactCapabilities(handles); tp_tests_contacts_connection_change_capabilities( TP_TESTS_CONTACTS_CONNECTION(mConn->service()), capabilities); g_hash_table_destroy(capabilities); QList contacts = mConn->contacts(ids, Contact::FeatureCapabilities); QCOMPARE(contacts.size(), ids.size()); for (int i = 0; i < contacts.size(); i++) { ContactPtr contact = contacts[i]; QCOMPARE(contact->requestedFeatures().contains(Contact::FeatureCapabilities), true); QCOMPARE(contact->actualFeatures().contains(Contact::FeatureCapabilities), true); QCOMPARE(contact->capabilities().textChats(), supportTextChat[i]); QCOMPARE(contact->capabilities().streamedMediaCalls(), false); QCOMPARE(contact->capabilities().streamedMediaAudioCalls(), false); QCOMPARE(contact->capabilities().streamedMediaVideoCalls(), false); QCOMPARE(contact->capabilities().streamedMediaVideoCallsWithAudio(), false); QCOMPARE(contact->capabilities().upgradingStreamedMediaCalls(), false); } } void TestContactsCapabilities::cleanup() { cleanupImpl(); } void TestContactsCapabilities::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestContactsCapabilities) #include "_gen/contacts-capabilities.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/account-connection-factory.cpp0000664000175000017500000003332212470405660023014 0ustar jrjr#include #include #include #include #include #include #include #include #include using namespace Tp; using namespace Tp::Client; // A really minimal Account implementation, totally not spec compliant outside the parts stressed by // this test class AccountAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Account") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QDBusObjectPath Connection READ Connection) Q_PROPERTY(QStringList Interfaces READ Interfaces) public: AccountAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent), mConnection(QLatin1String("/")) { } virtual ~AccountAdaptor() { } void setConnection(QString conn) { if (conn.isEmpty()) { conn = QLatin1String("/"); } mConnection = QDBusObjectPath(conn); QVariantMap props; props.insert(QLatin1String("Connection"), QVariant::fromValue(mConnection)); Q_EMIT AccountPropertyChanged(props); } public: // Properties inline QDBusObjectPath Connection() const { return mConnection; } inline QStringList Interfaces() const { return QStringList(); } Q_SIGNALS: // Signals void AccountPropertyChanged(const QVariantMap &properties); private: QDBusObjectPath mConnection; }; class TestAccountConnectionFactory : public Test { Q_OBJECT public: TestAccountConnectionFactory(QObject *parent = 0) : Test(parent), mConn1(0), mConn2(0), mDispatcher(0), mAccountAdaptor(0), mReceivedHaveConnection(0), mReceivedConn(0) { } protected Q_SLOTS: void onConnectionChanged(const Tp::ConnectionPtr &conn); void expectPropertyChange(const QString &property); private Q_SLOTS: void initTestCase(); void init(); void testIntrospectSeveralAccounts(); void testCreateAndIntrospect(); void testDefaultFactoryInitialConn(); void testReadifyingFactoryInitialConn(); void testSwitch(); void testQueuedSwitch(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn1, *mConn2; QObject *mDispatcher; QString mAccountBusName, mAccountPath; AccountAdaptor *mAccountAdaptor; AccountPtr mAccount; bool *mReceivedHaveConnection; QString *mReceivedConn; QStringList mReceivedConns; }; void TestAccountConnectionFactory::onConnectionChanged(const Tp::ConnectionPtr &conn) { qDebug() << "have connection:" << !conn.isNull(); if (mReceivedHaveConnection) { delete mReceivedHaveConnection; } mReceivedHaveConnection = new bool(!conn.isNull()); } void TestAccountConnectionFactory::expectPropertyChange(const QString &property) { if (property != QLatin1String("connection")) { // Not interesting return; } ConnectionPtr conn = mAccount->connection(); qDebug() << "connection changed:" << (conn ? conn->objectPath() : QLatin1String("none")); if (conn) { QCOMPARE(conn->objectPath(), conn->objectPath()); } if (mReceivedConn) { delete mReceivedConn; } mReceivedConn = new QString(conn ? conn->objectPath() : QLatin1String("")); mReceivedConns.push_back(conn ? conn->objectPath() : QLatin1String("")); } void TestAccountConnectionFactory::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("account-connection-factory"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn1 = new TestConnHelper(this, TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL); QCOMPARE(mConn1->isReady(), false); mConn2 = new TestConnHelper(this, TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me2@example.com", "protocol", "simple", NULL); QCOMPARE(mConn2->isReady(), false); mAccountBusName = TP_QT_IFACE_ACCOUNT_MANAGER; mAccountPath = QLatin1String("/org/freedesktop/Telepathy/Account/simple/simple/account"); } void TestAccountConnectionFactory::init() { initImpl(); mDispatcher = new QObject(this); mAccountAdaptor = new AccountAdaptor(mDispatcher); QDBusConnection bus = QDBusConnection::sessionBus(); QVERIFY(bus.registerService(mAccountBusName)); QVERIFY(bus.registerObject(mAccountPath, mDispatcher)); } // If this test fails, probably the code which tries to introspect the CD just once and then // continue with Account introspection has a bug void TestAccountConnectionFactory::testIntrospectSeveralAccounts() { QList ops; for (int i = 0; i < 10; i++) { AccountPtr acc = Account::create(mAccountBusName, mAccountPath); // This'll get the CD introspected in the middle (but won't finish any of the pending ops, // as they'll only finish in a singleShot in the next iter) // // One iteration to get readinessHelper to start introspecting, // the second to download the CD property // the third to get PendingVariant to actually emit the finished signal for it if (i == 5) { mLoop->processEvents(); mLoop->processEvents(); mLoop->processEvents(); } ops.push_back(acc->becomeReady()); } QVERIFY(connect(new PendingComposite(ops, SharedPtr()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); } // If this test fails, probably the mini-Account implements too little for the Account proxy to work // OR the Account proxy is completely broken :) void TestAccountConnectionFactory::testCreateAndIntrospect() { mAccount = Account::create(mAccountBusName, mAccountPath); QVERIFY(connect(mAccount->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); } void TestAccountConnectionFactory::testDefaultFactoryInitialConn() { mAccountAdaptor->setConnection(mConn1->objectPath()); mAccount = Account::create(mAccountBusName, mAccountPath); QVERIFY(connect(mAccount->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAccount->connection()->objectPath(), mConn1->objectPath()); QVERIFY(!mAccount->connection().isNull()); QCOMPARE(mAccount->connectionFactory()->features(), Features()); } void TestAccountConnectionFactory::testReadifyingFactoryInitialConn() { mAccountAdaptor->setConnection(mConn1->objectPath()); mAccount = Account::create(mAccountBusName, mAccountPath, ConnectionFactory::create(QDBusConnection::sessionBus(), Connection::FeatureCore), ChannelFactory::create(QDBusConnection::sessionBus())); QVERIFY(connect(mAccount->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mAccount->connection()->objectPath(), mConn1->objectPath()); ConnectionPtr conn = mAccount->connection(); QVERIFY(!conn.isNull()); QVERIFY(conn->isReady(Connection::FeatureCore)); QCOMPARE(mAccount->connectionFactory()->features(), Features(Connection::FeatureCore)); } void TestAccountConnectionFactory::testSwitch() { mAccount = Account::create(mAccountBusName, mAccountPath, ConnectionFactory::create(QDBusConnection::sessionBus(), Connection::FeatureCore), ChannelFactory::create(QDBusConnection::sessionBus())); QVERIFY(connect(mAccount->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mAccount->connection().isNull()); QVERIFY(connect(mAccount.data(), SIGNAL(connectionChanged(const Tp::ConnectionPtr &)), SLOT(onConnectionChanged(const Tp::ConnectionPtr &)))); QVERIFY(connect(mAccount.data(), SIGNAL(propertyChanged(QString)), SLOT(expectPropertyChange(QString)))); // Switch from none to conn 1 mAccountAdaptor->setConnection(mConn1->objectPath()); while (!mReceivedHaveConnection || !mReceivedConn) { mLoop->processEvents(); } QCOMPARE(*mReceivedHaveConnection, true); QCOMPARE(*mReceivedConn, mConn1->objectPath()); delete mReceivedHaveConnection; mReceivedHaveConnection = 0; delete mReceivedConn; mReceivedConn = 0; QCOMPARE(mAccount->connection()->objectPath(), mConn1->objectPath()); QVERIFY(!mAccount->connection().isNull()); ConnectionPtr conn = mAccount->connection(); QVERIFY(!conn.isNull()); QCOMPARE(conn->objectPath(), mConn1->objectPath()); QVERIFY(conn->isReady(Connection::FeatureCore)); // Switch from conn 1 to conn 2 mAccountAdaptor->setConnection(mConn2->objectPath()); while (!mReceivedConn) { mLoop->processEvents(); } QCOMPARE(*mReceivedConn, mConn2->objectPath()); delete mReceivedConn; mReceivedConn = 0; // connectionChanged() should have been emitted as it is a new connection QVERIFY(mReceivedHaveConnection); QVERIFY(!mAccount->connection().isNull()); QCOMPARE(mAccount->connection()->objectPath(), mConn2->objectPath()); conn = mAccount->connection(); QVERIFY(!conn.isNull()); QCOMPARE(conn->objectPath(), mConn2->objectPath()); QVERIFY(conn->isReady(Connection::FeatureCore)); // Switch from conn 2 to none mAccountAdaptor->setConnection(QString()); while (!mReceivedHaveConnection || !mReceivedConn) { mLoop->processEvents(); } QCOMPARE(*mReceivedConn, QString()); QCOMPARE(*mReceivedHaveConnection, false); QVERIFY(mAccount->connection().isNull()); } void TestAccountConnectionFactory::testQueuedSwitch() { mAccount = Account::create(mAccountBusName, mAccountPath, ConnectionFactory::create(QDBusConnection::sessionBus(), Connection::FeatureCore), ChannelFactory::create(QDBusConnection::sessionBus())); QVERIFY(connect(mAccount->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(mAccount->connection().isNull()); QVERIFY(connect(mAccount.data(), SIGNAL(propertyChanged(QString)), SLOT(expectPropertyChange(QString)))); // Switch a few times but don't give the proxy update machinery time to run mAccountAdaptor->setConnection(mConn1->objectPath()); mAccountAdaptor->setConnection(QString()); mAccountAdaptor->setConnection(mConn2->objectPath()); mAccountAdaptor->setConnection(QString()); mAccountAdaptor->setConnection(QString()); mAccountAdaptor->setConnection(QString()); mAccountAdaptor->setConnection(mConn2->objectPath()); mAccountAdaptor->setConnection(QString()); mAccountAdaptor->setConnection(mConn2->objectPath()); mAccountAdaptor->setConnection(mConn2->objectPath()); mAccountAdaptor->setConnection(mConn1->objectPath()); // We should get a total of 8 changes because some of them aren't actually any different while (mReceivedConns.size() < 8) { mLoop->processEvents(); } // To ensure it didn't go over, which might be possible if it handled two events in one iter QCOMPARE(mReceivedConns.size(), 8); // Ensure we got them in the correct order QCOMPARE(mReceivedConns, QStringList() << mConn1->objectPath() << QString() << mConn2->objectPath() << QString() << mConn2->objectPath() << QString() << mConn2->objectPath() << mConn1->objectPath()); // Check that the final state is correct QCOMPARE(mAccount->connection()->objectPath(), mConn1->objectPath()); QVERIFY(!mAccount->connection().isNull()); } void TestAccountConnectionFactory::cleanup() { mAccount.reset(); if (mReceivedHaveConnection) { delete mReceivedHaveConnection; mReceivedHaveConnection = 0; } if (mReceivedConn) { delete mReceivedConn; mReceivedConn = 0; } if (mAccountAdaptor) { delete mAccountAdaptor; mAccountAdaptor = 0; } if (mDispatcher) { delete mDispatcher; mDispatcher = 0; } mReceivedConns.clear(); cleanupImpl(); } void TestAccountConnectionFactory::cleanupTestCase() { if (mConn1) { QCOMPARE(mConn1->disconnect(), true); delete mConn1; } if (mConn2) { QCOMPARE(mConn2->disconnect(), true); delete mConn2; } cleanupTestCaseImpl(); } QTEST_MAIN(TestAccountConnectionFactory) #include "_gen/account-connection-factory.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/contact-factory.cpp0000664000175000017500000000367212470405660020663 0ustar jrjr#include #include #include #include #include #include #include using namespace Tp; class TestContactFactory : public Test { Q_OBJECT public: TestContactFactory(QObject *parent = 0) : Test(parent), mConn(0) { } private Q_SLOTS: void initTestCase(); void init(); void testConnectionSelfContactFeatures(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; }; void TestContactFactory::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("contact-factory"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create(Contact::FeatureAlias), TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "simple", NULL); QCOMPARE(mConn->isReady(), false); } void TestContactFactory::init() { initImpl(); } void TestContactFactory::testConnectionSelfContactFeatures() { QCOMPARE(mConn->client()->contactFactory()->features().size(), 1); QVERIFY(mConn->client()->contactFactory()->features().contains(Contact::FeatureAlias)); QCOMPARE(mConn->connect(Connection::FeatureSelfContact), true); ContactPtr selfContact = mConn->client()->selfContact(); QVERIFY(!selfContact.isNull()); QVERIFY(selfContact->requestedFeatures().contains(Contact::FeatureAlias)); } void TestContactFactory::cleanup() { cleanupImpl(); } void TestContactFactory::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestContactFactory) #include "_gen/contact-factory.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/conn-requests.cpp0000664000175000017500000001113712470405660020364 0ustar jrjr#include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include using namespace Tp; class TestConnRequests : public Test { Q_OBJECT public: TestConnRequests(QObject *parent = 0) : Test(parent), mConn(0), mHandle(0) { } protected Q_SLOTS: void expectPendingHandleFinished(Tp::PendingOperation*); void expectCreateChannelFinished(Tp::PendingOperation *); void expectEnsureChannelFinished(Tp::PendingOperation *); private Q_SLOTS: void initTestCase(); void init(); void testRequestHandle(); void testCreateChannel(); void testEnsureChannel(); void cleanup(); void cleanupTestCase(); private: TestConnHelper *mConn; QString mChanObjectPath; uint mHandle; }; void TestConnRequests::expectPendingHandleFinished(PendingOperation *op) { TEST_VERIFY_OP(op); PendingHandles *pending = qobject_cast(op); mHandle = pending->handles().at(0); mLoop->exit(0); } void TestConnRequests::expectCreateChannelFinished(PendingOperation* op) { TEST_VERIFY_OP(op); PendingChannel *pc = qobject_cast(op); ChannelPtr chan = pc->channel(); mChanObjectPath = chan->objectPath(); mLoop->exit(0); } void TestConnRequests::expectEnsureChannelFinished(PendingOperation* op) { TEST_VERIFY_OP(op); PendingChannel *pc = qobject_cast(op); ChannelPtr chan = pc->channel(); QCOMPARE(pc->yours(), false); QCOMPARE(chan->objectPath(), mChanObjectPath); mLoop->exit(0); } void TestConnRequests::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("conn-requests"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); mConn = new TestConnHelper(this, EXAMPLE_TYPE_ECHO_2_CONNECTION, "account", "me@example.com", "protocol", "contacts", NULL); QCOMPARE(mConn->connect(), true); } void TestConnRequests::init() { initImpl(); } void TestConnRequests::testRequestHandle() { // Test identifiers QStringList ids = QStringList() << QLatin1String("alice"); // Request handles for the identifiers and wait for the request to process PendingHandles *pending = mConn->client()->lowlevel()->requestHandles(Tp::HandleTypeContact, ids); QVERIFY(connect(pending, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectPendingHandleFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QVERIFY(disconnect(pending, SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(expectPendingHandleFinished(Tp::PendingOperation*)))); QVERIFY(mHandle != 0); } void TestConnRequests::testCreateChannel() { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), mHandle); QVERIFY(connect(mConn->client()->lowlevel()->createChannel(request), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectCreateChannelFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); } void TestConnRequests::testEnsureChannel() { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), mHandle); QVERIFY(connect(mConn->client()->lowlevel()->ensureChannel(request), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectEnsureChannelFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); } void TestConnRequests::cleanup() { cleanupImpl(); } void TestConnRequests::cleanupTestCase() { QCOMPARE(mConn->disconnect(), true); delete mConn; cleanupTestCaseImpl(); } QTEST_MAIN(TestConnRequests) #include "_gen/conn-requests.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/conn-basics.cpp0000664000175000017500000002141612470405660017756 0ustar jrjr#include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; class TestConnBasics : public Test { Q_OBJECT public: TestConnBasics(QObject *parent = 0) : Test(parent), mConnService(0) { } protected Q_SLOTS: void expectConnReady(Tp::ConnectionStatus); void expectConnInvalidated(); void expectPresenceAvailable(const Tp::SimplePresence &); void onRequestConnectFinished(Tp::PendingOperation *); private Q_SLOTS: void initTestCase(); void init(); void testBasics(); void testSimplePresence(); void cleanup(); void cleanupTestCase(); private: QString mConnName, mConnPath; TpTestsContactsConnection *mConnService; ConnectionPtr mConn; QList mStatuses; }; void TestConnBasics::expectConnReady(Tp::ConnectionStatus newStatus) { qDebug() << "connection changed to status" << newStatus; switch (newStatus) { case ConnectionStatusDisconnected: qWarning() << "Disconnected"; break; case ConnectionStatusConnecting: QCOMPARE(mConn->isReady(Connection::FeatureConnected), false); mStatuses << newStatus; qDebug() << "Connecting"; break; case ConnectionStatusConnected: QCOMPARE(mConn->isReady(Connection::FeatureConnected), true); mStatuses << newStatus; qDebug() << "Connected"; break; default: qWarning().nospace() << "What sort of status is " << newStatus << "?!"; break; } } void TestConnBasics::expectConnInvalidated() { qDebug() << "conn invalidated"; mLoop->exit(0); } void TestConnBasics::expectPresenceAvailable(const Tp::SimplePresence &presence) { if (presence.type == Tp::ConnectionPresenceTypeAvailable) { mLoop->exit(0); return; } mLoop->exit(1); } void TestConnBasics::onRequestConnectFinished(Tp::PendingOperation *op) { QCOMPARE(mConn->status(), ConnectionStatusConnected); QVERIFY(mStatuses.contains(ConnectionStatusConnected)); mLoop->exit(0); } void TestConnBasics::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("conn-basics"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); } void TestConnBasics::init() { initImpl(); gchar *name; gchar *connPath; GError *error = 0; mConnService = TP_TESTS_CONTACTS_CONNECTION(g_object_new( TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "contacts", NULL)); QVERIFY(mConnService != 0); QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService), "contacts", &name, &connPath, &error)); QVERIFY(error == 0); QVERIFY(name != 0); QVERIFY(connPath != 0); mConnName = QLatin1String(name); mConnPath = QLatin1String(connPath); g_free(name); g_free(connPath); mConn = Connection::create(mConnName, mConnPath, ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(mConn->isReady(), false); QVERIFY(connect(mConn.data(), SIGNAL(statusChanged(Tp::ConnectionStatus)), SLOT(expectConnReady(Tp::ConnectionStatus)))); qDebug() << "waiting connection to become connected"; PendingOperation *pr = mConn->becomeReady(Connection::FeatureConnected); QVERIFY(connect(pr, SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); PendingOperation *pc = mConn->lowlevel()->requestConnect(); QVERIFY(connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onRequestConnectFinished(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(pr->isFinished(), true); QCOMPARE(mLoop->exec(), 0); QCOMPARE(pc->isFinished(), true); QCOMPARE(mConn->isReady(Connection::FeatureConnected), true); qDebug() << "connection is now ready"; QVERIFY(disconnect(mConn.data(), SIGNAL(statusChanged(Tp::ConnectionStatus)), this, SLOT(expectConnReady(Tp::ConnectionStatus)))); } void TestConnBasics::testBasics() { QCOMPARE(static_cast(mConn->statusReason()), static_cast(ConnectionStatusReasonRequested)); } void TestConnBasics::testSimplePresence() { qDebug() << "Making SimplePresence ready"; Features features = Features() << Connection::FeatureSimplePresence; QCOMPARE(mConn->isReady(features), false); QVERIFY(connect(mConn->becomeReady(features), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(mConn->isReady(features), true); qDebug() << "SimplePresence ready"; qDebug() << "mConn->status:" << mConn->status(); const QStringList canSetNames = QStringList() << QLatin1String("available") << QLatin1String("busy") << QLatin1String("away"); const QStringList cantSetNames = QStringList() << QLatin1String("offline") << QLatin1String("unknown") << QLatin1String("error"); const QStringList expectedNames = canSetNames + cantSetNames; const ConnectionPresenceType expectedTypes[] = { ConnectionPresenceTypeAvailable, ConnectionPresenceTypeBusy, ConnectionPresenceTypeAway, ConnectionPresenceTypeOffline, ConnectionPresenceTypeUnknown, ConnectionPresenceTypeError }; SimpleStatusSpecMap statuses = mConn->lowlevel()->allowedPresenceStatuses(); Q_FOREACH (QString name, statuses.keys()) { QVERIFY(expectedNames.contains(name)); if (canSetNames.contains(name)) { QVERIFY(statuses[name].maySetOnSelf); QVERIFY(statuses[name].canHaveMessage); } else { QVERIFY(cantSetNames.contains(name)); QVERIFY(!statuses[name].maySetOnSelf); QVERIFY(!statuses[name].canHaveMessage); } QCOMPARE(statuses[name].type, static_cast(expectedTypes[expectedNames.indexOf(name)])); } QCOMPARE(mConn->lowlevel()->maxPresenceStatusMessageLength(), (uint) 512); } void TestConnBasics::cleanup() { if (mConn) { QVERIFY(mConn->isValid()); GHashTable *details = tp_asv_new( "debug-message", G_TYPE_STRING, "woo i'm going doooooown", "x-tpqt-test-rgba-herring-color", G_TYPE_UINT, 0xff0000ffU, NULL ); // Disconnect and wait for invalidation tp_base_connection_disconnect_with_dbus_error(TP_BASE_CONNECTION(mConnService), TP_QT_ERROR_CANCELLED.latin1(), details, TP_CONNECTION_STATUS_REASON_REQUESTED); g_hash_table_destroy(details); QVERIFY(connect(mConn.data(), SIGNAL(invalidated(Tp::DBusProxy *, const QString &, const QString &)), SLOT(expectConnInvalidated()))); QCOMPARE(mLoop->exec(), 0); QVERIFY(!mConn->isValid()); // Check that we got the connection error details QCOMPARE(static_cast(mConn->statusReason()), static_cast(ConnectionStatusReasonRequested)); QVERIFY(mConn->errorDetails().isValid()); QVERIFY(mConn->errorDetails().hasDebugMessage()); QCOMPARE(mConn->errorDetails().debugMessage(), QLatin1String("woo i'm going doooooown")); #if 0 // Not yet there QVERIFY(!mConn->errorDetails().hasExpectedHostname()); QVERIFY(!mConn->errorDetails().hasCertificateHostname()); #endif QVERIFY(mConn->errorDetails().allDetails().contains( QLatin1String("x-tpqt-test-rgba-herring-color"))); QCOMPARE(qdbus_cast(mConn->errorDetails().allDetails().value( QLatin1String("x-tpqt-test-rgba-herring-color"))), 0xff0000ffU); processDBusQueue(mConn.data()); mConn.reset(); } if (mConnService != 0) { g_object_unref(mConnService); mConnService = 0; } cleanupImpl(); } void TestConnBasics::cleanupTestCase() { cleanupTestCaseImpl(); } QTEST_MAIN(TestConnBasics) #include "_gen/conn-basics.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus/simple-observer.cpp0000664000175000017500000007122212470405660020675 0ustar jrjr#include #include #include #include #include #include #include #include #define TP_QT_ENABLE_LOWLEVEL_API #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; using namespace Tp::Client; class TestSimpleObserver; namespace { QList channels(const QList &channels) { QList ret; Q_FOREACH (const TextChannelPtr &channel, channels) { ret << channel; } return ret; } QList channels(const QList &channels) { QList ret; Q_FOREACH (const StreamedMediaChannelPtr &channel, channels) { ret << channel; } return ret; } } class AccountAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Account") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(QDBusObjectPath Connection READ Connection) Q_PROPERTY(QStringList Interfaces READ Interfaces) public: AccountAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent), mConnection(QLatin1String("/")) { } virtual ~AccountAdaptor() { } void setConnection(QString conn) { if (conn.isEmpty()) { conn = QLatin1String("/"); } mConnection = QDBusObjectPath(conn); QVariantMap props; props.insert(QLatin1String("Connection"), QVariant::fromValue(mConnection)); Q_EMIT AccountPropertyChanged(props); } public: // Properties inline QDBusObjectPath Connection() const { return mConnection; } inline QStringList Interfaces() const { return QStringList(); } Q_SIGNALS: // Signals void AccountPropertyChanged(const QVariantMap &properties); private: QDBusObjectPath mConnection; }; class Dispatcher : public QObject, public QDBusContext { Q_OBJECT; public: Dispatcher(QObject *parent) : QObject(parent) { } ~Dispatcher() { } }; class TestSimpleObserver : public Test { Q_OBJECT public: TestSimpleObserver(QObject *parent = 0) : Test(parent), mChannelsCount(0), mSMChannelsCount(0) { std::memset(mMessagesChanServices, 0, sizeof(mMessagesChanServices) / sizeof(ExampleEcho2Channel*)); std::memset(mCallableChanServices, 0, sizeof(mCallableChanServices) / sizeof(ExampleCallableMediaChannel*)); } protected Q_SLOTS: void onObserverNewChannels(const QList &channels); void onObserverChannelInvalidated(const Tp::ChannelPtr &channel, const QString &errorName, const QString &errorMessage); void onObserverStreamedMediaCallStarted( const Tp::StreamedMediaChannelPtr &channel); void onObserverStreamedMediaCallEnded( const Tp::StreamedMediaChannelPtr &channel, const QString &errorMessage, const QString &errorName); private Q_SLOTS: void initTestCase(); void init(); void testObserverRegistration(); void testCrossTalk(); void cleanup(); void cleanupTestCase(); private: QMap ourObservers(); AccountPtr mAccounts[2]; struct ConnInfo { ConnInfo() : connService(0), baseConnService(0), contactRepo(0) { } TpTestsContactsConnection *connService; TpBaseConnection *baseConnService; ConnectionPtr conn; TpHandleRepoIface *contactRepo; }; ConnInfo mConns[2]; QStringList mContacts; ExampleEcho2Channel *mMessagesChanServices[2]; TextChannelPtr mTextChans[2]; ExampleCallableMediaChannel *mCallableChanServices[2]; StreamedMediaChannelPtr mSMChans[2]; int mChannelsCount; int mSMChannelsCount; }; void TestSimpleObserver::onObserverNewChannels(const QList &channels) { QVERIFY(channels.size() == 1); mChannelsCount += channels.size(); } void TestSimpleObserver::onObserverChannelInvalidated(const Tp::ChannelPtr &channel, const QString &errorName, const QString &errorMessage) { QVERIFY(!channel.isNull()); mChannelsCount -= 1; } void TestSimpleObserver::onObserverStreamedMediaCallStarted( const Tp::StreamedMediaChannelPtr &channel) { QVERIFY(!channel.isNull()); mSMChannelsCount++; } void TestSimpleObserver::onObserverStreamedMediaCallEnded(const Tp::StreamedMediaChannelPtr &channel, const QString &errorMessage, const QString &errorName) { QVERIFY(!channel.isNull()); mSMChannelsCount--; } void TestSimpleObserver::initTestCase() { initTestCaseImpl(); g_type_init(); g_set_prgname("simple-observer"); tp_debug_set_flags("all"); dbus_g_bus_get(DBUS_BUS_STARTER, 0); QDBusConnection bus = QDBusConnection::sessionBus(); QString channelDispatcherBusName = TP_QT_IFACE_CHANNEL_DISPATCHER; QString channelDispatcherPath = QLatin1String("/org/freedesktop/Telepathy/ChannelDispatcher"); Dispatcher *dispatcher = new Dispatcher(this); QVERIFY(bus.registerService(channelDispatcherBusName)); QVERIFY(bus.registerObject(channelDispatcherPath, dispatcher)); mContacts << QLatin1String("alice") << QLatin1String("bob"); // Create 2 accounts to be used by the tests: // - each account contains a connection, a text channel and a SM channel setup: // - the channels for the first account have alice as target and; // - the channels for the second account have bob as target for (int i = 0; i < 2; ++i) { // setup account QString accountBusName = TP_QT_IFACE_ACCOUNT_MANAGER; QString accountPath = QLatin1String("/org/freedesktop/Telepathy/Account/simple/account/") + QString::number(i); QObject *adaptorObject = new QObject(this); AccountAdaptor *accountAdaptor = new AccountAdaptor(adaptorObject); QVERIFY(bus.registerService(accountBusName)); QVERIFY(bus.registerObject(accountPath, adaptorObject)); AccountPtr acc = Account::create(accountBusName, accountPath); QVERIFY(connect(acc->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(acc->isReady(), true); QCOMPARE(acc->supportsRequestHints(), false); QCOMPARE(acc->requestsSucceedWithChannel(), false); mAccounts[i] = acc; // setup conn TpTestsContactsConnection *connService = TP_TESTS_CONTACTS_CONNECTION( g_object_new(TP_TESTS_TYPE_CONTACTS_CONNECTION, "account", "me@example.com", "protocol", "example", NULL)); QVERIFY(connService != 0); TpBaseConnection *baseConnService = TP_BASE_CONNECTION(connService); QVERIFY(baseConnService != 0); gchar *connName, *connPath; GError *error = NULL; QString name(QLatin1String("example") + QString::number(i)); QVERIFY(tp_base_connection_register(baseConnService, name.toLatin1().constData(), &connName, &connPath, &error)); QVERIFY(error == 0); QVERIFY(connName != 0); QVERIFY(connPath != 0); ConnectionPtr conn = Connection::create(QLatin1String(connName), QLatin1String(connPath), ChannelFactory::create(QDBusConnection::sessionBus()), ContactFactory::create()); QCOMPARE(conn->isReady(), false); accountAdaptor->setConnection(QLatin1String(connPath)); QVERIFY(connect(conn->lowlevel()->requestConnect(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(expectSuccessfulCall(Tp::PendingOperation*)))); QCOMPARE(mLoop->exec(), 0); QCOMPARE(conn->isReady(), true); QCOMPARE(conn->status(), ConnectionStatusConnected); TpHandleRepoIface *contactRepo = tp_base_connection_get_handles(baseConnService, TP_HANDLE_TYPE_CONTACT); mConns[i].connService = connService; mConns[i].baseConnService = baseConnService; mConns[i].conn = conn; mConns[i].contactRepo = contactRepo; // setup channels guint handle = tp_handle_ensure(contactRepo, mContacts[i].toLatin1().constData(), 0, 0); QString messagesChanPath = QLatin1String(connPath) + QLatin1String("/MessagesChannel/") + QString::number(i); mMessagesChanServices[i] = EXAMPLE_ECHO_2_CHANNEL(g_object_new( EXAMPLE_TYPE_ECHO_2_CHANNEL, "connection", connService, "object-path", messagesChanPath.toLatin1().constData(), "handle", handle, NULL)); QVariantMap immutableProperties; immutableProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), mContacts[i]); mTextChans[i] = TextChannel::create(conn, messagesChanPath, immutableProperties); QVERIFY(connect(mTextChans[i]->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); QString callableChanPath = QLatin1String(connPath) + QLatin1String("/CallableChannel/") + QString::number(i); mCallableChanServices[i] = EXAMPLE_CALLABLE_MEDIA_CHANNEL(g_object_new( EXAMPLE_TYPE_CALLABLE_MEDIA_CHANNEL, "connection", connService, "object-path", callableChanPath.toLatin1().constData(), "handle", handle, NULL)); immutableProperties.clear(); immutableProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), mContacts[i]); mSMChans[i] = StreamedMediaChannel::create(conn, callableChanPath, immutableProperties); QVERIFY(connect(mSMChans[i]->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(expectSuccessfulCall(Tp::PendingOperation *)))); QCOMPARE(mLoop->exec(), 0); g_free(connName); g_free(connPath); } } void TestSimpleObserver::init() { initImpl(); } void TestSimpleObserver::testObserverRegistration() { QVERIFY(ourObservers().isEmpty()); QList observers; QList textObservers; QList callObservers; int numRegisteredObservers = 0; // Observers should be shared by bus and channel class, meaning that // the following code should register only 4 observers: // - one for text chat rooms // - one for text chats // - one for incoming/outgoing calls // - one for incoming calls (incoming) // // The Simple*Observer instances are added to the lists observers/textObservers/callObservers, // so they don't get deleted (refcount == 0) when out of scope for (int i = 0; i < 2; ++i) { AccountPtr acc = mAccounts[i]; for (int j = 0; j < 2; ++j) { QString contact = mContacts[j]; if (i == 0 && j == 0) { numRegisteredObservers = 1; } // on first run the following code should register an observer for text chat rooms, // on consecutive runs it should use the already registered observer for text chat rooms SimpleObserverPtr observer = SimpleObserver::create(acc, ChannelClassSpec::textChatroom(), contact); QCOMPARE(observer->account(), acc); QVERIFY(observer->channelFilter().size() == 1); QVERIFY(observer->channelFilter().contains(ChannelClassSpec::textChatroom())); QCOMPARE(observer->contactIdentifier(), contact); QVERIFY(observer->extraChannelFeatures().isEmpty()); QVERIFY(observer->channels().isEmpty()); observers.append(observer); QCOMPARE(ourObservers().size(), numRegisteredObservers); // the following code should always reuse the observer for text chat rooms already // created. QList extraChannelFeatures; extraChannelFeatures.append(QPair( ChannelClassSpec::textChatroom(), Channel::FeatureCore)); observer = SimpleObserver::create(acc, ChannelClassSpec::textChatroom(), contact, extraChannelFeatures); QCOMPARE(observer->account(), acc); QVERIFY(observer->channelFilter().size() == 1); QVERIFY(observer->channelFilter().contains(ChannelClassSpec::textChatroom())); QCOMPARE(observer->contactIdentifier(), contact); QCOMPARE(observer->extraChannelFeatures(), extraChannelFeatures); QVERIFY(observer->channels().isEmpty()); observers.append(observer); QCOMPARE(ourObservers().size(), numRegisteredObservers); if (i == 0 && j == 0) { numRegisteredObservers = 2; } // on first run the following code should register an observer for text chats, // on consecutive runs it should use the already registered observer for text chats SimpleTextObserverPtr textObserver = SimpleTextObserver::create(acc, contact); QCOMPARE(textObserver->account(), acc); QCOMPARE(textObserver->contactIdentifier(), contact); QVERIFY(textObserver->textChats().isEmpty()); textObservers.append(textObserver); QCOMPARE(ourObservers().size(), numRegisteredObservers); // the following code should always reuse the observer for text chats already // created. textObserver = SimpleTextObserver::create(acc, contact); QCOMPARE(textObserver->account(), acc); QCOMPARE(textObserver->contactIdentifier(), contact); QVERIFY(textObserver->textChats().isEmpty()); textObservers.append(textObserver); QCOMPARE(ourObservers().size(), numRegisteredObservers); if (i == 0 && j == 0) { numRegisteredObservers = 3; } // on first run the following code should register an observer for incoming/outgoing // calls, on consecutive runs it should use the already registered observer for // incoming/outgoing calls SimpleCallObserverPtr callObserver = SimpleCallObserver::create(acc, contact); QCOMPARE(callObserver->account(), acc); QCOMPARE(callObserver->contactIdentifier(), contact); QCOMPARE(callObserver->direction(), SimpleCallObserver::CallDirectionBoth); QVERIFY(callObserver->streamedMediaCalls().isEmpty()); callObservers.append(callObserver); QCOMPARE(ourObservers().size(), numRegisteredObservers); if (i == 0 && j == 0) { numRegisteredObservers = 4; } // on first run the following code should register an observer for incoming calls, // on consecutive runs it should use the already registered observer for incoming calls callObserver = SimpleCallObserver::create(acc, contact, SimpleCallObserver::CallDirectionIncoming); QCOMPARE(callObserver->account(), acc); QCOMPARE(callObserver->contactIdentifier(), contact); QCOMPARE(callObserver->direction(), SimpleCallObserver::CallDirectionIncoming); QVERIFY(callObserver->streamedMediaCalls().isEmpty()); callObservers.append(callObserver); QCOMPARE(ourObservers().size(), numRegisteredObservers); } } // deleting all SimpleObserver instances (text chat room) should unregister 1 observer observers.clear(); QCOMPARE(ourObservers().size(), 3); // deleting all SimpleTextObserver instances should unregister 1 observer textObservers.clear(); QCOMPARE(ourObservers().size(), 2); // deleting all SimpleCallObserver instances should unregister 2 observers callObservers.clear(); QVERIFY(ourObservers().isEmpty()); } void TestSimpleObserver::testCrossTalk() { SimpleObserverPtr observers[2]; SimpleTextObserverPtr textObservers[2]; SimpleTextObserverPtr textObserversNoContact[2]; SimpleCallObserverPtr callObservers[2]; SimpleCallObserverPtr callObserversNoContact[2]; for (int i = 0; i < 2; ++i) { AccountPtr acc = mAccounts[i]; observers[i] = SimpleObserver::create(acc, ChannelClassSpec::textChat(), mContacts[i]); QVERIFY(connect(observers[i].data(), SIGNAL(newChannels(QList)), SLOT(onObserverNewChannels(QList)))); QVERIFY(connect(observers[i].data(), SIGNAL(channelInvalidated(Tp::ChannelPtr,QString,QString)), SLOT(onObserverChannelInvalidated(Tp::ChannelPtr,QString,QString)))); // SimpleTextObserver::messageSent/Received is already tested in contact-messenger test textObservers[i] = SimpleTextObserver::create(acc, mContacts[i]); textObserversNoContact[i] = SimpleTextObserver::create(acc); callObservers[i] = SimpleCallObserver::create(acc, mContacts[i]); QVERIFY(connect(callObservers[i].data(), SIGNAL(streamedMediaCallStarted(Tp::StreamedMediaChannelPtr)), SLOT(onObserverStreamedMediaCallStarted(Tp::StreamedMediaChannelPtr)))); QVERIFY(connect(callObservers[i].data(), SIGNAL(streamedMediaCallEnded(Tp::StreamedMediaChannelPtr,QString,QString)), SLOT(onObserverStreamedMediaCallEnded(Tp::StreamedMediaChannelPtr,QString,QString)))); callObserversNoContact[i] = SimpleCallObserver::create(acc); } QMap ourObserversMap = ourObservers(); QMap::const_iterator it = ourObserversMap.constBegin(); QMap::const_iterator end = ourObserversMap.constEnd(); for (; it != end; ++it) { ClientObserverInterface *observerIface = new ClientObserverInterface( it.key(), it.value(), this); ChannelClassList observerFilter; if (!waitForProperty(observerIface->requestPropertyObserverChannelFilter(), &observerFilter)) { continue; } for (int i = 0; i < 2; ++i) { Q_FOREACH (const ChannelClassSpec &spec, observerFilter) { // only call ObserveChannels for text chat channels on observers that support text // chat if (spec.isSubsetOf(ChannelClassSpec::textChat())) { ChannelDetails textChan = { QDBusObjectPath(mTextChans[i]->objectPath()), mTextChans[i]->immutableProperties() }; observerIface->ObserveChannels( QDBusObjectPath(mAccounts[i]->objectPath()), QDBusObjectPath(mTextChans[i]->connection()->objectPath()), ChannelDetailsList() << textChan, QDBusObjectPath(QLatin1String("/")), Tp::ObjectPathList(), QVariantMap()); break; } } Q_FOREACH (const ChannelClassSpec &spec, observerFilter) { // only call ObserveChannels for SM channels on observers that support SM channels if (spec.isSubsetOf(ChannelClassSpec::streamedMediaCall())) { ChannelDetails smChan = { QDBusObjectPath(mSMChans[i]->objectPath()), mSMChans[i]->immutableProperties() }; observerIface->ObserveChannels( QDBusObjectPath(mAccounts[i]->objectPath()), QDBusObjectPath(mSMChans[i]->connection()->objectPath()), ChannelDetailsList() << smChan, QDBusObjectPath(QLatin1String("/")), Tp::ObjectPathList(), QVariantMap()); break; } } } } // due to QtDBus limitation, we cannot wait for ObserveChannels to finish properly before // proceeding, so we have to wait till all observers receive the channels while (observers[0]->channels().isEmpty() || observers[1]->channels().isEmpty() || textObservers[0]->textChats().isEmpty() || textObservers[1]->textChats().isEmpty() || textObserversNoContact[0]->textChats().isEmpty() || textObserversNoContact[1]->textChats().isEmpty() || callObservers[0]->streamedMediaCalls().isEmpty() || callObservers[1]->streamedMediaCalls().isEmpty() || callObserversNoContact[0]->streamedMediaCalls().isEmpty() || callObserversNoContact[1]->streamedMediaCalls().isEmpty()) { mLoop->processEvents(); } QCOMPARE(mChannelsCount, 2); QCOMPARE(mSMChannelsCount, 2); QCOMPARE(observers[0]->channels().size(), 1); QCOMPARE(textObservers[0]->textChats().size(), 1); QCOMPARE(textObserversNoContact[0]->textChats().size(), 1); QCOMPARE(callObservers[0]->streamedMediaCalls().size(), 1); QCOMPARE(callObserversNoContact[0]->streamedMediaCalls().size(), 1); QCOMPARE(observers[1]->channels().size(), 1); QCOMPARE(textObservers[1]->textChats().size(), 1); QCOMPARE(textObserversNoContact[1]->textChats().size(), 1); QCOMPARE(callObservers[1]->streamedMediaCalls().size(), 1); QCOMPARE(callObserversNoContact[1]->streamedMediaCalls().size(), 1); QVERIFY(textObservers[0]->textChats() != textObservers[1]->textChats()); QVERIFY(textObserversNoContact[0]->textChats() != textObserversNoContact[1]->textChats()); QCOMPARE(textObservers[0]->textChats(), textObserversNoContact[0]->textChats()); QCOMPARE(textObservers[1]->textChats(), textObserversNoContact[1]->textChats()); QVERIFY(callObservers[0]->streamedMediaCalls() != callObservers[1]->streamedMediaCalls()); QVERIFY(callObservers[0]->streamedMediaCalls() != callObserversNoContact[1]->streamedMediaCalls()); QCOMPARE(callObservers[0]->streamedMediaCalls(), callObserversNoContact[0]->streamedMediaCalls()); QCOMPARE(callObservers[1]->streamedMediaCalls(), callObserversNoContact[1]->streamedMediaCalls()); QCOMPARE(observers[0]->channels(), channels(textObservers[0]->textChats())); QVERIFY(observers[0]->channels() != channels(textObservers[1]->textChats())); QVERIFY(observers[0]->channels() != channels(callObservers[0]->streamedMediaCalls())); QVERIFY(observers[0]->channels() != channels(callObservers[1]->streamedMediaCalls())); QVERIFY(observers[1]->channels() != channels(textObservers[0]->textChats())); QCOMPARE(observers[1]->channels(), channels(textObservers[1]->textChats())); QVERIFY(observers[1]->channels() != channels(callObservers[0]->streamedMediaCalls())); QVERIFY(observers[1]->channels() != channels(callObservers[1]->streamedMediaCalls())); QVERIFY(channels(callObservers[0]->streamedMediaCalls()) != channels(textObservers[0]->textChats())); QVERIFY(channels(callObservers[0]->streamedMediaCalls()) != channels(textObservers[1]->textChats())); QVERIFY(channels(callObservers[1]->streamedMediaCalls()) != channels(textObservers[0]->textChats())); QVERIFY(channels(callObservers[1]->streamedMediaCalls()) != channels(textObservers[1]->textChats())); QCOMPARE(observers[0]->channels().first()->objectPath(), mTextChans[0]->objectPath()); QCOMPARE(observers[1]->channels().first()->objectPath(), mTextChans[1]->objectPath()); QCOMPARE(textObservers[0]->textChats().first()->objectPath(), mTextChans[0]->objectPath()); QCOMPARE(textObservers[1]->textChats().first()->objectPath(), mTextChans[1]->objectPath()); QCOMPARE(textObserversNoContact[0]->textChats().first()->objectPath(), mTextChans[0]->objectPath()); QCOMPARE(textObserversNoContact[1]->textChats().first()->objectPath(), mTextChans[1]->objectPath()); QCOMPARE(callObservers[0]->streamedMediaCalls().first()->objectPath(), mSMChans[0]->objectPath()); QCOMPARE(callObservers[1]->streamedMediaCalls().first()->objectPath(), mSMChans[1]->objectPath()); // invalidate channels for (int i = 0; i < 2; ++i) { if (mMessagesChanServices[i] != 0) { g_object_unref(mMessagesChanServices[i]); mMessagesChanServices[i] = 0; } if (mCallableChanServices[i] != 0) { g_object_unref(mCallableChanServices[i]); mCallableChanServices[i] = 0; } } while (!observers[0]->channels().isEmpty() || !observers[1]->channels().isEmpty() || !textObservers[0]->textChats().isEmpty() || !textObservers[1]->textChats().isEmpty() || !textObserversNoContact[0]->textChats().isEmpty() || !textObserversNoContact[1]->textChats().isEmpty() || !callObservers[0]->streamedMediaCalls().isEmpty() || !callObservers[1]->streamedMediaCalls().isEmpty() || !callObserversNoContact[0]->streamedMediaCalls().isEmpty() || !callObserversNoContact[1]->streamedMediaCalls().isEmpty()) { mLoop->processEvents(); } QCOMPARE(mChannelsCount, 0); QCOMPARE(mSMChannelsCount, 0); } void TestSimpleObserver::cleanup() { cleanupImpl(); } void TestSimpleObserver::cleanupTestCase() { for (int i = 0; i < 2; ++i) { if (!mConns[i].conn) { continue; } if (mConns[i].conn->requestedFeatures().contains(Connection::FeatureCore)) { QVERIFY(mConns[i].connService != NULL); if (TP_BASE_CONNECTION(mConns[i].connService)->status != TP_CONNECTION_STATUS_DISCONNECTED) { tp_base_connection_change_status(TP_BASE_CONNECTION(mConns[i].connService), TP_CONNECTION_STATUS_DISCONNECTED, TP_CONNECTION_STATUS_REASON_REQUESTED); } while (mConns[i].conn->isValid()) { mLoop->processEvents(); } } mConns[i].conn.reset(); mTextChans[i].reset(); mSMChans[i].reset(); if (mMessagesChanServices[i] != 0) { g_object_unref(mMessagesChanServices[i]); mMessagesChanServices[i] = 0; } if (mCallableChanServices[i] != 0) { g_object_unref(mCallableChanServices[i]); mCallableChanServices[i] = 0; } if (mConns[i].connService != 0) { mConns[i].baseConnService = 0; g_object_unref(mConns[i].connService); mConns[i].connService = 0; } } cleanupTestCaseImpl(); } QMap TestSimpleObserver::ourObservers() { QStringList registeredNames = QDBusConnection::sessionBus().interface()->registeredServiceNames(); QMap observers; Q_FOREACH (QString name, registeredNames) { if (!name.startsWith(QLatin1String("org.freedesktop.Telepathy.Client.TpQtSO"))) { continue; } if (QDBusConnection::sessionBus().interface()->serviceOwner(name).value() != QDBusConnection::sessionBus().baseService()) { continue; } QString path = QLatin1Char('/') + name; path.replace(QLatin1Char('.'), QLatin1Char('/')); ClientInterface client(name, path); QStringList ifaces; if (!waitForProperty(client.requestPropertyInterfaces(), &ifaces)) { continue; } if (!ifaces.contains(TP_QT_IFACE_CLIENT_OBSERVER)) { continue; } observers.insert(name, path); } return observers; } QTEST_MAIN(TestSimpleObserver) #include "_gen/simple-observer.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/CMakeLists.txt0000664000175000017500000000424612470405660016660 0ustar jrjrfind_program(SH sh) set(test_environment " export abs_top_builddir=${CMAKE_BINARY_DIR} export abs_top_srcdir=${CMAKE_SOURCE_DIR} export XDG_DATA_HOME=${CMAKE_SOURCE_DIR}/tests export XDG_DATA_DIRS=${CMAKE_BINARY_DIR}/tests ") # Add targets for callgrind and valgrind tests add_custom_target(check-valgrind) add_custom_target(check-callgrind) # Add targets for lcov reports add_custom_target(lcov-reset lcov --directory ${CMAKE_BINARY_DIR} --zerocounters COMMAND find ${CMAKE_BINARY_DIR} -name '*.gcda' -exec rm -f '{}' ';' || true COMMENT "Cleaning lcov files") add_custom_target(lcov-check make test || true COMMAND lcov --directory ${CMAKE_BINARY_DIR} --capture --output-file ${CMAKE_BINARY_DIR}/lcov.info && mkdir ${CMAKE_BINARY_DIR}/lcov.html || true && genhtml --title ${PACKAGE_NAME} --output-directory ${CMAKE_BINARY_DIR}/lcov.html ${CMAKE_BINARY_DIR}/lcov.info COMMENT "Generating lcov report in file://${CMAKE_BINARY_DIR}/lcov.html/index.html" WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests) add_dependencies(lcov-check lcov-reset) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/runGenericTest.sh "${test_environment} $@") file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/_gen) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_COVERAGE_FLAGS}") tpqt_add_generic_unit_test(Capabilities capabilities telepathy-qt-test-backdoors) tpqt_add_generic_unit_test(Callbacks callbacks) tpqt_add_generic_unit_test(ChannelClassSpec channel-class-spec) tpqt_add_generic_unit_test(Features features) tpqt_add_generic_unit_test(KeyFile key-file telepathy-qt-test-backdoors) tpqt_add_generic_unit_test(ManagerFile manager-file telepathy-qt-test-backdoors) tpqt_add_generic_unit_test(Presence presence) tpqt_add_generic_unit_test(Profile profile) tpqt_add_generic_unit_test(Ptr ptr) tpqt_add_generic_unit_test(RCCSpec rccspec) tpqt_add_generic_unit_test(FileTransferChannelCreationProperties file-transfer-channel-creation-properties) add_subdirectory(dbus-1) add_subdirectory(dbus) add_subdirectory(lib) telepathy-qt-0.9.6~git1/tests/callbacks.cpp0000664000175000017500000001634412470405660016545 0ustar jrjr#include #include using namespace Tp; class TestCallbacks : public QObject { Q_OBJECT private Q_SLOTS: void testMemFun(); void testPtrFun(); }; struct MyCallbacks { MyCallbacks() { reset(); } void testVV() { mVVCalled++; } void testVI1(int a1) { QCOMPARE(a1, 1); mVI1Called++; } void testVI2(int a1, int a2) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); mVI2Called++; } void testVI3(int a1, int a2, int a3) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); mVI3Called++; } void testVI4(int a1, int a2, int a3, int a4) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); QCOMPARE(a4, 4); mVI4Called++; } void testVI5(int a1, int a2, int a3, int a4, int a5) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); QCOMPARE(a4, 4); QCOMPARE(a5, 5); mVI5Called++; } void testVI6(int a1, int a2, int a3, int a4, int a5, int a6) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); QCOMPARE(a4, 4); QCOMPARE(a5, 5); QCOMPARE(a6, 6); mVI6Called++; } void testVI7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); QCOMPARE(a4, 4); QCOMPARE(a5, 5); QCOMPARE(a6, 6); QCOMPARE(a7, 7); mVI7Called++; } void reset() { mVVCalled = false; mVI1Called = false; mVI2Called = false; mVI3Called = false; mVI4Called = false; mVI5Called = false; mVI6Called = false; mVI7Called = false; } void verifyCalled(bool vv, bool vi1, bool vi2, bool vi3, bool vi4, bool vi5, bool vi6, bool vi7) { QCOMPARE(mVVCalled, vv); QCOMPARE(mVI1Called, vi1); QCOMPARE(mVI2Called, vi2); QCOMPARE(mVI3Called, vi3); QCOMPARE(mVI4Called, vi4); QCOMPARE(mVI5Called, vi5); QCOMPARE(mVI6Called, vi6); QCOMPARE(mVI7Called, vi7); } bool mVVCalled; bool mVI1Called; bool mVI2Called; bool mVI3Called; bool mVI4Called; bool mVI5Called; bool mVI6Called; bool mVI7Called; }; namespace { bool mVVCalled; bool mVI1Called; bool mVI2Called; bool mVI3Called; bool mVI4Called; bool mVI5Called; bool mVI6Called; bool mVI7Called; void testVV() { mVVCalled++; } void testVI1(int a1) { QCOMPARE(a1, 1); mVI1Called++; } void testVI2(int a1, int a2) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); mVI2Called++; } void testVI3(int a1, int a2, int a3) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); mVI3Called++; } void testVI4(int a1, int a2, int a3, int a4) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); QCOMPARE(a4, 4); mVI4Called++; } void testVI5(int a1, int a2, int a3, int a4, int a5) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); QCOMPARE(a4, 4); QCOMPARE(a5, 5); mVI5Called++; } void testVI6(int a1, int a2, int a3, int a4, int a5, int a6) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); QCOMPARE(a4, 4); QCOMPARE(a5, 5); QCOMPARE(a6, 6); mVI6Called++; } void testVI7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { QCOMPARE(a1, 1); QCOMPARE(a2, 2); QCOMPARE(a3, 3); QCOMPARE(a4, 4); QCOMPARE(a5, 5); QCOMPARE(a6, 6); QCOMPARE(a7, 7); mVI7Called++; } void reset() { mVVCalled = false; mVI1Called = false; mVI2Called = false; mVI3Called = false; mVI4Called = false; mVI5Called = false; mVI6Called = false; mVI7Called = false; } void verifyCalled(bool vv, bool vi1, bool vi2, bool vi3, bool vi4, bool vi5, bool vi6, bool vi7) { QCOMPARE(mVVCalled, vv); QCOMPARE(mVI1Called, vi1); QCOMPARE(mVI2Called, vi2); QCOMPARE(mVI3Called, vi3); QCOMPARE(mVI4Called, vi4); QCOMPARE(mVI5Called, vi5); QCOMPARE(mVI6Called, vi6); QCOMPARE(mVI7Called, vi7); } } void TestCallbacks::testMemFun() { MyCallbacks cbs; Callback0 cbVV = memFun(&cbs, &MyCallbacks::testVV); cbVV(); cbs.verifyCalled(true, false, false, false, false, false, false, false); cbs.reset(); Callback1 cbVI1 = memFun(&cbs, &MyCallbacks::testVI1); cbVI1(1); cbs.verifyCalled(false, true, false, false, false, false, false, false); cbs.reset(); Callback2 cbVI2 = memFun(&cbs, &MyCallbacks::testVI2); cbVI2(1, 2); cbs.verifyCalled(false, false, true, false, false, false, false, false); cbs.reset(); Callback3 cbVI3 = memFun(&cbs, &MyCallbacks::testVI3); cbVI3(1, 2, 3); cbs.verifyCalled(false, false, false, true, false, false, false, false); cbs.reset(); Callback4 cbVI4 = memFun(&cbs, &MyCallbacks::testVI4); cbVI4(1, 2, 3, 4); cbs.verifyCalled(false, false, false, false, true, false, false, false); cbs.reset(); Callback5 cbVI5 = memFun(&cbs, &MyCallbacks::testVI5); cbVI5(1, 2, 3, 4, 5); cbs.verifyCalled(false, false, false, false, false, true, false, false); cbs.reset(); Callback6 cbVI6 = memFun(&cbs, &MyCallbacks::testVI6); cbVI6(1, 2, 3, 4, 5, 6); cbs.verifyCalled(false, false, false, false, false, false, true, false); cbs.reset(); Callback7 cbVI7 = memFun(&cbs, &MyCallbacks::testVI7); cbVI7(1, 2, 3, 4, 5, 6, 7); cbs.verifyCalled(false, false, false, false, false, false, false, true); cbs.reset(); } void TestCallbacks::testPtrFun() { reset(); Callback0 cbVV = ptrFun(&testVV); cbVV(); verifyCalled(true, false, false, false, false, false, false, false); reset(); Callback1 cbVI1 = ptrFun(&testVI1); cbVI1(1); verifyCalled(false, true, false, false, false, false, false, false); reset(); Callback2 cbVI2 = ptrFun(&testVI2); cbVI2(1, 2); verifyCalled(false, false, true, false, false, false, false, false); reset(); Callback3 cbVI3 = ptrFun(&testVI3); cbVI3(1, 2, 3); verifyCalled(false, false, false, true, false, false, false, false); reset(); Callback4 cbVI4 = ptrFun(&testVI4); cbVI4(1, 2, 3, 4); verifyCalled(false, false, false, false, true, false, false, false); reset(); Callback5 cbVI5 = ptrFun(&testVI5); cbVI5(1, 2, 3, 4, 5); verifyCalled(false, false, false, false, false, true, false, false); reset(); Callback6 cbVI6 = ptrFun(&testVI6); cbVI6(1, 2, 3, 4, 5, 6); verifyCalled(false, false, false, false, false, false, true, false); reset(); Callback7 cbVI7 = ptrFun(&testVI7); cbVI7(1, 2, 3, 4, 5, 6, 7); verifyCalled(false, false, false, false, false, false, false, true); reset(); } QTEST_MAIN(TestCallbacks) #include "_gen/callbacks.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/key-file.cpp0000664000175000017500000001315312470405660016326 0ustar jrjr#include #include "TelepathyQt/key-file.h" using namespace Tp; class TestKeyFile : public QObject { Q_OBJECT private Q_SLOTS: void testKeyFile(); }; void TestKeyFile::testKeyFile() { QString top_srcdir = QString::fromLocal8Bit(::getenv("abs_top_srcdir")); if (!top_srcdir.isEmpty()) { QDir::setCurrent(top_srcdir + QLatin1String("/tests")); } KeyFile defaultKeyFile; QCOMPARE(defaultKeyFile.status(), KeyFile::None); KeyFile notFoundkeyFile(QLatin1String("test-key-file-not-found.ini")); QCOMPARE(notFoundkeyFile.status(), KeyFile::NotFoundError); KeyFile formatErrorkeyFile(QLatin1String("test-key-file-format-error.ini")); QCOMPARE(formatErrorkeyFile.status(), KeyFile::FormatError); KeyFile keyFile(QLatin1String("test-key-file.ini")); QCOMPARE(keyFile.status(), KeyFile::NoError); QStringList allGroups = keyFile.allGroups(); allGroups.sort(); QCOMPARE(allGroups, QStringList() << QString() << QLatin1String("test group 1") << QLatin1String("test group 2")); QStringList allKeys = keyFile.allKeys(); allKeys.sort(); QCOMPARE(allKeys, QStringList() << QLatin1String("a") << QLatin1String("b") << QLatin1String("c") << QLatin1String("d") << QLatin1String("e")); keyFile.setGroup(QLatin1String("test group 1")); QCOMPARE(keyFile.contains(QLatin1String("f")), false); QCOMPARE(keyFile.value(QLatin1String("c")).length(), 5); keyFile.setGroup(QLatin1String("test group 2")); QCOMPARE(keyFile.contains(QLatin1String("e")), true); QCOMPARE(keyFile.value(QLatin1String("e")), QString(QLatin1String("space"))); keyFile.setFileName(QLatin1String("telepathy/managers/test-manager-file.manager")); QCOMPARE(keyFile.status(), KeyFile::NoError); keyFile.setGroup(QLatin1String("Protocol somewhat-pathological")); QCOMPARE(keyFile.value(QLatin1String("param-foo")), QString(QLatin1String("s required"))); QCOMPARE(keyFile.value(QLatin1String("default-foo")), QString(QLatin1String("hello world"))); QCOMPARE(keyFile.value(QLatin1String("param-semicolons")), QString(QLatin1String("s secret"))); QCOMPARE(keyFile.value(QLatin1String("default-semicolons")), QString(QLatin1String("list;of;misc;"))); QCOMPARE(keyFile.value(QLatin1String("param-list")), QString(QLatin1String("as"))); QCOMPARE(keyFile.value(QLatin1String("default-list")), QString(QLatin1String("list;of;misc;"))); QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-list")), QStringList() << QLatin1String("list") << QLatin1String("of") << QLatin1String("misc")); QCOMPARE(keyFile.value(QLatin1String("param-unterminated-list")), QString(QLatin1String("as"))); QCOMPARE(keyFile.value(QLatin1String("default-unterminated-list")), QString(QLatin1String("list;of;misc"))); QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-unterminated-list")), QStringList() << QLatin1String("list") << QLatin1String("of") << QLatin1String("misc")); QCOMPARE(keyFile.value(QLatin1String("param-spaces-in-list")), QString(QLatin1String("as"))); QCOMPARE(keyFile.value(QLatin1String("default-spaces-in-list")), QString(QLatin1String("list; of; misc ;"))); QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-spaces-in-list")), QStringList() << QLatin1String("list") << QLatin1String(" of") << QLatin1String(" misc ")); QCOMPARE(keyFile.value(QLatin1String("param-escaped-semicolon-in-list")), QString(QLatin1String("as"))); QCOMPARE(keyFile.value(QLatin1String("default-escaped-semicolon-in-list")), QString(QLatin1String("list;of;misc;"))); QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-escaped-semicolon-in-list")), QStringList() << QLatin1String("list;of") << QLatin1String("misc")); QCOMPARE(keyFile.value(QLatin1String("param-doubly-escaped-semicolon-in-list")), QString(QLatin1String("as"))); QCOMPARE(keyFile.value(QLatin1String("default-doubly-escaped-semicolon-in-list")), QString(QLatin1String("list\\;of;misc;"))); QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-doubly-escaped-semicolon-in-list")), QStringList() << QLatin1String("list\\") << QLatin1String("of") << QLatin1String("misc")); QCOMPARE(keyFile.value(QLatin1String("param-triply-escaped-semicolon-in-list")), QString(QLatin1String("as"))); QCOMPARE(keyFile.value(QLatin1String("default-triply-escaped-semicolon-in-list")), QString(QLatin1String("list\\;of;misc;"))); QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-triply-escaped-semicolon-in-list")), QStringList() << QLatin1String("list\\;of") << QLatin1String("misc")); QCOMPARE(keyFile.value(QLatin1String("param-empty-list")), QString(QLatin1String("as"))); QCOMPARE(keyFile.value(QLatin1String("default-empty-list")), QString(QLatin1String(""))); QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-empty-list")), QStringList()); QCOMPARE(keyFile.value(QLatin1String("param-list-of-empty-string")), QString(QLatin1String("as"))); QCOMPARE(keyFile.value(QLatin1String("default-list-of-empty-string")), QString(QLatin1String(";"))); QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-list-of-empty-string")), QStringList() << QString()); QCOMPARE(keyFile.value(QLatin1String("param-escaped-semicolon")), QString(QLatin1String("s"))); QCOMPARE(keyFile.value(QLatin1String("default-escaped-semicolon")), QString(QLatin1String("foo;bar"))); } QTEST_MAIN(TestKeyFile) #include "_gen/key-file.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/features.cpp0000664000175000017500000000271712470405660016443 0ustar jrjr#include #include #include #include #include using namespace Tp; namespace { QList reverse(const QList &list) { QList ret(list); for (int k = 0; k < (list.size() / 2); k++) { ret.swap(k, list.size() - (1 + k)); } return ret; } }; class TestFeatures : public QObject { Q_OBJECT public: TestFeatures(QObject *parent = 0); private Q_SLOTS: void testFeaturesHash(); }; TestFeatures::TestFeatures(QObject *parent) : QObject(parent) { Tp::enableDebug(true); Tp::enableWarnings(true); } void TestFeatures::testFeaturesHash() { QList fs1; QList fs2; for (int i = 0; i < 100; ++i) { fs1 << Feature(QString::number(i), i); fs2 << Feature(QString::number(i), i); } QCOMPARE(qHash(fs1.toSet()), qHash(fs2.toSet())); fs2.clear(); for (int i = 0; i < 5; ++i) { for (int j = 0; j < 100; ++j) { fs2 << Feature(QString::number(j), j); } } QCOMPARE(qHash(fs1.toSet()), qHash(fs2.toSet())); fs1 = reverse(fs1); QCOMPARE(qHash(fs1.toSet()), qHash(fs2.toSet())); fs2 = reverse(fs2); QCOMPARE(qHash(fs1.toSet()), qHash(fs2.toSet())); fs2 << Feature(QLatin1String("100"), 100); QVERIFY(qHash(fs1.toSet()) != qHash(fs2.toSet())); } QTEST_MAIN(TestFeatures) #include "_gen/features.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/rccspec.cpp0000664000175000017500000001650412470405660016246 0ustar jrjr#include #include using namespace Tp; class TestRCCSpec : public QObject { Q_OBJECT private Q_SLOTS: void testRCCSpec(); }; void TestRCCSpec::testRCCSpec() { RequestableChannelClassSpec spec; spec = RequestableChannelClassSpec::textChat(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_TEXT); QCOMPARE(spec.targetHandleType(), HandleTypeContact); QCOMPARE(spec.fixedProperties().size(), 2); QCOMPARE(spec.allowedProperties().isEmpty(), true); spec = RequestableChannelClassSpec::textChatroom(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_TEXT); QCOMPARE(spec.targetHandleType(), HandleTypeRoom); QCOMPARE(spec.fixedProperties().size(), 2); QCOMPARE(spec.allowedProperties().isEmpty(), true); spec = RequestableChannelClassSpec::streamedMediaCall(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); QCOMPARE(spec.targetHandleType(), HandleTypeContact); QCOMPARE(spec.fixedProperties().size(), 2); QCOMPARE(spec.allowedProperties().isEmpty(), true); spec = RequestableChannelClassSpec::streamedMediaAudioCall(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); QCOMPARE(spec.targetHandleType(), HandleTypeContact); QCOMPARE(spec.fixedProperties().size(), 2); QCOMPARE(spec.allowedProperties().size(), 1); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio")), true); spec = RequestableChannelClassSpec::streamedMediaVideoCall(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); QCOMPARE(spec.targetHandleType(), HandleTypeContact); QCOMPARE(spec.fixedProperties().size(), 2); QCOMPARE(spec.allowedProperties().size(), 1); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo")), true); spec = RequestableChannelClassSpec::streamedMediaVideoCallWithAudio(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); QCOMPARE(spec.targetHandleType(), HandleTypeContact); QCOMPARE(spec.fixedProperties().size(), 2); QCOMPARE(spec.allowedProperties().size(), 2); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio")), true); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo")), true); spec = RequestableChannelClassSpec::conferenceTextChat(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_TEXT); QVERIFY(!spec.hasTargetHandleType()); QCOMPARE(spec.allowedProperties().size(), 1); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")), true); spec = RequestableChannelClassSpec::conferenceTextChatWithInvitees(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_TEXT); QVERIFY(!spec.hasTargetHandleType()); QCOMPARE(spec.allowedProperties().size(), 2); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")), true); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")), true); spec = RequestableChannelClassSpec::conferenceTextChatroom(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_TEXT); QCOMPARE(spec.targetHandleType(), HandleTypeRoom); QCOMPARE(spec.allowedProperties().size(), 1); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")), true); spec = RequestableChannelClassSpec::conferenceTextChatroomWithInvitees(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_TEXT); QCOMPARE(spec.targetHandleType(), HandleTypeRoom); QCOMPARE(spec.allowedProperties().size(), 2); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")), true); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")), true); spec = RequestableChannelClassSpec::conferenceStreamedMediaCall(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); QVERIFY(!spec.hasTargetHandleType()); QCOMPARE(spec.allowedProperties().size(), 1); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")), true); spec = RequestableChannelClassSpec::conferenceStreamedMediaCallWithInvitees(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); QVERIFY(!spec.hasTargetHandleType()); QCOMPARE(spec.allowedProperties().size(), 2); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")), true); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")), true); spec = RequestableChannelClassSpec::contactSearch(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); QCOMPARE(spec.fixedProperties().size(), 1); QCOMPARE(spec.allowedProperties().isEmpty(), true); spec = RequestableChannelClassSpec::contactSearchWithSpecificServer(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); QCOMPARE(spec.fixedProperties().size(), 1); QCOMPARE(spec.allowedProperties().size(), 1); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Server")), true); spec = RequestableChannelClassSpec::contactSearchWithLimit(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); QCOMPARE(spec.fixedProperties().size(), 1); QCOMPARE(spec.allowedProperties().size(), 1); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Limit")), true); spec = RequestableChannelClassSpec::contactSearchWithSpecificServerAndLimit(); QCOMPARE(spec.channelType(), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); QCOMPARE(spec.fixedProperties().size(), 1); QCOMPARE(spec.allowedProperties().size(), 2); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Server")), true); QCOMPARE(spec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Limit")), true); QCOMPARE(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio().supports( RequestableChannelClassSpec::streamedMediaVideoCall()), true); QCOMPARE(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio().supports( RequestableChannelClassSpec::streamedMediaAudioCall()), true); QCOMPARE(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio().supports( RequestableChannelClassSpec::streamedMediaCall()), true); QCOMPARE(RequestableChannelClassSpec::textChat() == RequestableChannelClassSpec::textChatroom(), false); RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); spec = RequestableChannelClassSpec(rcc); QCOMPARE(RequestableChannelClassSpec::textChat() == spec, true); } QTEST_MAIN(TestRCCSpec) #include "_gen/rccspec.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/presence.cpp0000664000175000017500000001665012470405660016432 0ustar jrjr#include #include #include #include #include using namespace Tp; class TestPresence : public QObject { Q_OBJECT public: TestPresence(QObject *parent = 0); private Q_SLOTS: void testPresence(); void testPresenceSpec(); }; TestPresence::TestPresence(QObject *parent) : QObject(parent) { Tp::enableDebug(true); Tp::enableWarnings(true); } #define TEST_PRESENCE(pr, prValid, prType, prStatus, prStatusMessage) \ { \ QVERIFY(pr.isValid() == prValid); \ QCOMPARE(pr.type(), prType); \ QCOMPARE(pr.status(), prStatus); \ QCOMPARE(pr.statusMessage(), prStatusMessage); \ } void TestPresence::testPresence() { Presence pr; TEST_PRESENCE(pr, false, ConnectionPresenceTypeUnknown, QString(), QString()); pr.setStatus(ConnectionPresenceTypeAvailable, QLatin1String("available"), QLatin1String("I am available")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeAvailable, QLatin1String("available"), QLatin1String("I am available")); pr = Presence::available(); TEST_PRESENCE(pr, true, ConnectionPresenceTypeAvailable, QLatin1String("available"), QString()); pr = Presence::available(QLatin1String("I am available")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeAvailable, QLatin1String("available"), QLatin1String("I am available")); pr = Presence::chat(); TEST_PRESENCE(pr, true, ConnectionPresenceTypeAvailable, QLatin1String("chat"), QString()); pr = Presence::chat(QLatin1String("I am chat")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeAvailable, QLatin1String("chat"), QLatin1String("I am chat")); pr = Presence::away(); TEST_PRESENCE(pr, true, ConnectionPresenceTypeAway, QLatin1String("away"), QString()); pr = Presence::away(QLatin1String("I am away")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeAway, QLatin1String("away"), QLatin1String("I am away")); pr = Presence::brb(); TEST_PRESENCE(pr, true, ConnectionPresenceTypeAway, QLatin1String("brb"), QString()); pr = Presence::brb(QLatin1String("I am brb")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeAway, QLatin1String("brb"), QLatin1String("I am brb")); pr = Presence::busy(); TEST_PRESENCE(pr, true, ConnectionPresenceTypeBusy, QLatin1String("busy"), QString()); pr = Presence::busy(QLatin1String("I am busy")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeBusy, QLatin1String("busy"), QLatin1String("I am busy")); pr = Presence::dnd(); TEST_PRESENCE(pr, true, ConnectionPresenceTypeBusy, QLatin1String("dnd"), QString()); pr = Presence::dnd(QLatin1String("I am dnd")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeBusy, QLatin1String("dnd"), QLatin1String("I am dnd")); pr = Presence::xa(); TEST_PRESENCE(pr, true, ConnectionPresenceTypeExtendedAway, QLatin1String("xa"), QString()); pr = Presence::xa(QLatin1String("I am xa")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeExtendedAway, QLatin1String("xa"), QLatin1String("I am xa")); pr = Presence::hidden(); TEST_PRESENCE(pr, true, ConnectionPresenceTypeHidden, QLatin1String("hidden"), QString()); pr = Presence::hidden(QLatin1String("I am hidden")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeHidden, QLatin1String("hidden"), QLatin1String("I am hidden")); pr = Presence::offline(); TEST_PRESENCE(pr, true, ConnectionPresenceTypeOffline, QLatin1String("offline"), QString()); pr = Presence::offline(QLatin1String("I am offline")); TEST_PRESENCE(pr, true, ConnectionPresenceTypeOffline, QLatin1String("offline"), QLatin1String("I am offline")); } #define TEST_PRESENCE_SPEC_FULL(specStatus, specType, specMaySetOnSelf, specCanHaveMessage) \ { \ SimpleStatusSpec bareSpec; \ bareSpec.type = specType; \ bareSpec.maySetOnSelf = specMaySetOnSelf; \ bareSpec.canHaveMessage = specCanHaveMessage; \ \ PresenceSpec spec(specStatus, bareSpec); \ TEST_PRESENCE_SPEC(spec, true, specStatus, specType, specMaySetOnSelf, specCanHaveMessage); \ } #define TEST_PRESENCE_SPEC(spec, specValid, specStatus, specType, specMaySetOnSelf, specCanHaveMessage) \ { \ QVERIFY(spec.isValid() == specValid); \ if (specValid) { \ QCOMPARE(spec.presence(), Presence(specType, specStatus, QString())); \ TEST_PRESENCE(spec.presence(), true, specType, specStatus, QString()); \ QCOMPARE(spec.presence(QLatin1String("test message")), Presence(specType, specStatus, QLatin1String("test message"))); \ TEST_PRESENCE(spec.presence(QLatin1String("test message")), true, specType, specStatus, QLatin1String("test message")); \ } else { \ QVERIFY(!spec.presence().isValid()); \ } \ QCOMPARE(spec.maySetOnSelf(), specMaySetOnSelf); \ QCOMPARE(spec.canHaveStatusMessage(), specCanHaveMessage); \ \ if (specValid) { \ SimpleStatusSpec bareSpec; \ bareSpec.type = specType; \ bareSpec.maySetOnSelf = specMaySetOnSelf; \ bareSpec.canHaveMessage = specCanHaveMessage; \ QCOMPARE(spec.bareSpec(), bareSpec); \ } else { \ QCOMPARE(spec.bareSpec(), SimpleStatusSpec()); \ } \ } void TestPresence::testPresenceSpec() { PresenceSpec spec; TEST_PRESENCE_SPEC(spec, false, QString(), ConnectionPresenceTypeUnknown, false, false); TEST_PRESENCE_SPEC_FULL(QLatin1String("available"), ConnectionPresenceTypeAvailable, true, true); TEST_PRESENCE_SPEC_FULL(QLatin1String("brb"), ConnectionPresenceTypeAway, true, true); TEST_PRESENCE_SPEC_FULL(QLatin1String("away"), ConnectionPresenceTypeAway, true, true); TEST_PRESENCE_SPEC_FULL(QLatin1String("xa"), ConnectionPresenceTypeExtendedAway, false, false); TEST_PRESENCE_SPEC_FULL(QLatin1String("offline"), ConnectionPresenceTypeOffline, true, false); spec = PresenceSpec::available(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("available"), ConnectionPresenceTypeAvailable, true, true); spec = PresenceSpec::chat(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("chat"), ConnectionPresenceTypeAvailable, true, true); spec = PresenceSpec::pstn(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("pstn"), ConnectionPresenceTypeAvailable, false, true); spec = PresenceSpec::away(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("away"), ConnectionPresenceTypeAway, true, true); spec = PresenceSpec::brb(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("brb"), ConnectionPresenceTypeAway, true, true); spec = PresenceSpec::busy(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("busy"), ConnectionPresenceTypeBusy, true, true); spec = PresenceSpec::dnd(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("dnd"), ConnectionPresenceTypeBusy, true, true); spec = PresenceSpec::xa(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("xa"), ConnectionPresenceTypeExtendedAway, true, true); spec = PresenceSpec::hidden(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("hidden"), ConnectionPresenceTypeHidden, true, true); spec = PresenceSpec::offline(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("offline"), ConnectionPresenceTypeOffline, false, true); spec = PresenceSpec::unknown(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("unknown"), ConnectionPresenceTypeUnknown, false, true); spec = PresenceSpec::error(); TEST_PRESENCE_SPEC(spec, true, QLatin1String("error"), ConnectionPresenceTypeError, false, true); } QTEST_MAIN(TestPresence) #include "_gen/presence.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/README0000664000175000017500000000065012470405660014773 0ustar jrjrTests should be divided up by the environment they require in order to operate correctly. Where to put new tests: * /tests/ if they're simple regression tests in pure C++ that don't access D-Bus (these are likely to be rare) * /tests/dbus/ if they touch the session bus (a temporary session bus will be used) /tests/lib/ contains support code, some of it taken from the telepathy-glib examples and regression tests. telepathy-qt-0.9.6~git1/tests/capabilities.cpp0000664000175000017500000004051312470405660017252 0ustar jrjr#include #include #include #include #include #include #include #include using namespace Tp; class TestCapabilities : public QObject { Q_OBJECT public: TestCapabilities(QObject *parent = 0); private Q_SLOTS: void testConnCapabilities(); void testContactCapabilities(); }; TestCapabilities::TestCapabilities(QObject *parent) : QObject(parent) { Tp::enableDebug(true); Tp::enableWarnings(true); } void TestCapabilities::testConnCapabilities() { ConnectionCapabilities connCaps; // capabilities base QVERIFY(!connCaps.isSpecificToContact()); QVERIFY(!connCaps.textChats()); QVERIFY(!connCaps.streamedMediaCalls()); QVERIFY(!connCaps.streamedMediaAudioCalls()); QVERIFY(!connCaps.streamedMediaVideoCalls()); QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio()); QVERIFY(!connCaps.upgradingStreamedMediaCalls()); QVERIFY(!connCaps.fileTransfers()); // conn caps specific QVERIFY(!connCaps.textChatrooms()); QVERIFY(!connCaps.conferenceStreamedMediaCalls()); QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees()); QVERIFY(!connCaps.conferenceTextChats()); QVERIFY(!connCaps.conferenceTextChatsWithInvitees()); QVERIFY(!connCaps.conferenceTextChatrooms()); QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees()); QVERIFY(!connCaps.contactSearches()); QVERIFY(!connCaps.contactSearchesWithSpecificServer()); QVERIFY(!connCaps.contactSearchesWithLimit()); QVERIFY(!connCaps.streamTubes()); RequestableChannelClassSpecList rccSpecs; rccSpecs.append(RequestableChannelClassSpec::textChat()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaCall()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaAudioCall()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCall()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio()); rccSpecs.append(RequestableChannelClassSpec::fileTransfer()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(!connCaps.isSpecificToContact()); QVERIFY(connCaps.textChats()); QVERIFY(connCaps.streamedMediaCalls()); QVERIFY(connCaps.streamedMediaAudioCalls()); QVERIFY(connCaps.streamedMediaVideoCalls()); QVERIFY(connCaps.streamedMediaVideoCallsWithAudio()); QVERIFY(connCaps.fileTransfers()); // conn caps specific QVERIFY(!connCaps.textChatrooms()); QVERIFY(!connCaps.conferenceStreamedMediaCalls()); QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees()); QVERIFY(!connCaps.conferenceTextChats()); QVERIFY(!connCaps.conferenceTextChatsWithInvitees()); QVERIFY(!connCaps.conferenceTextChatrooms()); QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees()); QVERIFY(!connCaps.contactSearches()); QVERIFY(!connCaps.contactSearchesWithSpecificServer()); QVERIFY(!connCaps.contactSearchesWithLimit()); QVERIFY(!connCaps.streamTubes()); QCOMPARE(connCaps.allClassSpecs(), rccSpecs); rccSpecs.append(RequestableChannelClassSpec::textChatroom()); rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCall()); rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCallWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::conferenceTextChat()); rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroom()); rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroomWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::contactSearch()); rccSpecs.append(RequestableChannelClassSpec::contactSearchWithSpecificServer()); rccSpecs.append(RequestableChannelClassSpec::contactSearchWithLimit()); rccSpecs.append(RequestableChannelClassSpec::contactSearchWithSpecificServerAndLimit()); rccSpecs.append(RequestableChannelClassSpec::streamTube()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(!connCaps.isSpecificToContact()); QVERIFY(connCaps.textChats()); QVERIFY(connCaps.streamedMediaCalls()); QVERIFY(connCaps.streamedMediaAudioCalls()); QVERIFY(connCaps.streamedMediaVideoCalls()); QVERIFY(connCaps.streamedMediaVideoCallsWithAudio()); QVERIFY(connCaps.fileTransfers()); // conn caps specific QVERIFY(connCaps.textChatrooms()); QVERIFY(connCaps.conferenceStreamedMediaCalls()); QVERIFY(connCaps.conferenceStreamedMediaCallsWithInvitees()); QVERIFY(connCaps.conferenceTextChats()); QVERIFY(connCaps.conferenceTextChatsWithInvitees()); QVERIFY(connCaps.conferenceTextChatrooms()); QVERIFY(connCaps.conferenceTextChatroomsWithInvitees()); QVERIFY(connCaps.contactSearches()); QVERIFY(connCaps.contactSearchesWithSpecificServer()); QVERIFY(connCaps.contactSearchesWithLimit()); QCOMPARE(connCaps.allClassSpecs(), rccSpecs); // start over rccSpecs.clear(); rccSpecs.append(RequestableChannelClassSpec::streamedMediaCall()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.streamedMediaCalls()); QVERIFY(!connCaps.streamedMediaAudioCalls()); QVERIFY(!connCaps.streamedMediaVideoCalls()); QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio()); // conn caps specific QVERIFY(!connCaps.conferenceStreamedMediaCalls()); QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaAudioCall()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.streamedMediaCalls()); QVERIFY(connCaps.streamedMediaAudioCalls()); QVERIFY(!connCaps.streamedMediaVideoCalls()); QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio()); // conn caps specific QVERIFY(!connCaps.conferenceStreamedMediaCalls()); QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCall()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.streamedMediaCalls()); QVERIFY(connCaps.streamedMediaAudioCalls()); QVERIFY(connCaps.streamedMediaVideoCalls()); QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio()); // conn caps specific QVERIFY(!connCaps.conferenceStreamedMediaCalls()); QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.streamedMediaCalls()); QVERIFY(connCaps.streamedMediaAudioCalls()); QVERIFY(connCaps.streamedMediaVideoCalls()); QVERIFY(connCaps.streamedMediaVideoCallsWithAudio()); // conn caps specific QVERIFY(!connCaps.conferenceStreamedMediaCalls()); QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCall()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.streamedMediaCalls()); QVERIFY(connCaps.streamedMediaAudioCalls()); QVERIFY(connCaps.streamedMediaVideoCalls()); QVERIFY(connCaps.streamedMediaVideoCallsWithAudio()); // conn caps specific QVERIFY(connCaps.conferenceStreamedMediaCalls()); QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCallWithInvitees()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.streamedMediaCalls()); QVERIFY(connCaps.streamedMediaAudioCalls()); QVERIFY(connCaps.streamedMediaVideoCalls()); QVERIFY(connCaps.streamedMediaVideoCallsWithAudio()); // conn caps specific QVERIFY(connCaps.conferenceStreamedMediaCalls()); QVERIFY(connCaps.conferenceStreamedMediaCallsWithInvitees()); // capabilities base QVERIFY(!connCaps.textChats()); QVERIFY(!connCaps.fileTransfers()); // conn caps specific QVERIFY(!connCaps.textChatrooms()); QVERIFY(!connCaps.conferenceTextChats()); QVERIFY(!connCaps.conferenceTextChatsWithInvitees()); QVERIFY(!connCaps.conferenceTextChatrooms()); QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees()); QVERIFY(!connCaps.contactSearches()); QVERIFY(!connCaps.contactSearchesWithSpecificServer()); QVERIFY(!connCaps.contactSearchesWithLimit()); QVERIFY(!connCaps.streamTubes()); rccSpecs.append(RequestableChannelClassSpec::textChat()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.textChats()); // conn caps specific QVERIFY(!connCaps.textChatrooms()); QVERIFY(!connCaps.conferenceTextChats()); QVERIFY(!connCaps.conferenceTextChatsWithInvitees()); QVERIFY(!connCaps.conferenceTextChatrooms()); QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::textChatroom()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.textChats()); // conn caps specific QVERIFY(connCaps.textChatrooms()); QVERIFY(!connCaps.conferenceTextChats()); QVERIFY(!connCaps.conferenceTextChatsWithInvitees()); QVERIFY(!connCaps.conferenceTextChatrooms()); QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::conferenceTextChat()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.textChats()); // conn caps specific QVERIFY(connCaps.textChatrooms()); QVERIFY(connCaps.conferenceTextChats()); QVERIFY(!connCaps.conferenceTextChatsWithInvitees()); QVERIFY(!connCaps.conferenceTextChatrooms()); QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatWithInvitees()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.textChats()); // conn caps specific QVERIFY(connCaps.textChatrooms()); QVERIFY(connCaps.conferenceTextChats()); QVERIFY(connCaps.conferenceTextChatsWithInvitees()); QVERIFY(!connCaps.conferenceTextChatrooms()); QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroom()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.textChats()); // conn caps specific QVERIFY(connCaps.textChatrooms()); QVERIFY(connCaps.conferenceTextChats()); QVERIFY(connCaps.conferenceTextChatsWithInvitees()); QVERIFY(connCaps.conferenceTextChatrooms()); QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees()); rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroomWithInvitees()); connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs); // capabilities base QVERIFY(connCaps.textChats()); // conn caps specific QVERIFY(connCaps.textChatrooms()); QVERIFY(connCaps.conferenceTextChats()); QVERIFY(connCaps.conferenceTextChatsWithInvitees()); QVERIFY(connCaps.conferenceTextChatrooms()); QVERIFY(connCaps.conferenceTextChatroomsWithInvitees()); // capabilities base QVERIFY(!connCaps.fileTransfers()); // conn caps specific QVERIFY(!connCaps.contactSearches()); QVERIFY(!connCaps.contactSearchesWithSpecificServer()); QVERIFY(!connCaps.contactSearchesWithLimit()); QVERIFY(!connCaps.streamTubes()); } void TestCapabilities::testContactCapabilities() { ContactCapabilities contactCaps; // capabilities base QVERIFY(!contactCaps.isSpecificToContact()); QVERIFY(!contactCaps.textChats()); QVERIFY(!contactCaps.streamedMediaCalls()); QVERIFY(!contactCaps.streamedMediaAudioCalls()); QVERIFY(!contactCaps.streamedMediaVideoCalls()); QVERIFY(!contactCaps.streamedMediaVideoCallsWithAudio()); QVERIFY(!contactCaps.upgradingStreamedMediaCalls()); QVERIFY(!contactCaps.fileTransfers()); // contact caps specific QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar"))); QVERIFY(!contactCaps.streamTubes(QLatin1String("service-foo"))); QVERIFY(!contactCaps.streamTubes(QLatin1String("service-bar"))); QVERIFY(contactCaps.streamTubeServices().isEmpty()); RequestableChannelClassSpecList rccSpecs; rccSpecs.append(RequestableChannelClassSpec::textChat()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaCall()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaAudioCall()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCall()); rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio()); rccSpecs.append(RequestableChannelClassSpec::fileTransfer()); contactCaps = TestBackdoors::createContactCapabilities(rccSpecs, true); // capabilities base QVERIFY(contactCaps.isSpecificToContact()); QVERIFY(contactCaps.textChats()); QVERIFY(contactCaps.streamedMediaCalls()); QVERIFY(contactCaps.streamedMediaAudioCalls()); QVERIFY(contactCaps.streamedMediaVideoCalls()); QVERIFY(contactCaps.streamedMediaVideoCallsWithAudio()); QVERIFY(contactCaps.fileTransfers()); // contact caps specific QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar"))); QVERIFY(!contactCaps.streamTubes(QLatin1String("service-foo"))); QVERIFY(!contactCaps.streamTubes(QLatin1String("service-bar"))); QVERIFY(contactCaps.streamTubeServices().isEmpty()); QCOMPARE(contactCaps.allClassSpecs(), rccSpecs); rccSpecs.append(RequestableChannelClassSpec::streamTube(QLatin1String("service-foo"))); rccSpecs.append(RequestableChannelClassSpec::streamTube(QLatin1String("service-bar"))); contactCaps = TestBackdoors::createContactCapabilities(rccSpecs, true); // capabilities base QVERIFY(contactCaps.isSpecificToContact()); QVERIFY(contactCaps.textChats()); QVERIFY(contactCaps.streamedMediaCalls()); QVERIFY(contactCaps.streamedMediaAudioCalls()); QVERIFY(contactCaps.streamedMediaVideoCalls()); QVERIFY(contactCaps.streamedMediaVideoCallsWithAudio()); QVERIFY(contactCaps.fileTransfers()); // contact caps specific QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar"))); QVERIFY(contactCaps.streamTubes(QLatin1String("service-foo"))); QVERIFY(contactCaps.streamTubes(QLatin1String("service-bar"))); QStringList stubeServices = contactCaps.streamTubeServices(); stubeServices.sort(); QStringList expectedSTubeServices; expectedSTubeServices << QLatin1String("service-foo") << QLatin1String("service-bar"); expectedSTubeServices.sort(); QCOMPARE(stubeServices, expectedSTubeServices); QCOMPARE(contactCaps.allClassSpecs(), rccSpecs); rccSpecs.clear(); rccSpecs.append(RequestableChannelClassSpec::streamTube(QLatin1String("service-foo"))); contactCaps = TestBackdoors::createContactCapabilities(rccSpecs, true); QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar"))); QVERIFY(contactCaps.streamTubes(QLatin1String("service-foo"))); QVERIFY(!contactCaps.streamTubes(QLatin1String("service-bar"))); QCOMPARE(contactCaps.streamTubeServices(), QStringList() << QLatin1String("service-foo")); rccSpecs.append(RequestableChannelClassSpec::streamTube(QLatin1String("service-bar"))); contactCaps = TestBackdoors::createContactCapabilities(rccSpecs, true); QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar"))); QVERIFY(contactCaps.streamTubes(QLatin1String("service-foo"))); QVERIFY(contactCaps.streamTubes(QLatin1String("service-bar"))); stubeServices = contactCaps.streamTubeServices(); stubeServices.sort(); expectedSTubeServices.clear(); expectedSTubeServices << QLatin1String("service-foo") << QLatin1String("service-bar"); expectedSTubeServices.sort(); QCOMPARE(stubeServices, expectedSTubeServices); } QTEST_MAIN(TestCapabilities) #include "_gen/capabilities.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/dbus-1/0000775000175000017500000000000012470405660015205 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/dbus-1/services/0000775000175000017500000000000012470405660017030 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/dbus-1/services/spurious.service.in0000664000175000017500000000013212470405660022704 0ustar jrjr[D-BUS Service] Name=org.freedesktop.Telepathy.ConnectionManager.spurious Exec=/bin/false telepathy-qt-0.9.6~git1/tests/dbus-1/services/CMakeLists.txt0000664000175000017500000000037612470405660021576 0ustar jrjrset(TEST_PYTHON ${PYTHON_EXECUTABLE}) set(abs_top_srcdir ${CMAKE_SOURCE_DIR}) configure_file(account-manager.service.in ${CMAKE_CURRENT_BINARY_DIR}/account-manager.service) configure_file(spurious.service.in ${CMAKE_CURRENT_BINARY_DIR}/spurious.service) telepathy-qt-0.9.6~git1/tests/dbus-1/services/account-manager.service.in0000664000175000017500000000020612470405660024061 0ustar jrjr[D-BUS Service] Name=org.freedesktop.Telepathy.AccountManager Exec=@TEST_PYTHON@ @abs_top_srcdir@/tests/lib/python/account-manager.py telepathy-qt-0.9.6~git1/tests/dbus-1/CMakeLists.txt0000664000175000017500000000021712470405660017745 0ustar jrjrset(abs_top_builddir ${CMAKE_BINARY_DIR}) configure_file(session.conf.in ${CMAKE_CURRENT_BINARY_DIR}/session.conf) add_subdirectory(services) telepathy-qt-0.9.6~git1/tests/dbus-1/session.conf.in0000664000175000017500000000176212470405660020152 0ustar jrjr session unix:tmpdir=/tmp @abs_top_builddir@/tests/dbus-1/services/ telepathy-qt-0.9.6~git1/tests/test-key-file-format-error.ini0000664000175000017500000000002712470405660021711 0ustar jrjra 1 b=2 [test group 1 telepathy-qt-0.9.6~git1/tests/utils.cpp0000664000175000017500000000127712470405660015765 0ustar jrjr#include #include using namespace Tp; class TestUtils : public QObject { Q_OBJECT private Q_SLOTS: void testUtils(); }; void TestUtils::testUtils() { QString res; res = escapeAsIdentifier(QString::fromLatin1("")); QCOMPARE(res, QString::fromLatin1("_")); res = escapeAsIdentifier(QString::fromLatin1("badger")); QCOMPARE(res, QString::fromLatin1("badger")); res = escapeAsIdentifier(QString::fromLatin1("0123abc_xyz")); QCOMPARE(res, QString::fromLatin1("_30123abc_5fxyz")); res = escapeAsIdentifier(QString::fromUtf8("©")); QCOMPARE(res, QString::fromLatin1("_c2_a9")); } QTEST_MAIN(TestUtils) #include "_gen/utils.cpp.moc.hpp" telepathy-qt-0.9.6~git1/tests/telepathy/0000775000175000017500000000000012470405660016111 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/telepathy/managers/0000775000175000017500000000000012470405660017706 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/telepathy/managers/spurious.manager0000664000175000017500000000120312470405660023127 0ustar jrjr[ConnectionManager] [Protocol normal] param-account=s required register param-password=s required register secret param-register=b default-register=true RequestableChannelClasses=text status-available=2 settable message status-offline=1 settable status-away=3 settable status-xa=4 [text] org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text org.freedesktop.Telepathy.Channel.TargetHandleType u=1 allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID; [Protocol weird] param-com.example.Bork.Bork.Bork=u dbus-property default-com.example.Bork.Bork.Bork=42 telepathy-qt-0.9.6~git1/tests/telepathy/managers/test-manager-file-invalid-signature.manager0000664000175000017500000000421312470405660030171 0ustar jrjr[Protocol foo] param-account = s required param-password = s required param-encryption-key = s secret param-port = q param-register = b param-server-list = as default-account = foo@default default-port = 1234 default-server-list = foo;bar; [Protocol bar] param-account = s required param-encryption-key = s required secret param-password = s required param-port = q param-register = b param-server-list = as default-account = bar@default default-port = 4321 default-server-list = bar;foo; [Protocol somewhat-pathological] # the value is "hello world" param-foo = s required default-foo = hello world # the value is "list;of;misc;" (it's not parsed as a list) param-semicolons=s secret default-semicolons=list;of;misc; # the values is a list ["list", "of", "misc"] param-list = as default-list = list;of;misc; # the spec says this is invalid but we should probably be permissive param-unterminated-list = as default-unterminated-list = list;of;misc # the value is a list ["list", " of", " misc "] (spaces significant) param-spaces-in-list = as default-spaces-in-list = list; of; misc ; # the value is a list ["list;of", "misc"] param-escaped-semicolon-in-list = as default-escaped-semicolon-in-list = list\;of;misc; # the value is a list ["list\", "of", "misc"] param-doubly-escaped-semicolon-in-list = as default-doubly-escaped-semicolon-in-list = list\\;of;misc; # the value is a list ["list\;of", "misc"] param-triply-escaped-semicolon-in-list = as default-triply-escaped-semicolon-in-list = list\\\;of;misc; # the value is an empty list param-empty-list = as default-empty-list = # the value is a list of empty string param-list-of-empty-string = as default-list-of-empty-string = ; # this is probably technically a Desktop Entry spec violation? # we should be permissive, interpreting this as either "foo\;bar" or "foo;bar" # seems reasonable param-escaped-semicolon = s default-escaped-semicolon = foo\;bar # all the other types param-object = o default-object = /misc param-q = q default-q = 42 param-u = u default-u = 42 param-t = t default-t = 42 param-n = n default-n = -42 param-i = i default-i = -42 param-x = x default-x = -42 param-d = 42.0 default-d = 42.0 telepathy-qt-0.9.6~git1/tests/telepathy/managers/protocol.manager0000664000175000017500000000203112470405660023077 0ustar jrjr[ConnectionManager] Interfaces= [Protocol protocol] Interfaces=org.freedesktop.Telepathy.Protocol.Interface.Addressing;org.freedesktop.Telepathy.Protocol.Interface.Avatars;org.freedesktop.Telepathy.Protocol.Interface.Presence; param-account=s required register ConnectionInterfaces=org.freedesktop.Telepathy.Connection.Interface.Contacts; RequestableChannelClasses=1-1-text; VCardField=x-telepathy-protocol EnglishName=Telepathy Protocol Icon=im-protocol status-offline=1 status-available=2 settable message SupportedAvatarMIMETypes=image/jpeg; MinimumAvatarHeight=32 RecommendedAvatarHeight=64 MaximumAvatarHeight=96 MinimumAvatarWidth=32 RecommendedAvatarWidth=64 MaximumAvatarWidth=96 MaximumAvatarBytes=37748736 AddressableVCardFields=x-protocol; AddressableURISchemes=protocol; [1-1-text] org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text org.freedesktop.Telepathy.Channel.TargetHandleType u=1 allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID; telepathy-qt-0.9.6~git1/tests/telepathy/managers/test-manager-file-malformed-keyfile.manager0000664000175000017500000000007412470405660030141 0ustar jrjr[Protocol foo [Protocol bar param-account = s required = = telepathy-qt-0.9.6~git1/tests/telepathy/managers/test-manager-file.manager0000664000175000017500000000622212470405660024550 0ustar jrjr[Protocol foo] param-account = s required param-password = s required param-encryption-key = s secret param-port = q param-register = b param-server-list = as default-account = foo@default default-port = 1234 default-server-list = foo;bar; status-offline=1 status-dnd=6 settable status-available=2 settable message SupportedAvatarMIMETypes=image/png;image/jpeg;image/gif; MinimumAvatarHeight=32 RecommendedAvatarHeight=64 MaximumAvatarHeight=96 MinimumAvatarWidth=32 RecommendedAvatarWidth=64 MaximumAvatarWidth=96 MaximumAvatarBytes=8192 VCardField=x-foo EnglishName=Foo Icon=im-foo RequestableChannelClasses=ft;foo text; AddressableVCardFields=x-foo; AddressableURISchemes=foo; [ft] org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.FileTransfer org.freedesktop.Telepathy.Channel.TargetHandleType u=1 org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentHashType u=1 allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID; [foo text] org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text org.freedesktop.Telepathy.Channel.TargetHandleType u=1 allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID; [Protocol bar] param-account = s required param-encryption-key = s required secret param-password = s required param-port = q param-register = b param-server-list = as default-account = bar@default default-port = 4321 default-server-list = bar;foo; [Protocol somewhat-pathological] # the value is "hello world" param-foo = s required default-foo = hello world # the value is "list;of;misc;" (it's not parsed as a list) param-semicolons=s secret default-semicolons=list;of;misc; # the values is a list ["list", "of", "misc"] param-list = as default-list = list;of;misc; # the spec says this is invalid but we should probably be permissive param-unterminated-list = as default-unterminated-list = list;of;misc # the value is a list ["list", " of", " misc "] (spaces significant) param-spaces-in-list = as default-spaces-in-list = list; of; misc ; # the value is a list ["list;of", "misc"] param-escaped-semicolon-in-list = as default-escaped-semicolon-in-list = list\;of;misc; # the value is a list ["list\", "of", "misc"] param-doubly-escaped-semicolon-in-list = as default-doubly-escaped-semicolon-in-list = list\\;of;misc; # the value is a list ["list\;of", "misc"] param-triply-escaped-semicolon-in-list = as default-triply-escaped-semicolon-in-list = list\\\;of;misc; # the value is an empty list param-empty-list = as default-empty-list = # the value is a list of empty string param-list-of-empty-string = as default-list-of-empty-string = ; # this is probably technically a Desktop Entry spec violation? # we should be permissive, interpreting this as either "foo\;bar" or "foo;bar" # seems reasonable param-escaped-semicolon = s default-escaped-semicolon = foo\;bar # all the other types param-object = o default-object = /misc param-q = q default-q = 42 param-u = u default-u = 42 param-t = t default-t = 42 param-n = n default-n = -42 param-i = i default-i = -42 param-x = x default-x = -42 param-d = d default-d = 42.0 telepathy-qt-0.9.6~git1/tests/telepathy/profiles/0000775000175000017500000000000012470405660017734 5ustar jrjrtelepathy-qt-0.9.6~git1/tests/telepathy/profiles/test-profile-invalid-service-id.profile0000664000175000017500000000221012470405660027402 0ustar jrjr TestProfile profile.com 1111 3 org.freedesktop.Telepathy.Channel.Type.Text telepathy-qt-0.9.6~git1/tests/telepathy/profiles/test-profile-non-im-type.profile0000664000175000017500000000050612470405660026106 0ustar jrjr TestProfile telepathy-qt-0.9.6~git1/tests/telepathy/profiles/test-profile-malformed.profile0000664000175000017500000000017312470405660025700 0ustar jrjr TestProfile profile.com 1111 1 org.freedesktop.Telepathy.Channel.Type.Text 3 org.freedesktop.Telepathy.Channel.Type.Text telepathy-qt-0.9.6~git1/tests/telepathy/profiles/test-profile-no-icon-and-provider.profile0000664000175000017500000000034012470405660027660 0ustar jrjr telepathy-qt-0.9.6~git1/CMakeLists.txt0000664000175000017500000002711312470405660015514 0ustar jrjrproject(TelepathyQt) cmake_minimum_required(VERSION 2.6) # CMake policies are used for backwards compatibilty. Setting a policy to a behavior lets newer # CMake versions where some behaviors changed behave in a way or another. In our specific case, # From CMake's documentation: # # In CMake 2.6.2 and below, CMake Policy settings in scripts loaded by # the include() and find_package() commands would affect the includer. # Explicit invocations of cmake_policy(PUSH) and cmake_policy(POP) were # required to isolate policy changes and protect the includer. While # some scripts intend to affect the policies of their includer, most do # not. In CMake 2.6.3 and above, include() and find_package() by # default PUSH and POP an entry on the policy stack around an included # script, but provide a NO_POLICY_SCOPE option to disable it. This # policy determines whether or not to imply NO_POLICY_SCOPE for # compatibility. The OLD behavior for this policy is to imply # NO_POLICY_SCOPE for include() and find_package() commands. The NEW # behavior for this policy is to allow the commands to do their default # cmake_policy PUSH and POP. # # This policy was introduced in CMake version 2.6.3. CMake version # 2.8.2 warns when the policy is not set and uses OLD behavior. Use the # cmake_policy command to set it to OLD or NEW explicitly. # # Whenever our cmake_minimum_required version bumps up to 2.7 or 2.6.3, this policy setting can # hence be removed. if(POLICY CMP0011) cmake_policy(SET CMP0011 NEW) endif(POLICY CMP0011) # Making releases: # set the new version number: # odd minor -> development series # even minor -> stable series # increment micro for each release within a series # set nano_version to 0 # make the release, tag it # set nano_version to 1 set(TP_QT_MAJOR_VERSION 0) set(TP_QT_MINOR_VERSION 9) set(TP_QT_MICRO_VERSION 6) set(TP_QT_NANO_VERSION 0) set(PACKAGE_NAME telepathy-qt) if (${TP_QT_NANO_VERSION} EQUAL 0) set(PACKAGE_VERSION ${TP_QT_MAJOR_VERSION}.${TP_QT_MINOR_VERSION}.${TP_QT_MICRO_VERSION}) else (${TP_QT_NANO_VERSION} EQUAL 0) set(PACKAGE_VERSION ${TP_QT_MAJOR_VERSION}.${TP_QT_MINOR_VERSION}.${TP_QT_MICRO_VERSION}.${TP_QT_NANO_VERSION}) endif (${TP_QT_NANO_VERSION} EQUAL 0) # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is # checked set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") # Default build type is RelWithDebInfo for release versions and Debug for developement # versions if(NOT CMAKE_BUILD_TYPE) if(TP_QT_NANO_VERSION EQUAL 0) set(CMAKE_BUILD_TYPE RelWithDebInfo) else(TP_QT_NANO_VERSION EQUAL 0) set(CMAKE_BUILD_TYPE Debug) endif(TP_QT_NANO_VERSION EQUAL 0) endif(NOT CMAKE_BUILD_TYPE) # This file contains all the needed initialization macros include(TelepathyDefaults) # This file contains all the tpqt macros used in the buildsystem include(TpQtMacros) include(MacroLogFeature) # external dependencies # Required dependencies # Find qt4 version >= 4.6 or qt5 >= 5.0.0 set(QT4_MIN_VERSION "4.6.0") set(QT4_MAX_VERSION "5.0.0") set(QT5_MIN_VERSION "5.0.0") set(QT5_MAX_VERSION "6.0.0") find_package(Qt REQUIRED) IF(QT_VERSION_MAJOR MATCHES 5) # It is QtCore for Qt4 but Qt5Core for Qt5 in pkg-config SET(QT_VERSION_PC 5) ENDIF(QT_VERSION_MAJOR MATCHES 5) foreach(flag ${QT_CONFIG_FLAGS}) if (${flag} MATCHES "reduce_relocations") set(TP_QT_EXECUTABLE_LINKER_FLAGS "-fPIE") set(TP_QT_LIBRARY_LINKER_FLAGS "-fPIC") endif (${flag} MATCHES "reduce_relocations") endforeach(flag ${QT_CONFIG_FLAGS}) # This value contains the library's SOVERSION. This value is to be increased everytime an API/ABI break # occurs, and will be used for the SOVERSION of the generated shared libraries. if (${QT_VERSION_MAJOR} EQUAL 4) set(TP_QT_ABI_VERSION 2) else (${QT_VERSION_MAJOR} EQUAL 4) set(TP_QT_ABI_VERSION 0) endif (${QT_VERSION_MAJOR} EQUAL 4) # This variable is used for the library's long version. It is generated dynamically, so don't change its # value! Change TP_QT_ABI_VERSION and TP_QT_*_VERSION instead. if (${TP_QT_NANO_VERSION} EQUAL 0) set(TP_QT_LIBRARY_VERSION ${TP_QT_ABI_VERSION}.${TP_QT_MAJOR_VERSION}.${TP_QT_MINOR_VERSION}.${TP_QT_MICRO_VERSION}) else (${TP_QT_NANO_VERSION} EQUAL 0) set(TP_QT_LIBRARY_VERSION ${TP_QT_ABI_VERSION}.${TP_QT_MAJOR_VERSION}.${TP_QT_MINOR_VERSION}.${TP_QT_MICRO_VERSION}.${TP_QT_NANO_VERSION}) endif (${TP_QT_NANO_VERSION} EQUAL 0) # Add an option for compiling tp-qt-service option(ENABLE_SERVICE_SUPPORT "Enable compilation of service side bindings for Telepathy-Qt" TRUE) # Add an option for compiling examples option(ENABLE_EXAMPLES "Enable compilation of examples for Telepathy-Qt" TRUE) # Add an option for compiling Farstream option(ENABLE_FARSTREAM "Enable compilation of Farstream bindings" TRUE) # Add an option for building tests option(ENABLE_TESTS "Enable compilation of automated tests" TRUE) # The doxygen macro requires Qt to have been looked up to enable crosslinking include(Doxygen) include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${QT_INCLUDES}) add_definitions(-DQT_NO_CAST_FROM_ASCII) set(ENABLE_DEBUG_OUTPUT ON CACHE BOOL "If activated, compiles support for printing debug output to stderr") if (ENABLE_DEBUG_OUTPUT) add_definitions(-DENABLE_DEBUG) endif (ENABLE_DEBUG_OUTPUT) # Check for Qt Glib support include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_INCLUDES ${QT_INCLUDES}) set(CMAKE_REQUIRED_DEFINITIONS "") # set the flags (-fPIE) here so that CHECK_CXX_SOURCE_COMPILES works properly if qt5 was built with # -reduce-locations set(CMAKE_REQUIRED_FLAGS "${TP_QT_EXECUTABLE_LINKER_FLAGS}") CHECK_CXX_SOURCE_COMPILES(" #include int main() { #if defined(QT_NO_GLIB) #error \"Qt was compiled with Glib disabled\" #endif return 0; }" QT_GLIB_SUPPORT) macro_log_feature(QT_GLIB_SUPPORT "Qt Glib Support" "QtCore library using Glib's main event loop" "http://qt.nokia.com/" FALSE "" "Needed, together with Telepathy-Glib, to build most of the unit tests") # reset flags set(CMAKE_REQUIRED_FLAGS "") # Find python version >= 2.5 find_package(PythonLibrary REQUIRED) set(REQUIRED_PY 2.5) if(${PYTHON_SHORT_VERSION} VERSION_GREATER ${REQUIRED_PY} OR ${PYTHON_SHORT_VERSION} VERSION_EQUAL ${REQUIRED_PY}) message(STATUS "Python ${PYTHON_SHORT_VERSION} found") else(${PYTHON_SHORT_VERSION} VERSION_GREATER ${REQUIRED_PY} OR ${PYTHON_SHORT_VERSION} VERSION_EQUAL ${REQUIRED_PY}) message(SEND_ERROR "Python >= ${REQUIRED_PY} is required") endif(${PYTHON_SHORT_VERSION} VERSION_GREATER ${REQUIRED_PY} OR ${PYTHON_SHORT_VERSION} VERSION_EQUAL ${REQUIRED_PY}) # Check for dbus-python execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import dbus.mainloop.glib" RESULT_VARIABLE PYTHON_DBUS_RESULT) if(PYTHON_DBUS_RESULT EQUAL 0) set(HAVE_TEST_PYTHON 1) else(PYTHON_DBUS_RESULT EQUAL 0) set(HAVE_TEST_PYTHON 0) endif(PYTHON_DBUS_RESULT EQUAL 0) macro_log_feature(HAVE_TEST_PYTHON "dbus-python" "GLib-based Python DBus support" "http://www.python.org/" FALSE "" "Needed to build some additional unit tests") if(ENABLE_TESTS OR ENABLE_FARSTREAM) # Find telepathy-glib set(TELEPATHY_GLIB_MIN_VERSION 0.18.0) find_package(TelepathyGlib) macro_log_feature(TELEPATHYGLIB_FOUND "Telepathy-glib" "Glib bindings for Telepathy" "http://telepathy.freedesktop.org/" FALSE ${TELEPATHY_GLIB_MIN_VERSION} "Needed, together with Qt Glib integration, to build most of the unit tests") find_program(GLIB_GENMARSHAL glib-genmarshal) # Find GLib2, GObject, DBus and LibXml2 # Those are needed for the insane include dir dependency hell find_package(GLIB2) find_package(GObject) find_package(GIO) find_package(GIOUnix) find_package(DBus) find_package(DBusGLib) find_package(LibXml2) endif() if(ENABLE_FARSTREAM) # Find tp-farstream set(FARSTREAM_MIN_VERSION "0.2.0") find_package(Farstream) macro_log_feature(FARSTREAM_FOUND "Farstream" "A Framework for dealing with audio/video conferencing protocols" "http://www.freedesktop.org/wiki/Software/Farstream" FALSE "${FARSTREAM_MIN_VERSION}" "Needed, together with GStreamer and Telepathy-Farstream, to build telepathy-qt-farstream") # Find tp-farstream set(TELEPATHY_FARSTREAM_MIN_VERSION "0.6.0") find_package(TelepathyFarstream) macro_log_feature(TELEPATHYFARSTREAM_FOUND "Telepathy-Farstream" "A Framework for dealing with audio/video conferencing protocols" "http://telepathy.freedesktop.org/wiki/" FALSE "${TELEPATHY_FARSTREAM_MIN_VERSION}" "Needed, together with GStreamer and Farstream, to build telepathy-qt-farstream") endif() if(ENABLE_FARSTREAM) # Find GStreamer find_package(GStreamer) macro_log_feature(GSTREAMER_FOUND "GStreamer" "An open source multimedia framework" "Needed, together with Tp-Farstream, to build telepathy-qt-farstream and some additional examples" "http://www.gstreamer.net/" FALSE) endif() # Build TelepathyQt-Farstream only if GStreamer, TelepathyFarstream and all of their dependencies were found if (TELEPATHYFARSTREAM_FOUND AND FARSTREAM_FOUND AND GSTREAMER_FOUND AND GLIB2_FOUND AND GOBJECT_FOUND AND DBUS_FOUND AND LIBXML2_FOUND AND TELEPATHYGLIB_FOUND AND ENABLE_FARSTREAM) set (FARSTREAM_COMPONENTS_FOUND 1) else (TELEPATHYFARSTREAM_FOUND AND FARSTREAM_FOUND AND GSTREAMER_FOUND AND GLIB2_FOUND AND GOBJECT_FOUND AND DBUS_FOUND AND LIBXML2_FOUND AND TELEPATHYGLIB_FOUND AND ENABLE_FARSTREAM) set (FARSTREAM_COMPONENTS_FOUND 0) endif (TELEPATHYFARSTREAM_FOUND AND FARSTREAM_FOUND AND GSTREAMER_FOUND AND GLIB2_FOUND AND GOBJECT_FOUND AND DBUS_FOUND AND LIBXML2_FOUND AND TELEPATHYGLIB_FOUND AND ENABLE_FARSTREAM) if (ENABLE_TESTS) # Enable glib-based tests only if Qt has GLib support and Telepathy-glib was found if(QT_GLIB_SUPPORT AND TELEPATHYGLIB_FOUND AND GLIB2_FOUND AND DBUS_FOUND) # Disable GLib deprecation warnings for now; GValueArray is deprecated but we # need it for telepathy-glib. add_definitions(-DGLIB_DISABLE_DEPRECATION_WARNINGS) set(ENABLE_TP_GLIB_TESTS 1) if(GIO_FOUND AND GIOUNIX_FOUND) set(ENABLE_TP_GLIB_GIO_TESTS 1) else(GIO_FOUND AND GIOUNIX_FOUND) set(ENABLE_TP_GLIB_GIO_TESTS 0) endif(GIO_FOUND AND GIOUNIX_FOUND) else(QT_GLIB_SUPPORT AND TELEPATHYGLIB_FOUND AND GLIB2_FOUND AND DBUS_FOUND) set(ENABLE_TP_GLIB_TESTS 0) set(ENABLE_TP_GLIB_GIO_TESTS 0) endif(QT_GLIB_SUPPORT AND TELEPATHYGLIB_FOUND AND GLIB2_FOUND AND DBUS_FOUND) endif(ENABLE_TESTS) # Add the source subdirectories add_subdirectory(TelepathyQt) if(ENABLE_EXAMPLES) add_subdirectory(examples) endif() if(ENABLE_TESTS) add_subdirectory(tests) endif() add_subdirectory(tools) # Generate config.h and config-version.h configure_file(${CMAKE_SOURCE_DIR}/config.h.in ${CMAKE_BINARY_DIR}/config.h) configure_file(${CMAKE_SOURCE_DIR}/config-version.h.in ${CMAKE_BINARY_DIR}/config-version.h) # Create the uninstall target configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") # Display the feature log macro_display_feature_log() # Always keep it last: CPack definitions file include(TelepathyDist) telepathy-qt-0.9.6~git1/examples/0000775000175000017500000000000012470405660014566 5ustar jrjrtelepathy-qt-0.9.6~git1/examples/accounts/0000775000175000017500000000000012470405660016405 5ustar jrjrtelepathy-qt-0.9.6~git1/examples/accounts/main.cpp0000664000175000017500000000057212470405660020041 0ustar jrjr#include #include #include #include #include #include "accounts-window.h" int main(int argc, char **argv) { QApplication app(argc, argv); Tp::registerTypes(); Tp::enableDebug(true); Tp::enableWarnings(true); AccountsWindow w; w.show(); return app.exec(); } telepathy-qt-0.9.6~git1/examples/accounts/accounts-window.cpp0000664000175000017500000000611512470405660022240 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "accounts-window.h" #include "_gen/accounts-window.moc.hpp" #include "account-item.h" #include #include #include #include #include #include #include #include #include #include #include #include AccountsWindow::AccountsWindow(QWidget *parent) : QMainWindow(parent) { setupGui(); mAM = Tp::AccountManager::create(Tp::AccountFactory::create(QDBusConnection::sessionBus(), Tp::Account::FeatureCore)); connect(mAM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onAMReady(Tp::PendingOperation *))); connect(mAM.data(), SIGNAL(newAccount(const Tp::AccountPtr &)), SLOT(onNewAccount(const Tp::AccountPtr &))); } AccountsWindow::~AccountsWindow() { } void AccountsWindow::setupGui() { mTable = new QTableWidget; mTable->setColumnCount(AccountItem::NumColumns); QStringList headerLabels; headerLabels << QLatin1String("Valid") << QLatin1String("Enabled") << QLatin1String("Connection Manager") << QLatin1String("Protocol Name") << QLatin1String("Display Name") << QLatin1String("Nickname") << QLatin1String("Connects Automatically") << QLatin1String("Changing Presence") << QLatin1String("Automatic Presence") << QLatin1String("Current Presence") << QLatin1String("Requested Presence") << QLatin1String("Connection Status") << QLatin1String("Connection"); mTable->setHorizontalHeaderLabels(headerLabels); setCentralWidget(mTable); } void AccountsWindow::onAMReady(Tp::PendingOperation *op) { mTable->setRowCount(mAM->allAccounts().count()); int row = 0; foreach (const Tp::AccountPtr &acc, mAM->allAccounts()) { (void) new AccountItem(acc, mTable, row++, this); } } void AccountsWindow::onNewAccount(const Tp::AccountPtr &acc) { int row = mTable->rowCount(); mTable->insertRow(row); (void) new AccountItem(acc, mTable, row, this); } telepathy-qt-0.9.6~git1/examples/accounts/CMakeLists.txt0000664000175000017500000000104412470405660021144 0ustar jrjrset(accounts_SRCS main.cpp account-item.cpp account-item.h accounts-window.cpp accounts-window.h) set(accounts_MOC_SRCS account-item.h accounts-window.h) tpqt_generate_mocs(${accounts_MOC_SRCS}) add_executable(accounts ${accounts_SRCS} ${accounts_MOC_SRCS}) target_link_libraries(accounts ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTWIDGETS_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_EXECUTABLE_LINKER_FLAGS}) telepathy-qt-0.9.6~git1/examples/accounts/account-item.cpp0000664000175000017500000001537712470405660021516 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "account-item.h" #include "_gen/account-item.moc.hpp" #include #include #include #include #include AccountItem::AccountItem(Tp::AccountPtr acc, QTableWidget *table, int row, QObject *parent) : QObject(parent), mAcc(acc), mTable(table), mRow(row) { init(); } AccountItem::~AccountItem() { } void AccountItem::setupGui() { mTable->setItem(mRow, ColumnValid, new QTableWidgetItem(mAcc->isValid() ? QLatin1String("true") : QLatin1String("false"))); mTable->setItem(mRow, ColumnEnabled, new QTableWidgetItem(mAcc->isEnabled() ? QLatin1String("true") : QLatin1String("false"))); mTable->setItem(mRow, ColumnConnectionManager, new QTableWidgetItem(mAcc->cmName())); mTable->setItem(mRow, ColumnProtocol, new QTableWidgetItem(mAcc->protocolName())); mTable->setItem(mRow, ColumnDisplayName, new QTableWidgetItem(mAcc->displayName())); mTable->setItem(mRow, ColumnNickname, new QTableWidgetItem(mAcc->nickname())); mTable->setItem(mRow, ColumnConnectsAutomatically, new QTableWidgetItem(mAcc->connectsAutomatically() ? QLatin1String("true") : QLatin1String("false"))); mTable->setItem(mRow, ColumnAutomaticPresence, new QTableWidgetItem(mAcc->automaticPresence().status())); mTable->setItem(mRow, ColumnCurrentPresence, new QTableWidgetItem(mAcc->currentPresence().status())); mTable->setItem(mRow, ColumnRequestedPresence, new QTableWidgetItem(mAcc->requestedPresence().status())); mTable->setItem(mRow, ColumnChangingPresence, new QTableWidgetItem(mAcc->isChangingPresence() ? QLatin1String("true") : QLatin1String("false"))); mTable->setItem(mRow, ColumnConnectionStatus, new QTableWidgetItem(QString::number(mAcc->connectionStatus()))); mTable->setItem(mRow, ColumnConnection, new QTableWidgetItem( mAcc->connection().isNull() ? QLatin1String("") : mAcc->connection()->objectPath())); } void AccountItem::init() { setupGui(); Tp::Account *acc = mAcc.data(); connect(acc, SIGNAL(validityChanged(bool)), SLOT(onValidityChanged(bool))); connect(acc, SIGNAL(stateChanged(bool)), SLOT(onStateChanged(bool))); connect(acc, SIGNAL(displayNameChanged(const QString &)), SLOT(onDisplayNameChanged(const QString &))); connect(acc, SIGNAL(nicknameChanged(const QString &)), SLOT(onNicknameChanged(const QString &))); connect(acc, SIGNAL(connectsAutomaticallyPropertyChanged(bool)), SLOT(onConnectsAutomaticallyPropertyChanged(bool))); connect(acc, SIGNAL(changingPresence(bool)), SLOT(onChangingPresenceChanged(bool))); connect(acc, SIGNAL(automaticPresenceChanged(const Tp::SimplePresence &)), SLOT(onAutomaticPresenceChanged(const Tp::SimplePresence &))); connect(acc, SIGNAL(currentPresenceChanged(const Tp::SimplePresence &)), SLOT(onCurrentPresenceChanged(const Tp::SimplePresence &))); connect(acc, SIGNAL(requestedPresenceChanged(const Tp::SimplePresence &)), SLOT(onRequestedPresenceChanged(const Tp::SimplePresence &))); connect(acc, SIGNAL(statusChanged(Tp::ConnectionStatus, Tp::ConnectionStatusReason, const QString &, const QVariantMap &)), SLOT(onStatusChanged(Tp::ConnectionStatus, Tp::ConnectionStatusReason, const QString &, const QVariantMap &))); connect(acc, SIGNAL(haveConnectionChanged(bool)), SLOT(onHaveConnectionChanged(bool))); } void AccountItem::onValidityChanged(bool valid) { QTableWidgetItem *item = mTable->item(mRow, ColumnValid); item->setText((valid ? QLatin1String("true") : QLatin1String("false"))); } void AccountItem::onStateChanged(bool enabled) { QTableWidgetItem *item = mTable->item(mRow, ColumnEnabled); item->setText((enabled ? QLatin1String("true") : QLatin1String("false"))); } void AccountItem::onDisplayNameChanged(const QString &name) { QTableWidgetItem *item = mTable->item(mRow, ColumnDisplayName); item->setText(name); } void AccountItem::onNicknameChanged(const QString &name) { QTableWidgetItem *item = mTable->item(mRow, ColumnNickname); item->setText(name); } void AccountItem::onConnectsAutomaticallyPropertyChanged(bool value) { QTableWidgetItem *item = mTable->item(mRow, ColumnConnectsAutomatically); item->setText((value ? QLatin1String("true") : QLatin1String("false"))); } void AccountItem::onChangingPresenceChanged(bool value) { QTableWidgetItem *item = mTable->item(mRow, ColumnChangingPresence); item->setText((value ? QLatin1String("true") : QLatin1String("false"))); } void AccountItem::onAutomaticPresenceChanged(const Tp::SimplePresence &presence) { QTableWidgetItem *item = mTable->item(mRow, ColumnAutomaticPresence); item->setText(presence.status); } void AccountItem::onCurrentPresenceChanged(const Tp::SimplePresence &presence) { QTableWidgetItem *item = mTable->item(mRow, ColumnCurrentPresence); item->setText(presence.status); } void AccountItem::onRequestedPresenceChanged(const Tp::SimplePresence &presence) { QTableWidgetItem *item = mTable->item(mRow, ColumnRequestedPresence); item->setText(presence.status); } void AccountItem::onStatusChanged(Tp::ConnectionStatus status, Tp::ConnectionStatusReason reason, const QString &error, const QVariantMap &errorDetails) { QTableWidgetItem *item = mTable->item(mRow, ColumnConnectionStatus); item->setText(QString::number(status)); } void AccountItem::onHaveConnectionChanged(bool haveConnection) { QTableWidgetItem *item = mTable->item(mRow, ColumnConnection); item->setText(mAcc->connection().isNull() ? QLatin1String("") : mAcc->connection()->objectPath()); } telepathy-qt-0.9.6~git1/examples/accounts/accounts-window.h0000664000175000017500000000275612470405660021714 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_accounts_accounts_window_h_HEADER_GUARD_ #define _TelepathyQt_examples_accounts_accounts_window_h_HEADER_GUARD_ #include #include namespace Tp { class PendingOperation; } class QTableWidget; class QTableWidgetItem; class AccountsWindow : public QMainWindow { Q_OBJECT public: AccountsWindow(QWidget *parent = 0); virtual ~AccountsWindow(); private Q_SLOTS: void onAMReady(Tp::PendingOperation *); void onNewAccount(const Tp::AccountPtr &); private: void setupGui(); Tp::AccountManagerPtr mAM; QTableWidget *mTable; }; #endif telepathy-qt-0.9.6~git1/examples/accounts/account-item.h0000664000175000017500000000513512470405660021152 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_accounts_account_item_h_HEADER_GUARD_ #define _TelepathyQt_examples_accounts_account_item_h_HEADER_GUARD_ #include #include #include #include namespace Tp { class AccountManager; class PendingOperation; } class QTableWidget; class AccountItem : public QObject { Q_OBJECT public: enum Columns { ColumnValid = 0, ColumnEnabled, ColumnConnectionManager, ColumnProtocol, ColumnDisplayName, ColumnNickname, ColumnConnectsAutomatically, ColumnChangingPresence, ColumnAutomaticPresence, ColumnCurrentPresence, ColumnRequestedPresence, ColumnConnectionStatus, ColumnConnection, NumColumns }; Q_ENUMS(Columns) AccountItem(Tp::AccountPtr acc, QTableWidget *table, int row, QObject *parent = 0); virtual ~AccountItem(); int row() const { return mRow; } private Q_SLOTS: void onValidityChanged(bool); void onStateChanged(bool); void onDisplayNameChanged(const QString &); void onNicknameChanged(const QString &); void onConnectsAutomaticallyPropertyChanged(bool); void onChangingPresenceChanged(bool); void onAutomaticPresenceChanged(const Tp::SimplePresence &); void onCurrentPresenceChanged(const Tp::SimplePresence &); void onRequestedPresenceChanged(const Tp::SimplePresence &); void onStatusChanged(Tp::ConnectionStatus, Tp::ConnectionStatusReason, const QString &error, const QVariantMap &errorDetails); void onHaveConnectionChanged(bool); private: void init(); void setupGui(); Tp::AccountPtr mAcc; QTableWidget *mTable; int mRow; }; #endif telepathy-qt-0.9.6~git1/examples/extensions/0000775000175000017500000000000012470405660016765 5ustar jrjrtelepathy-qt-0.9.6~git1/examples/extensions/cli-connection.cpp0000664000175000017500000000010312470405660022367 0ustar jrjr#include "cli-connection.h" #include "_gen/cli-connection.moc.hpp" telepathy-qt-0.9.6~git1/examples/extensions/cli-connection.h0000664000175000017500000000021412470405660022037 0ustar jrjr#ifndef _Example_Client_Connection_HEADER_GUARD_ #define _Example_Client_Connection_HEADER_GUARD_ #include "_gen/cli-connection.h" #endif telepathy-qt-0.9.6~git1/examples/extensions/Connection_Interface_Hats.xml0000664000175000017500000001450712470405660024554 0ustar jrjr Copyright (C) 2007 Collabora Ltd. Copyright (C) 2007 Nokia Corporation Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This interface is an example of how Telepathy can be extended. For the purposes of this example, we pretend we're an organisation example.com that's adding a proprietary extension to Telepathy, so the extension is not in the main Telepathy namespace. A data structure representing a contact and their hat. The contact wearing the hat. The color of the hat The style of the hat Optional key-value pairs describing extended properties of the hat. There is no hat. color MUST be the empty string and properties MUST be an empty mapping. An unspecified type of hat. A fedora, which MAY be red. A knitted hat, with or without a bobble. A bowler hat, as worn by stereotypical English businessmen. A hat with protective qualities. Emitted when the contact's hat has changed. The handle representing the contact's ID on the server The color of the contact's hat. The style of the contact's hat. There's always an a{sv}. Perhaps there's some special religious reason. Request a list of the hats worn by the given contacts. The handles of the contacts whose hats are requested A list of contacts and their hats. Indicate that the hat currently being worn by the local user has changed. The color of the contact's hat. The style of the contact's hat. There's always an a{sv}... Request the prices of a contact's current hat. The handle of the contact whose hat we're interested in purchasing. The price of the hat. This hat is not for sale. Get your own style, you trend-follower! telepathy-qt-0.9.6~git1/examples/extensions/connection.xml0000664000175000017500000000040412470405660021644 0ustar jrjr Connection extensions for 'extended' example telepathy-qt-0.9.6~git1/examples/extensions/types.cpp0000664000175000017500000000003712470405660020635 0ustar jrjr#include "_gen/types-body.hpp" telepathy-qt-0.9.6~git1/examples/extensions/CMakeLists.txt0000664000175000017500000000756412470405660021541 0ustar jrjr# This directory is an example of how to build extensions to the spec. # Typically this would be in a top-level extensions/ directory. # In this example we build an optional interface for Telepathy Connections, # so we specify Tp::Client::ConnectionInterface as the main interface for the # generated proxies with "--mainiface=Tp::Client::ConnectionInterface'. The # generated proxies will have a convenience constructors for associating the # proxy with the same remote object an instance of the main interface class # is associated with. We could instead have made an optional interface for any # other class, or by leaving that option out entirely we could have made an # extension that will work on QDBusAbstractInterface or any subclass of it. # # For stand-alone interfaces (for which the interface itself should be considered # the main interface) --mainiface should be specified as fully namespaced name # of the interface class itself. set(example_extensions_SRCS cli-connection.cpp cli-connection.h types.cpp) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/_gen) set(generated_all_xml ${CMAKE_CURRENT_BINARY_DIR}/_gen/all.xml) tpqt_xincludator(example-extensions-includator ${CMAKE_CURRENT_SOURCE_DIR}/all.xml ${generated_all_xml}) tpqt_constants_gen(example-extensions-constants ${generated_all_xml} ${CMAKE_CURRENT_BINARY_DIR}/_gen/constants.h --namespace=Example --str-constant-prefix=EXAMPLE_ DEPENDS example-extensions-includator) if(MSVC) set(TYPES_INCLUDE ^) else(MSVC) set(TYPES_INCLUDE '') endif(MSVC) tpqt_types_gen(example-extensions-typesgen ${generated_all_xml} ${CMAKE_CURRENT_BINARY_DIR}/_gen/types.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/types-body.hpp Example types.h types.h --extraincludes=${TYPES_INCLUDE} DEPENDS example-extensions-constants) set(connection_generated_xml ${CMAKE_CURRENT_BINARY_DIR}/_gen/connection.xml) tpqt_xincludator(example-extensions-connection-includator ${CMAKE_CURRENT_SOURCE_DIR}/connection.xml ${connection_generated_xml}) if(MSVC) set(ESCAPED_QUOTES \"\"\") set(connection_include ^) else(MSVC) set(ESCAPED_QUOTES \\\") set(connection_include '') endif(MSVC) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection-body.hpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection.h COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/tools/qt-client-gen.py --namespace=Example::Client --typesnamespace=Example --headerfile=${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection.h --implfile=${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection-body.hpp --realinclude=${CMAKE_CURRENT_SRC_DIR}/cli-connection.h --specxml=${generated_all_xml} --ifacexml=${connection_generated_xml} --extraincludes=${connection_include},${ESCAPED_QUOTES}types.h${ESCAPED_QUOTES} --mainiface=Tp::Client::ConnectionInterface) add_custom_target(example-extensions-connection-generation) add_dependencies(example-extensions-connection-generation example-extensions-connection-includator example-extensions-typesgen) list(APPEND example_extensions_SRCS ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection-body.hpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection.h) tpqt_generate_moc_i(${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection.moc.hpp) list(APPEND example_extensions_SRCS ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection.moc.hpp) add_library(example_extensions STATIC ${example_extensions_SRCS}) add_dependencies(example_extensions example-extensions-connection-generation) target_link_libraries(example_extensions ${QT_QTDBUS_LIBRARY} ${QT_QTCORE_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_LIBRARY_LINKER_FLAGS}) telepathy-qt-0.9.6~git1/examples/extensions/all.xml0000664000175000017500000000105012470405660020253 0ustar jrjr Extensions for 'extended' examples telepathy-qt-0.9.6~git1/examples/extensions/types.h0000664000175000017500000000015312470405660020301 0ustar jrjr#ifndef _Example_Types_HEADER_GUARD_ #define _Example_Types_HEADER_GUARD_ #include "_gen/types.h" #endif telepathy-qt-0.9.6~git1/examples/contact-messenger/0000775000175000017500000000000012470405660020207 5ustar jrjrtelepathy-qt-0.9.6~git1/examples/contact-messenger/CMakeLists.txt0000664000175000017500000000067012470405660022752 0ustar jrjrset(messenger-sender_SRCS sender.cpp) set(messenger-sender_MOC_SRCS sender.h) tpqt_generate_mocs(${messenger-sender_MOC_SRCS}) add_executable(messenger-sender ${messenger-sender_SRCS} ${messenger-sender_MOC_SRCS}) target_link_libraries(messenger-sender ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_EXECUTABLE_LINKER_FLAGS}) telepathy-qt-0.9.6~git1/examples/contact-messenger/sender.cpp0000664000175000017500000000502512470405660022175 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "sender.h" #include "_gen/sender.moc.hpp" #include #include #include #include #include #include #include Sender::Sender(const QString &accountPath, const QString &contactIdentifier, const QString &message) { Tp::AccountPtr acc = Tp::Account::create(TP_QT_ACCOUNT_MANAGER_BUS_NAME, accountPath); messenger = Tp::ContactMessenger::create(acc, contactIdentifier); connect(messenger->sendMessage(message), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onSendMessageFinished(Tp::PendingOperation*))); } Sender::~Sender() { } void Sender::onSendMessageFinished(Tp::PendingOperation *op) { if (op->isError()) { qDebug() << "Error sending message:" << op->errorName() << "-" << op->errorMessage(); QCoreApplication::exit(1); return; } Tp::PendingSendMessage *psm = qobject_cast(op); qDebug() << "Message sent, token is" << psm->sentMessageToken(); QCoreApplication::exit(0); } int main(int argc, char **argv) { QCoreApplication app(argc, argv); Tp::registerTypes(); Tp::enableDebug(true); Tp::enableWarnings(true); if (argc < 4) { qDebug() << "Usage: contact-messenger account_path contact_id message"; return -1; } Sender *sender = new Sender(QLatin1String(argv[1]), QLatin1String(argv[2]), QLatin1String(argv[3])); int ret = app.exec(); delete sender; return ret; } telepathy-qt-0.9.6~git1/examples/contact-messenger/sender.h0000664000175000017500000000272712470405660021650 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_contact_messenger_sender_h_HEADER_GUARD_ #define _TelepathyQt_examples_contact_messenger_sender_h_HEADER_GUARD_ #include #include #include namespace Tp { class PendingOperation; } class Sender : public QObject { Q_OBJECT public: Sender(const QString &accountPath, const QString &contactIdentifier, const QString &message); ~Sender(); private Q_SLOTS: void onSendMessageFinished(Tp::PendingOperation *op); private: Tp::ContactMessengerPtr messenger; }; #endif telepathy-qt-0.9.6~git1/examples/roster/0000775000175000017500000000000012470405660016104 5ustar jrjrtelepathy-qt-0.9.6~git1/examples/roster/roster-item.h0000664000175000017500000000273112470405660020532 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_roster_roster_item_h_HEADER_GUARD_ #define _TelepathyQt_examples_roster_roster_item_h_HEADER_GUARD_ #include #include #include #include class RosterItem : public QObject, public QListWidgetItem { Q_OBJECT public: RosterItem(const Tp::ContactPtr &contact, QListWidget *parent = 0); ~RosterItem(); Tp::ContactPtr contact() const { return mContact; } Q_SIGNALS: void changed(); private Q_SLOTS: void onContactChanged(); private: Tp::ContactPtr mContact; }; #endif telepathy-qt-0.9.6~git1/examples/roster/roster-widget.h0000664000175000017500000000500212470405660021051 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_roster_roster_widget_h_HEADER_GUARD_ #define _TelepathyQt_examples_roster_roster_widget_h_HEADER_GUARD_ #include #include #include namespace Tp { class Connection; class PendingOperation; } class QAction; class QDialog; class QLineEdit; class QListWidget; class QListWidgetItem; class QPushButton; class RosterItem; class RosterWidget : public QWidget { Q_OBJECT public: RosterWidget(QWidget *parent = 0); virtual ~RosterWidget(); Tp::ConnectionPtr connection() const { return mConn; } void setConnection(const Tp::ConnectionPtr &conn); void unsetConnection(); QListWidget *listWidget() const { return mList; } protected: virtual RosterItem *createItemForContact( const Tp::ContactPtr &contact, bool &exists); virtual void updateActions(RosterItem *item) { } private Q_SLOTS: void onContactManagerStateChanged(Tp::ContactListState state); void onPresencePublicationRequested(const Tp::Contacts &); void onItemSelectionChanged(); void onAddButtonClicked(); void onAuthActionTriggered(bool); void onDenyActionTriggered(bool); void onRemoveActionTriggered(bool); void onBlockActionTriggered(bool); void onContactRetrieved(Tp::PendingOperation *op); void updateActions(); private: void createActions(); void setupGui(); Tp::ConnectionPtr mConn; QAction *mAuthAction; QAction *mRemoveAction; QAction *mDenyAction; QAction *mBlockAction; QListWidget *mList; QPushButton *mAddBtn; QDialog *mAddDlg; QLineEdit *mAddDlgEdt; }; #endif telepathy-qt-0.9.6~git1/examples/roster/roster-widget.cpp0000664000175000017500000002645512470405660021423 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "roster-widget.h" #include "_gen/roster-widget.moc.hpp" #include "roster-item.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Tp; RosterWidget::RosterWidget(QWidget *parent) : QWidget(parent) { setWindowTitle(QLatin1String("Roster")); createActions(); setupGui(); } RosterWidget::~RosterWidget() { } void RosterWidget::setConnection(const ConnectionPtr &conn) { if (mConn) { unsetConnection(); } mConn = conn; connect(conn->contactManager().data(), SIGNAL(presencePublicationRequested(const Tp::Contacts &)), SLOT(onPresencePublicationRequested(const Tp::Contacts &))); // TODO listen to allKnownContactsChanged connect(conn->contactManager().data(), SIGNAL(stateChanged(Tp::ContactListState)), SLOT(onContactManagerStateChanged(Tp::ContactListState))); onContactManagerStateChanged(conn->contactManager()->state()); } void RosterWidget::unsetConnection() { while (mList->count() > 0) { RosterItem *item = (RosterItem *) mList->item(0); mList->takeItem(0); delete item; } mConn.reset(); updateActions(); mAddBtn->setEnabled(false); } void RosterWidget::createActions() { mAuthAction = new QAction(QLatin1String("Authorize Contact"), this); mAuthAction->setEnabled(false); connect(mAuthAction, SIGNAL(triggered(bool)), SLOT(onAuthActionTriggered(bool))); mDenyAction = new QAction(QLatin1String("Deny Contact"), this); mDenyAction->setEnabled(false); connect(mDenyAction, SIGNAL(triggered(bool)), SLOT(onDenyActionTriggered(bool))); mRemoveAction = new QAction(QLatin1String("Remove Contact"), this); mRemoveAction->setEnabled(false); connect(mRemoveAction, SIGNAL(triggered(bool)), SLOT(onRemoveActionTriggered(bool))); mBlockAction = new QAction(QLatin1String("Block Contact"), this); mBlockAction->setEnabled(false); mBlockAction->setCheckable(true); connect(mBlockAction, SIGNAL(triggered(bool)), SLOT(onBlockActionTriggered(bool))); } void RosterWidget::setupGui() { QVBoxLayout *vbox = new QVBoxLayout; mList = new QListWidget; connect(mList, SIGNAL(itemSelectionChanged()), SLOT(onItemSelectionChanged())); vbox->addWidget(mList); mList->setContextMenuPolicy(Qt::ActionsContextMenu); mList->addAction(mAuthAction); mList->addAction(mDenyAction); mList->addAction(mRemoveAction); mList->addAction(mBlockAction); QHBoxLayout *hbox = new QHBoxLayout; mAddBtn = new QPushButton(QLatin1String("+")); mAddBtn->setEnabled(false); connect(mAddBtn, SIGNAL(clicked(bool)), SLOT(onAddButtonClicked())); hbox->addWidget(mAddBtn); hbox->addStretch(1); vbox->addLayout(hbox); setLayout(vbox); mAddDlg = new QDialog(this); mAddDlg->setWindowTitle(QLatin1String("Add Contact")); QVBoxLayout *addDlgVBox = new QVBoxLayout; QHBoxLayout *addDlgEntryHBox = new QHBoxLayout; QLabel *label = new QLabel(QLatin1String("Username")); addDlgEntryHBox->addWidget(label); mAddDlgEdt = new QLineEdit(); addDlgEntryHBox->addWidget(mAddDlgEdt); addDlgVBox->addLayout(addDlgEntryHBox); QDialogButtonBox *addDlgBtnBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal); connect(addDlgBtnBox, SIGNAL(accepted()), mAddDlg, SLOT(accept())); connect(addDlgBtnBox, SIGNAL(rejected()), mAddDlg, SLOT(reject())); addDlgVBox->addWidget(addDlgBtnBox); mAddDlg->setLayout(addDlgVBox); } RosterItem *RosterWidget::createItemForContact(const ContactPtr &contact, bool &exists) { RosterItem *item; exists = false; for (int i = 0; i < mList->count(); ++i) { item = dynamic_cast(mList->item(i)); if (item->contact() == contact) { exists = true; return item; } } return new RosterItem(contact, mList); } void RosterWidget::onContactManagerStateChanged(ContactListState state) { if (state == ContactListStateSuccess) { qDebug() << "Loading contacts"; RosterItem *item; bool exists; foreach (const ContactPtr &contact, mConn->contactManager()->allKnownContacts()) { exists = false; item = createItemForContact(contact, exists); if (!exists) { connect(item, SIGNAL(changed()), SLOT(updateActions())); } } mAddBtn->setEnabled(true); } } void RosterWidget::onPresencePublicationRequested(const Contacts &contacts) { qDebug() << "Presence publication requested"; RosterItem *item; bool exists; foreach (const ContactPtr &contact, contacts) { exists = false; item = createItemForContact(contact, exists); if (!exists) { connect(item, SIGNAL(changed()), SLOT(updateActions())); } } } void RosterWidget::onItemSelectionChanged() { updateActions(); } void RosterWidget::onAddButtonClicked() { mAddDlgEdt->clear(); int ret = mAddDlg->exec(); if (ret == QDialog::Rejected) { return; } QString username = mAddDlgEdt->text(); PendingContacts *pcontacts = mConn->contactManager()->contactsForIdentifiers( QStringList() << username); connect(pcontacts, SIGNAL(finished(Tp::PendingOperation *)), SLOT(onContactRetrieved(Tp::PendingOperation *))); } void RosterWidget::onAuthActionTriggered(bool checked) { Q_UNUSED(checked); QList selectedItems = mList->selectedItems(); if (selectedItems.isEmpty()) { return; } Q_ASSERT(selectedItems.size() == 1); RosterItem *item = dynamic_cast(selectedItems.first()); if (item->contact()->publishState() != Contact::PresenceStateYes) { item->contact()->authorizePresencePublication(); } } void RosterWidget::onDenyActionTriggered(bool checked) { Q_UNUSED(checked); QList selectedItems = mList->selectedItems(); if (selectedItems.isEmpty()) { return; } Q_ASSERT(selectedItems.size() == 1); RosterItem *item = dynamic_cast(selectedItems.first()); if (item->contact()->publishState() != Contact::PresenceStateNo) { // The contact can't see my presence item->contact()->removePresencePublication(); } } void RosterWidget::onRemoveActionTriggered(bool checked) { Q_UNUSED(checked); QList selectedItems = mList->selectedItems(); if (selectedItems.isEmpty()) { return; } Q_ASSERT(selectedItems.size() == 1); RosterItem *item = dynamic_cast(selectedItems.first()); if (item->contact()->subscriptionState() != Contact::PresenceStateNo) { // The contact can't see my presence and I can't see his/her presence item->contact()->removePresencePublication(); item->contact()->removePresenceSubscription(); } } void RosterWidget::onBlockActionTriggered(bool checked) { QList selectedItems = mList->selectedItems(); if (selectedItems.isEmpty()) { return; } Q_ASSERT(selectedItems.size() == 1); RosterItem *item = dynamic_cast(selectedItems.first()); if (checked) { item->contact()->block(); } else { item->contact()->unblock(); } } void RosterWidget::onContactRetrieved(Tp::PendingOperation *op) { PendingContacts *pcontacts = qobject_cast(op); QList contacts = pcontacts->contacts(); Q_ASSERT(pcontacts->identifiers().size() == 1); QString username = pcontacts->identifiers().first(); if (contacts.size() != 1 || !contacts.first()) { QMessageBox msgBox; msgBox.setText(QString(QLatin1String("Unable to add contact \"%1\"")).arg(username)); msgBox.exec(); return; } ContactPtr contact = contacts.first(); qDebug() << "Request presence subscription for contact" << username; bool exists = false; RosterItem *item = createItemForContact(contact, exists); if (!exists) { connect(item, SIGNAL(changed()), SLOT(updateActions())); } contact->requestPresenceSubscription(); } void RosterWidget::updateActions() { QList selectedItems = mList->selectedItems(); if (selectedItems.isEmpty()) { mAuthAction->setEnabled(false); mDenyAction->setEnabled(false); mRemoveAction->setEnabled(false); mBlockAction->setEnabled(false); updateActions(0); return; } Q_ASSERT(selectedItems.size() == 1); RosterItem *item = dynamic_cast(selectedItems.first()); ContactPtr contact = item->contact(); ContactManagerPtr manager = contact->manager(); qDebug() << "Contact" << contact->id() << "selected"; qDebug() << " subscription state:" << contact->subscriptionState(); qDebug() << " publish state :" << contact->publishState(); qDebug() << " blocked :" << contact->isBlocked(); if (manager->canAuthorizePresencePublication() && contact->publishState() == Contact::PresenceStateAsk) { mAuthAction->setEnabled(true); } else { mAuthAction->setEnabled(false); } if (manager->canRemovePresencePublication() && contact->publishState() != Contact::PresenceStateNo) { mDenyAction->setEnabled(true); } else { mDenyAction->setEnabled(false); } if (manager->canRemovePresenceSubscription() && contact->subscriptionState() != Contact::PresenceStateNo) { mRemoveAction->setEnabled(true); } else { mRemoveAction->setEnabled(false); } if (manager->canBlockContacts() && contact->publishState() == Contact::PresenceStateYes) { mBlockAction->setEnabled(true); } else { mBlockAction->setEnabled(false); } mBlockAction->setChecked(contact->isBlocked()); updateActions(item); } telepathy-qt-0.9.6~git1/examples/roster/roster-item.cpp0000664000175000017500000000542012470405660021063 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "roster-item.h" #include "_gen/roster-item.moc.hpp" #include using namespace Tp; RosterItem::RosterItem(const ContactPtr &contact, QListWidget *parent) : QObject(parent), QListWidgetItem(parent), mContact(contact) { onContactChanged(); connect(contact.data(), SIGNAL(aliasChanged(QString)), SLOT(onContactChanged())); connect(contact.data(), SIGNAL(presenceChanged(Tp::Presence)), SLOT(onContactChanged())); connect(contact.data(), SIGNAL(subscriptionStateChanged(Tp::Contact::PresenceState)), SLOT(onContactChanged())); connect(contact.data(), SIGNAL(publishStateChanged(Tp::Contact::PresenceState,QString)), SLOT(onContactChanged())); connect(contact.data(), SIGNAL(blockStatusChanged(bool)), SLOT(onContactChanged())); } RosterItem::~RosterItem() { } void RosterItem::onContactChanged() { QString status = mContact->presence().status(); // I've asked to see the contact presence if (mContact->subscriptionState() == Contact::PresenceStateAsk) { setText(QString(QLatin1String("%1 (%2) (awaiting approval)")).arg(mContact->id()).arg(status)); // The contact asked to see my presence } else if (mContact->publishState() == Contact::PresenceStateAsk) { setText(QString(QLatin1String("%1 (%2) (pending approval)")).arg(mContact->id()).arg(status)); } else if (mContact->subscriptionState() == Contact::PresenceStateNo && mContact->publishState() == Contact::PresenceStateNo) { setText(QString(QLatin1String("%1 (unknown)")).arg(mContact->id())); } else { setText(QString(QLatin1String("%1 (%2)")).arg(mContact->id()).arg(status)); } if (mContact->isBlocked()) { setText(QString(QLatin1String("%1 (blocked)")).arg(text())); } emit changed(); } telepathy-qt-0.9.6~git1/examples/roster/main.cpp0000664000175000017500000000264012470405660017536 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "roster-window.h" int main(int argc, char **argv) { QApplication app(argc, argv); if (argc < 2) { qDebug() << "usage:" << argv[0] << ""; return 1; } Tp::registerTypes(); Tp::enableDebug(true); Tp::enableWarnings(true); QString accountPath = QLatin1String(argv[1]); RosterWindow w(accountPath); w.show(); return app.exec(); } telepathy-qt-0.9.6~git1/examples/roster/CMakeLists.txt0000664000175000017500000000207312470405660020646 0ustar jrjrset(roster_SRCS main.cpp roster-window.cpp roster-item.cpp roster-widget.cpp) set(roster_MOC_SRCS roster-window.h roster-item.h roster-widget.h) tpqt_generate_mocs(${roster_MOC_SRCS}) add_executable(roster ${roster_SRCS} ${roster_MOC_SRCS}) target_link_libraries(roster ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTWIDGETS_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_EXECUTABLE_LINKER_FLAGS}) set(telepathy_qt_examples_roster_SRCS roster-item.cpp roster-widget.cpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/roster-item.moc.hpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/roster-widget.moc.hpp) add_library(telepathy-qt-examples-roster ${telepathy_qt_examples_roster_SRCS}) target_link_libraries(telepathy-qt-examples-roster ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTWIDGETS_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_LIBRARY_LINKER_FLAGS}) telepathy-qt-0.9.6~git1/examples/roster/roster-window.h0000664000175000017500000000304312470405660021100 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_roster_roster_window_h_HEADER_GUARD_ #define _TelepathyQt_examples_roster_roster_window_h_HEADER_GUARD_ #include #include #include namespace Tp { class PendingOperation; } class RosterWidget; class RosterWindow : public QMainWindow { Q_OBJECT public: RosterWindow(const QString &accountName, QWidget *parent = 0); virtual ~RosterWindow(); private Q_SLOTS: void onAccountReady(Tp::PendingOperation *op); void onAccountConnectionChanged(const Tp::ConnectionPtr &conn); private: void setupGui(); Tp::AccountPtr mAccount; RosterWidget *mRoster; }; #endif telepathy-qt-0.9.6~git1/examples/roster/roster-window.cpp0000664000175000017500000000632212470405660021436 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "roster-window.h" #include "_gen/roster-window.moc.hpp" #include "roster-widget.h" #include #include #include #include #include #include #include #include using namespace Tp; RosterWindow::RosterWindow(const QString &accountName, QWidget *parent) : QMainWindow(parent) { setWindowTitle(QLatin1String("Roster")); setupGui(); ChannelFactoryPtr channelFactory = ChannelFactory::create( QDBusConnection::sessionBus()); ConnectionFactoryPtr connectionFactory = ConnectionFactory::create( QDBusConnection::sessionBus(), Connection::FeatureConnected | Connection::FeatureRoster | Connection::FeatureRosterGroups); ContactFactoryPtr contactFactory = ContactFactory::create( Contact::FeatureAlias | Contact::FeatureSimplePresence); mAccount = Account::create(TP_QT_ACCOUNT_MANAGER_BUS_NAME, TP_QT_ACCOUNT_OBJECT_PATH_BASE + QLatin1Char('/') + accountName, connectionFactory, channelFactory, contactFactory); connect(mAccount->becomeReady(Account::FeatureCore), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onAccountReady(Tp::PendingOperation *))); resize(240, 320); } RosterWindow::~RosterWindow() { } void RosterWindow::setupGui() { mRoster = new RosterWidget(); setCentralWidget(mRoster); } void RosterWindow::onAccountReady(Tp::PendingOperation *op) { if (op->isError()) { qWarning() << "Account cannot become ready - " << op->errorName() << '-' << op->errorMessage(); QCoreApplication::exit(1); return; } qDebug() << "Account ready"; connect(mAccount.data(), SIGNAL(connectionChanged(Tp::ConnectionPtr)), SLOT(onAccountConnectionChanged(Tp::ConnectionPtr))); if (mAccount->connection().isNull()) { qDebug() << "The account given has no Connection. Please set it online to continue."; } onAccountConnectionChanged(mAccount->connection()); } void RosterWindow::onAccountConnectionChanged(const ConnectionPtr &conn) { if (conn) { mRoster->setConnection(conn); } else { mRoster->unsetConnection(); } } telepathy-qt-0.9.6~git1/examples/protocols/0000775000175000017500000000000012470405660016612 5ustar jrjrtelepathy-qt-0.9.6~git1/examples/protocols/cm-wrapper.cpp0000664000175000017500000000363012470405660021375 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "cm-wrapper.h" #include "_gen/cm-wrapper.moc.hpp" #include #include #include #include CMWrapper::CMWrapper(const QString &cmName, QObject *parent) : QObject(parent), mCM(ConnectionManager::create(cmName)) { connect(mCM->becomeReady(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onCMReady(Tp::PendingOperation *))); } CMWrapper::~CMWrapper() { } ConnectionManagerPtr CMWrapper::cm() const { return mCM; } void CMWrapper::onCMReady(PendingOperation *op) { if (op->isError()) { qWarning() << "CM" << mCM->name() << "cannot become ready -" << op->errorName() << ": " << op->errorMessage(); return; } qDebug() << "CM" << mCM->name() << "ready!"; qDebug() << "Supported protocols:"; foreach (const QString &protocol, mCM->supportedProtocols()) { qDebug() << "\t" << protocol; } emit finished(); } telepathy-qt-0.9.6~git1/examples/protocols/protocols.h0000664000175000017500000000274312470405660021015 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_protocols_protocols_h_HEADER_GUARD_ #define _TelepathyQt_examples_protocols_protocols_h_HEADER_GUARD_ #include #include "cm-wrapper.h" #include #include using namespace Tp; namespace Tp { class PendingOperation; } class Protocols : public QObject { Q_OBJECT public: Protocols(); ~Protocols(); private Q_SLOTS: void onListNamesFinished(Tp::PendingOperation *op); void onCMWrapperFinished(); private: QList mCMWrappers; int cmWrappersFinished; }; #endif telepathy-qt-0.9.6~git1/examples/protocols/protocols.cpp0000664000175000017500000000422312470405660021343 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "protocols.h" #include "_gen/protocols.moc.hpp" #include #include #include #include #include Protocols::Protocols() : cmWrappersFinished(0) { qDebug() << "Listing names"; connect(ConnectionManager::listNames(), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onListNamesFinished(Tp::PendingOperation *))); } Protocols::~Protocols() { } void Protocols::onListNamesFinished(PendingOperation *op) { if (op->isError()) { qWarning() << "Error listing connection manager names -" << op->errorName() << ": " << op->errorMessage(); return; } PendingStringList *ps = qobject_cast(op); qDebug() << "Supported CMs:" << ps->result(); foreach (const QString &cmName, ps->result()) { CMWrapper *cmWrapper = new CMWrapper(cmName, this); mCMWrappers.append(cmWrapper); connect(cmWrapper, SIGNAL(finished()), SLOT(onCMWrapperFinished())); } } void Protocols::onCMWrapperFinished() { if (++cmWrappersFinished == mCMWrappers.size()) { QCoreApplication::quit(); } } telepathy-qt-0.9.6~git1/examples/protocols/main.cpp0000664000175000017500000000055212470405660020244 0ustar jrjr#include #include #include #include #include #include "protocols.h" int main(int argc, char **argv) { QCoreApplication app(argc, argv); Tp::registerTypes(); Tp::enableDebug(false); Tp::enableWarnings(false); Protocols protocols; return app.exec(); } telepathy-qt-0.9.6~git1/examples/protocols/CMakeLists.txt0000664000175000017500000000076212470405660021357 0ustar jrjrset(protocols_SRCS main.cpp cm-wrapper.cpp protocols.cpp) set(protocols_MOC_SRCS cm-wrapper.h protocols.h) tpqt_generate_mocs(${protocols_MOC_SRCS}) add_executable(protocols ${protocols_SRCS} ${protocols_MOC_SRCS}) target_link_libraries(protocols ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTWIDGETS_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_EXECUTABLE_LINKER_FLAGS}) telepathy-qt-0.9.6~git1/examples/protocols/cm-wrapper.h0000664000175000017500000000301212470405660021034 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_protocols_cm_wrapper_h_HEADER_GUARD_ #define _TelepathyQt_examples_protocols_cm_wrapper_h_HEADER_GUARD_ #include #include #include using namespace Tp; namespace Tp { class ConnectionManager; class PendingOperation; } class CMWrapper : public QObject { Q_OBJECT public: CMWrapper(const QString &cmName, QObject *parent = 0); ~CMWrapper(); ConnectionManagerPtr cm() const; Q_SIGNALS: void finished(); private Q_SLOTS: void onCMReady(Tp::PendingOperation *op); private: ConnectionManagerPtr mCM; }; #endif telepathy-qt-0.9.6~git1/examples/CMakeLists.txt0000664000175000017500000000064212470405660017330 0ustar jrjr# Set the required flags found in TelepathyDefaults set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DEPRECATED_DECLARATIONS_FLAGS}") set(LD_FLAGS "${LD_FLAGS} ${DEPRECATED_DECLARATIONS_FLAGS}") add_subdirectory(accounts) add_subdirectory(contact-messenger) add_subdirectory(cm) add_subdirectory(extensions) add_subdirectory(file-transfer) add_subdirectory(protocols) add_subdirectory(roster) add_subdirectory(stream-tubes) telepathy-qt-0.9.6~git1/examples/file-transfer/0000775000175000017500000000000012470405660017327 5ustar jrjrtelepathy-qt-0.9.6~git1/examples/file-transfer/pending-file-receive.cpp0000664000175000017500000000516012470405660024016 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pending-file-receive.h" #include "_gen/pending-file-receive.moc.hpp" #include #include #include #include #include PendingFileReceive::PendingFileReceive(const IncomingFileTransferChannelPtr &chan, const SharedPtr &object) : PendingFileTransfer(FileTransferChannelPtr::qObjectCast(chan), object), mReceivingFile(false) { // connect/call onTransferStateChanged here as now we are constructed, otherwise doing it in the base // class would only invoke the base class slot connect(chan.data(), SIGNAL(stateChanged(Tp::FileTransferState,Tp::FileTransferStateChangeReason)), SLOT(onTransferStateChanged(Tp::FileTransferState,Tp::FileTransferStateChangeReason))); onTransferStateChanged(chan->state(), chan->stateReason()); } PendingFileReceive::~PendingFileReceive() { mFile.close(); } void PendingFileReceive::onTransferStateChanged(FileTransferState state, FileTransferStateChangeReason stateReason) { PendingFileTransfer::onTransferStateChanged(state, stateReason); if (state == FileTransferStatePending) { Q_ASSERT(!mReceivingFile); mReceivingFile = true; IncomingFileTransferChannelPtr chan = IncomingFileTransferChannelPtr::qObjectCast(channel()); Q_ASSERT(chan); QString fileName(QLatin1String("TpQtExampleFTReceiver_") + chan->fileName()); fileName.replace(QLatin1String("/"), QLatin1String("_")); mFile.setFileName(fileName); qDebug() << "Receiving" << chan->fileName() << "from" << chan->targetId() << ", saving as" << fileName; chan->acceptFile(0, &mFile); } } telepathy-qt-0.9.6~git1/examples/file-transfer/pending-file-transfer.cpp0000664000175000017500000000564712470405660024232 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pending-file-transfer.h" #include "_gen/pending-file-transfer.moc.hpp" #include #include #include #include #include #include PendingFileTransfer::PendingFileTransfer(const FileTransferChannelPtr &chan, const SharedPtr &object) : PendingOperation(object), mChannel(chan) { connect(chan.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString))); connect(chan.data(), SIGNAL(transferredBytesChanged(qulonglong)), SLOT(onTransferredBytesChanged(qulonglong))); } PendingFileTransfer::~PendingFileTransfer() { } void PendingFileTransfer::onChannelInvalidated(DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { Q_UNUSED(proxy); qWarning() << "Error sending file, channel invalidated -" << errorName << "-" << errorMessage; setFinishedWithError(errorName, errorMessage); } void PendingFileTransfer::onTransferStateChanged(FileTransferState state, FileTransferStateChangeReason stateReason) { qDebug() << "File transfer channel state changed to" << state << "with reason" << stateReason; switch (state) { case FileTransferStatePending: case FileTransferStateOpen: break; case FileTransferStateAccepted: qDebug() << "Transfer accepted!"; break; case FileTransferStateCompleted: qDebug() << "Transfer completed!"; setFinished(); break; case FileTransferStateCancelled: qDebug() << "Transfer cancelled"; setFinished(); return; default: Q_ASSERT(false); } } void PendingFileTransfer::onTransferredBytesChanged(qulonglong count) { qDebug().nospace() << "Transferred bytes " << count << " - " << ((int) (((double) count / mChannel->size()) * 100)) << "% done"; } telepathy-qt-0.9.6~git1/examples/file-transfer/pending-file-send.h0000664000175000017500000000320212470405660022765 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_file_transfer_pending_file_send_h_HEADER_GUARD_ #define _TelepathyQt_examples_file_transfer_pending_file_send_h_HEADER_GUARD_ #include #include #include #include "pending-file-transfer.h" using namespace Tp; class PendingFileSend : public PendingFileTransfer { Q_OBJECT Q_DISABLE_COPY(PendingFileSend) public: PendingFileSend(const OutgoingFileTransferChannelPtr &chan, const SharedPtr &object); ~PendingFileSend(); private Q_SLOTS: void onTransferStateChanged(Tp::FileTransferState state, Tp::FileTransferStateChangeReason stateReason); private: bool mSendingFile; QFile mFile; }; #endif telepathy-qt-0.9.6~git1/examples/file-transfer/file-receiver.h0000664000175000017500000000257612470405660022233 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_file_transfer_file_receiver_h_HEADER_GUARD_ #define _TelepathyQt_examples_file_transfer_file_receiver_h_HEADER_GUARD_ #include #include #include "file-receiver-handler.h" using namespace Tp; class FileReceiver : public QObject { Q_OBJECT Q_DISABLE_COPY(FileReceiver) public: FileReceiver(QObject *parent); ~FileReceiver(); private: ClientRegistrarPtr mCR; SharedPtr mHandler; }; #endif telepathy-qt-0.9.6~git1/examples/file-transfer/pending-file-send.cpp0000664000175000017500000000535712470405660023335 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pending-file-send.h" #include "_gen/pending-file-send.moc.hpp" #include #include #include #include #include #include PendingFileSend::PendingFileSend(const OutgoingFileTransferChannelPtr &chan, const SharedPtr &object) : PendingFileTransfer(FileTransferChannelPtr::qObjectCast(chan), object), mSendingFile(false) { // connect/call onTransferStateChanged here as now we are constructed, otherwise doing it in the base // class would only invoke the base class slot connect(chan.data(), SIGNAL(stateChanged(Tp::FileTransferState,Tp::FileTransferStateChangeReason)), SLOT(onTransferStateChanged(Tp::FileTransferState,Tp::FileTransferStateChangeReason))); onTransferStateChanged(chan->state(), chan->stateReason()); } PendingFileSend::~PendingFileSend() { mFile.close(); } void PendingFileSend::onTransferStateChanged(FileTransferState state, FileTransferStateChangeReason stateReason) { PendingFileTransfer::onTransferStateChanged(state, stateReason); if (state == FileTransferStateAccepted) { Q_ASSERT(!mSendingFile); mSendingFile = true; OutgoingFileTransferChannelPtr chan = OutgoingFileTransferChannelPtr::qObjectCast(channel()); Q_ASSERT(chan); QString uri = chan->uri(); mFile.setFileName(QUrl(uri).toLocalFile()); if (!mFile.open(QIODevice::ReadOnly)) { qWarning() << "Unable to open" << uri << "for reading, aborting transfer"; setFinishedWithError(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Unable to open file for reading")); return; } qDebug() << "Sending" << uri << "to" << chan->targetId(); chan->provideFile(&mFile); } } telepathy-qt-0.9.6~git1/examples/file-transfer/CMakeLists.txt0000664000175000017500000000211512470405660022066 0ustar jrjrset(ft-receiver_SRCS file-receiver.cpp file-receiver-handler.cpp pending-file-receive.cpp pending-file-transfer.cpp) set(ft-receiver_MOC_SRCS file-receiver.h file-receiver-handler.h pending-file-receive.h pending-file-transfer.h) tpqt_generate_mocs(${ft-receiver_MOC_SRCS}) add_executable(ft-receiver ${ft-receiver_SRCS} ${ft-receiver_MOC_SRCS}) target_link_libraries(ft-receiver ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_EXECUTABLE_LINKER_FLAGS}) set(ft-sender_SRCS file-sender.cpp pending-file-send.cpp pending-file-transfer.cpp) set(ft-sender_MOC_SRCS file-sender.h pending-file-send.h pending-file-transfer.h) tpqt_generate_mocs(${ft-sender_MOC_SRCS}) add_executable(ft-sender ${ft-sender_SRCS} ${ft-sender_MOC_SRCS}) target_link_libraries(ft-sender ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_EXECUTABLE_LINKER_FLAGS}) telepathy-qt-0.9.6~git1/examples/file-transfer/pending-file-transfer.h0000664000175000017500000000356712470405660023676 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_file_transfer_pending_file_transfer_h_HEADER_GUARD_ #define _TelepathyQt_examples_file_transfer_pending_file_transfer_h_HEADER_GUARD_ #include #include #include using namespace Tp; class PendingFileTransfer : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingFileTransfer) public: PendingFileTransfer(const FileTransferChannelPtr &chan, const SharedPtr &object); ~PendingFileTransfer(); FileTransferChannelPtr channel() const { return mChannel; } protected Q_SLOTS: void onTransferStateChanged(Tp::FileTransferState state, Tp::FileTransferStateChangeReason stateReason); private Q_SLOTS: void onChannelInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage); void onTransferredBytesChanged(qulonglong count); private: FileTransferChannelPtr mChannel; }; #endif telepathy-qt-0.9.6~git1/examples/file-transfer/file-receiver-handler.cpp0000664000175000017500000000667412470405660024204 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "file-receiver-handler.h" #include "_gen/file-receiver-handler.moc.hpp" #include "pending-file-receive.h" #include #include #include #include #include #include #include #include #include FileReceiverHandler::FileReceiverHandler() : QObject(), AbstractClientHandler(ChannelClassSpecList() << ChannelClassSpec::incomingFileTransfer(), AbstractClientHandler::Capabilities(), false) { } FileReceiverHandler::~FileReceiverHandler() { } bool FileReceiverHandler::bypassApproval() const { return false; } void FileReceiverHandler::handleChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const QList &requestsSatisfied, const QDateTime &userActionTime, const HandlerInfo &handlerInfo) { // We should always receive one channel to handle, // otherwise either MC or tp-qt itself is bogus, so let's assert in case they are Q_ASSERT(channels.size() == 1); ChannelPtr chan = channels.first(); if (!chan->isValid()) { qWarning() << "Channel received to handle is invalid, ignoring channel"; context->setFinishedWithError(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Channel received to handle is invalid")); return; } // We should always receive incoming channels of type FileTransfer, as set by our filter, // otherwise either MC or tp-qt itself is bogus, so let's assert in case they are Q_ASSERT(chan->channelType() == TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER); Q_ASSERT(!chan->isRequested()); IncomingFileTransferChannelPtr transferChannel = IncomingFileTransferChannelPtr::qObjectCast(chan); Q_ASSERT(transferChannel); context->setFinished(); PendingFileReceive *receiveOperation = new PendingFileReceive(transferChannel, SharedPtr::dynamicCast(AbstractClientPtr(this))); connect(receiveOperation, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onReceiveFinished(Tp::PendingOperation*))); } void FileReceiverHandler::onReceiveFinished(PendingOperation *op) { PendingFileReceive *receiveOperation = qobject_cast(op); qDebug() << "Closing channel"; receiveOperation->channel()->requestClose(); } telepathy-qt-0.9.6~git1/examples/file-transfer/file-receiver-handler.h0000664000175000017500000000403712470405660023640 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_file_transfer_file_receiver_handler_h_HEADER_GUARD_ #define _TelepathyQt_examples_file_transfer_file_receiver_handler_h_HEADER_GUARD_ #include #include #include #include using namespace Tp; class FileReceiverHandler : public QObject, public AbstractClientHandler { Q_OBJECT Q_DISABLE_COPY(FileReceiverHandler) public: static SharedPtr create() { return SharedPtr(new FileReceiverHandler()); } ~FileReceiverHandler(); bool bypassApproval() const; void handleChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const QList &requestsSatisfied, const QDateTime &userActionTime, const HandlerInfo &handlerInfo); private Q_SLOTS: void onReceiveFinished(Tp::PendingOperation *op); private: FileReceiverHandler(); QSet mReceiveOps; }; #endif telepathy-qt-0.9.6~git1/examples/file-transfer/pending-file-receive.h0000664000175000017500000000322612470405660023464 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_file_transfer_pending_file_receive_h_HEADER_GUARD_ #define _TelepathyQt_examples_file_transfer_pending_file_receive_h_HEADER_GUARD_ #include #include #include #include "pending-file-transfer.h" using namespace Tp; class PendingFileReceive : public PendingFileTransfer { Q_OBJECT Q_DISABLE_COPY(PendingFileReceive) public: PendingFileReceive(const IncomingFileTransferChannelPtr &chan, const SharedPtr &object); ~PendingFileReceive(); private Q_SLOTS: void onTransferStateChanged(Tp::FileTransferState state, Tp::FileTransferStateChangeReason stateReason); private: bool mReceivingFile; QFile mFile; }; #endif telepathy-qt-0.9.6~git1/examples/file-transfer/file-sender.h0000664000175000017500000000374512470405660021706 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_file_transfer_file_sender_h_HEADER_GUARD_ #define _TelepathyQt_examples_file_transfer_file_sender_h_HEADER_GUARD_ #include #include using namespace Tp; namespace Tp { class PendingOperation; } class FileSender : public QObject { Q_OBJECT Q_DISABLE_COPY(FileSender) public: FileSender(const QString &accountName, const QString &receiverID, const QString &filePath, QObject *parent); ~FileSender(); private Q_SLOTS: void onAMReady(Tp::PendingOperation *op); void onAccountReady(Tp::PendingOperation *op); void onAccountConnectionChanged(const Tp::ConnectionPtr &conn); void onContactRetrieved(Tp::PendingOperation *op); void onContactCapabilitiesChanged(); void onTransferRequestFinished(Tp::PendingOperation *op); void onSendFinished(Tp::PendingOperation *op); private: QString mAccountName; QString mReceiver; QString mFilePath; bool mTransferRequested; AccountManagerPtr mAM; AccountPtr mAccount; ConnectionPtr mConnection; ContactPtr mContact; }; #endif telepathy-qt-0.9.6~git1/examples/file-transfer/file-receiver.cpp0000664000175000017500000000503712470405660022561 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "file-receiver.h" #include #include #include #include #include #include #include #include #include FileReceiver::FileReceiver(QObject *parent) : QObject(parent) { QDBusConnection bus(QDBusConnection::sessionBus()); AccountFactoryPtr accountFactory = AccountFactory::create(bus); ConnectionFactoryPtr connectionFactory = ConnectionFactory::create(bus); ChannelFactoryPtr channelFactory = ChannelFactory::create(bus); channelFactory->addCommonFeatures(Channel::FeatureCore); channelFactory->addFeaturesForIncomingFileTransfers(IncomingFileTransferChannel::FeatureCore); mCR = ClientRegistrar::create(accountFactory, connectionFactory, channelFactory); qDebug() << "Registering incoming file transfer handler"; mHandler = FileReceiverHandler::create(); QString handlerName(QLatin1String("TpQtExampleFileReceiverHandler")); if (!mCR->registerClient(AbstractClientPtr::dynamicCast(mHandler), handlerName)) { qWarning() << "Unable to register incoming file transfer handler, aborting"; QCoreApplication::exit(1); return; } qDebug() << "Awaiting file transfers"; } FileReceiver::~FileReceiver() { } int main(int argc, char **argv) { QCoreApplication app(argc, argv); Tp::registerTypes(); Tp::enableDebug(false); Tp::enableWarnings(true); new FileReceiver(&app); return app.exec(); } #include "_gen/file-receiver.moc.hpp" telepathy-qt-0.9.6~git1/examples/file-transfer/file-sender.cpp0000664000175000017500000002241312470405660022232 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "file-sender.h" #include "pending-file-send.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include FileSender::FileSender(const QString &accountName, const QString &receiver, const QString &filePath, QObject *parent) : QObject(parent), mAccountName(accountName), mReceiver(receiver), mFilePath(filePath), mTransferRequested(false) { qDebug() << "Retrieving account from AccountManager"; QDBusConnection bus(QDBusConnection::sessionBus()); // Let's not prepare any account feature as we only care about one account, thus no need to // prepare features for all accounts AccountFactoryPtr accountFactory = AccountFactory::create(bus); // We only care about CONNECTED connections, so let's specify that in a Connection Factory ConnectionFactoryPtr connectionFactory = ConnectionFactory::create(bus, Connection::FeatureCore | Connection::FeatureConnected); ChannelFactoryPtr channelFactory = ChannelFactory::create(bus); channelFactory->addCommonFeatures(Channel::FeatureCore); channelFactory->addFeaturesForOutgoingFileTransfers(OutgoingFileTransferChannel::FeatureCore); ContactFactoryPtr contactFactory = ContactFactory::create(); mAM = AccountManager::create(bus, accountFactory, connectionFactory, channelFactory, contactFactory); connect(mAM->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAMReady(Tp::PendingOperation*))); } FileSender::~FileSender() { } void FileSender::onAMReady(PendingOperation *op) { if (op->isError()) { qWarning() << "AccountManager cannot become ready -" << op->errorName() << '-' << op->errorMessage(); QCoreApplication::exit(1); return; } PendingReady *pr = qobject_cast(op); Q_ASSERT(pr != NULL); Q_UNUSED(pr); qDebug() << "AccountManager ready"; mAccount = mAM->accountForObjectPath( TP_QT_ACCOUNT_OBJECT_PATH_BASE + QLatin1Char('/') + mAccountName); if (!mAccount) { qWarning() << "The account given does not exist"; QCoreApplication::exit(1); } Q_ASSERT(!mAccount->isReady()); connect(mAccount->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountReady(Tp::PendingOperation*))); } void FileSender::onAccountReady(PendingOperation *op) { if (op->isError()) { qWarning() << "Account cannot become ready -" << op->errorName() << '-' << op->errorMessage(); QCoreApplication::exit(1); return; } PendingReady *pr = qobject_cast(op); Q_ASSERT(pr != NULL); Q_UNUSED(pr); qDebug() << "Account ready"; qDebug() << "Checking if account is online..."; connect(mAccount.data(), SIGNAL(connectionChanged(Tp::ConnectionPtr)), SLOT(onAccountConnectionChanged(Tp::ConnectionPtr))); onAccountConnectionChanged(mAccount->connection()); } void FileSender::onAccountConnectionChanged(const ConnectionPtr &conn) { if (!conn) { qDebug() << "The account given has no connection. " "Please set it online to continue"; return; } Q_ASSERT(conn->isValid()); Q_ASSERT(conn->status() == ConnectionStatusConnected); qDebug() << "Account online, got a connected connection!"; mConnection = conn; qDebug() << "Creating contact object for receiver" << mReceiver; connect(mConnection->contactManager()->contactsForIdentifiers(QStringList() << mReceiver, Contact::FeatureCapabilities), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onContactRetrieved(Tp::PendingOperation *))); } void FileSender::onContactRetrieved(PendingOperation *op) { if (op->isError()) { qWarning() << "Unable to create contact object for receiver" << mReceiver << "-" << op->errorName() << "-" << op->errorMessage(); QCoreApplication::exit(1); return; } PendingContacts *pc = qobject_cast(op); Q_ASSERT(pc->contacts().size() == 1); mContact = pc->contacts().first(); qDebug() << "Checking contact capabilities..."; connect(mContact.data(), SIGNAL(capabilitiesChanged(Tp::ContactCapabilities)), SLOT(onContactCapabilitiesChanged())); #if 0 qDebug() << "Contact capabilities:"; Q_FOREACH (const RequestableChannelClassSpec &spec, mContact->capabilities().allClassSpecs()) { qDebug() << " fixed:" << spec.fixedProperties(); qDebug() << " allowed:" << spec.allowedProperties(); } #endif if (mContact->capabilities().fileTransfers()) { onContactCapabilitiesChanged(); } else { qDebug() << "The receiver needs to be online and support file transfers to continue"; } } void FileSender::onContactCapabilitiesChanged() { if (mTransferRequested) { return; } if (mContact->capabilities().fileTransfers()) { qDebug() << "The remote contact is capable of receiving file transfers. " "Requesting file transfer channel"; mTransferRequested = true; FileTransferChannelCreationProperties ftProps(mFilePath, QLatin1String("application/octet-stream")); connect(mAccount->createAndHandleFileTransfer(mContact, ftProps), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onTransferRequestFinished(Tp::PendingOperation*))); } } void FileSender::onTransferRequestFinished(PendingOperation *op) { if (op->isError()) { qWarning() << "Unable to request stream tube channel -" << op->errorName() << ": " << op->errorMessage(); QCoreApplication::exit(1); return; } qDebug() << "File transfer channel request finished successfully!"; PendingChannel *pc = qobject_cast(op); Q_ASSERT(pc); ChannelPtr chan = pc->channel(); if (!chan->isValid()) { qWarning() << "Channel received to handle is invalid, aborting file transfer"; QCoreApplication::exit(1); return; } // We should always receive outgoing channels of type FileTransfer, as requested, // otherwise either MC or tp-qt itself is bogus, so let's assert in case they are Q_ASSERT(chan->channelType() == TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER); Q_ASSERT(chan->isRequested()); OutgoingFileTransferChannelPtr transferChannel = OutgoingFileTransferChannelPtr::qObjectCast(chan); Q_ASSERT(transferChannel); // We just passed the URI when requesting the channel, so it has to be set Q_ASSERT(!transferChannel->uri().isEmpty()); PendingFileSend *sendOperation = new PendingFileSend(transferChannel, SharedPtr()); connect(sendOperation, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onSendFinished(Tp::PendingOperation*))); } void FileSender::onSendFinished(PendingOperation *op) { PendingFileSend *sendOperation = qobject_cast(op); qDebug() << "Closing channel"; sendOperation->channel()->requestClose(); QCoreApplication::exit(0); } int main(int argc, char **argv) { QCoreApplication app(argc, argv); if (argc != 4) { qDebug() << "usage:" << argv[0] << " "; return 1; } QString filePath = QLatin1String(argv[3]); QFileInfo fileInfo(filePath); if (!fileInfo.exists()) { qWarning() << "File" << filePath << "does not exist"; return 1; } Tp::registerTypes(); Tp::enableDebug(false); Tp::enableWarnings(true); new FileSender(QLatin1String(argv[1]), QLatin1String(argv[2]), filePath, &app); return app.exec(); } #include "_gen/file-sender.moc.hpp" telepathy-qt-0.9.6~git1/examples/stream-tubes/0000775000175000017500000000000012470405660017201 5ustar jrjrtelepathy-qt-0.9.6~git1/examples/stream-tubes/tube-initiator.h0000664000175000017500000000474112470405660022317 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2009-2011 Collabora Ltd. * Copyright (C) 2009,2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_stream_tubes_tube_initiator_h_HEADER_GUARD_ #define _TelepathyQt_examples_stream_tubes_tube_initiator_h_HEADER_GUARD_ #include #include #include #include #include #include class QTcpServer; using namespace Tp; namespace Tp { class ChannelRequestHints; class PendingOperation; } class TubeInitiator : public QObject { Q_OBJECT public: TubeInitiator(const QString &accountName, const QString &receiver, QObject *parent); ~TubeInitiator(); private Q_SLOTS: void onAccountReady(Tp::PendingOperation *op); void onAccountConnectionChanged(const Tp::ConnectionPtr &); void onContactRetrieved(Tp::PendingOperation *op); void onContactCapabilitiesChanged(); void onTubeRequestFinished(Tp::PendingOperation *op); void onTubeNewConnection(const QHostAddress &sourceAddress, quint16 sourcePort, const Tp::AccountPtr &account, const Tp::ContactPtr &contact); void onTubeConnectionClosed(const QHostAddress &sourceAddress, quint16 sourcePort, const Tp::AccountPtr &account, const Tp::ContactPtr &contact, const QString &error, const QString &errorMessage); void onTcpServerNewConnection(); void onDataFromSocket(); private: void createStreamTubeChannel(); QString mReceiver; QTcpServer *mServer; StreamTubeServerPtr mTubeServer; AccountPtr mAccount; ConnectionPtr mConn; ContactPtr mContact; bool mTubeRequested; QHash, QString> mConnAliases; }; #endif telepathy-qt-0.9.6~git1/examples/stream-tubes/tube-receiver.cpp0000664000175000017500000000606212470405660022452 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2009-2011 Collabora Ltd. * Copyright (C) 2009,2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tube-receiver.h" #include #include #include #include #include #include TubeReceiver::TubeReceiver(QObject *parent) : QObject(parent) { mTubeClient = StreamTubeClient::create(QStringList() << QLatin1String("tp-qt-stube-example")); connect(mTubeClient.data(), SIGNAL(tubeAcceptedAsUnix(QString,bool,uchar,Tp::AccountPtr,Tp::IncomingStreamTubeChannelPtr)), SLOT(onTubeAccepted(QString))); mTubeClient->setToAcceptAsUnix(false); // no SCM_CREDENTIALS required } TubeReceiver::~TubeReceiver() { } void TubeReceiver::onTubeAccepted(const QString &listenAddress) { qDebug() << "Stream tube channel accepted and opened, listening at" << listenAddress; mDevice = new QLocalSocket(this); mDevice->connectToServer(listenAddress); connect(mDevice, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)), this, SLOT(onStateChanged(QLocalSocket::LocalSocketState))); onStateChanged(mDevice->state()); } void TubeReceiver::onStateChanged(QLocalSocket::LocalSocketState state) { if (state == QLocalSocket::ConnectedState) { qDebug() << "Local socket connected and ready"; connect(mDevice, SIGNAL(readyRead()), this, SLOT(onDataFromSocket())); mDevice->write(QByteArray("Hi there!!\n")); // Throw in some stuff QTimer *timer = new QTimer(this); timer->setInterval(2000); connect(timer, SIGNAL(timeout()), this, SLOT(onTimerTimeout())); timer->start(); } else { qDebug() << "Socket in state " << state; } } void TubeReceiver::onDataFromSocket() { QIODevice *source = qobject_cast(sender()); QString data = QLatin1String(source->readLine()); data.remove(QLatin1Char('\n')); qDebug() << "New data from socket: " << data; } void TubeReceiver::onTimerTimeout() { mDevice->write(QByteArray("ping, I'm alive\n")); } int main(int argc, char **argv) { QCoreApplication app(argc, argv); Tp::registerTypes(); new TubeReceiver(&app); return app.exec(); } #include "_gen/tube-receiver.moc.hpp" telepathy-qt-0.9.6~git1/examples/stream-tubes/CMakeLists.txt0000664000175000017500000000153512470405660021745 0ustar jrjrset(tubereceiver_SRCS tube-receiver.cpp) set(tubereceiver_MOC_SRCS tube-receiver.h) tpqt_generate_mocs(${tubereceiver_MOC_SRCS}) add_executable(tubereceiver ${tubereceiver_SRCS} ${tubereceiver_MOC_SRCS}) target_link_libraries(tubereceiver ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_EXECUTABLE_LINKER_FLAGS}) set(tubeinitiator_SRCS tube-initiator.cpp) set(tubeinitiator_MOC_SRCS tube-initiator.h) tpqt_generate_mocs(${tubeinitiator_MOC_SRCS}) add_executable(tubeinitiator ${tubeinitiator_SRCS} ${tubeinitiator_MOC_SRCS}) target_link_libraries(tubeinitiator ${QT_QTDBUS_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_EXECUTABLE_LINKER_FLAGS}) telepathy-qt-0.9.6~git1/examples/stream-tubes/tube-receiver.h0000664000175000017500000000303312470405660022112 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2009-2011 Collabora Ltd. * Copyright (C) 2009,2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_stream_tubes_tube_receiver_h_HEADER_GUARD_ #define _TelepathyQt_examples_stream_tubes_tube_receiver_h_HEADER_GUARD_ #include #include using namespace Tp; namespace Tp { class PendingOperation; } class TubeReceiver : public QObject { Q_OBJECT public: TubeReceiver(QObject *parent); ~TubeReceiver(); private Q_SLOTS: void onTubeAccepted(const QString &listenAddress); void onStateChanged(QLocalSocket::LocalSocketState newState); void onTimerTimeout(); void onDataFromSocket(); private: StreamTubeClientPtr mTubeClient; QLocalSocket *mDevice; }; #endif telepathy-qt-0.9.6~git1/examples/stream-tubes/tube-initiator.cpp0000664000175000017500000002440712470405660022653 0ustar jrjr/* * This file is part of TelepathyQt * * Copyright (C) 2010-2011 Collabora Ltd. * Copyright (C) 2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tube-initiator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include TubeInitiator::TubeInitiator(const QString &accountName, const QString &receiver, QObject *parent) : QObject(parent), mReceiver(receiver), mTubeRequested(false) { mServer = new QTcpServer(this); connect(mServer, SIGNAL(newConnection()), this, SLOT(onTcpServerNewConnection())); mServer->listen(); AccountFactoryPtr accountFactory = AccountFactory::create( QDBusConnection::sessionBus(), Account::FeatureCore); // We only care about CONNECTED connections, so let's specify that in a Connection Factory ConnectionFactoryPtr connectionFactory = ConnectionFactory::create( QDBusConnection::sessionBus(), Connection::FeatureCore | Connection::FeatureConnected); ChannelFactoryPtr channelFactory = ChannelFactory::create(QDBusConnection::sessionBus()); ContactFactoryPtr contactFactory = ContactFactory::create(Contact::FeatureAlias); mTubeServer = StreamTubeServer::create( QStringList() << QLatin1String("tp-qt-stube-example"), /* one peer-to-peer service */ QStringList(), /* no Room tube services */ QString(), /* autogenerated Client name */ true, /* do monitor connections */ accountFactory, connectionFactory, channelFactory, contactFactory); connect(mTubeServer.data(), SIGNAL(newTcpConnection(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr,Tp::OutgoingStreamTubeChannelPtr)), SLOT(onTubeNewConnection(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr))); connect(mTubeServer.data(), SIGNAL(tcpConnectionClosed(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr,QString,QString,Tp::OutgoingStreamTubeChannelPtr)), SLOT(onTubeConnectionClosed(QHostAddress,quint16,Tp::AccountPtr,Tp::ContactPtr,QString,QString))); mTubeServer->exportTcpSocket(mServer); Q_ASSERT(mTubeServer->isRegistered()); connect(accountFactory->proxy( TP_QT_ACCOUNT_MANAGER_BUS_NAME, TP_QT_ACCOUNT_OBJECT_PATH_BASE + QLatin1Char('/') + accountName, connectionFactory, mTubeServer->registrar()->channelFactory(), mTubeServer->registrar()->contactFactory()), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onAccountReady(Tp::PendingOperation *))); } TubeInitiator::~TubeInitiator() { } void TubeInitiator::onAccountReady(Tp::PendingOperation *op) { if (op->isError()) { qWarning() << "Account cannot become ready - " << op->errorName() << '-' << op->errorMessage(); QCoreApplication::exit(1); return; } PendingReady *ready = qobject_cast(op); Q_ASSERT(ready != NULL); mAccount = AccountPtr::qObjectCast(ready->proxy()); qDebug() << "Account ready"; connect(mAccount.data(), SIGNAL(connectionChanged(Tp::ConnectionPtr)), SLOT(onAccountConnectionChanged(Tp::ConnectionPtr))); if (mAccount->connection().isNull()) { qDebug() << "The account given has no Connection. Please set it online to continue."; } else { onAccountConnectionChanged(mAccount->connection()); } } void TubeInitiator::onAccountConnectionChanged(const ConnectionPtr &conn) { if (!conn) { return; } // Connection::FeatureConnected being in the Connection Factory means that we shouldn't get // pre-Connected Connections Q_ASSERT(conn->isValid()); Q_ASSERT(conn->status() == ConnectionStatusConnected); qDebug() << "Got a Connected Connection!"; mConn = conn; qDebug() << "Creating contact object for receiver" << mReceiver; connect(mConn->contactManager()->contactsForIdentifiers(QStringList() << mReceiver, Features(Contact::FeatureCapabilities)), SIGNAL(finished(Tp::PendingOperation *)), SLOT(onContactRetrieved(Tp::PendingOperation *))); } void TubeInitiator::onContactRetrieved(PendingOperation *op) { if (op->isError()) { qWarning() << "Unable to create contact object for receiver" << mReceiver << "-" << op->errorName() << ": " << op->errorMessage(); return; } PendingContacts *pc = qobject_cast(op); Q_ASSERT(pc->contacts().size() == 1); mContact = pc->contacts().first(); qDebug() << "Checking contact capabilities..."; connect(mContact.data(), SIGNAL(capabilitiesChanged(Tp::ContactCapabilities)), SLOT(onContactCapabilitiesChanged())); if (mContact->capabilities().streamTubes(QLatin1String("tp-qt-stube-example"))) { onContactCapabilitiesChanged(); } else { qDebug() << "The remote contact needs to be online and have the receiver application running to continue"; } } void TubeInitiator::onContactCapabilitiesChanged() { if (mTubeRequested) { return; } if (mContact->capabilities().streamTubes(QLatin1String("tp-qt-stube-example"))) { qDebug() << "The remote contact is capable of receiving tubes with service tp-qt-stube-example now"; mTubeRequested = true; connect(mAccount->createStreamTube( mContact->id(), QLatin1String("tp-qt-stube-example")), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onTubeRequestFinished(Tp::PendingOperation*))); } } void TubeInitiator::onTubeRequestFinished(PendingOperation *op) { if (op->isError()) { qWarning() << "Unable to request stream tube channel -" << op->errorName() << ": " << op->errorMessage(); return; } qDebug() << "Stream tube channel request finished successfully!"; } void TubeInitiator::onTubeNewConnection( const QHostAddress &srcAddr, quint16 srcPort, const Tp::AccountPtr &account, const Tp::ContactPtr &contact) { qDebug() << "Source port" << srcPort << "is" << contact->alias(); mConnAliases.insert(qMakePair(srcAddr, srcPort), contact->alias()); } void TubeInitiator::onTubeConnectionClosed( const QHostAddress &srcAddr, quint16 srcPort, const Tp::AccountPtr &account, const Tp::ContactPtr &contact, const QString &error, const QString &message) { qDebug() << "Connection from source port" << srcPort << "closed with" << error << ':' << message; mConnAliases.remove(qMakePair(srcAddr, srcPort)); } void TubeInitiator::onTcpServerNewConnection() { qDebug() << "Pending connection found"; QTcpSocket *socket = mServer->nextPendingConnection(); connect(socket, SIGNAL(readyRead()), this, SLOT(onDataFromSocket())); } void TubeInitiator::onDataFromSocket() { QAbstractSocket *source = qobject_cast(sender()); QString data = QLatin1String(source->readLine()); data.remove(QLatin1Char('\n')); // Look up the alias of the remote sending us data based on the tube connection tracking. Of // course, this is slightly overengineered; given that this example uses one-to-one tubes (not // group/MUC tubes), all remote connections are always from the same contact we opened the tube // to in the first place. QPair peerAddr(source->peerAddress(), source->peerPort()); if (mConnAliases.contains(peerAddr)) { qDebug() << "New data from contact" << mConnAliases.value(peerAddr) << ':' << data; } else { // We haven't found out the identity for this connection yet. This may happen, because the // TCP server listen socket and the D-Bus connection are on separate sockets and have no // mutual ordering guarantees. // // A GUI application would likely use a placeholder item and lazily replace it with a // representation of the contact when newTcpConnection for this source address has been // received. A non-interactive daemon or alike might, in turn, queue incoming data until the // contact is known, or just carry on if the contact's details aren't needed (yet). qDebug() << "New data from source port" << peerAddr.second << ':' << data; } if (data == QLatin1String("Hi there!!")) { source->write(QByteArray("Hey back mate.\n")); } else { source->write(QByteArray("Sorry, I have no time for you right now.\n")); } } int main(int argc, char **argv) { QCoreApplication app(argc, argv); if (argc != 3) { qDebug() << "usage:" << argv[0] << " "; return 1; } Tp::registerTypes(); new TubeInitiator(QLatin1String(argv[1]), QLatin1String(argv[2]), &app); return app.exec(); } #include "_gen/tube-initiator.moc.hpp" telepathy-qt-0.9.6~git1/examples/cm/0000775000175000017500000000000012470405660015165 5ustar jrjrtelepathy-qt-0.9.6~git1/examples/cm/main.cpp0000664000175000017500000000134712470405660016622 0ustar jrjr#include #include #include #include #include #include #include "protocol.h" using namespace Tp; int main(int argc, char **argv) { QCoreApplication app(argc, argv); Tp::registerTypes(); Tp::enableDebug(true); Tp::enableWarnings(true); BaseProtocolPtr proto = BaseProtocol::create( QDBusConnection::sessionBus(), QLatin1String("example-proto")); BaseConnectionManagerPtr cm = BaseConnectionManager::create( QDBusConnection::sessionBus(), QLatin1String("TpQtExampleCM")); cm->addProtocol(proto); cm->registerObject(); return app.exec(); } telepathy-qt-0.9.6~git1/examples/cm/CMakeLists.txt0000664000175000017500000000103312470405660017722 0ustar jrjrif(ENABLE_SERVICE_SUPPORT) set(cm_SRCS protocol.h protocol.cpp main.cpp) set(cm_MOC_SRCS protocol.h) tpqt_generate_mocs(${cm_MOC_SRCS}) add_executable(cm ${cm_SRCS} ${cm_MOC_SRCS}) target_link_libraries(cm ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} telepathy-qt${QT_VERSION_MAJOR} telepathy-qt${QT_VERSION_MAJOR}-service ${TP_QT_EXECUTABLE_LINKER_FLAGS}) endif(ENABLE_SERVICE_SUPPORT) telepathy-qt-0.9.6~git1/examples/cm/protocol.h0000664000175000017500000000364212470405660017204 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_examples_cm_protocol_h_HEADER_GUARD_ #define _TelepathyQt_examples_cm_protocol_h_HEADER_GUARD_ #include class Protocol : public Tp::BaseProtocol { Q_OBJECT Q_DISABLE_COPY(Protocol) public: Protocol(const QDBusConnection &dbusConnection, const QString &name); virtual ~Protocol(); private: Tp::BaseConnectionPtr createConnection(const QVariantMap ¶meters, Tp::DBusError *error); QString identifyAccount(const QVariantMap ¶meters, Tp::DBusError *error); QString normalizeContact(const QString &contactId, Tp::DBusError *error); // Proto.I.Addressing QString normalizeVCardAddress(const QString &vCardField, const QString vCardAddress, Tp::DBusError *error); QString normalizeContactUri(const QString &uri, Tp::DBusError *error); Tp::BaseProtocolAddressingInterfacePtr addrIface; Tp::BaseProtocolAvatarsInterfacePtr avatarsIface; Tp::BaseProtocolPresenceInterfacePtr presenceIface; }; #endif telepathy-qt-0.9.6~git1/examples/cm/protocol.cpp0000664000175000017500000001076512470405660017543 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "protocol.h" #include "_gen/protocol.moc.hpp" #include #include #include #include #include #include #include using namespace Tp; Protocol::Protocol(const QDBusConnection &dbusConnection, const QString &name) : BaseProtocol(dbusConnection, name) { setParameters(ProtocolParameterList() << ProtocolParameter(QLatin1String("example-param"), QLatin1String("s"), ConnMgrParamFlagRequired)); setRequestableChannelClasses( RequestableChannelClassSpecList() << RequestableChannelClassSpec::textChat()); setEnglishName(QLatin1String("ExampleProto")); setIconName(QLatin1String("example-icon")); setVCardField(QLatin1String("x-example")); // callbacks setCreateConnectionCallback(memFun(this, &Protocol::createConnection)); setIdentifyAccountCallback(memFun(this, &Protocol::identifyAccount)); setNormalizeContactCallback(memFun(this, &Protocol::normalizeContact)); addrIface = BaseProtocolAddressingInterface::create(); addrIface->setAddressableVCardFields(QStringList() << QLatin1String("x-example-vcard-field")); addrIface->setAddressableUriSchemes(QStringList() << QLatin1String("example-uri-scheme")); addrIface->setNormalizeVCardAddressCallback(memFun(this, &Protocol::normalizeVCardAddress)); addrIface->setNormalizeContactUriCallback(memFun(this, &Protocol::normalizeContactUri)); plugInterface(AbstractProtocolInterfacePtr::dynamicCast(addrIface)); avatarsIface = BaseProtocolAvatarsInterface::create(); avatarsIface->setAvatarDetails(AvatarSpec(QStringList() << QLatin1String("image/png"), 16, 64, 32, 16, 64, 32, 1024)); plugInterface(AbstractProtocolInterfacePtr::dynamicCast(avatarsIface)); SimpleStatusSpec spAvailable; spAvailable.type = ConnectionPresenceTypeAvailable; spAvailable.maySetOnSelf = true; spAvailable.canHaveMessage = true; SimpleStatusSpec spOffline; spOffline.type = ConnectionPresenceTypeOffline; spOffline.maySetOnSelf = true; spOffline.canHaveMessage = false; SimpleStatusSpecMap specs; specs.insert(QLatin1String("available"), spAvailable); specs.insert(QLatin1String("offline"), spOffline); presenceIface = BaseProtocolPresenceInterface::create(); presenceIface->setStatuses(PresenceSpecList(specs)); plugInterface(AbstractProtocolInterfacePtr::dynamicCast(presenceIface)); } Protocol::~Protocol() { } BaseConnectionPtr Protocol::createConnection(const QVariantMap ¶meters, Tp::DBusError *error) { error->set(QLatin1String("CreateConnection.Error.Test"), QLatin1String("")); return BaseConnectionPtr(); } QString Protocol::identifyAccount(const QVariantMap ¶meters, Tp::DBusError *error) { error->set(QLatin1String("IdentifyAccount.Error.Test"), QLatin1String("")); return QString(); } QString Protocol::normalizeContact(const QString &contactId, Tp::DBusError *error) { error->set(QLatin1String("NormalizeContact.Error.Test"), QLatin1String("")); return QString(); } QString Protocol::normalizeVCardAddress(const QString &vcardField, const QString vcardAddress, Tp::DBusError *error) { error->set(QLatin1String("NormalizeVCardAddress.Error.Test"), QLatin1String("")); return QString(); } QString Protocol::normalizeContactUri(const QString &uri, Tp::DBusError *error) { error->set(QLatin1String("NormalizeContactUri.Error.Test"), QLatin1String("")); return QString(); } telepathy-qt-0.9.6~git1/config.h.in0000664000175000017500000000004612470405660014773 0ustar jrjr#define PACKAGE_NAME "@PACKAGE_NAME@" telepathy-qt-0.9.6~git1/doxygen.cfg.in0000664000175000017500000017246512470405660015532 0ustar jrjr# This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = ${PROJECT_NAME} # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = ${PACKAGE_VERSION} # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = ${abs_top_builddir}/doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, # and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The \$name class" \ "The \$name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = YES # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = ${abs_top_srcdir} # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = $abs_top_srcdir} ${abs_top_builddir} # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = YES # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = YES # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = YES # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = NO # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = NO # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 0 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = NO # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = NO # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "\$file:\$line: \$text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = doxygen.log #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ${abs_top_srcdir}/TelepathyQt ${abs_top_builddir}/TelepathyQt # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.cpp \ *.cc \ *.cxx \ *.h \ *.hh \ *.hxx \ *.hpp \ *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = */.svn/* \ */.git/* \ */cmake/* \ *.moc.* \ */tests/* \ *-internal.* \ future* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = ${abs_top_srcdir}/examples # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = YES # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = ${GENERATE_HTML} # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = @abs_top_srcdir@/doxygen-header.html # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = @abs_top_srcdir@/doxygen-footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = @abs_top_srcdir@/doxygen.css # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = NO # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = ${GENERATE_CHM} # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = ../${PROJECT}.chm # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = ${HHC_PATH} # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = ${GENERATE_CHI} # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = YES # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to FRAME, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. Other possible values # for this tag are: HIERARCHIES, which will generate the Groups, Directories, # and Class Hiererachy pages using a tree view instead of an ordered list; # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which # disables this behavior completely. For backwards compatibility with previous # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE # respectively. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = ${GENERATE_LATEX} # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = ${PAPER_SIZE} # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = YES # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = ${GENERATE_RTF} # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = ${GENERATE_MAN} # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .1 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = ${GENERATE_XML} # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = ${abs_top_srcdir} ${abs_top_builddir} # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = * # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. # FIXME: for some reason, doxygen doesn't seem to emit a doxygen= attribute at all # in the element if there is no location, in which case there is nothing for # installdox to rewrite. TAGFILES = ${QT_TAGS_FILE}=/you/forgot/to/run/installdox # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = ${abs_top_builddir}/doc/html/${PACKAGE_NAME}.tags # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = ${PERL_PATH} #--------------------------------------------------------------------------- # Configuration options related to the dot tool # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = NO # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = ${HAVE_DOT} # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = NO # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = ${DOT_PATH} # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is enabled by default, which results in a transparent # background. Warning: Depending on the platform used, enabling this option # may lead to badly anti-aliased labels on the edges of a graph (i.e. they # become hard to read). DOT_TRANSPARENT = YES # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO GENERATE_QHP = ${GENERATE_QHP} QHP_NAMESPACE = "org.freedesktop.Telepathy.Qt" QHP_VIRTUAL_FOLDER = "${PROJECT_NAME}-${PACKAGE_VERSION}" QCH_FILE = ${abs_top_builddir}/doc/help/telepathy-qt.qch QHG_LOCATION = ${QHELPGENERATOR_EXECUTABLE} ### TelepathyQt Settings ALIASES = \ "intern=\parInternal use only." \ "reimp=\parReimplemented from superclass." \ "obsolete=@deprecated" \ "feature=\xrefitem features \"Feature(s)\" \"Features\"" \ "maintainer=\xrefitem maintainers \"Maintainer(s)\" \"Maintainers\"" \ "unmaintained=\xrefitem unmaintained \"Unmaintained\" \"Unmaintained\"" \ "requirement=\xrefitem requirements \"Requirement(s)\" \"Requirements\"" \ "faq=\xrefitem FAQ \"F.A.Q.\" \"F.A.Q.\"" \ "authors=\xrefitem authors \"Author(s)\" \"Authors\"" \ "maintainers=\xrefitem maintainers \"Maintainer(s)\" \"Maintainers\"" \ "glossary=\xrefitem glossary \"TelepathyQt Glossary\" \"TelepathyQt Glossary\"" \ "acronym=\b "\ "licenses=\xrefitem licenses \"License(s)\" \"Licenses\"" \ "short=@brief "\ "FIXME=\xrefitem fixme \"Fixme\" \"Fixme\"" \ "bc=\xrefitem bc \"Binary Compatible\" \"Binary Compatible\"" \ "telepathy=Telepathy" \ "telepathy_spec=Telepathy specification" \ "dbus=D-Bus" \ "artistic=Artistic" \ "bsd=BSD" \ "x11=X11" \ "gpl=GPL" \ "lgpl=LGPL" \ "qpl=QPL" PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS \ TP_QT_EXPORT="" \ TP_QT_NO_EXPORT="" \ Q_SLOTS="slots" \ Q_SIGNALS="signals" telepathy-qt-0.9.6~git1/README0000664000175000017500000001137612470405660013640 0ustar jrjr============= telepathy-qt ============= This is a library for Qt-based Telepathy clients. Telepathy is a D-Bus framework for unifying real time communication, including instant messaging, voice calls and video calls. It abstracts differences between protocols to provide a unified interface for applications. See the Telepathy website for more information: http://telepathy.freedesktop.org/ Telepathy specification ======================= The copy of the Telepathy specification in the spec/ directory indicates the specification that this library claims to implement. The HTML documentation for the latest version of the specification can be viewed at: http://telepathy.freedesktop.org/spec/ Requirements ============ Building telepathy-qt requires: Qt, QtDBus, QtNetwork and QtXml (QtGui and QtWidgets are required for some examples) GNU make pkg-config libxslt, xsltproc Python For the full set of regression tests to run, you'll also need: telepathy-glib For building the Farsight convenience library, you'll need: telepathy-glib telepathy-farsight GStreamer and to build the Farstream convenience library, you'll need: telepathy-glib telepathy-farstream farstream GStreamer See CMakeLists.txt for full details, including versions required. Of the packages listed above, only Qt libraries are required at runtime. Building also requires the cmake build system. Qt 5 alpha release contains some build issues that should be addressed in order to build telepathy-qt against it: - When running 'configure' in Qt 5 alpha, the pkg-config files are properly generated, but when 'make' is executed, these files are replaced with empty ones. So, to build telepathy-qt against it one must either backup the pkg-config files generated during the 'configure' phase before running 'make' and replace them afterwards, or re-run 'configure' with the same parameters after building it. - If Qt 5 alpha is built with -reduce-relocations enabled, one must add the keyword "reduce_relocations" to qtbase/lib/pkgconfig/QtCore.pc in the qt_config section, so that telepathy-qt knows when to use -fPIC/PIE at linking stage accordingly. Both issues were reported and should be fixed when beta is out. Bugs, feature requests and to-do list ===================================== Report all bugs, feature requests and "to-do" items here: Running "make check" will produce FIXME.out, which lists all the mentions of FIXME, TODO or XXX in the source code. Ideally, all of these should be in Bugzilla, but sometimes they're not. API stability policy ==================== We use an "odd/even" versioning scheme where the minor version (the y in x.y.z) determines stability - stable branches have y even, development branches have y odd. In a stable (even) branch, we will not make incompatible API or ABI changes between one release tarball and the next. In a development (odd) branch, if we make incompatible ABI changes between one release tarball and the next, we will change the SONAME of the library; we will attempt to avoid incompatible API or ABI changes. Unreleased builds straight from git identify themselves as version "x.y.z.1". We DO NOT make any API guarantees about unreleased builds: any binary relying on new functionality from an unreleased build is not guaranteed to work with any subsequent release or unreleased build, and on platforms with versioned symbols (mainly Linux) it definitely won't work with subsequent releases (you'll have to at least relink the binary). We do not increment SONAMEs on the basis of unreleased changes. Unreleased builds are compiled with -Werror, so they might stop working if your gcc version issues more warnings than ours. If this is a problem for you, use a release tarball. Contact info ============ This library is maintained by the Telepathy project: Telepathy development is supported by Collabora Ltd. . Hacking ======= See HACKING for version control, coding style and patch submission information. telepathy-qt-0.9.6~git1/cmake_uninstall.cmake.in0000664000175000017500000000165412470405660017536 0ustar jrjrIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) STRING(REGEX REPLACE "\n" ";" files "${files}") FOREACH(file ${files}) MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") IF(EXISTS "$ENV{DESTDIR}${file}") EXEC_PROGRAM( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") ENDIF(NOT "${rm_retval}" STREQUAL 0) ELSE(EXISTS "$ENV{DESTDIR}${file}") MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") ENDIF(EXISTS "$ENV{DESTDIR}${file}") ENDFOREACH(file) telepathy-qt-0.9.6~git1/.gitignore0000664000175000017500000000042112470405660014735 0ustar jrjr# For a project mostly in C, the following would be a good set of # Lines that start with '#' are comments. # exclude patterns (uncomment them if you want to use them): # git-ls-files --others --exclude-from=.git/info/exclude *.directory *.py[co] *~ .*.sw[p,o] /build tags telepathy-qt-0.9.6~git1/ChangeLog0000664000175000017500000000017612470405660014526 0ustar jrjrThis is a placeholder ChangeLog - use `git log` instead. In distributed tarballs this is replaced by the output of `git log`. telepathy-qt-0.9.6~git1/doxygen-footer.html0000664000175000017500000000051012470405660016603 0ustar jrjr


Copyright © 2008-2011 Collabora Ltd. and Nokia Corporation
Telepathy-Qt $projectnumber
telepathy-qt-0.9.6~git1/spec/0000775000175000017500000000000012470405660013702 5ustar jrjrtelepathy-qt-0.9.6~git1/spec/Channel_Dispatch_Operation.xml0000664000175000017500000005555312470405660021650 0ustar jrjr Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as a stable interface)

A channel dispatch operation is an object in the ChannelDispatcher representing a batch of unrequested channels being announced to client Approver processes.

These objects can result from new incoming channels or channels which are automatically created for some reason, but cannot result from outgoing requests for channels.

More specifically, whenever the Connection.Interface.Requests.NewChannels signal contains channels whose Requested property is false, or whenever the Connection.NewChannel signal contains a channel with suppress_handler false, one or more ChannelDispatchOperation objects are created for those channels.

(If some channels in a NewChannels signal are in different bundles, this is an error. The channel dispatcher SHOULD recover by treating the NewChannels signal as if it had been several NewChannels signals each containing one channel.)

First, the channel dispatcher SHOULD construct a list of all the Handlers that could handle all the channels (based on their HandlerChannelFilter property), ordered by priority in some implementation-dependent way. If there are handlers which could handle all the channels, one channel dispatch operation SHOULD be created for all the channels. If there are not, one channel dispatch operation SHOULD be created for each channel, each with a list of channel handlers that could handle that channel.

If no handler at all can handle a channel, the channel dispatcher SHOULD terminate that channel instead of creating a channel dispatcher for it. It is RECOMMENDED that the channel dispatcher closes the channels using Channel.Interface.Destroyable.Destroy if supported, or Channel.Close otherwise. As a special case, the channel dispatcher SHOULD NOT close ContactList channels, and if Close fails, the channel dispatcher SHOULD ignore that channel.

ContactList channels are strange. We hope to replace them with something better, such as an interface on the Connection, in a future version of this specification.

When listing channel handlers, priority SHOULD be given to channel handlers that are already handling channels from the same bundle.

If a handler with BypassApproval = True could handle all of the channels in the dispatch operation, then the channel dispatcher SHOULD call HandleChannels on that handler, and (assuming the call succeeds) emit Finished and stop processing those channels without involving any approvers.

Some channel types can be picked up "quietly" by an existing channel handler. If a Text channel is added to an existing bundle containing a StreamedMedia channel, there shouldn't be any approvers, flashing icons or notification bubbles, if the the UI for the StreamedMedia channel can just add a text box and display the message.

Otherwise, the channel dispatcher SHOULD send the channel dispatch operation to all relevant approvers (in parallel) and wait for an approver to claim the channels or request that they are handled. See AddDispatchOperation for more details on this.

Finally, if the approver requested it, the channel dispatcher SHOULD send the channels to a handler.

A list of the extra interfaces provided by this channel dispatch operation. This property cannot change. The Connection with which the Channels are associated. The well-known bus name to use can be derived from this object path by removing the leading '/' and replacing all subsequent '/' by '.'. This property cannot change. The Account with which the Connection and Channels are associated. This property cannot change. The Channels to be dispatched, and their properties. Change notification is via the ChannelLost signal (channels cannot be added to this property, only removed).

A channel has closed before it could be claimed or handled. If this is emitted for the last remaining channel in a channel dispatch operation, it MUST immediately be followed by Finished.

This signal MUST NOT be emitted until all Approvers that were invoked have returned (successfully or with an error) from their AddDispatchOperation method.

This means that Approvers can connect to the ChannelLost signal in a race-free way. Non-approver processes that discover a channel dispatch operation in some way (such as observers) will have to follow the usual "connect to signals then recover state" model - first connect to ChannelLost and Finished, then download Channels (and on error, perhaps assume that the operation has already Finished).

The Channel that closed.

The name of a D-Bus error indicating why the channel closed. If no better reason can be found, org.freedesktop.Telepathy.Error.NotAvailable MAY be used as a fallback; this means that this error SHOULD NOT be given any more specific meaning.

A string associated with the D-Bus error.

The well known bus names (starting with org.freedesktop.Telepathy.Client.) of the possible Handlers for these channels. The channel dispatcher MUST place the most preferred handlers first, according to some reasonable heuristic. As a result, approvers SHOULD use the first handler by default.

The heuristic used to prioritize handlers SHOULD give a higher priority to handlers that are already running.

If, for instance, Empathy and Kopete have similar functionality, and Empathy is running, we should prefer to send channels to it rather than launching Kopete via service activation.

Called by an approver to accept a channel bundle and request that the given handler be used to handle it.

If successful, this method will cause the ChannelDispatchOperation object to disappear, emitting Finished.

However, this method may fail because the dispatch has already been completed and the object has already gone. If this occurs, it indicates that another approver has asked for the bundle to be handled by a particular handler. The approver MUST NOT attempt to interact with the channels further in this case, unless it is separately invoked as the handler.

Approvers which are also channel handlers SHOULD use Claim instead of HandleWith to request that they can handle a channel bundle themselves.

(FIXME: list some possible errors)

If the channel handler raises an error from HandleChannels, this method MAY respond by raising that same error, even if it is not specifically documented here.

The well-known bus name (starting with org.freedesktop.Telepathy.Client.) of the channel handler that should handle the channel, or the empty string if the client has no preferred channel handler.

The selected handler is non-empty, but is not a syntactically correct DBus_Bus_Name or does not start with "org.freedesktop.Telepathy.Client.". The selected handler is temporarily unable to handle these channels. The selected handler is syntactically correct, but will never be able to handle these channels (for instance because the channels do not match its HandlerChannelFilter, or because HandleChannels raised NotImplemented). At the time that HandleWith was called, this dispatch operation was processing an earlier call to HandleWith. The earlier call has now succeeded, so some Handler nominated by another approver is now responsible for the channels. In this situation, the second call to HandleWith MUST NOT return until the first one has returned successfully or unsuccessfully, and if the first call to HandleChannels fails, the channel dispatcher SHOULD try to obey the choice of Handler made by the second call to HandleWith.

Called by an approver to claim channels for handling internally. If this method is called successfully, the process calling this method becomes the handler for the channel, but does not have the HandleChannels method called on it.

Clients that call Claim on channels but do not immediately close them SHOULD implement the Handler interface and its HandledChannels property.

Approvers wishing to reject channels MUST call this method to claim ownership of them, and MUST NOT call Close on the channels unless/until this method returns successfully.

The channel dispatcher can't know how best to close arbitrary channel types, so it leaves it up to the approver to do so. For instance, for Text channels it is necessary to acknowledge any messages that have already been displayed to the user first - ideally, the approver would display and then acknowledge the messages - or to call Channel.Interface.Destroyable.Destroy if the destructive behaviour of that method is desired.

Similarly, an Approver for StreamedMedia channels can close the channel with a reason (e.g. "busy") if desired. The channel dispatcher, which is designed to have no specific knowledge of particular channel types, can't do that.

If successful, this method will cause the ChannelDispatchOperation object to disappear, emitting Finished, in the same way as for HandleWith.

This method may fail because the dispatch operation has already been completed. Again, see HandleWith for more details. The approver MUST NOT attempt to interact with the channels further in this case.

(FIXME: list some other possible errors)

At the time that Claim was called, this dispatch operation was processing a call to HandleWith which has now succeeded, so some Handler nominated by another approver is now responsible for the channel.
At the time of writing, no released implementation of the Channel Dispatcher implements this method; clients should fall back to calling HandleWith.

A variant of HandleWith allowing the approver to pass an user action time. This timestamp will be passed to the Handler when HandleChannels is called.

The well-known bus name (starting with org.freedesktop.Telepathy.Client.) of the channel handler that should handle the channel, or the empty string if the client has no preferred channel handler.

The time at which user action occurred.

The selected handler is non-empty, but is not a syntactically correct DBus_Bus_Name or does not start with "org.freedesktop.Telepathy.Client.". The selected handler is temporarily unable to handle these channels. The selected handler is syntactically correct, but will never be able to handle these channels (for instance because the channels do not match its HandlerChannelFilter, or because HandleChannels raised NotImplemented). At the time that HandleWith was called, this dispatch operation was processing an earlier call to HandleWith. The earlier call has now succeeded, so some Handler nominated by another approver is now responsible for the channels. In this situation, the second call to HandleWith MUST NOT return until the first one has returned successfully or unsuccessfully, and if the first call to HandleChannels fails, the channel dispatcher SHOULD try to obey the choice of Handler made by the second call to HandleWith.

Emitted when this dispatch operation finishes. The dispatch operation is no longer present and further methods must not be called on it.

Approvers that have a user interface SHOULD stop notifying the user about the channels in response to this signal; they MAY assume that on errors, they would have received ChannelLost first.

Its object path SHOULD NOT be reused for a subsequent dispatch operation; the ChannelDispatcher MUST choose object paths in a way that avoids immediate re-use.

Otherwise, clients might accidentally call HandleWith or Claim on a new dispatch operation instead of the one they intended to handle.

This signal MUST NOT be emitted until all Approvers that were invoked have returned (successfully or with an error) from their AddDispatchOperation method.

This means that Approvers can connect to the ChannelLost signal in a race-free way. Non-approver processes that discover a channel dispatch operation in some way (such as observers) will have to follow the usual "connect to signals then recover state" model - first connect to ChannelLost and Finished, then download Channels (and on error, perhaps assume that the operation has already Finished).

telepathy-qt-0.9.6~git1/spec/Channel_Type_Text.xml0000664000175000017500000006666412470405660020023 0ustar jrjr Copyright © 2005-2009 Collabora Limited Copyright © 2005-2009 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

The Messages interface is now mandatory This interface used to have a bunch of clunky Telepathy.Properties. They have been removed in favour of D-Bus properties on the Room2, Subject2 and RoomConfig1 interfaces. A unique-per-channel identifier for an incoming message. These SHOULD be allocated in a way that minimizes collisions (in particular, message IDs SHOULD NOT be re-used until all of the 32-bit integer space has already been used). New APIs should use an array of Message_Part instead. A struct (message ID, timestamp in seconds since 1970-01-01 00:00 UTC, sender's handle, message type, flags, text) representing a pending text message, as returned by ListPendingMessages. The arguments of the Received signal also match this struct's signature. The IDs of the messages to acknowledge Inform the channel that you have handled messages by displaying them to the user (or equivalent), so they can be removed from the pending queue. A given message ID was not found, so no action was taken Consulting MessageTypes is preferred. An array of integer message types (ChannelTextMessageType) Return an array indicating which types of message may be sent on this channel. Consulting PendingMessages is preferred. If true, behave as if AcknowledgePendingMessages had also been called. Setting this to true is NOT RECOMMENDED for clients that have some sort of persistent message storage - clients SHOULD only acknowledge messages after they have actually stored them, which is impossible if this flag is true. An array of structs representing the pending queue. Each contains:
  • a numeric identifier
  • a Unix timestamp indicating when the message was received
  • the contact handle for the contact who sent the message
  • the message type, taken from ChannelTextMessageType
  • the bitwise-OR of the message flags from ChannelTextMessageFlags
  • the text of the message
List the messages currently in the pending queue, and optionally remove then all.
In practice, this signal was not emitted, and does not have useful semantics. This signal is emitted to indicate that an incoming message was not able to be stored and forwarded by the connection manager due to lack of memory. The MessageReceived signal is more informative. A numeric identifier for acknowledging the message A Unix timestamp indicating when the message was received The handle of the contact who sent the message The type of the message (normal, action, notice, etc.) A bitwise OR of the message flags The text of the message Signals that a message with the given id, timestamp, sender, type and text has been received on this channel. Applications that catch this signal and reliably inform the user of the message should acknowledge that they have dealt with the message with the AcknowledgePendingMessages method. The SendMessage method is more flexible. An integer indicating the type of the message The message to send

Request that a message be sent on this channel. When the message has been submitted for delivery, this method will return and the Sent signal will be emitted. If the message cannot be submitted for delivery, the method returns an error and no signal is emitted.

This method SHOULD return before the Sent signal is emitted.

When a Text channel implements the Messages interface, that "SHOULD" becomes a "MUST".

An unknown error occurred The requested contact was offline The requested contact is not valid The user does not have permission to speak on this channel The outgoing message was too long and was rejected by the server The channel doesn't support sending text messages to the requested contact Delivery reporting is now provided by the Messages interface. The error that occurred The Unix timestamp indicating when the message was sent The message type The text of the message

Signals that an outgoing message has failed to send. The error will be one of the values from ChannelTextSendError.

This signal should only be emitted for messages for which Sent has already been emitted and Send has already returned success.

older spec versions claimed that SendError was emitted instead of Sent, rather than in addition to Sent. However, the 0.17.3+ semantics were what we'd always actually implemented.
The MessageSent signal is more informative. Unix timestamp indicating when the message was sent The message type (normal, action, notice, etc) from ChannelTextMessageType The text of the message. If the message was, or will be, altered during transmission, this argument SHOULD reflect what other contacts will receive rather than being a copy of the argument to Send.

Signals that a message has been submitted for sending.

The type of message. An ordinary chat message. Unknown types SHOULD be treated like this. An action which might be presented to the user as "* <sender> <action>", such as an IRC CTCP ACTION (typically selected by the "/me" command). For example, the text of the message might be "drinks more coffee". A one-off or automated message not necessarily expecting a reply An automatically-generated reply message. A delivery report. This message type MUST NOT appear unless the channel supports the Messages interface; see Message_Part for the format that delivery reports must take. The Messages interface has an extensible data structure including separate booleans for most of these flags. The incoming message was truncated to a shorter length by the server or the connection manager.

The incoming message contained non-text content which cannot be represented by this interface, but has been signalled in the Messages interface.

Connection managers SHOULD only set this flag if the non-text content appears to be relatively significant (exactly how significant is up to the implementor). The intention is that if this flag is set, clients using this interface SHOULD inform the user that part of the message was not understood.

The incoming message was part of a replay of message history.

In XMPP multi-user chat, a few past messages are replayed when you join a chatroom. A sufficiently capable IRC connection manager could also set this flag on historical messages when connected to a proxy like bip or irssi-proxy. The existence of this flag allows loggers and UIs to use better heuristics when eliminating duplicates (a simple implementation made possible by this flag would be to avoid logging scrollback at all).

The incoming message has been seen in a previous channel during the lifetime of the Connection, but had not been acknowledged when that channel closed, causing an identical channel (the channel in which the message now appears) to open.

This means that a logger (which should already have seen the message in the previous channel) is able to recognise and ignore these replayed messages.

A channel type for sending and receiving messages. This channel type is primarily used for textual messages, but can also be used for formatted text, text with "attachments", or binary messages on some protocols.

Most of the methods and signals on this interface are deprecated, since they only support plain-text messages with limited metadata. See the mandatory Messages interface for the modern equivalents.

When a message is received, an identifier is assigned and a MessageReceived signal emitted, and the message is placed in a pending queue represented by the PendingMessages property. When the Handler for a channel has handled the message by showing it to the user (or equivalent), it should acknowledge the receipt of that message using the AcknowledgePendingMessages method, and the message will then be removed from the pending queue. Numeric identifiers for received messages may be reused over the lifetime of the channel.

Sending messages can be requested using the SendMessage method, which will return successfully when the message has been submitted for sending, or return an error with no signal emission if there is an immediate failure. If a message is submitted for sending but delivery of the message later fails, this is indicated by a delivery report, which is received in the same way as an incoming message.

Simple one-to-one chats (such as streams of private messages in XMPP or IRC) should be represented by a Text channel whose TargetHandleType is Contact. The expected way to request such a channel is to set the ChannelType, TargetHandleType, and either TargetHandle or TargetID in a call to EnsureChannel.

Named chat rooms whose identity can be saved and used again later (IRC channels, Jabber MUCs) are expected to be represented by Text channels with TargetHandleType = Room and the Group interface. In protocols where a chatroom can be used as a continuation of one or more one-to-one chats, these channels should also have the Conference interface.

Unnamed, transient chat rooms which cannot be rejoined by their unique identifier (e.g. a conversation on MSN which has, or once had, three or more participants) are expected to be represented by Text channels with TargetHandleType = None (and hence TargetHandle = 0), Group interface, and optionally the Conference interface.

On protocols like MSN where a conversation with a user is actually just a nameless chat room starting with exactly two members, to which more members can be invited, the initial one-to-one conversation SHOULD be represented with TargetHandleType = Contact. If a third participant joins or is invited, this SHOULD be represented by signalling a new Conference channel with the one-to-one channel in its InitialChannels, migrating the underlying protocol object from the one-to-one channel to the Conference channel, and creating a new protocol-level conversation if the one-to-one channel is re-used. See the Conference interface for more details.

This keeps the presentation of all one-to-one conversations uniform, and makes it easier to hand over a conversation from a 1-1-specific UI to a more elaborate multi-user UI; while it does require UIs to understand Conference to follow the upgrade, UIs that will deal with XMPP need to understand Conference anyway.

If a channel of type Text is closed while it has pending messages, the connection manager MUST allow this, but SHOULD open a new channel to deliver those messages, signalling it as a new channel with the NewChannels signal. The new channel should resemble the old channel, but have Requested = FALSE regardless of its previous value; the InitiatorHandle and InitiatorID should correspond to the sender of one of the pending messages.

In effect, this turns this situation, in which a client is likely to lose messages:

  • UI window is closed
  • message arrives
  • text channel emits Received
  • UI calls Close on text channel before it has seen the Received signal
  • text channel emits Closed and closes

into something nearly equivalent to this situation, which is fine:

  • UI window is closed
  • UI calls Close on text channel
  • text channel emits Closed and closes
  • message arrives
  • new text channel is created, connection emits NewChannels
  • (the same or a different) UI handles it

Requested must be set to FALSE so the replacement channel will be handled by something.

In practice, connection managers usually implement this by keeping the same internal object that represented the old channel, adjusting its properties, signalling that it was closed, then immediately re-signalling it as a new channel.

As a result, Text channels SHOULD implement Channel.Interface.Destroyable.

This "respawning" behaviour becomes problematic if there is no suitable handler for Text channels, or if a particular message repeatedly crashes the Text channel handler; a channel dispatcher can't just Close() the channel in these situations, because it will come back.

In these situations, the channel dispatcher needs a last-resort way to destroy the channel and stop it respawning. It could either acknowledge the messages itself, or use the Destroyable interface; the Destroyable interface has the advantage that it's not channel-type-dependent, so the channel dispatcher only has to understand one extra interface, however many channel types eventually need a distinction between Close and Destroy.

Opaquely-named rejoinable chatrooms (such as Skype rooms) are represented using the properties in the Room2 interface. Instructions and examples of how to request such channels are given in said interface's description.

telepathy-qt-0.9.6~git1/spec/Call_Stream.xml0000664000175000017500000003163412470405660016621 0ustar jrjr Copyright © 2009-2010 Collabora Ltd. Copyright © 2009-2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

One stream inside a Content. A stream is a single flow of packets to and from a single remote endpoint. If your call connects to multiple people, you could have multiple streams.

For protocols that support muting streams separately, this object MAY also implement the Mute interface

Set the stream to start or stop sending media from the local user to other contacts.

If True, the LocalSendingState should change to Sending, if it isn't already.

If False, the LocalSendingState should change to None, if it isn't already.

If the call has not been accepted yet, calling SetSending(True) is an error. See LocalSendingState for details.

Request that a remote contact stops or starts sending on this stream.

The CanRequestReceiving property defines whether the protocol allows the local user to request the other side start sending on this stream.

Contact from which sending is requested

If true, request that the given contact starts to send media. If false, request that the given contact stops sending media.

The request contact is valid but is not involved in this stream. The protocol does not allow the local user to request the other side starts sending on this stream.
renamed from SendersChanged to MembersChanged renamed from MembersChanged to RemoteMembersChanged Emitted when RemoteMembers changes. A mapping from channel-specific handles to their updated sending state, whose keys include at least the members who were added, and the members whose states changed. The identifiers of the contacts in the Updates map. The channel-specific handles that were removed from the keys of the RemoteMembers property, as a result of the contact leaving this stream A structured reason for the change. Emitted when LocalSendingState changes. The new value of LocalSendingState. A structured reason for the change. Enum indicating whether a contact is sending media. The contact is not sending media and has not been asked to do so. The contact has been asked to start sending media. The contact is sending media. The contact has been asked to stop sending media. A map from a contact to his or her sending state. The contact handle. The sending state of the contact.

Extra interfaces provided by this stream, such as Stream.Interface.Media. This SHOULD NOT include the Stream interface itself, and cannot change once the stream has been created.

renamed from Senders

A map from remote contacts to their sending state.

Media sent to this stream will be sent to all members listed here. All members listed here will also appear in CallMembers, and each CallMembers member will be listed in at most one Stream per Content. Therefore, to hide things from a member of the call, UIs only need to mute one Stream per Content.

Contacts' handles in this map indicate whether they are sending media to this stream. Sending_State_Pending_Send indicates contacts who are not sending but have been asked to do so. The local user's sending state is shown in LocalSendingState.

This mapping is also used by the streaming implementation to map from MediaDescriptions to Streams. In this use-case, all of the senders in this stream will be represented in RemoteMediaDescriptions. This use-case should not affect anything that does not handle media streaming.

The string identifiers for handles mentioned in RemoteMembers, to give clients the minimal information necessary to create contacts without waiting for round-trips.

The local user's sending state. Media sent on this stream should be assumed to be received, directly or indirectly, by every other contact in the RemoteMembers mapping. Change notification is given via the LocalSendingStateChanged signal.

Implementations of the first Call draft had the self handle in the RemoteMembers (then called Members) map and this showed that it's annoying having to keep track of the self handle so that it can be special-cased.

A value of Pending_Send for this property indicates that the other side requested the local user start sending media (which can be done by calling either SetSending or Accept).

When Accept is called, all streams with a local sending state of Pending_Send and the associated Disposition set to Initial are automatically set to sending.

If true, the user can request that a remote contact starts sending on this stream.

Not all protocols allow the user to ask the other side to start sending media.
telepathy-qt-0.9.6~git1/spec/Client_Handler_Future.xml0000664000175000017500000000771512470405660020643 0ustar jrjr Copyright © 2009 Collabora Ltd. Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

This interface contains functionality which we intend to incorporate into the Handler interface in future. It should be considered to be conceptually part of the core Handler interface, but without API or ABI guarantees.

If true, channels destined for this handler are not passed to observers for observing.

This is useful in use-cases where the handler doesn't want anyone observing the channel - for example, because channels it handles shouldn't be logged.

For service-activatable handlers, this property should be specified in the handler's .client file as follows:

[org.freedesktop.Telepathy.Client.Handler]
BypassObservers=true

If true, channels destined for this handler that have the Conference interface, with a channel that was previously handled by the same client process in their InitialChannels property, should bypass the approval stage. In effect, this is a weaker form of BypassApproval.

It would be reasonable for a user interface to accept invitations to continuations of an existing channel automatically, or not; this is a matter of UI policy.

It's somewhat complex for an Approver to keep track of which channels are being handled by a particular Handler, but the Channel Dispatcher already has to track this, so it's useful for the channel dispatcher to assist here.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Communication_Policy.xml0000664000175000017500000001460512470405660024715 0ustar jrjr Copyright © 2010 Collabora Limited This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library 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. (draft 1)

This interface supports controlling which contacts are allowed to initiate text chats, incoming calls, and other forms of communication as supported by the underlying protocol. The policies supported for different communication methods on this connection are listed in the SupportedPolicies property. The current configuration is held in ActivePolicies; it can be modified using SetPolicy, and changes are signalled by PolicyChanged.

A mapping of communication methods (channel types), and their associated policy. The channel interface with the policy. The active policy for this channel type. The communication policies supported by this connection.

The active communication policies on this connection. Communication methods that are not in this mapping are considered open.

For example, to allow incoming calls only from contacts buddy list, and to allow text messages from anyone, the policy would look like this:

{
    'org.freedesktop.Telepathy.Channel.Type.Text' : Access_Control_Type_Open,
    'org.freedesktop.Telepathy.Channel.Type.Call' : Access_Control_Type_Publish_List
}
        

Changes to this property are signalled by PolicyChanged.

Set a policy for a communication method (channel type). Depending on the server or protocol, more than one communication method could be bound to the same policy, if calling this method on one channel type changes the policy on another channel type, the PolicyChanged signal that would follow would include all the channel types that have an altered policy. The channel type to set the policy for. The policy to set for this channel. ActivePolicies has changed. This occurs when the server unilaterally changed the policy or SetPolicy has been called. A subset of the active policies that have changed.

The communication methods (channel types), and the policies that can be applied to them. This is server and protocol dependant.

Grouped channel types will always have the same policy applied to them.

Different protocols have different limitations to the granularity of communication policies. One protocol might be able to set a different policy for VoIP calls and text chat, while another protocol might only be able to set one policy to both VoIP and text chat.
A list of channel interfaces that support these policies. A list of supported policies.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Addressing.xml0000664000175000017500000002627112470405660022656 0ustar jrjr Copyright (C) 2010-2012 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

This interface deals with the multiple address types that can refer to the same contact, such as vCard fields and URIs.

It can be used to retrieve contacts with a specific addresses through GetContactsByVCardField and GetContactsByURI, as well as defining the various addressing methods for a given contact through this interface's contact attributes.

The vCard field of the addresses we are requesting. The field name SHOULD be in lower case. Supported fields can be found in AddressableVCardFields.

The url vCard field MUST NOT appear here; see GetContactsByURI instead.

In practice, protocols have a limited set of URI schemes that make sense to resolve as a contact.

The addresses to get contact handles for. The address types should match the given vCard field.

A list of strings indicating which D-Bus interfaces the calling process is interested in. All supported attributes from these interfaces, whose values can be obtained without additional network activity, will be in the reply.

Attributes from this interface and from org.freedesktop.Telepathy.Connection are always returned, and need not be requested explicitly.

The behavior of this parameter is similar to the same parameter in Contacts.GetContactAttributes.

A mapping from requested vCard addresses to the corresponding contact handles.

Requested addresses that are not valid or understood for this protocol MUST be omitted from the mapping.

A dictionary mapping the contact handles to contact attributes. If any of the requested addresses are in fact invalid, they are simply omitted from this mapping. If contact attributes are not immediately known, the behaviour is defined by the interface; the attribute should either be omitted from the result or replaced with a default value.

Requested addresses that are not valid or understood for this protocol MUST be omitted from the mapping.

Each contact's attributes will always include at least the identifier that would be obtained by inspecting the handle (org.freedesktop.Telepathy.Connection/contact-id).

Request contacts and retrieve their attributes using a given field in their vCards.

The connection manager should record that these handles are in use by the client who invokes this method, and must not deallocate the handles until the client disconnects from the bus or calls the Connection.ReleaseHandles method.

The URI addresses to get contact handles for. Supported schemes can be found in AddressableURISchemes.

A list of strings indicating which D-Bus interfaces the calling process is interested in. All supported attributes from these interfaces, whose values can be obtained without additional network activity, will be in the reply.

Attributes from this interface and from org.freedesktop.Telepathy.Connection are always returned, and need not be requested explicitly.

The behavior of this parameter is similar to the same parameter in Contacts.GetContactAttributes.

A mapping of requested URIs to the corresponding contact handles.

Requested URIs that are not valid or understood for this protocol MUST be omitted from the mapping.

A dictionary mapping the contact handles to contact attributes. If any of the requested addresses are in fact invalid, they are simply omitted from this mapping. If contact attributes are not immediately known, the behaviour is defined by the interface; the attribute should either be omitted from the result or replaced with a default value.

Requested URIs that are not valid or understood for this protocol MUST be omitted from the mapping.

Each contact's attributes will always include at least the identifier that would be obtained by inspecting the handle (org.freedesktop.Telepathy.Connection/contact-id).

Request contacts and retrieve their attributes using URI addresses.

The connection manager should record that these handles are in use by the client who invokes this method, and must not deallocate the handles until the client disconnects from the bus or calls the Connection.ReleaseHandles method.

A mapping of vCard fields and addresses equivalent to a particular contact's protocol identifier. For instance, on XMPP this would contain x-jabber for all contacts, and x-facebook-id for contacts on Facebook's server.

A vCard field, such as x-jabber. The value of that vCard field for the contact.
The various vCard addresses that identify this contact. The various URI addresses that identify this contact. A map from URIs/vCard addresses to the corresponding handle. The URI or vCard address that has been requested by GetContactsByVCardField or GetContactsByURI. A nonzero handle.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Aliasing.xml0000664000175000017500000002107112470405660022313 0ustar jrjr Copyright (C) 2005, 2006 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A dictionary whose keys are contact handles and whose values are aliases. A pair (contact handle, alias) as seen in the AliasesChanged signal. An array containing structs of:
  • the handle representing the contact
  • the new alias
Signal emitted when a contact's alias (or that of the user) is changed.

The aliases of contacts on this connection may be changed by the user of the service, not just by the contacts themselves. This is the case on Jabber, for instance.

It is possible that aliases can be changed by the contacts too - which alias takes precedence is not defined by this specification, and depends on the server and/or connection manager implementation.

This flag only applies to the aliases of "globally valid" contact handles. At this time, clients should not expect to be able to change the aliases corresponding to any channel-specific handles. If this becomes possible in future, a new flag will be defined.

An integer with a bitwise OR of flags from ConnectionAliasFlags Return a bitwise OR of flags detailing the behaviour of aliases on this connection. An array of handles representing contacts A list of aliases in the same order as the contact handles Request the value of several contacts' aliases at once. An array of handles representing contacts A dictionary mapping contact handles to aliases Request the value of several contacts' aliases at once. This SHOULD only return cached aliases, falling back on the contact identifier (i.e. the string corresponding to the handle) if none is present. Also if there was no cached alias, a request SHOULD be started of which the result is later signalled by AliasesChanged. A dictionary mapping integer handles of contacts to strings of the new alias to set. Request that the alias of the given contact be changed. Success will be indicated by emitting an AliasesChanged signal. On connections where the CONNECTION_ALIAS_FLAG_USER_SET flag is not set, this method will only ever succeed if the contact is the user's own handle (as returned by Connection.GetSelfHandle).

The same string that would be returned by GetAliases (always present with some value, possibly the same as Connection/contact-id, if information from the Aliasing interface was requested)

An interface on connections to support protocols where contacts have an alias which they can change at will. Provides a method for the user to set their own alias, and a signal which should be emitted when a contact's alias is changed or first discovered.

On connections where the user is allowed to set aliases for contacts and store them on the server, the GetAliasFlags method will have the CONNECTION_ALIAS_FLAG_USER_SET flag set, and the SetAliases method may be called on contact handles other than the user themselves.

Aliases are intended to be used as the main displayed name for the contact, where available.

telepathy-qt-0.9.6~git1/spec/Channel_Dispatcher.xml0000664000175000017500000010270612470405660020150 0ustar jrjr Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as a stable interface)

The channel dispatcher is responsible for responding to new channels and launching client processes to handle them. It also provides functionality for client processes to request that new channels are created.

If a channel dispatcher is running, it is responsible for dispatching new channels on all Connections created by the AccountManager. Connections not created by the AccountManager are outside the scope of the channel dispatcher.

Connections created by standalone Telepathy clients that do not intend to interact with the channel dispatcher should be ignored - otherwise, the channel dispatcher would try to launch handlers for channels that the standalone client was already handling internally.

The current channel dispatcher is defined to be the process that owns the well-known bus name org.freedesktop.Telepathy.ChannelDispatcher on the session bus. This process MUST export an object with this interface at the object path /org/freedesktop/Telepathy/ChannelDispatcher.

Until a mechanism exists for making a reasonable automatic choice of ChannelDispatcher implementation, implementations SHOULD NOT register as an activatable service for the ChannelDispatcher's well-known bus name. Instead, it is RECOMMENDED that some component of the user's session will select and activate a particular implementation, and that other Telepathy-enabled programs can detect whether channel request/dispatch functionality is available by checking whether the ChannelDispatcher's well-known name is in use at runtime.

There are three categories of client process defined by this specification:

Observer

Observers monitor the creation of new channels. This functionality can be used for things like message logging. All observers are notified simultaneously.

Approver

Approvers notify the user that new channels have been created, and also select which channel handler will be used for the channel, either by asking the user or by choosing the most appropriate channel handler.

Handler

Each new channel or set of channels is passed to exactly one handler as its final destination. A typical channel handler is a user interface process handling channels of a particular type.

A list of the extra interfaces provided by this channel dispatcher.

Equivalent to calling CreateChannelWithHints with an empty Hints parameter.

The Account for which the new channel is to be created.

A dictionary containing desirable properties.

This parameter is used in the same way as the corresponding parameter to CreateChannelWithHints.

The time at which user action occurred, or 0 if this channel request is for some reason not involving user action.

This parameter is used in the same way as the corresponding parameter to CreateChannelWithHints.

Either the well-known bus name (starting with org.freedesktop.Telepathy.Client.) of the preferred handler for this channel, or an empty string to indicate that any handler would be acceptable.

This parameter is used in the same way as the corresponding parameter to CreateChannelWithHints.

Previously, the spec didn't say that this should disregard the handler's filter. This has been implemented since telepathy-mission-control 5.3.2.
A ChannelRequest object. The Preferred_Handler is syntactically invalid or does not start with org.freedesktop.Telepathy.Client., the Account does not exist, or one of the Requested_Properties is invalid

Equivalent to calling EnsureChannelWithHints with an empty Hints parameter.

The Account for which the new channel is to be created.

A dictionary containing desirable properties.

This parameter is used in the same way as the corresponding parameter to CreateChannelWithHints.

The time at which user action occurred, or 0 if this channel request is for some reason not involving user action.

This parameter is used in the same way as the corresponding parameter to CreateChannelWithHints.

Either the well-known bus name (starting with org.freedesktop.Telepathy.Client.) of the preferred handler for this channel, or an empty string to indicate that any handler would be acceptable. The behaviour and rationale are the same as for the corresponding parameter to EnsureChannelWithHints.

A ChannelRequest object. The Preferred_Handler is syntactically invalid or does not start with org.freedesktop.Telepathy.Client., the Account does not exist, or one of the Requested_Properties is invalid
Support for this method is indicated by the SupportsRequestHints property. Clients MUST recover from this method being unsupported by falling back to CreateChannel.

Start a request to create a channel. This initially just creates a ChannelRequest object, which can be used to continue the request and track its success or failure.

The request can take a long time - in the worst case, the channel dispatcher has to ask the account manager to put the account online, the account manager has to ask the operating system to obtain an Internet connection, and the operating system has to ask the user whether to activate an Internet connection using an on-demand mechanism like dialup.

This means that using a single D-Bus method call and response to represent the whole request will tend to lead to that call timing out, which is not the behaviour we want.

If this method is called for an Account that is disabled, invalid or otherwise unusable, no error is signalled until ChannelRequest.Proceed is called, at which point ChannelRequest.Failed is emitted with an appropriate error.

This means there's only one code path for errors, apart from InvalidArgument for "that request makes no sense".

It also means that the request will proceed if the account is enabled after calling CreateChannel, but before calling Proceed.

The Account for which the new channel is to be created.

A dictionary containing desirable properties. This has the same semantics as the corresponding parameter to Connection.Interface.Requests.CreateChannel.

Certain properties will not necessarily make sense in this dictionary: for instance, TargetHandle can only be given if the requester is able to interact with a Connection to the desired account.

The time at which user action occurred, or 0 if this channel request is for some reason not involving user action. The UserActionTime property will be set to this value, and it will eventually be passed as the User_Action_Time parameter of HandleChannels.

Either the well-known bus name (starting with org.freedesktop.Telepathy.Client.) of the preferred handler for this channel, or an empty string to indicate that any handler would be acceptable. The channel dispatcher SHOULD dispatch as many as possible of the resulting channels (ideally, all of them) to that handler—irrespective of whether that handler's HandlerChannelFilter matches the channel—and SHOULD remember the preferred handler so it can try to dispatch subsequent channels in the same bundle to the same handler.

This must be the well-known bus name, not the unique name, to ensure that all handlers do indeed have the Client API, and the Client object on the handler can be located easily.

This is partly so the channel dispatcher can call HandleChannels on it, and partly so the channel dispatcher can recover state if it crashes and is restarted.

The filter should be disregarded for ease of use of this interface: clients will usually use this argument to request channels be sent to themself, and this should trump the filter not matching. This also allows a client to become the handler for a channel produced by one of its own requests, while not being a candidate to handle other channels of that type.

If this is a well-known bus name and the handler has the Requests interface, the channel dispatcher SHOULD call AddRequest on that Handler after this method has returned.

This ordering allows a Handler which calls CreateChannel with itself as the preferred handler to associate the call to AddRequest with that call.

This is copied to the ChannelRequest that is returned, as the PreferredHandler property.

Previously, the spec didn't say that this should disregard the handler's filter. This has been implemented since telepathy-mission-control 5.3.2.

Additional information about the channel request, which will be used as the value for the resulting request's Hints property.

See the Hints property's documentation for rationale.

A ChannelRequest object. The Preferred_Handler is syntactically invalid or does not start with org.freedesktop.Telepathy.Client., the Account does not exist, or one of the Requested_Properties is invalid
Support for this method is indicated by the SupportsRequestHints property. Clients MUST recover from this method being unsupported by falling back to EnsureChannel.

Start a request to ensure that a channel exists, creating it if necessary. This initially just creates a ChannelRequest object, which can be used to continue the request and track its success or failure.

If this method is called for an Account that is disabled, invalid or otherwise unusable, no error is signalled until ChannelRequest.Proceed is called, at which point ChannelRequest.Failed is emitted with an appropriate error.

The rationale is as for CreateChannelWithHints.

The Account for which the new channel is to be created.

A dictionary containing desirable properties. This has the same semantics as the corresponding parameter to Connection.Interface.Requests.EnsureChannel.

Certain properties will not necessarily make sense in this dictionary: for instance, TargetHandle can only be given if the requester is able to interact with a Connection to the desired account.

The time at which user action occurred, or 0 if this channel request is for some reason not involving user action.

This parameter is used in the same way as the corresponding parameter to CreateChannelWithHints.

Either the well-known bus name (starting with org.freedesktop.Telepathy.Client.) of the preferred handler for this channel, or an empty string to indicate that any handler would be acceptable. The behaviour and rationale are the same as for the corresponding parameter to CreateChannelWithHints, except as noted here.

If any new channels are created in response to this request, the channel dispatcher SHOULD dispatch as many as possible of the resulting channels (ideally, all of them) to that handler, and SHOULD remember the preferred handler so it can try to dispatch subsequent channels in the same bundle to the same handler. If the requested channel already exists (that is, Connection.Interface.Requests.EnsureChannel returns Yours=False) then the channel dispatcher SHOULD re-dispatch the channel to its existing handler, and MUST NOT dispatch it to this client (unless it is the existing handler); the request is still deemed to have succeeded in this case.

An address book application, for example, might call EnsureChannel to ensure that a text channel with a particular contact is displayed to the user; it does not care whether a new channel was made. An IM client might call EnsureChannel in response to the user double-clicking an entry in the contact list, with itself as the Preferred_Handler; if the user already has a conversation with that contact in another application, they would expect the existing window to be presented, rather than their double-click leading to an error message. So the request should succeed, even if its Preferred_Handler is not used.

Additional information about the channel request, which will be used as the value for the resulting request's Hints property. A ChannelRequest object. The Preferred_Handler is syntactically invalid or does not start with org.freedesktop.Telepathy.Client., the Account does not exist, or one of the Requested_Properties is invalid
Implemented since telepathy-mission-control 5.7.12. This method now returns Delegated and Not_Delegated instead of nothing. HandleChannels is now called once per Channel in Channels.

Called by a Handler to redispatch a bunch of channels it is currently handling.

For each Channel in Channels, if another Handler can be found, HandleChannels will be called on it until a Handler accepts it.

This method returns once all the Channels have either been accepted or rejected by Handlers.

If this method fails, the original Handler is still handling the channels.

The list of channels to redispatch. The caller has to be the current Handler of all of these channels

The time at which user action occurred, or 0 if this channels delegation is for some reason not involving user action.

This parameter is used in the same way as the corresponding parameter to CreateChannelWithHints.

Either the well-known bus name (starting with org.freedesktop.Telepathy.Client.) of the preferred new handler for these channels, or an empty string to indicate that any handler would be acceptable. The behaviour and rationale are the same as for the corresponding parameter to CreateChannelWithHints.

The list of channels which have been delegated; the caller is no longer handling these channels.

The client should remove these channels from its HandledChannels property.

The list of channels which have NOT been delegated; the caller is still handling these channels.

The Preferred_Handler is syntactically invalid or does not start with org.freedesktop.Telepathy.Client.. At least one Channel in Channels is not currently handled by the caller. No Channel has been delegated.
A mapping associating not delegated channel with an error. The path of the channel An error describing why the channel has not be delegated the name of a D-Bus error describing what went wrong. a human-readable informative error message. Implemented since telepathy-mission-control 5.7.12.

Equivalent of calling EnsureChannel with a Requested_Properties which would result in ensuring Channel.

If Channel is handled, its handler will be asked to present it the user (e.g. bring it into the foreground).

The channel to present.

The time at which user action occurred, or 0 if this channel request is for some reason not involving user action.

This parameter is used in the same way as the corresponding parameter to EnsureChannelWithHints.

The Account does not exist, the Channel does not exist or it does not belong to the Account.
If True, the channel dispatcher is new enough to support CreateChannelWithHints and EnsureChannelWithHints, in addition to the older CreateChannel and EnsureChannel methods, and also new enough to emit SucceededWithChannel before the older Succeeded signal. If False or missing, only the metadata-less variants are supported.
telepathy-qt-0.9.6~git1/spec/Channel_Type_Server_Authentication.xml0000664000175000017500000001372012470405660023365 0ustar jrjr Copyright © 2010 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

The type for a channel representing an authentication step with the server. The actual authentication functionality is implemented by the additional interface named in AuthenticationMethod, such as Channel.Interface.SASLAuthentication.

Future authentication steps also supported by this channel type might include solving a captcha and/or agreeing to an EULA or terms-of-use document; each of these would be represented by a channel with this type, but a different AuthenticationMethod.

Channels of this type will normally be be signalled and dispatched while the Connection owning them is in the CONNECTING state. They MAY also appear on a Connection in the CONNECTED state, for instance if periodic re-authentication is required.

Normally, only one channel of this type will exist on a given Connection; if there is more than one, the handler must complete authentication with each of them in turn.

Channels of this type cannot be requested with methods such as CreateChannel. They always have Requested = False, TargetHandleType = None and TargetHandle = 0.

While it is CONNECTING, the Connection MUST NOT proceed with connection, or signal StatusChanged to the CONNECTED state, until each channel of this type has either been accepted as having a positive result (for instance, on SASL channels this is done with the AcceptSASL method), or closed with the Close method.

ServerAuthentication channels normally represent the client authenticating itself to the server, but can also be used for the server to authenticate itself to the client (i.e. prove that it is in fact the desired server and not an imposter). Until the authentication handler has confirmed this, connection should not continue.

If a channel of this type is closed with the Close method before authentication has succeeded, this indicates that the Handler has given up its attempts to authenticate or that no Handler is available.

If this occurs, the connection manager MAY attempt to continue connection (for instance, performing SASL authentication by using any credentials passed to RequestConnection, for instance from the Account.Parameters). If this fails or has already been tried, the Connection will disconnect.

In particular, the ChannelDispatcher will close the channel if it cannot find a handler.

When the connection is done with the channel and it is no longer needed, it is left open until either the connection state turns to DISCONNECTED or the handler closes the channel. The channel SHOULD NOT close itself once finished with.

This property defines the method used for the authentication step represented by this channel, which MUST be one of this channel's Interfaces.

The initially-defined interface that can be used here is Channel.Interface.SASLAuthentication.

telepathy-qt-0.9.6~git1/spec/Account_Interface_External_Password_Storage.xml0000664000175000017500000000500712470405660025212 0ustar jrjr Copyright © 2011 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft 1)

An interface for Accounts whose passwords are stored externally and SHOULD NOT be stored by either the AccountManager nor any ServerAuthentication handler.

This interface SHOULD only appear on accounts for which the related Connection Manager implements ConnectionManager.Interface.AccountStorage.DRAFT.

Clears any saved password associated with this account.

Indicates whether the account has a saved password or not.

Change notification for this property is provided by the standard D-Bus PropertiesChanged signal.

telepathy-qt-0.9.6~git1/spec/Connection_Manager.xml0000664000175000017500000007311212470405660020161 0ustar jrjr Copyright (C) 2005-2012 Collabora Limited Copyright (C) 2005-2008 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

The name of a connection manager, found in its well-known bus name and object path. This must be a non-empty string of ASCII letters, digits and underscores, starting with a letter. This is typically the name of the executable with any "telepathy-" prefix removed, and any hyphen/minus signs replaced by underscores.

Connection manager names SHOULD NOT be the same as the name of the protocol they implement.

This is likely to lead to conflicts between different implementations of the same protocol (or indeed inability to distinguish between the different implementations!). The Telepathy project traditionally uses some sort of pun (Haze is based on libpurple, Salut implements a protocol often called Bonjour, and Wilde implements the OSCAR protocol).

Connection manager names SHOULD NOT be the same as the name of a library on which they are based.

We often abbreviate, for instance, telepathy-haze as “Haze”, but abbreviating telepathy-sofiasip—since renamed to telepathy-rakia for exactly this reason—to “Sofia-SIP” caused confusion between the connection manager and the library it uses. Please don't repeat that mistake.

Prior to version 0.17.1, the allowed characters were not specified

An instant messaging protocol. It must consist only of ASCII letters, digits and hyphen/minus signs (U+002D "-"), and must start with a letter. Where possible, this SHOULD be chosen from the following well-known values:

  • aim - AOL Instant Messenger (OSCAR or TOC)
  • gadugadu - Gadu-Gadu
  • groupwise - Novell Groupwise
  • icq - ICQ (OSCAR)
  • irc - Internet Relay Chat (RFC 1459, 2810-2813)
  • jabber - XMPP (RFC 3920, 3921) or Jabber
  • local-xmpp - Link-local XMPP (XEP-0174) (Bonjour, Salut)
  • msn - MSNP (Windows Live Messenger)
  • myspace - MySpaceIM
  • mxit - MXit
  • napster - Napster
  • qq - Tencent QQ
  • sametime - IBM Lotus Sametime
  • silc - SILC
  • sip - Session Initiation Protocol (SIP), with or without SIMPLE support
  • skype - Skype
  • tel - telephony (the PSTN, including GSM, CDMA and fixed-line telephony)
  • trepia - Trepia
  • yahoo - YMSG (Yahoo! Messenger)
  • yahoojp - Japanese version of YMSG
  • zephyr - Zephyr
Prior to version 0.17.1, the allowed characters were not specified
A struct representing an allowed parameter, as returned by GetParameters on the ConnectionManager interface. A string parameter name A bitwise OR of the parameter flags A string containing the D-Bus type signature for this parameter The default value (if the Has_Default flag is not present, there is no default and this takes some dummy value, which SHOULD be of the appropriate D-Bus type) This parameter is required for connecting to the server. This parameter is required for registering an account on the server. This parameter has a default value, which is returned in GetParameters; not providing this parameter is equivalent to providing the default.

This parameter should be considered private or secret; for instance, clients should store it in a "password safe" like gnome-keyring or kwallet, omit it from debug logs, and use a text input widget that hides the value of the parameter.

(Clients that support older connection managers may also treat any parameter whose name contains "password" as though it had this flag.)

This parameter is also a D-Bus property on the resulting Connection; a parameter named com.example.Duck.Macaroni with this flag corresponds to the Macaroni property on the com.example.Duck interface. Its value can be queried and possibly changed on an existing Connection using methods on the org.freedesktop.DBus.Properties interface.

When a new value for a parameter with this flag is passed to Account.UpdateParameters, the account manager will attempt to update its value on any running connections. Similarly, if the parameter also has the Has_Default flag, and is passed in the second argument to UpdateParameters, the default value will be applied to any running connections. Thus, clients generally do not need to directly access or update the connection property; instead, they SHOULD manipulate Account.Parameters.

This allows runtime-configurable options to be stored and maintained by the AccountManager, without needing to invent a separate account preference for “properties that should be set on the connection as soon as it is created”. It was originally invented to manage Cellular preferences.

The required protocol name An array of structs representing possible parameters. Get a list of the parameters which may be specified in the Parameters of an Account (or, for specialised applications which do not use the account manager, passed to RequestConnection). Some parameters are mandatory, and some parameters only make sense when registering new accounts with the server; see the Param_Spec documentation for more details. The requested protocol is not supported by this manager

A map from protocol identifiers supported by a connection manager to the immutable properties of the corresponding Protocol objects.

A protocol name The immutable properties of the corresponding Protocol object

A map from protocol identifiers supported by this connection manager to the immutable properties of the corresponding Protocol objects.

Providing the immutable properties here means that when the API of Protocol objects has been finalized, most clients will only need one D-Bus round trip to interrogate the ConnectionManager about all its protocols.

If this map is empty or missing, clients SHOULD fall back to calling ListProtocols and GetParameters.

The keys of the Protocols map. Get a list of protocol identifiers that are implemented by this connection manager. The D-Bus service where the connection object can be found The object path of the Connection object on this service The identifier for the protocol this connection uses Emitted when a new Connection object is created. The protocol identifier A dictionary mapping parameter names to values of the appropriate type, as indicated by GetParameters and the well-known list of names and value types documented on the Connection_Parameter_Name type. A D-Bus service name where the new Connection object can be found The D-Bus object path to the Connection on this service

Request a Connection object representing a given account on a given protocol with the given parameters. The method returns the bus name and the object path where the new Connection object can be found, which should have the status of Connection_Status_Disconnected, to allow signal handlers to be attached before connecting is started with the Connect method.

Most applications should not use this method: they should instead use the the Connection property on an Account object obtained from the AccountManager. This method is used internally by the account manager to create connections when needed.

The parameters which must and may be provided in the parameters dictionary can be discovered with the GetParameters method. These parameters, their types, and their default values may be cached in files so that all available connection managers do not need to be started to discover which protocols are available.

To request values for these parameters from the user, a client must have prior knowledge of the meaning of the parameter names, so the well-known names and types defined by the Connection_Parameter_Name type should be used where appropriate.

Connection manager authors SHOULD avoid introducing parameters whose default values would not be serializable in a .manager file.

The same serialization format is used in Mission Control to store accounts.

Every successful RequestConnection call will cause the emission of a NewConnection signal for the same newly created connection. The requester can use the returned object path and service name independently of the emission of that signal. In that case this signal emission is most useful for, e.g. other processes that are monitoring the creation of new connections.

The requested protocol is not supported by this manager The requested connection already appears to exist Unrecognised connection parameters

Well-known connection parameter names, along with their expected type. Where possible, connection managers should use names and types from this list in the Parameters that may be passed to RequestConnection.

account (s)
The identifier for the user's account on the server
server (s)
A fully qualified domain name or numeric IPv4 or IPv6 address. Using the fully-qualified domain name form is recommended whenever possible. If this parameter is specified and the account for that protocol also specifies a server, this parameter should override that in the user id.
port (q)
A TCP or UDP port number. If this parameter is specified and the account for that protocol also specifies a port, this parameter should override that in the account.
password (s)
A password associated with the account.
require-encryption (b)
Require encryption for this connection. A connection should fail to connect if require-encryption is set and an encrypted connection is not possible.
register (b)
This account should be created on the server if it does not already exist.
ident (s)
The local username to report to the server if necessary, such as in IRC.
fullname (s)
The user's full name if the service requires this when authenticating or registering.
stun-server (s)
The IP address or FQDN of a STUN server to use for NAT traversal, without any ":port" suffix.
stun-port (q)
The UDP port number on the stun-server to use for STUN. Only significant if the stun-server is also supplied.
keepalive-interval (u)

The time in seconds between pings sent to the server to ensure that the connection is still alive, or 0 to disable such pings.

This parameter is superseded by the KeepaliveInterval property, which can be updated on an already-established connection as well as being specified when requesting the connection. Clients SHOULD provide that parameter instead, if allowed; new connection managers SHOULD implement it in preference to this one.

The following well-known parameter names correspond to D-Bus properties, and thus their Conn_Mgr_Param_Flags should include DBus_Property. See that flag for more details on this kind of parameter.

A list of the extra interfaces provided by this connection manager (i.e. extra functionality that can be provided even before a connection has been created).

No interfaces suitable for listing in this property are currently defined; it's provided as a hook for possible future functionality.

To be compatible with older connection managers, if retrieving this property fails, clients SHOULD assume that its value is an empty list.

Connection managers with a non-empty list of Interfaces MUST represent them in the .manager file, if they have one, as an Interfaces key in the group headed [ConnectionManager], whose value is a list of strings each followed by a semicolon.

A D-Bus service which allows connections to be created. The manager processes are intended to be started by D-Bus service activation.

For service discovery, each Telepathy connection manager must have a connection manager name (see Connection_Manager_Name for syntax).

The connection manager must then provide a well-known bus name of org.freedesktop.Telepathy.ConnectionManager.cmname where cmname is its connection manager name. If it makes sense to start the connection manager using D-Bus service activation, it must register that well-known name for service activation by installing a .service file.

Clients can list the running connection managers by calling the ListNames method on the D-Bus daemon's org.freedesktop.DBus interface and looking for names matching the above pattern; they can list the activatable connection managers by calling ListActivatableNames, and they should usually combine the two lists to get a complete list of running or activatable connection managers.

When the connection manager is running, it must have an object implementing the ConnectionManager interface at the object path /org/freedesktop/Telepathy/ConnectionManager/cmname.

Connection managers' capabilities can be determined dynamically by calling their ListProtocols method, then for each protocol of interest, calling GetParameters to discover the required and optional parameters. However, since it is inefficient to activate all possible connection managers on the system just to find out what they can do, there is a standard mechanism to store static information about CMs in ".manager files".

To look up a connection manager's supported protocols, clients should search the data directories specified by the freedesktop.org XDG Base Directory Specification ($XDG_DATA_HOME, defaulting to $HOME/.local/share if unset, followed by colon-separated paths from $XDG_DATA_DIRS, defaulting to /usr/local/share:/usr/share if unset) for the first file named telepathy/managers/cmname.manager that can be read without error. This file has the same syntax as a freedesktop.org Desktop Entry file.

Clients must still support connection managers for which no .manager file can be found, which they can do by activating the connection manager and calling its methods; the .manager file is merely an optimization. Connection managers whose list of protocols can change at any time (for instance, via a plugin architecture) should not install a .manager file.

The .manager file SHOULD have a group headed [ConnectionManager], containing a key Interfaces representing Interfaces as a sequence of strings each followed by a semicolon (the "localestrings" type from the Desktop Entry Specification).

The [ConnectionManager] group SHOULD NOT contain keys ObjectPath or BusName. If it does, they MUST be ignored.

The object path and bus name are derivable from the connection manager's name, which is part of the filename, so these keys are redundant. They were required in very old versions of Telepathy.

For each protocol name proto that would be returned by ListProtocols, the .manager file contains a group headed [Protocol proto]. For each parameter p that would be returned by GetParameters(proto), the .manager file contains a key param-p with a value consisting of a D-Bus signature (a single complete type), optionally followed by a space and a space-separated list of flags. The supported flags are:

  • required, corresponding to Conn_Mgr_Param_Flag_Required
  • register, corresponding to Conn_Mgr_Param_Flag_Register
  • secret, corresponding to Conn_Mgr_Param_Flag_Secret
  • dbus-property, corresponding to Conn_Mgr_Param_Flag_DBus_Property

The group may also contain a key default-p whose value is a string form of the default value for the parameter. If this key exists, it sets the default, and also sets the flag Conn_Mgr_Param_Flag_Has_Default. The default value is formatted according to the D-Bus signature as follows:

s (string)
The UTF-8 string, with the standard backslash escape sequences supported by the Desktop Entry Specification (the "localestring" type from the Desktop Entry Specification)
o (object path)
The object path as an ASCII string
b (boolean)
"true" (case-insensitively) or "1" means True, "false" (case-insensitively) or "0" means False; when writing a file, "true" and "false" SHOULD be used
y, q, u, t (8-, 16-, 32-, 64-bit unsigned integer)
ASCII decimal integer
n, i, x (16-, 32-, 64-bit signed integer)
ASCII decimal integer, optionally prefixed with "-"
d (double-precision floating point)
ASCII decimal number
as (array of string), ao (array of object path)
A sequence of UTF-8 strings each followed by a semicolon, with any semicolons they contain escaped with a backslash (the "localestrings" type from the Desktop Entry Specification)

Currently, no other D-Bus signatures are allowed to have default values, but clients parsing the .manager file MUST ignore defaults that they cannot parse, and treat them as if the default-p key was not present at all.

It is not required that a connection manager be able to support multiple protocols, or even multiple connections. When a connection is made, a service name where the connection object can be found is returned. A manager which can only make one connection may then remove itself from its well-known bus name, causing a new connection manager to be activated when somebody attempts to make a new connection.

Prior to version 0.17.2, support for CMs with no .manager file was not explicitly required. Prior to version 0.17.16 the serialization of string arrays (signature 'as') was not defined Prior to version 0.25.2 the serialization of object-path arrays (signature 'ao') was not defined
telepathy-qt-0.9.6~git1/spec/Channel_Interface_Captcha_Authentication.xml0000664000175000017500000005561012470405660024445 0ustar jrjr Copyright © 2010-2012 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(version 1)

A channel interface for captcha authentication. When this interface appears on a ServerAuthentication channel, it represents authentication with the server. In future, it could also be used to authenticate with secondary services, or even to authenticate end-to-end connections with contacts. As a result, this interface does not REQUIRE ServerAuthentication to allow for a potential future Channel.Type.PeerAuthentication interface.

In any protocol that requires a captcha, the connection manager can use this channel to let a user interface carry out a simple captcha handshake with it, as a way to test the user is human interactively.

For channels managed by a ChannelDispatcher, only the channel's Handler may call the methods on this interface. Other clients MAY observe the authentication process by watching its signals and properties.

The most commonly used form of captcha challenge is OCR (recognition of distorted letters or words in an image), but for accessibility reasons, this interface also allows various other types of challenge, such as plain-text questions or recognition of words in audio. Its structure is modelled on XMPP's XEP-0158, but can be used with other protocols by mapping their semantics into those used in XMPP.

It is important to support multiple types of captcha challenge to avoid discriminating against certain users; for instance, blind or partially-sighted users cannot be expected to answer an OCR challenge.

XEP-0158 supports a superset of all other known protocols' captcha interfaces, and is sufficiently elaborate that we expect it will continue to do so.

There can only be one Handler, which is a good fit for the question/answer model implied by captchas.

A struct containing information regarding a single captcha mechanism.

The ID with which to reference this captcha method when retrieving its data and answering it. They are unique within this channel instance only.

The type of challenge as defined by XEP-0158. For instance, the commonly-used "type the letters/words you see in this image" challenge is represented by ocr

A human-readable label for the challenge, as defined in XEP-0158.

If the server does not supply a label for a challenge of type other than qa, connection managers SHOULD set Label to an empty string instead of generating their own text. If the Label is an empty string, the Handler SHOULD replace it with a generic label in the user's locale, such as the strings suggested in XEP-0158 (for instance, Enter the text you see for ocr challenges). The Handler MAY use those generic labels in any case, as per the Internationalization Considerations section of XEP-0158.

Connection managers are not usually localized, so text generated by the connection manager would be in English, regardless of the user's locale. The Handler is better-placed to generate a generic Label in the user's locale.

For challenges of type qa, the Label is a plain-text question for the user to answer. The connection manager SHOULD NOT provide an empty Label; if it does, the Handler SHOULD treat that challenge as impossible, and SHOULD NOT attempt to display it.

One flag defined: Required. Most captchas will have no flags.

A list of MIME types the server is offering to provide for this captcha method.

A mapping of captcha IDs to answer strings. The ID of the captcha to which the associated answer string is answering. The answer string to answer the captcha referenced by the associated ID.

If true, GetCaptchas can be expected to return new captcha information when in the Local_Pending state. If false, GetCaptchas will return NotAvailable on subsequent calls.

Refreshing the captcha isn't required to work, although some protocols and implementations allow it. This is usually done in case a given captcha is unintelligible.

The current status of this channel.

Because only the Handler should call methods on this interface, the Handler MAY reduce round-trips by not fetching the initial value of this property, and instead assume that is initially Local_Pending.

This assumption normally avoids the need to call GetAll(), since the values of CaptchaError and CaptchaErrorDetails are also implied by this assumption, and the only other property is CanRetryCaptcha, which is immutable.

The reason for the CaptchaStatus, or an empty string if the state is neither Try_Again nor Failed.

Typical values: "", Cancelled, AuthenticationFailed, CaptchaNotSupported

In particular, an ordinary authentication failure (as would be produced for an incorrect answer) SHOULD be represented by AuthenticationFailed, cancellation by the user's request SHOULD be represented by Cancelled, cancellation due to the inability to display the captcha to the user or otherwise answer it SHOULD be represented by CaptchaNotSupported, and cancellation by a local process due to inconsistent or invalid challenges from the server SHOULD be represented by ServiceConfused.

If this interface appears on a ServerAuthentication channel, and connection to the server fails with an authentication failure, this error code SHOULD be copied into the Connection.ConnectionError signal.

If CaptchaError is non-empty, any additional information about the last disconnection; otherwise, the empty map. The keys and values are the same as for the second argument of Connection.ConnectionError.

If this interface appears on a ServerAuthentication channel, and connection to the server fails with an authentication failure, these details SHOULD be copied into the Connection.ConnectionError signal.

Information about each of the available captcha methods. The number of captcha methods required to be answered in order to successfully complete this captcha challenge (most frequently 1, but XMPP allows servers to demand that more than one captcha is answered). The language of each Label in Captcha_Info if available, for instance en_US, or "" if unknown.

Gets information regarding each of the captcha methods available and which and how many need to be successfully answered

To call this method successfully, the state must be Local_Pending or Try_Again. If it is Local_Pending, it remains Local_Pending. If called more than once while in Local_Pending state, or if the state is Try_Again, this method fetches a new set of captcha challenges, if possible, and the state returns to Local_Pending.

For instance, you could call GetCaptchas again from Local_Pending state if the user indicates that they can't understand the initially-offered captcha.

This is a method, not a property, so that it can be used to fetch more than one set of captcha challenges, and so that change notification is not required. Only the Handler should call this method and calling GetAll would not reduce round-trips, so the usual reasons to prefer a property do not apply here.

Either the state is not Local_Pending or Try_Again, or it has already been called and CanRetryCaptcha is False.
The ID of the captcha of which to retrieve data. MIME type picked by the Handler, chosen from the list of MIME types received in GetCaptchas. XEP-0158 allows the same captcha to be made available in multiple formats, for instance the same spoken question as audio/x-wav, application/ogg and audio/speex. Captcha data as requested.

Fetch and return the captcha data. In protocols where captchas are downloaded out-of-band (for instance via HTTP), the connection manager is expected to do so.

Returns an empty array if the type was "qa"

If audio-based and image-based captchas are both available, we don't want to waste time downloading the audio until/unless the user asks to hear it. The extra D-Bus round-trips are not a problem, since they are expected to be quick compared with the time taken for the user to solve the captcha.

The state is not in Local_Pending or GetCaptchas had never been called.
The mapping of captcha IDs to answer strings.

Answer as many captchas as desired and/or required.

Callable in state Local_Pending only. State changes to Remote_Pending.

The state is not in Local_Pending.
Reason for cancelling. This MAY be used to choose an error response to the remote server, and SHOULD also be reflected in the CaptchaError. A textual description of the reason for cancelling, supplied by the Handler. This message SHOULD NOT be sent to the remote server, but SHOULD be copied into the 'debug-message' field of the CaptchaErrorDetails and ConnectionError.

Cancel. State changes to Failed with error NotAvailable or Cancelled if it isn't already Failed. All you can do now is to close the channel.

The current state is Failed.

Extra flags to include with Captcha information

This captcha mechanism is required to be successfully answered in order to pass this captcha challenge.

A reason why captcha authentication was aborted by the client.

The user aborted the authentication. If this is used, the CaptchaError SHOULD be set to Cancelled The Handler doesn't support the given/required captcha types. If this is used, the CaptchaError SHOULD be set to CaptchaNotSupported. This SHOULD also be used if Close is called before CancelCaptcha. If no Handler supports captcha channels, the ChannelDispatcher will just call Close, because it has no knowledge of specific channel types. The Handler doesn't understand the captcha data received. The challenger may be sending gibberish. If this is used, the CaptchaError SHOULD be set to ServiceConfused.
The challenge/response exchange is in progress and waiting for a local action. Call AnswerCaptchas to go to the Remote_Pending state, or call CancelCaptcha followed by Close to give up. The challenge/response exchange is in progress and waiting for a response from the server. Wait for a reply from the server, which will result in the Succeeded, Try_Again, or Failed state, or call CancelCaptcha followed by Close to give up. Everyone is happy. Connection to the server will proceed as soon as this state is reached. There is nothing useful to do in this state except to call Close to close the channel. The server has indicated an authentication failure. Call GetCaptchas again to get a new captcha, or CancelCaptcha followed by Close to give up. Authentication has failed in some way. There is nothing useful to do in this state except to close the channel with Close.
telepathy-qt-0.9.6~git1/spec/Channel_Interface_Messages.xml0000664000175000017500000020462012470405660021607 0ustar jrjr Copyright © 2008–2010 Collabora Ltd. Copyright © 2008–2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

This interface extends the Text interface to support more general messages, including:

  • messages with attachments (like MIME multipart/mixed)
  • groups of alternatives (like MIME multipart/alternative)
  • delivery reports (which replace Text.SendError), addding support for protocols where the message content is not echoed back to the sender on failure and for receiving positive acknowledgements, as well as ensuring that incoming delivery reports are not lost if no client is handling the channel yet;
  • any extra types of message we need in future

Incoming messages, outgoing messages, and delivery reports are all represented as lists of Message_Part structures, with a format reminiscent of e-mail. Messages are sent by calling SendMessage; outgoing messages are announced to other clients which may be interested in the channel by the MessageSent signal. Incoming messages and delivery reports are signalled by MessageReceived, and are stored in the the PendingMessages property until acknowledged by calling Text.AcknowledgePendingMessages. Only the Handler for a channel should acknowledge messages; Observers (such as loggers) and Approvers for the channel may listen for incoming messages, and send messages of their own, but SHOULD NOT acknowledge messages.

If observers were allowed to acknowledge messages, then messages might have been acknowledged before the handler even got to see the channel, and hence could not be shown to the user.

If this interface is present, clients that support it SHOULD listen for the MessageSent and MessageReceived signals, and ignore the Sent, SendError and Received signals on the Text interface (which are guaranteed to duplicate signals from this interface).

Although this specification supports formatted (rich-text) messages with unformatted alternatives, implementations SHOULD NOT attempt to send formatted messages until the Telepathy specification has also been extended to cover capability discovery for message formatting.

We intend to expose all rich-text messages as XHTML-IM, but on some protocols, formatting is an extremely limited subset of that format (e.g. there are protocols where foreground/background colours, font and size can be set, but only for entire messages). Until we can tell UIs what controls to offer to the user, it's unfriendly to offer the user controls that may have no effect.

A list of MIME types supported by this channel, with more preferred MIME types appearing earlier in the list. The list MAY include "*/*" to indicate that attachments with arbitrary MIME types can be sent. This list MUST NOT be empty, since all Messages implementations MUST accept messages containing a single "text/plain" part.

Items in this list MUST be normalized to lower-case.

Some examples of how this property interacts with the MessagePartSupportFlags:

A simple IM implementation: only plain text messages are allowed
SupportedContentTypes = ['text/plain'], MessagePartSupportFlags = 0
Formatted text with a plain text alternative is allowed (see the HTML interface draft)
SupportedContentTypes = ['text/html', 'text/plain'], MessagePartSupportFlags = 0
JPEG or PNG images may be sent, but without any attached text
SupportedContentTypes = ['text/plain', 'image/jpeg', 'image/png'], MessagePartSupportFlags = 0
Unformatted text to which an optional JPEG or PNG image may be attached
SupportedContentTypes = ['text/plain', 'image/jpeg', 'image/png'], MessagePartSupportFlags = One_Attachment
Formatted text to which arbitrarily many images may be attached
SupportedContentTypes = ['text/html', 'text/plain', 'image/jpeg', 'image/png', 'image/x-ms-bmp'], MessagePartSupportFlags = One_Attachment | Multiple_Attachments
A full SIP implementation: arbitrary MIME messages are allowed
SupportedContentTypes = ['*/*'], MessagePartSupportFlags = One_Attachment | Multiple_Attachments
This supersedes GetMessageTypes; fall back to that method for compatibility with older connection managers.

A list of message types which may be sent on this channel.

Flags indicating the level of support for message parts on this channel.

Flags indicating the level of support for message parts on this channel. They are designed such that setting more flags always implies that the channel has more capabilities.

If no flags are set, this indicates that messages may contain a single message part whose content-type is any of the types from SupportedContentTypes, possibly with some alternatives.

There is no flag indicating support for alternatives. This is because the SendMessage implementation can always accept messages containing alternatives, even if the underlying protocol does not, by deleting all alternatives except the first (most preferred) that is supported.

Each of the flags so far implies the previous flag, so we could have used a simple enumeration here; however, we've defined the message-part support indicator as a flag set for future expansion.

See SupportedContentTypes for some examples.

SendMessage will accept messages containing a textual message body, plus a single attachment of any type listed in the SupportedContentTypes property. It does not make sense for this flag to be set if Message_Part_Support_Flag_Data_Only is not also set (because the connection manager can trivially provide an empty text part if necessary). SendMessage will accept messages containing a textual message body, plus an arbitrary number of attachments of any type listed in the SupportedContentTypes property. It does not make sense for this flag to be set if Message_Part_Support_Flag_One_Attachment is not also set.

Part of a message's content. In practice, this mapping never appears in isolation: incoming messages are represented by a list of Message_Part mappings in the MessageReceived signal, and outgoing messages are passed to SendMessage as a list of these mappings.

The first part of the message contains "headers", which refer to the entire message. The second and subsequent parts contain the message's content, including plain text, formatted text and/or attached files. Well-known keys for the header and body parts are defined by the Message_Header_Key and Message_Body_Key types, respectively. It is an error for a connection manager to put keys referring to the message as a whole in the second or subsequent Message_Part, or keys intended for body parts in the first Message_Part; clients MUST recover from this error by ignoring these mis-placed keys.

Instead of representing messages as aa{sv} where the first dictionary is special (a dictionary of headers), we could have used a signature like (a{sv}aa{sv}) to separate out the headers and the body parts.

However, this would make access to the messages more awkward. In Python, the syntax for access to a header field would remain message[0]['message-type'], but access to a body field in the second body part would change from message[2]['content'] to message[1][1]['content']. In GLib, the message would change from being a GPtrArray(GHashTable) to being a GValueArray(GHashTable, GPtrArray(GHashTable)) which is rather inconvenient to dereference.

In any group of parts with the same non-empty value for the alternative key (which represent alternative versions of the same content), more faithful versions of the intended message MUST come before less faithful versions (note that this order is the opposite of MIME multipart/alternative parts). Clients SHOULD display the first alternative that they understand.

Specifying the preference order means that if the underlying protocol doesn't support alternatives, the CM can safely delete everything apart from the first supported alternative when sending messages.

The order is the reverse of MIME because MIME's rationale for placing the "plainest" part first (legibility in pre-MIME UAs) does not apply to us, and placing the most preferred part first simplifies display (a client can iterate the message in order, display the first alternative that it understands, and skip displaying all subsequent parts with the same "alternative" key).

Clients SHOULD present all parts that are not redundant alternatives in the order they appear in this array, possibly excluding parts that are referenced by another displayed part. It is implementation-specific how the parts are presented to the user.

This allows CMs to assume that all parts are actually shown to the user, even if they are not explicitly referenced - we do not yet recommend formatted text, and there is no way for plain text to reference an attachment since it has no concept of markup or references. This also forces clients to do something sensible with messages that consist entirely of "attachments", with no "body" at all.

For instance, when displaying the above example, a client that understands the HTML part should display the JPEG image once, between the two lines "Here is a photo of my cat:" and "Isn't it cute?"; it may additionally present the image in some way for a second time, after "Isn't it cute?", or may choose not to.

A client that does not understand HTML, displaying the same message, should display the plain-text part, followed by the JPEG image.

Connection managers, clients and extensions to this specification SHOULD NOT include Handles as values in a Message_Part, except for message-sender in the header.

Reference-counting handles in clients becomes problematic if the channel proxy cannot know whether particular map values are handles or not.

Example messages

A rich-text message, with an embedded image, might be represented as:

[
  {
    'message-token': '9de9546a-3400-4419-a505-3ea270cb834c',
    'message-sender': 42,
    'message-sent': 1210067943,
    'message-received': 1210067947,
    'message-type': 0,              # = Channel_Text_Message_Type_Normal
    'pending-message-id': 437,
  },
  { 'alternative': 'main',
    'content-type': 'text/html',
    'content': 'Here is a photo of my cat:<br />' +
               '<img src="cid:catphoto" alt="lol!" />' +
               '<br />Isn't it cute?',
  },
  { 'alternative': 'main',
    'content-type': 'text/plain',
    'content': 'Here is a photo of my cat:\n[IMG: lol!]\nIsn't it cute?',
  },
  { 'identifier': 'catphoto',
    'content-type': 'image/jpeg',
    'size': 101000,
    'needs-retrieval': True,
  },
]

telepathy-ring, Nokia's GSM connection manager, represents vCards sent via SMS as:

[
  {
    'message-token': '9de9546a-3400-4419-a505-3ea270cb834c',
    'message-sender': 42,
    'message-sent': 1210067943,
    'message-received': 1210067947,
    'message-type': 0,              # = Channel_Text_Message_Type_Normal
    'pending-message-id': 437,
  },
  { 'content-type': 'text/x-vcard',
    'content': [ 0x66, 0x69, 0x71, ...], # vCard data as an array of bytes
  },
]

Delivery reports

Delivery reports are also represented as messages with the message-type header mapping to Channel_Text_Message_Type Delivery_Report. Delivery reports SHOULD contain the message-sender header, mapping to the intended recipient of the original message, if possible; other headers specific to delivery reports are defined by the Delivery_Report_Header_Key type. The second and subsequent parts, if present, are a human-readable report from the IM service.

For backwards- and forwards-compatibility, whenever a delivery error report is signalled—that is, with delivery-status mapping to Delivery_Status Temporarily_Failed or Permanently_Failed—SendError SHOULD also be emitted; whenever SendError is emitted, a delivery report MUST also be signalled. Delivery report messages on this interface MUST be represented in emissions of Received as messages with the Non_Text_Content Channel_Text_Message_Flags; clients which understand this interface SHOULD ignore the SendError signal in favour of listening for delivery reports, as mentioned in the introduction.

The result of attempting to send delivery reports using SendMessage is currently undefined.

Example delivery reports

A minimal delivery report indicating permanent failure of the sent message whose token was b9a991bd-8845-4d7f-a704-215186f43bb4 for an unknown reason
[{
# header
'message-sender': 123,
'message-type': Channel_Text_Message_Type_Delivery_Report,
'delivery-status': Delivery_Status_Permanently_Failed,
'delivery-token': 'b9a991bd-8845-4d7f-a704-215186f43bb4',
}
# no body
]
A delivery report where the failed message is echoed back to the sender rather than being referenced by ID, and the failure reason is that this protocol cannot send messages to offline contacts such as the contact with handle 123
[{ # header
'message-sender': 123,
'message-type': Channel_Text_Message_Type_Delivery_Report,
'delivery-status': Delivery_Status_Temporarily_Failed,
'delivery-error': Channel_Text_Send_Error_Offline,
'delivery-echo':
    [{ # header of original message
    'message-sender': 1,
    'message-sent': 1210067943,
    },
    { # body of original message
    'content-type': 'text/plain',
    'content': 'Hello, world!',
    }]
  ],

# no body
]
A maximally complex delivery report: the server reports a bilingual human-readable failure message because the user sent a message "Hello, world!" with token b9a991bd-8845-4d7f-a704-215186f43bb4 to a contact with handle 123, but that handle represents a contact who does not actually exist
[{ # header
'message-sender': 123,
'message-type': Channel_Text_Message_Type_Delivery_Report,
'delivery-status': Delivery_Status_Permanently_Failed,
'delivery-error': Channel_Text_Send_Error_Invalid_Contact,
'delivery-token': 'b9a991bd-8845-4d7f-a704-215186f43bb4',
'delivery-echo':
    [{ # header of original message
    'message-sender': 1,
    'message-sent': 1210067943,
    },
    { # body of original message
    'content-type': 'text/plain',
    'content': 'Hello, world!',
    }]
  ],
},
{ # message from server (alternative in English)
'alternative': '404',
'content-type': 'text/plain',
'lang': 'en',
'content': 'I have no contact with that name',
},
{ # message from server (alternative in German)
'alternative': '404'.
'content-type': 'text/plain',
'lang': 'de',
'content', 'Ich habe keinen Kontakt mit diesem Namen',
}
]
A minimal delivery report indicating successful delivery of the sent message whose token was b9a991bd-8845-4d7f-a704-215186f43bb4
[{
# header
'message-sender': 123,
'message-type': Channel_Text_Message_Type_Delivery_Report,
'delivery-status': Delivery_Status_Delivered,
'delivery-token': 'b9a991bd-8845-4d7f-a704-215186f43bb4',
}
# no body
]
A key, which SHOULD be one of the well-known keys specified by Message_Header_Key, Message_Body_Key or Delivery_Report_Header_Key if possible. The value corresponding to the given key, which SHOULD be one of the specified types for well-known keys.
Removed protocol-token—which had never been implemented—and respecified message-token not to have unimplementable uniqueness guarantees.

Well-known keys for the first Message_Part of a message, which contains metadata about the message as a whole, along with the corresponding value types. Some keys make sense for both incoming and outgoing messages, while others are only meaningful for one or the other.

message-token (s - Protocol_Message_Token)

An opaque identifier for the message, as used by the underlying protocol. For outgoing messages, this SHOULD be globally unique; for incoming messages, this is not guaranteed to uniquely identify a message, even within the scope of a single channel or contact; the only guarantee made is that two messages with different message-token headers are different messages.

Clients wishing to determine whether a new message with the scrollback header matches a previously-logged message with the same message-token SHOULD compare the message's sender, contents, message-sent or message-received timestamp, etc. Note that, in XMPP, the server only supplies a timestamp for scrollback messages, not for messages received while you are in a room; thus, non-scrollback messages will lack a message-sent timestamp.

In practice, most protocols do not provide globally-unique identifiers for messages. Connection managers, being stateless, do not have the necessary information — namely, IM logs — to generate reliable unique tokens for messages.

For instance, some XMPP clients (including Gabble) stamp messages they send with unique identifiers, but others number outgoing messages in a conversation from 1 upwards.

message-sent (x - Unix_Timestamp64)
The time the message was sent (if unavailable, the time it arrived at a central server MAY be used). Omitted if no reasonable approximation is available; SHOULD always be present on outgoing messages.
message-received (x - Unix_Timestamp64)
The time the message was received locally. SHOULD always be present.
message-sender (u - Contact_Handle)
The contact who sent the message. If 0 or omitted, the contact who sent the message could not be determined.
message-sender-id (s)
The identifier of the contact who sent the message, i.e. the result of calling InspectHandles on message-sender. If omitted, clients MUST fall back to looking at message-sender.
sender-nickname (s)
The nickname chosen by the sender of the message, which can be different for each message in a conversation.
message-type (u - Channel_Text_Message_Type)
The type of message; if omitted, Channel_Text_Message_Type_Normal MUST be assumed. MAY be omitted for normal chat messages.
supersedes (s – Protocol_Message_Token)
If present, this message supersedes a previous message, identified by its message-token header. The user interface MAY, for example, choose to replace the superseded message with this message, or grey out the superseded message. Skype, for example, allows the user to amend messages they have already sent (to correct typos, etc.). Connection Managers SHOULD represent repeatedly edited messages in the following form:
                message {token = a};
                message {token = b, supersedes = a};
                message {token = c, supersedes = a};
              
The alternative form is:
                  message {token = a};
                  message {token = b, supersedes = a};
                  message {token = c, supersedes = b};
                
but it is more difficult to implement in UIs/loggers, and it breaks irrecoverably if message b is lost. If a CM is forced to use this form, it should be tested extensively for interoperability with existing clients.
Clients should deal gracefully if the original message gets lost, but one or more corrections to it get through:
                message {token = x} gets lost;
                message {token = y, supersedes = x};
                message {token = z, supersedes = x};
              
This is the form that CMs will use to mean "I know that this message was edited, but I don't know what it originally said." It is often in the interests of the remote side for message x to be lost (e.g. to hide embarassing mistakes or sensitive information) so it might not be possible to retrieve it (even on protocols with reliable message-delivery guarantees).
original-message-sent (x - Unix_Timestamp64)
The message-sent header of the message that this one supersedes. This key should only be present if supersedes is also present. It MAY be used as a hint to help clients locate the original message in its logs. If present, comparing the tuple (original-message-sent, supersedes) with (message-sent, message-token) SHOULD be enough to uniquely identify the original message.
original-message-received (x - Unix_Timestamp64)
The message-received header of the message that this one supersedes. This key should only be present if supersedes is also present. It MAY be used as a hint in a similar way to original-message-sent.
pending-message-id (u - Message_ID)
The incoming message ID. This MUST NOT be present on outgoing messages. Clients SHOULD NOT store this key - it is only valid for as long as the message remains unacknowledged.
interface (s - DBus_Interface)
This message is specific to the given interface, which is neither Text nor Messages. It SHOULD be ignored if that interface is not supported. (Note that an 'interface' key can also appear on the second and subsequent parts, where it indicates that that part (only) should be ignored if unsupported.)
scrollback (b)
If present and true, the incoming message was part of a replay of message history (this matches the Scrollback flag in Channel_Text_Message_Flags). This flag does not make sense on outgoing messages and SHOULD NOT appear there.
rescued (b)
If present and true, the incoming message has been seen in a previous channel during the lifetime of the Connection, but had not been acknowledged when that channel closed, causing an identical channel (in which the message now appears) to open. This matches the Rescued flag in Channel_Text_Message_Flags; it does not make sense on outgoing messages, and SHOULD NOT appear there.

Well-known keys for the second and subsequent Message_Parts of a message, which contain the message content, along with the corresponding value types.

identifier (s — Protocol_Content_Identifier)
An opaque identifier for this part. Parts of a message MAY reference other parts by treating this identifier as if it were a MIME Content-ID and using the cid: URI scheme.
alternative (s)

If present, this part of the message is an alternative for all other parts with the same value for "alternative". Clients SHOULD only display one of them (this is expected to be used for XHTML messages in a future version of this specification).

If omitted, this part is not an alternative for any other part.

Parts of a message MAY reference the group of alternatives as a whole (i.e. a reference to whichever of them is chosen) by treating this identifier as if it were the MIME Content-ID of a multipart/alternative part, and using the cid: URI scheme.

content-type (s)

The MIME type of this part. See the documentation for MessageReceived and MessageSent for notes on the special status of "text/plain" parts.

Connection managers MUST NOT signal parts without a 'content-type' key; if a protocol provides no way to determine the MIME type, the connection manager is responsible for guessing it, but MAY fall back to "text/plain" for text and "application/octet-stream" for non-text.

Clients MUST ignore parts without a 'content-type' key, which are reserved for future expansion.

When sending messages, clients SHOULD normalize the content-type to lower case, but connection managers SHOULD NOT rely on this. When signalling sent or received messages, connection managers MUST normalize the content-type to lower case.

lang (s)
The natural language of this part, identified by a RFC 3066 language tag. XMPP allows alternative-selection by language as well as by content-type.
size (u)
The size in bytes (if needs-retrieval is true, this MAY be an estimated or approximate size). SHOULD be omitted if 'content' is provided. There's no point in providing the size if you're already providing all the content.
thumbnail (b)

This part is a thumbnail. To represent an image together with its thumbnail in a single message, there should be one part for the full image followed by a part for the thumbnail (following the “more complete versions first” requirement), with the same 'alternative' value. For example:

[ ... ,
  { 'alternative': 'catphoto',
    'content-type': 'image/jpeg',
    'size': 150000,
    'content': [0xFF, 0xD8, ... 0xFF 0xD9],
  },
  { 'alternative': 'catphoto',
    'content-type': 'image/jpeg'
    'size': 1024,
    'thumbnail': True,
    'content': [0xFF, 0xD8, ... 0xFF 0xD9],
  },
  ...
]
needs-retrieval (b)
If false or omitted, the connection manager already holds this part in memory. If present and true, this part must be retrieved on demand (like MIME's message/external-body) by a mechanism to be defined later. The mechanism was meant to be GetPendingMessageContent, but that didn't work out. It's worth leaving the header in in preparation for a future mechanism.
truncated (b)
The content available via the 'content' key has been truncated by the server or connection manager (equivalent to Channel_Text_Message_Flag_Truncated in the Text interface).
content (s or ay)
The part's content, if it is available and sufficiently small to include here (implies that 'needs-retrieval' is false or omitted). Otherwise, omitted. If the part is human-readable text or HTML, the value for this key MUST be a UTF-8 string (D-Bus signature 's'). If the part is not text, the value MUST be a byte-array (D-Bus signature 'ay'). If the part is a text-based format that is not the main body of the message (e.g. an iCalendar or an attached XML document), the value SHOULD be a UTF-8 string, transcoding from another charset to UTF-8 if necessary, but MAY be a byte-array (of unspecified character set) if transcoding fails or the source charset is not known.
interface (s - DBus_Interface)
This part is specific to the given interface, which is neither Text nor Messages. It SHOULD be ignored if that interface is not supported. (Note that an 'interface' key can also appear on the first part, where it indicates that the entire message should be ignored if unsupported.)

Well-known keys for the first Message_Part of a delivery report, along with the corresponding value types. Some of these are special-cases of headers defined by Message_Header_Key.

message-sender (u - Contact_Handle, as defined by Message_Header_Key)
MUST be the intended recipient of the original message, if available (zero or omitted if the intended recipient is unavailable or is not a contact, e.g. a chatroom), even if the delivery report actually came from an intermediate server.
message-type (u - Channel_Text_Message_Type, as defined by Message_Header_Key)
MUST be Channel_Text_Message_Type_Delivery_Report.
delivery-status (u - Delivery_Status)
The status of the message. All delivery reports MUST contain this key in the first Message_Part.
delivery-token (s - Protocol_Message_Token)

An identifier for the message to which this delivery report refers. MUST NOT be an empty string. Omitted if not available.

Clients may match this against the token produced by the SendMessage method and MessageSent signal. A status report with no token could match any sent message, and a sent message with an empty token could match any status report. If multiple sent messages match, clients SHOULD use some reasonable heuristic.

In an ideal world, we could unambiguously match reports against messages; however, deployed protocols are not ideal, and not all reports and messages can be matched.
delivery-error (u - Channel_Text_Send_Error)
The reason for the failure. MUST be omitted if this was a successful delivery; SHOULD be omitted if it would be Channel_Text_Send_Error_Unknown.
delivery-dbus-error (s - DBus_Error_Name)
The reason for the failure, specified as a (possibly implementation-specific) D-Bus error. MUST be omitted if this was a successful delivery. If set, the 'delivery-error' key SHOULD be set to the closest available value.
delivery-error-message (s)
Debugging information on why the message could not be delivered. MUST be omitted if this was a successful delivery; MAY always be omitted.
delivery-echo (aa{sv} - Message_Part[])

The message content, as defined by the Messages interface. Omitted if no content is available. Content MAY have been truncated, message parts MAY have been removed, and message parts MAY have had their content removed (i.e. the message part metadata is present, but the 'content' key is not).

Some protocols, like XMPP, echo the failing message back to the sender. This is sometimes the only way to match it against the sent message, so we include it here.
This type is only used by GetPendingMessageContent, which is unimplemented and deprecated. The index of a message part within a message. This structure is only used by GetPendingMessageContent, which is unimplemented and deprecated. A mapping from message part indexes to their content, as returned by GetPendingMessageContent. Indexes into the array of Message_Parts that represents a message. The "headers" part (which is not a valid argument to GetPendingMessageContent) is considered to be part 0, so the valid part numbers start at 1 (for the second message part). The message part's content. The variant MUST contain either type 's' or 'ay' (UTF-8 text string, or byte array), following the same rules as for the value of the 'content' key in the Message_Part mappings.

An opaque token used to identify messages in the underlying. protocol. As a special case, the empty string indicates that there is no particular identification for a message.

CM implementations SHOULD use an identifier expected to be unique, such as a UUID, for outgoing messages (if possible).

Some protocols can only track a limited number of messages in a small message-ID space (SMS messages are identified by a single byte), and some implementations send non-unique identifiers (some XMPP clients use very simple message IDs, such as an incrementing integer that resets to 1 at the beginning of each connection). As a result, clients MUST NOT assume that protocol tokens will not be re-used.

In particular, clients SHOULD use a heuristic to assign delivery reports to messages, such as matching on message content or timestamp (if available), or assuming that the delivery report refers to the most recent message with that ID.

A protocol-specific identifier for a blob of content, as used for the identifier key in a Message_Part. The same identifier MAY be re-used if the same content, byte-for-byte, appears as a part of several messages.

On XMPP, these identifiers might be Content-IDs for custom smileys implemented using XEP-0232 Bits of Binary; the same smiley might well appear in multiple messages.

Submit a message to the server for sending. If this method returns successfully, the message has been submitted to the server and the MessageSent signal is emitted. A corresponding Sent signal on the Text interface MUST also be emitted.

This method MUST return before the MessageSent signal is emitted.

This means that the process sending the message is the first to see the Protocol_Message_Token, and can relate the message to the corresponding MessageSent signal by comparing message tokens (if supported by the protocol).

If this method fails, message submission to the server has failed and no signal on this interface (or the Text interface) is emitted.

If this method succeeds, message submission to the server has succeeded, but the message has not necessarily reached its intended recipient. If a delivery failure is detected later, this is signalled by receiving a message whose message-type header maps to Delivery_Report. Similarly, if delivery is detected to have been successful (which is not possible in all protocols), a successful delivery report will be signalled.

The message content, including any attachments or alternatives. This MUST NOT include the following headers, or any others that do not make sense for a client to specify: message-sender, message-sender-id, message-sent, message-received, pending-message-id. Flags affecting how the message is sent. The channel MAY ignore some or all flags, depending on DeliveryReportingSupport; the flags that were handled by the CM are provided in MessageSent. An opaque token used to match any incoming delivery or failure reports against this message, or an empty string if the message is not readily identifiable. The requested message is malformed and cannot be sent.
Flags altering the way a message is sent. The "most usual" action should always be to have these flags unset. Some indication of which flags are supported is provided by the DeliveryReportingSupport property.

Provide a successful delivery report if possible, even if this is not the default for this protocol. Ignored if delivery reports are not possible on this protocol.

In some protocols, like XMPP, it is not conventional to request or send positive delivery notifications.

Delivery failure reports SHOULD always be sent, but if this flag is present, the connection manager MAY also try harder to obtain failed delivery reports or allow them to be matched to outgoing messages.

Provide a delivery report when the message is read by the recipient, even if this is not the default for this protocol. Ignored if read reports are not possible on this protocol.

Provide a delivery report when the message is deleted by the recipient, even if this is not the default for this protocol. Ignored if such reports are not possible on this protocol.

Signals that a message has been submitted for sending. This MUST be emitted exactly once per emission of the Sent signal on the Text interface, for backwards-compatibility; clients SHOULD ignore the latter if this interface is present, as mentioned in the introduction.

This SHOULD be emitted as soon as the CM determines it's theoretically possible to send the message (e.g. the parameters are supported and correct).

This signal allows a process that is not the caller of SendMessage to log sent messages.

The message content (see Message_Part for full details). If the message that was passed to SendMessage has a formatted text part that the connection manager recognises, but no text/plain alternative, the CM MUST use the formatted text part to generate a text/plain alternative which is also included in this signal argument.

The connection manager SHOULD include the message-sender, message-sender-id and message-sent headers in the representation of the message that is signalled here. If the channel has channel-specific handles, the message-sender and message-sender-id SHOULD reflect the sender that other contacts will see.

If the connection manager can predict that the message will be altered during transmission, this argument SHOULD reflect what other contacts will receive, rather than being a copy of the argument to SendMessage (if the message is truncated, formatting or alternatives are dropped, etc., then the edited version SHOULD appear in this signal).

Flags affecting how the message was sent. The flags might be a subset of those passed to SendMessage if the caller requested unsupported flags.

An opaque token used to match any incoming delivery or failure reports against this message, or an empty string if the message is not readily identifiable.

A list of incoming messages that have neither been acknowledged nor rejected. This list is a more detailed version of the one returned by Text.ListPendingMessages, and contains the same messages, uniquely identified by the same pending message IDs. Its items can be removed using Text.AcknowledgePendingMessages.

Change notification is via MessageReceived and PendingMessagesRemoved.

The messages with the given IDs have been removed from the PendingMessages list. Clients SHOULD NOT attempt to acknowledge those messages. This completes change notification for the PendingMessages property (previously, there was change notification when pending messages were added, but not when they were removed). The messages that have been removed from the pending message list. This method has never been implemented, and in any case would have been impossible to use correctly when multiple clients (such as a logger and the handler) are interested in a text channel. See freedesktop.org bug #26417 for more details. Retrieve the content of one or more parts of a pending message. Note that this function may take a considerable amount of time to return if the part's 'needs-retrieval' flag is true; consider extending the default D-Bus method call timeout. Additional API is likely to be added in future, to stream large message parts. The ID of a pending message The desired entries in the array of message parts, identified by their position. The "headers" part (which is not a valid argument to this method) is considered to be part 0, so the valid part numbers start at 1 (for the second Message_Part).

The content of the requested parts. The keys in this mapping are positions in the array of message parts; the values are either of type 's' or 'ay' (UTF-8 text string, or byte array), following the same rules as for the value of the 'content' key in the Message_Part mappings.

If the one of the requested part numbers was greater than zero but referred to a part that had no content (i.e. it had no 'content-type' key or no 'content' key), it is simply omitted from this mapping; this is not considered to be an error condition.

Either there is no pending message with the given message ID, or one of the part numbers given was 0 or too large.
Signals that a message has been received and added to the pending messages queue. This MUST be emitted exactly once per emission of the Received signal on the Text interface, for backwards-compatibility; clients SHOULD ignore the latter in favour of this signal if this interface is present, as mentioned in the introduction.

The message content, including any attachments or alternatives. If the incoming message contains formatted text without a plain text alternative, the connection manager MUST generate a text/plain alternative from the formatted text, and include it in this message (both here, and in the PendingMessages property).

The status of a message as indicated by a delivery report.

If this enum is extended in future specifications, this should only be to add new, non-overlapping conditions (i.e. all failures should still be signalled as either Temporarily_Failed or Permanently_Failed). If additional detail is required (e.g. distinguishing between the various types of permanent failure) this will be done using additional Delivery_Report_Header_Keys.

The message's disposition is unknown. Clients SHOULD consider all messages to have status Delivery_Status_Unknown unless otherwise specified; connection managers SHOULD NOT signal this delivery status explicitly. The message has been delivered to the intended recipient. Delivery of the message has failed. Clients SHOULD notify the user, but MAY automatically try sending another copy of the message. Similar to errors with type="wait" in XMPP; analogous to 4xx errors in SMTP. Delivery of the message has failed. Clients SHOULD NOT try again unless by specific user action. If the user does not modify the message or alter configuration before re-sending, this error is likely to happen again. Similar to errors with type="cancel", type="modify" or type="auth" in XMPP; analogous to 5xx errors in SMTP. An intermediate server has accepted the message but the message has not been yet delivered to the ultimate recipient. The connection manager might send a Failed report or Delivered report later. Similar to "202 Accepted" success code in SIP; analogous to 251 and 252 responses in SMTP. The message has been read by the intended recipient. The message has been deleted by the intended recipient. This MAY be signalled on its own if the message is deleted without being read, or after Read if the message was read before being deleted.
Flags indicating the level of support for delivery reporting on this channel, as found on the DeliveryReportingSupport property. Any future flags added to this set will conform to the convention that the presence of an extra flag implies that more operations will succeed. Note that CMs may always provide more reports than are requested in the Message_Sending_Flags passed to SendMessage. If senders want delivery reports, they should ask for them. If they don't want delivery reports, they can just ignore them, so there's no need to have capability discovery for what will happen if a delivery report isn't requested. Clients MAY expect to receive negative delivery reports if Message_Sending_Flag_Report_Delivery is specified when sending. Clients MAY expect to receive positive delivery reports if Message_Sending_Flag_Report_Delivery is specified when sending. Clients MAY expect to receive Delivery_Status Read reports if Message_Sending_Flag_Report_Read is specified when sending. Clients MAY expect to receive Delivery_Status Deleted reports if Message_Sending_Flag_Report_Deleted is specified when sending. A bitfield indicating features supported by this channel.
telepathy-qt-0.9.6~git1/spec/Connection_Manager_Interface_Account_Storage.xml0000664000175000017500000001115212470405660025275 0ustar jrjr Copyright © 2011 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft 1)

An interface for connection managers that store account details internally. At the moment this consists only of storing an account's credentials, but other functionality may be added in the future.

Account objects representing accounts on a connection manager that implements this interface should implement the ExternalPasswordStorage.DRAFT interface.

A set of flags representing the status of the Account stored in the Connection Manager. The associated account has its authentication credentials (password) stored in the connection manager A mapping from Account_Ids to account flags.

The set of Accounts stored in this Connection Manager, and flags indicating their status.

Change notification for this property is provided by the standard D-Bus PropertiesChanged signal.

Clears any saved credentials associated with the specified Account_Id. Any other saved data related to the account will be unaffected. An account id as returned from Protocol.IdentifyAccount. The account id is invalid. Completely removes all data associated with an account from the connection manager's internal storage. An account id as returned from Protocol.IdentifyAccount. The account id is invalid.
telepathy-qt-0.9.6~git1/spec/Channel_Interface_Destroyable.xml0000664000175000017500000000742512470405660022321 0ustar jrjr Copyright (C) 2008 Collabora Ltd. Copyright (C) 2008 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

This interface exists to support channels where Channel.Close is insufficiently destructive. At the moment this means Channel.Type.Text, but the existence of this interface means that unsupported channels can be terminated in a non-channel-type-specific way.

Close the channel abruptly, possibly with loss of data. The connection manager MUST NOT re-create the channel unless/until more events occur.

The main motivating situation for this method is that when a Text channel with pending messages is closed with Close, it comes back as an incoming channel (to avoid a race between Close and an incoming message). If Destroy is called on a Text channel, the CM should delete all pending messages and close the channel, and the channel shouldn't be re-created until/unless another message arrives.

Most clients SHOULD call Channel.Close instead. However, if a client explicitly intends to destroy the channel with possible loss of data, it SHOULD call this method if this interface is supported (according to the Channel.Interfaces property), falling back to Close if not.

In particular, channel dispatchers SHOULD use this method if available when terminating channels that cannot be handled correctly (for instance, if no handler has been installed for a channel type, or if the handler crashes repeatedly).

Connection managers do not need to implement this interface on channels where Close and Destroy would be equivalent.

Callers need to be able to fall back to Close in any case.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Location.xml0000664000175000017500000004750112470405660022342 0ustar jrjr Copyright (C) 2008 Collabora Ltd. Copyright (C) 2008 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface on connections to support protocols which allow users to publish their current geographical location, and subscribe to the current location of their contacts.

This interface is geared strongly towards automatic propagation and use of this information, so focuses on latitude, longitude and altitude which can be determined by GPS, although provision is also included for an optional human-readable description of locations. All co-ordinate information is required to be relative to the WGS84 datum.

The information published through this interface is intended to have the same scope as presence information, so will normally be made available to those individuals on the user's "publish" contact list. Even so, user interfaces should not automatically publish location information without the consent of the user, and it is recommended that an option is made available to reduce the accuracy of the reported information to allow the user to maintain their privacy.

Location information is represented using the terminology of XMPP's XEP-0080 or the XEP-0080-derived Geoclue API where possible.

Clients of this interface SHOULD register an interest in it by calling Connection.AddClientInterest with an argument containing the name of this interface, before calling any Location method. If they do so, they SHOULD also call Connection.RemoveClientInterest after use to allow the CM to release resources associated with this interface.

A user's location, represented as an extensible mapping.

Civic addresses are represented by the following well-known keys (all of which have string values), which should be kept in sync with those used in XEP-0080 and in the Geoclue project:

  • countrycode - s: an ISO-3166-1 alpha-2 (two-letter) country code, e.g. "us", "gb", "fr"
  • country - s: a country name in unspecified locale, e.g. "USA"
  • region - s: an administrative region of the nation, such as a state or province
  • locality - s: a locality within the administrative region, such as a town or city
  • area - s: a named area such as a campus or neighborhood
  • postalcode - s: a code used for postal delivery
  • street - s: a thoroughfare within the locality, or a crossing of two thoroughfares

The following address keys are defined in XEP-0080 but not by Geoclue, and are also allowed:

  • building - s: a specific building on a street or in an area
  • floor - s: a particular floor in a building
  • room - s: a particular room in a building
  • text - s: any more specific information, e.g. "Northwest corner of the lobby"
  • description - s: A natural-language name for or description of the location, e.g. "Bill's house"
  • uri - s: a URI representing the location or pointing to more information about it

Since the previous strings have data intended to be read by users, the language used should be stated using:

  • language - s: a specific language or locale of location information in a format compatible to RFC 4646. Note that UTF-8 is the only allowed encoding, e.g. "en" or "fr-CA".

Positions are represented by the following well-known keys:

  • lat - d: latitude in decimal degrees north, -90 to +90, relative to the WGS-84 datum This is from XEP-0080; the XEP allows use of a different datum, but recommends this one. We enforce sanity by requiring a consistent datum: a minimal compliant implementation of this specification in terms of XEP-0080 would simply ignore the <lat> and <lon> elements if <datum> exists and has a value other than WGS-84, while an advanced implementation might correct for the different datum.
  • lon - d: Longitude in decimal degrees east, -180 to +180, relative to the WGS-84 datum Same rationale as 'lat'
  • alt - d: altitude in metres above sea level (negative if below sea level) This is from XEP-0080
  • accuracy - d: horizontal position error in metres if known This is from XEP-0080

Velocities are represented by the following well-known keys:

  • speed - d: speed in metres per second This is from XEP-0080
  • bearing - d: direction of movement in decimal degrees, where North is 0 and East is 90 This is from XEP-0080, and is equivalent to the struct field called "direction" in GeoClue

Other well-known keys:

  • timestamp - x (Unix_Timestamp64): the time that the contact was at this location, in seconds since 1970-01-01T00:00:00Z (i.e. the beginning of 1970 in UTC) XEP-0080 uses an ISO 8601 string for this, but a number of seconds since the epoch is probably easier to work with.
The value corresponding to the well-known key.
A map from contacts to their locations. A contact The contact's location, which MAY be empty to indicate that the contact's location is unknown

Return the current locations of the given contacts, if they are already known. If any of the given contacts' locations are not known, request their current locations, but return immediately without waiting for a reply; if a reply with a non-empty location is later received for those contacts, the LocationUpdated signal will be emitted for them.

This method is appropriate for "lazy" location finding, for instance displaying the location (if available) of everyone in your contact list.

For backwards compatibility, if this method is called by a client whose "interest count" for this interface, as defined by Connection.AddClientInterest, is zero, the Connection SHOULD behave as if AddClientInterest had been called for this interface just before that method call. Clients that do not explicitly call AddClientInterest SHOULD NOT call Connection.RemoveClientInterest either.

The contacts whose locations should be returned or signalled. The contacts' locations, if already known. Contacts whose locations are not already known are omitted from the mapping; contacts known to have no location information appear in the mapping with an empty Location dictionary.
Return the current location of the given contact. If necessary, make a request to the server for up-to-date information, and wait for a reply. This method is appropriate for use in a "Contact Information..." dialog; it can be used to show progress information (while waiting for the method to return), and can distinguish between various error conditions. The contact whose location should be returned. The contact's location. It MAY be empty, indicating that no location information was found. The requested contact does not allow the local user to see their location information. Emitted when a contact's location changes or becomes known. The contact The contact's location, or empty to indicate that nothing is known about the contact's location. Set the local user's own location. The location to advertise. If the user wants to obscure their exact location by reducing the precision or accuracy, clients MUST do this themselves, rather than relying on the connection manager to do so. Clients that interact with more than one connection SHOULD advertise the same reduced-accuracy location to all of them, so that contacts cannot obtain an undesirably accurate location by assuming that random errors have been added and averaging the locations advertised on multiple connections. The user's server does not support publishing their own location. If it is possible to determine this ahead of time, the Can_Set flag will not be set in SupportedLocationFeatures. The types of access control that are supported by this connection. The current access control mechanism and settings for this connection. Before publishing location for the first time, if this has not been set by a client, implementations SHOULD set it to be as restrictive as possible (an empty whitelist, if supported). Indicates the Location features supported by this connection. This property MAY be undefined before Status becomes Connected, but MUST remain constant thereafter. Indicates that setting your own location with SetLocation is supported on this connection. Flags describing the Location features which may be supported on any given connection.

The same mapping that would be returned by GetLocations for this contact. Omitted from the result if the contact's location is not known.

For backwards compatibility, if contact attributes that include this interface are requested by a client whose "interest count" for this interface, as defined by Connection.AddClientInterest, is zero, the Connection SHOULD behave as if AddClientInterest was called for this interface just before that request. Clients that do not explicitly call AddClientInterest SHOULD NOT call Connection.RemoveClientInterest either.

telepathy-qt-0.9.6~git1/spec/Call_Content_Media_Description_Interface_RTCP_Feedback.xml0000664000175000017500000000525212470405660027013 0ustar jrjr Copyright © 2005-2010 Nokia Corporation Copyright © 2005-2010 Collabora Ltd This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. (as stable API)

This codec offer interface provides a method of signalling support for RTCP feedback, documented by Extended RTP Profile for Real-time Transport Control Protocol (RTCP)-Based Feedback (RTP/AVPF) (RFC 4585).

The codec identifiers used in the description of the Feedback Messages sent in the Accept's should match those used for the RemoteCodecs in the same Accept call.

For more details on what RTCP Feedback can do and how to use it, one should refer to RFC 4585.

A map of remote feedback codec properties that are supported. True if the remote contact supports Audio-Visual Profile Feedback (AVPF), otherwise False.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Mail_Notification.xml0000664000175000017500000007016012470405660024157 0ustar jrjr Copyright (C) 2007 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library 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.

(as stable API) A client MUST notify interest in this feature before it will be enabled. This Connection provides the number of unread e-mails (or e-mail threads) in the main folder of your e-mail account, as the UnreadMailCount property. The connection manager will update this value by emitting the UnreadMailsChanged signal. This Connection provides a detailed list of unread e-mails, as the UnreadMails property. If this flag is set, Supports_Unread_Mail_Count MUST be set, and Emits_Mails_Received MUST NOT be set. The Connection will update the list by emitting the UnreadMailsChanged signals. This Connection emits the MailsReceived signal, which provides details about newly arrived e-mails but does not maintain their read/unread status afterwards. This flag MUST NOT be combined with Supports_Unread_Mails. This Connection can provide a URL (with optional POST data) to open the the inbox of the e-mail account in a web-based client, via the RequestInboxURL method.

This Connection can provide a URL (with optional POST data) to open a specific mail in a web-based client, via the RequestMailURL method. This feature is not useful unless either Emits_Mails_Received or Supports_Unread_Mails is set.

If this flag is not set, clients SHOULD fall back to using RequestInboxURL if available.

Each Mail represents a thread of e-mails, which MAY have more than one sender.

Google Talk notifies users about new mail in terms of unread threads, rather than unread e-mails.

Flags representing capabilities provided by a connection manager. Those values can be used as bitfield. Some flags depend on, or conflict with, each other.

Connections SHOULD implement as many of these features as the underlying protocol allows, preferring to implement Supports_Unread_Mails instead of Emits_Mails_Received if both are possible.

Use the GET method when opening the URL. Use the POST method when opening the URL. Refer to HTTP_Post_Data for more details. The HTTP Method with which to request a URL.

A pair (key, value) representing POST data compatible with the application/x-www-form-urlencoded MIME type. The strings MUST be valid UTF-8 strings, and the characters used in the key MUST obey the requirements of the HTML CDATA type. The value MUST NOT be encoded with HTML entities.

For example, if the POST data should contain a key "less-than" with value "<", and a key "percent" with value "%", this should be represented as two HTTP_Post_Data structures, ("less-than", "<") and ("percent", "%"), resulting in a POST request whose request body is "less-than=&lt;&percent=%25". If a client passes this to a browser by writing it into an HTML form, it could do so by representing it as:

        <input type="hidden" name="less-than">&lt;</input>
        <input type="hidden" name="percent">%</input>
        

This data can be used to generate a HTML file that will automatically load the URL with appropriate POST data, in which case the client MUST convert any characters that are special within HTML into HTML entities. Alternatively, it can be used in an API that will instruct the browser how to load the URL (like the Netscape Plug-in API), in which case the client MUST escape characters that are reserved in URLs, if appropriate for that API.

An array of pairs is used instead of a map from keys to values, because it's valid to repeat keys in both HTML and x-www-form-urlencoded data.

The key, corresponding to a HTML control name The value

A pair (name, address) representing an e-mail address, such as ("Nicolas Dufresne", "nicolas.dufresne@collabora.co.uk"). At least one of name and address MUST be provided. A missing element will be represented by the empty string.

The CM should provide as much information as possible, but not all protocols provide both the displayed name and the address. (If a protocol doesn't provide either, it should omit the appropriate field from the Mail entirely.)

The displayed name corresponding to the e-mail address The actual e-mail address

A structure containing the required information to open a web-based e-mail UI, without needing re-authentication (if possible).

Because the URL and POST data frequently contain short-lived credential tokens, a new URL should be requested (by calling one of the methods that returns a Mail_URL) for each visit to the web-based UI, and the URL should be visited soon after it is returned.

The URL to which to send a request. The HTTP method of the request. An array of name-value pairs containing the POST data to use when opening the URL. This MUST be an empty array if the Method is not POST.
An extensible map representing a mail, or (on protocols where Thread_Based appears in MailNotificationFlags) a thread of mails. All keys are optional where not otherwise stated; however, at least one of "senders" and "subject" must be included.

A key providing information about the mail or thread. Well-known keys are as follows:

id — s

A unique ID for this e-mail. CMs with Supports_Unread_Mails set in MailNotificationFlags MUST provide this key in each Mail.

If provided, the ID SHOULD be unique to a Mail at least until that mail is removed with the UnreadMailsChanged signal (in protocols with Supports_Unread_Emails), or unique for the duration of a session (otherwise).

In protocols with Supports_Unread_Mails, this key is used to indicate which mail was removed. In protocols without that feature, it's impossible to tell when a mail has been removed (and hence how long the identifier will remain valid for use with RequestMailURL).

url-data — any type
An opaque identifier (typically a string or list of strings) provided to the Connection when calling RequestMailURL, containing information used by the Connection to build the URL.
senders — a(ss) (Mail_Address)
An array of sender display name and e-mail address pairs. Note that only e-mails represented as a thread can have multiple senders.
to-addresses — a(ss) (Mail_Address)
An array of display name and e-mail address pairs representing the recipients.
cc-addresses — a(ss) (Mail_Address)
An array of display name and e-mail address pairs representing the carbon-copy recipients.
sent-timestamp — x (Unix_Timestamp64)
A UNIX timestamp indicating when the message was sent, or for a thread, when the most recent message was sent.
received-timestamp — x (Unix_Timestamp64)
A UNIX timestamp indicating when the message was received, or for a thread, when the most recent message was received.
has-attachments — b
If true, this mail has attachments.
subject — s
The subject of the message. This MUST be encoded in UTF-8.
content-type — s

The MIME type of the message content. Two types are currently supported: "text/plain" for plain text, and "text/html" for a HTML document. If omitted, "text/plain" MUST be assumed. Regardless of MIME type, the content MUST be valid UTF-8 (which may require that the Connection transcodes it from a legacy encoding).

All strings on D-Bus must be UTF-8.

truncated — b
If true, the content is only a partial message; if false or omitted, the content is the entire message.
content — s
The body of the message, possibly truncated, encoded as appropriate for "content-type".
folder — s
The name of the folder containing this e-mails. If omitted, the inbox SHOULD be assumed.
The value, of whatever type is appropriate for the key.
Integer representing the bitwise-OR of supported features for e-mails notification on this server. This property MUST NOT change after the Connection becomes CONNECTED. This property indicates the behavior and availability of the other properties and signals within this interface. A connection manager that cannot at least set one of the flags in the Mail_Notification_Flags SHOULD NOT provide this interface.

The number of unread messages in the Inbox. Change notification is via UnreadMailsChanged.

This property is only useful if Supports_Unread_Mail_Count is set in the MailNotificationFlags; otherwise, it MUST be zero.

If Thread_Based appears in the MailNotificationFlags, this property counts the number of threads, not the number of mails.

Note that this count MAY be bigger than the number of items in UnreadMails. See UnreadMails for more details.

An array of unread Mails. Change notification is via UnreadMailsChanged. This property is only useful if Supports_Unread_Mails is set in MailNotificationFlags; otherwise, it MUST be an empty list.

The array size MAY be shorter than UnreadMailCount.

Some servers may limits the amount of detailed e-mails sent. This can significantly reduce the network traffic for large inbox. For this reason, it is normal that UnreadMailCount be bigger or equal to the size of this array.

A string representing the e-mail address of the account. The CMs MUST provide this information. In close integration of MailNotification with other e-mail services, the e-mail address can be used has a unique identifier for the account. Possible integration could be between Telepathy and Evolution where the e-mail address is the common information in both interfaces.

An array of Mails. Those e-mail MUST NOT have the "id" key.

On connections that emit this signal, it's impossible to tell when a mail has been removed, and hence when "id" has become invalid.

Emitted when new e-mails messages arrive to the inbox associated with this connection. This signal is used for protocols that are not able to maintain the UnreadMails list, but do provide real-time notification about newly arrived e-mails. It MUST NOT be emitted unless Emits_Mails_Received is set in MailNotificationFlags.
Number of unread messages in the inbox (the new value of UnreadMailCount).

A list of Mail that are being added or updated in UnreadMails.

Mails may be updated when the URL information (URL and POST data) have changed, or senders were added or removed from an e-mail thread.

If the Supports_Unread_Mails flag is not set, this list MUST be empty, even if Count has increased.

A list of e-mail IDs that are being removed from UnreadMails. If the Supports_Unread_Mails flag is not set, this list MUST be empty, even if Count has decreased.

Emitted when UnreadMails or UnreadMailCount have changed. It MUST NOT be emited if Supports_Unread_Mail_Count flag is not set in MailNotificationFlags.

Mails_Added and Mails_Removed MUST be empty if the Supports_Unread_Mails flag is not set.

A struture containing a URL and optional additional data to open a webmail client, without re-authentication if possible. This method creates and returns a URL and an optional POST data that allow opening the Inbox folder of a webmail account. This URL MAY contain tokens with a short lifetime, so clients SHOULD request a new URL for each visit to the webmail interface. This method is implemented only if the Supports_Request_Inbox_URL flag is set in MailNotificationFlags. We are not using properties here because the tokens are unsuitable for sharing between clients, and network round-trips may be required to obtain the information that leads to authentication free webmail access. The mail's id as found in the Mail structure, or the empty string if no id key was provided. Whatever url-data was found in the Mail structure, or the boolean value False (D-Bus type 'b') if no url-data was provided in the Mail. A struture that contains a URL and optional additional data to open a webmail client, without re-authentication if possible. This method creates and returns a URL and optional POST data that allow opening a specific mail in a webmail interface. This method is implemented only if Supports_Request_Mail_URL flag is set in MailNotificationFlags. See RequestInboxURL for design rationale.

An interface to support receiving notifications about a e-mail account associated with this connection.

In protocols where this is possible, this interface also allows the connection manager to provide the necessary information for clients to open a web-based mail client without having to re-authenticate.

To use this interface, a client MUST first subscribe by passing the name of this interface to the Connection.AddClientInterest method. The subscription mechanic aims at reducing network traffic and memory footprint in the situation where nobody is currently interesting in provided information. When done with this interface, clients SHOULD call Connection.RemoveClientInterest to allow the CM to release resources.

Protocols have various different levels of Mail Notification support. To describe the level of support, the interface provides a property called MailNotificationFlags. Not all combinations are valid; protocols can be divided into four categories as follows.

Connections to the most capable protocols, such as Google's XMPP Mail Notification extension, have the Supports_Unread_Mails flag (this implies that they must also have Supports_Unread_Mail_Count, but not Emits_Mails_Received). On these connections, clients requiring change notification MUST monitor the UnreadMailsChanged signal, and either recover the initial state from the UnreadMails property (if they require details other than the number of mails) or the UnreadMailCount property (if they are only interested in the number of unread mails). The MailsReceived signal is never emitted on these connections, so clients that will display a short-term notification for each new mail MUST do so in response to emission of the UnreadMailsChanged signal.

The most common situation, seen in protocols like MSN and Yahoo, is that the number of unread mails is provided and kept up-to-date, and a separate notification is emitted with some details of each new mail. This is a combination of the following two features, and clients SHOULD implement one or both as appropriate for their requirements.

On protocols that have the Emits_Mails_Received flag (which implies that they do not have Supports_Unread_Mails), the CM does not keep track of any mails; it simply emits a notification whenever new mail arrives. Those events may be used for short term display (like a notification popup) to inform the user. No protocol is known to support only this feature, but it is useful for integration with libraries that that do not implement tracking of the number of mails. Clients requiring these notifications MUST monitor the MailsReceived signal on any connections with this flag.

On protocols that have the Supports_Unread_Mail_Count flag but not the Supports_Unread_Mails flag, clients cannot display complete details of unread email, but can display an up-to-date count of the number of unread mails. To do this, they must monitor the UnreadMailsChanged signal, and retrieve the initial state from the UnreadMailCount property.

Orthogonal features described by the MailNotificationFlags property include the RequestSomethingURL methods, which are used to obtain URLs allowing clients to open a webmail client. Connections SHOULD support as many of these methods as possible.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Room.xml0000664000175000017500000004427112470405660020760 0ustar jrjr Copyright © 2010 Collabora Ltd. Copyright © 2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(version 2)

Different IM protocols use a variety of ways to name chat rooms. The simplest example is perhaps IRC, where chat rooms have short, persistent, human-readable string names, and are generally global across the network. Skype chat rooms have persistent string names, so you can leave and re-join a room, but these names are opaque unique identifiers. MSN chat rooms are unnamed, and you can only join one by being invited. And XMPP wins the coveted “most complicated chat rooms” prize: chat rooms may be hosted by different servers with different DNS names; normally they have human-readable names, except that all MUCs on Google Talk's conference server have UUIDs as names, and XEP-0045 §10.1.4 Requesting a Unique Room Name defines a protocol for requesting a unique, opaque room name on the server. Note that this interface is not restricted to Text channels, and can also be used on Call channels.

This interface intends to support and differentiate these mechanisms more clearly than the TargetHandleType and TargetID properties can alone. It initially contains a pair of properties used to represent the human-readable parts of a Room_Handle's identifier, if any. The above examples for different protocols are represented as follows:

  • The IRC channel #telepathy on Freenode is represented by a channel with properties TargetHandleType = Room, TargetID = "#telepathy", RoomName = "#telepathy", Server = "", indicating that the room has a human-readable identifier, and is not confined to a particular server on the network. Actually, IRC supports creating “local” channels specific to the server they are created on. These channels have identifiers starting with & rather than #. These could be represented by setting Server appropriately.
  • A Skype group chat with opaque identifier 0xdeadbeef has TargetHandleType = Room, TargetID = "0xdeadbeef", RoomName = "", Server = "", indicating that the room has an identifier but no human-readable name.
  • An MSN group chat has TargetHandleType = None, RoomName = "", Server = "", indicating that the room has neither an identifier (so it cannot be re-joined later) nor a human-readable name.
  • A standard Jabber multi-user chat jdev@conference.jabber.org has TargetHandleType = Room, TargetID = "jdev@conference.jabber.org", RoomName = "jdev", Server = "conference.jabber.org".
  • A Google Talk private MUC private-chat-11111x1x-11xx-111x-1111-111x1xx11x11@groupchat.google.com has TargetHandleType = Room, TargetID = "private-chat-11111x1x-11xx-111x-1111-111x1xx11x11@groupchat.google.com", RoomName = "", Server = "groupchat.google.com", indicating that the room has a persistent identifier, no human-readable name, and is hosted by a particular server.
  • Similarly, a XEP-0045 §10.1.4 uniquely-named room lrcgsnthzvwm@conference.jabber.org has TargetHandleType = Room, TargetID = "lrcgsnthzvwm@conference.jabber.org", RoomName = "", Server = "conference.jabber.org", indicating that the room has a persistent identifier, no human-readable name, and is hosted by a particular server.

Requestable channel classes

If the connection supports joining text chat rooms by unique identifier, like Skype, it should advertise a Requestable_Channel_Class matching:

( Fixed = { ...ChannelType: ...Text,
            ...TargetHandleType: Room,
          },
  Allowed = [ ...TargetID,
              ...TargetHandle,
            ]
)

Channel requests must specify either TargetID or TargetHandle.

If, like IRC, the room identifiers are also human-readable, the RCCs should also include RoomName in Allowed_Properties:

( Fixed = { ...ChannelType: ...Text,
            ...TargetHandleType: Room,
          },
  Allowed = [ ...TargetID,
              ...TargetHandle,
              ...RoomName
            ]
),

( Fixed = { ...ChannelType: ...Text
          },
  Allowed = [ ...RoomName,
            ]
)

Requests may specify the RoomName in place of TargetID or TargetHandle . Note how RoomName appears in Allowed_Properties of a different RCC because when TargetHandleType is omitted (or is None), both TargetHandle and TargetID must also be omitted. RoomName is allowed in conjuction with TargetID or TargetHandle in some situations, as explained below in the Requesting room channels section.

If rooms may be on different servers, Server should also be included in the allowed properties, but CMs MUST use a reasonable default Server if not explicitly specified in a channel request. The CM's default server MAY be configurable by a connection parameter specified on a RequestConnection call, similarly to how the fallback conference server is specified on jabber connections in gabble.

If the protocol supports unnamed rooms, RoomName should be fixed to the empty string, and TargetHandleType should be None:

( Fixed = { ...ChannelType: ...Text,
            ...TargetHandleType: None,
            ...RoomName: "",
          },
  Allowed = [ ]
)

Requesting room channels

When explicitly joining a room, the CM cannot know whether the room ID is unique or not. As a result, if this is the case, adding an empty string RoomName into the channel request will ensure the CM knows. For example:

{ ...ChannelType: ...Text,
  ...TargetHandleType: Room,
  ...TargetID: "qwerasdfzxcv@conference.jabber.org",
  ...RoomName: ""
}

If RoomName features in Allowed_Properties then the only value allowed in conjunction with TargetID or TargetHandle is the empty string. Requests with conflicting TargetID and RoomName properties will fail with InvalidArgument.

To create a XEP-0045 §10.1.4 uniquely-named room channel on the conference.jabber.org server, then the following channel request should be made:

{ ...ChannelType: ...Text,
  ...RoomName: ""
  ...Server: "conference.jabber.org"
}

If everything is successful, then when the channel request is satisfied, a new channel will appear with the following properties:

{ ...ChannelType: ...Text,
  ...TargetHandleType: Room,
  ...TargetID: "kajsdhkajshdfjkshdfjkhs@conference.jabber.org",
  ...RoomName: ""
  ...Server: "conference.jabber.org"
}

The CM will have received the unique room name (kajsdhkajshdfjkshdfjkhs) and then created a room with such a name on the said server. The empty RoomName property shows that the room name is not human-readable.

The human-readable identifier of a chat room. Note that if non-empty, this property (and perhaps also Server) should be sufficient in a channel request to join the room. XMPP MUCs have a room name concept which is more like a topic, except more persistent. This D-Bus property is not this XMPP room name, but the bit before the @ in the room jid; see RoomConfig1.Title for that concept.

This property cannot change during the lifetime of the channel. It should appear in the Allowed_Properties of a Requestable_Channel_Class for the connection if rooms on this connection have human-readable names, and can be joined by name.

For protocols with a concept of chatrooms on multiple servers with different DNS names (like XMPP), the DNS name of the server hosting this channel (for example, "conference.jabber.org" or "groupchat.google.com"). For other protocols, the empty string.

This property cannot change during the lifetime of the channel. It should appear in the Allowed_Properties of a Requestable_Channel_Class for the connection if and only if non-empty values are supported.

The normalized contact ID representing who created the room; or the empty string if unknown. The handle corresponding to Creator; or 0 if Creator is unknown. A unix timestamp indicating when the room was created; or INT_MAX64 if unknown.
telepathy-qt-0.9.6~git1/spec/Call_Content_Interface_Video_Control.xml0000664000175000017500000001175512470405660023610 0ustar jrjr Copyright © 2011 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface that allows the connection manager to control the video stream.

This interface is generally not needed. In cases where the connection manager handles the network communication and the media is transferred from the client to the connection manager via shared memory, it can sometimes be beneficial for the connection manager to be able to control certain aspects of the video stream.

Request that the video encoder produce a new key frame as soon as possible. With of the video stream. Height of the video stream. The resolution at which the streaming engine should be sending.

Change notification is via the VideoResolutionChanged signal.

The desired video resolution has changed. The bitrate the streaming engine should be sending at.

Change notification is via the BitrateChanged signal.

The desired bitrate has changed The framerate the streaming engine should be sending at.

Change notification is via the FramerateChanged signal.

The desired framerate has changed The Maximum Transmission Unit

Change notification is via the MTUChanged signal.

The Maximum Transmission Unit has changed Only send key frames when manually requested
telepathy-qt-0.9.6~git1/spec/Account.xml0000664000175000017500000010264412470405660016027 0ustar jrjr Copyright © 2008-2012 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

An Account object encapsulates the necessary details to make a Telepathy connection.

Accounts are uniquely identified by object path. The object path of an Account MUST take the form /org/freedesktop/Telepathy/Account/cm/proto/acct, where:

  • cm is the same Connection_Manager_Name that appears in the connection manager's well-known bus name and object path
  • proto is the Protocol name as seen in ConnectionManager.ListProtocols, but with "-" replaced with "_" (i.e. the same as in the object-path of a Connection)
  • acct is an arbitrary string of ASCII letters, digits and underscores, starting with a letter or underscore, which uniquely identifies this account
  • Clients SHOULD parse the object path to discover the connection manager and protocol
  • Clients MUST NOT attempt to parse acct
  • Clients MUST NOT assume that acct matches the connection-specific part of a Connection's object-path and bus name
  • The account manager SHOULD choose acct such that if an account is deleted, its object path will be re-used if and only if the new account is in some sense "the same" (incorporating the 'account' parameter in some way is recommended)

This API avoids specifying the "profiles" used in Mission Control 4.x or the "presets" that have been proposed to replace them. An optional interface will be provided for AM implementations that want to provide presets.

There is deliberately no functionality here for opening channels; we intend to provide that in the channel dispatcher.

Other missing features which would be better in their own interfaces:

  • dynamic parameter-providing (aka provisioning)
  • saved server capabilities
  • account conditions
  • account grouping
moved the Avatar property to a separate interface A list of the extra interfaces provided by this account. Delete the account. This account has been removed. This is redundant with AccountRemoved, but it's still worth having, to avoid having to bind to AccountManager.AccountRemoved to tell you whether your Account is valid — ideally, an account-editing UI should only care about a single Account. The values of one or more properties on this interface (that do not specify that this signal does not apply to them) may have changed. This does not cover properties of other interfaces, which must provide their own change notification if appropriate. A map from property names in this namespace (e.g. Nickname) to values. Properties whose values have not changed SHOULD be omitted, but this need not be done. The user-visible name of this account. This SHOULD be chosen by the user at account creation time. The account creation user interface is responsible for setting a reasonable default value in the user's locale; something like "Jabber (bob@example.com)" would be sensible. The name of an icon in the system's icon theme, such as "im-msn", or the empty string to not specify an icon. If the icon is set to an empty string, the account manager or any client MAY derive a default icon, for instance from the protocol. If true, this account is considered by the account manager to be complete and usable. If false, user action is required to make it usable, and it will never attempt to connect (for instance, this might be caused by the absence of a required parameter). For connection managers with a plugin architecture, like telepathy-haze, we have little or no control over the parameters offered; for platforms with package management, we have little or no control over the CMs offered. NMC 4.x would just pretend the account didn't exist in these circumstances, but silent data loss is bad, and UIs with CM-specific knowledge (or a user filling in newly-required parameters) might be able to rescue a broken account.

This property gives the users the possibility to prevent an account from being used. This flag does not change the validity of the account.

A disabled account can never be put online.

Use cases:

  • user has two or more accounts capable of calling contact X, but he doesn't want the UI to prompt him everytime about which one he wants to use for the call. He can then disable all the equivalent accounts but one.
  • There is some temporary server error and the user doesn't want to be be bother by error messages, or change the account configuration: temporarily disabling the account is quicker.

The AccountManager SHOULD allow this property to be set on invalid accounts, but MUST NOT attempt to put invalid accounts online even if they become Enabled.

There doesn't seem to be any good reason not to allow this.

The nickname to set on this account for display to other contacts, as set by the user. When the account becomes connected, the account manager SHOULD set this as the user's alias using SetAliases if appropriate. In a later specification revision, we plan to separate the concepts of a contact's nickname as set by themselves, and the local name for them in our contact list (a "handle" or "pet name" as described in XEP-0165 and its references). The terminology change from alias to nickname here is a step in that direction.

Some protocols, like XMPP and SIP, are used by various different user-recognised brands, such as Google Talk and Ovi by Nokia. On accounts for such services, this property SHOULD be set to a string describing the service, which MUST consist only of ASCII letters, numbers and hyphen/minus signs, and start with a letter (matching the requirements for Protocol). For the jabber protocol, one of the following service names should be used if possible:

For the IRC protocol, the network name (freenode, gimpnet, etc.) can be used if relevant.

The Icon property SHOULD be set to a corresponding brand-specific icon name, if possible. In the future, this property may be used as an index into additional service-specific customizations. If this property is the empty string (or missing), the service is determined by the protocol name (either because this is a single-service protocol like msn, or because this is just a generic jabber or sip account without specific branding).

This property MAY be set, if appropriate, when calling CreateAccount. Updating this property will fail on externally-stored accounts whose StorageRestrictions include Cannot_Set_Service.

A map from connection manager parameter names (as in the ConnectionManager interface) to their values. This property includes only those parameters that are stored for this account, and SHOULD only include those parameters that the user has explicitly set.

This property cannot be altered using org.freedesktop.DBus.Properties.Set(); use UpdateParameters instead.

Change the value of the Parameters property.

If any of the Set parameters’ Conn_Mgr_Param_Flags include DBus_Property, the change will be applied immediately to the corresponding D-Bus Property on the active Connection, if there is one. If any of the Unset parameters’ Conn_Mgr_Param_Flags include both DBus_Property and Has_Default, the corresponding D-Bus Property on the connection will be set to the default value. Changes to other parameters will not take effect until the next time the account is disconnected and reconnected. (If parameters are explicitly set to their default value, or are unset when previously set to their default value, the account manager MAY decide that no reconnection is necessary to make the change take effect.)

In general, reconnecting is a destructive operation that shouldn't happen as a side-effect. In particular, migration tools that twiddle the settings of all accounts shouldn't cause an automatic disconnect and reconnect.

parameters which are also D-Bus properties can and should be updated on existing Connections return an array of the parameters that won't change until the account is reconnected A mapping from parameter names to their values. These parameters should be stored for future use. A list of the names of parameters to be removed from the set of stored values, allowing the default values to be used. If the given parameters were not, in fact, stored, or even if they do not exist at all, the account manager MUST accept this without error.

If all of the updates could be applied to the active Connection (if any), the empty list, signifying that no reconnection is required for the new parameters to take effect. For example, if the only parameter updated is ...Cellular.MessageValidityPeriod, the new value can be applied immediately to the connection.

Otherwise, a list of the names of parameters with changes that will not take effect until the account is reconnected. User interfaces that require "instant apply" semantics MAY call Reconnect in response to receiving a non-empty list. For example, if the caller updates both ...Anonymity.AnonymityMandatory and require-encryption, the former can be applied to the current connection, but the latter needs a reconnect to take effect, so this method should return ["require-encryption"].

The presence status that this account should have if it is brought online.

In ITOS2007 and ITOS2008 this is a global preference, not visible on D-Bus (the "default presence"). "Automatic presence" better describes when it is used.

Setting this property MUST NOT actually change the account's status until the next time it is (re)connected for some reason.

The value of this property MUST be one that would be acceptable for RequestedPresence, with the additional restriction that the Connection_Presence_Type MUST NOT be Offline.

Otherwise, it would not be possible to use this presence to bring the account online for a channel request.

If true, the account manager SHOULD attempt to put this account online with the AutomaticPresence whenever possible (in the base Account interface this is deliberately left vague). If false, it MUST NOT put the account online automatically in response to, for instance, connectivity changes, but SHOULD still put the account online with the AutomaticPresence if requested by the user (for instance, if the user tries to start a conversation using this account).

Either the object path of the Connection to this account, or the special value '/' if there is no connection.

If this object path is not '/', the Connection's well-known bus name can be derived from this object path by removing the first '/' and replacing subsequent '/' characters with '.'.

Object paths aren't nullable, so we can't use an empty string.
If the Connection property is non-empty, the status of that connection. If the Connection property is the empty string, this property may either be Disconnected (indicating that the account manager is not attempting to bring it online), or Connecting (indicating that the account manager is attempting to connect). The account manager is expected to set this by observing signals from the Connection. If the AM is doing some sort of backoff/delay on reconnection attempts, the account's status is conceptually "Connecting" even though there is no Connection. The reason for the last change to ConnectionStatus. The account manager is expected to set this by observing signals from the Connection. If you weren't watching the Connection at the time it failed, you can't tell why - unless the AM can tell you.

If the last connection to this account failed with an error, the D-Bus error name of that error; otherwise, the empty string. The account manager is expected to set this by observing the Connection.ConnectionError and Connection.StatusChanged signals.

If ConnectionError is received before the connection disconnects, its first argument should be used to set this property; otherwise, the Reason argument of StatusChanged should be converted to a suitable D-Bus error name.

Whenever the Connection connects successfully, this property should be reset to the empty string.

This combines the state-recoverability of ConnectionStatusReason with the extensibility of Connection.ConnectionError.

If the last connection to this account failed with an error, a mapping representing any additional information about the last disconnection; otherwise, the empty map. The keys and values are the same as for the second argument of Connection.ConnectionError.

Whenever the Connection connects successfully, this property should be reset to the empty map.

This combines the state-recoverability of ConnectionStatusReason with the extensibility of Connection.ConnectionError.

The actual presence. If the connection is not online, the Connection_Presence_Type SHOULD be Connection_Presence_Type_Offline. If the connection is online but does not support the SimplePresence interface, the type SHOULD be Connection_Presence_Type_Unset. The account manager is expected to set this by observing signals from the Connection.

The requested presence for this account. When this is changed, the account manager should attempt to manipulate the connection manager to make CurrentPresence match RequestedPresence as closely as possible. It should not be saved to any sort of persistent storage.

When the account manager automatically connects an account, it must signal this by setting the RequestedPresence to the same thing as the AutomaticPresence.

The Connection_Presence_Type in this property MUST NOT be Unset, Unknown or Error.

Requesting those presence types doesn't make sense.

If true, a change to the presence of this account is in progress.

Whenever RequestedPresence is set on an account that could go online, or whenever an account with a non-offline RequestedPresence becomes able to go online (for instance because Enabled or Valid changes to True), ChangingPresence MUST change to True, and the two property changes MUST be emitted in the same AccountPropertyChanged signal, before the Set method returns.

When the account manager succeeds or fails in changing the presence, or the connection disconnects due to an error, ChangingPresence MUST change to False as part of the same AccountPropertyChanged signal.

This allows UIs to indicate that a presence change is in progress or has finished, even if the change was initiated by a different UI.

For instance, Maemo 5 and Empathy indicate a presence change by having the presence indicator alternate between the RequestedPresence and the CurrentPresence; they should start blinking when ChangingPresence becomes true, and stop when it becomes false.

Re-connect this account. If the account is currently disconnected and the requested presence is offline, or if the account is not Enabled or not Valid, this does nothing.

If the account is disconnected and the requested presence is not offline, this forces an attempt to connect with the requested presence immediately.

If the account is connecting or connected, this is equivalent to remembering the current value of RequestedPresence, setting its value to (OFFLINE, "offline", ""), waiting for the change to take effect, then setting its value to the value that was previously remembered.

Clients desiring "instant apply" semantics for CM parameters MAY call this method to achieve that.

In particular, if the account's Connection is in the Connecting state, calling this method causes the attempt to connect to be aborted and re-tried.

This is necessary to ensure that the new parameters are picked up.

The normalized user ID of the local user on this account (i.e. the string returned when the InspectHandles method is called on the result of GetSelfHandle for an active connection).

It is unspecified whether this user ID is globally unique.

As currently implemented, IRC user IDs are only unique within the same IRCnet. On some saner protocols, the user ID includes a DNS name which provides global uniqueness.

If this value is not known yet (which will always be the case for accounts that have never been online), it will be an empty string.

It is possible that this value will change if the connection manager's normalization algorithm changes, although this SHOULD be avoided.

It's not always completely clear what normalization algorithm should be used; for instance, in Gabble, we currently use JIDs, but it would also have been reasonable to use xmpp URIs.

If true, this account has successfully been put online at some point in the past. UIs could apply a policy that the 'account' parameter can only be edited in accounts that have never been online, or that ConnectAutomatically cannot be set on such accounts. The account manager should not enforce such policies, but it can expose enough information to UIs that the UI can decide what to do.

A list of the object paths of formerly-used accounts which are superseded by this one.

For instance, if an account is migrated from one connection manager implementation to another, or even from one protocol to another (for instance formerly-proprietary services which can now be accessed via XMPP), log storage services could look for logs under all of the superseded object paths as well as the new object path.

This is a list because a single user-visible account could be migrated more than once.

If the Account Manager implementation performs an account migration automatically, it SHOULD set this property. If a client performs an account migration, it SHOULD set this property via via the Properties argument of CreateAccount when creating the migrated account. In either case, the value SHOULD include the old account's path, and every path from the old account's Supersedes property.

telepathy-qt-0.9.6~git1/spec/Protocol_Interface_Presence.xml0000664000175000017500000001063712470405660022040 0ustar jrjr Copyright © 2009-2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface for protocols where it might be possible to set the user's presence, and the supported presence types can be predicted before connecting.

This allows UIs to show or hide presence types that aren't always supported, such as "invisible", while not online.

The properties on this interface SHOULD be cached in the .manager file, in the [Protocol proto] group. For each status s in Statuses, that group should contain a key of the form status-s whose value is the Connection_Presence_Type as an ASCII decimal integer, followed by a space-separated sequence of tokens from the following set:

settable
If present, the user can set this status on themselves using SetPresence; this corresponds to May_Set_On_Self in the Simple_Status_Spec struct.
message
If present, the user can set a non-empty message for this status; this corresponds to Can_Have_Message in the Simple_Status_Spec struct.

Unrecognised tokens MUST be ignored.

For instance, an XMPP connection manager might have this .manager file:

[Protocol jabber]
Interfaces=org.freedesktop.Telepathy.Protocol.Interface.Presence;
param-account=s required
param-password=s required
status-offline=1
status-unknown=7
status-error=8
status-hidden=5 settable message
status-xa=4 settable message
status-away=3 settable message
status-dnd=6 settable message
status-available=2 settable message
status-chat=2 settable message

which corresponds to these property values (using a Python-like syntax):

Statuses = {
    'offline': (OFFLINE, False, False),
    'unknown': (UNKNOWN, False, False),
    'error': (ERROR, False, False),
    'hidden': (HIDDEN, True, True),
    'xa': (EXTENDED_AWAY, True, True),
    'away': (AWAY, True, True),
    'dnd': (BUSY, True, True),
    'available': (AVAILABLE, True, True),
    'chat': (AVAILABLE, True, True),
}

The statuses that might appear in the Connection.Interface.SimplePresence.Statuses property on a connection to this protocol that supports SimplePresence. This property is immutable.

Depending on server capabilities, it is possible that not all of these will actually appear on the Connection.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Contact_Info.xml0000664000175000017500000005764512470405660023152 0ustar jrjr Copyright (C) 2008 Collabora Limited Copyright (C) 2008 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API) The name of the field; this is the lowercased name of a vCard field. For example, a field representing a contact's address would be named "adr".

A list of vCard type parameters applicable to this field, with their values. The type parameter names, and any values that are case-insensitive in vCard, MUST be in lower case. For example, a contact's preferred home address would have parameters 'type=home' and 'type=pref'.

The type parameter 'type' is likely to be the most common, but there can be others, such as 'language=en'.

Characters which are required to be escaped in vCard type parameters should not be escaped in this list. For instance, a field "X-FOO;SEMICOLON=\;:bar" in a vCard would become ('x-foo', ['semicolon=;'], ['bar']) in this interface.

This avoids Telepathy UIs having to understand the escaping and unescaping rules for vCards. The type parameter name is not allowed (by RFC 2425) to contain an '=' character, so no ambiguity is introduced.

For unstructured vCard fields (such as 'fn', a formatted name field), a single-element array containing the field's value.

For structured fields (such as 'adr', an address field), an array corresponding to the semicolon-separated elements of the field (with empty strings for empty elements).

A vCard field with multiple comma-separated values, such as 'nickname', should be represented by several Contact_Info_Fields.

Characters which are required to be escaped in vCard values, such as semi-colons and newlines, should not be escaped in this list (e.g. if a value contains a newline, the data passed over D-Bus should contain a literal newline character).

An earlier draft of this interface split structured vCard fields into multiple Telepathy-level fields; for example, 'n' became 'family-name', 'given-name', etc. But under this representation, omitting empty components leads to difficulty identifying where one name ends and another begins. Consider the fields ['given-name', 'honorific-suffixes', 'family-name', 'honorific-prefixes']: does this represent two 'n' fields, or one with incorrect component ordering?

Represents one piece of information about a contact, as modelled by a single vCard field. Of the fields defined in RFC 2426, common examples include:

fn
The contact's full name, formatted to their liking
n
The contact's full name, divided into five parts: family name, given name, additional names, honorific prefixes, and honorific suffixes
org
The contact's organisation, divided into the organization's name possibly followed by one or more organizational unit names.
adr
A street address for the contact, divided into seven components: post office box, extended address, street address, locality (e.g., city), region (e.g., state or province), the postal code, and the country name.
label
A free-form street address for the contact, formatted as a single value (with embedded newlines where necessary) suitable for printing on an address label
tel
A telephone number for the contact.
email
An email address for the contact.

For example, the following vCard:

   BEGIN:vCard
   VERSION:3.0
   FN:Wee Ninja
   N;LANGUAGE=ja:Ninja;Wee;;;-san
   ORG:Collabora, Ltd.;Management Division;Human Resources\; Company Policy Enforcement
   ADR;TYPE=WORK,POSTAL,PARCEL:;;11 Kings Parade;Cambridge;Cambridgeshire
    ;CB2 1SJ;UK
   LABEL;TYPE=WORK,POSTAL,PARCEL:11 Kings Parade\nCambridge\nCambridgeshire\nUK\nCB2 1SJ
   TEL;TYPE=VOICE,WORK:+44 1223 362967, +44 7700 900753
   EMAIL;TYPE=INTERNET,PREF:wee.ninja@collabora.co.uk
   EMAIL;TYPE=INTERNET:wee.ninja@example.com
   URL:http://www.thinkgeek.com/geektoys/plush/8823/
   NICKNAME:HR Ninja,Enforcement Ninja
   END:vCard

would be represented by (in Python-like syntax):

[
  ('fn', [], ['Wee Ninja']),
  ('n', ['language=ja'], ['Ninja', 'Wee', '', '', '-san']),
  ('org', [], ['Collabora, Ltd.', 'Management Division',
    'Human Resources; Company Policy Enforcement']),
  ('adr', ['type=work','type=postal','type=parcel'],
   ['','','11 Kings Parade','Cambridge', 'Cambridgeshire','CB2 1SJ','UK']),
  ('label', ['type=work','type=postal','type=parcel'],
   ['''11 Kings Parade
  Cambridge
  Cambridgeshire
  UK
  CB2 1SJ''']),
  ('tel', ['type=voice','type=work'], ['+44 1223 362967']),
  ('tel', ['type=voice','type=work'], ['+44 7700 900753']),
  ('email', ['type=internet','type=pref'], ['wee.ninja@collabora.co.uk']),
  ('email', ['type=internet'], ['wee.ninja@example.com']),
  ('url', [], ['http://www.thinkgeek.com/geektoys/plush/8823/']),
  ('nickname', [], ['HR Ninja']),
  ('nickname', [], ['Enforcement Ninja'])
]
A dictionary whose keys are contact handles and whose values are contact information.. An integer handle for the contact whose info has changed. An array of fields representing information about this contact. Emitted when a contact's information has changed or been received for the first time on this connection. An array of handles representing contacts. A dictionary mapping contact handles to information, whose keys are the subset of the requested list of handles for which information was cached. Request information on several contacts at once. This SHOULD only return cached information, omitting handles for which no information is cached from the returned map. Integer handles for contacts. Retrieve information for the given contact, requesting it from the network if an up-to-date version is not cached locally. This method SHOULD return immediately, emitting ContactInfoChanged when the contacts' updated contact information is returned. This method allows a client with cached contact information to update its cache after a number of days. An integer handle for a contact. Information about that contact. Retrieve information for a contact, requesting it from the network if it is not cached locally. This method is appropriate for an explicit user request to show a contact's information; it allows a UI to wait for the contact info to be returned. The contact's information could not be retrieved. Set new contact information for this connection, replacing existing information. This method is only suppported if ContactInfoFlags contains Can_Set, and may only be passed fields conforming to SupportedFields. The new information to be set. Setting your own information is not supported on this protocol. The supplied fields do not match the restrictions specified by SupportedFields. Flags defining the behaviour of contact information on this protocol. Some protocols provide no information on contacts without an explicit request; others always push information to the connection manager as and when it changes. Indicates that SetContactInfo is supported on this connection. Indicates that the protocol pushes all contacts' information to the connection manager without prompting. If set, ContactInfoChanged will be emitted whenever contacts' information changes. A string naming a field in a vCard, such as "fn" or "adr". Although these are case-insensitive in RFC 2425, in Telepathy they MUST be normalized to lower case. In the terminology of RFC 2425 this is called a "type name", and corresponds to the "name" production given in the ABNF. A type parameter as defined by RFC 2426, such as "type=cell" or "language=en".

An integer representing the bitwise-OR of flags on this connection.

This property MAY change, without change notification, at any time before the connection moves to status Connection_Status_Connected. It MUST NOT change after that point.

Some XMPP servers, like Facebook Chat, do not allow the vCard to be changed (and so would not have the Can_Set flag). Whether the user's server is one of these cannot necessarily be detected until quite late in the connection process.

A struct describing a vCard field, with parameters, that may be passed to SetContactInfo on this Connection. A vCard field name, such as 'tel'. The set of vCard type parameters which may be set on this field. If this list is empty and the Contact_Info_Field_Flag_Parameters_Exact flag is not set, any vCard type parameters may be used. Flags describing the behaviour of this field. Maximum number of instances of this field which may be set. MAXUINT32 is used to indicate that there is no limit.

A list of field specifications describing the kinds of fields which may be passed to SetContactInfo. The empty list indicates that arbitrary vCard fields are permitted. This property SHOULD be the empty list, and be ignored by clients, if ContactInfoFlags does not contain the Can_Set flag.

For example, a protocol in which arbitrary vCards were stored as-is would set this property to the empty list. A protocol whose notion of contact information is one each of personal phone number, mobile phone number, location, email address and date of birth, with no attributes allowed on each piece of information, would set this property to (in Python-like syntax):

[
  ('tel', ['type=home'], Parameters_Exact, 1),
  ('tel', ['type=cell'], Parameters_Exact, 1),
  ('adr', [], Parameters_Exact, 1),
  ('bday', [], Parameters_Exact, 1),
  ('email', ['type=internet'], Parameters_Exact, 1),
]

A protocol which allows users to specify up to four phone numbers, which may be labelled as personal and/or mobile, would set this property to [ ('tel', ['type=home', 'type=cell'], 0, 4), ].

Studying existing IM protocols shows that in practice protocols allow either a very restricted set of fields (such as MSN, which seems to correspond roughly to the largest example above), or something mapping 1:1 to a large subset of vCard (such as XMPP's XEP-0054).

This property MAY change, without change notification, at any time before the connection moves to status Connection_Status_Connected. It MUST NOT change after that point.

Some XMPP servers, like Google Talk, only allow a small subset of the "vcard-temp" protocol. Whether the user's server is one of these cannot be detected until quite late in the connection process.

Flags describing the behaviour of a vCard field.

If present, exactly the parameters indicated must be set on this field; in the case of an empty list of parameters, this implies that parameters may not be used.

If absent, and the list of allowed parameters is non-empty, any (possibly empty) subset of that list may be used.

If absent, and the list of allowed parameters is empty, any parameters may be used.

Indicates that this field will be overwritten when the user's alias is changed with SetAliases or when the Account's Nickname is updated. Clients that allow the editing of the Alias and the ContactInfo in the same location should hide fields with this flag.

If a client allowed the user to edit both the nickname and the ContactInfo field at the same time, the user could set them to two different values even though they map to the same property. This would result in surprising behavior where the second value would win over the first.

In addition to hiding this field when editing ContactInfo together with the user's nickname, it is recommended that clients call SetContactInfo before setting the user's nickname.

This ensures that if the user changes the nickname, the correct value will get set even if the stale nickname is mistakenly sent along with SetContactInfo.

If used, this flag typically appears on either the 'nickname' or 'fn' field.

An interface for requesting information about a contact on a given connection. Information is represented as a list of Contact_Info_Fields forming a structured representation of a vCard (as defined by RFC 2426), using field names and semantics defined therein.

On some protocols, information about your contacts is pushed to you, with change notification; on others, like XMPP, the client must explicitly request the avatar, and has no way to tell whether it has changed without retrieving it in its entirety. This distinction is exposed by ContactInfoFlags containing the Push flag.

On protocols with the Push flag set, UIs can connect to ContactInfoChanged, call GetContactInfo once at login for the set of contacts they are interested in, and then be sure they will receive the latest contact info. On protocols like XMPP, clients can do the same, but will receive (at most) opportunistic updates if the info is retrieved for other reasons. Clients may call RequestContactInfo or RefreshContactInfo to force a contact's info to be updated, but MUST NOT do so unless this is either in response to direct user action, or to refresh their own cache after a number of days.

We don't want clients to accidentally cause a ridiculous amount of network traffic.

The same value that would be returned by GetContactInfo for this contact. Omitted from the result if the contact's info is not known.

telepathy-qt-0.9.6~git1/spec/Client_Observer.xml0000664000175000017500000005114112470405660017513 0ustar jrjr Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as a stable interface)

Observers monitor the creation of new channels. This functionality can be used for things like message logging. All observers are notified simultaneously.

Observers SHOULD NOT modify the state of a channel except via user interaction.

We want Observer UIs for file transfer channels (a progress bar for the transfer) to be able to have a Cancel button.

Observers MUST NOT carry out actions that exactly one process must take responsibility for (e.g. acknowledging Text messages, or carrying out the actual transfer in a file transfer channel).

Since arbitrarily many observers can be activated for each channel, it would not make sense for observers to do things that can only be done by one process (acknowledging Text messages, carrying out streaming for StreamedMedia channels, doing the actual data transfer for file transfers, setting up the out-of-band connection for Tubes). The Handler is responsible for such tasks.

Handlers MAY, of course, delegate responsibility for these tasks to other processes (including those run as observers), but this MUST be done explicitly via a request from the Handler to the Observer.

Whenever a collection of new channels is signalled, the channel dispatcher will notify all running or activatable observers whose ObserverChannelFilter property (possibly as cached in the .client file) indicates that they are interested in some of the channels.

Observers are activated for all channels in which they have registered an interest - incoming, outgoing or automatically created - although of course the ObserverChannelFilter property can be set to filter on the Requested property.

Because it might take time for an observer to become ready (for instance, a Text logger needs to wait until pending messages have been downloaded), the channel dispatcher must wait (up to some timeout) for all observers to return from ObserveChannels before letting anything destructive happen. Destructive things (e.g. acknowledging messages) are defined to be done by handlers, therefore HandleWith and Claim aren't allowed to succeed until all observers are ready.

Non-interactive approvers (for instance, to shoot down spam IM channels before the tray icon blinks at the user, or to grab a SASL channel before the user is prompted for a password) can be implemented as observers by following these steps:

  1. ObserveChannels() is called on the observer.
  2. The observer calls Claim() on the CDO.
  3. The observer then returns from ObserveChannels().
  4. Claim will return successfully if the channels were successfully claimed, or failure if someone else got there first.

Non-interactive approvers implemented as observers SHOULD also set DelayApprovers to TRUE so that other Approvers are not called on until all observers return from ObserveChannels. This gives non-interactive approvers a chance to claim the channels before Approvers are called.

A specification of the channels in which this observer is interested. The ObserveChannels method should be called by the channel dispatcher whenever any of the new channels in a NewChannels signal match this description.

Only certain D-Bus types have useful semantics for matching like this, so only certain types are allowed:

Integers of all sizes, including byte (y, n, q, i, u, x, t)
Matched by numeric value, regardless of type (e.g. 42 as a 16-bit signed integer 'n' is considered equal to 42 as a 32-bit unsigned integer 'u')
Booleans (b)
Matched by equality in the obvious way; not considered equal to any other type
Strings (s)
Matched by equality in the obvious way; not considered equal to any other type
Object paths (o)
Matched by equality in the obvious way; not considered equal to any other type

This property never changes while the observer process owns its Client bus name. For activatable processes, the filter can change due to an upgrade - the channel dispatcher SHOULD observe changes to .client files using a mechanism like inotify.

Not allowing this property to change is a simplification, particularly for activatable processes (we reject the possibility that a process with a .client file, when activated, has a filter that differs from what its .client file said).

If an Observer wants to add extra channels to its list of interests at runtime, it can register an additional Client bus name (for instance, the org.freedesktop.Telepathy.Client.Empathy process with unique name :1.42 could additionally register org.freedesktop.Telepathy.Client.Empathy._1_42) with additional filters. To remove those filters, it can release the bus name; it could even re-claim the bus name immediately, with different filters.

The same principle is applied to Approvers and Handlers.

For observers that have a .client file, the channel dispatcher may discover this property from keys of the form "propertyname type", in groups in the .client file whose name is the name of this interface followed by .ObserverChannelFilter, a space and an ASCII decimal number starting from 0.

Values in the .client file are encoded in exactly the same way as the default-p keys in .manager files, as described in the ConnectionManager interface (but note that not all types supported in .manager files can appear in .client files).

For instance, a .client file for an observer that is only interested in Text channels, with CONTACT or ROOM handles, that were requested by a local client:

[org.freedesktop.Telepathy.Client]
Interfaces=org.freedesktop.Telepathy.Client.Observer;

[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 0]
org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
org.freedesktop.Telepathy.Channel.TargetHandleType u=1
org.freedesktop.Telepathy.Channel.Requested b=true

[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 1]
org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
org.freedesktop.Telepathy.Channel.TargetHandleType u=2
org.freedesktop.Telepathy.Channel.Requested b=true
When using telepathy-mission-control, version 5.4.0 or later is needed for this property to be useful.

If true, upon the startup of this observer, ObserveChannels will be called for every already existing channel matching its ObserverChannelFilter

When an activatable client having this property disappears from the bus and there are channels matching its ObserverChannelFilter, ObserveChannels will be called immediately to reactivate it again. Such clients should specify this property in their .client file as follows:

[org.freedesktop.Telepathy.Client.Observer]
Recover=true

This means that if an activatable Observer crashes, it will be restarted as soon as possible; while there is an unavoidable possibility that it will miss some events during this process (particularly Text messages), this window of event loss is kept to a minimum.

Non-activatable observers can't take advantage of this mechanism, but setting this property on a non-activatable observer does allow it to "catch up" on channels that are currently active at the time that it starts up.

When the ObserveChannels method is called due to observer recovery, the Observer_Info dictionary will contain one extra item mapping the key "recovering" to True.

Called by the channel dispatcher when channels in which the observer has registered an interest are announced in a NewChannels signal.

If the same NewChannels signal announces some channels that match the filter, and some that do not, then only a subset of the channels (those that do match the filter) are passed to this method.

If the channel dispatcher will split up the channels from a single NewChannels signal and dispatch them separately (for instance because no installed Handler can handle all of them), it will call ObserveChannels several times.

The observer MUST NOT return from this method call until it is ready for a handler for the channel to run (which may change the channel's state).

The channel dispatcher must wait for observers to start up, to avoid the following race: text channel logger (observer) gets ObserveChannels, text channel handler gets HandleChannels channel handler starts up faster and acknowledges messages, logger never sees those messages.

The channel dispatcher SHOULD NOT change its behaviour based on whether this method succeeds or fails: there are no defined D-Bus errors for this method, and if it fails, this only indicates that an Observer is somehow broken.

The expected error response in the channel dispatcher is to log a warning, and otherwise continue as though this method had succeeded.

The Account with which the channels are associated. The well-known bus name to use is that of the AccountManager. The Connection with which the channels are associated. The well-known bus name to use can be derived from this object path by removing the leading '/' and replacing all subsequent '/' by '.'. The Channels and their properties. Their well-known bus names are all the same as that of the Connection.

The path to the ChannelDispatchOperation for these channels, or the special value '/' if there is no ChannelDispatchOperation (because the channels were requested, not incoming).

If the Observer calls Claim or HandleWith on the dispatch operation, it MUST be careful to avoid deadlock, since these methods cannot return until the Observer has returned from ObserveChannels.

This allows an Observer to Claim a set of channels without having to match up calls to this method with calls to AddDispatchOperation.

The ChannelRequests satisfied by these channels. If the same process is an Observer and a Handler, it can be useful to be given this information as soon as possible (it will also be passed to Handler.HandleChannels).

Additional information about these channels. Currently defined keys are:

recovering - b
True if ObserveChannels was called for an existing channel (due to the Recover property being True); False or omitted otherwise. This allows observers to distinguish between new channels (the normal case), and existing channels that were given to the observer in order to catch up on previous events (perhaps after a previous instance of the same observer crashed).
request-properties - a{oa{sv}}
A map from ChannelRequest paths listed in Requests_Satisfied to Qualified_Property_Value_Maps containing namespaced immutable properties of each request.

All defined keys for this dictionary are optional; observers MAY safely ignore any entry in this dictionary.

If true, the channel dispatcher will wait for ObserveChannels to return before calling Approver.AddDispatchOperation on appropriate Approvers.

This property SHOULD be false unless there is a reason why a channel should not be given to approvers. An example of this is if an Observer is also a Handler and wants to Claim a channel so that it becomes its handler and doesn't want any approver to be called, this property should be true.

Observers and Approvers should be called at the same time in normal operation (with this property set to false) to improve responsiveness. For example, if an incoming call appears, the approver should get the channel as fast as possible to show a dialog, but if an approver has to make round-trips to set itself up, then the approval of the channel is delayed. As a result, it is recommended for this property to remain false unless absolutely necessary.

For service-activatable clients, this property should be specified in the observer's .client file as follows:

If this property is not implemented (telepathy-mission-control 5.7.5 and older), the channel dispatcher SHOULD consider it as being false.

[org.freedesktop.Telepathy.Client.Observer]
DelayApprovers=true
telepathy-qt-0.9.6~git1/spec/Properties_Interface.xml0000664000175000017500000002164512470405660020550 0ustar jrjr Copyright (C) 2005-2007 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

All uses of this interface have been expunged, and it may now be laid to rest. A struct (property ID, property name, D-Bus signature, flags) representing a property, as returned by ListProperties on the Properties interface. A struct (property ID, flags) representing a change to a property's flags, as seen in the PropertyFlagsChanged signal on the Properties interface. An unsigned integer used to represent a Telepathy property. A struct (property ID, value) representing a property's value, as seen in the PropertiesChanged signal on the Properties interface, returned by the GetProperties method and passed to the SetProperties method. Returns an array of (identifier, value) pairs containing the current values of the given properties. An array of property identifiers

An array of structs containing:

  • integer identifiers
  • variant boxed values
Some property identifier requested is invalid Some property requested does not have the PROPERTY_FLAG_READ flag
Returns a dictionary of the properties available on this channel. An array of structs containing:
  • an integer identifier
  • a string property name
  • a string representing the D-Bus signature of this property
  • a bitwise OR of the flags applicable to this property
Emitted when the value of readable properties has changed.

An array of structs containing:

  • integer identifiers
  • variant boxed values

The array should contain only properties whose values have actually changed.

Emitted when the flags of some room properties have changed.

An array of structs containing:

  • integer identifiers
  • a bitwise OR of the current flags

The array should contain only properties whose flags have actually changed.

Takes an array of (identifier, value) pairs containing desired values to set the given properties. In the case of any errors, no properties will be changed. When the changes have been acknowledged by the server, the PropertiesChanged signal will be emitted.

All properties given must have the PROPERTY_FLAG_WRITE flag, or PermissionDenied will be returned. If any variants are of the wrong type, NotAvailable will be returned. If any given property identifiers are invalid, InvalidArgument will be returned.

An array mapping integer property identifiers to boxed values

Interface for channels and other objects, to allow querying and setting properties. ListProperties returns which properties are valid for the given channel, including their type, and an integer handle used to refer to them in GetProperties, SetProperties, and the PropertiesChanged signal. The values are represented by D-Bus variant types, and are accompanied by flags indicating whether or not the property is readable or writable.

Each property also has a flags value to indicate what methods are available. This is a bitwise OR of PropertyFlags values.

The property can be read The property can be written
telepathy-qt-0.9.6~git1/spec/Client_Approver.xml0000664000175000017500000002331312470405660017522 0ustar jrjr Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as a stable interface)

Approvers are clients that notify the user that new channels have been created by a contact, and allow the user to accept or reject those channels. The new channels are represented by a ChannelDispatchOperation object, which is passed to the AddDispatchOperation method.

For instance, Empathy's tray icon, or the answer/reject window seen when a Maemo device receives a VoIP call, should be Approvers.

Approvers can also select which channel handler will be used for the channel, for instance by offering the user a list of possible handlers rather than just an accept/reject choice. However, the Channel Dispatcher must be able to prioritize possible handlers on its own using some reasonable heuristic, probably based on user configuration.

It is possible (and useful) to have an approver and a channel handler in the same process; this is particularly useful if a channel handler wants to claim responsibility for particular channels itself.

All approvers are notified simultaneously. For instance, in a desktop system, there might be one approver that displays a notification-area icon, one that is part of a contact list window and highlights contacts there, and one that is part of a full-screen media player.

Any approver can approve the handling of a channel dispatch operation with a particular channel handler by calling the HandleWith method. Approvers can also attempt to Claim channels; if this succeeds, the approver may handle the channels itself (if it is also a Handler), or close the channels in order to reject them.

At the D-Bus level, there is no "reject" operation: approvers wishing to reject channels SHOULD call the Claim method, then (if it succeeds) close the channels in any way they see fit.

The first approver to reply gets its decision acted on; any other approvers that reply at approximately the same time will get a D-Bus error, indicating that the channel has already been dealt with.

Approvers should usually prompt the user and ask for confirmation, rather than dispatching the channel to a handler straight away.

Non-interactive approvers can also be implemented as Observers as described in the interface description.

A specification of the channels in which this approver is interested. The AddDispatchOperation method should be called by the channel dispatcher whenever at least one of the channels in a channel dispatch operation matches this description.

This property works in exactly the same way as the Client.Observer.ObserverChannelFilter property. In particular, it cannot change while the approver process continues to own the corresponding Client bus name.

In the .client file, it is represented in the same way as ObserverChannelFilter, but the group has the same name as this interface and the keys start with ApproverChannelFilter instead of ObserverChannelFilter.

Called by the channel dispatcher when a ChannelDispatchOperation in which the approver has registered an interest is created, or when the approver starts up while such channel dispatch operations already exist.

The channel dispatcher SHOULD call this method on all approvers at the same time. If an approver returns an error from this method, the approver is assumed to be faulty.

If no approvers return from this method successfully (including situations where there are no matching approvers at all), the channel dispatcher SHOULD consider this to be an error, and recover by dispatching the channel to the most preferred handler.

Processes that aren't approvers (or don't at least ensure that there is some approver) probably shouldn't be making connections anyway, so there should always be at least one approver running.

The initial value of the ChannelDispatchOperation.Channels property, containing the Channels to be dispatched and their properties.

This can't be signalled to the approver through the Properties parameter of this method, because Channels is not an immutable property.

This argument always contains all of the channels in the channel dispatch operation, even if not all of them actually match the ApproverChannelFilter.

This seems the least bad way to handle such a situation; see the discussion on bug #21090.

The actual channels to be dispatched may reduce as channels are closed: this is signalled by ChannelDispatchOperation.ChannelLost.

Approvers SHOULD connect to ChannelLost and ChannelDispatchOperation.Finished. (if desired) before returning from AddDispatchOperation, since those signals are guaranteed not to be emitted until after all AddDispatchOperation calls have returned (with success or failure) or timed out.

The ChannelDispatchOperation to be processed.

Properties of the channel dispatch operation. The keys MUST be fully qualified D-Bus property names. This MUST NOT include properties that could change, SHOULD include as many properties as possible given that constraint, and MUST include at least the Account, Connection and PossibleHandlers properties.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Service_Point.xml0000664000175000017500000001021012470405660022577 0ustar jrjr Copyright © 2005-2010 Nokia Corporation Copyright © 2005-2010 Collabora Ltd

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface for channels that can indicate when/if they are connected to some form of service point. For example, when dialing 9-1-1 in the US, a GSM modem/network will recognize that as an emergency call, and inform higher levels of the stack that the call is being handled by an emergency service. In this example, the call is handled by a Public Safety Answering Point (PSAP) which is labeled as "urn:service:sos". Other networks and protocols may handle this differently while still using this interface.

Note that while the majority of examples given in this documentation are for GSM calls, they could just as easily be SIP calls, GSM SMS's, etc.

This property is used to indicate that the channel target is a well-known service point. Please note that the CM (or lower layers of the stack or network) may forward the connection to other other service points, which the CM SHOULD indicate via ServicePointChanged signal.

This property SHOULD be set for channel requests that are specifically targeting service points.

The service point that the channel is connected to. If the channel is not connected to a service point, the CM MUST set the Service_Point_Type field to None; for instance, this will be the case for ordinary calls.

Emitted when a channel changes the service point that it's connected to. This might be a new call being connected to a service, a call connected to a service being routed to a different service (ie, an emergency call being routed from a generic emergency PSAP to a poison control PSAP), or any number of other things.

Note that this should be emitted as soon as the CM has been notified of the switch, and has updated its internal state. The CM MAY still be in the process of connecting to the new service point.

The new service point that is being used.
telepathy-qt-0.9.6~git1/spec/Channel_Handler.xml0000664000175000017500000000562612470405660017442 0ustar jrjr Copyright (C) 2007-2008 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

Clients should implement Client.Handler instead.

An interface exported by Mission Control 4 client applications which are able to handle incoming channels.

Called when a channel handler should handle a new channel. The bus name of the connection and channel The object-path of the connection that owns the channel The channel type The object-path of the channel The type of the handle that the channel communicates with, or 0 if there is no associated handle The handle that the channel communicates with, or 0 if there is no associated handle
telepathy-qt-0.9.6~git1/spec/Account_Manager_Interface_Hidden.xml0000664000175000017500000000774312470405660022720 0ustar jrjr Copyright © 2010 Collabora Ltd. Copyright © 2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

This interface lists accounts whose Hidden property is True.

first draft A list of valid (complete, usable) Accounts intended exclusively for noninteractive applications. These accounts are not included in AccountManager.ValidAccounts. Change notification is via HiddenAccountValidityChanged. A list of incomplete or otherwise unusable Accounts intended exclusively for noninteractive applications. Change notification is via HiddenAccountValidityChanged. The given account has been removed from ValidHiddenAccounts or InvalidHiddenAccounts. An Account, which must not be used any more. The validity of the given account has changed. New magic accounts are also indicated by this signal, as an account validity change (usually to True) on an account that did not previously exist. This is effectively change notification for the valid and invalid accounts lists. An Account. True if the account is now valid.
telepathy-qt-0.9.6~git1/spec/Media_Session_Handler.xml0000664000175000017500000000702212470405660020604 0ustar jrjr Copyright (C) 2005, 2006 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

Use StreamHandler.Error on each StreamHandler object instead. Informs the connection manager that an error occured in this session. If used, the connection manager must terminate the session and all of the streams within it, and may also emit a StreamError signal on the channel for each stream within the session. The path of a new object implementing the StreamHandler interface. The unique ID of the new stream Type of media that this stream should handle Direction of this stream Emitted when a new stream handler has been created for this session. Inform the connection manager that a client is ready to handle this session handler (i.e. that it has connected to the NewStreamHandler signal and done any other necessary setup). An media session handler is an object that handles a number of synchronised media streams.
telepathy-qt-0.9.6~git1/spec/Account_Interface_Addressing.xml0000664000175000017500000001014012470405660022137 0ustar jrjr Copyright © 2010 Collabora Ltd

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API) The standard D-Bus PropertiesChanged signal is now used for URISchemes property change notifications.

Some accounts can be used for multiple protocols; for instance, SIP and Skype accounts can often be used to contact the PSTN, MSN and Yahoo accounts can contact each other, and XMPP accounts can potentially contact many protocols via a transport.

However, if the user does not intend to make use of this functionality, user interfaces can improve clarity by not displaying it: for instance, if a user prefers to call phone numbers via a particular SIP account, when an address book displays a contact with a phone number, it is desirable to display a "call with SIP" button for that account, but avoid displaying similar buttons for any other configured SIP or Skype accounts.

The purpose of this interface is to allow this "for use with" information to be recorded and retrieved.

A list of fields indicating the type of URI addressing scheme the the account should be used for (eg 'tel') indicating the account is intended for use by applications offering a telephony UI, or 'sip' or 'xmpp' for those protocols

Note that these fields signify intent, not ability: It is entirely possible that an account which can be used for a given URI scheme is not wanted for it by the user, and therefore not flagged as such in this field.

Change notification for this property is provided by the standard D-Bus PropertiesChanged signal.

Associate (or disassociate) an account with a particular URI addressing scheme, (such as 'tel' for telephony)

URI scheme to associate/disassociate the account with/from

True to associate this account with a given addressing scheme

False if the account should not be associated with said scheme

telepathy-qt-0.9.6~git1/spec/Channel_Interface_SASL_Authentication.xml0000664000175000017500000010344312470405660023642 0ustar jrjr Copyright © 2010 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

A channel interface for SASL authentication, as defined by RFC 4422. When this interface appears on a ServerAuthentication channel, it represents authentication with the server. In future, it could also be used to authenticate with secondary services, or even to authenticate end-to-end connections with contacts. As a result, this interface does not REQUIRE ServerAuthentication to allow for a potential future Channel.Type.PeerAuthentication interface.

In any protocol that requires a password, the connection manager can use this channel to let a user interface carry out a simple SASL-like handshake with it, as a way to get the user's credentials interactively. This can be used to connect to protocols that may require a password, without requiring that the password is saved in the Account.Parameters.

In some protocols, such as XMPP, authentication with the server is also carried out using SASL. In these protocols, a channel with this interface can provide a simple 1:1 mapping of the SASL negotiations taking place in the protocol, allowing more advanced clients to perform authentication via SASL mechanisms not known to the connection manager.

By providing SASL directly when the protocol supports it, we can use mechanisms like Kerberos or Google's X-GOOGLE-TOKEN without specific support in the connection manager.

For channels managed by a ChannelDispatcher, only the channel's Handler may call the methods on this interface. Other clients MAY observe the authentication process by watching its signals and properties.

There can only be one Handler, which is a good fit for SASL's 1-1 conversation between a client and a server.

A SASL mechanism, as defined by RFC 4422 and registered in the IANA registry of SASL mechanisms, or an unregistered SASL mechanism such as X-GOOGLE-TOKEN used in the same contexts.

As a special case, pseudo-mechanisms starting with X-TELEPATHY- are defined by this specification. Use of these pseudo-mechanisms indicates that the user's credentials are to be passed to the connection manager, which will then use them for authentication with the service, either by implementing the client side of some SASL mechanisms itself or by using a non-SASL protocol. The only such pseudo-mechanism currently defined is X-TELEPATHY-PASSWORD.

The X-TELEPATHY-PASSWORD mechanism is extremely simple:

  • The client MUST call StartMechanismWithData, with Initial_Data set to the password encoded in UTF-8. For simplicity, calling StartMechanism followed by calling Respond is not allowed in this mechanism.
  • The connection manager uses the password, together with authentication details from the Connection parameters, to authenticate itself to the server.
  • When the connection manager finishes its attempt to authenticate to the server, the channel's state changes to either SASL_Status_Server_Succeeded or SASL_Status_Server_Failed as appropriate.

The SASL mechanisms as offered by the server, plus any pseudo-SASL mechanisms supported by the connection manager for credentials transfer. For instance, in a protocol that natively uses SASL (like XMPP), this might be [ "X-TELEPATHY-PASSWORD", "PLAIN", "DIGEST-MD5", "SCRAM-SHA-1" ].

To make it possible to implement a very simple password-querying user interface without knowledge of any particular SASL mechanism, implementations of this interface MUST implement the pseudo-mechanism X-TELEPATHY-PASSWORD, unless none of the available mechanisms use a password at all.

If true, StartMechanismWithData can be expected to work for SASL mechanisms not starting with X-TELEPATHY- (this is the case in most, but not all, protocols). If false, StartMechanism must be used instead.

This property does not affect the X-TELEPATHY- pseudo-mechanisms such as X-TELEPATHY-PASSWORD, which can use StartMechanismWithData regardless of the value of this property.

If true, StartMechanism and (if supported) StartMechanismWithData can be expected to work when in one of the Failed states. If false, the only thing you can do after failure is to close the channel.

Retrying isn't required to work, although some protocols and implementations allow it.

The current status of this channel. Change notification is via the SASLStatusChanged signal.

The reason for the SASLStatus, or an empty string if the state is neither Server_Failed nor Client_Failed.

In particular, an ordinary authentication failure (as would be produced for an incorrect password) SHOULD be represented by AuthenticationFailed, cancellation by the user's request SHOULD be represented by Cancelled, and cancellation by a local process due to inconsistent or invalid challenges from the server SHOULD be represented by ServiceConfused.

If this interface appears on a ServerAuthentication channel, and connection to the server fails with an authentication failure, this error code SHOULD be copied into the Connection.ConnectionError signal.

If SASLError is non-empty, any additional information about the last disconnection; otherwise, the empty map. The keys and values are the same as for the second argument of Connection.ConnectionError.

If this interface appears on a ServerAuthentication channel, and connection to the server fails with an authentication failure, these details SHOULD be copied into the Connection.ConnectionError signal.

The identity for which authorization is being attempted, typically the 'account' from the RequestConnection parameters, normalized and formatted according to the conventions used for SASL in this protocol.

The normalization used for SASL might not be the same normalization used elsewhere: for instance, in a protocol with email-like identifiers such as XMPP or SIP, the user "juliet@example.com" might have to authenticate to the example.com server via SASL PLAIN as "juliet".

This is usually achieved by using the authorization identity for authentication, but an advanced Handler could offer the option to authenticate under a different identity.

The terminology used here is that the authorization identity is who you want to act as, and the authentication identity is used to prove that you may do so. For instance, if Juliet is authorized to access a role account, "sysadmin@example.com", and act on its behalf, it might be possible to authenticate as "juliet@example.com" with her own password, but request to be authorized as "sysadmin@example.com" instead of her own account. See RFC 4422 §3.4.1 for more details.

In SASL the authorization identity is normally guessed from the authentication identity, but the information available to the connection manager is the identity for which authorization is required, such as the desired JID in XMPP, so that's what we signal to UIs; it's up to the UI to choose whether to authenticate as the authorization identity or some other identity.

As a concrete example, the "sysadmin" XMPP account mentioned above would have { 'account': 'sysadmin@example.com' } in its Parameters, and this property would also be 'sysadmin@example.com'. A simple Handler would merely prompt for sysadmin@example.com's password, and use that JID as both the authorization and authentication identity, which might result in SASL PLAIN authentication with the initial response '\000sysadmin@example.com\000root'.

A more advanced Handler might also ask for an authentication identity, defaulting to 'sysadmin@example.com'; if Juliet provided authentication identity 'juliet@example.com' and password 'romeo', the Handler might perform SASL PLAIN authentication using the initial response 'sysadmin@example.com\000juliet@example.com\000romeo'.

The default username for use with SASL mechanisms that deal with a "simple username" (as defined in RFC 4422). If such a SASL mechanism is in use, clients SHOULD default to using the DefaultUsername; also, if the client uses the DefaultUsername, it SHOULD assume that the authorization identity AuthorizationIdentity will be derived from it by the server.

In XMPP, servers typically expect "user@example.com" to authenticate with username "user"; this was a SHOULD in RFC 3920.

3920bis weakens that SHOULD to "in the absence of local information provided by the server, an XMPP client SHOULD assume that the authentication identity for such a SASL mechanism is the combination of a user name and password, where the simple user name is the localpart of the user's JID".

For example, in the simple case, if the user connects with RequestConnection({ account: "user@example.com" }) and use PLAIN with password "password", he or she should authenticate like so: "\0user\0password" and the channel will look like this:

{ "...DefaultUsername": "user",
  "...AuthorizationIdentity": "user@example.com }

In the complex case, if the same user is using his or her sysadmin powers to log in as the "announcements" role address, he or she would connect with RequestConnection({ account: "announcements@example.com" }) and the SASL channel would look like this:

{ "...DefaultUsername": "announcements",
  "...AuthorizationIdentity": "announcements@example.com }

A sufficiently elaborate UI could give the opportunity to override the username from "announcements" to "user". The user's simple username is still "user", and the password is still "password", but this time he or she is trying to authorize to act as announcements@example.com, so the UI would have to perform SASL PLAIN with this string: "announcements@example.com\0user\0password", where "announcements@example.com" is the AuthorizationIdentity.

The default realm (as defined in RFC 2831) to use for authentication, if the server does not supply one.

The server is not required to provide a realm; if it doesn't, the client is expected to ask the user or provide a sensible default, typically the requested DNS name of the server. In some implementations of DIGEST-MD5, the server does not specify a realm, but expects that the client will choose a particular default, and authentication will fail if the client's default is different. Connection managers for protocols where this occurs are more easily able to work around these implementations than a generic client would be.

Whether or not the client can save the authentication response and re-use it to automate future authentication challenges.

If this property is False, the client SHOULD NOT attempt to cache the authentication response in its own keyring.

If this property is not specified, it should be treated as if it were True.

Some protocols or services may have terms and conditions that prohibit caching a user's credentials.
The chosen mechanism.

Start an authentication try using Mechanism, without sending initial data (an "initial response" as defined in RFC 4422).

This method is appropriate for mechanisms where the client cannot send anything until it receives a challenge from the server, such as DIGEST-MD5 in "initial authentication" mode.

The channel is not in a state where starting authentication makes sense (i.e. SASL_Status_Not_Started, or (if CanTryAgain is true) SASL_Status_Server_Failed or SASL_Status_Client_Failed). You should call AbortSASL and wait for SASL_Status_Client_Failed before starting another attempt. The server or connection manager doesn't implement the given SASL mechanism. Choose a SASL mechanism from AvailableMechanisms, or abort authentication if none of them are suitable.
The chosen mechanism. Initial data (an "initial response" in RFC 4422's terminology) to send with the mechanism.

Start an authentication try using Mechanism, and send Initial_Data as the "initial response" defined in RFC 4422 §3.3.

This method is appropriate for mechanisms where the client may send data first, such as PLAIN, or must send data first, such as DIGEST-MD5 in "subsequent authentication" mode.

Having two methods allows any mechanism where it makes a difference to distinguish between the absence of an initial response (StartMechanism) and a zero-byte initial response (StartMechanismWithData, with Initial_Data empty).

If the HasInitialData property is false, this indicates that the underlying protocol does not make it possible to send initial data. In such protocols, this method may only be used for the X-TELEPATHY- pseudo-mechanisms (such as X-TELEPATHY-PASSWORD), and will fail if used with an ordinary SASL mechanism.

For instance, the IRC SASL extension implemented in Charybdis and Atheme does not support initial data - the first message in the exchange only carries the mechanism. This is significant if using DIGEST-MD5, which cannot be used in the faster "subsequent authentication" mode on a protocol not supporting initial data.

The channel is not in a state where starting authentication makes sense (i.e. SASL_Status_Not_Started, or (if CanTryAgain is true) SASL_Status_Server_Failed or SASL_Status_Client_Failed). You should call AbortSASL and wait for SASL_Status_Client_Failed before starting another attempt. The server or connection manager doesn't implement the given SASL mechanism (choose one from AvailableMechanisms, or abort authentication if none of them are suitable), or doesn't allow initial data to be sent (as indicated by HasInitialData; call StartMechanism instead).
The response data.

Send a response to the the last challenge received via NewChallenge.

Either the state is not In_Progress, or no challenge has been received yet, or you have already responded to the last challenge.

If the channel's status is SASL_Status_Server_Succeeded, this method confirms successful authentication and advances the status of the channel to SASL_Status_Succeeded.

If the channel's status is SASL_Status_In_Progress, calling this method indicates that the last NewChallenge signal was in fact additional data sent after a successful SASL negotiation, and declares that from the client's point of view, authentication was successful. This advances the state of the channel to SASL_Status_Client_Accepted.

In mechanisms where the server authenticates itself to the client, calling this method indicates that the client considers this to have been successful. In the case of ServerAuthentication channels, this means that the connection manager MAY continue to connect, and MAY advance the Connection.Status to Connected.

Either the state is neither In_Progress nor Server_Succeeded, or no challenge has been received yet, or you have already responded to the last challenge.
Reason for abort. Debug message for abort.

Abort the current authentication try.

If the current status is SASL_Status_Server_Failed or SASL_Status_Client_Failed, this method returns successfully, but has no further effect. If the current status is SASL_Status_Succeeded or SASL_Status_Client_Accepted then NotAvailable is raised. Otherwise, it changes the channel's state to SASL_Status_Client_Failed, with an appropriate error name and reason code.

The current state is either Succeeded or Client_Accepted.
Emitted when the status of the channel changes. The new value of SASLStatus. The new value of SASLError. The new value of SASLErrorDetails.

Emitted when a new challenge is received from the server, or when a message indicating successful authentication and containing additional data is received from the server.

When the channel's handler is ready to proceed, it should respond to the challenge by calling Respond, or respond to the additional data by calling AcceptSASL. Alternatively, it may call AbortSASL to abort authentication.

The challenge data or additional data from the server.

A reason why SASL authentication was aborted by the client.

The server sent an invalid challenge or data. The user aborted the authentication.
The initial state. The Handler SHOULD either call AbortSASL, or connect to the NewChallenge signal then call StartMechanism or StartMechanismWithData. The challenge/response exchange is in progress. The Handler SHOULD call either Respond or AcceptSASL exactly once per emission of NewChallenge, or call AbortSASL at any time. The server has indicated successful authentication, and the connection manager is waiting for confirmation from the Handler. The Handler must call either AcceptSASL or AbortSASL to indicate whether it considers authentication to have been successful. The Handler has indicated successful authentication, and the connection manager is waiting for confirmation from the server. The state will progress to either Succeeded or Server_Failed when confirmation is received. Everyone is happy (the server sent success, and the client has called AcceptSASL). Connection to the server will proceed as soon as this state is reached. The Handler SHOULD call Close to close the channel. The server has indicated an authentication failure. If CanTryAgain is true, the client may try to authenticate again, by calling StartMechanism or StartMechanismWithData again. Otherwise, it should give up completely, by calling Close on the channel. The client has indicated an authentication failure. The possible actions are the same as for Server_Failed.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Client_Types.xml0000664000175000017500000002201712470405660023167 0ustar jrjr Copyright (C) 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface on connections to support protocols which allows users to subscribe to the client types of their contacts.

One can connect to instant messaging networks on a huge variety of devices, from PCs, to phones to consoles. It can be useful for users to know what kind of device a contact is using so that he or she can decide not to send that big file or start a video chat. This interface exposes exactly this information for clients to display.

The client types are represented in strings, using the values documented by the XMPP registrar with some additional types added for other protocols. A contact can set one or more client types so this interface returns a list of strings to denote client types for a contact. The well-known client types to be used are:

  • bot
  • console (minimal non-GUI client used on dumb terminals or text-only screens, not a games console)
  • handheld
  • pc
  • phone
  • web

If the empty list is given as the client types, this means that details about the contact's client types are unknown. If there are multiple resources of a contact online at one point in time, the client types of the most available resource will be returned. In other words, the returned client types are those for the resource whose presence will be retreived using the SimplePresence interface.

For example, if a contact has two resources:

  • their phone, with presence "available"; and
  • their pc, with presence "busy";

then the methods in this interface will return an array (with one element: "phone") as the client types because that is the more available resource. If at some later time the contact's phone's presence changes to "away", the ClientTypesUpdated signal will notify that the contact's client types attribute has changed from ["phone"] to ["pc"], because "busy" is a more available presence than "away".

A mapping from contact handle to client types. A contact. The contact's client types as documented earlier in this interface. Return the client types of the given contacts, if they are already known. If any of the given contacts' client types are not known, request their current client types, but return immediately without waiting for a reply; if a reply with a non-empty client type array is later received for those contacts, the ClientTypesUpdated signal will be emitted for them. This method is appropriate for "lazy" client type finding, for instance displaying the client types (if available) of everyone in your contact list. The contacts whose client types should be returned or signalled. The contacts' client types, if already known. Contacts whose client types are not already known are omitted from the mapping; contacts known to have no client type information appear in the mapping with an empty list. Return the current client types of the given contact. If necessary, make a request to the server for up-to-date information, and wait for a reply. This method is appropriate for use in a "Contact Information..." dialog; it can be used to show progress information (while waiting for the method to return), and can distinguish between various error conditions. The contact whose client types should be returned. The contact's client types. It MAY be empty, indicating that no client type information was found. The requested contact does not allow the local user to see their client type information. Emitted when a contact's client types change or become known. The contact. The contact's client types, or an empty list to indicate that nothing is known about the contact's client types.

The same mapping that would be returned by GetClientTypes for this contact. Omitted from the result if the contact's client types are not known.

A string representing a single client type of a contact.
telepathy-qt-0.9.6~git1/spec/Account_Interface_Storage.xml0000664000175000017500000001512712470405660021472 0ustar jrjr Copyright (C) 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

This interface extends the core Account interface to specify details regarding the storage of this account.

Single-sign-on systems do not generally have directly user-editable properties for Accounts, and require the user to visit a specific UI to alter their account properties. User interfaces should know not to expose these account properties as user-editable, and instead redirect the user to the appropriate interface.

The name of the account storage implementation, which SHOULD start with a reversed domain name in the same way as D-Bus interface names. When this is the empty string the account is internally stored.

This property cannot change once an Account has been created.

Unique identification of the account within the storage backend. The contents of the variant are defined by the StorageProvider.

This property cannot change once an Account has been created.

Different storage systems will have their own way of uniquely identifying an account, typically an integer or a string. Given that all users of this property should have direct knowledge of the backend they should know what types to expect and how to handle it.

Map containing information specific to the storage backend. The keys and the types of their values are defined by the StorageProvider, and are not interpreted by the AccountManager implementation.

As the values in this map may change at any time (due to an external application manipulating the storage provider directly), this property should not be cached; it should instead be retrieved each time it is needed.

This can be used to provide additional hints to user interfaces aware of a specific storage provider, without requiring those user interfaces to use the StorageIdentifier to query the storage provider directly.

Bitfield which defines what restrictions this Storage method has.

This property cannot change once an Account has been created.

Flags indicating restrictions imposed on an Account by its storage method. The account's Parameters property can't be changed by calling UpdateParameters. The account can't be enabled/disabled by setting the Enabled property. The account's presence can't be changed by setting the RequestedPresence and AutomaticPresence properties. The account's Service property cannot be changed.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Contact_List.xml0000664000175000017500000014600312470405660023155 0ustar jrjr Copyright © 2009-2010 Collabora Ltd. Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface for connections that have any concept of a list of known contacts (roster, buddy list, friends list etc.)

On many protocols, there's a server-side roster (as in XMPP), or a set of server-side lists that can be combined to form a roster (as in MSN).

In some protocols (like link-local XMPP), while there might not be any server or roster, it's possible to list "nearby" contacts.

In Telepathy 0.20 and older, we represented contact lists as a collection of ContactList channels. This is remarkably difficult to work with in practice - every client that cares about contact lists has to take the union of some hard-to-define set of these channels - and conflicts with the idea that channels that cannot be dispatched to a handler should be closed.

The list of contacts is not exposed as a D-Bus property; it can be fetched using GetContactListAttributes.

In some protocols, such as XMPP, the contact list may not be available immediately. The GetContactListAttributes method will fail until the contact list is available. Using a method also allows extra attributes to be retrieved at the same time.

The progress made in retrieving the contact list. The connection has not started to retrieve the contact list. If GetContactListAttributes is called in this state, it will raise NotYet. The connection has started to retrieve the contact list, but has not yet succeeded or failed. If GetContactListAttributes is called in this state, it will raise NotYet.

The connection has tried and failed to retrieve the contact list. If GetContactListAttributes is called in this state, it will immediately raise an error indicating the reason for failure.

The connection manager SHOULD try again to obtain the contact list, if appropriate for the protocol. If it succeeds later, the ContactListState MUST advance to Success.

The connection has successfully retrieved the contact list. If GetContactListAttributes is called in this state, it will return successfully.
The progress made in retrieving the contact list. Change notification is via ContactListStateChanged. Emitted when ContactListState changes. The new value of ContactListState.

Return some contact attributes for a list of contacts associated with the user. This list MUST include at least:

  • all contacts whose subscribe attribute is not No
  • all contacts whose publish attribute is not No

but MAY contain other contacts.

For instance, on XMPP, all contacts on the roster would appear here even if they have subscription="none", unless there's reason to believe the user does not want to see them (such as having been blocked).

This list does not need to contain every visible contact: for instance, contacts seen in XMPP or IRC chatrooms SHOULD NOT appear here. Blocked contacts SHOULD NOT appear here, unless they still have a non-No subscribe or publish attribute for some reason.

It's reasonable to assume that blocked contacts should not be visible to the user unless they specifically go looking for them, at least in protocols like XMPP where blocking a contact suppresses presence.

A list of strings indicating which D-Bus interfaces the calling process is interested in. Equivalent to the corresponding argument to GetContactAttributes, except that if this list does not contain the ContactList interface itself, it is treated as though that interface was also requested.

If true, all handles that appear as keys in the result have been held on behalf of the calling process, as if by a call to Connection.HoldHandles. (If HasImmortalHandles is true, which SHOULD be the case in all new connection managers, this has no effect.)

A dictionary mapping the contact handles to contact attributes, equivalent to the result of GetContactAttributes.

The ContactListState is None or Waiting. In particular, this error is raised if the Status is not yet Connection_Status_Connected.

An enumeration indicating whether presence subscription is denied, denied but pending permission, or allowed. The exact semantics vary according to where this type is used: see the subscribe and publish contact attributes for details.

The presence subscription state is unknown. Presence information cannot be seen, and either the subscription state Removed_Remotely does not apply, or it is not known whether that state applies. Presence information cannot be seen because the remote contact took action: either the local user's request to see the remote contact's presence was denied, or the remote contact requested to see the local user's presence but then cancelled their request. Presence information cannot be seen. Permission to see presence information has been requested, and the request has not yet been declined or accepted. Presence information can be seen.

If this attribute on a contact is Yes, this connection can expect to receive their presence, along with any other information that has the same access control.

This is subscription="from" or subscription="both" in XMPP, the "forward list" on MSN, or the contact being "added to the local user's buddy list" in ICQ, for example.

If this attribute is not Yes, the local user cannot generally expect to receive presence from this contact. Their presence status as returned by GetPresences is likely to be (Unknown, "unknown", ""), unless the local user can temporarily see their presence for some other reason (for instance, on XMPP, contacts seen in chatrooms will temporarily have available presence).

If this attribute is Ask, this indicates that the local user has asked to receive the contact's presence at some time. It is implementation-dependent whether contacts' subscribe attributes can remain set to Ask, or are reset to No, when the connection disconnects.

Some protocols store the fact that we wishes to see a contact's presence; on these protocols, this attribute can remain Ask indefinitely. On other protocols, only contacts who have been asked during the current session will ever have Ask status.

If this attribute is Removed_Remotely, this indicates that the local user has asked to receive the contact's presence at some time, but the remote contact has rejected that request, and a local user interface has not yet acknowledged this. It is implementation-dependent whether contacts' subscribe attributes can remain set to Removed_Remotely, or are reset to No, when the connection disconnects.

After notifying the user, user interfaces MAY acknowledge a change to subscribe=Removed_Remotely by calling either Unsubscribe or RemoveContacts, which will set subscribe to No (and perhaps remove the contact). This allows user interfaces to detect that the user has been notified about the rejected request.

This attribute's value will be Unknown or omitted until the ContactListState has changed to Success.

If this attribute on a contact is Yes, the local user's presence is published to that contact, along with any other information that shares an access-control mechanism with presence (depending on protocol, server configuration and/or user configuration, this may include avatars, "rich presence" such as location, etc.).

This is subscription="to" or subscription="both" in XMPP, the "reverse list" on MSN, or the state of "being added to the contact's buddy list" in ICQ, for example.

If this attribute is not Yes, the local user's presence is not published to that contact; however, if it is Ask, the contact has requested that the local user's presence is made available to them.

It is implementation-dependent whether contacts' publish attributes can remain set to Ask, or are reset to No, when the connection disconnects.

Some protocols store the fact that a contact wishes to see our presence; on these protocols, this attribute can remain Ask indefinitely. On other protocols, only contacts who have asked during the current session will ever have Ask status.

If this attribute is Removed_Remotely, this indicates that the remote contact has asked to receive the user's presence at some time, but has then cancelled that request before a response was given by the local user. User interfaces MAY reset publish from Removed_Remotely to No, by calling either Unpublish or RemoveContacts.

If multiple factors affect whether a contact can receive the local user's presence, this attribute SHOULD reflect the overall result. For instance, an XMPP contact with subscription="to" or subscription="both", but who has been blocked via XEP-0016 Privacy Lists, SHOULD have publish=No.

This attribute's value will be Unknown or omitted until the ContactListState has changed to Success.

If the publish attribute is Ask, an optional message that was sent by the contact asking to receive the local user's presence; omitted if none was given.

If the contact asking to receive our presence is also using Telepathy, this is the message they supplied as the Message argument to RequestSubscription.

Otherwise, this SHOULD be omitted.

This attribute will also be omitted until the ContactListState has changed to Success.

If true, presence subscriptions (in both directions) on this connection are stored by the server or other infrastructure.

XMPP, MSN, ICQ, etc. all behave like this.

If false, presence subscriptions on this connection are not stored.

In SIMPLE (SIP), clients are expected to keep a record of subscriptions, as described below. In link-local XMPP, subscriptions are implicit (everyone on the local network receives presence from everyone else) so nothing is ever stored.

If CanChangeContactList is true, Telepathy clients (e.g. user interfaces or address books) MAY keep a record of permission to publish and requests to subscribe locally, and attempt to restore it for each Connection. If ContactListPersists is false, clients MAY do this for all contacts; if ContactListPersists is true, clients SHOULD NOT change the state of contacts that were not changed locally.

In SIMPLE (SIP), ContactListPersists is false, but CanChangeContactList is true. Presence will not be received unless clients renew any subscriptions they have for each connection, in the way described. There is no server-side storage, so clients have no alternative but to maintain independent contact lists.

In protocols like XMPP and MSN, it may be useful for clients to queue up subscription requests or removals made while offline and process them next time the connection is online. However, clients should only replay the changes, rather than resetting the contact list to match a stored copy, to avoid overwriting changes that were made on the server.

Clients that replay requests like this SHOULD do so by calling AuthorizePublication to pre-approve publication of presence to the appropriate contacts, followed by RequestSubscription to request the appropriate contacts' presences.

This property cannot change after the connection has moved to the Connected state. Until then, its value is undefined, and it may change at any time, without notification.

Values of this enumeration indicate the extent to which metadata such as aliases and group memberships can be stored for the contacts on a particular connection.

On some protocols, certain metadata (for instance, contact aliases) can only be stored for contacts on the contact list, or contacts with a particular contact list state.

To make it easier to deal with such protocols, if clients set metadata on a contact who is not in the required state, the Connection MUST cache the metadata for the duration of the session. If clients request the attributes of that contact after the appropriate "set" method has returned successfully, the Connection MUST return the new (cached) value.

If the contact is later placed in the required state to store metadata (for instance, if subscription to the contact's presence is requested, on a protocol like MSN where the alias has storage type Subscribed_Or_Pending), the connection MUST store the cached metadata at that time.

If the Connection didn't cache changes in this way, a client intending to change the alias on MSN would have to wait until the server acknowledged the subscription request; in the meantime, other clients would still display the old alias.

The only exception to that general rule is that if the Connection cannot store particular metadata at all (i.e. the storage type is None), it MUST reject attempts to set it.

If the implementation knows that metadata can't be stored at all, it's useful to report that, which can be done synchronously. In general, user interfaces should detect storage type None and not display editing controls at all.

This connection cannot store this type of metadata at all, and attempting to do so will fail with NotImplemented.

Link-local XMPP can't store aliases or group memberships at all, and subscription and presence states are implicit (all contacts on the local network have subscribe = publish = Yes and no other contacts exist).

As of April 2010, the XMPP server for Facebook Chat provides a read-only view of the user's Facebook contacts, so it could also usefully have this storage type.

This type of metadata can only be stored permanently for contacts whose subscribe attribute is Ask or Yes.

Contact aliases and groups on MSN have this behaviour.

This type of metadata can only be stored permanently for contacts whose subscribe attribute is Yes.

No service with this behaviour is currently known, but it's a stricter form of Subscribed_Or_Pending.

The user can set this metadata for any valid contact identifier, whether or not they have any presence subscription relationship to it, and it will be stored on their contact list.

Contact aliases and groups on XMPP have this behaviour; it is possible to put a contact in a group, or assign an alias to them, without requesting that presence be shared.

A single contact's subscribe, publish and publish-request attributes. The new value of the contact's "subscribe" attribute. The new value of the contact's "publish" attribute. The new value of the contact's "publish-request" attribute, or the empty string if that attribute would be omitted. A map from contacts to their subscribe, publish and publish-request attributes. The contact's handle. The contact's subscribe, publish and publish-request attributes.

Emitted when the contact list becomes available, when contacts' basic stored properties change, when new contacts are added to the list that would be returned by GetContactListAttributes, or when contacts are removed from that list.

This provides change notification for that list, and for contacts' subscribe, publish and publish-request attributes.

Connection managers SHOULD also emit this signal when a contact requests that the user's presence is published to them, even if that contact's publish attribute is already Ask and the publish-request has not changed.

If the same contact sends 10 identical requests, 10 identical signals should be emitted.

The new subscribe, publish and publish-request attributes of all the contacts that have been added, and all the contacts for which those attributes have changed. The identifiers of the contacts in the Changes map. The contacts that have been removed from the list that would be returned by GetContactListAttributes. This also implies that they have subscribe = No and publish = No; contacts MUST NOT be listed both here and in Changes.
Connection managers MUST still emit this signal, but clients SHOULD listen for the ContactsChangedWithID signal in addition, and ignore this signal after ContactsChangedWithID has been emitted at least once.

Emitted immediately after ContactsChangedWithID, under the same circumstances.

If clients receive this signal without first receiving a corresponding ContactsChangedWithID, they MUST assume that only this signal will be emitted.

The same as the corresponding argument to ContactsChangedWithID. The same as the corresponding argument to ContactsChangedWithID, except that it only includes handles and not identifiers.

If true, presence subscription and publication can be changed using the RequestSubscription, AuthorizePublication and RemoveContacts methods.

If false, all of those methods will always fail; they SHOULD raise the error org.freedesktop.Telepathy.Error.NotImplemented.

In XEP-0174 "Serverless Messaging" (link-local XMPP), presence is implicitly published to everyone in the local subnet, so the user cannot control their presence publication.

This property cannot change after the connection has moved to the Connected state. Until then, its value is undefined, and it may change at any time, without notification.

Request that the given contacts allow the local user to subscribe to their presence, i.e. that their subscribe attribute becomes Yes.

Connection managers SHOULD NOT attempt to enforce a mutual-subscription policy (i.e. when this method is called, they should not automatically allow the contacts to see the local user's presence). User interfaces that require mutual subscription MAY call AuthorizePublication at the same time as this method.

Whether to enforce mutual subscription is a matter of policy, so it is left to the user interface and/or the server.

Before calling this method on a connection where GetAliasFlags returns the User_Set flag, user interfaces SHOULD obtain, from the user, an alias to identify the contact in future, and store it using SetAliases.

The user MAY be prompted using the contact's current self-assigned nickname, or something derived from the contact's (presumably self-assigned) identifier, as a default, but these names chosen by the contact SHOULD NOT be used without user approval.

This is a generalization of XEP-0165 "Best Practices to Discourage JID Mimicking") to protocols other than XMPP. A reasonable user interface for this, as used in many XMPP clients, is to have a text entry for the alias adjacent to the text entry for the identifier to add.

For contacts with subscribe=Yes, this method has no effect. It MUST return successfully if all contacts are in this state.

For contacts with subscribe=Ask, this method SHOULD send a new request, with the given message, if allowed by the underlying protocol.

For contacts with subscribe=No or subscribe=Rejected, this method SHOULD request that the contact allows the local user to subscribe to their presence; in general, this will change their publish attribute to Ask (although it could change directly to Yes in some situations).

Any state changes that immediately result from this request MUST be signalled via ContactsChanged before this method returns.

This makes it easy for user interfaces to see what practical effect this method had.

If the remote contact accepts the request, their subscribe attribute will later change from Ask to Yes.

If the remote contact explicitly rejects the request (in protocols that allow this), their subscribe attribute will later change from Ask to Rejected.

If the subscription request is cancelled by the local user, the contact's subscribe attribute will change from Ask to No.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState changes to Failure, this method SHOULD raise the same error as GetContactListAttributes.

One or more contacts to whom requests are to be sent.

An optional plain-text message from the user, to send to those contacts with the subscription request. The RequestUsesMessage property indicates whether this message will be used or ignored.

Clients SHOULD NOT send a non-empty message without first giving the user an opportunity to edit it.

These messages are typically presented to the remote contact as if the user had typed them, so as a minimum, the user should be allowed to see what the UI will be saying on their behalf.

Connections where this message is not useful MUST still allow it to be non-empty.

The ContactListState is None or Waiting. It was not possible to perform the requested action, because CanChangeContactList is false.

If true, the Message parameter to RequestSubscription is likely to be significant, and user interfaces SHOULD prompt the user for a message to send with the request; a message such as "I would like to add you to my contact list", translated into the local user's language, might make a suitable default.

This matches user expectations in XMPP and ICQ, for instance.

If false, the parameter is ignored; user interfaces SHOULD avoid prompting the user, and SHOULD pass an empty string to RequestSubscription.

FIXME: is there any such protocol?

If true, the contact list is automatically downloaded at connection. If false, the contact list is only downloaded when requested explicitely with Download.

Downloading the contact list uses bandwidth and is not always necessary or desired. For example, a client could cache the contact list from previous connections and accept less regular updates, it could get the contact list from an out-of-band protocol-specific way, or it could not need the contact list at all.

Connection managers MUST default to true.

If a connection manager starts supporting this property but defaults to false, it would break all existing clients that don't call Download.

For each of the given contacts, request that the local user's presence is sent to that contact, i.e. that their publish attribute becomes Yes.

Connection managers SHOULD NOT attempt to enforce a mutual-subscription policy (i.e. when this method is called, they should not automatically request that the contacts allow the user to subscribe to their presence). User interfaces that require mutual subscription MAY call RequestSubscription at the same time as this method.

Whether to enforce mutual subscription is a matter of policy, so it is left to the user interface and/or the server.

For contacts with publish=Yes, this method has no effect; it MUST return successfully if all contacts given have this state.

For contacts with publish=Ask, this method accepts the contact's request to see the local user's presence, changing their publish attribute from Ask to Yes.

For contacts with publish=No, if the protocol allows it, this method allows the contacts to see the local user's presence even though they have not requested it, changing their publish attribute from No to Yes. Otherwise, it merely records the fact that presence publication to those contacts is allowed; if any of those contacts ask to receive the local user's presence later in the lifetime of the connection, the connection SHOULD immediately allow them to do so, changing their publish attribute directly from No to Yes.

This makes it easy to implement the common UI policy that if the user attempts to subscribe to a contact's presence, requests for reciprocal subscription are automatically approved.

Any state changes that immediately result from this request MUST be signalled via ContactsChanged before this method returns.

This makes it easy for user interfaces to see what practical effect this method had.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState changes to Failure, this method SHOULD raise the same error as GetContactListAttributes.

One or more contacts to authorize.

It was not possible to perform the requested action, because CanChangeContactList is false. The ContactListState is None or Waiting.

Remove the given contacts from the contact list entirely. It is protocol-dependent whether this works, and under which circumstances.

If possible, this method SHOULD set the contacts' subscribe and publish attributes to No, remove any stored aliases for those contacts, and remove the contacts from the result of GetContactListAttributes.

This method SHOULD succeed even if it was not possible to carry out the request entirely or for all contacts (for instance, if there is an outstanding request to subscribe to the contact's presence, and it's not possible to cancel such requests). However, all signals that immediately result from this method call MUST be emitted before it returns, so that clients can interpret the result.

User interfaces removing a contact from the contact list are unlikely to want spurious failure notifications resulting from limitations of a particular protocol. However, emitting the signals first means that if a client does want to check exactly what happened, it can wait for the method to return (while applying change-notification signals to its local cache of the contact list's state), then consult its local cache of the contact list's state to see whether the contact is still there.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState changes to Failure, this method SHOULD raise the same error as GetContactListAttributes.

One or more contacts to remove.

It was not possible to perform the requested action because CanChangeContactList is false. The ContactListState is None or Waiting.

Attempt to set the given contacts' subscribe attribute to No, i.e. stop receiving their presence.

For contacts with subscribe=Ask, this attempts to cancel an earlier request to subscribe to the contact's presence; for contacts with subscribe=Yes, this attempts to unsubscribe from the contact's presence.

As with RemoveContacts, this method SHOULD succeed even if it was not possible to carry out the request entirely or for all contacts; however, all signals that immediately result from this method call MUST be emitted before it returns.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState changes to Failure, this method SHOULD raise the same error as GetContactListAttributes.

One or more contacts to remove.

It was not possible to perform the requested action because CanChangeContactList is false.

Attempt to set the given contacts' publish attribute to No, i.e. stop sending presence to them.

For contacts with publish=Ask, this method explicitly rejects the contact's request to subscribe to the user's presence; for contacts with publish=Yes, this method attempts to prevent the user's presence from being received by the contact.

As with RemoveContacts, this method SHOULD succeed even if it was not possible to carry out the request entirely or for all contacts; however, all signals that immediately result from this method call MUST be emitted before it returns.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState changes to Failure, this method SHOULD raise the same error as GetContactListAttributes.

One or more contacts to remove.

It was not possible to perform the requested action because CanChangeContactList is false. The ContactListState is None or Waiting.

Download the contact list from the server. If DownloadAtConnection is true, Download does nothing.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Mergeable_Conference.xml0000664000175000017500000001164612470405660024056 0ustar jrjr Copyright © 2009 Collabora Limited Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft 1)

An interface for multi-user conference channels that can have additional individual channels merged into them after they are created.

This interface addresses part of freedesktop.org bug #24906 (GSM-compatible conference calls). GSM is currently the only protocol known to implement this; PBXs might implement it too.

It might be made into a mandatory-to-implement part of Conference, or kept as a separate interface, when stabilized.

Request that the given channel be incorporated into this channel.

The given channel SHOULD be added to Conference.Channels if and only if the underlying protocol signals the merge in some way. It MUST NOT be added to Conference.InitialChannels (to preserve immutability).

In GSM it is possible to merge additional calls into an ongoing conference.

In XMPP this method could be implemented to merge a 1-1 Text channel into a MUC Text channel by inviting the peer from the Text channel into the MUC, or to merge a 1-1 Jingle call into a Muji call by inviting the peer from the Jingle call into the Muji call. (MUC and Muji channels are both implemented by XMPP MUCs, with Handle_Type_Room.)

A channel with the same ChannelType as this one, but with TargetHandleType = CONTACT.

The given channel isn't suitable for merging into this one: for instance, it might have the wrong channel type or handle type. It will never be possible to merge channels into this particular conference. The given channel is theoretically suitable for merging into this one, but that's not currently possible for some reason (for instance, this SHOULD be raised if a limit on the number of channels in a conference is exceeded). [FIXME: PermissionDenied?]
telepathy-qt-0.9.6~git1/spec/Channel_Interface_SMS.xml0000664000175000017500000003140612470405660020502 0ustar jrjr Copyright © 2008–2010 Nokia Corporation Copyright © 2010 Collabora Ltd. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library 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. Imported from rtcom-telepathy-glib, with the unused properties removed and the documentation tidied up.

This interface contains SMS-specific properties for text channels.

The presence of this interface on a channel does not imply that messages will be delivered via SMS.

This interface MAY appear in the Interfaces property of channels where SMSChannel would be immutable and false. It SHOULD appear on channels where SMSChannel is immutable and true, and also on channels where SMSChannel is mutable (i.e. channels that might fall back to sending SMS at any time, such as on MSN).

Handler filters

A handler for class 0 SMSes should advertise the following filter:

{ ...ChannelType: ...Text,
  ...TargetHandleType: Contact,
  ...SMS.Flash: True,
}

It should also set its BypassApproval property to True, so that it is invoked immediately for new channels.

Contact Capabilities

Contacts to whom SMSes can be sent SHOULD indicate this via a requestable channel class with SMSChannel = True as a fixed property.

For instance, a contact that can accept both text and SMS channels:

[
({ ...ChannelType: ...Text,
   ...TargetHandleType: Contact,
 },
 [ ...TargetHandle, ...TargetID ]),

({ ...ChannelType: ...Text,
   ...TargetHandleType: Contact,
   ...SMSChannel: True,
 },
 [ ...TargetHandle, ...TargetID ]),
]

If True, then this channel is exclusively for receiving class 0 SMSes (and no SMSes can be sent using SendMessage on this channel). If False, no incoming class 0 SMSes will appear on this channel.

This property is immutable (cannot change), and therefore SHOULD appear wherever immutable properties are reported, e.g. NewChannels signals.

Class 0 SMSes should be displayed immediately to the user, and need not be saved to the device memory unless the user explicitly chooses to do so. This is unlike “normal”, class 1 SMSes, which must be stored, but need not be shown immediately in their entirity to the user.

Separating class 0 SMSes into their own channel with this immutable property allows them to be dispatched to a different Handler—which would include this property in its HandlerChannelFilter—avoiding the normal Text channel handler having to decide for each message whether it should be displayed to the user immediately or handled normally.

Currently, no mechanism is defined for sending class 0 SMSes. It seems reasonable to support specifying the class of an outgoing SMS in its header Message_Part, rather than requiring the UI to request a special channel for such SMSes; hence, we define here that channels with Flash set to True are read-only.

If TRUE, messages sent and received on this channel are transmitted via SMS.

If this property is included in the channel request, the Connection Manager MUST return an appropriate channel (i.e. if TRUE the channel must be for SMSes, if FALSE it must not), or else fail to provide the requested channel with the NotCapable error.

For example, to explicitly request an SMS channel to a contact. You might construct a channel request like:

{
  Channel.Type: Channel.Type.Text,
  Channel.TargetHandleType: Handle_Type_Contact,
  Channel.TargetID: escher.cat,
  Channel.Interface.SMS.SMSChannel: True,
}
Some protocols allow us to send SMSes to a remote contact, without knowing the phone number to which those SMSes will be sent. This provides a mechanism to request such channels.

If this property is not included in the channel request, the Connection Manager MAY return an SMS channel if that is the most appropriate medium (i.e. if the channel target is a phone number).

To some types of identifiers (i.e. phone numbers) it only makes sense to return an SMS channel, this is what happens currently with telepathy-ring. We don't want to break this behaviour when we are not explicit about the type of channel we want. Alternatively, for protocols where there is an SMS fallback for IM messages, it's possible that we don't care what sort of channel we get, and simply want notification of the transport.

Some protocols have a fallback to deliver IM messages via SMS. On these protocols, the Connection Manager SHOULD set the property value as appropriate, and notify its change with SMSChannelChanged.

Protocols such as MSN can fall back to delivering IM messages via SMS. Where possible we want clients to be able to inform the user that their messages are going to be redirected to the remote contact's phone.
The new value for SMSChannel. This signal indicates a change in the SMSChannel property.

Returns the number of 140 octet chunks required to send a message via SMS, as well as the number of remaining characters available in the final chunk and, if possible, an estimate of the cost.

There are a number of different SMS encoding mechanisms, and the client doesn't know which mechanisms an individual CM might support. This method allows the client, without any knowledge of the encoding mechanism, to provide length details to the user.

Clients SHOULD limit the frequency with which this method is called and SHOULD NOT call it for every keystroke. Clients MAY estimate the remaining size between single keystrokes.

The message the user wishes to send.

The number of 140 octet chunks required to send this message.

For example, in the GSM standard 7-bit encoding, a 162 character message would require 2 chunks.

The number of further characters that can be fit in the final chunk. A negative value indicates that the message will be truncated by abs(Remaining_Characters). The value MIN_INT32 (-231) indicates the message will be truncated by an unknown amount.

For example, in the GSM standard 7-bit encoding, a 162 character message would return 144 remaining characters (because of the space required for the multipart SMS header).

The estimated cost of sending this message. The currency and scale of this value are the same as the Balance.AccountBalance property.

A value of -1 indicates the cost could not be estimated.

Raised when the method is not available on this channel. Clients MAY choose to make their own estimation. Raised when the content cannot be encoded into a valid SMS.
telepathy-qt-0.9.6~git1/spec/Client.xml0000664000175000017500000001424012470405660015643 0ustar jrjr Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as a stable interface)

Telepathy clients use connection managers, the channel dispatcher and optionally the account manager to provide useful functionality.

User interface processes are the obvious example of Telepathy clients, but they can provide other functionality, such as address-book synchronization.

Every running or activatable process with a well-known name of the form org.freedesktop.Telepathy.Client.clientname should be probed by the channel dispatcher to discover its capabilities. Each client is either an observer, an approver, a channel handler, or some combination of these.

Activatable services (those with a D-Bus .service file) must be supported so that we can run clients in response to channel creation.

Non-activatable services (those that do not register a D-Bus .service file for their well-known name, but do request it at runtime) must be supported so that we can have programs that process channels, but only if they are already running - for instance, a full-screen media centre application might do this.

The client name, clientname, MUST be a non-empty string of ASCII digits, letters, dots and/or underscores, starting with a letter, and without sets of two consecutive dots or a dot followed by a digit. For non-activatable services, it MAY contain a part that is generated per instance at runtime.

If each of a client Foo's instances should be able to manipulate channels separately, the instance with unique name :1.25 might request a well-known name like org.freedesktop.Telepathy.Client.Foo._1._25.

(Note that well-known bus-name components may not start with a digit, so o.f.T.Client.Foo.1.25 would not be acceptable.)

Each Client MUST export an object whose object path may be determined by replacing '.' with '/' in the well-known name and prepending '/'. This object represents its API as a Telepathy client; the channel dispatcher will call its methods and read its properties when appropriate.

As an optimization, activatable clients SHOULD install a file $XDG_DATA_DIRS/telepathy/clients/clientname.client containing a cached version of its immutable properties, so that for most clients, the channel dispatcher can just read a file to discover capabilities, instead of having to service-activate the client immediately in order to fetch its read-only properties. However, the D-Bus API is canonical, and the channel dispatcher MUST support clients without such a file.

Non-activatable clients MAY install a .client file, but there's not much point in them doing so.

The .client files MUST contain UTF-8 text with the same syntax as Desktop Entry files (although the allowed groups, keys and values differ). Every .client file MUST contain a group whose name is the name of this interface.

The groups, keys and values in the .client file are defined by individual interfaces. Each interface that can usefully cache information in the .client file SHOULD correspond to a group with the same name.

A list of the extra interfaces provided by this client. This SHOULD include at least one of Client.Observer, Client.Approver or Client.Handler.

In the .client file, this is represented by key "Interfaces" in the group named after this interface. The value of the key is a list of interface names each followed by a semicolon (so it always ends with a semicolon unless it is empty), i.e. a key of type "strings" as described in the Desktop Entry specification.

telepathy-qt-0.9.6~git1/spec/Connection.xml0000664000175000017500000016446212470405660016540 0ustar jrjr Copyright (C) 2005-2009 Collabora Limited Copyright (C) 2005-2009 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A struct representing a channel, as returned by ListChannels on the Connection interface. The object path of the channel, which is on the same bus name as the connection The channel's type The type of the handle that the channel communicates with, or Handle_Type_None if there is no associated handle The handle that the channel communicates with, or 0 if there is no associated handle

Request that the connection be established. This will be done asynchronously and errors will be returned by emitting StatusChanged signals.

Calling this method on a Connection that is already connecting or connected is allowed, and has no effect.

Request that the connection be closed. This closes the connection if it's not already in DISCONNECTED state, and destroys the connection object.

The set of optional interfaces supported by this connection. Before the connection status changes to CONNECTED, this property may change at any time, but it is guaranteed that interfaces will only be added, not removed. After the connection status changes to CONNECTED, this property cannot change further.

There is no explicit change notification; reasonable behaviour for a client would be to retrieve the interfaces list once initially, and once more when it becomes CONNECTED.

In some connection managers, certain capabilities of a connection are known to be implemented for all connections (e.g. support for SimplePresence), and some interfaces (like SimplePresence) can even be used before connecting. Other capabilities may or may not exist, depending on server functionality; by the time the connection goes CONNECTED, the connection manager is expected to have evaluated the server's functionality and enabled any extra interfaces for the remainder of the Connection's lifetime.

Clients SHOULD fall back to calling GetInterfaces if this property is not supported.
The value of the Interfaces property

Returns the set of optional interfaces supported by this connection. See Interfaces for more details.

Before version 0.17.8 calling GetInterfaces while on a connection that is not yet CONNECTED wasn't allowed. If a CM returns this error, its list of interfaces should be regarded as empty until it becomes CONNECTED.
A string identifier for the protocol Get the protocol this connection is using. Emitted whenever the SelfHandle property changes. If the connection is not yet in the CONNECTED state, this signal is not guaranteed to be emitted. Clients MAY assume that if the SelfHandle property exists, this signal will be emitted when necessary. Use SelfContactChanged to get the new SelfID at the same time The new value of the SelfHandle property. Emitted whenever the SelfHandle and SelfID property changes. If the connection is not yet in the CONNECTED state, this signal is not guaranteed to be emitted. Clients MAY assume that if the SelfHandle and SelfID property exists, this signal will be emitted when necessary. The new value of the SelfHandle property. The new value of the SelfID property. The handle which represents the user on this connection, which will remain valid for the lifetime of this connection, or until a change in the user's identifier is signalled by the SelfContactChanged signal. If the connection is not yet in the CONNECTED state, the value of this property MAY be zero. For compatibility with older versions, clients should fall back to calling the GetSelfHandle method. The identifier which represents the user on this connection, which will remain valid for the lifetime of this connection, or until a change in the user's identifier is signalled by the SelfContactChanged signal. If the connection is not yet in the CONNECTED state, the value of this property MAY be empty string. The value of the SelfHandle property Returns the value of the SelfHandle property. Change notification is via the SelfHandleChanged signal. Use GetAll to get the SelfHandle property (and all other Connection properties) instead.

The current status of the connection. Change notification is via the StatusChanged signal.

If retrieval of property succeeds and yields the value Disconnected, this indicates that the connection has not yet been established. If connection has been attempted and failed, the Connection object SHOULD be removed from the bus entirely, meaning that retrieval of this property SHOULD fail.

Clients SHOULD fall back to calling GetStatus if this property is not supported.
The value of the Status property Get the current status as defined in the StatusChanged signal. If HasImmortalHandles is true, this method no longer does anything. The type of handle to be held A array of integer handles to hold

If HasImmortalHandles is true, which SHOULD always be the case in this version of telepathy-spec, this method does nothing and returns successfully, unless the given handle type or any of the given handles is invalid.

In older connection managers, this method notifies the connection manger that your client is holding a copy of handles which may not be in use in any existing channel or list, and were not obtained by using the RequestHandles method. For example, a handle observed in an emitted signal, or displayed somewhere in the UI that is not associated with a channel. The connection manager must not deallocate a handle where any clients have used this method to indicate it is in use until the ReleaseHandles method is called, or the clients disappear from the bus.

Note that HoldHandles is idempotent - calling it multiple times is equivalent to calling it once. If a handle is "referenced" by several components which share a D-Bus unique name, the client should perform reference counting internally, and only call ReleaseHandles when none of the cooperating components need the handle any longer.

The handle type is invalid One of the given handles is not valid
The type of handle to be inspected An array of integer handles of this type An array of identifiers corresponding to the given handles, in the same order. Return a string representation for a number of handles of a given type. The handle type is invalid One of the given handles is not valid Use the Requests.Channels property instead. An array of structs representing channels. List all the channels which currently exist on this connection. Connection managers MUST still emit this signal, but clients SHOULD listen for the Requests.NewChannels signal instead. A D-Bus object path for the channel object on this service A D-Bus interface name representing the channel type An integer representing the type of handle this channel communicates with, or Handle_Type_None if no handle is specified A handle indicating the specific contact, room or list this channel communicates with, or zero if no handle is specified

If true, the channel was requested by a client that intends to present it to the user itself (i.e. it passed suppress_handler=TRUE to the RequestChannel method), so no other handler should be launched. Clients MAY assume that channels where this is true were created by a user request.

If false, either the channel was created due to incoming information from the service, or the channel was requested by a local client that does not intend to handle the channel itself (this usage is deprecated).

Clients MUST NOT assume that only incoming channels will have this flag set to false.

Emitted when a new Channel object is created, either through user request or incoming information from the service.
If HasImmortalHandles is true, this method no longer does anything. An integer handle type (as defined in RequestHandle) An array of integer handles being held by the client

If HasImmortalHandles is true, which SHOULD always be the case in this version of telepathy-spec, this method does nothing and returns successfully, unless the given handle type or any of the given handles is invalid.

In older connection managers, this method explicitly notifies the connection manager that your client is no longer holding any references to the given handles, and that they may be deallocated if they are not held by any other clients or referenced by any existing channels. See HoldHandles for notes.

The handle type is invalid One of the given handles is not valid
Use Requests.CreateChannel or Requests.EnsureChannel instead. Connection managers MAY implement RequestChannel by raising NotImplemented, or implement fewer types of channel via this API. A D-Bus interface name representing base channel type An integer representing the handle type, or Handle_Type_None if no handle is specified A nonzero integer handle representing a contact, room, list etc. according to handle_type, or zero if the handle_type is Handle_Type_None

Clients SHOULD always set this to true.

The historical meaning was that clients that did not intend to take responsibility for displaying the channel to the user could set this to FALSE, in which case the channel dispatcher would launch an appropriate channel handler.

However, clients whose functionality relies on having a working channel dispatcher should obtain that functionality by calling methods on the channel dispatcher, so that they will get an appropriate error if the channel dispatcher is missing or not working.

The channel dispatcher itself should set this to true too, so that it will ignore the NewChannel signal that results from the creation of the channel. It can then dispatch the channel returned from this method to an appropriate handler.

So, there is no sensible use-case for setting this to false, and setting it to false can result in unhandled channels (in the case where clients assume that a channel dispatcher is present, but it isn't).

The D-Bus object path for the channel created or retrieved

Request a channel satisfying the specified type and communicating with the contact, room, list etc. indicated by the given handle_type and handle. The handle_type and handle may both be zero to request the creation of a new, empty channel, which may or may not be possible, depending on the protocol and channel type.

On success, the returned channel will always be of the requested type (i.e. implement the requested channel-type interface).

If a new, empty channel is requested, on success the returned channel will always be an "anonymous" channel for which the type and handle are both zero.

If a channel to a contact, room etc. is requested, on success, the returned channel may either be a new or existing channel to the requested entity (i.e. its TargetHandleType and TargetHandle properties are the requested handle type and handle), or a newly created "anonymous" channel associated with the requested handle in some implementation-specific way.

For example, for a contact handle, the returned channel might be "anonymous", but implement the groups interface and have the requested contact already present among the members.

If the request cannot be satisfied, an error is raised and no channel is created.

Unknown channel type The given handle does not exist or cannot be created The requested channel type cannot be created with the given handle The requested channel cannot be created because contact doesn't have the required capabilities.
A "null" handle type used to indicate the absence of a handle. When a handle type and a handle appear as a pair, if the handle type is zero, the handle must also be zero. A contact A chat room Replaced by Connection.Interface.ContactList A server-generated contact list (see Channel.Interface.Group) Replaced by Connection.Interface.ContactList A user-defined contact list (see Channel.Interface.Group) An unsigned 32-bit integer representing a handle An unsigned 32-bit integer representing a handle of type Handle_Type_Contact An unsigned 32-bit integer representing a handle of type Handle_Type_Room Replaced by Connection.Interface.ContactList An unsigned 32-bit integer representing a handle of type Handle_Type_List Replaced by Connection.Interface.ContactList An unsigned 32-bit integer representing a handle of type Handle_Type_Group If HasImmortalHandles is true, this method no longer has its reference-counting effect. The type of handle required An array of identifiers of entities to request handles for An array of integer handle numbers in the same order as the given identifiers.

Request several handles from the connection manager which represent a number of contacts, rooms or server-stored lists on the service.

If HasImmortalHandles is true, which SHOULD always be the case in this version of telepathy-spec, the handles remain valid until the connection disconnects.

The implementation of this method in older connection managers must record that these handles are in use by the client who invokes this method, and must not deallocate the handles until the client disconnects from the bus or calls the ReleaseHandles method. Where the identifier refers to an entity that already has a handle in this connection manager, this handle should be returned instead. The handle number 0 must not be returned by the connection manager.

The given identifier does not identify a valid entity of the given type. For instance, an XMPP connection would raise this error for identifiers with type Handle_Type_Room that do not contain exactly one '@' character, that contain spaces, and so on. The given handle type is not valid, or is not implemented on this connection. For instance, a connection to a protocol that doesn't have chat rooms would raise this error for room handles, and all CMs would raise this error for Handle_Type_None.
The connection is fully connected and all methods are available. Connect has been called but the connection has not yet been established. Some methods may fail until the connection has been established. If this is retrieved from GetStatus or Status, it indicates that connection has not yet been attempted. If seen in a StatusChanged signal, it indicates that the connection has failed; the Connection object SHOULD be removed from D-Bus immediately, and all subsequent method calls SHOULD fail.

A reason why the status of the connection changed. Apart from Requested, the values of this enumeration only make sense as reasons why the status changed to Disconnected.

There is no reason set for this state change. Unknown status reasons SHOULD be treated like this reason.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Disconnected.

The change is in response to a user request. Changes to the Connecting or Connected status SHOULD always indicate this reason; changes to the Disconnected status SHOULD indicate this reason if and only if the disconnection was requested by the user.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cancelled.

There was an error sending or receiving on the network socket.

When the status changes from Connecting to Disconnected for this reason, the equivalent D-Bus error is either org.freedesktop.Telepathy.Error.NetworkError, org.freedesktop.Telepathy.Error.ConnectionRefused, org.freedesktop.Telepathy.Error.ConnectionFailed or some more specific error.

When the status changes from Connected to Disconnected for this reason, the equivalent D-Bus error is either org.freedesktop.Telepathy.Error.NetworkError, org.freedesktop.Telepathy.Error.ConnectionLost or some more specific error.

The username or password was invalid.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.AuthenticationFailed.

There was an error negotiating SSL on this connection, or encryption was unavailable and require-encryption was set when the connection was created.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.EncryptionNotAvailable if encryption was not available at all, or org.freedesktop.Telepathy.Error.EncryptionError if encryption failed.

In general, this reason indicates that the requested account name or other identification could not be used due to conflict with another connection. It can be divided into three cases:

  • If the status change is from Connecting to Disconnected and the 'register' parameter to RequestConnection was present and true, the requested account could not be created on the server because it already exists. The equivalent D-Bus error is org.freedesktop.Telepathy.Error.RegistrationExists.
  • If the status change is from Connecting to Disconnected but the 'register' parameter is absent or false, the connection manager could not connect to the specified account because a connection to that account already exists. The equivalent D-Bus error is org.freedesktop.Telepathy.Error.AlreadyConnected. In some protocols, like XMPP (when connecting with the same JID and resource as an existing connection), the existing connection "wins" and the new one fails to connect.
  • If the status change is from Connected to Disconnected, the existing connection was automatically disconnected because a new connection to the same account (perhaps from a different client or location) was established. The equivalent D-Bus error is org.freedesktop.Telepathy.Error.ConnectionReplaced. In some protocols, like MSNP (when connecting twice with the same Passport), the new connection "wins" and the existing one is automatically disconnected.

The server did not provide a SSL certificate.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.NotProvided.

The server's SSL certificate is signed by an untrusted certifying authority. This error SHOULD NOT be used to represent a self-signed certificate: use the more specific Cert_Self_Signed reason for that.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.Untrusted.

The server's SSL certificate has expired.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.Expired.

The server's SSL certificate is not yet valid.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.NotActivated.

The server's SSL certificate did not match its hostname.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.HostnameMismatch.

The server's SSL certificate does not have the expected fingerprint.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.FingerprintMismatch.

The server's SSL certificate is self-signed.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.SelfSigned.

There was some other error validating the server's SSL certificate.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.Invalid.

The server's SSL certificate has been revoked.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.Revoked.

The server's SSL certificate uses an insecure algorithm, or is cryptographically weak.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.Insecure.

The length in bytes of the server certificate, or the depth of the sever certificate chain exceed the limits imposed by the crypto library.

When disconnected for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cert.LimitExceeded

Emitted when an error occurs that renders this connection unusable.

Whenever this signal is emitted, it MUST immediately be followed by a StatusChanged signal with status Connection_Status_Disconnected and an appropriate reason code.

Connection managers SHOULD emit this signal on disconnection, but need not do so. Clients MUST support connection managers that emit StatusChanged(Disconnected, ...) without first emitting ConnectionError.

This signal provides additional information about the reason for disconnection. The reason for connection is always straightforward - it was requested - so it does not need further explanation. However, on errors, it can be useful to provide additional information.

The Connection_Status_Reason is not given here, since it will be signalled in StatusChanged. A reasonable client implementation would be to store the information given by this signal until StatusChanged is received, at which point the information given by this signal can be used to supplement the StatusChanged signal.

The name of a D-Bus error describing the error that occurred, which may correspond to a Connection_Status_Reason, or may be a more specific Telepathy error (such as org.freedesktop.Telepathy.Error.ConnectionRefused for Connection_Status_Reason_Network_Error) or a protocol-specific or connection-manager-specific error in a suitable namespace. For instance, a SIP connection manager could signal "402 Payment Required" as an error in a connection-manager-specific namespace, or a link-local XMPP implementation that used Avahi could provide the error given to it by the avahi-daemon.

Additional information about the error, which may include the following well-known keys:

debug-message (s)
Debugging information on the change, corresponding to the message part of a D-Bus error message, which SHOULD NOT be displayed to users under normal circumstances
server-message (s)
A human-readable message from the server explaining what happened. This may be in the user's native language, or in the server operator's native language, or even in Lojban.
user-requested (b), expected-hostname (s), certificate-hostname (s)
The same details defined in TLS_Certificate_Rejection.
An integer indicating the new status, as defined by ConnectionStatus An integer indicating the reason for the status change, as defined by ConnectionStatusReason Emitted when the status of the connection changes. All states and reasons have numerical values, as defined in ConnectionStatus and ConnectionStatusReason.

The same string that would be returned by InspectHandles. As a special case, this is always present in the result of GetContactAttributes, whether it was explicitly requested or not.

Register a client's interest in notifications related to one or more interfaces.

Groups of notifications are identified by a token which is either a D-Bus interface name, or a string that starts with a D-Bus interface name. The meaning of each token is given by that D-Bus interface, which MUST define it in its documentation.

Initially, all interests are in entire interface, but allowing other strings allows subscription to part of an interface; for instance, an interest in ...MailNotification/count could track the number of messages without caring about their detailed content.

For each token with which this method interacts, the Connection tracks an "interest count" (like a reference count) for each unique bus name that has called this method. When a client calls this method, for each token, the interest count for its unique bus name is incremented; when RemoveClientInterest is called, all interest counts for that unique bus name are decremented. If the unique bus name leaves the bus (for instance, if the client crashes or exits), all interest counts for that unique bus name are set to zero.

The Connection can then use these reference counts to avoid subscribing to protocol-level notifications unless at least one client has a non-zero interest count for the relevant token.

This method exists to reduce memory and network overhead when there is no active subscription.

One situation where this is useful is Location: on XMPP, location updates are received over PEP. If the Connection advertises the geoloc+notify capability, it will be sent location updates for all contacts. To avoid consuming resources for this, the connection should avoid advertising that capability until a client has expressed an interest in contacts' locations.

Another example of a protocol that benefits from this method is the Google XMPP Mail Notification extension, which can be used to implement MailNotification. In this protocol, the CM receives a notification that something has changed, but to get more information, the CM must request this information. Knowing that nobody is currently interested in this information, the CM can avoid generating useless network traffic. Similarly, the CM may free the list of unread messages to reduce memory overhead.

If this method is called for an interface that might require protocol-level subscription, but the connection cannot set up that subscription yet (for instance because the Status is not Connected yet), the Connection MUST remember the client's interest, and attempt to subscribe to the appropriate protocol feature when this becomes possible.

Clients MAY ignore any errors raised by this method; it is intended to be called with the reply ignored.

The only reason it could fail is if it's unimplemented, in which case the only thing the client can usefully do is to proceed as if it had succeeded.

Interfaces or parts of interfaces in which to register an interest, represented by either a DBus_Interface, or a string prefixed with a DBus_Interface.

If the Connection does not support one of these tokens, this is not considered to be an error; the unsupported token is simply ignored.

Release an interest registered using AddClientInterest. See that method's documentation for details.

Clients MAY ignore any errors raised by this method; it is intended to be called with the reply ignored.

The only reasons it could fail are if it's unimplemented, or if the client's reference-counting is wrong and it has tried to remove a client interest that it did not add. In both cases, there's nothing the client could do about it.

Interfaces or parts of interfaces that were previously passed to AddClientInterest.

True if handles last for the whole lifetime of the Connection. This SHOULD be the case in all connection managers, but clients MUST interoperate with older connection managers (which reference-count handles).

This models a connection to a single user account on a communication service. Its basic capability is to provide the facility to request and receive channels of differing types (such as text channels or streaming media channels) which are used to carry out further communication.

In order to allow Connection objects to be discovered by new clients, the object path and well-known bus name MUST be of the form /org/freedesktop/Telepathy/Connection/cmname/proto/account and org.freedesktop.Telepathy.Connection.cmname.proto.account where:

  • cmname is the same Connection_Manager_Name that appears in the connection manager's object path and well-known bus name
  • proto is the Protocol name as seen in ListProtocols, but with "-" replaced with "_" to get a valid object path/bus name
  • account is some non-empty sequence of ASCII letters, digits and underscores not starting with a digit

account SHOULD be formed such that any valid distinct connection instance on this protocol has a distinct name. This might be formed by including the server name followed by the user name (escaped via some suitable mechanism like telepathy-glib's tp_escape_as_identifier() function to preserve uniqueness); on protocols where connecting multiple times is permissable, a per-connection identifier might be necessary to ensure uniqueness.

Clients MAY parse the object path to determine the connection manager name and the protocol, but MUST NOT attempt to parse the account part. Connection managers MAY use any unique string for this part.

As well as the methods and signatures below, arbitrary interfaces may be provided by the Connection object to represent extra connection-wide functionality, such as the Connection.Interface.SimplePresence for receiving and reporting presence information, and Connection.Interface.Aliasing for connections where contacts may set and change an alias for themselves. These interfaces can be discovered using the GetInterfaces method.

Contacts, rooms, and server-stored lists (such as subscribed contacts, block lists, or allow lists) on a service are all represented by immutable handles, which are unsigned non-zero integers which are valid only for the lifetime of the connection object, and are used throughout the protocol where these entities are represented, allowing simple testing of equality within clients.

Zero as a handle value is sometimes used as a "null" value to mean the absence of a contact, room, etc.

Handles have per-type uniqueness, meaning that every (handle type, handle number) tuple is guaranteed to be unique within a connection and that a handle alone (without its type) is meaningless or ambiguous. Connection manager implementations should reference count these handles to determine if they are in use either by any active clients or any open channels, and may deallocate them when this ceases to be true. Clients may request handles of a given type and identifier with the RequestHandles method, inspect the entity identifier with the InspectHandles method, keep handles from being released with HoldHandles, and notify that they are no longer storing handles with ReleaseHandles.

Previously, the account part of Connection bus names/object paths was allowed to have more than one component (i.e. contain dots or slashes), resulting in Connection bus names and object paths with more than 7 components. We now restrict Connection bus names/object paths to have exactly 7 components. The Requests and Contacts interfaces are now mandatory. Their functionality will be merged into the main Connection interface at some point in future.
telepathy-qt-0.9.6~git1/spec/Call_Content_Interface_Audio_Control.xml0000664000175000017500000001227312470405660023577 0ustar jrjr Copyright © 2009-2011 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

This interface allows the connection manager to be kept informed of, and control, the input and output volumes of an audio stream. While generally not needed, if the connection manager needs to handle stream volumes directly (typically when using Call_Content_Packetization_Type_Raw), this interface may be necessary.

If this interface is present, the handler should call ReportInputVolume and ReportOutputVolume whenever the input and output volume change, both when the user manually modifies the volume and when the volumes are adjusted in response to RequestedInputVolume and RequestedOutputVolume changing.

The maximum volume as used in this interface represent the unamplified hardware volume (0 dB). No software amplification should be used to boost the signal to a higher level when this Interface is in use

The input volume as requested by the Connection Manager. Initially and on any changes the client should change its input volume to match the requested volume. Report the input volume level as set by the client.

Report to the CM that the Content input volume has been changed by the client.

It is the client's responsibility to change the input volume used for the content. However, the client MUST call this whenever it changes input volume for the content.

The input volume as requested by the Connection Manager. Initially and on any changes the client should change its input volume to match the requested volume. Report the output volume level as set by the client.

Report to the CM that the content output volume has been changed by the client.

It is the client's responsibility to change the output volume used for the content. However, the client MUST call this whenever it changes output volume for the content.

A volume value either reported to or requested by the Connection Manager. This value should either be -1 for an unknown value or in the range of 0-255, with 0 being the minimal volume and 255 being the highest unamplified volume the input or output is capable of (known as 0 dB)

telepathy-qt-0.9.6~git1/spec/Call_Content_Media_Description_Interface_RTP_Header_Extensions.xml0000664000175000017500000000576512470405660030644 0ustar jrjr Copyright © 2005-2010 Nokia Corporation Copyright © 2005-2010 Collabora Ltd This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. (as stable API)

This media description interface provides a method of signalling support for RTP Header Extensions, documented by A General Mechanism for RTP Header Extensions (RFC 5285).

For more details on the General Mechanism for RTP Header Extensions and how to use them, one should refer to RFC 5285.

A struct defining a RTP Header extension. Identifier to be negotiated. Direction in which the Header Extension is negotiated. URI defining the extension. Feedback parameters as a string. Format is defined in the relevant RFC. A list of remote header extensions which are supported.
telepathy-qt-0.9.6~git1/spec/Channel_Interface_Splittable.xml0000664000175000017500000000604412470405660022143 0ustar jrjr Copyright © 2009 Collabora Limited Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft 1)

An interface for channels that can be made conceptually part of a Conference, and can then be detached from that conference.

This interface addresses part of freedesktop.org bug #24906 (GSM-compatible conference calls). GSM is currently the only protocol known to implement this; PBXs might implement it too.

Request that this channel is removed from any Conference of which it is a part.

This implies that the media streams within the conference are put on hold and the media streams within the member channel leaving the conference are unheld.

This channel isn't in a conference. This channel is in a conference but can't currently be split away from it.
telepathy-qt-0.9.6~git1/spec/Channel_Interface_Media_Signalling.xml0000664000175000017500000002167012470405660023230 0ustar jrjr Copyright © 2005-2009 Collabora Limited Copyright © 2005-2009 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

The old-style Telepathy properties, deprecated since March 2009, have been removed.

An interface for signalling a channel containing synchronised media sessions which can contain an arbitrary number of streams. The presence of this interface on a Channel indicates that the connection manager will not carry out the actual streaming for this channel, and that the client handling the channel is responsible for doing so; in most cases we recommend doing this by using the telepathy-farsight library.

Streaming audio and (particularly) video requires a high level of integration with the UI, and having the connection manager act as a proxy would be likely to introduce unacceptable latency. As a result, audio/video streaming is offloaded into the client where possible, as an exception to the general design of Telepathy.

The negotiation interface is based on the API of the Farsight library. This, in turn, is based upon the IETF MMusic ICE drafts, where connections are established by signalling potential connection candidates to the peer until a usable connection is found, and codecs are negotiated with an SDP-style offer and answer. However, the principles should be applicable to other media streaming methods and the API re-used without difficulty.

Note that the naming conventions used in the MediaStreamHandler and MediaSessionHandler interfaces are rather confusing; methods have signal-like names and signals have method-like names, due to the API being based rather too closely on that of Farsight. This is for historical reasons and will be fixed in a future release of the Telepathy specification.

The type of a media session. Currently, the only supported value is "rtp". A struct representing a active session handler. The object path of the session handler, which is on the same bus name as the channel. The media session's type Returns all currently active session handlers on this channel as a list of (session_handler_path, type). Object path of the new Media.SessionHandler object String indicating type of session, eg "rtp" Signal that a session handler object has been created. The client should create a session object and create streams for the streams within.

The client can implement streaming for streams whose NATTraversal property is gtalk-p2p.

The client can implement streaming for streams whose NATTraversal property is ice-udp.

The client can implement streaming for streams whose NATTraversal property is wlm-8.5.

The client can implement streaming for streams whose NATTraversal property is wlm-2009.

The client supports media streaming with H264 (etc.).

This handler capability token is a one of a family of similar tokens: for any other audio or video codec whose MIME type is audio/subtype or video/subtype, a handler capability token of this form may exist (the subtype MUST appear in lower case in this context). Clients MAY support more codecs than they explicitly advertise support for; clients SHOULD explicitly advertise support for their preferred codec(s), and for codecs like H264 that are, in practice, significant in codec negotiation.

For instance, the XMPP capability used by the Google Video Chat web client to determine whether a client is compatible with it requires support for H264 video, so an XMPP connection manager that supports this version of Jingle should not advertise the Google Video Chat capability unless there is at least one installed client that declares that it supports video/h264 on StreamedMedia channels.

For example, a client could advertise support for Speex, Theora and H264 by having three handler capability tokens, org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/audio/speex, org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/video/theora and org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/video/h264, in its Capabilities property.

Clients MAY have media signalling abilities without explicitly supporting any particular codec, and connection managers SHOULD support this usage.

This is necessary to support gatewaying between two Telepathy connections, in which case the available codecs might not be known to the gatewaying process.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Room_Config.xml0000664000175000017500000003006112470405660022235 0ustar jrjr Copyright © 2011 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

version 1. This replaces the old-school Telepathy properties on Text.

Represents the configuration of a chatroom, some aspects of which may be modifiable by the user, depending on their privileges. This corresponds to the room configuration on XMPP, and various channel mode flags on IRC.

The “topic” (on IRC) or “subject” (on XMPP) is not part of this interface; it can be found on the Subject2 interface.

True if people may join the channel without other members being made aware of their identity. True if people may not join the channel until they have been invited. The limit to the number of members; or 0 if there is no limit. True if channel membership is not sufficient to allow participation. A human-visible name for the channel, if it differs from Room2.RoomName; the empty string, otherwise.

On XMPP, this represents the muc#roomconfig_roomname field of the muc#roomconfig form. So for jdev@conference.jabber.org, for example:

  • Room2.RoomName = "jdev";
  • Room2.Server = "conference.jabber.org";
  • Title = "General Jabber development discussion".

XEP-0045 is awful.

A human-readable description of the channel's overall purpose; if any. True if the channel will remain in existence on the server after all members have left it. True if the channel is not visible to non-members. True if contacts joining this channel must provide a password to be granted entry. Note that this property does not indicate that a password is required right now; see the Password interface for the API used to provide a password while joining a room. If PasswordProtected is True, the password required to enter the channel, if known. If the password is unknown, or PasswordProtected is False, the empty string. On XMPP—bless its cotton socks!—non-owners of a MUC cannot see its current password, even if they just provided the password in order to join the room…

If PasswordProtected is True, an optional hint for the password.

On protocols supporting PasswordHint (indicated by its presence in MutableProperties), Password and PasswordHint MUST be set in a single call to UpdateConfiguration.

Skype requires that the password and its hint be supplied together.
If True, the user may call UpdateConfiguration to change the values of the properties listed in MutableProperties.

A list of (unqualified) property names on this interface which may be modified using UpdateConfiguration (if CanUpdateConfiguration is True). Properties not listed here cannot be modified.

For example, IRC does not have the concept of joining a room without other participants knowing your true identity; so on IRC the Anonymous property will always be False, and MutableProperties will not include "Anonymous".

True once the initial room configuration has been retrieved, or False otherwise. On some services, this may take some time after you've joined a room to fetch the configuration. Once this property changes to True, the other properties on this interface can be assumed to be accurate; this property MUST not change to False after it becomes True.

An application's “configure this room” dialog might choose to display a spinner while this property is False, rather than allowing the user to edit probably-inaccurate configuration.

The new values of one or more properties on this interface, which must be listed in MutableProperties. For instance, to set up a channel for discussing top-secret corporate merge plans, this parameter might be:

{
  'Private': True,
  'InviteOnly': True,
  'Description': "The first rule of #inteltakeover is: do not talk about #inteltakeover",
}

If CanUpdateConfiguration is True, modifies the current values of one or more room properties. This method SHOULD NOT return until the change has been accepted or declined by the server.

Note that the server may ostensibly accept the changes (thus allowing this method to return success) but signal different values; for example, the server might truncate Title to some maximum length. Callers SHOULD continue to listen for the PropertiesChanged signal, and trust the values it signals over those provided to this method.

The user is not allowed to reconfigure this room. One or more of the specified properties is unknown, or ill-typed. One or more of the specified properties cannot be modified on this protocol. The room's current configuration has not yet been retrieved, so we cannot update it just yet. The application might like to try again once the ConfigurationRetrieved property becomes True.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Cellular.xml0000664000175000017500000001706512470405660022337 0ustar jrjr Copyright © 2008-2010 Nokia Corporation Copyright © 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

This interface is for various cellular things (GSM and/or CDMA) that aren't really applicable to other protocols.

Define how long should the service centre try message delivery before giving up, failing delivery and deleting the message. A value of 0 means to use the service centre's default period.

The value specified is in seconds. Note that various protocols or implementations may round the value up (eg. to a minute or hour precision). The maximum validity period may vary depending on protocol or provider.

Previously, as an undocumented feature, setting MessageServiceCentre to the empty string caused the SIM's default SMSC to be used.

If True, SMSes will be sent via the service centre specified by MessageServiceCentre. If False, the SIM's default SMSC will be used, ignoring the value of MessageServiceCentre.

It could be desirable for a configuration interface to remember the user's previous choice of custom SMSC, even if it's not in use. This boolean allows that choice to be saved as an account parameter by Mission Control, rather than the UI needing to save it elsewhere to be restored if the user wants to reactivate it.

This property's value is now ignored unless OverrideMessageServiceCentre is True.

Address for the messaging service centre. Typically (as is the case for GSM's SMSC), it's the ISDN / telephony address (ie. a phone number). If OverrideMessageServiceCentre is False, this property's value should be ignored by the CM in favour of the SIM's default SMSC.

The International Mobile Subscriber Identifier, if it exists. This would originate from a SIM card. If the IMSI is unknown, this will contain an empty string ("").

Emitted when the IMSI for the connection changes. This sort of thing is rare, but could happen on cellular phones that allow hot-swapping of SIM cards. In the case of SIM swapping, this signal would be emitted twice; the first time while the SIM is being ejected (with an empty string), and the second time after a new SIM has been inserted (assuming that the IMSI can be determined from the new SIM). The new IMSI value. This may be an empty string in the case where the IMSI is being reset or removed.

Determines how to encode SMSes containing characters that do not fit into a non-Unicode character set. If False (which SHOULD be the default), messages will be encoded as UCS-2 and sent with no loss of fidelity (at the potential financial cost of using twice as many SMSes); if True, the message will be recoded in an implementation‐specific way to fit into a GSM reduced character set.

Hint for the connection manager for the GSM character set that should be used to send SMSes. The connection manager SHOULD follow this hint unless it has other ways to determine a better encoding. If the value is "gsm" (which SHOULD be the default), SMSes will be encoded in the normal 7-bit GSM character set, eventually falling back to UCS-2; see the MessageReducedCharacterSet property for details. Other valid character sets are specified in the GSM standard and are, for instance, "turkey", "spain" or "portugal". If the SMS cannot be encoded using the requested character set the behaviour is implementation-specific, but it is RECOMMENDED that the connection manager should behave as if this property was set to "gsm".

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Securable.xml0000664000175000017500000000674312470405660021753 0ustar jrjr Copyright (C) 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

as stable API

This interface exists to expose security information about Channels. The two properties are sometimes immutable and can be used to make decisions on how cautious to be about transferring sensitive data. The special case of ServerAuthentication channels is one example of where the two properties are immutable.

For example, clients MAY use these properties to decide whether the PLAIN mechanism is acceptable for a SASLAuthentication channel.

True if this channel occurs over an encrypted connection. This does not imply that steps have been taken to avoid man-in-the-middle attacks.

For future support for RFC 5056 Channel Binding it is desirable to be able to use some SASL mechanisms over an encrypted connection to an unverified peer, which can prove that it is the desired destination during the SASL negotiation.

True if this channel occurs over a connection that is protected against tampering, and has been verified to be with the desired destination: for instance, one where TLS was previously negotiated, and the TLS certificate has been verified against a configured certificate authority or accepted by the user.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Contact_Blocking.xml0000664000175000017500000002400612470405660023770 0ustar jrjr Copyright © 2009–2011 Collabora Ltd. Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

Changes from the draft: methods and signals now return Handle_Identifier_Map (a{us}) rather than bare lists of contact handles (au)

An interface for connections where contacts can be blocked from communicating with this user and receiving this user's presence. Clients may retrieve a list of currently-blocked contacts using RequestBlockedContacts, and listen for BlockedContactsChanged to be notified when contacts are blocked and unblocked. The BlockContacts and UnblockContacts methods do what they say on the tin; depending on the value of the ContactBlockingCapabilities property, contacts may be reported for spam or other abuse when calling BlockContacts.

This interface is intended for protocols where blocking contacts persists on the server between connections; connection managers for protocols with no server-side support for blocking contacts MAY choose to implement this interface using an on-disk file of blocked contacts or some other means to store blocked contacts between connections.

This interface is intended to replace the ContactList channel with TargetHandleType List and TargetID "deny" (along with the ContactList and ContactGroups interfaces replacing other channels with TargetHandleType List and TargetHandleType Group, respectively).

Direct the server to block some contacts. The precise effect is protocol-dependent, but SHOULD include ignoring all current and subsequent communications from the given contacts, avoiding sending presence to them in future, and if they were already receiving the local user's presence, behaving as if the local user went offline.

Some contacts to block. If some of the contacts in this list are already blocked, the connection manager MUST act as if they were not specified in this list.

In addition to blocking, report these contacts as abusive to the server administrators.

Clients can determine whether this capability is available by checking the ContactBlockingCapabilities property. If this argument is set to True by a client despite ContactBlockingCapabilities not containing the Can_Report_Abusive flag, the connection manager SHOULD act as if it were False and simply block the supplied contacts.

A correct user interface shouldn't get this far without knowing that reporting abusive contacts is not supported. If it does, then the user has expressed their intention to block these contacts. Returning an error would leave the UI with three options:

  • Ignore the error, leaving the contacts not actually blocked;
  • Display an error to the user;
  • Call this method again, passing False for this argument.

None of these seem preferable to the CM just ignoring this flag if it doesn't support it: that way, the contacts will be blocked, as the user requested, and UIs have fewer ways to mess up entirely.

Direct the server to unblock some contacts.

Some contacts to unblock. If some of the contacts in this list are not currently blocked, the connection manager MUST act as if they were not specified in this list.

List the contacts that are blocked.

Clients SHOULD allow a relatively long timeout for calls to this method, since on some protocols contact blocking is part of the contact list, which can take a significant time to retrieve.

The blocked contacts’ handles, together with their identifiers.

Emitted when the list of blocked contacts is first retrieved (before returning from any pending calls to RequestBlockedContacts), and whenever the list of blocked contacts subsequently changes.

Contacts added to the result of RequestBlockedContacts. Contacts removed from the result of RequestBlockedContacts.

True if the contact would be in the result of RequestBlockedContacts; False or omitted if the contact is not blocked, or if it is unknown whether the contact is blocked.

Additional capabilities for contact blocking; currently, this is limited to whether contacts may be reported as abusive.

Note that there is no capability for supporting blocking itself: the presence of this interface on a Connection indicates that blocking contacts is supported.

When calling BlockContacts, the contacts may be reporting as abusive to the server administrators by setting Report_Abusive to True.
telepathy-qt-0.9.6~git1/spec/Channel_Type_Server_TLS_Connection.xml0000664000175000017500000001356712470405660023240 0ustar jrjr Copyright © 2010 Collabora Limited This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. (as stable API)

A channel type that carries a TLS certificate between a server and a client connecting to it.

Channels of this kind always have Requested = False, TargetHandleType = None and TargetHandle = 0, and cannot be requested with methods such as CreateChannel. Also, they SHOULD be dispatched while the Connection owning them is in the CONNECTING state.

In this case, handlers SHOULD accept or reject the certificate, using the relevant methods on the provided object, or MAY just Close the channel before doing so, to fall back to a non-interactive verification process done inside the CM.

For example, channels of this kind can pop up while a client is connecting to an XMPP server.

A TLSCertificate containing the certificate chain as sent by the server, and other relevant information.

The hostname or domain that the user expects to connect to. Clients SHOULD use the ReferenceIdentities property to verify the identity of the certificate. Clients MAY display this hostname to the user as the expected identity. Clients SHOULD use this property to lookup pinned certificates or other user preferences for the connection.

If this property is not present, clients SHOULD use the Hostname property as the reference identity to validate server certificates against.

The identities of the server we expect ServerCertificate to certify; clients SHOULD verify that ServerCertificate matches one of these identities when checking its validity.

This property MUST NOT be the empty list; it MUST contain the value of the Hostname property. All other identities included in this property MUST be derived from explicit user input or choices, such as Parameters passed to RequestConnection.

The primary use for this property is for XMPP services hosted by Google Apps. When connecting to Google Talk using an @gmail.com JID, the server correctly presents a certificate for gmail.com; however, for domains hosted via Google Apps, a certificate for talk.google.com is offered, due to unresolved technical limitations.

If the user has explicitly chosen to create a Google Talk account, then trusting a certificate for talk.google.com is reasonable. To handle this case, the connection manager may add the values of any or all of the server, fallback-server and extra-identities parameters; the Google Talk account creation user interface may set these parameters appropriately, or the user may set them for accounts with other services.

telepathy-qt-0.9.6~git1/spec/Channel_Type_Contact_Search.xml0000664000175000017500000005401212470405660021737 0ustar jrjr Copyright © 2005-2009 Collabora Limited Copyright © 2005-2009 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

as stable API. Changes from draft 2: Contact_Search_Result_Map keys are now identifiers rather than handles; consequently, the values need not include x-telepathy-identifier.

A channel type for searching server-stored user directories. A new channel should be requested by a client for each search attempt, and closed when the search is completed or the required result has been found.

Connections that support contact search channels SHOULD have an entry in RequestableChannelClasses with the ChannelType fixed to this interface, and no other fixed properties. That requestable channel class MAY also have the Server and Limit properties in its list of allowed properties, depending on the protocol.

The requestable channel class would normally also have TargetHandleType fixed to None, but the initial implementation of ContactSearch (in telepathy-gabble) didn't do this.

All channels of this type should have TargetHandleType None (and hence TargetHandle 0 and TargetID "").

Requests for channels of this type need only optionally specify the Server property (if it is an allowed property in the connection's RequestableChannelClasses).

Before searching, the AvailableSearchKeys property should be inspected to determine the valid search keys which can be provided to the Search method. A search request is then started by providing some of these terms to the Search method, and the SearchState will change from Not_Started to In_Progress. As results are returned by the server, the SearchResultReceived signal is emitted for each contact found; when the search is complete, the search state will be set to Completed. If the search fails after Search has been called, the state will change to Failed. A running search can be cancelled by calling Stop.

If the protocol supports limiting the number of results returned by a search and subsequently requesting more results, after Limit results have been received the search state will be set to More_Available. Clients may call More to request another Limit results. If allowed by the connection manager, clients may specify the "page size" by specifying Limit when calling CreateChannel.

The client should call the channel's Close method when it is finished with the channel.

Each channel can only be used for a single search; a new channel should be requested for each subsequent search. Connection managers MUST support multiple ContactSearch channels being open at once (even to the same server, if applicable).

It does not make sense to request this channel type using EnsureChannel; clients SHOULD request channels of this type using CreateChannel instead.

A contact search channel that is already in use for a different search isn't useful.

The search has not started The search is in progress The search has paused, but more results can be retrieved by calling More. The search has been completed The search has failed The current state of this search channel object. Change notification is via SearchStateChanged. The new search state If the new state is Failed, the name of a D-Bus error describing what went wrong. Otherwise, the empty string.

Additional information about the state transition, which may include the following well-known keys:

debug-message (s)
Debugging information on the change, corresponding to the message part of a D-Bus error message, which SHOULD NOT be displayed to users under normal circumstances

This argument allows for future extensions. For instance, if moving to state Failed because the server rejected one of our search terms, we could define a key that indicates which terms were invalid.

Emitted when the SearchState property changes. The implementation MUST NOT make transitions other than the following:

  • Not_StartedIn_Progress
  • In_ProgressMore_Available
  • More_AvailableIn_Progress
  • In_ProgressCompleted
  • In_ProgressFailed

Any of the following search keys, with the indicated result for the search:

The empty string
Search for the search term in some implementation-dependent set of fields, using an implementation-dependent algorithm (e.g. searching for each word mentioned) The "one big search box" approach to searching, as is familiar from Google. The Sametime plugin to Pidgin appears to search in this way.
A VCard_Field
Search for the search term in fields matching that name (for instance, nickname would search nicknames, and tel would search any available phone number, regardless of its work/home/mobile/... status).
A VCard_Field followed by ";" and a VCard_Type_Parameter of the form "type=..."
Search for the search term in fields of that name and type only (for instance, tel;type=mobile).
x-telepathy-identifier
Search for contacts whose identifier in the IM protocol matches the search term (e.g. contains it as a substring) Otherwise, starting a search by identifier would require the UI to know the vCard field name corresponding to identifiers in this protocol, which might be non-standard (like x-jabber) or not exist at all.
x-gender
For the search term "male" or "female", search only for contacts listed as male or female, respectively. The results for other search terms are undefined; it is likely that contacts with unspecified gender will only be matched if this search key is omitted from the request. Examples in XEP-0055 suggest this usage, and at least Gadu-Gadu also supports limiting search results by gender.
x-n-family
Search for the search term in contacts' family names (the first component of the vCard field n). Gadu-Gadu and TOC seem to support this mode of searching.
x-n-given
Search for the search term in contacts' given names (the second component of the vCard field n). As for x-n-family.
x-online
For the search term "yes", search only for contacts who are currently online. The results for other search terms are undefined. Gadu-Gadu appears to support this.
x-adr-locality
Search for the search term as a locality or city (the fourth component of the vCard field adr). Gadu-Gadu and TOC appear to support this.

If supported by the protocol, the maximum number of results that should be returned, where 0 represents no limit. If the protocol does not support limiting results, this should be 0.

For example, if the terms passed to Search match Antonius, Bridget and Charles and this property is 2, the search service SHOULD only return Antonius and Bridget.

This property SHOULD be requestable if and only if the protocol supports specifying a limit; implementations SHOULD use 0 as the default if possible, or a protocol-specific sensible default otherwise.

The set of search keys supported by this channel. Example values include [""] (for protocols where several address fields are implicitly searched) or ["x-n-given", "x-n-family", "nickname", "email"] (for XMPP XEP-0055, without extensibility via Data Forms). It can be in the NewChannels signal for round-trip reduction. A map from search keys to search terms. The search key to match against The term or terms to be searched for in the search key; depending on the protocol and the server implementation, this may be matched by exact or approximate equality, substring matching, word matching or any other matching algorithm A dictionary mapping search key names to the desired values Send a request to start a search for contacts on this connection. This may only be called while the SearchState is Not_Started; a valid search request will cause the SearchStateChanged signal to be emitted with the state In_Progress. The SearchState is no longer Not_Started, so this method is no longer available. The search terms included something this connection manager cannot search for. Request that a search in SearchState More_Available move back to state In_Progress and continue listing up to Limit more results. The SearchState is not More_Available.

Stop the current search. This may not be called while the SearchState is Not_Started. If called while the SearchState is In_Progress, SearchStateChanged will be emitted, with the state Failed and the error org.freedesktop.Telepathy.Error.Cancelled.

Calling this method on a search in state Completed or Failed succeeds, but has no effect.

Specifying Stop to succeed when the search has finished means that clients who call Stop just before receiving SearchStateChanged don't have to handle a useless error.

Depending on the protocol, the connection manager may not be able to prevent the server from sending further results after this method returns; if this is the case, it MUST ignore any further results.

The SearchState is Not_Started, so this method is not yet available.
A map from contact identifier to search result, emitted in the SearchResultReceived signal. The identifier of a contact matching the search terms. This is an identifier rather than a handle in case we make handles immortal; see fd.o#23155 and fd.o#13347 comment 5.

An array of fields representing information about this contact, in the same format used in the ContactInfo interface. It is possible that a separate call to RequestContactInfo would return more information than this signal provides.

A mapping from contact identifier to an array of fields representing information about this contact. Emitted when a some search results are received from the server. This signal can be fired arbitrarily many times so clients MUST NOT assume they'll get only one signal.

For protocols which support searching for contacts on multiple servers with different DNS names (like XMPP), the DNS name of the server being searched by this channel, e.g. "characters.shakespeare.lit". Otherwise, the empty string.

XEP 0055 defines a mechanism for XMPP clients to search services of their choice for contacts, such as users.jabber.org (the "Jabber User Directory").

This property SHOULD be requestable if and only if the protocol supports querying multiple different servers; implementations SHOULD use a sensible default if possible if this property is not specified in a channel request.

This allows a client to perform searches on a protocol it knows nothing about without requiring the user to guess a valid server's hostname.

telepathy-qt-0.9.6~git1/spec/Debug.xml0000664000175000017500000001402112470405660015450 0ustar jrjr Copyright (C) 2009 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface for providing debug messages.

This interface is primarily provided by one object per service, at the path /org/freedesktop/Telepathy/debug.

TRUE if the NewDebugMessage signal should be emitted when a new debug message is generated. Retrieve buffered debug messages. An implementation could have a limit on how many message it keeps and so the array returned from this method should not be assumed to be all of the messages in the lifetime of the service. A list of debug messages. Emitted when a debug messages is generated if the Enabled property is set to TRUE. Timestamp of the debug message. Domain of the debug message, as described in the Debug_Message struct. Level of the debug message. The text of the debug message. Log level for errors. Error messages are always fatal, resulting in the service terminating after something completely unexpected occurred. Log level for critical messages. Critical messages are messages that the service might predict and it is up to the service itself to decide whether to terminate following a critical message. Log level for warnings. Log level for messages. Log level for information messages. Log level for debug messages. A struct representing a debug message, as returned by GetMessages. Timestamp of the debug message. This is a double to allow more accuracy in the time the message was logged.

Domain of the debug message. This is used to identify the source of debug messages. For example, debug messages from a connection manager could have this Domain struct member be the name of the connection manager, and logs from any helper library could have the name of the helper library.

The domain could also contain a category as to where the log message originated separated by a forward-slash. For example, if a debug message was output in a connection manager called "dummy", in the file-transfer code, this Domain struct member might be dummy/file-transfer.

Level of the debug message. This states the severity of the debug message. The text of the debug message.
telepathy-qt-0.9.6~git1/spec/Account_Interface_Avatar.xml0000664000175000017500000000626712470405660021311 0ustar jrjr Copyright (C) 2008 Collabora Ltd. Copyright (C) 2008 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

This interface extends the core Account interface to provide a user-settable avatar image.

The avatar could have been a property on the core Account interface, but was moved to a separate interface because it is likely to be large. This means that clients can safely use GetAll to get properties on the core Account interface without flooding the session bus with large images.

A struct containing avatar data marked with its MIME type.

May be set to an empty byte-array and an empty string, indicating no avatar.

The avatar to set on this account for display to other contacts, represented as a structure containing the bytes of the avatar, and the MIME type as a string; may be set to an empty byte-array and an empty string to indicate no avatar. When the account becomes connected, the account manager SHOULD set this avatar using SetAvatar if appropriate. Emitted when the Avatar property changes. The avatar itself is deliberately not included in this signal, to reduce bus traffic in the (likely common) case where no running application cares about the user's own avatar.
telepathy-qt-0.9.6~git1/spec/Client_Handler.xml0000664000175000017500000003732312470405660017307 0ustar jrjr Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as a stable interface)

Handlers are the user interface for a channel. They turn an abstract Telepathy channel into something the user wants to see, like a text message stream or an audio and/or video call.

For its entire lifetime, each channel on a connection known to the channel dispatcher is either being processed by the channel dispatcher, or being handled by precisely one Handler.

Because each channel is only handled by one Handler, handlers may perform actions that only make sense to do once, such as acknowledging Text messages, doing the actual streaming for StreamedMedia channels with the MediaSignalling interface, or transferring the file in FileTransfer channels.

When a new incoming channel (one with Requested = FALSE) is offered to Approvers by the channel dispatcher, it also offers the Approvers a list of all the running or activatable handlers whose HandlerChannelFilter property (possibly as cached in the .client file) indicates that they are able to handle the channel. The Approvers can choose one of those channel handlers to handle the channel.

When a new outgoing channel (one with Requested = TRUE) appears, the channel dispatcher passes it to an appropriate channel handler automatically.

A specification of the channels that this channel handler can deal with. It will be offered to approvers as a potential channel handler for bundles that contain only suitable channels, or for suitable channels that must be handled separately.

This property works in exactly the same way as the Client.Observer.ObserverChannelFilter property. In particular, it cannot change while the handler process continues to own the corresponding Client bus name.

In the .client file, it is represented in the same way as ObserverChannelFilter, but the group has the same name as this interface and the keys start with HandlerChannelFilter instead of ObserverChannelFilter.

If true, channels destined for this handler are automatically handled, without invoking approvers.

The intended usage is to allow a client handling one channel to pick up closely related channels. Suppose a client capable of handling both Text and StreamedMedia, org.freedesktop.Telepathy.Client.Empathy, is handling a StreamedMedia channel. That client can take a second well-known bus name, say org.freedesktop.Telepathy.Client.Empathy._1._42.Bundle1, and configure an object at /org/freedesktop/Telepathy/Client/Empathy/_1/_42/Bundle1 with BypassApproval = TRUE, whose HandlerChannelFilter matches closely related Text channels by their Bundle property.

For service-activatable handlers, this property should be specified in the handler's .client file as follows:

[org.freedesktop.Telepathy.Client.Handler]
BypassApproval=true
A DBus_Interface, followed by a slash '/' character and an identifier for a capability defined by that interface. The capability identifier SHOULD be in lower case. If an interface references an external specification which is case-insensitive (such as MIME), then names from that specification MUST be normalized to lower-case before providing them to this Telepathy API, so that implementations can safely rely on simple byte-by-byte comparison. These aren't D-Bus core Properties, and we want them to look visibly different.

So far, all client capabilities are defined by the MediaSignalling interface.

The set of additional capabilities supported by this handler. This describes things like support for streamed media codecs and NAT traversal mechanisms: see the Contact Capabilities interface for more details.

For handlers that have a .client file, the channel dispatcher may discover this property from the org.freedesktop.Telepathy.Client.Handler.Capabilities group; for each capability, that group contains a key whose name is the capability, with value true. Keys with other values SHOULD NOT appear in this group.

For instance, the .client file for a streamed media handler that supports ICE-UDP NAT traversal, Speex audio, and Theora and H264 video might contain this group:

[org.freedesktop.Telepathy.Client.Handler.Capabilities]
org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/ice-udp=true
org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/audio/speex=true
org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/video/theora=true
org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/video/h264=true

Like the HandlerChannelFilter property, this property cannot change while the Handler owns its Client bus name. However, the .client file, if any, can change (due to upgrades or installation of pluggable codecs), and the capabilities really supported by the handler might not exactly match what is cached in the .client file.

The client file is installed statically and is intended to list codecs etc. that the handler guarantees it can support (e.g. by having a hard dependency on them), whereas the running handler process might be able to find additional codecs.

Called by the channel dispatcher when this client should handle these channels, or when this client should present channels that it is already handling to the user (e.g. bring them into the foreground).

Clients are expected to know what channels they're already handling, and which channel object path corresponds to which window or tab. This can easily be done using a hash table keyed by channels' object paths.

This method can raise any D-Bus error. If it does, the handler is assumed to have failed or crashed, and the channel dispatcher MUST recover in an implementation-specific way; it MAY attempt to dispatch the channels to another handler, or close the channels.

If closing the channels, it is RECOMMENDED that the channel dispatcher attempts to close the channels using Channel.Close, but resorts to calling Channel.Interface.Destroyable.Destroy (if available) or ignoring the channel (if not) if the same handler repeatedly fails to handle channels.

After HandleChannels returns successfully, the client process is considered to be responsible for the channel until it its unique name disappears from the bus.

If a process has multiple Client bus names - some temporary and some long-lived - and drops one of the temporary bus names in order to reduce the set of channels that it will handle, any channels that it is already handling should remain unaffected.

The Account with which the channels are associated. The well-known bus name to use is that of the AccountManager. The Connection with which the channels are associated. The well-known bus name to use can be derived from this object path by removing the leading '/' and replacing all subsequent '/' by '.'. The channels and their immutable properties. Their well-known bus name is the same as that of the Connection.

The requests satisfied by these channels.

If the handler implements Requests, this tells it that these channels match previous AddRequest calls that it may have received.

There can be more than one, if they were EnsureChannel requests.

The time at which user action occurred, or 0 if this channel is to be handled for some reason not involving user action. Handlers SHOULD use this for focus-stealing prevention, if applicable. This property has the same semantic as User_Action_Timestamp but is unsigned for historical reasons.

Additional information about these channels. Currently defined keys are:

request-properties - a{oa{sv}}
A map from ChannelRequest paths listed in Requests_Satisfied to Qualified_Property_Value_Maps containing namespaced immutable properties of each request.

When more keys are defined for this dictionary, all will be optional; handlers MAY safely ignore any entry in this dictionary.

A list of the channels that this process is currently handling.

There is no change notification.

This property exists for state recovery - it makes it possible for channel handling to survive a ChannelDispatcher crash.

If the channel dispatcher is automatically replaced, the replacement can discover all Handlers by looking for the Client well-known bus names, and discover which channels they are currently handling. Once this has been done, all unhandled channels can be re-dispatched, and the only issue visible to the user is that unhandled channels that they have already approved might be sent back to Approvers.

The value of this property SHOULD be the same for all Client instances that share a unique bus name, and SHOULD include all channels that are being handled, even if they were conceptually handled by a different Client instance.

Otherwise, when a process released a temporary Client name, channels that it handled because of that Client name would no longer be state-recoverable.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Balance.xml0000664000175000017500000001433512470405660022116 0ustar jrjr Copyright © 2009 Collabora Ltd. Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

In many real-time communication services the user can pay for certain services, typically calls to the PSTN, in advance. In (at least) Skype, it's possible to query the current balance in a machine-readable way.

An amount of money in a specified currency. For example, 3.21 British pounds would conventionally be represented by (Amount = 321, Scale = 2, Currency = "GBP"), but could be represented by (Amount = 3210, Scale = 3, Currency = "GBP") in a service that records balance in units of 0.001 pounds.

As a special case, if Amount = 0, Scale = 2**32 - 1 (i.e. the largest possible 32-bit unsigned integer) and Currency = "", this indicates an unknown amount.

The amount, expressed as a fixed-point number with decimal scale defined by the Scale field; for instance, an Amount value of 1234 with Scale of 2 represents 12.34 in the currency unit given by the Currency field.

The decimal scale for the fixed point value of the Amount field, defining the number of rightmost decimal digits from the integer value which form the fractional part of the resulting currency value.

As well as defining the interpretation of Amount, user interfaces may use this value to determine the precision with which to display the amount.

The currency code represented by this amount, which SHOULD be an international currency code such as "EUR", "USD", or "JPY" if possible. An empty string can be used to indicate that the currency is not known.

The user's balance on the account corresponding to this Connection. A negative amount may be possible on some services, and indicates that the user owes money to the service provider.

On initial connection, this property may have an unknown value, represented by Amount = 0, Scale = 2**32 - 1 (the largest possible 32-bit unsigned integer) and Currency = "".

A URI the user may visit via the web browser to manage and top-up their account balance. This property is not guaranteed to be well-defined until the connection becomes Connected; there is no change notification. Different protocols and even servers or gateways (e.g. SIP and XMPP PSTN gateways) will have a different website used to manage a user's account balance. This property enables the client to provide that to the user. A Connection Manager MAY set this itself (because it is static or discoverable), or expose it as a connection parameter.

Emitted when the user's balance has changed.

The new value of the AccountBalance property.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Contacts.xml0000664000175000017500000002522312470405660022345 0ustar jrjr Copyright (C) 2005-2008 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

This interface allows many attributes of many contacts to be obtained in a single D-Bus round trip.

Each contact attribute has an string identifier (Contact_Attribute), which is namespaced by the D-Bus interface which defines it.

A DBus_Interface, followed by a slash '/' character and an identifier for an attribute defined by that interface. The attribute identifier SHOULD be in lower case. These aren't D-Bus core Properties, and we want them to look visibly different. Some of the attributes of a single contact. The name of the attribute The value of the attribute Mapping returned by GetContactAttributes, representing a collection of Contacts and their requested attributes. A contact Attributes of that contact A list of D-Bus interfaces for which GetContactAttributes is expected to work. This cannot change during the lifetime of the Connection. Return any number of contact attributes for the given handles. An array of handles representing contacts.

A list of strings indicating which D-Bus interfaces the calling process is interested in. All supported attributes from these interfaces, whose values can be obtained without additional network activity, will be in the reply.

Connection managers SHOULD ignore interfaces requested which they do not support (i.e. those not mentioned in the ContactAttributeInterfaces property.)

This simplifies client-side code. Clients which care may distinguish between unsupported interfaces (e.g. this Connection does not support Avatars), and interfaces on which no information is known for these contacts (e.g. we don't know the avatar tokens of any of the contacts, so we omitted them all) by inspecting ContactAttributeInterfaces.

Attributes from the interface org.freedesktop.Telepathy.Connection are always returned, and need not be requested explicitly.

As well as returning cached information immediately, the connection MAY start asynchronous requests to obtain better values for the contact attributes. If better values are later obtained by this process, they will be indicated with the usual signals (such as AliasesChanged).

For instance, an XMPP connection manager could download vCards in response to a request for Aliasing attributes.
requesting information for interfaces not mentioned in ContactAttributeInterfaces is no longer an error. Be aware that older connection managers may still consider this an error.

If true, all handles that appear as keys in the result have been held on behalf of the calling process, as if by a call to Connection.HoldHandles. (If HasImmortalHandles is true, which SHOULD be the case in all new connection managers, this has no effect.)

For further round-trip avoidance.

A dictionary mapping the contact handles to contact attributes. If any of the requested handles are in fact invalid, they are simply omitted from this mapping. If contact attributes are not immediately known, the behaviour is defined by the interface; the attribute should either be omitted from the result or replaced with a default value.

Each contact's attributes will always include at least the identifier that would be obtained by inspecting the handle (org.freedesktop.Telepathy.Connection/contact-id).

Return any number of contact attributes for the given identifier. This is for a single identifier to make it simpler to use for the most common use case. For multiple contacts case, GetContactAttributes should be used. An identifier representing a contact.

A list of strings indicating which D-Bus interfaces the calling process is interested in. All supported attributes from these interfaces, whose values can be obtained without additional network activity, will be in the reply.

See GetContactAttributes for details.

The contact's handle, as returned by RequestHandles

All supported attributes of the contact on the given interfaces that can be returned without network round-trips. If contact attributes are not immediately known, the behaviour is defined by the interface; the attribute should either be omitted from the result or replaced with a default value.

The contact's attributes will always include at least the identifier that would be obtained by inspecting the handle (org.freedesktop.Telepathy.Connection/contact-id).

telepathy-qt-0.9.6~git1/spec/Call_Content.xml0000664000175000017500000002100312470405660016765 0ustar jrjr Copyright © 2009-2010 Collabora Ltd. Copyright © 2009-2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

This object represents one Content inside a Call1. For example, in an audio/video call there would be one audio content and one video content. Each content has one or more Stream objects which represent the actual transport to one or more remote contacts.

There are two cases where multiple streams may happen:
  • Calls with more than two participants, if the protocol does not support multicast, and does not have mixer proxy.
  • With jingle, when calling a contact connected from multiple resources, a stream is created for each resource. Once the remote contact answered from one of its resources, all other streams get removed.

For protocols that support muting all streams of a given content separately, this object MAY also implement the Mute interface

previously there were no arguments Remove the content from the call. This will cause Call1.ContentRemoved((self_handle, User_Requested, "", "")) to be emitted. Raised when a Call doesn't support removing contents (e.g. a Google Talk video call).

Extra interfaces provided by this content, such as Content.Interface.Media, Interface.Hold or Interface.Mute. This SHOULD NOT include the Content interface itself, and cannot change once the content has been created.

The name of the content.

The content name property should be meaningful, so should be given a name which is significant to the user. The name could be the "audio" or "video" string localized, or perhaps include some string identifying the source, such as a webcam identifier.

The media type of this content.

The disposition of this content, which defines whether to automatically start sending data on the streams when Accept is called on the channel. The content has no specific disposition.

The content was initially part of the call. When Accept is called on the channel, all streams of this content with LocalSendingState set to Pending_Send will be moved to Sending as if SetSending (True) had been called.

The disposition of this content. plural version, renamed from StreamAdded

Emitted when streams are added to a call.

The Streams which were added.
plural version, renamed from StreamRemoved

Emitted when streams are removed from a call

The Streams which were removed. Why the content was removed.

The list of Stream objects that exist in this content.

In a conference call multiple parties can share one media content (say, audio), but the streaming of that media can either be shared or separate. For example, in a multicast conference all contacts would share one stream, while in a Muji conference there would be a stream for each participant.

Change notification is through the StreamsAdded and StreamsRemoved signals.

telepathy-qt-0.9.6~git1/spec/Account_Interface_Hidden.xml0000664000175000017500000000617612470405660021265 0ustar jrjr Copyright © 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft 1)

An interface for flagging certain accounts as hidden, so that they do not appear in the account manager's standard lists of accounts. Accounts whose Hidden property is True are intended for non-interactive use (by non-user-visible services), and appear on the AccountManager.Interface.Hidden.DRAFT1 interface; in all other respects, they behave like any other account.

XMPP, in particular, is increasingly used for purposes other than instant messaging and VoIP. For instance, extensions exist for inter-device bookmark synchronization.

While obviously these services could re-use connections intended for instant messaging, in some cases you might want to use a different account. (Perhaps your bookmark sync provider is not your IM provider.) This API allows such auxiliary accounts to exist in Telepathy, while not being displayed in standard user interfaces for IM, VoIP, and friends.

If True, this account is intended for non-interactive use, and thus should not be presented to the user. It will not appear in properties and signals on the main AccountManager interface; instead, it will show up on AccountManager.Interface.Hidden.DRAFT1.

telepathy-qt-0.9.6~git1/spec/Channel_Type_Call.xml0000664000175000017500000021634512470405660017743 0ustar jrjr Copyright © 2009-2010 Collabora Limited Copyright © 2009-2010 Nokia Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. (as stable API)

A channel type for making audio and video calls. Call channels supersede the old StreamedMedia channel type. Call channels are much more flexible than its predecessor and allow more than two participants.

Handlers are advised against executing all the media signalling, codec and candidate negotiation themselves but instead use a helper library such as telepathy-farstream which when given a new Call channel will set up the transports and codecs and create GStreamer pads which can be added to the handler UI. This is useful as it means the handler does not have to worry how exactly the connection between the call participants is being made.

The TargetHandle and TargetID properties in a Call channel refer to the contact that the user initially called, or which contact initially called the user. Even in a conference call, where there are multiple contacts in the call, these properties refer to the initial contact, who might have left the conference since then. As a result, handlers should not rely on these properties.

Contents

Content objects represent the actual media that forms the Call (for example an audio content and a video content). Calls always have one or more Content objects associated with them. As a result, a new Call channel request MUST have either InitialAudio=True, or InitialVideo=True, or both, as the Requestable Channel Classes will document.

Content objects have one or more stream associated with them. More information on these streams and how to maniuplate them can be found on the Content interface page.

Outgoing calls

To make an audio-only call to a contact foo@example.com handlers should call:

CreateChannel({
  ...ChannelType: ...Call1,
  ...TargetHandleType: Contact,
  ...TargetID: 'foo@example.com',
  ...InitialAudio: True,
})

As always, TargetHandle may be used in place of TargetID if the contact's handle is already known. To make an audio and video call, the handler should also specify InitialVideo The connection manager SHOULD return a channel whose immutable properties contain the local user as the InitiatorHandle, the remote contact as the TargetHandle, Requested = True (indicating the call is outgoing).

After a new Call channel is requested, the CallState property will be Pending_Initiator. As the local user is the initiator, the call must be accepted by the handler by calling the Accept method. At this point, CallState changes to Initialising, which signifies that the call is waiting for the network to do something. When the CM has information indicating that the remote contact has been notified about the call (or immediately if the network is known not to convey such information) it should also change to Initialised. All changes to the CallState property are signalled using the CallStateChanged signal.

When the call is accepted by the remote contact, the CallStateChanged signal fires again to show that CallState = Accepted.

At this point telepathy-farstream will signal that a pad is available for the handler to show in the user interface. Once media is correctly flowing in both directions, the state will change to Active, to inform the user that they have a correctly working call there is nothing amiss.

Missed calls

If the remote contact does not accept the call in time, then the call can be terminated by the server. Note that this only happens in some protocols. Most XMPP clients, for example, do not do this and rely on the call initiator terminating the call. A missed call is shown in a Call channel by the CallState property changing to Ended, and the CallStateReason property changing to (remote contact, No_Answer, "").

Rejected calls

If the remote contact decides he or she does not feel like talking to the local user, he or she can reject his or her incoming call. This will be shown in the Call channel by CallState changing to Ended and the CallStateReason property changing to (remote contact, User_Requested, "org.freedesktop.Telepathy.Error.Rejected").

Incoming calls

When an incoming call occurs, something like the following NewChannels signal will occur:

NewChannels([
  /org/freedesktop/Telepathy/Connection/foo/bar/foo_40bar_2ecom/CallChannel,
  {
    ...ChannelType: ...Call1,
    ...TargetHandleType: Contact,
    ...TargetID: 'foo@example.com',
    ...TargetHandle: 42,
    ...Requested: False,
    ...InitialAudio: True,
    ...InitialVideo: True,
    ...InitialAudioName: "audio",
    ...InitialVideoName: "video",
    ...MutableContents: True,
  }])

The InitialAudio and InitialVideo properties show that the call has been started with two contents: one for audio streaming and one for video streaming. The InitialAudioName and InitialVideoName properties also show that the aforementioned audio and video contents have names "audio" and "video".

Once the handler has notified the local user that there is an incoming call waiting for acceptance, the handler should call SetRinging to let the CM know. The new channel should also be given to telepathy-farstream to work out how the two participants will connect together. telepathy-farstream will call the appropriate methods on the call's Contents to negotiate codecs and transports.

To pick up the call, the handler should call Accept. The CallState property changes to Accepted and once media is being transferred, telepathy-farstream will notify the handler of a new pad to be shown to the local user in the UI. Once media is correctly flowing in both directions, the state will change to Active, to inform the user that they have a correctly working call there is nothing amiss.

To reject the call, the handler should call the Hangup method. The CallState property will change to Ended and the CallStateReason property will change to (self handle, User_Requested, "org.freedesktop.Telepathy.Error.Rejected").

Ongoing calls

Adding and removing contents

When a call is open, new contents can be added as long as the CM supports it. The MutableContents property will let the handler know whether further contents can be added or existing contents removed. An example of this is starting a voice call between a contact and then adding a video content. To do this, the should call AddContent like this:

AddContent("video",
           Video)

Assuming no errors, the new video content will be added to the call. telepathy-farstream will pick up the new content and perform the transport and codec negotiation automatically. telpathy-farstream will signal when the video is ready to show in the handler's user interface.

A similar method is used for removing contents from a call, except that the Remove method is on the Content object.

Ending the call

To end the call, the handler should call the Hangup method. The CallState property will change to Ended and CallStateReason will change to (self handle, User_Requested, "org.freedesktop.Telepathy.Error.Cancelled").

If the other participant hangs up first then the CallState property will change to Ended and CallStateReason will change to (remote contact, User_Requested, "org.freedesktop.Telepathy.Error.Terminated").

Multi-party calls

Requestable channel classes

The RequestableChannelClasses for Call1 channels can be:

[( Fixed = { ...ChannelType: ...Call1,
            ...TargetHandleType: Contact,
            ...InitialVideo: True
          },
  Allowed = [ ...InitialVideoName,
              ...InitialAudio,
              ...InitialAudioName
            ]
),
( Fixed = { ...ChannelType: ...Call1,
            ...TargetHandleType: Contact,
            ...InitialAudio: True
          },
  Allowed = [ ...InitialAudioName,
              ...InitialVideo,
              ...InitialVideoName
            ]
)]

Clients aren't allowed to make outgoing calls that have neither initial audio nor initial video. Clearly, CMs which don't support video should leave out the first class and omit InitialVideo from the second class, and vice versa for CMs without audio support.

Handlers should not close Call1 channels without first calling Hangup on the channel. If a Call handler crashes, the ChannelDispatcher will call Close on the channel which SHOULD also imply a call to Hangup(User_Requested, "org.freedesktop.Telepathy.Error.Terminated", "") before actually closing the channel.

renamed from Ringing

Indicate that the local user has been alerted about the incoming call.

This method is only useful if the channel's Requested property is False, and the CallState is Initialised (an incoming call is ready and waiting for the user to be notified). Calling this method SHOULD set CallFlags' bit Locally_Ringing, and notify the remote contact that the local user has been alerted (if the protocol supports this); repeated calls to this method SHOULD succeed, but have no further effect.

In all other states, this method SHOULD fail with the error NotAvailable.

The call was Requested, so ringing does not make sense. The call is no longer in state Initialised.
renamed from Ringing

Notifies the CM that the local user is already in a call, so this call has been put in a call-waiting style queue.

This method is only useful if the channel's Requested property is False, and the CallState is Initialising or Initialised. Calling this method SHOULD set CallFlags' bit Locally_Queued, and notify the remote contact that the call is in a queue (if the protocol supports this); repeated calls to this method SHOULD succeed, but have no further effect.

Locally_Queued is a little like Locally_Held, but applies to calls that have not been Accepted (the Locally_Queued flag should be unset by the CM when Accept is called). It should also be set in response to the state of the world, rather than in response to user action.

The call was Requested, so queueing does not make sense. The call is no longer in state Initialising or Initialised.

For incoming calls in state Initialised, accept the incoming call. This changes the CallState to Accepted.

For outgoing calls in state Pending_Initiator, actually call the remote contact; this changes the CallState to Initialising.

Otherwise, this method SHOULD fail with the error NotAvailable.

This method should be called exactly once per Call, by whatever client (user interface) is handling the channel.

When this method is called, for each Content whose Disposition is Initial, any streams where the LocalSendingState is Pending_Send will be moved to Sending as if SetSending(True) had been called.

The call is not in one of the states where this method makes sense.
Request that the call is ended. All contents will be removed from the Call so that the Contents property will be the empty list. A generic hangup reason. A more specific reason for the call hangup, if one is available, or an empty string otherwise. A human-readable message to be sent to the remote contact(s). XMPP Jingle allows calls to be terminated with a human-readable message. The call has already been ended. Request that a new Content of type Content_Type is added to the Call1. Handlers should check the value of the MutableContents property before trying to add another content as it might not be allowed.

The suggested name of the content to add.

The content name property should be meaningful, so should be given a name which is significant to the user. The name could be a localized "audio", "video" or perhaps include some string identifying the source, such as a webcam identifier.

If there is already a content with the same name as this property then a sensible suffix should be added. For example, if this argument is "audio" but a content of the same name already exists, a sensible suffix such as " (1)" is appended to name the new content "audio (1)". A further content with the name "audio" would then be named "audio (2)".

The media stream type of the content to be added to the call. The requested initial direction of the new content. Path to the newly-created Call1.Content object. The media stream type given is invalid. The media stream type requested is not implemented by the CM. The media stream type requested is not supported by either the local or remote side. The content type requested cannot be added to this call. Examples of why this might be the case include because a second video stream cannot be added, or a content cannot be added when the content set isn't mutable.

Emitted when a new Content is added to the call.

Path to the newly-created Content object.

Emitted when a Content is removed from the call.

The Content which was removed. Why the content was removed.

The list of Content objects that are part of this call. Change notification is via the ContentAdded and ContentRemoved signals.

The state of a call, as a whole.

The allowed transitions are:

  • Pending_Initiator → Initialising (for outgoing calls, when Accept is called)
  • Initialising → Initialised (for outgoing calls, when the remote client indicates that the user has been notified about the call. If the network is known not to provide feedback about whether the remote side is ringing, then the call should immediately be set to Initialised.
  • Initialising → Initialised (for incoming calls, when e.g. the implementation has been initialised far enough that it is sensible to notify the user about the call (to reduce the probability that the user will pick up the call and have it immediately fail). The UI should then alert the user about the call, and call SetRinging)
  • Initialised → Accepted (for outgoing calls to a contact, when the remote contact accepts the call; for incoming calls, when Accept is called.)
  • Accepted → Active (when the local user successfully joins the call/conference, and media is known to be flowing successfully; also, when temporary connection problems are resolved (See below)). If the network is known not to provide feedback about when the call is properly connected, the call should immediately be set to Active.
  • Active → Accepted (when there are temporary connection problems that the CM is aware of and able to recover from)
  • any state → Ended (when the call is terminated normally, or when an error occurs that the CM is unable to recover from)

Clients MAY consider unknown values from this enum to be an error - additional values will not be defined after the Call specification is declared to be stable.

The call state is not known. This call state MUST NOT appear as a value of the CallState property, but MAY be used by client code to represent calls whose state is as yet unknown. The initiator of the call hasn't accepted the call yet. This state only makes sense for outgoing calls, where it means that the local user has not yet sent any signalling messages to the remote user(s), and will not do so until Accept is called. Progress has been made in placing the call, but the contact has not been made aware of the call yet. This corresponds to SIP's status code 183 Session Progress, and should be used for the period where the CM is waiting for the streaming implementation to initialise (before sending the initial INVITE or equivalent) and when the outgoing call has reached a gateway or ICE negotiation is pending. UIs should not produce a dialtone or start ringing if the call is in this state. In the outgoing case: at least one called user has been alerted about the call (a SIP 180 (Ringing) packet or equivalent has been received) but none have answered, so the call cannot go to Accepted (use Ringing to determine which members have been informed and which haven't, if you care). UIs SHOULD produce a dialtone for outgoing calls in this state. In the incoming case, the local user should be informed of the call as soon as the call reaches this state (and SetRinging should be called to inform the CM that this has happened, so that it can relay this fact to the caller using a SIP 180 (Ringing) packet or equivalent). The contact being called has accepted the call, but the call is not in the Active state (The most common reason for this is that the streaming implementation hasn't connected yet). The contact being called has accepted the call, and discourse between at least two parties should now be possible. The call has ended, either via normal termination or an error.
A set of flags representing additional information than is available in CallState. Many of these flags only make sense in a particular (or may explain why a call is in a specific state). The call has been put on hold by the local user, e.g. using the Hold interface. This flag SHOULD only be set if there is at least one Content, and all Contents are locally held. Otherwise, in transient situations where some but not all contents are on hold, UIs would falsely indicate that the call as a whole is on hold, which could lead to the user saying something they'll regret, while under the impression that the other contacts can't hear them! This flag exists as a simplified proxy for HoldStateChanged, to reduce the number of signals that need to be listened to by a simple UI. This flag exists for observability of the SetRinging method (e.g. so that loggers can tell whether the call got as far as alerting the user, or whether something went wrong before then). It should be set when the SetRinging is called, and unset when the call leaves Initialised. This flag exists for observability of the SetQueued method. It should be set when the SetQueued is called, and unset when the call leaves Initialising or Initialised. The initiator of the call originally called a contact other than the current recipient of the call, but the call was then forwarded or diverted. This flag only makes sense on outgoing calls. It SHOULD be set or unset according to informational messages from other contacts. This flag only occurs when the CallState is Ended. The call with this flag set has ended, but not all resources corresponding to the call have been freed yet. Depending on the protocol there might be some audible feedback while the clearing flag is set. In calls following the ITU-T Q.931 standard there is a period of time between the call ending and the underlying channel being completely free for re-use.

A map used to provide optional extensible details for the CallState, CallFlags and/or CallStateReason.

Well-known keys and their corresponding value types include:

hangup-message - s
An optional human-readable message sent when the call was ended, corresponding to the Message argument to the Hangup method. This is only applicable when the call state is Ended. XMPP Jingle can send such messages.
queue-message - s
An optional human-readable message sent when the local contact is being held in a queue. This is only applicable when Locally_Queued is in the call flags. SIP 182 notifications can have human-readable messages attached.
debug-message - s
A message giving further details of any error indicated by the CallStateReason. This will not normally be localized or suitable for display to users, and is only applicable when the call state is Ended.
balance-required - i
Optionally included when a call cannot be connected because there is InsufficientBalance, indicating what the required balance would be to place this call. The value of this key has the same units and scale as AccountBalance.
forwarded-to - u
Optionally included when the CallStateReason is Forwarded. It indicates the handle to whom the Call was forwarded.
forwarded-to-id - s
The string that would result from inspecting the forwarded-to key (i.e. the contact's identifier in the IM protocol).

The current high-level state of this call. The CallFlags provide additional information, and the CallStateReason and CallStateDetails explain the reason for the current values for those properties.

Note that when in a conference call, this property is purely to show your state in joining the call. The receiver (or remote contact) in this context is the conference server itself. The property does not change when other call members' states change.

Clients MAY consider unknown values in this property to be an error.

Flags representing the status of the call as a whole, providing more specific information than the CallState.

Clients are expected to ignore unknown flags in this property, without error.

When an ongoing call is active and not on hold or has any other problems, this property will be 0.

A simple representation of the reason for a change in the call's state, which may be used by simple clients, or used as a fallback when the DBus_Reason member of a Call_State_Reason struct is not understood. We just don't know. Unknown values of this enum SHOULD also be treated like this. Situation normal. Progress has been made in the setup/teardown of the call (and it didn't require any user interaction).

The change was requested by the contact indicated by the Actor member of a Call_State_Reason struct.

The DBus_Reason SHOULD be the empty string if the call was terminated normally, but MAY be a non-empty error name to indicate error-like call termination reasons (kicked from a conference by a moderator, etc.).

The call was forwarded. If known, the handle of the contact the call was forwarded to will be indicated by the "forwarded-to" member of a CallStateDetails dictionnary in the CallStateChanged signal.

The CallState changed from Initialised or Ended (or a content's direction changed) because it was rejected by the remote user.

Corresponds to Rejected

The CallState changed from Initialised or Ended because the initiator ended the call before the receiver accepted it. With an incoming call this state change reason signifies a missed call, or one that was picked up elsewhere before it was picked up here.

Corresponds to NoAnswer or PickedUpElsewhere

The CallState changed because one of the addresses does not exist on the network.

Corresponds to DoesNotExist

The CallState changed because the local user is not authorised.

Corresponds to PermissionDenied or InsufficientBalance

The CallState changed from Initialised Ended because the receiver is busy (e.g. is already engaged in another call, and has not placed the initiator in a call-waiting queue).

Corresponds to Busy

There has been an unexpected error in either the CM or some other local component.

Corresponds to Confused or Media.StreamingError

There has been an unexpected error in the server or some other remote component.

Corresponds to ServiceConfused

There has been a network error related to the CM or the signalling part of the call (compare and contrast: Streaming_Error).

Corresponds to NetworkError

Some aspect of the content is unsupported so has to be removed from the call.

Corresponds to Media.UnsupportedType or Media.CodecsIncompatible

It was not possible for the streaming implementation to connect to any of the users participating in this call or content.

Corresponds to ConnectionFailed or ConnectionLost

A description of the reason for a change to the CallState and/or CallFlags.

The contact responsible for the change, or 0 if no contact was responsible. The reason, chosen from a limited set of possibilities defined by the Telepathy specification. If User_Requested then the Actor member will dictate whether it was the local user or a remote contact responsible.

A specific reason for the change, which may be a D-Bus error in the Telepathy namespace, a D-Bus error in any other namespace (for implementation-specific errors), or the empty string to indicate that the state change was not an error.

This SHOULD be an empty string for changes to any state other than Ended.

The errors Cancelled and Terminated SHOULD NOT be used here; an empty string SHOULD be used instead.

Those error names are used to indicate normal call termination by the local user or another user, respectively, in contexts where a D-Bus error name must appear.

An optional debug message, to expediate debugging the potentially many processes involved in a call. This may be communicated across the network in protocols that support doing so, but it is not essential.

The reason for the last change to the CallState and/or CallFlags. The CallStateDetails MAY provide additional information.

Emitted when the state of the call as a whole changes.

This signal is emitted for any change in the properties corresponding to its arguments, even if the other properties referenced remain unchanged.

The new value of the CallState property. The new value of the CallFlags property. The new value of the CallStateReason property. The new value of the CallStateDetails property.

If this property is True, all of the media streaming is done by some mechanism outside the scope of Telepathy.

A connection manager might be intended for a specialized hardware device, which will take care of the audio streaming (e.g. telepathy-ring, which uses GSM hardware which does the actual audio streaming for the call).

If this is False, the handler is responsible for doing the actual media streaming for at least some contents itself. Those contents will have the Media interface, to communicate the necessary information to a streaming implementation. Connection managers SHOULD operate like this, if possible.

Many connection managers (such as telepathy-gabble) only do the call signalling, and expect the client to do the actual streaming using something like Farsight, to improve latency and allow better UI integration.

A set of flags representing the status of a remote contact in a call.

It is protocol- and client-specific whether a particular contact will ever have a particular flag set on them, and Telepathy clients SHOULD NOT assume that a flag will ever be set.

180 Ringing in SIP, and its equivalent in XMPP, are optional informational messages, and implementations are not required to send them. The same applies to the messages used to indicate hold state.

The remote contact's client has told us that the contact has been alerted about the call but has not responded.

This is a flag per member, not a flag for the call as a whole, because in Muji conference calls, you could invite someone and have their state be "ringing" for a while.

The call member has put this call on hold.

This is a flag per member, not a flag for the call as a whole, because in conference calls, any member could put the conference on hold.

This contact has merged this call into a conference. Note that GSM provides a notification when the remote party merges a call into a conference, but not when it is split out again; thus, this flag can only indicate that the call has been part of a conference at some point. If a GSM connection manager receives a notification that a call has been merged into a conference a second time, it SHOULD represent this by clearing and immediately re-setting this flag on the remote contact.
A mapping from handles to their current state in the call. Emitted when the CallMembers property changes in any way, either because contacts have been added to the call, contacts have been removed from the call, or contacts' flags have changed. A map from members of the call to their new call member flags, including at least the members who have been added to CallMembers, and the members whose flags have changed. The identifiers of the contacts in the Flags_Changed map. A list of members who have left the call, i.e. keys to be removed from CallMembers. A structured reason for the change.

A mapping from the remote contacts that are part of this call to flags describing their status. This mapping never has the local user's handle as a key.

When the call ends, this property should be an empty list, and notified with CallMembersChanged

If the Call implements Group and the Group members are channel-specific handles, then this call SHOULD also use channel-specific handles.

Anonymous members are exposed as channel-specific handles with no owner.

The string identifiers for handles mentioned in CallMembers, to give clients the minimal information necessary to create contacts without waiting for round-trips.

If set on a requested channel, this indicates the transport that should be used for this call. Where not applicable, this property is defined to be Unknown, in particular, on CMs with hardware streaming.

When implementing a voip gateway one wants the outgoing leg of the gatewayed to have the same transport as the incoming leg. This property allows the gateway to request a Call with the right transport from the CM.

If set to True in a channel request that will create a new channel, the connection manager should immediately attempt to establish an audio stream to the remote contact, making it unnecessary for the client to call AddContent.

If this property, or InitialVideo, is passed to EnsureChannel (as opposed to CreateChannel), the connection manager SHOULD ignore these properties when checking whether it can return an existing channel as suitable; these properties only become significant when the connection manager has decided to create a new channel.

If True on a requested channel, this indicates that the audio stream has already been requested and the client does not need to call RequestStreams, although it MAY still do so.

If True on an unrequested (incoming) channel, this indicates that the remote contact initially requested an audio stream; this does not imply that that audio stream is still active (as indicated by Contents).

The name of this new content can be decided by using the InitialAudioName property.

Connection managers that support the ContactCapabilities interface SHOULD represent the capabilities of receiving audio and/or video calls by including a channel class in a contact's capabilities with ChannelType = Call in the fixed properties dictionary, and InitialAudio and/or InitialVideo in the allowed properties list. Clients wishing to discover whether a particular contact is likely to be able to receive audio and/or video calls SHOULD use this information.

Not all clients support video calls, and it would also be possible (although unlikely) to have a client which could only stream video, not audio.

Clients that are willing to receive audio and/or video calls SHOULD include the following among their channel classes if calling UpdateCapabilities (clients of a ChannelDispatcher SHOULD instead arrange for the ChannelDispatcher to do this, by including the filters in their HandlerChannelFilter properties):

  • { ChannelType = Call }
  • { ChannelType = Call, InitialAudio = True } if receiving calls with audio is supported
  • { ChannelType = Call, InitialVideo = True } if receiving calls with video is supported

Connection managers for protocols with capability discovery, like XMPP, need this information to advertise the appropriate capabilities for their protocol.

The same as InitialAudio, but for a video stream. This property is immutable (cannot change).

In particular, note that if this property is False, this does not imply that an active video stream has not been added, only that no video stream was active at the time the channel appeared.

This property is the correct way to discover whether connection managers, contacts etc. support video calls; it appears in capabilities structures in the same way as InitialAudio.

If InitialAudio is set to True, then this property will name the intial audio content with the value of this property.

Content names are meant to be significant, but if no name can be given to initial audio content, then its name cannot be meaningful or even localized.

If this property is empty or missing from the channel request and InitialAudio is True, then the CM must come up with a sensible for the content, such as "audio".

If the protocol has no concept of stream names then this property will not show up in the allowed properties list of the Requestable Channel Classes for call channels.

The same as InitialAudioName, but for a video stream created by setting InitialVideo to True. This property is immutable and so cannot change.

If True, a stream of a different content type can be added after the Channel has been requested

If this property is missing, clients SHOULD assume that it is False, and thus that the channel's streams cannot be changed once the call has started.

If this property isn't present in the "allowed" set in any of the Call entries contact capabilities, then user interfaces MAY choose to show a separate "call" option for each class of call.

For example, once an audio-only Google Talk call has started, it is not possible to add a video stream; both audio and video must be requested at the start of the call if video is desired. User interfaces may use this pseudo-capability as a hint to display separate "Audio call" and "Video call" buttons, rather than a single "Call1" button with the option to add and remove video once the call has started for contacts without this flag.

This client supports audio calls.

This client supports video calls.

The client can implement streaming for streams whose Transport property is GTalk_P2P.

The client can implement streaming for streams whose Transport property is ICE.

The client can implement streaming for streams whose Transport property is WLM_2009.

The client can implement streaming for streams whose Transport property is SHM.

The client supports media streaming with H264 (etc.).

This handler capability token is a one of a family of similar tokens: for any other audio or video codec whose MIME type is audio/subtype or video/subtype, a handler capability token of this form may exist (the subtype MUST appear in lower case in this context). Clients MAY support more codecs than they explicitly advertise support for; clients SHOULD explicitly advertise support for their preferred codec(s), and for codecs like H264 that are, in practice, significant in codec negotiation.

For instance, the XMPP capability used by the Google Video Chat web client to determine whether a client is compatible with it requires support for H264 video, so an XMPP connection manager that supports this version of Jingle should not advertise the Google Video Chat capability unless there is at least one installed client that declares that it supports video/h264 on Call channels.

For example, a client could advertise support for audio and video calls using Speex, Theora and H264 by having five handler capability tokens in its Capabilities property:

  • org.freedesktop.Telepathy.Channel.Type.Call1/audio
  • org.freedesktop.Telepathy.Channel.Type.Call1/audio/speex
  • org.freedesktop.Telepathy.Channel.Type.Call1/video
  • org.freedesktop.Telepathy.Channel.Type.Call1/video/theora
  • org.freedesktop.Telepathy.Channel.Type.Call1/video/h264

Clients MAY have media signalling abilities without explicitly supporting any particular codec, and connection managers SHOULD support this usage.

This is necessary to support gatewaying between two Telepathy connections, in which case the available codecs might not be known to the gatewaying process.

telepathy-qt-0.9.6~git1/spec/Call_Content_Media_Description.xml0000664000175000017500000002446512470405660022446 0ustar jrjr Copyright © 2009-2010 Collabora Ltd. Copyright © 2009-2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API) This object represents a remote Description Offer to which the local streaming implementation should reply with its local Description. This is intended as a temporary transactional object for use with Content.Interface.Media. There will always be 0 or 1 MediaDescription object per Content. In most cases, this object will stay alive until you call either Accept or Reject, and then disappear. There are some cases (e.g. an endpoint being removed from the call) where a MediaDescription object will disappear before you have had a chance to either Accept or Reject it. The local description to send to the remote contacts and to use in the Content. Accepts the updated Description and update the corresponding local description. If FurtherNegotiationRequired is True, calling this method will generally cause a network round-trip and a new MediaDescription to be offered (hopefully with FurtherNegotiationRequired set to False). The description given is invalid in some way. Reject the proposed update to the remote description. A structured reason for the rejection.

Extra interfaces provided by this media description. This SHOULD NOT include the Description interface itself.

If this is set to True by the CM in a MediaDescriptionOffer, it means "This is an offer under the SDP Offer/Answer model. Whatever you accept this offer with is what I will send to the other side in my answer." If this is set to False by the CM then it means "This is an Answer under the SDP Offer/Answer model, and if it remains False in the Accept(), no further codec negotiation needs to happen." If this is set to True by the streaming implementation (e.g. in an Accept or UpdateLocalMediaDescription call) then a new SDP Offer/Answer round-trip will be initiated.

True if this offer contains information from the remote side: If False then the Accept response solely depends on the capabilities and preferences of the local side. In most protocols this property will be False for the initial DescriptionOffer on an outgoing call.

A list of codecs the remote contact supports. When used with Accept, it means the locally supported codecs. The contact handle that this description applies to. This property can be used as an opaque identifier, and searched for in RemoteMembers for each Stream in this Content, to determine which Stream this MediaDescription applies to. If multiple MediaDescriptions apply to the same Stream, the SSRCs property should be used to separate media before decoding. If this property is 0, this MediaDescription applies to all streams, so the above matching method is unneccesary (e.g. in conference calls with a mixer, media from all participants is mixed into one stream). When calling Accept or UpdateLocalMediaDescription, this should always be set to 0, or omitted, because it is assumed that you send the same MediaDescription to everyone (Encoding a stream separately for each contact in a call is inefficient, and should be avoided). The remote contact these SSRCs belong to or 0. The list of Synchronisation Sources.

A map from Handle to list of Synchronisation Sources, as defined by RFC 3550.

Some protocols require the negotiation of SSRC identifiers for RTP streams. If this is the case, then MediaDescription offers will appear with this property set. The streaming implementation should then call Accept with a map from 0 to a list containing a single SSRC (which does not collide with these, or any previously seen SSRCs). If a new MediaDescription offer appears with an SSRC the same as one in LocalMediaDescriptions, then the streaming implementation should pick a new SSRC to resolve the collision.

It is expected that this list will normally be at most one element long, but it is kept as a list for extensibility. The concatenation of all SSRCs associated with a Stream should contain no duplicate entries. If there are collisions, then it is the responsibility of the protocol implementation to resolve them and generate new offers.

If this property is omitted, then the streaming implementation can assume that there is only one MediaDescription per Stream.

If there is a single multicast Call Stream with multiple Remote Members, and all members are forced to use the same MediaDescription, this map can be used by the streaming implementation to determine which video sources belong to which contacts (e.g. in order to put a name under each face in the call)

A mapping containing all properties that define the information from a MediaDescription and its interfaces.

If HasRemoteInformation is True, then this mapping will always contains at least Codecs

A D-Bus interface name, followed by a dot and a D-Bus property name. The value of the property
telepathy-qt-0.9.6~git1/spec/Call_Content_Interface_DTMF.xml0000664000175000017500000002513212470405660021566 0ustar jrjr Copyright © 2005-2010 Collabora Limited Copyright © 2005-2010 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API) An interface that gives audio Contents the ability to send DTMF events which have been established using the Call1 channel type. The event codes used are in common with those defined in RFC4733, and are listed in the DTMF_Event enumeration. A numeric event code from the DTMF_Event enum.

Start sending a DTMF tone to all eligible streams in the channel. Where possible, the tone will continue until StopTone is called. On certain protocols, it may only be possible to send events with a predetermined length. In this case, the implementation MAY emit a fixed-length tone, and the StopTone method call SHOULD return NotAvailable.

The client may wish to control the exact duration and timing of the tones sent as a result of user's interaction with the dialpad, thus starting and stopping the tone sending explicitly.

Tone overlaping or queueing is not supported, so this method can only be called if no DTMF tones are already being played.

The event id was invalid. DTMF tones are already being played.
Stop sending any DTMF tones which have been started using the StartTone or MultipleTones methods. If there is no current tone, this method will do nothing. If MultipleTones was used, the client should not assume the sending has stopped immediately; instead, the client should wait for the StoppedTones signal. On some protocols it might be impossible to cancel queued tones immediately. Continuous tones are not supported by this stream. Deprecated, since stream IDs are ignored.

A string representation of one or more DTMF events. Implementations of this method MUST support all of the following characters in this string:

  • the digits 0-9, letters A-D and a-d, and symbols '*' and '#' correspond to the members of DTMF_Event
  • any of 'p', 'P', 'x', 'X' or ',' (comma) results in an implementation-defined pause, typically for 3 seconds
  • 'w' or 'W' waits for the user to continue, by stopping interpretation of the string, and if there is more to be played, emitting the TonesDeferred signal with the rest of the string as its argument: see that signal for details

Send multiple DTMF events to all eligible streams in the channel. Each tone will be played for an implementation-defined number of milliseconds (typically 250ms), followed by a gap before the next tone is played (typically 100ms). The duration and gap are defined by the protocol or connection manager.

In cases where the client knows in advance the tone sequence it wants to send, it's easier to use this method than manually start and stop each tone in the sequence.

The tone and gap lengths may need to vary for interoperability, according to the protocol and other implementations' ability to recognise tones. At the time of writing, GStreamer uses a minimum of 250ms tones and 100ms gaps when playing in-band DTMF in the normal audio stream, or 70ms tones and 50ms gaps when encoding DTMF as audio/telephone-event.

Tone overlaping or queueing is not supported, so this method can only be called if no DTMF tones are already being played.

The supplied Tones string was invalid. DTMF tones are already being played.
Indicates whether there are DTMF tones currently being sent in the channel. If so, the client should wait for StoppedTones signal before trying to send more tones.

The tones waiting for the user to continue, if any.

When this property is set to a non-empty value, TonesDeferred is emitted. When any tones are played (i.e. whenever SendingTones is emitted), this property is reset to the empty string.

The new non-empty value of DeferredTones.

Emitted when 'w' or 'W', indicating "wait for the user to continue", is encountered while playing a DTMF string queued by MultipleTones. Any queued DTMF events after the 'w', which have not yet been played, are placed in the DeferredTones property and copied into this signal's argument.

When the channel handler is ready to continue, it MAY pass the value of DeferredTones to MultipleTones, to resume sending. Alternatively, it MAY ignore the deferred tones, or even play different tones instead. Any deferred tones are discarded the next time a tone is played.

This signal SHOULD NOT be emitted if there is nothing left to play, i.e. if the 'w' was the last character in the DTMF string.

DTMF string (one or more events) that is to be played.

DTMF tone(s)are being sent to all eligible streams in the channel. The signal is provided to indicating the fact that the streams are currently being used to send one or more DTMF tones, so any other media input is not getting through to the audio stream. It also serves as a cue for the StopTone method.

True if the DTMF tones were actively cancelled via StopTone.

DTMF tones have finished playing on streams in this channel.

telepathy-qt-0.9.6~git1/spec/Channel_Type_Contact_List.xml0000664000175000017500000001256712470405660021456 0ustar jrjr Copyright (C) 2005, 2006 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

Replaced by Connection.Interface.ContactList

A channel type for representing a list of people on the server which is not used for communication. This is intended for use with the interface Channel.Interface.Group for managing buddy lists and privacy lists on the server. This channel type has no methods because all of the functionality it represents is available via the group interface.

There are currently two types of contact list: HANDLE_TYPE_LIST is a "magic" server-defined list, and HANDLE_TYPE_GROUP is a user-defined contact group.

For server-defined lists like the subscribe list, singleton instances of this channel type should be created by the connection manager at connection time if the list exists on the server, or may be requested by using the appropriate handle. These handles can be obtained using RequestHandles with a Handle_Type of HANDLE_TYPE_LIST and one of the following identifiers:

  • subscribe - the group of contacts for whom you receive presence
  • publish - the group of contacts who may receive your presence
  • hide - a group of contacts who are on the publish list but are temporarily disallowed from receiving your presence
  • allow - a group of contacts who may send you messages
  • deny - a group of contacts who may not send you messages
  • stored - on protocols where the user's contacts are stored, this contact list contains all stored contacts regardless of subscription status.

A contact can be in several server-defined lists. All lists are optional to implement. If RequestHandles or RequestChannel for a particular contact list raises an error, this indicates that the connection manager makes no particular statement about the list's contents; clients MUST NOT consider this to be fatal.

If a client wants to list all of a user's contacts, it is appropriate to use the union of the subscribe, publish and stored lists, including the local and remote pending members.

For example in XMPP, contacts who have the subscription type "none", "from", "to" and "both" can be respectively in the lists:

  • "none": stored
  • "from": stored and publish
  • "to": stored and subscribe
  • "both": stored, publish and subscribe

These contact list channels may not be closed.

For user-defined contact groups, instances of this channel type should be created by the connection manager at connection time for each group that exists on the server. New, empty groups can be created by calling RequestHandles with a Handle_Type of HANDLE_TYPE_GROUP and with the name set to the human-readable UTF-8 name of the group.

User-defined groups may be deleted by calling Close on the channel, but only if the group is already empty. Closing a channel to a non-empty group is not allowed; its members must be set to the empty set first.

On some protocols (e.g. XMPP) empty groups are not represented on the server, so disconnecting from the server and reconnecting might cause empty groups to vanish.

telepathy-qt-0.9.6~git1/spec/Channel_Type_Streamed_Media.xml0000664000175000017500000012014312470405660021721 0ustar jrjr Copyright © 2005-2009 Collabora Limited Copyright © 2005-2009 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

An audio stream A video stream The stream is disconnected. The stream is trying to connect. The stream is connected. Media are not being sent or received Media are being sent, but not received Media are being received, but not sent Media are being sent and received The local user has been asked to send media by the remote user. Call RequestStreamDirection to indicate whether or not this is acceptable. The remote user has been asked to send media by the local user. The StreamDirectionChanged signal will be emitted when the remote user accepts or rejects this change.

An unsigned integer identifying a stream within a channel.

An array of structs containing:
  • the stream identifier
  • the contact handle who the stream is with (or 0 if the stream represents more than a single member)
  • the type of the stream
  • the current stream state
  • the current direction of the stream
  • the current pending send flags
Returns an array of structs representing the streams currently active within this channel. Each stream is identified by an unsigned integer which is unique for each stream within the channel.
An array of stream identifiers (as defined in ListStreams)

Request that the given streams are removed. If all streams are removed, the channel MAY close.

Clients SHOULD NOT attempt to terminate calls by removing all the streams; instead, clients SHOULD terminate calls by removing the Group.SelfHandle from the channel, using either RemoveMembers or RemoveMembersWithReason.

A stream identifier is unknown
The stream identifier (as defined in ListStreams) The desired stream direction (a value of MediaStreamDirection)

Request a change in the direction of an existing stream. In particular, this might be useful to stop sending media of a particular type, or inform the peer that you are no longer using media that is being sent to you.

Depending on the protocol, streams which are no longer sending in either direction should be removed and a StreamRemoved signal emitted. Some direction changes can be enforced locally (for example, BIDIRECTIONAL -> RECEIVE can be achieved by merely stopping sending), others may not be possible on some protocols, and some need agreement from the remote end. In this case, the MEDIA_STREAM_PENDING_REMOTE_SEND flag will be set in the StreamDirectionChanged signal, and the signal emitted again without the flag to indicate the resulting direction when the remote end has accepted or rejected the change.

A stream identifier is unknown The requested direction is not available on this stream
A contact handle with whom to establish the streams An array of stream types (values of MediaStreamType) An array of structs (in the same order as the given stream types) containing:
  • the stream identifier
  • the contact handle who the stream is with (or 0 if the stream represents more than a single member)
  • the type of the stream
  • the current stream state
  • the current direction of the stream
  • the current pending send flags

Request that streams be established to exchange the given types of media with the given member. In general this will try and establish a bidirectional stream, but on some protocols it may not be possible to indicate to the peer that you would like to receive media, so a send-only stream will be created initially. In the cases where the stream requires remote agreement (eg you wish to receive media from them), the StreamDirectionChanged signal will be emitted with the MEDIA_STREAM_PENDING_REMOTE_SEND flag set, and the signal emitted again with the flag cleared when the remote end has replied.

If streams of the requested types already exist, calling this method results in the creation of additional streams. Accordingly, clients wishing to have exactly one audio stream or exactly one video stream SHOULD check for the current streams using ListStreams before calling this method.

It is valid to use a handle which is neither a current nor pending member in this channel's Group interface. If so, that handle will be added to the remote-pending set only when an attempt has actually been made to contact them. For further call-state notification, use the CallState interface, if supported. This usage was not allowed in spec versions below 0.17.2.

A stream type given is invalid. A stream type given is not implemented by the connection manager. Since 0.17.23, connection managers SHOULD raise this error in preference to InvalidArgument. Connection managers can't know whether an unknown number is a valid stream type that was introduced in a later spec version. That contact's client does not implement one of the given stream types. For this method, clients SHOULD consider this error and NotCapable to be equivalent. That contact's client does not implement one of the given stream types. Since 0.17.23, connection managers SHOULD raise this in preference to NotAvailable.
The stream identifier (as defined in ListStreams) The contact handle who the stream is with (or 0 if it represents more than a single member) The stream type (a value from MediaStreamType)

Emitted when a new stream has been added to this channel. Clients SHOULD assume that the stream's Media_Stream_State is initially Disconnected.

If a connection manager needs to represent the addition of a stream whose state is already Connecting or Connected, it MUST do this by emitting StreamAdded, closely followed by StreamStateChanged indicating a change to the appropriate state.

Historically, it was not clear from the StreamAdded signal what the state of the stream was. telepathy-spec 0.17.22 clarified this.

Similarly, clients SHOULD assume that the initial Media_Stream_Direction of a newly added stream is Receive, and that the initial Media_Stream_Pending_Send is Pending_Local_Send.

If a connection manager needs to represent the addition of a stream whose direction or pending-send differs from those initial values, it MUST do so by emitting StreamAdded, closely followed by StreamDirectionChanged indicating a change to the appropriate direction and pending-send state.

StreamAdded doesn't itself indicate the stream's direction; this is unfortunate, but is preserved for compatibility.

This is the appropriate direction for streams added by a remote contact on existing connection managers, and does not violate user privacy by automatically sending audio or video (audio streams start off muted, video streams start off not sending). For streams added by the local user using the client receiving the signal, the true direction can also be determined from the return value of the RequestStreams method.

Existing clients typically operate by maintaining a separate idea of the directions that they would like the streams to have, and enforcing these intended directions by calling RequestStreamDirection whenever needed.

The stream identifier (as defined in ListStreams) The new stream direction (as defined in ListStreams) The new pending send flags (as defined in ListStreams)

Emitted when the direction or pending flags of a stream are changed.

If the MEDIA_STREAM_PENDING_LOCAL_SEND flag is set, the remote user has requested that we begin sending on this stream. RequestStreamDirection should be called to indicate whether or not this change is acceptable.

This allows for a MSN-style user interface, "Fred has asked you to enable your webcam. (Accept | Reject)", if desired.

The stream identifier (as defined in ListStreams) A stream error number, one of the values of MediaStreamError A string describing the error (for debugging purposes only) Emitted when a stream encounters an error. stream_id - the stream identifier (as defined in ListStreams) Emitted when a stream has been removed from this channel. The stream identifier (as defined in ListStreams) The new stream state (as defined in ListStreams) Emitted when a member's stream's state changes.

If set to true in a channel request that will create a new channel, the connection manager should immediately attempt to establish an audio stream to the remote contact, making it unnecessary for the client to call RequestStreams.

If this property, or InitialVideo, is passed to EnsureChannel (as opposed to CreateChannel), the connection manager SHOULD ignore these properties when checking whether it can return an existing channel as suitable; these properties only become significant when the connection manager has decided to create a new channel.

If true on a requested channel, this indicates that the audio stream has already been requested and the client does not need to call RequestStreams, although it MAY still do so.

If true on an unrequested (incoming) channel, this indicates that the remote contact initially requested an audio stream; this does not imply that that audio stream is still active (as indicated by ListStreams).

This property is immutable (cannot change), and therefore SHOULD appear wherever immutable properties are reported, e.g. NewChannels signals.

This reduces D-Bus round trips.

Connection managers capable of signalling audio calls to contacts SHOULD include a channel class in RequestableChannelClasses with ChannelType = StreamedMedia and TargetHandleType = Contact in the fixed properties dictionary, and InitialAudio (and also InitialVideo, if applicable) in the allowed properties list. Clients wishing to discover whether a connection manager can signal audio and/or video calls SHOULD use this information.

Not all protocols support signalling video calls, and it would be possible (although unlikely) to have a protocol where only video, and not audio, could be signalled.

Connection managers that support the ContactCapabilities interface SHOULD represent the capabilities of receiving audio and/or video calls by including a channel class in a contact's capabilities with ChannelType = StreamedMedia in the fixed properties dictionary, and InitialAudio and/or InitialVideo in the allowed properties list. Clients wishing to discover whether a particular contact is likely to be able to receive audio and/or video calls SHOULD use this information.

Not all clients support video calls, and it would also be possible (although unlikely) to have a client which could only stream video, not audio.

Clients that are willing to receive audio and/or video calls SHOULD include the following among their channel classes if calling UpdateCapabilities (clients of a ChannelDispatcher SHOULD instead arrange for the ChannelDispatcher to do this, by including the filters in their HandlerChannelFilter properties):

  • { ChannelType = StreamedMedia }
  • { ChannelType = StreamedMedia, InitialAudio = true } if receiving calls with audio is supported
  • { ChannelType = StreamedMedia, InitialVideo = true } if receiving calls with video is supported

Connection managers for protocols with capability discovery, like XMPP, need this information to advertise the appropriate capabilities for their protocol.

The same as InitialAudio, but for a video stream. This property is immutable (cannot change).

In particular, note that if this property is false, this does not imply that an active video stream has not been added, only that no video stream was active at the time the channel appeared.

This property is the correct way to discover whether connection managers, contacts etc. support video calls; it appears in capabilities structures in the same way as InitialAudio.

If True, once streams have been requested for this channel (either by setting InitialAudio or InitialVideo when the channel is requested, or by calling RequestStreams on a channel with no streams), a stream of a different content type cannot be added; subsequent calls to RequestStreams that attempt to do so will fail.

If this property is missing, clients SHOULD assume that it is false, and thus that the channel's streams can be changed once the call has started.

If this property is present in the "allowed" set in all of the StreamedMedia entries in a contact's capabilities, then user interfaces MAY choose to show a separate "call" option for each class of call.

For example, once an audio-only Google Talk call has started, it is not possible to add a video stream; both audio and video must be requested at the start of the call if video is desired. User interfaces may use this pseudo-capability as a hint to display separate "Audio call" and "Video call" buttons, rather than a single "Call" button with the option to add and remove video once the call has started for contacts without this flag.

This property is immutable, and therefore SHOULD be announced in NewChannels, etc.

A channel that can send and receive streamed media such as audio or video. Provides a number of methods for listing and requesting new streams, and signals to indicate when streams have been added, removed and changed status. The state of the call (ringing remotely, ringing locally, answered, missed, etc.) are represented using the properties and signals of the Group interface.

In general this should be used in conjunction with the MediaSignalling interface to exchange connection candidates and codec choices with whichever component is responsible for the streams. However, in certain applications where no candidate exchange is necessary (eg the streams are handled by specialised hardware which is controlled directly by the connection manager), the signalling interface can be omitted and this channel type used simply to control the streams.

Outgoing calls

To make an audio-only call to a contact foo@example.com, clients should call:

CreateChannel({
  ChannelType: StreamedMedia,
  TargetHandleType: Contact,
  TargetID: 'foo@example.com',
  InitialAudio: True,
)

As always, TargetHandle may be used in place of TargetID if the contact's handle is already known. To make an audio-and-video call, the client should also specify InitialVideo. The connection manager SHOULD return a channel whose immutable properties contain the local user as the InitiatorHandle, the remote contact as the TargetHandle, Requested = True (indicating that the call is outgoing); the Group interface should initially have the local user in Members and the remote contact in RemotePendingMembers, to indicate that we are awaiting their response.

The contact answering the call is represented by the CM signalling MembersChanged, moving the remote contact to Members, with the remote contact as the Actor and Reason None. The contact rejecting the call is represented by both contacts being removed from the group, with the remote contact as the Actor and Reason set appropriately. The local user may hang up at any time by calling RemoveMembersWithReason to remove themself, with an appropriate reason; the CM SHOULD relay the reason to the remote contact, and emit MembersChanged removing both contacts from the group with the self handle as the Actor.

(In the past, several other patterns have been used to place outgoing calls; see 'Requesting StreamedMedia Channels' on the Telepathy wiki for the details.)

Incoming calls

Incoming calls' immutable properties should contain TargetHandleType = Contact, both TargetHandle and InitiatorHandle set to the remote contact, Requested = False (indicating that this is an incoming call), and appropriate values of InitialAudio and InitialVideo; the Group interface should initially have the local user in LocalPendingMembers and the remote contact in Members, indicating that the contact is awaiting our response.

To accept the call, use AddMembers to move the local user to the group's members. To reject the call, use RemoveMembersWithReason to remove the local member from the group, with an appropriate reason. If the remote user ends the call before it is answered, this is represented by MembersChanged removing both parties from the group with the remote contact as the Actor, and Reason set appropriately.

Note that the call may end with the self handle as the Actor without the user having chosen to reject the call, as indicated by the nature of the Reason. Specifically, some local component may time out the call (indicating this with reason No_Answer; for example, the CM may have forwarded the call to another number, as configured using Forwarding.DRAFT), or something may have gone wrong with the call (indicated by reason Error). Such calls SHOULD be considered missed, just as if the remote contact had hung up before the local user answered the call.

This is a bit awkward, but these are the best ways we can represent these situations. It's important to document which calls should be considered missed, to ensure that the user can be notified.

When the local user accepts an incoming call, the connection manager SHOULD change the direction of any streams with pending local send to be sending, without altering whether those streams are receiving.

This matches existing practice, and means that a client can answer incoming calls and get an unmuted microphone/activated webcam without having to take additional action to accept the stream directions.

It does, however, introduce a race condition: a client believing that it is accepting an audio-only call by calling AddMembers can inadvertantly accept an audio + video call (and hence activate sending from a webcam without the user's permission) if a video stream is added just before AddMembers is processed. This race should be removed when this specification is revised.

During a call

If ImmutableStreams is False, new streams may be requested using RequestStreams (to add video to an audio-only call, for instance), and existing streams may be removed using RemoveStreams (for example, to downgrade an audio-video call to audio-only). The call may be ended by calling RemoveMembers or RemoveMembersWithReason; the call ending is signalled by the CM emitting MembersChanged, removing both parties from the group.

Handler filters

For historical reasons, handlers must specify more than one filter if they want to correctly advertise support for audio and/or video calls. If they can handle channels using the MediaSignalling interface, they should also advertise various Handler_Capability_Tokens to indicate which codecs and transports they support. See InitialAudio and MediaSignalling/video/h264 for the gory details. In summary:

To advertise support for streamed media in general, include the following filter in HandlerChannelFilter:
{ '...Channel.ChannelType': '...Channel.Type.StreamedMedia' ,
  '...Channel.TargetHandleType': Contact,
}
To advertise support for audio calls, also include the following filter:
{ '...Channel.ChannelType': '...Channel.Type.StreamedMedia' ,
  '...Channel.TargetHandleType': Contact,
  '...Channel.Type.StreamedMedia.InitialAudio': True,
}
To advertise support for video calls, also include the following filter:
{ '...Channel.ChannelType': '...Channel.Type.StreamedMedia' ,
  '...Channel.TargetHandleType': Contact,
  '...Channel.Type.StreamedMedia.InitialVideo': True,
}
If you use telepathy-farsight, and have H.264 support, you probably want these Capabilities:
[ "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/ice-udp",
  "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/gtalk-p2p",
  "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/video/h264",
]
The channel-type-specific capability flags used for Channel.Type.StreamedMedia in the Connection.Interface.Capabilities interface. See the InitialAudio property for details of the mechanisms that will replace this. The handle is capable of using audio streams within a media channel. The handle is capable of using video streams within a media channel. The handle is capable of performing STUN to traverse NATs. The handle is capable of establishing Google Talk peer-to-peer connections (as implemented in libjingle 0.3) to traverse NATs. The handle is capable of establishing ICE UDP peer-to-peer connections (as defined by the IETF MMUSIC working group) to traverse NATs. Channels whose target handle is this contact will have ImmutableStreams = True.
telepathy-qt-0.9.6~git1/spec/Channel_Type_Room_List.xml0000664000175000017500000001717712470405660021001 0ustar jrjr Copyright © 2005-2009 Collabora Limited Copyright © 2005-2009 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

For protocols with a concept of chatrooms on multiple servers with different DNS names (like XMPP), the DNS name of the server whose rooms are listed by this channel, e.g. "conference.jabber.org". Otherwise, the empty string.

This property cannot change during the lifetime of the channel.

A boolean indicating if room listing is in progress Check to see if there is already a room list request in progress on this channel. An array of structs containing:
  • an integer room handle
  • a string representing the D-Bus interface name of the channel type
  • a dictionary mapping string keys to variant boxed information

Emitted when information about rooms on the server becomes available. The array contains the room handle (as can be passed to the RequestChannel method with HANDLE_TYPE_ROOM), the channel type, and a dictionary containing further information about the room as available. The following well-known keys and types are recommended for use where appropriate:

handle-name (s)
The identifier of the room (as would be returned by InspectHandles). This property is mandatory.
name (s)
The human-readable name of the room if different from the handle
description (s)
A description of the room's overall purpose
subject (s)
The current subject of conversation in the room (as would be returned by getting the string part of the Subject property)
members (u)
The number of members in the room
password (b)
True if the room requires a password to enter
invite-only (b)
True if you cannot join the room, but must be invited
room-id (s)
The human-readable identifier of a chat room (as would be returned by getting the RoomName property)
server (s)
The DNS name of the server hosting these channels (as would be returned by getting the Server property)
Request the list of rooms from the server. The ListingRooms (True) signal should be emitted when this request is being processed, GotRooms when any room information is received, and ListingRooms (False) when the request is complete. Stop the room listing if it's in progress, but don't close the channel. The ListingRooms (False) signal should be emitted when the listing stops. A boolean indicating if room listing is in progress Emitted to indicate whether or not room listing request is currently in progress.

A channel type for listing named channels available on the server. Once the ListRooms method is called, it emits signals for rooms present on the server, until you Close this channel. In some cases, it may not be possible to stop the deluge of information from the server. This channel should be closed when the room information is no longer being displayed, so that the room handles can be freed.

This channel type may be implemented as a singleton on some protocols, so clients should be prepared for the eventuality that they are given a channel that is already in the middle of listing channels. The ListingRooms signal, or GetListingRooms method, can be used to check this.

telepathy-qt-0.9.6~git1/spec/template.xml0000664000175000017500000000250512470405660016241 0ustar jrjr Copyright © 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft 1)

Foo.

telepathy-qt-0.9.6~git1/spec/Channel_Dispatcher_Interface_Messages1.xml0000664000175000017500000001714112470405660024036 0ustar jrjr Copyright (C) 2011-2013 Collabora Ltd. Copyright (C) 2011 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

This interface allows DBus clients to use the ChannelDispatcher to send one-off text messages to a contact, identified by account and target ID, without requiring the caller to handle channels or be the primary message UI.

This enables entities other than the main UI to send messages to contacts.

The Account through which to communicate. The contact to send the message to. The parts of the message, the same as for Messages.SendMessage. Flags influencing how to send the message, the same as for Messages.SendMessage. An opaque token equivalent to the one returned by Messages.SendMessage.

Submit a message to the server for sending, like the Messages.SendMessage method.

If the Account is connected and a Text channel to the Target_ID already exists, this method is equivalent to sending the same message via that channel.

Otherwise, this method creates a channel (connecting the Account if appropriate), sends the desired message, and closes the channel as if via Channel.Close, without acknowledging any messages received on that channel during that time.

If any messages are received on that channel before it is closed, a correct connection manager implementation will reopen the channel when it is closed, resulting in those "rescued" messages being processed by the system's normal Handler for text channels. In particular, this deals with the situation where a successful or failed delivery report is received before the channel is closed.

Expecting a trivial client (perhaps a send-only IRC bot, or a simple SMS-sending API) to go through all those steps to send a message seems somewhat unreasonable. Having this as a method in the ChannelDispatcher lets it take some short-cuts if required, and centralizes the implementation to reduce the risk of mistakes that cause message loss.

The ChannelDispatcher SHOULD support this method for any connection manager that would accept channel requests of this form:

  {
    …Channel.ChannelType:
        …Channel.Type.Text,
    …Channel.TargetHandleType:
        Contact,
    …Channel.TargetID:
    Target_ID
  }

However, if the connection manager provides additional APIs (such as a way to open "send-only" channels), the ChannelDispatcher MAY use those: it is not required to use those exact request parameters.

This method may raise any error that would be raised by the Requests.EnsureChannel or Messages.SendMessage methods, or signalled by the Failed signal.

The connection manager does not implement Text channels that communicate with a named contact. The Target_ID was not syntactically valid for the Account's protocol. The requested message is malformed and cannot be sent. The requested channel cannot be created because the target is offline. The requested channel cannot be created, but in principle, a similar request might succeed in future.
telepathy-qt-0.9.6~git1/spec/Protocol.xml0000664000175000017500000005616712470405660016244 0ustar jrjr Copyright © 2009-2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An object representing a protocol for which this ConnectionManager can create Connections.

Each Protocol object has the same well-known bus name as its parent ConnectionManager. Its object path is formed by taking the ConnectionManager's object path and appending '/', followed by the Protocol name with any hyphen/minus '-' converted to underscores '_'.

This is the same as the representation of protocol names in Account object paths, and in Connection object paths and bus names. For instance, telepathy-gabble and telepathy-salut would implement objects at /org/freedesktop/Telepathy/ConnectionManager/gabble/jabber and /org/freedesktop/Telepathy/ConnectionManager/salut/local_xmpp, respectively.

If the ConnectionManager has a .manager file, each Protocol's immutable properties must be represented in that file; the representation is described as part of the documentation for each property. For instance, a very simple ConnectionManager with one Protocol might be represented like this:

[ConnectionManager]
Interfaces=

[Protocol example]
Interfaces=
ConnectionInterfaces=org.freedesktop.Telepathy.Connection.Interface.Requests;
param-account=s required
param-password=s required secret
RequestableChannelClasses=text;
VCardField=x-example
EnglishName=Example
Icon=im-example
AuthenticationTypes=org.freedesktop.Telepathy.Channel.Type.ServerTLSConnection;org.freedesktop.Telepathy.Channel.Interface.SASLAuthentication;

[text]
org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
org.freedesktop.Telepathy.Channel.TargetHandleType u=1
allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID;

A list of interfaces supported by this Protocol object.

This property should not be confused with ConnectionInterfaces, which refers to the interfaces of connections to this protocol.

Connection managers with a .manager file (as described as part of the ConnectionManager interface) MUST cache this property in the protocol's section of the .manager file, using the key Interfaces. The corresponding value is a list of D-Bus interface names, each followed by a semicolon.

The parameters which may be specified in the Parameters of an Account (or, for specialised applications which do not use the account manager, passed to RequestConnection). Some parameters are mandatory, and some parameters only make sense when registering new accounts with the server; see the Param_Spec documentation for more details.

Connection managers with a .manager file (as described as part of the ConnectionManager interface) MUST cache this property in the protocol's section of the .manager file via keys of the form param-p and default-p, as documented in the ConnectionManager interface.

A list of interface names which might be in the Interfaces property of a Connection to this protocol. Whether a Connection will have all, some or none of these interfaces depends on server capabilities.

This property should not be confused with Interfaces.

Connection managers with a .manager file MUST cache this property in the protocol's section of the .manager file, using the key ConnectionInterfaces. The corresponding value is a list of D-Bus interface names, each followed by a semicolon.

A list of channel classes which might be requestable from a Connection to this protocol (i.e. they will, or might, appear in the Connection's RequestableChannelClasses property).

Whether a Connection will have all, some or none of these requestable channel classes depends on server capabilities; similarly, individual contacts are not guaranteed to support all of these channel classes.

Connection managers with a .manager file MUST cache this property in the protocol's section of the .manager file, using the key RequestableChannelClasses. The corresponding value is a list of opaque strings, each followed by a semicolon; each of those strings is the name of a group in the .manager file which represents a channel class.

The names of the groups representing channel classes are not significant, and MUST NOT be interpreted. When writing .manager files, authors MAY choose mnemonic group names, generate group names mechanically (e.g. with an incrementing integer), or use some combination of these.

Each group representing a channel class has a key allowed which is a list of D-Bus property names representing allowed parameters. Any other keys that do not contain a space MUST be ignored. Any key containing a space represents a fixed property; the key has the form "propertyname type", and the value is encoded in the same way as for the default-p keys described in the ConnectionManager documentation.

Connection managers that have channel classes whose fixed properties are not representable in this form SHOULD NOT have .manager files.

For instance, this .manager file could represent a connection manager that supports 1-1 Text messages and StreamedMedia audio calls:

[Protocol jabber]
param-account=s required
param-password=s required
RequestableChannelClasses=rcc0;rcc1;

[rcc0]
org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.Text
org.freedesktop.Telepathy.Channel.TargetHandleType u=1
allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID;

[rcc1]
org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.StreamedMedia
org.freedesktop.Telepathy.Channel.TargetHandleType u=1
allowed=org.freedesktop.Telepathy.Channel.TargetHandle;org.freedesktop.Telepathy.Channel.TargetID;org.freedesktop.Telepathy.Channel.Type.StreamedMedia.InitialAudio;

The name of the most common vCard field used for this protocol's contact identifiers, normalized to lower case, or the empty string if there is no such field.

For example, this would be x-jabber for Jabber/XMPP (including Google Talk), or tel for the PSTN.

A more exhaustive list of addressable vCard fields can be found in the Protocol's Addressing interface's AddressableVCardFields.

It is not necessarily valid to interpret contacts' identifiers as values of this vCard field. For instance, telepathy-sofiasip supports contacts whose identifiers are of the form sip:jenny@example.com or tel:8675309, which would not normally both be represented by any single vCard field. Arbitrary handles/identifiers as vCard fields are represented through the Connection's Addressing1 contact attributes.

This is taken from Mission Control profiles as used on Maemo 5. One valid use of this field is to answer the question: given a contact's vCard containing an X-JABBER field, how can you communicate with the contact? By iterating through protocols looking for an x-jabber VCardField, one can build up a list of protocols that handle x-jabber, then offer the user a list of accounts for those protocols and/or the option to create a new account for one of those protocols.

Connection managers with a .manager file MUST cache this property in the protocol's section of the .manager file if it is non-empty, using the key VCardField. The corresponding value is a string, following the syntax of the "localestring" type from the Desktop Entry Specification.

The name of the protocol in a form suitable for display to users, such as "AIM" or "Yahoo!", or the empty string if none is available.

This is effectively in the C locale (international English); user interfaces requiring a localized protocol name SHOULD look one up in their own message catalog based on either the Telepathy Protocol name or this property, but SHOULD use this English version as a fallback if no translated version can be found.

Many protocols are named after a company or product which isn't translated in non-English locales. This also provides a fallback display name, for UIs with no prior knowledge of a particular protocol.

If this property's value is empty, clients MAY fall back to using the Telepathy Protocol name, possibly with its capitalization adjusted.

Connection managers with a .manager file MUST cache this property in the protocol's section of the .manager file if it is non-empty, using the key EnglishName. The corresponding value is a string, following the syntax of the "localestring" type from the Desktop Entry Specification.

The name of an icon in the system's icon theme, such as "im-msn", or the empty string.

This can be used as a default if the Icon property is not set on an Account, or used by the AccountManager to choose a default icon if none is set during account creation.

If this property's value is empty, clients MAY fall back to generating a name based on the Protocol name.

Connection managers with a .manager file MUST cache this property in the protocol's section of the .manager file if it is non-empty, using the key Icon. The corresponding value is a string, following the syntax of the "localestring" type from the Desktop Entry Specification.

Return a string which uniquely identifies the account to which the given parameters would connect.

For many protocols, this would return the well-known 'account' parameter. However, for IRC the returned string would be composed from the 'account' (i.e. nickname) and 'server' parameters. AccountManager implementations can use this to form the account-specific part of an Account's object path.

A set of parameters as would be provided to RequestConnection

An opaque string suitable for use as the account-specific part of an Account's object path. This is not necessarily globally unique, but should represent a "best-effort" identification of the account.

For a pathological case, consider a user signing in as 'me@example.com' with 'server' set to either jabber1.example.com or jabber2.example.com. Both of these should result in me@example.com being returned from this method, even if the user can actually be signed in to those two servers simultaneously.

The IdentifyAccount method is not supported by this connection manager. The caller SHOULD fall back to deriving identification from the parameters.

Attempt to normalize the given contact ID. Where possible, this SHOULD return the same thing that would be returned by InspectHandles(RequestHandles(CONTACT, [Contact_ID])) on a connected Connection.

If full normalization requires network activity or is otherwise impossible to do without a Connection, this method SHOULD perform a best-effort normalization.

One common example of a best-effort offline normalization differing from the ideal normalization is XMPP.

On XMPP, contacts' JIDs should normally have the resource removed during normalization, but for contacts in a MUC (chatroom), the resource is an integral part of the JID - so the contact JID alice@example.com/Empathy should normalize to alice@example.com, but the in-MUC JID wonderland@conference.example.com/Alice should normalize to itself.

While online, the connection manager has enough context to know which chatrooms the user is in, and can infer from that whether to remove resources, but the best-effort normalization performed while offline does not have this context, so the best that can be done is to remove the resource from all JIDs.

This method MAY simply raise NotImplemented on some protocols.

In link-local XMPP, you can't talk to someone who isn't present on your local network, so normalizing identifiers in advance is meaningless.

The identifier of a contact in this protocol The identifier of a contact in this protocol, normalized as much as possible The NormalizeContact method is not supported by this connection manager. The caller MAY recover by using the contact ID as-is.

A list of D-Bus interfaces which provide information as to what kind of authentication channels can possibly appear before the connection reaches the CONNECTED state.

These can either be channel types, or where the channel type isn't enough information to be useful, interfaces indicating a specific use of a channel type. For example, ServerTLSConnection channels are obviously about TLS certificates so the channel type would appear in this list. However, a ServerAuthentication channel type alone does not explain enough about the authentication type in use as it is merely a base for the channel interfaces that appear in said channels. In this case, CMs should use the value of the ServerAuthentication.AuthenticationMethod property in this list.

For example, if a protocol's AuthenticationTypes contains two values:

[ ...Channel.Type.ServerTLSConnection,
  ...Channel.Interface.SASLAuthentication ]

This tells a client that before the connection status reached CONNECTED, a ServerTLSConnection could appear carrying a TLS certificate. It also tells the client that before the connection status reaches CONNECTED, a ServerAuthentication channel could also appear, where ServerAuthentication.AuthenticationMethod=SASLAuthentication. A hypothetical future Channel.Interface.Captcha interface would also appear in this list if the CM might require the user solve a captcha before connecting.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Credentials_Storage.xml0000664000175000017500000000605112470405660023757 0ustar jrjr Copyright © 2011 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft 1)

A channel interface for SASL authentication channels that can save the credentials in the connection manager.

This interface is unlikely to be present for any SASL channels that are more complex than a simple password prompt (e.g. X-TELEPATHY-PASSWORD or PLAIN).

In practice, this interface should only be implemented by connection managers that implement the ConnectionManager.Interface.AccountStorage.DRAFT interface. To clear a password that has been saved in this manner, a client should call AccountStorage.DRAFT.ForgetCredentials on the Account.

Whether to store the authentication credentials.

This method tells the connection manager whether to store the authentication response in order to allow the connection manager to sign-on automatically in the future.

If credentials have been stored in this way, the client SHOULD NOT attempt to store the credentials locally in a keyring.

This method MUST be called before AcceptSASL is called or it will have no effect.

telepathy-qt-0.9.6~git1/spec/Call_Stream_Interface_Media.xml0000664000175000017500000007701512470405660021703 0ustar jrjr Copyright © 2009-2010 Collabora Ltd. Copyright © 2009-2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

This interface deals with how to connect a stream to an endpoint. It contains all that is required to describe the local endpoint, to succesfully establish a connection. While a call is established, one may try to connect to multiple remote endpoints at the same time. This is called forking in the SIP jargon. Informations related to the connections are on the Endpoint objects. Once the call is established, there MUST be a single endpoint left.

ICE restarts

If the CM wants to do an ICE restart, then the ICERestartPending property is set, and the ICERestartRequested signal is emitted. The streaming implementation should then call SetCredentials again. This will trigger the actual ICE restart, and cause LocalCandidates to be cleared.

For more information on ICE restarts see RFC 5245 section 9.1.1.1

The type of SendingState and ReceivingState. No data is flowing (or expected to be flowing) at this time. The streaming implementation has been told to start or receiving, but has not yet indicated that it is doing so. The streaming implementation has been told to stop sending or receiving data, but it has not yet indicated that it has done so. The streaming implementation is successfully sending or receiving data, and everything is going swimmingly. Indicates whether the streaming implementation is/should be sending media for this stream. The streaming implementation should be able to rely on reading this value and listening to SendingStateChanged to determine whether it should be sending media or not. It should not need to listen to the Hold interfaces on the Call/Content. Feedback on success should be given via CompleteSendingStateChange. Failures should be reported via ReportSendingFailure. Change notification for SendingState. Note that this information is duplicated onto the Stream interface, so that UIs can ignore the Media interface, and streaming implementations can ignore everything but the media interface. The new value of SendingState.

Called in response to SendingStateChanged(Pending_*, *) to indicate that the media state has successfully progressed from Pending_{Start, Stop, Pause} to the corresponding non-pending state.

The new (non-pending) value of SendingState. The state change made no sense, and was ignored by the CM. The most likely cause for this is a race-condition between the CM emitting a new state change and the streaming implementation responding to the previous state change.
Can be called at any point to indicate a failure in the outgoing portion of the stream. The counterpart of SendingState. Indicates whether the streaming implementation is/should be expecting to receive media for this stream. The CM should only tell the streaming implementation to stop receiving if it has been told to put the stream on hold, or the stream has been removed from the call. Change notification for ReceivingState. The new value of ReceivingState.

Called in response to ReceivingStateChanged(Pending_*, *) to indicate that the media state has successfully progressed from Pending_{Start, Stop, Pause} to the corresponding non-pending state.

The new (non-pending) value of ReceivingState. The state change made no sense, and was ignored by the CM. The most likely cause for this is a race-condition between the CM emitting a new state change and the streaming implementation responding to the previous state change.
Can be called at any point to indicate a failure in the incoming portion of the stream.

Used to set the username fragment and password for streams that have global credentials.

The username to use when authenticating on the stream. The password to use when authenticating on the stream.
The network topology that an IP candidate represents. This can sometimes be used to infer what kind of performance characteristics (latency, bandwith, etc) can be expected of connections made to this candidate. This is not an IP candidate. This is a reserved value, and should not be seen on the bus. This candidate represents a direct connection to the host, as its address is taken directly the host's IP stack. This candidate probably represents a connection to the host through a NAT device, as its address was discovered by sending a binding request to a STUN server or similar. This candidate probably represents a good route between the host and its peer, as its address was discovered by sending a STUN binding request to one of the candidates advertised by the peer. This candidate represents the address of a relay server (usually somewhere on the public internet). This candidate is the most likely to work, but all media will go via a relay server, so latency is likely to be higher than other types of candidate. This candidate represents a Multicast group. This value should only appear if the Stream's Transport is set to Multicast.

Extra information about the candidate. Allowed and mandatory keys depend on the transport protocol used. The following keys are commenly used:

type - u
The type of candidate (Call_Stream_Candidate_Type)
foundation - s
The foundation of this candidate
protocol - u
Underlying protocol of the candidate (Media_Stream_Base_Proto)
priority - u
Priority of the candidate (should be a number between 0 and 65535). Most ICE implementations will prefer the highest priority candidate pair that manages to connect. For backwards compatibility with non-ICE SIP clients, the lowest priority candidate may be sent as a raw UDP fallback candidate. It is recommended that a relay candidate is used as the lowest priority candidate if possible. If both IPv4 and IPv6 raw udp fallback candidates are available, they should be set to the same priority and advertised to the CM at the same time. The CM will decide which to advertise to the remote end.
base-ip - s
The underlying Host address where media sent to this (non-host-type) candidate will eventually arrive.
base-port - u
The underlying Host port where media sent to this (non-host-type) candidate will eventually arrive.
username - s
Username of this candidate (only if credentials are per candidate)
password - s
Password of this candidate (only if credentials are per candidate)
ttl - u
The TTL mandated for RTP/RTCP packets sent to a multicast group (only valid for Multicast Streams)
One of the well-known keys documented here, or an implementation-specific key. The value corresponding to that key.
Media streams can use more than one UDP socket: one for RTP (data) and one for RTCP (control). Most of the time, they are adjacent to each other, but some protocols (xmpp) signal each port separately. The stream transport type is unknown or not applicable (should not appear over dbus). This is the high-traffic data socket, containing the audio/video data for the stream. This is the low-traffic control socket, usually containing feedback about packet loss etc. A Stream Candidate. The component number. The IP address to use. The port number to use. Additional information about the candidate. Add candidates to the LocalCandidates property and signal them to the remote contact(s). Note that connection managers MAY delay the sending of candidates until FinishInitialCandidates is called. The candidates to be added. This indicates to the CM that the initial batch of candidates has been added, and should now be processed/sent to the remote side. Protocols supporting Raw UDP SHOULD wait for FinishInitialCandidates, and then set the lowest priority candidate as the Raw UDP candidate. The minimal required candidates have not been set. For example, for an RTP protocol, at least one candidate on the component 1 (RTP) must have been set. WLM_8_5 was removed A transport that can be used for streaming. The stream transport type is unknown or not applicable (for streams that do not have a configurable transport). Raw UDP, with or without STUN. All streaming clients are assumed to support this transport, so there is no handler capability token for it in the Call1 interface. [This corresponds to "none" or "stun" in the old Media.StreamHandler interface.] Interactive Connectivity Establishment, as defined by RFC 5245. Note that this value covers ICE-UDP only. [This corresponds to "ice-udp" in the old Media.StreamHandler interface.] Google Talk peer-to-peer connectivity establishment, as implemented by libjingle 0.3. [This corresponds to "gtalk-p2p" in the old Media.StreamHandler interface.] The transport used by Windows Live Messenger 2009 or later, which resembles ICE draft 19. [This corresponds to "wlm-2009" in the old Media.StreamHandler interface.] Shared memory transport, as implemented by the GStreamer shmsrc and shmsink plugins. Multicast transport. The transport for this stream. [FIXME]. Change notification is via the LocalCandidatesAdded signal. Emitted when local candidates are added to the LocalCandidates property. Candidates that have been added. A username and password pair. The username. The password. The local credentials are sent to the remote site over the signalling protocol. They are used in ICE to make sure that the connectivity checks come from the right peer. Change notification is via the LocalCredentialsChanged signal. This property will be a pair of empty strings if ICE has not yet been started. renamed from LocalCredentailsSet Emitted when the value of LocalCredentials changes to a non-empty value. This should only happen when the streaming implementation calls SetCredentials, so this signal is mostly useful for debugging. Emitted when the value of RelayInfo changes. Emitted when the value of STUNServers changes.

The IP addresses of possible STUN servers to use for NAT traversal, as dotted-quad IPv4 address literals or RFC2373 IPv6 address literals. Change notification is via the STUNServersChanged signal. The IP addresses MUST NOT be given as DNS hostnames.

High-quality connection managers already need an asynchronous DNS resolver, so they might as well resolve this name to an IP to make life easier for streaming implementations.

A list of mappings describing TURN or Google relay servers available for the client to use in its candidate gathering, as determined from the protocol. Well-known map keys are:

ip - s
The IP address of the relay server as a dotted-quad IPv4 address literal or an RFC2373 IPv6 address literal. This MUST NOT be a DNS hostname. High-quality connection managers already need an asynchronous DNS resolver, so they might as well resolve this name to an IP and make life easier for streaming implementations.
type - s

Either udp for UDP (UDP MUST be assumed if this key is omitted), tcp for TCP, or tls.

The precise meaning of this key depends on the Transport property: if Transport is ICE, tls means TLS over TCP as referenced by ICE draft 19, and if Transport is GTalk_P2P, tls means a fake SSL session over TCP as implemented by libjingle.

port - q
The UDP or TCP port of the relay server as an ASCII unsigned integer
unique-id - s
A string identifying the relay server. If two RelayInfo entries have the same unique-id, but different types, there is usually little point in connecting to both. Use priority to determine which version to prefer in this case. Can also be used by the streaming implementation to avoid connecting to the same relay multiple times if relaying is required for both audio and video.
priority - u
A number determining which version of a server to prefer (if multiple are present with the same unique-id, the one with the highest priority should be used, or the streaming implementation should use the one whose type has the most desirable properties)
username - s
The username to use
password - s
The password to use
component - u
The component number to use this relay server for, as an ASCII unsigned integer; if not included, this relay server may be used for any or all components. In ICE draft 6, as used by Google Talk, credentials are only valid once, so each component needs relaying separately.

An equivalent of the gtalk-p2p-relay-token property on MediaSignalling channels is not included here. The connection manager should be responsible for making the necessary HTTP requests to turn the token into a username and password.

The type of relay server that this represents depends on the value of the Transport property. If Transport is ICE, this is a TURN server; if Transport is GTalk_P2P, this is a Google relay server; otherwise, the meaning of RelayInfo is undefined.

If relaying is not possible for this stream, the list is empty.

Change notification is given via the RelayInfoChanged signal.

Signals that the initial information about STUN and Relay servers has been retrieved, i.e. the HasServerInfo property is now true.

True if all the initial information about STUN servers and Relay servers has been retrieved. Change notification is via the ServerInfoRetrieved signal.

Streaming implementations that can't cope with STUN and relay servers being added later SHOULD wait for this property to become true before proceeding.
Emitted when the Endpoints property changes. Endpoints that were added. Endpoints that no longer exist.

The list of Endpoint objects that exist for this stream.

Change notification is via the EndpointsChanged signal.

Emitted when the remote side requests an ICE restart (e.g. third party call control, when the remote endpoint changes). The streaming implementation should call SetCredentials again. State recovery for ICERestartRequested. Set when the signal is emitted, and unset when SetCredentials is called. Useful for debugging. Signal an unrecoverable error for this stream, and remove it. If all streams are removed from a content, then it will also be removed. A structured reason for stream removal.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Sidecars1.xml0000664000175000017500000001244612470405660022410 0ustar jrjr Copyright © 2009-2013 Collabora Limited Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API) The "primary" interface implemented by an object attached to a connection. For example, a Gabble plugin implementing fine-grained control of XEP-0016 privacy lists might expose an object implementing com.example.PrivacyLists. The object path of the sidecar, exported by the same bus name as the Connection to which it is attached. Immutable properties of the sidecar.

Request an object with a particular interface providing additional connection-specific functionality, together with its immutable properties. These will often be implemented by plug-ins to the connection managers; for example, support for an XMPP XEP for which no generic Telepathy interface exists might be implemented by a Gabble plugin exposing a sidecar with a particular interface.

This method may be called at any point during the lifetime of a connection, even before its Connection_Status changes to Connected. It MAY take a long time to return—perhaps it needs to wait for a connection to be established and for all the services supported by the server to be discovered before determining whether necessary server-side support is available—so callers SHOULD override the default method timeout (25 seconds) with a much higher value (perhaps even MAX_INT32, meaning “no timeout” in recent versions of libdbus).

There is an implicit assumption that any connection manager plugin will only want to export one “primary” object per feature it implements, since there is a one-to-one mapping between interface and object. This is reasonable since Sidecars are (intended to be) analogous to extra interfaces on the connection, providing once-per-connection shared functionality; it also makes client code straightforward (look up the interface you care about in a dictionary, build a proxy object from the value). More “plural” plugins are likely to want to implement new types of Channel instead.

The requested sidecar is not implemented by this connection manager, or a necessary server-side component does not exist. (FIXME: split these two errors out? Then again, once we list the guaranteed and possible sidecars on a Protocol object, clients can tell the difference themselves, because they shouldn't be calling this in the first case.) A server-side component needed by the requested sidecar reported it is currently too busy, or did not respond for some implementation-defined time. The caller may wish to try again later. The connection was disconnected while the sidecar was being set up.
telepathy-qt-0.9.6~git1/spec/Client_Interface_Requests.xml0000664000175000017500000001711312470405660021520 0ustar jrjr Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as a stable interface)

This interface can be implemented by a Handler to be notified about requests for channels that it is likely to be asked to handle.

Called by the ChannelDispatcher to indicate that channels have been requested, and that if the request is successful, they will probably be handled by this Handler. The ChannelDispatcher SHOULD only call this method on one handler per request.

This allows the UI to start preparing to handle the channels in advance (e.g. render a window with an "in progress" message), improving perceived responsiveness.

The use of "probably" is because you can't necessarily tell from a channel request which handler will handle particular channels. A reasonable heuristic would be to match the request against the HandlerChannelFilter, and respect the preferred handler (if any).

If the request succeeds and is given to the expected Handler, the Requests_Satisfied parameter to HandleChannels can be used to match the channel to a previous AddRequest call.

This lets the UI direct the channels to the window that it already opened.

If the request fails, the expected handler is notified by the channel dispatcher calling its RemoveRequest method.

This lets the UI close the window or display the error.

The channel dispatcher SHOULD remember which handler was notified, and if the channel request succeeds, it SHOULD dispatch the channels to the expected handler, unless the channels do not match that handler's HandlerChannelFilter. If the channels are not dispatched to the expected handler, the handler that was expected is notified by the channel dispatcher calling its RemoveRequest method with the NotYours error.

Expected handling is for the UI to close the window it previously opened.

Handlers SHOULD NOT return an error from this method; errors returned from this method SHOULD NOT alter the channel dispatcher's behaviour.

Calls to this method are merely a notification.

The ChannelRequest object, which MUST have been returned by CreateChannel or EnsureChannel before this method is called. See those methods for the rationale of this ordering.

Some of the properties of the ChannelRequest. To avoid race conditions, this dictionary MUST NOT include properties whose values could subsequently change. It SHOULD include as many properties as possible, given that constraint.

In particular, the properties Requests, UserActionTime and Account MUST be included, and Hints MUST be included if implemented.

Called by the ChannelDispatcher to indicate that a request previously passed to AddRequest has failed and should be disregarded.

Handlers SHOULD NOT return an error from this method; errors returned from this method SHOULD NOT alter the channel dispatcher's behaviour.

Calls to this method are merely a notification.

The request that failed.

The name of the D-Bus error with which the request failed.

If this is org.freedesktop.Telepathy.Error.NotYours, this indicates that the request succeeded, but all the resulting channels were given to some other handler.

Any message supplied with the D-Bus error.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Requests.xml0000664000175000017500000007171612470405660022412 0ustar jrjr Copyright (C) 2008 Collabora Limited Copyright (C) 2008 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An enhanced version of the Telepathy connection interface, which can represent bundles of channels that should be dispatched together, and does not assume any particular properties by which channels are uniquely identifiable.

If this interface is implemented on a connection, then NewChannels MUST be emitted for all new channels, even those created with RequestChannel.

(as stable API) Enough details of a channel that clients can work out how to dispatch or handle it. The object path of the channel.

Properties of the channel.

Connection managers MUST NOT include properties in this mapping if their values can change. Clients MUST ignore properties that appear in this mapping if their values can change.

If properties that could change were included, the following race condition would be likely to exist in some cases:

  • NewChannels or Get("Channels") includes a property P with value V1
  • Client creates a proxy object for the channel
  • The value of P changes to V2
  • Client connects to PChanged signal
  • Client should call Get("P") or GetAll here, to avoid the race, but client's author has forgotten to do so
  • Proxy object thinks P == V1, but actually P == V2

We've taken the opportunity to make the API encourage the client author to get it right. Where possible, we intend that properties whose value will be used in channel dispatching or other "early" processing will be defined so that they are immutable (can never change).

Each dictionary MUST contain the keys org.freedesktop.Telepathy.Channel.ChannelType, org.freedesktop.Telepathy.Channel.TargetHandleType, org.freedesktop.Telepathy.Channel.TargetHandle, org.freedesktop.Telepathy.Channel.TargetID and org.freedesktop.Telepathy.Channel.Requested.

We expect these to be crucial to the channel-dispatching process.

(as stable API) It is now guaranteed that CreateChannel returns the channel before NewChannels announces it (the reverse was previously guaranteed).

Request that an entirely new channel is created.

There is deliberately no flag corresponding to the suppress_handler argument to Connection.RequestChannel, because passing a FALSE value for that argument is deprecated. Requests made using this interface always behave as though suppress_handler was TRUE.

A dictionary containing desirable properties, which MUST include ChannelType. Some properties are defined such that only an exact match makes sense, and connection managers MUST NOT satisfy a request with a channel where that property does not match; some properties are defined such that the connection manager MAY treat the request as merely a hint, and make a best-effort attempt to satisfy it. This is documented separately for each property.

If this dictionary contains a property whose semantics are not known to the connection manager, this method MUST fail without side-effects (in particular it must not create a new channel).

This is necessary if we want to be able to invent properties in future that, when used in a request, are hard requirements rather than just hints. A connection manager that did not know the semantics of those properties could incorrectly return a new channel that did not satisfy the requirements.

The connection manager MUST NOT respond successfully, and SHOULD NOT create a new channel or cause any other side-effects, unless it can create a new channel that satisfies the client's requirements.

Properties that will be set by this argument need not have write access after the channel has been created - indeed, it is expected that most will be read-only.

The Channel object, which MUST NOT be signalled with NewChannels until after this method returns.

This allows the requester to alter its handling of NewChannels by knowing whether one of the channels satisfied a request it made.

Properties of the channel that was produced, equivalent to the properties in Channel_Details. Connection managers MUST NOT include properties here whose values can change, for the same reasons as in Channel_Details.

The channel request was one that can never succeed, such as requesting an unsupported channel type, or requesting a channel type which this connection manager does not support with the given target handle type. An invalid handle was requested as the value of a property whose value is a handle (like Channel.TargetHandle), or a syntactically invalid identifier was requested as the value of a property whose value is the string corresponding to a handle (like Channel.TargetID). The request matched the fixed properties of a Requestable_Channel_Class in RequestableChannelClasses, but the allowed arguments did not make sense; for example, a RoomList was requested, but the Server property provided was not a valid DNS name. The requested channel cannot be created because the requested contact is using a client that lacks a particular feature. The requested channel cannot be created because the target is offline.

The requested channel cannot be created, but in principle, a similar request might succeed in future. For instance, this might be because:

  • a channel matching the request already exists and the protocol requires that only one such channel can exist at a time
  • a channel matching the request has already been requested (by a previous call to CreateChannel, EnsureChannel, Connection.RequestChannel or similar) and the protocol requires that only one such channel can exist at a time
It is now guaranteed that if the channel was created by this call to EnsureChannel, it's returned before NewChannels announces it (the reverse was previously guaranteed).

Request that channels are ensured to exist.

The connection manager is in the best position to determine which existing channels could satisfy which requests.

A dictionary containing desirable properties, with the same semantics as the corresponding parameter to CreateChannel.

If false, the caller of EnsureChannel MUST assume that some other process is handling this channel; if true, the caller of EnsureChannel SHOULD handle it themselves or delegate it to another client.

If the creation of a channel makes several calls to EnsureChannel (and no other requests) successful, exactly one of those calls MUST return a true value for this argument.

If the creation of a channel makes other requests successful, the value returned for this argument MUST be such that exactly one of the clients making requests ends up responsible for the channel. In particular, if CreateChannel returns a channel C, any EnsureChannel calls that also return C MUST return a false value for this argument.

The Channel object. If it was created as a result of this method call, it MUST NOT be signalled by NewChannels until after this method returns.

This allows the requester to alter its handling of NewChannels by knowing whether one of the channels satisfied a request it made.

Properties of the channel that was produced, equivalent to the properties in Channel_Details. Connection managers MUST NOT include properties here whose values can change, for the same reasons as in Channel_Details.

The channel request was one that can never succeed, such as requesting an unsupported channel type, or requesting a channel type which this connection manager does not support with the given target handle type. An invalid handle was requested as the value of a property whose value is a handle (like Channel.TargetHandle), or a syntactically invalid identifier was requested as the value of a property whose value is the string corresponding to a handle (like Channel.TargetID). The request matched the fixed properties of a Requestable_Channel_Class in RequestableChannelClasses, but the allowed arguments did not make sense; for example, a RoomList was requested, but the Server property provided was not a valid DNS name. The requested channel cannot be created because the requested contact is using a client that lacks a particular feature. The requested channel cannot be created because the target is offline. The requested channel cannot be created, but in principle, a similar request might succeed in future.
(as stable API) Added a guarantee of ordering relative to NewChannel

New channels have been created. The connection manager SHOULD emit a single signal for any group of closely related channels that are created at the same time, so that the channel dispatcher can try to dispatch them to a handler as a unit.

In particular, if additional channels are created as a side-effect of a call to CreateChannel, these channels SHOULD appear in the same NewChannels signal as the channel that satisfies the request.

Joining a MUC Tube in XMPP requires joining the corresponding MUC (chatroom), so a Text channel can be created as a side-effect.

Every time NewChannels is emitted, it MUST be followed by a Connection.NewChannel signal for each channel.

The double signal emission is for the benefit of older Telepathy clients, which won't be listening for NewChannels.

The more informative NewChannels signal comes first so that clients that did not examine the connection to find out whether Requests is supported will see the more informative signal for each channel first, and then ignore the less informative signal because it announces a new channel of which they are already aware.

The channels and their details. All channels that are signalled together like this MUST have the same Bundle property, which may either refer to an existing bundle, or establish a new bundle.
(as stable API) A list of all the channels which currently exist on this connection. Change notification is via the NewChannels and ChannelClosed signals. (as stable API) Emitted when a channel is closed and hence disappears from the Channels property. This is redundant with the Closed signal on the channel itself, but it does provide full change notification for the Channels property. The channel which has been removed from the Channels property (as stable API)

Mapping representing a class of channels that can be requested from a connection manager, can be handled by a user interface, are supported by a contact, etc.

Classes of channel are identified by the fixed values of a subset of their properties.

Channel classes SHOULD always include the keys org.freedesktop.Telepathy.Channel.ChannelType and org.freedesktop.Telepathy.Channel.TargetHandleType. (One exception is that ContactSearch channels do not have TargetHandleType None in their requestable channel classes, for historical reasons.)

A D-Bus interface name, followed by a dot and a D-Bus property name. The value of the property.
(as stable API)

Structure representing a class of channels that can be requested, identified by a set of properties that identify that class of channel.

This will often just be the channel type and the handle type, but can include other properties of the channel - for instance, encrypted channels might require properties that unencrypted channels do not, like an encryption key.

In some cases, these classes of channel may overlap, in the sense that one class fixes all the properties that another class does, plus some more properties.

For older clients to still be able to understand how to request channels in the presence of a hypothetical "encryption" interface, we'd need to represent it like this:

  • class 1: ChannelType = Text, TargetHandleType = CONTACT
  • class 2: Channel.ChannelType = Text, Channel.TargetHandleType = CONTACT, Encryption.Encrypted = TRUE

The property values that identify this requestable channel class. These properties MUST be included in requests for a channel of this class, and MUST take these values.

Clients that do not understand the semantics of all the Fixed_Properties MUST NOT request channels of this class, since they would be unable to avoid making an incorrect request.

This implies that connection managers wishing to make channels available to old or minimal clients SHOULD have a channel class with the minimum number of Fixed_Properties, and MAY additionally have channel classes with extra Fixed_Properties.

Interface designers SHOULD avoid introducing fixed properties whose types are not serializable in a .manager file.

Connection managers with a fixed property that is not serializable cannot have a complete .manager file.

Properties that MAY be set when requesting a channel of this channel type and handle type.

This array MUST NOT include properties that are in the Fixed_Properties mapping.

Properties in this array may either be required or optional, according to their documented semantics.

For instance, if TargetHandleType takes a value that is not Handle_Type_None, one or the other of TargetHandle and TargetID is required. Clients are expected to understand the documented relationship between the properties, so we do not have separate arrays of required and optional properties.

If this array contains the Bundle property, then this class of channel can be combined with other channels with that property in a request, or added to an existing bundle. If not, this signifies that the connection manager is unable to mark channels of this class as part of a bundle - this means that to the remote contact they are likely to be indistinguishable from channels requested separately.

(as stable API)

The classes of channel that are expected to be available on this connection, i.e. those for which CreateChannel can reasonably be expected to succeed. User interfaces can use this information to show or hide UI components.

This property cannot change after the connection has gone to state Connection_Status_Connected, so there is no change notification (if the connection has context-dependent capabilities, it SHOULD advertise support for all classes of channel that it might support during its lifetime). Before this state has been reached, the value of this property is undefined.

This is not on an optional interface, because connection managers can always offer some sort of clue about the channel classes they expect to support (at worst, they can announce support for everything for which they have code).

telepathy-qt-0.9.6~git1/spec/Channel_Type_DBus_Tube.xml0000664000175000017500000002211612470405660020673 0ustar jrjr Copyright © 2008-2009 Collabora Limited Copyright © 2008-2009 Nokia Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A D-Bus tube is an ordered reliable transport, for transporting D-Bus traffic.

For each D-Bus tube, the connection manager listens on a D-Bus server address, as detailed in the D-Bus specification. On this address, it emulates a bus upon which each tube participant appears as an endpoint.

The objects and interfaces which are expected to exist on the emulated bus depend on the well-known name; typically, either the participant who initiated the tube is expected to export the same objects/interfaces that would be exported by a service of that name on a bus, or all participants are expected to export those objects/interfaces.

In a multi-user context (Handle_Type_Room) the tube behaves like the D-Bus bus daemon, so participants can send each other private messages, or can send broadcast messages which are received by everyone in the tube (including themselves). Each participant has a D-Bus unique name; connection managers MUST prevent participants from sending messages with the wrong sender unique name, and SHOULD attempt to avoid participants receiving messages not intended for them.

In a 1-1 context (Handle_Type_Contact) the tube behaves like a peer-to-peer D-Bus connection - arbitrary D-Bus messages with any sender and/or destination can be sent by each participant, and each participant receives all messages sent by the other participant.

Offers a D-Bus tube providing the service specified. The dictionary of arbitrary Parameters to send with the tube offer. The access control the connection manager applies to the D-Bus socket. The string describing the address of the private bus. The client SHOULD NOT attempt to connect to the address until the tube is open. The contact associated with this channel doesn't have tubes capabilities. Accept a D-Bus tube that's in the "local pending" state. The connection manager will attempt to open the tube. The tube remains in the "local pending" state until the TubeChannelStateChanged signal is emitted. The access control the connection manager applies to the D-Bus socket. The string describing the address of the private bus. The client SHOULD NOT attempt to connect to the address until the tube is open. Emitted on a multi-user (i.e. Handle_Type_Room) D-Bus tube when a participant opens or closes the tube. This provides change notification for the DBusNames property. Array of handles and D-Bus names of new participants. Array of handles of former participants.

A string representing the service name that will be used over the tube. It SHOULD be a well-known D-Bus service name, of the form com.example.ServiceName.

When the tube is offered, the service name is transmitted to the other end.

When requesting a channel with CreateChannel, this property MUST be included in the request.

For a multi-user (i.e. Handle_Type_Room) D-Bus tube, a mapping between contact handles and their unique bus names on this tube. For a peer-to-peer (i.e. Handle_Type_Contact) D-Bus tube, the empty dictionary. Change notification is via DBusNamesChanged. Represents the participants in a multi-user D-Bus tube, as used by the DBusNames property and the DBusNamesChanged signal. The handle of a participant in this D-Bus tube. That participant's unique name.

A list of the access control types that are supported with this channel. Note that only Socket_Access_Control_Localhost and Socket_Access_Control_Credentials can be used with D-Bus tubes. Using Socket_Access_Control_Credentials is recommended.

Socket_Access_Control_Credentials is easy to implement for a D-Bus tube, because typical D-Bus library implementations like libdbus and GDBus already have to support it to be able to connect to the system or session bus, and usually enable it by default; so there's typically no good reason to relax access control to Localhost.

When requesting a channel with Connection.Interface.Requests.CreateChannel, this property MUST NOT be included in the request.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Transfer.xml0000664000175000017500000000472112470405660021624 0ustar jrjr Copyright (C) 2005, 2006 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

The handle of the member to transfer The handle of the destination contact Request that the given channel member instead connects to a different contact ID. An interface for channels where you may request that one of the members connects to somewhere else instead.
telepathy-qt-0.9.6~git1/spec/Call_Stream_Endpoint.xml0000664000175000017500000003764612470405660020472 0ustar jrjr Copyright © 2009-2010 Collabora Ltd. Copyright © 2009-2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

This object represents an endpoint for a stream. In a one-to-one call, there will be one (bidirectional) stream per content and one endpoint per stream (as there is only one remote contact). In a multi-user call there is a stream for each remote contact and each stream has one endpoint as it refers to the one physical machine on the other end of the stream.

The multiple endpoint use case appears when SIP call forking is used. Unlike jingle call forking (which is just making multiple jingle calls to different resources appear as one call), SIP call forking is actually done at the server so you have one stream to the remote contact and then and endpoint for each SIP client to be called.

The ICE credentials used for all candidates. If each candidate has different credentials, then this property SHOULD be ("", ""). Per-candidate credentials are set in the Candidate's Candidate_Info a{sv}. The username set. The password set. Emitted when the remote ICE credentials for the endpoint are set. If each candidate has different credentials, then this signal will never be fired. A list of candidates for this endpoint. Emitted when remote candidates are added to the RemoteCandidates property. The candidates that were added. A Pair of candidates. The local candidate. The remote candidate. Emitted when a candidate is selected for use in the stream by the controlling side of an ICE session. The controlled side should call AcceptSelectedCandidatePair or RejectSelectedCandidatePair when connectivity checks have either succeeded or failed for this candidate pair. See also: SelectedCandidatePairs. The local candidate that has been selected. The remote candidate that has been selected.

The candidates that have been selected for use to stream packets to the remote contact for each component of the stream. Change notification is given via the the CandidatePairSelected signal.

Note to client implementors (from RFC 5245 section 9.2.2.3):

If at least one of the pairs is In-Progress, the agent SHOULD wait for those checks to complete, and as each completes, redo the processing in this section until there are no losing pairs.

Also note that some or all of the local candidates in this list may represent a peer-reflexive candidate that do not appear in LocalCandidates.

See RFC 5245 Appendix B.6. for more details about why this is.

Update the entry in SelectedCandidatePairs for a particular component, and signal it to the remote side.

This method should only be called by the controlling side of an ICE session. See CandidatePairSelected for details.

In the SDP offer/answer model, this signalling will take place as generating an updated offer. Note that updates may be queued up until information about all components of all streams is gathered.

The local candidate that has been selected. The remote candidate that has been selected.
Represents the state of ICE negotiation for a single component of a stream to an endpoint. Candidate gathering and connectivity checks are in progress. The streaming implementation has found at least one working candidate pair. It is possible to send media at this point, but the controlling side has yet to negotiate the final candidates for use in this call. This component of the stream is connected, and an updated offer has been sent and accepted (finalising the candidates to be used for the call). This should be set by the CM in response to AcceptSelectedCandidatePair. The streaming implementation has tried connecting to all of the available candidates and none of them have connected. This is distinct from Failed, because the CM might be able to provide more candidates later (more likely in XMPP than SIP). The CM and streaming implementation are in agreement that it is impossible to connect to this endpoint. This value should only be set by the CM. The state of ICE negotiation with this Endpoint for each component of the stream. Emitted when the EndpointState property changes. The component whose state has changed. The new state of this component. Change the EndpointState of the endpoint. The component whose state needs updating. The new state of this component. Called in response to CandidatePairSelected if/when this candidate pair is known to have passed its connectivity checks. The local candidate that has been selected. The remote candidate that has been selected. Called in response to CandidatePairSelected if/when this candidate pair is known to have failed its connectivity checks. The local candidate that has been selected. The remote candidate that has been selected. The transport type for the stream endpoint. This can be different from the transport of the Stream in the case where of falling back from ICE to Raw_UDP.

The local side is taking the controlling role (as defined by ICE RFC 5245). Change notification is given via the ControllingChanged signal.

In ICE, the Caller is normally in controlling mode (and the Callee in controlled-mode), except if the Caller is doing ICE-Lite, in which case it's reversed. The Controlling side is responsible for selecting nominated pairs, and generating updated offers upon conclusion of ICE.
Set whether the local side is taking the Controlling role. Note that if there are multiple endpoints (e.g. SIP call forking) it may be the case that all endpoints need to have the same controlling/controlled orientation. The new value of Controlling. The value of Controlling has changed. The new value of Controlling. The Remote side is an ICE Lite endpoint. (The local side is assumed to always be an ICE Full implementation.)
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Presence.xml0000664000175000017500000004154712470405660022342 0ustar jrjr Copyright (C) 2005, 2006 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

Mapping used in Last_Activity_And_Statuses and passed to SetStatus, representing a collection of statuses. Use of this mapping with more than one member is deprecated. Structure representing a contact's presence, containing a last-activity time (deprecated) and a Multiple_Status_Map. Mapping returned by GetPresence and signalled by PresenceUpdate, where the keys are contacts and the values represent their presences. The string identifier of the desired status A dictionary of optional parameter names mapped to their variant-boxed values Request that a single presence status is published for the user, along with any desired parameters. Changes will be indicated by PresenceUpdate signals being emitted. Request that all of a user's presence statuses be removed. Be aware that this request may simply result in the statuses being replaced by a default available status. Changes will be indicated by PresenceUpdate signals being emitted. An array of the contacts whose presence should be obtained Presence information in the same format as for the PresenceUpdate signal Get presence previously emitted by PresenceUpdate for the given contacts. Data is returned in the same structure as the PresenceUpdate signal. Using this method in favour of RequestPresence has the advantage that it will not wake up each client connected to the PresenceUpdate signal. A dictionary of string identifiers mapped to a struct for each status, containing:
  • a type value from one of the values above
  • a boolean to indicate if this status may be set on yourself
  • a boolean to indicate if this is an exclusive status which you may not set alongside any other
  • a dictionary of valid optional string argument names mapped to their types
Get a dictionary of the valid presence statuses for this connection. This is only available when online because only some statuses will be available on some servers.
A dictionary of contact handles mapped to a struct containing a UNIX timestamp of the last activity time (in UTC), and a dictionary mapping the contact's current status identifiers to a dictionary of optional parameter names mapped to their variant-boxed values This signal should be emitted when your own presence has been changed, or the presence of the member of any of the connection's channels has been changed, or when the presence requested by RequestPresence is available. The string identifier of the status not to publish anymore for the user Request that the given presence status is no longer published for the user. Changes will be indicated by PresenceUpdate signals being emitted. As with ClearStatus, removing a status may actually result in it being replaced by a default available status. The status requested is not currently set An array of the contacts whose presence should be obtained Request the presence for contacts on this connection. A PresenceUpdate signal will be emitted when they are received. This is not the same as subscribing to the presence of a contact, which must be done using the 'subscription' ContactList, and on some protocols presence information may not be available unless a subscription exists. The presence of the requested contacts is not reported to this connection A UNIX timestamp of the user's last activity time (in UTC) Request that the recorded last activity time for the user be updated on the server. This protocol has no concept of idle time A dictionary mapping status identifiers to dictionaries, which map optional parameter names to their variant-boxed values

Request that the user's presence be changed to the given statuses and desired parameters. Changes will be reflected by PresenceUpdate signals being emitted.

Statuses whose Connection_Presence_Type is Offline, Error or Unknown MUST NOT be passed to this function. Connection managers SHOULD reject these statuses.

The same rationale as for SimplePresence.SetPresence applies.

On certain protocols, this method may be called on a newly-created connection which is still in the DISCONNECTED state, and will sign on with the requested status. If the requested status is not available after signing on, NotAvailable will be returned and the connection will remain offline, or if the protocol does not support signing on with a certain status, Disconnected will be returned.

Client implementations SHOULD use SimplePresence instead. Connection managers implementing Presence MUST implement SimplePresence too.

This interface is for services which have a concept of presence which can be published for yourself and monitored on your contacts. Telepathy's definition of presence is based on that used by the Galago project.

Presence on an individual (yourself or one of your contacts) is modelled as a last activity time along with a set of zero or more statuses, each of which may have arbitrary key/value parameters. Valid statuses are defined per connection, and a list of them can be obtained with the GetStatuses method.

(The SimplePresence interface which replaces this one restricts presences to one status per contact, with an optional message, which is in practice all that was implemented on this interface.)

Each status has an arbitrary string identifier which should have an agreed meaning between the connection manager and any client which is expected to make use of it. The well-known values defined by the SimplePresence interface SHOULD be used where possible

As well as these well-known status identifiers, every status also has a numerical type value chosen from Connection_Presence_Type which can be used by the client to classify even unknown statuses into different fundamental types.

These numerical types exist so that even if a client does not understand the string identifier being used, and hence cannot present the presence to the user to set on themselves, it may display an approximation of the presence if it is set on a contact.

The dictionary of variant types allows the connection manager to exchange further protocol-specific information with the client. It is recommended that the string (s) argument 'message' be interpreted as an optional message which can be associated with a presence status.

If the connection has a 'subscribe' contact list, PresenceUpdate signals should be emitted to indicate changes of contacts on this list, and should also be emitted for changes in your own presence. Depending on the protocol, the signal may also be emitted for others such as people with whom you are communicating, and any user interface should be updated accordingly.

On some protocols, RequestPresence may only succeed on contacts on your 'subscribe' list, and other contacts will cause a PermissionDenied error. On protocols where there is no 'subscribe' list, and RequestPresence succeeds, a client may poll the server intermittently to update any display of presence information.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_HTML.xml0000664000175000017500000001027212470405660020602 0ustar jrjr Copyright (C) 2008 Collabora Ltd. Copyright (C) 2008 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft version, not API-stable)

This interface extends the Messages interface to support capability discovery, so clients can decide what subset of HTML is supported.

(However, the capability discovery mechanism has not been written yet, so this interface MUST NOT be used. It exists only to indicate what direction we intend to go in.)

XMPP supports all of XHTML-IM, and SIP (at least theoretically) supports all of XHTML. However, many protocols are more limited - for instance, in MSN you can only set font properties for a whole message at a time. We should not mislead users into thinking they can send MSN messages where individual words are emphasized.

If this interface is present, clients MAY send XHTML formatted text in message parts with type "text/html", and SHOULD interpret "text/html" message parts received in reply.

Client authors SHOULD pay careful attention to the security considerations in XEP-0071, "XHTML-IM", to avoid exposing client users to security risks. Clients MUST NOT assume that connection managers will filter messages to remove unsafe HTML.

Connection managers are the components in Telepathy that are most likely to be exploitable by a remote attacker to run malicious code (since they are network-facing), so any filtering that the CM does might be subverted.

To avoid misleading users, clients SHOULD only present UI for the subset of HTML that is indicated to be supported by this interface. It follows that clients SHOULD NOT send unsupported markup to the connection manager. However, even if the connection manager cannot send arbitrary XHTML, it MUST cope gracefully with being given arbitrary XHTML by a client.

Connection managers should be lenient in what they receive.

Clients MUST NOT send HTML that is not well-formed XML, but connection managers MAY signal HTML that is malformed or invalid. Clients SHOULD attempt to parse messages as XHTML, but fall back to using a permissive "tag-soup" HTML parser if that fails. (FIXME: or should the presence of this interface imply that the CM fixes up "text/html" to be XHTML? In practice that would result in all the CMs having to link against libxml2 or something... the rationale above no longer applies here, since dropping a malformed message is "safe")

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Avatars.xml0000664000175000017500000005436412470405660022200 0ustar jrjr Copyright (C) 2005-2008 Collabora Limited Copyright (C) 2005-2008 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

strengthened uniqueness requirements so (CM name, protocol, token) is unique; previously only (our Account, remote contact identifier, token) was required to be unique

An opaque token chosen by the connection manager, representing a particular avatar.

Because avatars can be relatively large images, most protocols provide a way to detect whether an old avatar is still valid, or whether an avatar has changed, without pushing the actual avatar data to all clients.

The connection manager MUST choose these tokens in a way that makes it highly unlikely that two different avatars with the same connection manager and protocol will have the same token.

This means that clients MAY use the triple (Connection_Manager_Name, Protocol, avatar token) as a key for their avatar cache. For instance, an avatar for a telepathy-gabble Jabber contact might be stored in a file .../gabble/jabber/4e199b4a1c40b497a95fcd1cd896351733849949.png.

For instance, some protocols (like XMPP) identify avatars by a hash of the avatar data; in this case, the hash can be used as the avatar token.

Some protocols identify avatars by the timestamp of the last change to the avatar; in these protocols it would be necessary for the connection manager to encode both the timestamp and the contact's identifier into the avatar token in order to ensure uniqueness.

This token SHOULD be kept short and reasonably suitable for use in a filename, but MAY contain any UTF-8 character (so clients using avatar tokens in filenames MUST be prepared to escape characters that are not valid in filenames). Connection managers for protocols where tokens would otherwise become inconveniently large or contain many unsuitable characters SHOULD hash the identifying data to generate the token.

A dictionary whose keys are contact handles and whose values are avatar tokens. An integer handle for the contact whose avatar has changed Unique token for their new avatar Emitted when the avatar for a contact has been updated, or first discovered on this connection. If the token differs from the token associated with the client's cached avatar for this contact, the new avatar should be requested with RequestAvatars. The contact whose avatar has been retrieved The token corresponding to the avatar An array of bytes containing the image data A string containing the image MIME type (eg image/jpeg), or empty if unknown Emitted when the avatar for a contact has been retrieved. Fall back to calling GetAvatarRequirements if getting this property fails. An array of supported MIME types (e.g. "image/jpeg"). Clients MAY assume that the first type in this array is preferred. This property cannot change after the Connection goes to the Connected state. Fall back to calling GetAvatarRequirements if getting this property fails. The minimum height in pixels of an avatar on this protocol, which MAY be 0. This property cannot change after the Connection goes to the Connected state. Fall back to calling GetAvatarRequirements if getting this property fails. The minimum width in pixels of an avatar on this protocol, which MAY be 0. This property cannot change after the Connection goes to the Connected state. The recommended height in pixels of an avatar on this protocol, or 0 if there is no preferred height. This property cannot change after the Connection goes to the Connected state. In XMPP a recommended width is given by the protocol specification; in proprietary protocols, using the same avatar size as the proprietary client is likely to lead to the best display to other users. The recommended width in pixels of an avatar on this protocol, or 0 if there is no preferred width. This property cannot change after the Connection goes to the Connected state. The rationale is the same as for RecommendedAvatarHeight. Fall back to calling GetAvatarRequirements if getting this property fails. The maximum height in pixels of an avatar on this protocol, or 0 if there is no limit. This property cannot change after the Connection goes to the Connected state. Fall back to calling GetAvatarRequirements if getting this property fails. The maximum width in pixels of an avatar on this protocol, or 0 if there is no limit. This property cannot change after the Connection goes to the Connected state. Fall back to calling GetAvatarRequirements if getting this property fails. The maximum size in bytes of an avatar on this protocol, or 0 if there is no limit. This property cannot change after the Connection goes to the Connected state. Use GetAll to retrieve the D-Bus properties on this interface, falling back to this method on failure. An array of supported MIME types (eg image/jpeg) The minimum image width in pixels The minimum image height in pixels The maximum image width in pixels, or 0 if there is no limit The maximum image height in pixels, or 0 if there is no limit The maximum image size in bytes, or 0 if there is no limit Get the required format of avatars on this connection. An array of handles representing contacts An array of avatar tokens or empty strings (if no avatar is set) in the same order as the given array of contact handles Use GetKnownAvatarTokens instead. Get the unique tokens for all of the given contacts' avatars. Using this method in new Telepathy clients is deprecated; use GetKnownAvatarTokens instead. An array of handles representing contacts A dictionary of handles mapped to avatar tokens, containing only the known avatar tokens. Get the unique tokens for the given contacts' avatars. These tokens can be persisted across connections, and should be used by the client to check whether the avatars have been updated. For handles other than the self handle, only tokens that are already known are returned; an empty token means the given contact has no avatar. However, a CM must always have the tokens for the self handle if one is set (even if it is set to no avatar). On protocols where the avatar does not persist between connections, a CM should omit the self handle from the returned map until an avatar is explicitly set or cleared. An integer handle for the contact to request the avatar for An array of bytes containing the image data A string containing the image MIME type (eg image/jpeg), or empty if unknown Use RequestAvatars instead. Request the avatar for a given contact. Using this method in new Telepathy clients is deprecated; use RequestAvatars instead. The contact does not currently have an avatar. The contacts to retrieve avatars for Request avatars for a number of contacts. The AvatarRetrieved signal is emitted for each avatar retrieved. If the handles are valid but retrieving an avatar fails (for any reason, including the contact not having an avatar) the AvatarRetrieved signal is not emitted for that contact. An array of bytes representing the avatar image data A string representing the image MIME type The string token of the new avatar Set a new avatar image for this connection. The avatar image must respect the requirements obtained by GetAvatarRequirements. Remove the avatar image for this connection.

The same string that would be returned by GetKnownAvatarTokens (omitted from the result if the contact's avatar token is not known, present as an empty string if the contact is known not to have an avatar). Unlike in the GetKnownAvatarTokens method, the avatar tokens for the self handle aren't required to be present. This attribute should not be used to determine whether or not the Avatar needs to be set.

An interface for requesting avatars for contacts on a given connection, receiving notification when avatars are changed, and publishing your own avatar.

Avatars are identified by a string, the Avatar_Token, which represents a particular avatar. Tokens MUST be chosen by the connection manager in such a way that the triple (Connection_Manager_Name, Protocol, Avatar_Token) uniquely identifies an avatar. An empty token means that an avatar has not been set for this contact, and a changed token implies the contact's avatar has changed, but the strings should otherwise be considered opaque by clients.

A client should use GetKnownAvatarTokens to request the tokens for the avatars of all the contacts it is interested in when it connects. The avatars can then be requested using RequestAvatars for the contacts. Clients should bind to the AvatarUpdated signal and request a new copy of the avatar when a contacts' avatar token changes. Clients should cache the token and data of each contact's avatar between connections, to avoid repeatedly retrieving the same avatar.

To publish an avatar, a client should use SetAvatar to provide an image which meets the requirements returned by the GetAvatarRequirements function. On some protocols the avatar is stored on the server, so setting the avatar is persistent, but on others it is transferred via a peer to peer mechanism, so needs to be set every connection. Hence, on every connection, clients should inspect the avatar token of the connection's self handle using GetKnownAvatarTokens; if the self handle is not in the returned map, the client should re-set the avatar. If the self handle's avatar token is known, but the avatar has been changed locally since the last connection, the client should upload the new avatar; if the avatar has not changed locally, then the client should download the avatar from the server if its token differs from the that of the local avatar.

To remove the published avatar on protocols which have persistent avatars, a client should use the ClearAvatar method. This method can safely be used even if there is no avatar for this connection.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Conference.xml0000664000175000017500000007502512470405660022114 0ustar jrjr Copyright © 2009 Collabora Limited Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface for multi-user conference channels that can "continue from" one or more individual channels. This could be used to invite other contacts to an existing 1-1 text conversation, combine two phone calls into one conference call, and so on, with roughly the same API in each case.

This interface addresses freedesktop.org bug #24906 (GSM-compatible conference calls) and bug #24939 (upgrading calls and chats to multi-user). See those bugs for more rationale and use cases.

Existing channels are upgraded by requesting a new channel of the same ChannelType, listing the channels to be merged into the new conference in the InitialChannels property of the request. If InitialInviteeHandles and InitialInviteeIDs are Allowed_Properties in RequestableChannelClasses, ad-hoc conferences to a set of contacts may be created by requesting a channel, specifying InitialInviteeHandles and/or InitialInviteeIDs to be the contacts in question. A request may specify these alongside InitialChannels, to simultaneously upgrade a channel to a conference and invite others to join it.

Channels with this interface MAY also implement MergeableConference.DRAFT to support merging more 1-1 channels into an ongoing conference. Similarly, 1-1 channels MAY implement Splittable.DRAFT to support being broken out of a Conference channel.

The Group interface on Conference channels MAY use channel-specific handles for participants; clients SHOULD support both Conferences that have channel-specific handles, and those that do not.

In the GSM case, the Conference's Group interface MAY have channel-specific handles, to represent the fact that the same phone number may be in a conference twice (for instance, it could be the number of a corporate switchboard).

In the XMPP case, the Conference's Group interface SHOULD have channel-specific handles, to reflect the fact that the participants have MUC-specific identities, and the user might also be able to see their global identities, or not.

In most other cases, including MSN and link-local XMPP, the Conference's Group interface SHOULD NOT have channel-specific handles, since users' identities are always visible.

Connection managers implementing channels with this interface MUST NOT allow the object paths of channels that could be merged into a Conference to be re-used, unless the channel re-using the object path is equivalent to the channel that previously used it.

If you upgrade some channels into a conference, and then close the original channels, InitialChannels (which is immutable) will contain paths to channels which no longer exist. This implies that you should not re-use channel object paths, unless future incarnations of the path are equivalent.

For instance, on protocols where you can only have zero or one 1-1 text channels with Emily at one time, it would be OK to re-use the same object path for every 1-1 text channel with Emily; but on protocols where this is not true, it would be misleading.

Examples of usage

A pair of 1-1 GSM calls C1 and C2 can be merged into a single conference call by calling:

CreateChannel({ ...ChannelType: ...Call, ...InitialChannels: [C1, C2] })

which returns a new channel Cn implementing the conference interface. (As a quirk of GSM, both 1-1 will cease to function normally until they are Split from the conference, or the conference ends.)

An XMPP 1-1 conversation C3 (with chris@example.com, say) can be continued in a newly created multi-user chatroom by calling:

CreateChannel({ ...ChannelType: ...Text, ...InitialChannels: [C3] })

Or, to invite emily@example.net to join the newly-created MUC at the same time:

CreateChannel({ ...ChannelType: ...Text, ...InitialChannels: [C3], ...InitialInviteeIDs: ['emily@example.net'] })

To continue C3 in a particular multi-user chatroom (rather than the implementation inventing a unique name for the room), call:

EnsureChannel({ ...ChannelType: ...Text, ...TargetHandleType: ...Room, ...TargetID: 'telepathy@conf.example.com', ...InitialChannels: [C3] })

Note the use of EnsureChannel — if a channel for telepathy@conf.example.com is already open, this SHOULD be equivalent to inviting chris@example.com to the existing channel.

In the above cases, the text channel C3 SHOULD remain open and fully functional (until explicitly closed by a client); new incoming 1-1 messages from chris@example.com SHOULD appear in C3, and messages sent using C3 MUST be relayed only to chris@example.com.

If there is an open 1-1 text channel with a contact, in every other situation new messages will appear in that channel. Given that the old channel remains open — which is the least surprising behaviour, and eases us towards a beautiful world where channels never close themselves — it stands to reason that it should be where new messages from Chris should appear. On MSN, creating a conference from C3 should migrate the underlying switchboard from C3 to the new channel; this is an implementation detail, and should not affect the representation on D-Bus. With a suitable change of terminology, Skype has the same behaviour.

If the current handler of that channel doesn't want this to happen (maybe it transformed the existing tab into the group chat window, and so there'd be no UI element still around to show new messages), then it should just Close the old 1-1 channel; it'll respawn if necessary.

Either of the XMPP cases could work for Call channels, to upgrade from 1-1 Jingle to multi-user Jingle. Any of the XMPP cases could in principle work for link-local XMPP (XEP-0174).

XMPP and MSN do not natively have a concept of merging two or more channels C1, C2... into one channel, Cn. However, the GSM-style merging API can be supported on XMPP and MSN, as an API short-cut for upgrading C1 into a conference Cn (which invites the TargetHandle of C1 into Cn), then immediately inviting the TargetHandle of C2, the TargetHandle of C3, etc. into Cn as well.

Sample RequestableChannelClasses

A GSM connection might advertise the following channel class for conference calls:

( Fixed = {
    ...ChannelType: ...StreamedMedia
  },
  Allowed = [ InitialChannels, InitialAudio ]
)

This indicates support for starting audio-only conference calls by merging two or more existing channels (since InitialInviteeHandles and InitialInviteeIDs are not allowed).

An XMPP connection might advertise the following classes for ad-hoc multi-user text chats:

( Fixed = {
    ...ChannelType: ...Text
  },
  Allowed = [ InitialChannels, InitialInviteeHandles, InitialInviteeIDs, InvitationMessage ]
),
( Fixed = {
    ...ChannelType: ...Text,
    ...TargetHandleType: Room
  },
  Allowed = [ TargetHandle, TargetID,
              InitialChannels, InitialInviteeHandles, InitialInviteeIDs, InvitationMessage ]
)

The first class indicates support for starting ad-hoc (nameless) chat rooms, upgraded from existing 1-1 channels and/or inviting new contacts, along with a message to be sent along with the invitations. The second indicates support for upgrading to a particular named chat room.

The individual Channels that are continued by this conference, which have the same ChannelType as this one, but with TargetHandleType = CONTACT.

This property MUST NOT be requestable; instead, the InitialChannels property may be specified when requesting a channel.

This is consistent with requesting InitialInviteeHandles and InitialInviteeIDs, rather than requesting Group.Members and some hypothetical ID version of that property.

Change notification is via the ChannelMerged and ChannelRemoved signals.

Emitted when a new channel is added to the value of Channels.

The channel that was added to Channels. A new channel-specific handle for the TargetHandle of Channel, as will appear in OriginalChannels, or 0 if a global handle is used for Channel's TargetHandle on the Group interface of this channel. Channel's immutable properties.

Emitted when a channel is removed from the value of Channels, either because it closed or because it was split using the Splittable.DRAFT.Split method.

If a channel is removed because it was closed, Closed should be emitted before this signal.

The channel that was removed from Channels. Additional information about the removal, which may include the same well-known keys as the Details argument of MembersChangedDetailed, with the same semantics.

The initial value of Channels.

This property SHOULD be requestable. Omitting it from a request is equivalent to providing it with an empty list as value. Requests where its value has at least two channel paths SHOULD be expected to succeed on any implementation of this interface. If InitialInviteeHandles and InitialInviteeIDs are Allowed_Properties in RequestableChannelClasses, then requests with zero or one channel paths SHOULD also succeed; otherwise, clients SHOULD NOT make requests with zero or one paths for this property.

In GSM, a pair of calls can be merged into a conference, but you can't start a conference call from zero or one existing calls. In XMPP and MSN, you can create a new chatroom, or upgrade one 1-1 channel into a chatroom; however, on these protocols, it is also possible to fake GSM-style merging by upgrading the first channel, then inviting the targets of all the other channels into it.

If possible, the Channels' states SHOULD NOT be altered by merging them into a conference. However, depending on the protocol, the Channels MAY be placed in a "frozen" state by placing them in this property's value or by calling MergeableConference.DRAFT.Merge on them.

In Jingle, nothing special will happen to merged calls. UIs MAY automatically place calls on hold before merging them, if that is the desired behaviour; this SHOULD always work. Not doing an implicit hold/unhold seems to preserve least-astonishment.

In GSM, the calls that are merged go into a state similar to Hold, but they cannot be unheld, only split from the conference call using Channel.Interface.Splittable.DRAFT.Split.

Depending on the protocol, it might be signalled to remote users that this channel is a continuation of all the requested channels, or that it is only a continuation of the first channel in the list.

In MSN, the conference steals the underlying switchboard (protocol construct) from one of its component channels, so the conference appears to remote users to be a continuation of that channel and no other. The connection manager has to make some arbitrary choice, so we arbitrarily mandate that it SHOULD choose the first channel in the list as the one to continue.

A list of additional contacts invited to this conference when it was created.

If it is possible to invite new contacts when creating a conference (as opposed to merging several channels into one new conference channel), this property SHOULD be requestable, and appear in the allowed properties in RequestableChannelClasses. Otherwise, this property SHOULD NOT be requestable, and its value SHOULD always be the empty list.

On GSM you have to place a 1-1 call before you can merge it into a conference; on the other hand, you can invite new contacts to XMPP Muji calls and XMPP/MSN/Skype ad-hoc chat rooms without starting a 1-1 channel with them first.

If included in a request, the given contacts are automatically invited into the new channel, as if they had been added with Group.AddMembers(InitialInviteeHandles, InvitationMessage) immediately after the channel was created.

This is a simple convenience API for the common case that a UI upgrades a 1-1 chat to a multi-user chat solely in order to invite someone else to participate.

If the local user was not the initiator of this channel, the Group.SelfHandle SHOULD appear in the value of this property, together with any other contacts invited at the same time (if that information is known).

InitialInviteeHandles, InitialInviteeIDs and InitialChannels MAY be combined in a single request.

For example, if you have a 1-1 channel C1 with Rob, and you want to invite Sjoerd to join the discussion, you can do so by requesting a channel with InitialChannels=[C1] and InitialInviteeHandles=[sjoerd], or InitialChannels=[C1] and InitialInviteeIDs=["sjoerd@example.com"].

If a request includes some combination of InitialInviteeHandles, InitialInviteeIDs and InitialChannels, then the value of InitialInviteeHandles on the resulting channel SHOULD be the union of the handles from InitialInviteeHandles, the handles corresponding to the InitialInviteeIDs, and the target handles of the InitialChannels, with any duplicate handles removed. Because this property is immutable, its value SHOULD be computed before the channel is announced via the NewChannels signal.

This simplifies identification of new channels in clients - they only have to look at one of the properties, not both. For example, after either of the requests mentioned above, the NewChannels signal would announce the channel with InitialChannels=[C1], InitialInviteeHandles=[rob, sjoerd], and InitialInviteeIDs=["rob@example.net", "sjoerd.example.com"].

A list of additional contacts invited to this conference when it was created.

This property SHOULD be requestable if and only if InitialInviteeHandles is requestable. Its semantics are the same, except that it takes a list of the string representations of contact handles; invitations are sent to any contact present in either or both of these properties.

When a channel is created, the values of InitialInviteeHandles and InitialInviteeIDs MUST correspond to each other. In particular, this means that the value of InitialInviteeIDs will include the TargetID of each channel in InitialChannels, and the ID corresponding to each handle in InitialInviteeHandles.

The message that was sent to the InitialInviteeHandles when they were invited.

This property SHOULD be requestable, and appear in the allowed properties in RequestableChannelClasses, in protocols where invitations can have an accompanying text message.

This allows invitations with a message to be sent when using InitialInviteeHandles or InitialInviteeIDs.

If the local user was not the initiator of this channel, the message with which they were invited (if any) SHOULD appear in the value of this property.

On GSM conference calls, it is possible to have the same phone number in a conference twice; for instance, it could be the number of a corporate switchboard. This is represented using channel-specific handles; whether or not a channel uses channel-specific handles is reported in Group.GroupFlags. The Group.HandleOwners property specifies the mapping from opaque channel-specific handles to actual numbers; this property specifies the original 1-1 channel corresponding to each channel-specific handle in the conference.

In protocols where this situation cannot arise, such as XMPP, this property MAY remain empty.

For example, consider this situation:

  1. Place a call (with path /call/to/simon) to the contact +441234567890 (which is assigned the handle h, say), and ask to be put through to Simon McVittie;
  2. Put that call on hold;
  3. Place another call (with path /call/to/jonny) to +441234567890, and ask to be put through to Jonny Lamb;
  4. Request a new channel with InitialChannels: ['/call/to/simon', '/call/to/jonny'].

The new channel will have the following properties, for some handles s and j:

{
...Group.GroupFlags: Channel_Specific_Handles | (other flags),
...Group.Members: [self_handle, s, j],
...Group.HandleOwners: { s: h, j: h },
...InitialChannels: ['/call/to/simon', '/call/to/jonny'],
...Channels: ['/call/to/simon', '/call/to/jonny'],
...OriginalChannels: { s: '/call/to/simon', j: '/call/to/jonny' },
# ...standard properties like ChannelType: Group elided...
}

Change notification is via the ChannelMerged and ChannelRemoved signals: if Channel_Specific_Handle in the former is non-zero, this property SHOULD be updated to map that handle to the merged channel's path.

A channel-specific handle for a participant in this conference. The object path of Channels representing the original 1-1 channel with Channel_Specific_Handle. A mapping from members of a conference to the original 1-1 channel with that contact, if any. See OriginalChannels for details.
telepathy-qt-0.9.6~git1/spec/Call_Interface_Mute.xml0000664000175000017500000001432312470405660020254 0ustar jrjr Copyright © 2005-2010 Nokia Corporation Copyright © 2005-2010 Collabora Ltd This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. (as stable API)

Interface for calls which may be muted. This only makes sense for channels where audio or video is streaming between members.

Muting a call content indicates that the user does not wish to send outgoing audio or video.

It should always be possible to mute an entire call. It is sometimes also possible to mute individual Contents (e.g. to prevent background noise from disturbing other participants, but remain visible on webcam) or to mute individual streams (e.g. to "whisper" to other call participants)

For some protocols, the fact that the content is muted needs to be transmitted to the peer; for others, the notification to the peer is only informational (eg. XMPP), and some protocols may have no notion of muting at all.
The mute state of (at least part of) the call. See LocalMuteState for more details. All streams are unmuted (the call is active). New channels SHOULD have this mute state. All streams are Muted. The connection manager is attempting to move to state Muted, but has not yet completed that operation. It is unspecified whether any, all or none of the streams making up the channel are muted. Examining the Mute state of Call Contents (if applicable) may provide more useful information. The connection manager is attempting to move to state Unmuted, but has not yet completed that operation. It is unspecified whether any, all or none of the streams making up the channel are muted. Examining the Mute state of Call Contents or Streams may provide more useful information. Some of the constituent Streams are Muted. This state only makes sense on Call Channels or Contents. Examining the Mute state of Call Contents or Streams should provide more useful information. Emitted to indicate that the mute state has changed for this call content. This may occur as a consequence of the client calling RequestMuted, or as an indication that another client has (un)muted the content. The new mute state. The current mute state of this part of the call. New Contents should inherit the value of this property from the parent Call1. Similarly, Streams should inherit it from the parent Content. renamed from SetMuted to Mute renamed back from Mute to SetMuted True if the client wishes to mute the Content or Call.

Inform the CM that the Call, Content or Stream should be muted or unmuted.

The CM will tell the streaming implementation to Mute Streams as required, and emit MuteStateChanged when done.

telepathy-qt-0.9.6~git1/spec/Call_Content_Media_Description_Interface_RTCP_Extended_Reports.xml0000664000175000017500000001412312470405660030602 0ustar jrjr Copyright © 2005-2010 Nokia Corporation Copyright © 2005-2010 Collabora Ltd This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. (as stable API)

This codec offer interface provides a method of signalling for RTCP extended reports, documented by RTP Control Protocol Extended Reports (RTCP XR) (RFC 3611). CMs should ignore all RTCP Extended Report parameters that are not listed in this spec at the time of implementation. More parameters can be added to the spec as required.

For more details on what RTCP extended reports can do and how to use them, one should refer to RFC 3611.

If non-zero, enable Loss Run Length Encoded Report Blocks. The value of this integer represents the max-size of report blocks, as specified in RFC 3611 section 5.1. MAXUINT32 is used to indicate that there is no limit. If non-zero, enable Duplicate Run-Length-Encoded Report Blocks. The value of this integer represents the max-size of report blocks, as specified in RFC 3611 section 5.1. MAXUINT32 is used to indicate that there is no limit. If non-zero, enable Packet Receipt Times Report Blocks. The value of this integer represents the max-size of report blocks, as specified in RFC 3611 section 5.1. MAXUINT32 is used to indicate that there is no limit. If non-zero, enable Receiver Reference Time and Delay since Last Receiver Report Blocks (for estimating Round Trip Times between non-senders and other parties in the call. The value of this integer represents the max-size of report blocks, as specified in RFC 3611 section 5.1. MAXUINT32 is used to indicate that there is no limit. Who is allowed to send Delay since Last Receiver Reports. Which fields SHOULD be included in the statistics summary report blocks that are sent, and whether to send VoIP Metrics Report Blocks. There can be zero or more flags set. Whether to enable VoIP Metrics Report Blocks. These blocks are of a fixed size. Loss report flag, as defined in RFC3611 section 4.6. Duplicate report flag, as defined in RFC3611 section 4.6. Jitter flag, as defined in RFC3611 section 4.6. First bit of TTL or Hop Limit flag, as defined in RFC3611 section 4.6. Second bit of TTL or Hop Limit flag, as defined in RFC3611 section 4.6. Both RTP data senders and data receivers MAY send DLRR blocks. Only active RTP senders MAY send DLRR blocks, i.e., non RTP senders SHALL NOT send DLRR blocks.
telepathy-qt-0.9.6~git1/spec/Channel_Future.xml0000664000175000017500000000617112470405660017333 0ustar jrjr Copyright (C) 2008 Collabora Ltd. Copyright (C) 2008 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

This interface contains functionality which we intend to incorporate into the Channel interface in future. It should be considered to be conceptually part of the core Channel interface, but without API or ABI guarantees.

If we add new functionality to the Channel interface, libraries that use generated code (notably telepathy-glib) will have it as part of their ABI forever, meaning we can't make incompatible changes. By using this interface as a staging area for future Channel functionality, we can try out new properties, signals and methods as application-specific extensions, then merge them into the core Channel interface when we have enough implementation experience to declare them to be stable.

The name is by analogy to Python's __future__ pseudo-module.

(in Channel.FUTURE pseudo-interface)

The ChannelBundle.DRAFT to which this channel belongs.

A channel's Bundle property can never change.

Older connection managers might not have this property. Clients (particularly the channel dispatcher) SHOULD recover by considering each channel to be in a bundle containing only that channel, distinct from all other bundles, which has no additional interfaces.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Hold.xml0000664000175000017500000002255712470405660020735 0ustar jrjr Copyright (C) 2005-2008 Collabora Limited Copyright (C) 2005-2008 Nokia Corporation Copyright (C) 2006 INdT This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. first API-stable version

Interface for channels where you may put the channel on hold. This only makes sense for channels where you are streaming media to or from the members. (To see whether the other participant has put you on hold, see CallState.)

If you place a channel on hold, this indicates that you do not wish to be sent media streams by any of its members and will be ignoring any media streams you continue to receive. It also requests that the connection manager free up any resources that are only needed for an actively used channel (e.g. in a GSM or PBX call, it will be necessary to place an active call on hold before you can start another call).

This can also be used for putting a single Content on hold, if the protocol supports it (This interface is in the Channel namespace for historical reasons).

Return whether the local user has placed the channel on hold. The state of the channel The reason why the channel is in that state Emitted to indicate that the hold state has changed for this channel. This may occur as a consequence of you requesting a change with RequestHold, or the state changing as a result of a request from another process. The state of the channel The reason for the state change The hold state of a channel. All streams are unheld (the call is active). New channels SHOULD have this hold state. All streams are held (the call is on hold) The connection manager is attempting to move to state Held, but has not yet completed that operation. It is unspecified whether any, all or none of the streams making up the channel are on hold. Examining the Hold state of Call Contents (if applicable) may provide more useful information. The connection manager is attempting to move to state Unheld, but has not yet completed that operation. It is unspecified whether any, all or none of the streams making up the channel are on hold. Examining the Hold state of Call Contents (if applicable) may provide more useful information. The reason for a change to the Local_Hold_State. Clients MUST treat unknown values as equivalent to Local_Hold_State_Reason_None. The reason cannot be described by any of the predefined values (connection managers SHOULD avoid this reason, but clients MUST handle it gracefully) The change is in response to a user request The change is because some resource was not available A boolean indicating whether or not the channel should be on hold

Request that the channel be put on hold (be instructed not to send any media streams to you) or be taken off hold.

If the connection manager can immediately tell that the requested state change could not possibly succeed, this method SHOULD return the NotAvailable error. If the requested state is the same as the current state, this method SHOULD return successfully without doing anything.

Otherwise, this method SHOULD immediately set the hold state to Local_Hold_State_Pending_Hold or Local_Hold_State_Pending_Unhold (as appropriate), emitting HoldStateChanged if this is a change, and return successfully.

The eventual success or failure of the request is indicated by a subsequent HoldStateChanged signal, changing the hold state to Local_Hold_State_Held or Local_Hold_State_Unheld.

If the channel has multiple streams, and the connection manager succeeds in changing the hold state of one stream but fails to change the hold state of another, it SHOULD attempt to revert all streams to their previous hold states.

The following state transitions SHOULD be used, where appropriate:

  • Successful hold: (Unheld, any reason) → (Pending_Hold, Requested) → (Held, Requested)
  • Successful unhold: (Held, any reason) → (Pending_Unhold, Requested) → (Unheld, Requested)
  • Attempting to unhold fails at the first attempt to acquire a resource: (Held, any reason) → (Pending_Unhold, Requested) → (Held, Resource_Not_Available)
  • Attempting to unhold acquires one resource, but fails to acquire a second, and takes time to release the first: (Held, any reason) → (Pending_Unhold, Requested) → (Pending_Hold, Resource_Not_Available) → (Held, Resource_Not_Available)
The requested hold state cannot be achieved; for example, if only a limited number of channels can be in the "not on hold" state, attempts to exceed this number will raise NotAvailable.
telepathy-qt-0.9.6~git1/spec/generic-types.xml0000664000175000017500000002155212470405660017207 0ustar jrjr An unsigned 32-bit integer representing time as the number of seconds elapsed since the Unix epoch (1970-01-01T00:00:00Z) An signed 64-bit integer representing time as the number of seconds elapsed since the Unix epoch (1970-01-01T00:00:00Z); negative for times before the epoch The Text interface is the only user of Unix_Timestamp so far, and we'd like to be Y2038 compatible in future interfaces. A string representing a D-Bus bus name - either a well-known name like "org.freedesktop.Telepathy.MissionControl" or a unique name like ":1.123" A string representing a D-Bus well-known name like "org.freedesktop.Telepathy.MissionControl". A string representing a D-Bus unique name, such as ":1.123" An ASCII string representing a D-Bus interface - two or more elements separated by dots, where each element is a non-empty string of ASCII letters, digits and underscores, not starting with a digit. The maximum total length is 255 characters. For example, "org.freedesktop.DBus.Peer". An ASCII string representing a D-Bus error. This is syntactically the same as a DBus_Interface, but the meaning is different. A string representing a D-Bus signature (the 'g' type isn't used because of poor interoperability, particularly with dbus-glib) An ASCII string representing a D-Bus method, signal or property name - a non-empty string of ASCII letters, digits and underscores, not starting with a digit, with a maximum length of 255 characters. For example, "Ping". A string representing the full name of a D-Bus method, signal or property, consisting of a DBus_Interface, followed by a dot, followed by a DBus_Member. For example, "org.freedesktop.DBus.Peer.Ping". A mapping from strings representing D-Bus properties (by their namespaced names) to their values. A D-Bus interface name, followed by a dot and a D-Bus property name. The value of the property. A mapping from strings to variants representing extra key-value pairs. A mapping from strings to strings representing extra key-value pairs. An IP address and port. Either a dotted-quad IPv4 address literal as for Socket_Address_IPv4, or an RFC2373 IPv6 address as for Socket_Address_IPv6. The TCP or UDP port number. An IPv4 address and port. A dotted-quad IPv4 address literal: four ASCII decimal numbers, each between 0 and 255 inclusive, e.g. "192.168.0.1". The TCP or UDP port number. An IPv6 address and port. An IPv6 address literal as specified by RFC2373 section 2.2, e.g. "2001:DB8::8:800:200C:4171". The TCP or UDP port number. An IPv4 network or subnet. A dotted-quad IPv4 address literal: four ASCII decimal numbers, each between 0 and 255 inclusive, e.g. "192.168.0.1". The number of leading bits of the address that must match, for this netmask to be considered to match an address. An IPv6 network or subnet. An IPv6 address literal as specified by RFC2373 section 2.2, e.g. "2001:DB8::8:800:200C:4171". The number of leading bits of the address that must match, for this netmask to be considered to match an address.

The time at which an user action occurred. This type has the 2 following special values:

0: the action doesn't involve any user action. Clients SHOULD avoid stealing focus when presenting the channel.

MAX_INT64: clients SHOULD behave as though the user action happened at the current time, e.g. a client MAY request that its window gains focus.

This can be used by clients that can't know the X server time like command line applications for example.

For all the other values it corresponds to the time of the user action. Clients SHOULD use this for focus-stealing prevention, if applicable. Note that the time is dependant on the local environment and so is not necessarily a wall-clock time. For example in an X environment it's expected to be the X timestamp of events. This corresponds to the _NET_WM_USER_TIME property in EWMH.

A mapping from object path to the immutable properties of the object. The object path of an object The immutable properties of the object A language tag as defined in IETF BCP 47, such as "en_US".
telepathy-qt-0.9.6~git1/spec/Call_Content_Interface_Media.xml0000664000175000017500000005651412470405660022063 0ustar jrjr Copyright © 2009-2010 Collabora Ltd. Copyright © 2009-2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

Interface to use by a software implementation of media streaming. The reason behind splitting the members of this interface out from the main Content interface is that the software is not necessarily what controls the media. An example of this is in GSM phones, where the CM just tells the phone to dial a number and it does the audio routing in a device specific hardware way and the CM does not need to concern itself with codecs.

Codec Negotiation

When a new Call1 channel appears (whether it was requested or not) a MediaDescription object will either be waiting in the MediaDescriptionOffer property, or will appear at some point via the NewMediaDescriptionOffer signal.

If nothing is known about the remote side's Media capabilities (e.g. outgoing SIP/XMPP call), this MediaDescription will pop up with {HasRemoteInformation = false, FurtherNegotiationRequired = true}, and the local user's streaming implementation SHOULD call Accept, with a description of all supported codecs and other features. The CM will then send this information to the remote side (and LocalMediaDescriptionChanged will fire with details of the description passed into Accept for debugging purposes).

When the remote codecs and other content information are available (e.g. Remote user replies to initial offer, or sends a new offer of their own, a new MediaDescription will appear, with {HasRemoteInformation = true, FurtherNegotiationRequired = false}, and the Codecs property on the description offer set to the codecs which are supported by the remote contact. The local user's streaming implementation SHOULD then call Accept, with a description that is compatible with the one one in the offer. After the codec set is accepted, both LocalMediaDescriptionChanged and RemoteMediaDescriptionsChanged will fire to signal their respective changes, to aid with debugging. Note that if Accept is called, with FurtherNegotiationRequired set to false, the CM should be able to rely on the fact that the description passed into Accept is compatible with the one in the offer, and the description passed into Accept will not be signalled to the remote side.

Changing codecs mid-call

To update the codecs in the local (and optionally remote) media descriptions mid-call, the UpdateLocalMediaDescription method should be called with details of the new codec list. If this is accepted, then LocalMediaDescriptionChanged will be emitted with the new codec set.

If parameters requiring negotiation are changed, then the FurtherNegotiationRequired property should be set to TRUE, and the new media description should only be used once they come in a new MediaDescriptionOffer

If the other side decides to update his or her codec list during a call, a new MediaDescription object will appear through NewMediaDescriptionOffer which should be acted on as documented above.

Protocols without negotiation

For protocols where the codecs are not negotiable, the initial content's MediaDescription object will appear with HasRemoteInformation, set to true and the known supported codec values in Codecs.

A description of a codec. Numeric identifier for the codec. This will be used as the PT in the SDP or content description. The name of the codec. The clockrate of the codec. Number of channels of the codec if applicable, otherwise 0. This should be set to true in calls to Accept and UpdateLocalMediaDescription if this codec has changed in a way that needs to be signalled over the network. If it is set to false, the CM is allowed ignore any differences between the current parameters and the previous ones This mechanism may be used to save bandwidth and avoid the CM having to calculate diffs against previous versions of this struct, which can lead to false-positives (e.g. redundant ptime updates). Extra parameters for this codec. A map from contact to the list of codecs he or she supports. A contact handle. The codecs that the contact supports. The remote contact this description refers to or 0. This matches the RemoteContact property on MediaDescription The properties of the description The remote description offer and its information The object path to the MediaDescription The immutable properties of all interfaces of the codec description. Having all the codec description properties here saves a D-Bus round-trip - it shouldn't be necessary to get the properties from the MediaDescription object, in practice. Update the local codec mapping and other interfaces of the MediaDescription. This method should only be used during an existing call to update the local media description. This may trigger a re-negotiation which may result in new new MediaDescriptionOffers if the "FurtherNegotiationRequired" property is TRUE. Otherwise, only parameters which strictly describe the media being sent can be changed. The updated media description that the local side wants to use. The protocol does not support changing the codecs mid-call. The description given is invalid in some way.

A map from contact handles to descriptions supported by that contact.

Keys of this map will appear in at most one RemoteMembers. See RemoteContact for more details on how to map between MediaDescriptions and Streams.

A map from contact handles to the descriptions the local side responsed with.

Emitted when a new MediaDescription appears. The streaming >implementation MUST respond by calling the Accept or Reject method on the description object appeared.

Emission of this signal indicates that the MediaDescriptionOffer property has changed to (Description, Contact, MediaDescriptionProperties).

When the MediaDescriptionOffer has been dealt with then MediaDescriptionOfferDone must be emitted before NewMediaDescriptionOffer is emitted again.

The object path of the new media description. This replaces any previous media description. The immutable properties of the remote media description. Having all the MediaDescription properties here saves a D-Bus round-trip - it shouldn't be necessary to get the properties from the MediaDescription object, in practice.

Emitted when a MediaDescription has been handled.

Emission of this signal indicates that the MediaDescriptionOffer property has changed to ("/", 0, {}).

Change notification for LocalMediaDescriptions

The local content description that was updated

Change notification for RemoteMediaDescriptions

The remote content descriptions that were updated

Removal notification for RemoteMediaDescriptions and LocalMediaDescriptions

The local and remote content descriptions that are no longer part of this content

The object path to the current MediaDescription object, its RemoteContact and a mapping of the MediaDescriptions properties. If the object path is "/" then there isn't an outstanding content description, and the mapping MUST be empty.

Having all MediaDescription properties here saves a D-Bus round-trip - it shouldn't be necessary to get these properties from the Content MediaDescription object, in practice.

Change notification is via the NewMediaDescriptionOffer and MediaDescriptionOfferDone signals.

A packetization method that can be used for a content. Real-time Transport Protocol, as documented by RFC 3550. Raw media. MSN webcam. This is the video-only one-way type which was used in earlier versions of WLM. Although no longer used, modern WLM clients still support the MSN webcam protocol.

The packetization method in use for this content.

Used by the CM to relay instructions from Channel.Interface.DTMF to the streaming implementation. If any contact in this call supports the telephone-event codec in their MediaDescription, this event should be sent as outlined in RFC 4733. Otherwise, it should be sent as an audible tone. The event to send (or stop sending). Either Pending_Send or Pending_Stop_Sending. Called by the streaming implementation in response to DTMFChangeRequested to confirm that it has started or stopped sending the event in question. The event referred to in the corresponding DTMFChangeRequested signal. Either Sending or None. The currently requested DTMF event (for state-recoverability of DTMFChangeRequested). Should be ignored if CurrentDTMFState is None. The current DTMF state (for state-recoverability of DTMFChangeRequested). Signal an unrecoverable error for this content, and remove it. A reason struct describing the error.
telepathy-qt-0.9.6~git1/spec/Channel_Dispatcher_Interface_Operation_List.xml0000664000175000017500000001332412470405660025140 0ustar jrjr Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as a stable interface)

This interface allows users of the ChannelDispatcher to enumerate all the pending dispatch operations, with change notification.

The existence of the DispatchOperations property allows a newly started approver to pick up existing dispatch operations.

This is on a separate interface so clients that aren't interested in doing this aren't woken up by its signals.

Details of a channel dispatch operation. The object path of the ChannelDispatchOperation.

Properties of the channel dispatch operation.

Connection managers MUST NOT include properties in this mapping if their values can change. Clients MUST ignore properties that appear in this mapping if their values can change.

The rationale is the same as for Channel_Details.

Each dictionary MUST contain at least the following keys:

  • org.freedesktop.Telepathy.ChannelDispatchOperation.Interfaces
  • org.freedesktop.Telepathy.ChannelDispatchOperation.Connection
  • org.freedesktop.Telepathy.ChannelDispatchOperation.Account
  • org.freedesktop.Telepathy.ChannelDispatchOperation.PossibleHandlers

The list of ChannelDispatchOperation objects currently being processed. Change notification is via the NewDispatchOperation and DispatchOperationFinished signals.

Emitted when a dispatch operation is added to DispatchOperations.

The dispatch operation that was created. The same properties that would appear in the Properties member of Dispatch_Operation_Details.
Emitted when a dispatch operation finishes (i.e. exactly once per emission of ChannelDispatchOperation.Finished). Strictly speaking this is redundant with ChannelDispatchOperation.Finished, but it provides full change-notification for the DispatchOperations property. The dispatch operation that was closed.
telepathy-qt-0.9.6~git1/spec/Channel_Type_Stream_Tube.xml0000664000175000017500000003134512470405660021275 0ustar jrjr Copyright © 2008-2009 Collabora Limited Copyright © 2008-2009 Nokia Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A stream tube is a transport for ordered, reliable data transfer, similar to SOCK_STREAM sockets.

When offering a stream tube, the initiating client creates a local listening socket and offers it to the recipient client using the Offer method. When a recipient accepts a stream tube using the Accept method, the recipient's connection manager creates a new local listening socket. Each time the recipient's client connects to this socket, the initiator's connection manager proxies this connection to the originally offered socket.

Offer a stream tube exporting the local socket specified. The type of the listening address of the local service, as a member of Socket_Address_Type. The listening address of the local service, as indicated by the address_type. The access control the local service applies to the local socket, specified so the connection manager can behave appropriately when it connects. The dictionary of arbitrary Parameters to send with the tube offer. The contact associated with this channel doesn't have tube capabilities. The connection manager doesn't support the given address type or access-control type. Accept a stream tube that's in the "local pending" state. The connection manager will attempt to open the tube. The tube remains in the "local pending" state until the TubeChannelStateChanged signal is emitted. The type of address the connection manager should listen on.

The type of access control the connection manager should apply to the socket.

Note that if you plan to establish more than one connection through the tube, the Socket_Access_Control_Port access control can't be used as you can't connect more than once from the same port.

A parameter for the access control type, to be interpreted as specified in the documentation for the Socket_Access_Control enum. The address on which the connection manager will listen for connections to this tube. The client should not attempt to connect to the address until the tube is open. The access_control_param is invalid with the given access_control. The given address type or access-control mechanism is not supported.

Emitted each time a participant opens a new connection to its socket.

This signal is only fired on the offering side.

The handle of the participant who opened the new connection

A parameter which can be used by the listening process to identify the connection. Note that this parameter has a meaningful value only in the Socket_Access_Control_Port and Socket_Access_Control_Credentials cases. If a different Socket_Access_Control has been chosen when offering the tube, this parameter should be ignored.

In the Socket_Access_Control_Port case, the variant contains a struct Socket_Address_IPv4 (or Socket_Address_IPv6) containing the address from which the CM is connected to the client application.

In the Socket_Access_Control_Credentials case, the variant contains the byte (D-Bus signature 'y') that has been sent with the credentials.

The unique ID associated with this connection. This ID will be used to identifiy the connection when reporting errors with ConnectionClosed.

Emitted when the tube application connects to the CM's socket.

This signal is only fired on the accepting side.

The unique ID associated with this connection. This ID will be used to identifiy the connection when reporting errors with ConnectionClosed.

Emitted when a connection has been closed.

The ID of the connection.

The name of a D-Bus error describing the error that occurred.

The following errors can be used:

  • org.freedesktop.Telepathy.Error.Cancelled: user closed the socket or the tube.
  • org.freedesktop.Telepathy.Error.ConnectionLost: the bytestream relaying connection's data has been broken.
  • org.freedesktop.Telepathy.Error.ConnectionRefused: the tube offer refused the connection.
A debug message.

A string representing the service name that will be used over the tube. It should be a well-known TCP service name as defined by http://www.iana.org/assignments/port-numbers or http://www.dns-sd.org/ServiceTypes.html, for instance "rsync" or "daap".

When the tube is offered, the service name is transmitted to the other end.

When requesting a channel with Connection.Interface.Requests.CreateChannel, this property MUST be included in the request.

A mapping from address types (members of Socket_Address_Type) to arrays of access-control type (members of Socket_Access_Control) that the connection manager supports for stream tubes with that address type. For simplicity, if a CM supports offering a particular type of tube, it is assumed to support accepting it.

A typical value for a host without IPv6 support:

          {
            Socket_Address_Type_IPv4:
              [Socket_Access_Control_Localhost, Socket_Access_Control_Port,
               Socket_Access_Control_Netmask],
            Socket_Address_Type_Unix:
              [Socket_Access_Control_Localhost, Socket_Access_Control_Credentials]
          }
        

Connection Managers MUST support at least IPv4 with the localhost access control.

When requesting a channel with Connection.Interface.Requests.CreateChannel, this property MUST NOT be included in the request.

An identifier for a stream tube connection. These are defined with the NewLocalConnection or NewRemoteConnection signals and are used by ConnectionClosed to identify the closed connection.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Renaming.xml0000664000175000017500000001156212470405660022330 0ustar jrjr Copyright (C) 2005, 2006 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API) The handle of the original identifier The handle of the new identifier

Emitted when the unique identifier of a contact on the server changes.

Any channels associated with the contact's original handle will continue to be to that handle, and so are no longer useful (unless the contact renames back, or another contact connects with that unique ID). Clients may open a similar channel associated with the new handle to continue communicating with the contact.

For example, if a GUI client associates text channels with chat windows, it should detach the old channel from the chat window, closing it, and associate a channel to the new handle with the same window.

If the contact's old handle is in any of the member lists of a channel which has the groups interface, it will be removed from the channel and the new handle will be added. The resulting MembersChanged signal must be emitted after the Renamed signal; the reason should be RENAMED.

The handles may be either general-purpose or channel-specific. If the original handle is general-purpose, the new handle must be general-purpose; if the original handle is channel-specific, the new handle must be channel-specific in the same channel.

The desired identifier

Request that the user's own identifier is changed on the server. If successful, a Renamed signal will be emitted for the current "self handle" as returned by GetSelfHandle.

It is protocol-dependent how the identifier that's actually used will be derived from the supplied identifier; some sort of normalization might take place.

An interface on connections to support protocols where the unique identifiers of contacts can change. Because handles are immutable, this is represented by a pair of handles, that representing the old name, and that representing the new one.
telepathy-qt-0.9.6~git1/spec/Channel_Type_Tubes.xml0000664000175000017500000005727212470405660020154 0ustar jrjr Copyright © 2007-2009 Collabora Limited This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. Client implementations SHOULD use StreamTube and DBusTube instead.

A "tube" is a mechanism for arbitrary data transfer. Two types of data transfer are currently specified: D-Bus messages, and streams of bytes. Each tube has a service name, which is a string specifying the kind of communication that takes place over it, and a dictionary of arbitrary parameters. Tube parameters are commonly used for bootstrap information such as usernames and passwords. Each tube is identified by a locally unique identifier.

The Tubes channel type may be requested for handles of type HANDLE_TYPE_CONTACT and HANDLE_TYPE_ROOM.

Stream tubes specify listening addresses using pairs of parameters with signature 'u', 'v', where the integer 'u' is a member of Socket_Address_Type and the v is dependent on the type of address.

An identifier for a tube. These are local to a Tubes channel, and may not be assumed to be the same as the other participants' idea of the tube identifier. A struct (tube ID, initiator handle, tube type, service name, parameters, state) representing a tube, as returned by ListTubes on the Tubes channel type. Represents a participant in a multi-user D-Bus tube, as returned by GetDBusNames and seen in the DBusNamesChanged signal. The handle of a participant in this D-Bus tube. That participant's unique name.

The tube is D-Bus tube as described by the org.freedesktop.Telepathy.Channel.Type.DBusTube interface.

The tube is stream tube as described by the org.freedesktop.Telepathy.Channel.Type.StreamTube interface.

The tube is waiting to be accepted/closed locally. The tube is waiting to be accepted/closed remotely. The tube is open for traffic. The supported socket address and access-control types for tubes. See GetAvailableStreamTubeTypes. List the available address types and access-control types for stream tubes.

A mapping from address types (members of Socket_Address_Type) to arrays of access-control type (members of Socket_Access_Control) that the connection manager supports for stream tubes with that address type. For simplicity, if a CM supports offering a particular type of tube, it is assumed to support accepting it.

A typical value for a host without IPv6 support:

            {
              Socket_Address_Type_IPv4:
                [Socket_Access_Control_Localhost, Socket_Access_Control_Port,
                 Socket_Access_Control_Netmask],
              Socket_Address_Type_Unix:
                [Socket_Access_Control_Localhost, Socket_Access_Control_Credentials]
            }
          

If stream tubes are not supported, this will be an empty dictionary.

An array of the available tube types, as defined by the Tube_Type enum. Return an array of tuples, each representing a tube, with the following members:
  • the tube's ID
  • the tube's initiator
  • the tube's type
  • the tube's service
  • the tube's parameters
  • the tube's state
Offers a D-Bus tube providing the service specified. A string representing the service name that will be used over the tube. It should be a well-known D-Bus service name, of the form com.example.ServiceName. A dictionary of properties for the new tube; the allowable keys, types and values are defined by the service. Connection managers must support the value being any primitive (non-container) D-Bus type, or a byte array 'ay'. The ID of the new tube. The contact associated with this channel doesn't have tubes capabilities. The connection manager doesn't support D-Bus tubes. Offer a stream tube exporting the local socket specified. A string representing the service name that will be used over the tube. It should be a well-known TCP service name as defined by http://www.iana.org/assignments/port-numbers or http://www.dns-sd.org/ServiceTypes.html, for instance "rsync" or "daap".

A dictionary of properties for the new tube; the allowable keys, types and values are defined by the service. Connection managers must support the value being any primitive (non-container) D-Bus type, or a byte array 'ay'.

These should usually be the same key-value pairs specified for use in the DNS-SD TXT record for that service.

The type of the listening address of the local service, as a member of Socket_Address_Type. The listening address of the local service, as indicated by the address_type. The access control the local service applies to the local socket, specified so the connection manager can behave appropriately when it connects. A parameter for the access control type, to be interpreted as specified in the documentation for the Socket_Access_Control enum. The ID of the new tube. The contact associated with this channel doesn't have tube capabilities. The connection manager doesn't support stream tubes, or does not support the given address type or access-control type.
Emitted when a tube is created. The ID of the new tube. The handle of the contact who initiated the tube. The tube type, as defined by the Tube_Type enum. A string representing the service that will be used over the tube. The new tube's properties. The new tube's state. Accept a D-Bus tube that's in the "local pending" state. The connection manager will attempt to open the tube. The tube remains in the "local pending" state until the TubeStateChanged signal is emitted. The ID of the tube to accept. The string describing the address of the private bus. The client should not attempt to connect to the address until the tube is open. The given tube ID is invalid or does not refer to a D-Bus tube. Accept a stream tube that's in the "local pending" state. The connection manager will attempt to open the tube. The tube remains in the "local pending" state until the TubeStateChanged signal is emitted. The ID of the tube to accept. The type of address the connection manager should listen on. The type of access control the connection manager should apply to the socket. A parameter for the access control type, to be interpreted as specified in the documentation for the Socket_Access_Control enum. The address on which the connection manager will listen for connections to this tube. The client should not attempt to connect to the address until the tube is open. The given tube ID is invalid or does not refer to a stream tube. The given address type or access-control mechanism is not supported. Emitted when the state of a tube changes. The ID of the tube that changed state. The new state of the tube; see the Tube_State enumeration. Close a tube. The ID of the tube to close. Emitted when a tube has been closed. The ID of a closed tube is no longer valid. The ID may later be reused for a new tube. The ID of the tube that was closed. For a D-Bus tube, return a string describing the address of the private bus. The ID of the tube to get an address for. The bus address. The tube is not a D-Bus tube. This tube is not in the "open" state. For a multi-user (i.e. Handle_Type_Room) D-Bus tube, obtain a mapping between contact handles and their unique bus names on this tube. The ID of the tube to get names for. An array of structures, each containing a contact handle and a D-Bus bus name. The tube is not a multi-user D-Bus tube. This tube is not in the "open" state. Emitted on a multi-user (i.e. Handle_Type_Room) D-Bus tube when a participant opens or closes the tube. The ID of the tube whose names have changed. Array of handles and D-Bus names of new participants. Array of handles of former participants. For a stream tube, obtain the address of the socket used to communicate over this tube. The ID of the stream tube to get the socket for. The type of the listening address of the socket, as a member of Socket_Address_Type. The listening address of the socket, as indicated by the address_type. The tube is not a stream tube. This tube is not in the "open" state. Emitted on a stream tube when a participant opens a new connection to its socket. The ID of the tube The handle of the participant who opened the new connection
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Contact_Capabilities.xml0000664000175000017500000003465412470405660024643 0ustar jrjr Copyright (C) 2005, 2006, 2008 Collabora Limited Copyright (C) 2005, 2006, 2008 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

Contact capabilities describe the channel classes which may be created with a given contact in advance of attempting to create a channel. Each capability represents a commitment by the connection manager that it will ordinarily be able to create a channel with a contact when given a request with the properties defined by the channel class.

Capabilities pertain to particular contact handles, and represent activities such as having a text chat, a voice call with the user or a stream tube of a defined type.

This interface also enables user interfaces to notify the connection manager what capabilities to advertise for the user to other contacts. This is done by using the UpdateCapabilities method.

XMPP is a major user of this interface: XMPP contacts will not, in general, be callable using VoIP unless they advertise suitable Jingle capabilities.

Many other protocols also have some concept of capability flags, which this interface exposes in a protocol-independent way.

A structure representing the capabilities of a single client. For implementations of the Client interface, the well-known bus name name of the client; for any other process, any other reversed domain name that uniquely identifies it. An array of channel classes that can be handled by this client. This will usually be a copy of the client's HandlerChannelFilter property. An array of client capabilities supported by this client, to be used by the connection manager to determine what capabilities to advertise. This will usually be a copy of the client's Capabilities property.

Alter the connection's advertised capabilities to include the intersection of the given clients' capabilities with what the connection manager is able to implement.

On connections managed by the ChannelDispatcher, processes other than the ChannelDispatcher SHOULD NOT call this method, and the ChannelDispatcher SHOULD use this method to advertise the capabilities of all the registered Client.Handler implementations.On connections not managed by the ChannelDispatcher, clients MAY use this method directly, to indicate the channels they will handle and the extra capabilities they have.

Upon a successful invocation of this method, the connection manager will only emit the ContactCapabilitiesChanged signal for the user's SelfHandle if, in the underlying protocol, the new capabilities are distinct from the previous state.

The connection manager will essentially intersect the provided capabilities and the channel classes it implements. Therefore, certain properties which are never fixed for a channel class (such as the target handle, or the Parameters property of a tube channel) will almost certainly not be advertised.

This method MAY be called on a newly-created connection while it is still in the DISCONNECTED state, to request that when the connection connects, it will do so with the appropriate capabilities. Doing so MUST NOT fail.

The capabilities of one or more clients.

For each client in the given list, any capabilities previously advertised for the same client name are discarded, then replaced by the capabilities indicated.

As a result, if a client becomes unavailable, this method SHOULD be called with a Handler_Capabilities structure containing its name, an empty list of channel classes, and an empty list of capabilities. When this is done, the connection manager SHOULD free all memory associated with that client name.

This method takes a list of clients so that when the channel dispatcher first calls it (with a list of all the Handlers that are initially available), the changes can be made atomically, with only one transmission of updated capabilities to the network. Afterwards, the channel dispatcher will call this method with a single-element list every time a Handler becomes available or unavailable.

The connection manager MUST ignore any channel classes and client capabilities for which there is no representation in the protocol or no support in the connection manager.

An array of contact handles for this connection.

The handle zero MUST NOT be included in the request.

A map from contact handles to lists of requestable channel classes, representing the channel requests that are expected to succeed for that contact.

Contacts listed among Handles whose capabilities are unknown SHOULD be omitted from this map; contacts known to have an empty set of capabilities SHOULD be included in the keys of this map, with an empty array as the corresponding value.

Returns an array of requestable channel classes for the given contact handles, representing the channel requests that are expected to succeed.

The handle does not represent a contact. Zero is always invalid.
All the capabilities of the contacts

Announce that there has been a change of capabilities on the given handles. A single signal can be emitted for several contacts.

The underlying protocol can get several contacts' capabilities at the same time.

A mapping from contact handle to their capabilities. A contact handle.

The contact's capabilities. These should be represented in the same way as in RequestableChannelClasses, except that they may have more fixed properties or fewer allowed properties, to represent contacts who do not have all the capabilities of the connection.

In particular, requestable channel classes for channels with target handle type Contact MUST list TargetHandleType among their fixed properties when they appear here, and clients MAY assume that this will be the case.

This matches the initial implementations - service-side in telepathy-gabble, and client-side in telepathy-qt4 - and means that clients can use exactly the same code to interpret RequestableChannelClasses and contact capabilities.

Channel classes with target handle type Handle_Type_Contact indicate that a request that matches the channel class, and also either has the contact's handle as TargetHandle or the contact's identifier as TargetID, can be expected to succeed. Connection managers SHOULD NOT include the TargetHandle or TargetID as a fixed property in contact capabilities.

This makes one channel class sufficient to describe requests via TargetHandle or TargetID, and is necessary in order to allow clients to interpret RequestableChannelClasses and contact capabilities with the same code.

Channel classes with target handle type Handle_Type_Room or Handle_Type_None indicate that if a channel matching the channel class is created, then inviting the contact to that channel can be expected to succeed.

To support room-based XMPP protocols like Muji and MUC Tubes, it's necessary to be able to discover who can be invited to a given room channel; most XMPP contacts won't support being invited into a Muji conference call, at least in the short to medium term.

No interpretation is defined for channel classes with any other target handle type, or for channel classes that do not fix a target handle type, in this version of the Telepathy specification.

The same structs that would be returned by GetContactCapabilities. Omitted from the result if the contact's capabilities are not known; present in the result as an empty array if the contact is known to have no capabilities at all.

telepathy-qt-0.9.6~git1/spec/all.xml0000664000175000017500000003333612470405660015204 0ustar jrjr Telepathy D-Bus Interface Specification 0.27.3 Copyright © 2005-2012 Collabora Limited Copyright © 2005-2011 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A Connection Manager is a factory for connections.

Connections represent active protocol sessions. There are a number of core interfaces which all connections should implement, and a number of optional interfaces which provide various functionality related to contacts and to the connection itself.

On protocols that support contact lists, these interface expose the user's contact lists, along with presence subscription information, contact list groups (if supported), and the ability to block and unblock contacts (if supported).

These optional Connection interfaces expose metadata about contacts on this connection—from their current presence through to the type of client they're connected with—and allow the local user to publish such metadata back to their contacts.

These optional Connection interfaces expose protocol-specific features, and allow configuring the running connection.

A Channel is used by Telepathy to exchange data between local applications and remote servers. A given connection will have many channels, each one represented by a D-Bus object.

Each Channel has a type, represented by a D-Bus interface, and may implement one or more additional interfaces from the list of channel interfaces below.

Each Channel implements one of the following types:

A Channel may also implement one or more of the following interfaces, depending on its type. Some interfaces are only applicable to particular channel types, while others may (in principle) appear on any type of channel.

These interfaces may only appear on channels of type Text.

These interfaces are only applicable to channels of type StreamedMedia, with the exception of the Hold and DTMF interfaces, which may also appear on Call1 channels.

These interfaces provide functionality for ad-hoc conference calls and chat rooms. They are primarily intended for Text, StreamedMedia and Call1 channels, but may also appear on other types of channel.

A set of objects to be used for authentication purposes, such as TLS certificates or handshakes for negotiating end-to-end security.

These interfaces are used when a Call1 channel doesn't have HardwareStreaming to implement the media streaming aspects of a call.

The Account Manager is a desktop service that provides account configuration and can manage the connection managers. In general, clients will use the account manager to find out about instant messaging accounts and their associated connections.

The Channel Dispatcher is a desktop service whose purpose is to dispatch incoming Telepathy Channels to the appropriate client (e.g. incoming text chat, file transfer, tubes, etc.).

Clients should implement one or more of these interfaces to be able to handle channels coming in from the Channel Dispatcher.

telepathy-qt-0.9.6~git1/spec/errors.xml0000664000175000017500000006042012470405660015742 0ustar jrjr

The D-Bus errors used in Telepathy all start with org.freedesktop.Telepathy.Error.. They are used in D-Bus messages of type ERROR, and also as plain strings annotated with the DBus_Error_Name type.

In principle, any method can raise any error (this is a general fact of IPC). For instance, generic D-Bus errors starting with org.freedesktop.DBus.Error. will occur in some situations.

Telepathy methods can also raise implementation-specific errors to indicate specialized failure conditions. For better interoperability, if a suitable Telepathy error exists, it should be preferred.

The namespace org.freedesktop.Telepathy.Qt4.Error. is reserved for use by the D-Bus client implementation in telepathy-qt4, which uses it to represent certain error situations that did not involve a D-Bus ERROR message. These errors are defined and documented as part of telepathy-qt4's C++ API, and should not be used on D-Bus.

Raised when there is an error reading from or writing to the network. Raised when the requested method, channel, etc is not available on this connection. Raised when one of the provided arguments is invalid. Raised when the requested functionality is temporarily unavailable. The user is not permitted to perform the requested operation. The connection is not currently connected and cannot be used. This error may also be raised when operations are performed on a Connection for which StatusChanged has signalled status Disconnected for reason None. The second usage corresponds to None in the Connection_Status_Reason enum; if a better reason is available, the corresponding error should be used instead. The handle specified is unknown on this channel or connection. You are banned from the channel. The channel is full. The requested channel is invite-only.

The requested channel or other resource already exists, and another user interface in this session is responsible for it.

User interfaces SHOULD handle this error unobtrusively, since it indicates that some other user interface is already processing the channel.

Raised by an ongoing request if it is cancelled by user request before it has completed, or when operations are performed on an object which the user has asked to close (for instance, a Connection where the user has called Disconnect, or a Channel where the user has called Close). The second form can be used to correspond to the Requested member in the Connection_Status_Reason enum, or to to represent the situation where disconnecting a Connection, closing a Channel, etc. has been requested by the user but this request has not yet been acted on, for instance because the service will only act on the request when it has finished processing an event queue. Raised when authentication with a service was unsuccessful. This corresponds to Authentication_Failed in the Connection_Status_Reason enum. Raised if a user request insisted that encryption should be used, but encryption was not actually available. This corresponds to part of Encryption_Error in the Connection_Status_Reason enum. It's been separated into a distinct error here because the two concepts that were part of EncryptionError seem to be things that could reasonably appear differently in the UI. Raised if encryption appears to be available, but could not actually be used (for instance if SSL/TLS negotiation fails). This corresponds to part of Encryption_Error in the Connection_Status_Reason enum. Raised if the server did not provide a SSL/TLS certificate. This error MUST NOT be used to represent the absence of a client certificate provided by the Telepathy connection manager. This corresponds to Cert_Not_Provided in the Connection_Status_Reason enum. That error explicitly applied only to server SSL certificates, so this one is similarly limited; having the CM present a client certificate is a possible future feature, but it should have its own error handling. Raised if the server provided a SSL/TLS certificate signed by an untrusted certifying authority. This error SHOULD NOT be used to represent a self-signed certificate: see the Self Signed error for that. This corresponds to Cert_Untrusted in the Connection_Status_Reason enum and to Untrusted in the TLS_Certificate_Reject_Reason enum, with a clarification to avoid ambiguity. Raised if the server provided an expired SSL/TLS certificate. This corresponds to Cert_Expired in the Connection_Status_Reason enum and to Expired in the TLS_Certificate_Reject_Reason enum. Raised if the server provided an SSL/TLS certificate that will become valid at some point in the future. This corresponds to Cert_Not_Activated in the Connection_Status_Reason enum and to Not_Activated in the TLS_Certificate_Reject_Reason enum. Raised if the server provided an SSL/TLS certificate that did not have the expected fingerprint. This corresponds to Cert_Fingerprint_Mismatch in the Connection_Status_Reason enum and to Fingerprint_Mismatch in the TLS_Certificate_Reject_Reason enum.

Raised if the server provided an SSL/TLS certificate that did not match its hostname.

You MAY be able to get more details about the expected and certified hostnames by looking up the 'expected-hostname' and 'certificate-hostname' keys in the details map that came together with this error.

This corresponds to Cert_Hostname_Mismatch in the Connection_Status_Reason enum and to Hostname_Mismatch in the TLS_Certificate_Reject_Reason enum.
Raised if the server provided an SSL/TLS certificate that is self-signed and untrusted. This corresponds to Cert_Self_Signed in the Connection_Status_Reason enum and to Self_Signed in the TLS_Certificate_Reject_Reason enum. Raised if the server provided an SSL/TLS certificate that has been revoked. This corresponds to Cert_Revoked in the Connection_Status_Reason enum and to Revoked in the TLS_Certificate_Reject_Reason enum. Raised if the server provided an SSL/TLS certificate that uses an insecure cipher algorithm or is cryptographically weak. This corresponds to Cert_Insecure in the Connection_Status_Reason enum and to Insecure in the TLS_Certificate_Reject_Reason enum. Raised if the server provided an SSL/TLS certificate that is unacceptable in some way that does not have a more specific error. This corresponds to Cert_Other_Error in the Connection_Status_Reason enum and to Unknown in the TLS_Certificate_Reject_Reason enum. Raised if the length in bytes of the server certificate, or the depth of the server certificate chain exceeds the limits imposed by the crypto library. This corresponds to Cert_Limit_Exceeded in the Connection_Status_Reason enum and to Limit_Exceeded in the TLS_Certificate_Reject_Reason enum. Raised when requested functionality is unavailable due to contact not having required capabilities. Raised when requested functionality is unavailable because a contact is offline. This corresponds to Offline in the Channel_Group_Change_Reason enum. Used to represent a user being ejected from a channel by another user, for instance being kicked from a chatroom. This corresponds to Kicked in the Channel_Group_Change_Reason enum. Used to represent a user being removed from a channel because of a "busy" indication. This error SHOULD NOT be used to represent a server or other infrastructure being too busy to process a request - for that, see ServerBusy. This corresponds to Busy in the Channel_Group_Change_Reason enum. Used to represent a user being removed from a channel because they did not respond, e.g. to a StreamedMedia call. This corresponds to No_Answer in the Channel_Group_Change_Reason enum. Raised when the requested user does not, in fact, exist. This corresponds to Invalid_Contact in the Channel_Group_Change_Reason enum, but can also be used to represent other things not existing (like chatrooms, perhaps). Raised when a channel is terminated for an unspecified reason. In particular, this error SHOULD be used whenever normal termination of a 1-1 StreamedMedia call by the remote user is represented as a D-Bus error name. This corresponds to None in the Channel_Group_Change_Reason enum. Raised when the local streaming implementation has no codecs in common with the remote side. This corresponds to Media_Error. The media stream type requested is not supported by either the local or remote side. This corresponds to Media_Error. Raised when the call's streaming implementation has some kind of internal error. This corresponds to Internal_Error. Raised when a connection is refused. Raised when a connection can't be established. Raised when a connection is broken. Raised when the user attempts to connect to an account but they are already connected (perhaps from another client or computer), and the protocol or account settings do not allow this. XMPP can have this behaviour if the user chooses the same resource in both clients (it is server-dependent whether the result is AlreadyConnected on the new connection, ConnectionReplaced on the old connection, or two successful connections). Raised by an existing connection to an account if it is replaced by a new connection (perhaps from another client or computer). In MSNP, when connecting twice with the same Passport, the new connection "wins" and the old one is automatically disconnected. XMPP can also have this behaviour if the user chooses the same resource in two clients (it is server-dependent whether the result is AlreadyConnected on the new connection, ConnectionReplaced on the old connection, or two successful connections). Raised during in-band registration if the server indicates that the requested account already exists. Raised if a server or some other piece of infrastructure cannot process the request, e.g. due to resource limitations. Clients MAY try again later. This is not the same error as Busy, which indicates that a user is busy. Raised if a request cannot be satisfied because a process local to the user has insufficient resources. Clients MAY try again later. For instance, the ChannelDispatcher might raise this error for some or all channel requests if it has detected that there is not enough free memory. Raised if a request cannot be satisfied without violating an earlier request for anonymity, and the earlier request specified that raising an error is preferable to disclosing the user's identity (for instance via Connection.Interface.Anonymity.AnonymityMandatory or Channel.Interface.Anonymity.AnonymityMandatory). Raised when the requested functionality is not yet available, but is likely to become available after some time has passed. Raised when an incoming or outgoing Call1 is rejected by the the receiver. Raised when a call was terminated as a result of the local user picking up the call on a different resource. Raised when a server or other piece of infrastructure indicates an internal error, or when a message that makes no sense is received from a server or other piece of infrastructure. For instance, this is appropriate for XMPP's internal-server-error, and is also appropriate if you receive sufficiently inconsistent information from a server that you cannot continue. Raised if a server rejects protocol messages from a connection manager claiming that they do not make sense, two local processes fail to understand each other, or an apparently impossible situation is reached. For instance, this would be an appropriate mapping for XMPP's errors bad-format, invalid-xml, etc., which can't happen unless the local (or remote) XMPP implementation is faulty. This is also analogous to Invalid_CM_Behavior, TP_DBUS_ERROR_INCONSISTENT in telepathy-glib, and TELEPATHY_QT4_ERROR_INCONSISTENT in telepathy-qt4.

Raised as a ConnectionError when a Connection cannot be established because either the Connection Manager or its support library (e.g. wocky, papyon, sofiasip) requires upgrading to support a newer protocol version.

This error corresponds to the Connection_Status_Reason of Network_Error.

Some protocols transmit a protocol or library version number to the server, which will disconnect them if the version isn't appropriate. This way we can report the error to the user, and if appropriate, the user's client can check for updates.
Raised if a client attempts to dial a number that is recognized as an emergency number (e.g. '911' in the USA), but the Connection Manager or provider does not support dialling emergency numbers. Many VOIP providers have the ability to dial traditional (PSTN) telephone numbers, but do not provide the ability to dial emergency numbers (for instance, Google Voice). This error provides additional information about why such a call was unsuccessful.

Raised if the user has insufficient Balance to place a call or send a message.

The key 'balance-required' MAY be included in CallStateDetails or a delivery report's Message_Part (with the same units and scale as AccountBalance) to indicate how much credit is required to make this call or send this message.

Raised if the CaptchaAuthentication1 Handler either has no UI to present captchas, or it does, but wasn't able to answer any of the captchas given.

Copyright © 2005-2010 Collabora Limited Copyright © 2005-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Simple_Presence.xml0000664000175000017500000007252112470405660023647 0ustar jrjr Copyright (C) 2005-2008 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A struct representing the presence of a contact. The presence type, e.g. Connection_Presence_Type_Away. The string identifier of the status, e.g. "brb", as defined in the Statuses property.

The user-defined status message, e.g. "Back soon!".

Clients SHOULD set the status message for the local user to the empty string, unless the user has actually provided a specific message (i.e. one that conveys more information than the Status).

User interfaces SHOULD regard an empty status message as unset, and MAY replace it with a localized string corresponding to the Status or Type.

Use case: Daf sets his status in Empathy by choosing the Welsh translation of "Available" from a menu. It is more informative for his English-speaking colleagues to see the English translation of "Available" (as localized by their own clients) than to see "Ar Gael" (which they don't understand anyway).
Mapping returned by GetPresences and signalled by PresencesChanged, indicating the presence of a number of contacts. A contact The contact's presence A struct containing information about a status. The type of a presence. This SHOULD NOT be used as a way to set statuses that the client does not recognise (as explained in SetPresence), but MAY be used to check that the client's assumptions about a particular status name match the connection manager's. If true, the user can set this status on themselves using SetPresence. If true, a non-empty message can be set for this status. Otherwise, the empty string is the only acceptable message. On IRC you can be Away with a status message, but if you are available you cannot set a status message. A mapping describing possible statuses. The string identifier of this status. Details of this status.

The string identifier of the desired status. Possible status identifiers are defined in the Statuses property.

Clients MUST NOT set a status whose string value they do not recognise, even if its presence type in Statuses matches what the user requested.

Suppose a protocol has statuses that include 'phone' (of type BUSY) and 'in-a-meeting' (of type BUSY), but there is no generic 'busy' status.

If the user requests "Busy" status from a menu, a client author might be tempted to pick an arbitrary status that has type BUSY. However, on this protocol, neither of the choices would be appropriate, and incorrect information about the user would be conveyed.

Statuses whose Connection_Presence_Type is Offline, Error or Unknown MUST NOT be passed to this function. Connection managers SHOULD reject these statuses.

To go offline, call Disconnect instead. The "error" and "unknown" statuses make no sense.

The status message associated with the current status.

Request that the presence status and status message are published for the connection. Changes will be indicated by PresencesChanged signals being emitted.

This method may be called on a newly-created connection while it is still in the DISCONNECTED state, to request that when the connection connects, it will do so with the selected status.

In DISCONNECTED state the Statuses property will indicate which statuses are allowed to be set while DISCONNECTED (none, if the Connection Manager doesn't allow this). This value MUST NOT be cached, as the set of allowed presences might change upon connecting.

Either the specified status is not supported, the specified status cannot be set on the user themselves, or a non-empty message was supplied for a status that does not accept a message.
An array of the contacts whose presence should be obtained.

Presence information in the same format as for the PresencesChanged signal. The returned mapping MUST include an entry for each contact in the method's argument.

The definition of the connection presence types Unknown and Offline means that if a connection manager will return Unknown for contacts not on the subscribe list, it MUST delay the reply to this method call until it has found out which contacts are, in fact, on the subscribe list.

Get presence previously emitted by PresencesChanged for the given contacts. Data is returned in the same structure as the PresencesChanged signal; no additional network requests are made. While discovering the subscribe list in order to distinguish between Unknown and Offline statuses, a network error occurred.

A dictionary where the keys are the presence statuses that are available on this connection, and the values are the corresponding presence types.

While the connection is in the DISCONNECTED state, it contains the set of presence statuses allowed to be set before connecting. The connection manager will attempt to set the appropriate status when the connection becomes connected, but cannot necessarily guarantee it. The available statuses cannot change until the connection status changes, so there is no change notification.

While the connection is in the CONNECTED state, this property contains the set of presence statuses which are actually available on this protocol. This set is constant for the remaining lifetime of the connection, so again, there is no change notification.

While the connection is in the CONNECTING state, the value of this property is undefined and SHOULD NOT be used. It can change at any time without notification (in particular, any cached values from when the connection was in the DISCONNECTED or CONNECTING state MUST NOT be assumed to still be correct when the state has become CONNECTED).

This property MUST include the special statuses "unknown" and "error" if and only if the connection manager can emit them as a contact's status.

For instance, connection managers for local-xmpp (XEP-0174) would omit "unknown" since there is no such concept.

The maximum length in characters for any individual status message, or 0 if there is no limit.

While the connection is in the DISCONNECTED state, this property will be 0. The connection manager will attempt to set the appropriate value when the connection becomes connected, but cannot necessarily guarantee it. The maximum length cannot change until the connection status changes, so there is no change notification.

While the connection is in the CONNECTED state, this property contains the maximum length in characters for any individual status message which is actually allowed on this protocol. This value is constant for the remaining lifetime of the connection, so again, there is no change notification.

While the connection is in the CONNECTING state, the value of this property is undefined and SHOULD NOT be used. It can change at any time without notification (in particular, any cached values from when the connection was in the DISCONNECTED or CONNECTING state MUST NOT be assumed to still be correct when the state has become CONNECTED).

If a message passed to SetPresence is longer than allowed by this property, the connection manager MUST truncate the supplied message; when emitting PresencesChanged, the truncated version of the message MUST be used.

Some XMPP servers, like Google Talk, define a maximum length for status messages. Whether the user's server is one of these cannot be detected until quite late in the connection process.

A dictionary of contact handles mapped to the status, presence type and status message. This signal should be emitted when your own presence has been changed, or the presence of the member of any of the connection's channels has been changed. An invalid presence type used as a null value. This value MUST NOT appear in the Statuses property, or in the result of GetStatuses on the deprecated Presence interface. Offline Available Away Away for an extended time Hidden (invisible) Busy, Do Not Disturb. Unknown, unable to determine presence for this contact, for example if the protocol only allows presence of subscribed contacts. Error, an error occurred while trying to determine presence. The message, if set, is an error from the server.

A type for communication access control. These control policies are used in CommunicationPolicy.DRAFT as well as most rich presence interfaces.

New interfaces should use this type, and NOT Rich_Presence_Access_Control_Type.

Only allow contacts that are in a certain whitelist.

The associated variant in Access_Control is a list of Contact_Handle representing the whitelist, with signature au.

Allow contacts in the user's 'publish' list. The associated variant in Access_Control is ignored.

Only allow contacts that are in a certain group.

The associated variant in Access_Control is a Group_Handle representing the permitted group.

Allow all contacts. The associated variant in Access_Control is ignored. Allow all contacts in the user's 'subscribe' or 'publish' list. The associated variant in Access_Control is ignored. Forbid all contacts. The associated variant in Access_Control is ignored.

The access control rule is too complex to be represented in the current Telepathy API. The associated variant is meaningless. Setting this mode is never valid; the connection manager MUST raise an error if this is attempted.

XEP-0016 Privacy Lists can easily produce access control mechanisms that can't be expressed in a simpler API. We need to be able to at least indicate that fact.

The associated variant in Access_Control is ignored.

A type of access control for Rich_Presence_Access_Control. For most types, the exact access control is given by an associated variant.

These are the access control types from XMPP publish/subscribe (XEP-0060).

Location uses this for historical reasons, new interfaces will use Access_Control_Type.

The associated variant is a list of contacts (signature 'au', Contact_Handle[]) who can see the extended presence information. All contacts in the user's 'publish' contact list can see the extended presence information. The associated variant is ignored. The associated variant is a handle of type Group (signature 'u', Group_Handle) representing a group of contacts who can see the extended presence information. Anyone with access to the service can see the extended presence information.

An access control mode for extended presence items like geolocation. This type isn't actually used by the SimplePresence interface, but it's included here so it can be referenced by rich presence interfaces.

New interfaces should use this type, and NOT Rich_Presence_Access_Control.

The type of access control to apply. Any additional information required by the Type. The required type and semantics are defined for each Access_Control_Type.

An access control mode for extended presence items like geolocation. This type isn't actually used by the SimplePresence interface, but it's included here so it can be referenced by rich presence interfaces such as Location.

Location uses this for historical reasons, new interfaces will use Access_Control_Type.

The type of access control to apply. Any additional information required by the Type. The required type and semantics are defined for each Rich_Presence_Access_Control_Type.

The same struct that would be returned by GetPresences (always present with some value if information from the SimplePresence interface was requested)

This interface is for services which have a concept of presence which can be published for yourself and monitored on your contacts.

Presence on an individual (yourself or one of your contacts) is modelled as a status and a status message. Valid statuses are defined per connection, and a list of those that can be set on youself can be obtained from the Statuses property.

Each status has an arbitrary string identifier which should have an agreed meaning between the connection manager and any client which is expected to make use of it. The following well-known values should be used where possible to allow clients to identify common choices:

Status identifier Connection_Presence_Type Remarks
"available" Available
"chat" Available Actively interested in chatting, as opposed to merely available.
"pstn" Available This contact is actually a phone number, not an IM account. As such, the contact is conceptually always available, but not in the same way that a contact can set their IM status to “available”. It does not make sense to allow the user to set this status on herself; hence, on protocols where this status is supported, its entry in Statuses SHOULD have May_Set_On_Self set to False.
"away" Away
"brb" Away Be Right Back (a more specific form of Away)
"busy" Busy
"dnd" Busy Do Not Disturb (a more specific form of Busy)
"xa" Extended_Away Extended Away
"hidden" Hidden Also known as "Invisible" or "Appear Offline"
"offline" Offline
"unknown" Unknown special, see below
"error" Error special, see below

As well as these well-known status identifiers, every status also has a numerical type value chosen from Connection_Presence_Type which can be used by the client to classify even unknown statuses into different fundamental types.

These numerical types exist so that even if a client does not understand the string identifier being used, and hence cannot present the presence to the user to set on themselves, it may display an approximation of the presence if it is set on a contact.

As well as the normal status identifiers, there are two special ones that may be present: 'unknown' with type Unknown and 'error' with type Error. 'unknown' indicates that it is impossible to determine the presence of a contact at this time, for example because it's not on the 'subscribe' list and the protocol only allows one to determine the presence of contacts you're subscribed to. 'error' indicates that there was a failure in determining the status of a contact.

If the connection has a 'subscribe' contact list, PresencesChanged signals should be emitted to indicate changes of contacts on this list, and should also be emitted for changes in your own presence. Depending on the protocol, the signal may also be emitted for others such as people with whom you are communicating, and any user interface should be updated accordingly.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Call_State.xml0000664000175000017500000001374012470405660022054 0ustar jrjr Copyright (C) 2008 Collabora Limited Copyright (C) 2008 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

An interface for streamed media channels that can indicate call progress or call states. The presence of this interface is no guarantee that call states will actually be signalled (for instance, SIP implementations are not guaranteed to generate status 180 Ringing, so a call can be accepted without the Ringing flag ever having been set; similarly, Jingle implementations are not guaranteed to send <ringing/>).

To notify the other participant in the call that they are on hold, see Hold.

Get the current call states for all contacts involved in this call. The current call states. Participants where the call state flags would be 0 (all unset) may be omitted from this mapping. Emitted when the state of a member of the channel has changed. An integer handle for the contact. The new state for this contact. A map from contacts to call states. A contact involved in this call. State flags for the given contact. A set of flags representing call states. The contact has been alerted about the call but has not responded (e.g. 180 Ringing in SIP). The contact is temporarily unavailable, and the call has been placed in a queue (e.g. 182 Queued in SIP, or call-waiting in telephony). The contact has placed the call on hold, and will not receive media from the local user or any other participants until they unhold the call again. The initiator of the call originally called a contact other than the current recipient of the call, but the call was then forwarded or diverted. Progress has been made in placing the outgoing call, but the destination contact may not have been made aware of the call yet (so the Ringing state is not appropriate). This corresponds to SIP's status code 183 Session Progress, and could be used when the outgoing call has reached a gateway, for instance. This contact has merged this call into a conference. Note that GSM provides a notification when the remote party merges a call into a conference, but not when it is split out again; thus, this flag can only indicate that the call has been part of a conference at some point. If a GSM connection manager receives a notification that a call has been merged into a conference a second time, it SHOULD represent this by clearing and immediately re-setting this flag on the remote contact.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Keepalive.xml0000664000175000017500000000675412470405660022504 0ustar jrjr Copyright © 2010 Collabora Ltd. Copyright © 2010 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft 1)

Most messaging protocols allow the client to send periodic content-less pings to the server when the connection is otherwise idle, to reassure both itself and the server that its connection is still alive. Depending on the nature of the network connection, and the device running the client, the desired interval between such pings may vary.

For instance, on a mobile handset connected via 3G, overly-frequent keepalives can drain the battery through needlessly waking up the radio, and a relatively high interval is appropiate. By contrast, a desktop computer is less likely to be asleep in the first place, and users expect dropped connections to be noticed as soon as possible.

This interface provides a KeepaliveInterval property which controls the frequency of keepalive pings, if any. Connection managers implementing this property should also include it in Protocol.Parameters with the DBus_Property flag, allowing the desired value to be stored in Account.Parameters and passed onto the connection by the account manager.

The time in seconds between pings sent to the server to ensure that the connection is still alive, or 0 to disable such pings.

This property (and parameter) supersedes the older keepalive-interval Connection_Parameter_Name.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Tube.xml0000664000175000017500000003366612470405660020751 0ustar jrjr Copyright © 2008-2009 Collabora Limited Copyright © 2008-2009 Nokia Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A tube is a mechanism for arbitrary data transfer between two or more IM users, used to allow applications on the users' systems to communicate without having to establish network connections themselves. Currently, two types of tube exist: Channel.Type.DBusTube and Channel.Type.StreamTube. This interface contains the properties, signals and methods common to both types of tube; you can only create channels of a specific tube type, not of this type. A tube channel contains exactly one tube; if you need several tubes, you have to create several tube channels.

Tube channels can be requested for Handle_Type Contact (for 1-1 communication) or Room (to communicate with others in the room simultaneously).

As an exception to the usual handling of capabilities, connection managers for protocols with capability discovery (such as XMPP) SHOULD advertise the capability representing each Tube type that they support (Channel.Type.DBusTube and/or Channel.Type.StreamTube) even if no client has indicated via UpdateCapabilities that such a tube is supported. They SHOULD also allow clients to offer tubes with any Service or ServiceName to any contact which supports the corresponding tube capability.

This lowers the barrier to entry for those writing new tube applications, and preserves interoperability with older versions of the Telepathy stack which did not support rich capabilities.

Each tube has a dictionary of arbitrary parameters. Parameters are commonly used to bootstrap legacy protocols where you can't negotiate parameters in-band. The allowable keys, types and values are defined by the service, but connection managers must support the value being a string (D-Bus type 's'), array of bytes (D-Bus type 'ay'), unsigned integer (D-Bus type 'u'), integer (D-Bus type 'i') and boolean (D-Bus type 'b').

When the tube is offered, the parameters are transmitted with the offer and appear as a property of the incoming tube for other participants.

For example, a stream tube for Service "smb" (Server Message Block over TCP/IP) might use the following properties, as defined in DNS SRV (RFC 2782) Service Types:

{ 'u': 'some-username',
  'p': 'top-secret-password',
  'path': '/etc/passwd',
}

When requesting a tube with CreateChannel, this property MUST NOT be included in the request; instead, it is set when StreamTube.Offer or DBusTube.Offer (as appropriate) is called. Its value is undefined until the tube is offered; once set, its value MUST NOT change.

When receiving an incoming tube, this property is immutable and so advertised in the NewChannels signal.

State of the tube in this channel.

When requesting a tube with CreateChannel, this property MUST NOT be included in the request.

The initiator offered the tube. The tube is waiting to be accepted/closed locally. If the client accepts the tube, the tube's state will be Open. The tube is waiting to be accepted/closed remotely. If the recipient accepts the tube, the tube's state will be Open. The initiator offered the tube and the recipient accepted it. The tube is open for traffic. The tube's state stays in this state until it is closed. The tube channel has been requested but the tube is not yet offered. The client should offer the tube to the recipient and the tube's state will be Remote_Pending. The method used to offer the tube depends on the tube type. Emitted when the state of the tube channel changes. Valid state transitions are documented with Tube_Channel_State. The new state of the tube. A Unix socket. The address variant contains a byte-array, signature 'ay', containing the path of the socket. An abstract Unix socket. The address variant contains a byte-array, signature 'ay', containing the path of the socket including the leading null byte. An IPv4 socket. The address variant contains a Socket_Address_IPv4, i.e. a structure with signature (sq) in which the string is an IPv4 dotted-quad address literal (and must not be a DNS name), while the 16-bit unsigned integer is the port number. An IPv6 socket. The address variant contains a Socket_Address_IPv6, i.e. a structure with signature (sq) in which the string is an IPv6 address literal as specified in RFC2373 (and must not be a DNS name), while the 16-bit unsigned integer is the port number.

The IP or Unix socket can be accessed by any local user (e.g. a Unix socket that accepts all local connections, or an IP socket listening on 127.0.0.1 (or ::1) or rejecting connections not from that address). The associated variant must be ignored.

For a D-Bus tube, this means that the "same user" access control typically provided by default in D-Bus implementations SHOULD be disabled. If the socket is only available to local users (e.g. a Unix socket, an IPv4 socket bound to 127.0.0.1, or an IPv6 socket bound to ::1), the ANONYMOUS authentication mechanism MAY be enabled.

May only be used on IP sockets, and only for Stream tubes. The associated variant must contain a struct Socket_Address_IPv4 (or Socket_Address_IPv6) containing the string form of an IP address of the appropriate version, and a port number. The socket can only be accessed if the connecting process has that address and port number; all other connections will be rejected. This has never been implemented. If you want to share a service to your whole LAN, Telepathy is not the way to do it. May only be used on IP sockets. The associated variant must contain a struct Socket_Netmask_IPv4 (or Socket_Netmask_IPv6) with signature (sy), containing the string form of an IP address of the appropriate version, and a prefix length "n". The socket can only be accessed if the first n bits of the connecting address match the first n bits of the given address.

The high-level meaning of this access control type is that only the same user (e.g. same numeric Unix uid) is allowed to interact with the tube. Exactly how this is achieved varies by channel type.

For StreamTube channels, this access control type may only be used on UNIX sockets. The connecting process must send a byte when it first connects, which is not considered to be part of the data stream. If the operating system uses sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass credentials over sockets, the connecting process must do so if possible; if not, it must still send the byte, without any attached credentials. (This mechanism is very similar to the first byte of a D-Bus connection, except that in D-Bus the byte is always zero, whereas in Tubes it can be nonzero.)

For DBusTube channels, this access control type may be used on any type of socket, and there is no extra byte added by Telepathy at the beginning of the stream: all bytes in the stream are part of the D-Bus tube connection. The connecting process should prove its identity via any of the SASL authentication mechanisms usually used for D-Bus (in typical D-Bus implementations this involves either sending and receiving credentials as above, or demonstrating the ability to write to a file in the user's home directory).

In either case, the listening process will disconnect the connection unless it can determine by OS-specific means that the connecting process has the same user ID as the listening process.

In either tube type, the associated variant must be ignored.

telepathy-qt-0.9.6~git1/spec/Protocol_Interface_Addressing.xml0000664000175000017500000003551112470405660022355 0ustar jrjr Copyright © 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API). From the draft, NormalizeURI was renamed to NormalizeContactURI, clarifying that it removes any actions from the URI.

An interface for protocols that support multiple forms of addressing contacts, for example through vCard addresses and URIs.

If the ConnectionManager has a .manager file, and it supports this interface, the interface's immutable properties must be represented in the file; the representation is described as part of the documentation for each property.

For instance, a SIP connection manager might have the following lines in the .manager file.

[Protocol sip]
AddressableVCardFields=tel;x-sip;
AddressableURISchemes=tel;sip;

The vCard fields that can be used to request a contact with normalized to lower case. If the URL vCard field is addressable, a colon, followed by the supported URI schemes will be concatenated.

For example: ["tel", "x-sip"].

The url vCard field MUST NOT appear here; see AddressableURISchemes instead.

In practice, protocols have a limited set of URI schemes that make sense to resolve as a contact.

Connection managers with a .manager file MUST cache this property in the protocol's section of the .manager file if it is non-empty, using the key AddressableVCardFields. The corresponding value is a list of strings, each followed with a semicolon and in the syntax of the "localestring" type from the Desktop Entry Specification.

Well-known vCard fields:

tel
The TEL vCard field. Used for phone numbers.
x-sip
The X-SIP vCard field. Used for SIP addresses.
x-aim
The X-AIM vCard field. Used for AIM user IDs.
x-icq
The X-ICQ vCard field. Used for ICQ UINs.
x-skype
The X-SKYPE vCard field. Used for Skype user names or telephone numbers. There is also a X-SKYPE-USERNAME field, but for Telepathy purposes, x-skype is preferred
x-groupwise
The X-GROUPWISE vCard field. Used for Groupwise contacts.
x-gadugadu
The X-GADUGADU vCard field. Used for Gadu-Gadu contacts.
x-jabber
The X-JABBER vCard field. Used for XMPP JIDs.
x-msn
The X-MSN vCard field. Used for MSN contacts.
x-yahoo
The X-YAHOO vCard field. Used for Yahoo! IDs.
x-facebook-id
Used for Facebook IDs in XMPP. If the user JID is "-12345@chat.facebook.com" then the x-facebook-id is "12345"

The URI schemes that are supported by this protocol.

For example: ["tel", "sip"].

This property should only be used when the connection is offline. When it is connected the addressable URI schemes should be retrieved from the Requests.RequestableChannelClasses's TargetURIScheme fixed-property instead.

Connection managers with a .manager file MUST cache this property in the protocol's section of the .manager file if it is non-empty, using the key AddressableURISchemes. The corresponding value is a list of strings, each followed with a semicolon and in the syntax of the "localestring" type from the Desktop Entry Specification.

Well-known URI schemes:

sip
SIP protocol. For example: sip:julien@example.com.
sips
Secure (encrypted) SIP protocol. For example: sips:julien@example.com.
tel
Used for telephone numbers. For example: tel:+12065551234.
xmpp
XMPP protocol. For example: xmpp:julien@example.com.
msnim
For the purposes of Protocol.Interface.Addressing, Connection.Interface.Addressing1, and Channel.Interface.Addressing1, the verb part is ignored, and SHOULD be add; the contact field in the query string is used to identify the contact. For example: msnim:add?contact=julien.
aim
For the purposes of Protocol.Interface.Addressing, Connection.Interface.Addressing1, and Channel.Interface.Addressing1, the verb part is ignored, and SHOULD be addbuddy; the screenname field in the query string is used to identify the contact. For example: aim:addbuddy?screenname=julien.
skype
Skype protocol. For example: skype:julien.
ymsgr
For the purposes of Protocol.Interface.Addressing, Connection.Interface.Addressing1, and Channel.Interface.Addressing1, the verb part is ignored, and SHOULD be addfriend; the query string is used to identify the contact. For example: ymsgr:addfriend?julien.
gg
Gadu-Gadu protocol. For example: gg:julien.

Attempt to normalize the given vCard address. Where possible, this SHOULD return an address that would appear in the org.freedesktop.Telepathy.Connection.Interface.Addressing1/addresses attribute for a contact on a connected Connection.

If full normalization requires network activity or is otherwise impossible to do without a Connection, this method SHOULD perform a best-effort normalization.

An example would be a vCard TEL field with a formatted number in the form of +1 (206) 555 1234, this would be normalized to +12065551234.

This method MAY simply raise NotImplemented on some protocols, if it has no use.

The vCard field of the address we are normalizing. The field name SHOULD be in lower case, and MUST appear in AddressableVCardFields. The address to normalize, which is assumed to belong to a contact (and not, for instance, a chatroom or server). The vCard address, normalized as much as possible. The vCard field is not supported (it is not in AddressableVCardFields). The address is syntactically incorrect.
(renamed from NormalizeURI)

Attempt to normalize the given contact URI. Where possible, this SHOULD return an address that would appear in the org.freedesktop.Telepathy.Connection.Interface.Addressing1/uris attribute for a contact on a connected Connection.

If full normalization requires network activity or is otherwise impossible to do without a Connection, this method SHOULD perform a best-effort normalization.

If the URI has extra information beyond what's necessary to identify a particular contact, such as an XMPP resource or an action to carry out, this extra information SHOULD be removed. If all URIs in a scheme contain a verb or action (like aim, ymsgr and msnim URIs), then the verb SHOULD be replaced with the one specified in AddressableURISchemes.

This method is intended to normalize URIs stored in address books, for instance. In protocols like XMPP, if you vary the resource or action (query string), the URI still refers to the same high-level contact.

For instance, xmpp:romeo@Example.Com/Empathy?message;body=Hello would be normalized to xmpp:romeo@example.com, and aim:goim?screenname=Romeo%20M&message=Hello would be normalized to aim:addbuddy?screenname=romeom.

This method MAY simply raise NotImplemented on some protocols, if it has no use.

The URI to normalize, which is assumed to refer to a contact (as opposed to, for instance, a chatroom or a server).

In some protocols, like XMPP, there is no way to tell whether a given URI refers to a contact or a chatroom by looking at its syntax.

The URI's scheme (i.e. the part before the first colon) MUST appear in AddressableURISchemes.

A URI, normalized as much as possible. The URI scheme is not supported (it is not in AddressableURISchemes).

The URI is syntactically incorrect or cannot be interpreted as a reference to a contact.

For instance, aim:!? is not a valid AIM URI, while aim:goaway?message=Absent is a valid AIM URI, but not a contact.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Service_Point.xml0000664000175000017500000001300112470405660023327 0ustar jrjr Copyright © 2005-2010 Nokia Corporation Copyright © 2005-2010 Collabora Ltd

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface for connections whose channels may be able to indicate specific they are connected to some form of service station. For example, when dialing 9-1-1 in the US, a GSM modem/network will recognize that as an emergency call, and inform higher levels of the stack that the call is being handled by an emergency service. In this example, the call is handled by a Public Safety Answering Point (PSAP) which is labeled as "urn:service:sos". Other networks and protocols may handle this differently while still using this interface.

The service point. A list of IDs that are mapped to this service. This is provided as a convenience for the UIs, but the preferred method for requesting channel to a service is by setting the InitialServicePoint property in a channel request.

Description of a service point and IDs which are mapped to it.

An example Service Point info for GSM emergency calls (callable through "911" and "112") could look like:

  ServicePointInfo = (
    Service_Point: (
      Service_Point_Type: 1 (Emergency),
      Service_Point: "urn:service:sos"
    ),
    Service_IDs: [ "911", "112" ]
  )
The list of all (known) service points.

The new value of KnownServicePoints.

Emitted when the list of known service points (or their IDs) has changed.
A service point. The service type. String representation of the service point. The representation is service specific; it may be a 'service' Uniform Resource Name as specified by RFC 5031, or may be in some other form. Empty, unused or unknown value is represented by "". The various types of service points a channel might connect to. The channel is not communicating with a service point, or it is not known whether it is communicating with a service point (e.g. an ordinary call). The service point is a generic emergency point. The service point is some kind of counseling service (ie, mental health or child-services counseling).
telepathy-qt-0.9.6~git1/spec/Channel_Request.xml0000664000175000017500000003671412470405660017517 0ustar jrjr Copyright © 2008–2011 Collabora Ltd. Copyright © 2008–2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as a stable interface)

A channel request is an object in the ChannelDispatcher representing an ongoing request for some channels to be created or found. They are created by methods such as CreateChannel. There can be any number of ChannelRequest objects at the same time.

Its well-known bus name is the same as that of the ChannelDispatcher, "org.freedesktop.Telepathy.ChannelDispatcher".

See ChannelDispatcher.CreateChannel for rationale for ChannelRequest being a separate object.

A channel request can be cancelled by any client (not just the one that requested it). This means that the ChannelDispatcher will Close the resulting channel, or refrain from requesting it at all, rather than dispatching it to a handler.

The Account on which this request was made. This property cannot change.

The time at which user action occurred, or 0 if this channel request is for some reason not involving user action.

This property is set when the channel request is created, and can never change.

Either the well-known bus name (starting with org.freedesktop.Telepathy.Client.) of the preferred handler for this channel, or an empty string to indicate that any handler would be acceptable.

This property is set when the channel request is created, and can never change.

An array of dictionaries containing desirable properties for the channel or channels to be created.

This is an array so that we could add a CreateChannels method in future without redefining the API of ChannelRequest.

This property is set when the channel request is created, and can never change.

A list of the extra interfaces provided by this channel request. This property cannot change.

Proceed with the channel request.

The client that created this object calls this method when it has connected signal handlers for Succeeded and Failed.

Clients other than the client which created the ChannelRequest MUST NOT call this method.

This method SHOULD return immediately; on success, the request might still fail, but this will be indicated asynchronously by the Failed signal.

Proceed cannot fail, unless clients have got the life-cycle of a ChannelRequest seriously wrong (e.g. a client calls this method twice, or a client that did not create the ChannelRequest calls this method). If it fails, clients SHOULD assume that the whole ChannelRequest has become useless.

This method has already been called, so it is no longer available. Stop calling it.

Cancel the channel request. The precise effect depends on the current progress of the request.

If the connection manager has not already been asked to create a channel, then Failed is emitted immediately, and the channel request is removed.

If the connection manager has already been asked to create a channel but has not produced one yet (e.g. if Connection.Interface.Requests.CreateChannel has been called, but has not yet returned), then the ChannelDispatcher will remember that the request has been cancelled. When the channel appears, it will be closed (if it was newly created and can be closed), and will not be dispatched to a handler.

If the connection manager has already returned a channel, but the channel has not yet been dispatched to a handler then the channel dispatcher will not dispatch that channel to a handler. If the channel was newly created for this request, the channel dispatcher will close it with Close; otherwise, the channel dispatcher will ignore it. In either case, Failed will be emitted when processing has been completed.

If Failed is emitted in response to this method, the error SHOULD be org.freedesktop.Telepathy.Error.Cancelled.

If the channel has already been dispatched to a handler, then it's too late to call this method, and the channel request will no longer exist.

The channel request has failed. It is no longer present, and further methods must not be called on it.

The name of a D-Bus error. This can come from various sources, including the error raised by CreateChannel, or an error generated to represent failure to establish the Connection.

If the first argument of the D-Bus error message was a string, that string. Otherwise, an empty string.

The channel request has succeeded. It is no longer present, and further methods must not be called on it.

A dictionary of metadata provided by the channel requester, which the handler and other clients MAY choose to interpret. Clients MAY choose to use platform-specific keys for their own purposes, but MUST ignore unknown keys and MUST cope with expected keys being missing. Clients SHOULD namespace hint names by having them start with a reversed domain name, in the same way as D-Bus interface names.

This property might be used to pass a contact ID for a telephone number shared between two contacts from the address book to the call UI, so that if you try to call “Mum”, the call UI knows this rather than having to guess or show “Calling Mum or Dad”. The format of these contact IDs would be platform-specific, so we leave the definition of the dictionary entry up to the platform in question. But third-party channel requesters might not include the contact ID, so the call UI has to be able to deal with it not being there.

The channel dispatcher does not currently interpret any of these hints: they are solely for communication between cooperating clients. If hints that do affect the channel dispatcher are added in future, their names will start with an appropriate reversed domain name (e.g. org.freedesktop.Telepathy for hints defined by this specification, or an appropriate vendor name for third-party plugins).

This property may be set when the channel request is created, and can never change. Since it is immutable, it SHOULD be included in the dictionary of properties passed to AddRequest by the ChannelDispatcher.

The following standardised hints are defined:

org.freedesktop.Telepathy.ChannelRequest.DelegateToPreferredHandler - b
If present and True the client currently handling the channel SHOULD pass the channel to the PreferredHandler using DelegateChannels. This hint allows the user to request a channel in their preferred client in a situation where there are two chat handlers (for example: requesting a channel in Empathy which is currently being handled by gnome-shell). If the channel is currently unhandled, clients SHOULD ignore this hint. It is assumed that Mission Control will correctly delegate an unhandled channel to the preferred Handler. This allows requesting clients to always include this hint in their channel request. The Handler should check each ChannelRequest of the Requests_Satisfied parameter of HandleChannels for the hint. The first request containing the hint SHOULD be used and all further hints SHOULD be ignored. This covers the very unlikely case where HandleChannels satisfies two separate requests which have different PreferredHandlers.

Variant of the Succeeded signal allowing to get the channel which has been created.

This signal MUST be emitted if the ChannelDispatcher's SupportsRequestHints property is true. If supported, it MUST be emitted before the Succeeded signal.

The Connection owning the channel.

A subset of the Connection's properties, currently unused. This parameter may be used in future.

The channel which has been created.

The same immutable properties of the Channel that would appear in a NewChannels signal.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Capabilities.xml0000664000175000017500000003066512470405660023166 0ustar jrjr Copyright (C) 2005, 2006 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

An interface for connections where it is possible to know what channel types may be requested before the request is made to the connection object. Each capability represents a commitment by the connection manager that it will ordinarily be able to create a channel when given a request with the given type and handle.

Capabilities pertain to particular contact handles, and represent activities such as having a text chat or a voice call with the user. The activities are represented by the D-Bus interface name of the channel type for that activity.

The generic capability flags are defined by Connection_Capability_Flags.

In addition, channel types may have type specific capability flags of their own, which are described in the documentation for each channel type.

This interface also provides for user interfaces notifying the connection manager of what capabilities to advertise for the user. This is done by using the AdvertiseCapabilities method, and deals with the interface names of channel types and the type specific flags pertaining to them which are implemented by available client processes.

Previously, this interface also expressed capabilities of the connection itself, indicating what sorts of channels could be requested (for instance, the ability to open chatroom lists or chatrooms). However, this was never very well-defined or consistent, and as far as we know it was never implemented correctly. This usage is now deprecated. Client implementations SHOULD use ContactCapabilities instead. Connection managers implementing Capabilities MUST implement ContactCapabilities too. The given channel type and handle can be given to RequestChannel to create a new channel of this type. The given contact can be invited to an existing channel of this type. A pair (channel type, type-specific flags) as passed to AdvertiseCapabilities on the Capabilities interface. A struct (contact handle, channel type, generic flags, type-specific flags) representing a capability posessed by a contact, as returned by GetCapabilities on the Capabilities interface. A struct (contact handle, channel type, old generic flags, new generic flags, old type-specific flags, new type-specific flags) representing a change to one of a contact's capabilities, as seen in the CapabilitiesChanged signal on the Capabilities interface. An array of structures containing:
  • a string channel type
  • a bitwise OR of type specific capability flags
An array of D-Bus interface names of channel types to remove An array of structures describing the current capabilities containing:
  • a string channel type
  • a bitwise OR of type specific capability flags

Used by user interfaces to indicate which channel types they are able to handle on this connection. Because these may be provided by different client processes, this method accepts channel types to add and remove from the set already advertised on this connection. The type of advertised capabilities (create versus invite) is protocol-dependent and hence cannot be set by the this method. In the case of a client adding an already advertised channel type but with new channel type specific flags, the connection manager should simply add the new flags to the set of advertised capabilities.

Upon a successful invocation of this method, the CapabilitiesChanged signal will be emitted for the user's own handle ( Connection.GetSelfHandle) by the connection manager to indicate the changes that have been made. This signal should also be monitored to ensure that the set is kept accurate - for example, a client may remove capabilities or type specific capability flags when it exits which are still provided by another client.

On connections managed by the ChannelDispatcher, this method SHOULD NOT be used by clients other than the ChannelDispatcher itself.

An array of structures containing:
  • an integer handle representing the contact
  • a string channel type
  • a bitwise OR of the contact's old generic capability flags
  • a bitwise OR of the contact's new generic capability flags
  • a bitwise OR of the contact's old type specific capability flags
  • a bitwise OR of the contact's new type specific capability flags

Announce that there has been a change of capabilities on the given handle.

If the handle is zero, the capabilities refer to the connection itself, in some poorly defined way. This usage is deprecated and clients should ignore it.

An array of contact handles for this connection.

This may include zero, which originally meant a query for capabilities available on the connection itself. This usage is deprecated; clients SHOULD NOT do this, and connection managers SHOULD proceed as though zero had not been present in this list.

An array of structures containing:
  • an integer handle representing the contact
  • a string channel type
  • a bitwise OR of generic capability flags for the type
  • a bitwise OR of type specific capability flags for the type
Returns an array of capabilities for the given contact handles. The handle does not represent a contact and is not zero

The same structs that would be returned by GetCapabilities (all of them will redundantly have the contact's handle as the first member). Omitted from the result if the contact's capabilities are not known; present in the result as an empty array if the contact is known to have no capabilities at all.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Anonymity.xml0000664000175000017500000000606012470405660022025 0ustar jrjr Copyright © 2008-2010 Nokia Corporation Copyright © 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

Interface for requesting the anonymity modes of a channel (as defined in Connection.Interface.Anonymity).

The list of initially requested anonymity modes on the channel. This MUST NOT change, and is Requestable. Whether or not the anonymity settings are required for this channel. This MUST NOT change, and is Requestable.

This is the ID that the remote user of the channel MAY see (assuming there's a single ID). For example, for SIP connections where the From address has been scrambled by the CM, the scrambled address would be available here for the client to see. This is completely optional, and MAY be an empty string ("") in cases where anonymity modes are not set, or the CM doesn't know what the remote contact will see, or any other case where this doesn't make sense.

This MAY change over the lifetime of the channel, and SHOULD NOT be used with the Request interface.

telepathy-qt-0.9.6~git1/spec/Channel_Bundle.xml0000664000175000017500000000422712470405660017272 0ustar jrjr Copyright (C) 2008 Collabora Ltd. Copyright (C) 2008 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A group of related channels, which should all be dispatched to the same handler if possible.

Bundles currently have no functionality of their own, so clients SHOULD NOT examine this interface, but should instead treat the bundle object-path as an opaque identifier. If more functionality is added to bundles in future, this interface will be used for capability discovery.

The lifetime of a bundle is defined by its component channels - as long as one or more channels whose Bundle property is B exist, the bundle B will also exist.

A list of the extra interfaces provided by this channel bundle.
telepathy-qt-0.9.6~git1/spec/Protocol_Interface_Avatars.xml0000664000175000017500000001435212470405660021673 0ustar jrjr Copyright © 2009-2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface for protocols where it might be possible to set the user's avatar, and the expected size limits and supported MIME types are known before connecting.

If the avatar requirements cannot be discovered while offline, it's impossible to avoid setting the Account's Avatar property to an unsupported avatar.

Each property on this interface SHOULD be cached in the .manager file, using a key of the same name as the property in the [Protocol proto] group. All properties are encoded in ASCII decimal in the obvious way, except for SupportedAvatarMIMETypes which is encoded as a sequence of strings each followed by a semicolon (as for the "localestrings" type in the Desktop Entry Specification).

For instance, an XMPP connection manager might have this .manager file:

[Protocol jabber]
Interfaces=org.freedesktop.Telepathy.Protocol.Interface.Avatars;
param-account=s required
param-password=s required
SupportedAvatarMIMETypes=image/png;image/jpeg;image/gif;
MinimumAvatarHeight=32
RecommendedAvatarHeight=64
MaximumAvatarHeight=96
MinimumAvatarWidth=32
RecommendedAvatarWidth=64
MaximumAvatarWidth=96
MaximumAvatarBytes=8192
The expected value of the Connection.Interface.Avatars.SupportedAvatarMIMETypes property on connections to this protocol. The expected value of the Connection.Interface.Avatars.MinimumAvatarHeight property on connections to this protocol. The expected value of the Connection.Interface.Avatars.MinimumAvatarWidth property on connections to this protocol. The expected value of the Connection.Interface.Avatars.RecommendedAvatarHeight property on connections to this protocol. The expected value of the Connection.Interface.Avatars.RecommendedAvatarWidth property on connections to this protocol. The expected value of the Connection.Interface.Avatars.MaximumAvatarHeight property on connections to this protocol. The expected value of the Connection.Interface.Avatars.MaximumAvatarWidth property on connections to this protocol. The expected value of the Connection.Interface.Avatars.MaximumAvatarBytes property on connections to this protocol.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Forwarding.xml0000664000175000017500000004000312470405660022662 0ustar jrjr Copyright © 2005-2010 Nokia Corporation Copyright © 2005-2010 Collabora Ltd. Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft version, not API-stable)

This connection interface is for protocols that are capable of signaling to remote contacts that incoming communication channels should be instead sent to a separate contact. This might apply to things such as call forwarding, for example.

In some cases, a CM may register forwarding rules with an external service; in those cases, it will never see the incoming channel, and the forwarding will happen automatically.

In other cases, the CM will handle the forwarding itself. When an incoming channel is detected, the status of the local user will determine whether or not a forwarding rule is matched. For some rules, this MAY happen immediately (ie, if the user is Busy); for others, there MAY be a timeout (in seconds) that must expire before the forwarding rule is matched (the timeout is specified by the first element in the Forwarding_Rule_Entry list).

Once a forwarding rule is matched and any necessary timeouts have expired, the CM can forward the incoming channel to the specified handle. If for whatever reason the remote handle does not accept the channel AND the CM supports multiple forwarding entries AND any necessary timeouts have expired (specified by the next entry in the list), the CM can forward the incoming channel to the next handle in the entry list. This continues until the list is exhausted, or the incoming channel is accepted.

Note that the rule matches are only for the first entry in the in the forwarding rule list. Once the incoming channel has been forwarded, the next entry in the list (assuming one exists and the contact that the channel has been forwarded to does not respond after any necessary timeouts) is used regardless of the status of the forwarded channel. The initial match rule might have been Busy, whereas the contact that the channel has been forwarded to might be offline. Even in this case, the Busy list is still traversed until the channel is handled (or there are no more forwarding entries in the list).

For example, assuming the following dict for Forwarding_Rules:

        ForwardingRules = {
          Busy: ( initial-timeout: 30, [
            (handle: 3, timeout: 15),
            (handle: 5, timeout: 20)
          ]),
          NoReply: ( initial-timeout: 15, [
            (handle: 5, timeout: 30),
            (handle: 3, timeout: 20)
          ])
        }

We can imagine a scenario where an incoming channel is detected, the media stream is available (ie, not Busy), and the local user is online. While the CM is waiting for the local user to accept the channel, it looks at NoReply's first timeout value. After 15s if the local user hasn't accepted, the CM forwards the channel to Handle #5. The CM then waits 30s for Handle #5 to accept the channel. If after 30s it does not, the CM forwards the incoming channel to Handle #3, which will have 20s to accept the channel.

When an unanswered StreamedMedia call is forwarded, both the contact and the self handle should be removed from the group with the self handle as the actor, and Channel_Group_Change_Reason No_Answer or Busy, as appropriate. For Call1 channels, the Call_State_Change_Reason Forwarded should be used.

The various forwarding conditions that are supported by this interface. In general, the conditions should not overlap; it should be very clear which rule would be chosen given a CM's behavior with an incoming channel. The exception to this is Unconditional, which will override all other rules. Incoming channels should always be forwarded. Note that setting this will override any other rules. If not set, other rules will be checked when an incoming communication channel is detected.

The incoming channel should be forwarded if a busy signal is detected. What defines "Busy" is CM-specific (perhaps a single resource is already in use, or a user's status is set to Busy Connection_Presence_Type).

If initial timeout is specified for Busy condition and call waiting is not supported by the service, the timeout will be ignored.

The incoming channel should be forwarded if the local user doesn't accept it within the specified amount of time. The incoming channel should be forwarded if the user is offline. This could be a manual setting (the user has chosen to set their presence to offline or invisible) or something specified by the underlying network (the user is not within range of a cell tower).

A forwarding rule entry. These MAY be chained together for CMs that support chaining of forwards (in other words, a forwarding rule may have multiple entries; if the contact in the first entry doesn't respond, the incoming channel might be forwarded to the contact in the second entry).

For CMs and protocols that don't support chaining of entries, only the first entry would be used.

The length of time (in seconds) to wait the contact to respond to the forwarded channel. This MAY be ignored by the CM if it isn't supported by the underlying network/protocol for the specific status of the remote contact (for example, a GSM call that is forwarded may return Not_Reachable immediately without waiting for the timeout value to expire).

A value of 0 means the condition can match immediately. A value of MAX_UINT32 means that the CM's default should be used.

The contact to forward an incoming channel to. If the handle doesn't point to anything (e.g. points to a phone number that doesn't exist), the entry SHOULD be skipped.
A chain of forwarding rules and an initial timeout after which the rules are applied. Initial timeout for the rule. The forwarding targets (an array of type Forwarding_Rule_Entry). A dictionary whose keys are forwarding conditions and whose values are Forwarding_Rule_Chain structs. A dictionary whose keys are forwarding conditions and whose values are maximum number of Forwarding_Rule_Entry for the condition.

A map of forwarding conditions supported on this connection to maximum number of Forwarding_Rule_Entry supported for the specific condition.

When forwarding is done by the provider, different providers might support different chain sizes, or provider and local implementation chain sizes might differ.

The current forwarding rules that are enabled for this connection. Forwarding rules each contain an array of type Forwarding_Rule_Entry.

Emitted when the ForwardingRules property changes.

By the time this is emitted, the property MUST have been updated with the new rules being active. If any protocol/network requests must be made, they should be completed before the signal is emitted.

The condition of the forwarding rule that's been changed. The new initial timeout for the rule. The new (and as of the emission of the signal, currently active) forwards. The order is relevant; those at the lowest array index are used first.
Update the forwarding rules.

The forwarding rule to override. Note that this SHOULD not affect other rules; setting a rule that overrides others (such as Forwarding_Rule_Unconditional) will not modify other rules. This means that when a client sets Forwarding_Rule_Busy and then temporarily sets Forwarding_Rule_Unconditional, the Forwarding_Rule_Busy rule will retain settings after Forwarding_Rule_Unconditional, has been unset.

If the CM has no choice but to adjust multiple rules after a call to this function (ie, due to the network or protocol forcing such behavior), the CM MUST emit multiple ForwardingRuleChanged signals for each changed rule. The order of the signals is implementation-dependent, with the only requirement that the last signal is for the rule that was originally requested to have been changed (e.g. if Unconditional automatically modifies Busy and NoReply, three separate ForwardingRuleChanged signals should be raised with the last signal being for Forwarding_Rule_Unconditional).

Each forwarding condition will occur no more than once in the rule array. Setting a rule will overwrite the old rule with the same Forwarding_Condition in its entirety.

The forwarding targets (an array of type Forwarding_Rule_Entry) to activate for the rule. An empty array will effectively disable the rule. The old forwarding targets (an array of type Forwarding_Rule_Entry). This is the list of entries that is being replaced with the call to SetForwardingRule. The specified Condition is not supported by this connection, or the number of chained SupportedForwardingConditions should be checked prior to calling SetForwardingRule. A Handle that has been supplied is invalid.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Contact_Groups.xml0000664000175000017500000006155312470405660023527 0ustar jrjr Copyright © 2009-2010 Collabora Ltd. Copyright © 2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface for connections in which contacts can be placed in user-defined groups.

The most basic functionality of this interface is to list and monitor a contact's set of groups. To do this, use the GroupsChanged signal, and the groups contact attribute (this should usually be done by connecting to the GroupsChanged signal, then calling GetContactListAttributes with this interface included in the Interfaces argument). Simple user interfaces can limit themselves to displaying that information, and ignore the rest of this interface: to ensure that this works, GroupsChanged is emitted for every change, even if that change could be inferred from another signal such as GroupsRemoved.

Looking at contacts' lists of groups is sufficient to present a user interface resembling XMPP's data model, in which groups behave like tags applied to contacts, and so an empty group cannot exist or is not interesting. However, some protocols model groups as objects in their own right. User interfaces may either track the set of groups via the Groups property and the GroupsCreated and GroupsRemoved signals, or ignore this extra information.

Similarly, in some protocols it is possible to rename a group as a single atomic operation. Simpler user interfaces will see the new name being created, the old name being removed, and the members moving to the new name, via the signals described above. More advanced user interfaces can optionally distinguish between an atomic rename and a create/remove pair, and display renamed groups differently, by monitoring the GroupRenamed signal.

This interface also provides various methods to manipulate user-defined groups, which can be expected to work if GroupStorage is not None.

Depending on the protocol, some methods might be implemented by more than one protocol operation; for instance, in a "contact-centric" protocol like XMPP, SetContactGroups is a single protocol operation and SetGroupMembers requires a protocol operation per contact, whereas in a more "group-centric" protocol it might be the other way around. User interfaces SHOULD call whichever method most closely resembles the way in which the user's action was represented in the UI, and let the connection manager deal with the details.

True if each contact can be in at most one group; false if each contact can be in many groups.

This property cannot change after the connection has moved to the Connected state. Until then, its value is undefined, and it may change at any time, without notification.

Indicates the extent to which contacts' groups can be set and stored.

This property cannot change after the connection has moved to the Connected state. Until then, its value is undefined, and it may change at any time, without notification.

The names of groups of which a contact is a member.

Change notification is via GroupsChanged; clients can also get extra context for group membership changes by receiving GroupRenamed and GroupsRemoved.

Emitted when contacts' groups change. The relevant contacts. The names of groups to which the contacts were added. The names of groups from which the contacts were removed.

The names of all groups that currently exist. This may be a larger set than the union of all contacts' groups contact attributes, if the connection allows groups to be empty.

Change notification is via GroupsCreated and GroupsRemoved; clients can also distinguish between a create/remove pair and a renamed group by receiving GroupRenamed.

This property's value is not meaningful until the ContactListState has become Success.

Emitted when new, empty groups are created. This will often be followed by GroupsChanged signals that add some members. The names of the new groups.

Emitted when a group is renamed, in protocols where this can be distinguished from group creation, removal and membership changes.

Immediately after this signal is emitted, GroupsCreated MUST signal the creation of a group with the new name, and GroupsRemoved MUST signal the removal of a group with the old name.

Emitting these extra signals, in this order, means that clients that are interested in the set of groups that exist (but treat a rename and a create/remove pair identically) can ignore the GroupRenamed signal entirely.

If the group was not empty, immediately after those signals are emitted, GroupsChanged MUST signal that the members of that group were removed from the old name and added to the new name.

On connection managers where groups behave like tags, renaming a group MAY be signalled as a set of GroupsCreated, GroupsRemoved and GroupsChanged signals, instead of emitting this signal.

On protocols like XMPP, another resource "renaming a group" is indistinguishable from changing contacts' groups individually.

The old name of the group. The new name of the group.

Emitted when one or more groups are removed. If they had members at the time that they were removed, then immediately after this signal is emitted, GroupsChanged MUST signal that their members were removed.

Emitting the signals in this order allows for two modes of operation. A client interested only in a contact's set of groups can ignore GroupsRemoved and rely on the GroupsChanged signal that will follow; a more elaborate client wishing to distinguish between all of a group's members being removed, and the group itself being removed, can additionally watch for GroupsRemoved and use it to disambiguate.

The names of the groups.

Add the given contact to the given groups (creating new groups if necessary), and remove them from all other groups.

This is the easiest and most correct way to implement user interfaces that display a single contact with a list of groups, resulting in a user expectation that when they apply the changes, the contact's set of groups will become exactly what was displayed.

If the user is removed from a group of which they were the only member, the group MAY be removed automatically.

In protocols like XMPP where groups behave like tags, a group with no members has no protocol representation.

Any GroupsCreated, GroupsChanged and GroupsRemoved signals that result from this method call MUST be emitted before the method returns.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState is Failure, this method SHOULD raise the same error as GetContactListAttributes.

The contact to alter. The set of groups which the contact should be in. Raised if DisjointGroups is true and the list of groups has more than one member. Raised if GroupStorage is Contact_Metadata_Storage_Type_None, i.e. groups cannot be edited.

Add the given members to the given group (creating it if necessary), and remove all other members.

This is the easiest and most correct way to implement user interfaces that display a single group with a list of contacts, resulting in a user expectation that when they apply the changes, the groups's set of members will become exactly what was displayed.

If DisjointGroups is true, this will also remove each member from their previous group.

If the user is removed from a group of which they were the only member, the group MAY be removed automatically.

Any GroupsCreated, GroupsChanged and GroupsRemoved signals that result from this method call MUST be emitted before the method returns.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState is Failure, this method SHOULD raise the same error as GetContactListAttributes.

The group to alter. The set of members for the group. If this set is empty, this method MAY remove the group. Raised if GroupStorage is Contact_Metadata_Storage_Type_None, i.e. groups cannot be edited.

Add the given members to the given group, creating it if necessary.

If DisjointGroups is true, this will also remove each member from their previous group.

This is good for user interfaces in which you can edit groups via drag-and-drop.

Any GroupsCreated, GroupsChanged and GroupsRemoved signals that result from this method call MUST be emitted before the method returns.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState is Failure, this method SHOULD raise the same error as GetContactListAttributes.

The group to alter. The set of members to include in the group. Raised if GroupStorage is Contact_Metadata_Storage_Type_None, i.e. groups cannot be edited.

Remove the given members from the given group.

This is good for user interfaces in which you can edit groups via drag-and-drop.

Any GroupsChanged or GroupsRemoved signals that result from this method call MUST be emitted before the method returns.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState is Failure, this method SHOULD raise the same error as GetContactListAttributes.

The group to alter. If it does not exist, then it has no members by definition, so this method SHOULD return successfully. The set of members to remove from the group. It is not an error to remove members who are already not in the group. If there are no members left in the group afterwards, the group MAY itself be removed. Raised if GroupStorage is Contact_Metadata_Storage_Type_None, i.e. groups cannot be edited.

Remove all members from the given group, then remove the group itself. If the group already does not exist, this method SHOULD return successfully.

Any GroupsChanged or GroupsRemoved signals that result from this method call MUST be emitted before the method returns.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState is Failure, this method SHOULD raise the same error as GetContactListAttributes.

The group to remove. Raised if GroupStorage is Contact_Metadata_Storage_Type_None, i.e. groups cannot be edited.

Rename the given group.

On protocols where groups behave like tags, this is an API short-cut for adding all of the group's members to a group with the new name, then removing the old group.

Otherwise, clients can't perform this operation atomically, even if the connection could.

Any GroupRenamed or GroupsRemoved signals that result from this method call MUST be emitted before the method returns.

This method SHOULD NOT be called until the ContactListState changes to Success. If the ContactListState is Failure, this method SHOULD raise the same error as GetContactListAttributes.

The group to rename. The new name for the group. Raised if GroupStorage is Contact_Metadata_Storage_Type_None, i.e. groups cannot be edited. Raised if there is no group with that name. Raised if there is already a group with the new name.
telepathy-qt-0.9.6~git1/spec/Authentication_TLS_Certificate.xml0000664000175000017500000002742512470405660022441 0ustar jrjr Copyright © 2010 Collabora Limited This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. (as stable API) This object represents a TLS certificate.

The raw data contained in a TLS certificate.

For X.509 certificates (CertificateType = "x509"), this MUST be in DER format, as defined by the X.690 ITU standard.

For PGP certificates (CertificateType = "pgp"), this MUST be a binary OpenPGP key as defined by section 11.1 of RFC 4880.

Struct representing one reason why a TLS certificate was rejected.

Since there can be multiple things wrong with a TLS certificate, arrays of this type are used to represent lists of reasons for rejection. In that case, the most important reason SHOULD be placed first in the list.

The value of the TLS_Certificate_Reject_Reason enumeration for this certificate rejection. Clients that do not understand the Error member, which may be implementation-specific, can use this property to classify rejection reasons into common categories.

The DBus error name for this certificate rejection.

This MAY correspond to the value of the Reason member, or MAY be a more specific D-Bus error name, perhaps implementation-specific.

Additional information about why the certificate was rejected. This MAY also include one or more of the following well-known keys:

user-requested (b)
True if the error was due to an user-requested rejection of the certificate; False if there was an unrecoverable error in the verification process.
expected-hostname (s)
If the rejection reason is Hostname_Mismatch, the hostname that the server certificate was expected to have.
certificate-hostname (s)
If the rejection reason is Hostname_Mismatch, the hostname of the certificate that was presented.

For instance, if you try to connect to gmail.com but are presented with a TLS certificate issued to evil.example.org, the error details for Hostname_Mismatch MAY include:

                {
                  'expected-hostname': 'gmail.com',
                  'certificate-hostname': 'evil.example.org',
                }
              
debug-message (s)
Debugging information on the error, corresponding to the message part of a D-Bus error message, which SHOULD NOT be displayed to users under normal circumstances

The possible states for a TLSCertificate object. The certificate is currently waiting to be accepted or rejected. The certificate has been verified. The certificate has been rejected. Possible reasons to reject a TLS certificate. The certificate has been rejected for another reason not listed in this enumeration. The certificate is not trusted. The certificate is expired. The certificate is not active yet. The certificate provided does not have the expected fingerprint. The hostname certified does not match the provided one. The certificate is self-signed. The certificate has been revoked. The certificate uses an insecure cipher algorithm, or is cryptographically weak. The length in bytes of the certificate, or the depth of the certificate chain exceed the limits imposed by the crypto library. The current state of this certificate. State change notifications happen by means of the Accepted and Rejected signals.

If the State is Rejected, an array of TLS_Certificate_Rejection structures containing the reason why the certificate is rejected.

If the State is not Rejected, this property is not meaningful, and SHOULD be set to an empty array.

The first rejection in the list MAY be assumed to be the most important; if the array contains more than one element, the CM MAY either use the values after the first, or ignore them.

The type of this TLS certificate (e.g. 'x509' or 'pgp').

This property is immutable

One or more TLS certificates forming a trust chain, each encoded as specified by Certificate_Data.

The first certificate in the chain MUST be the server certificate, followed by the issuer's certificate, followed by the issuer's issuer and so on.

The State of this certificate has changed to Accepted. The State of this certificate has changed to Rejected. The new value of the Rejections property. Accepts this certificate, i.e. marks it as verified. Rejects this certificate.

The new value of the Rejections property.

This MUST NOT be an empty array.

Raised when the method is called on an object whose State is not Pending, or when the provided rejection list is empty.
telepathy-qt-0.9.6~git1/spec/Channel_Interface_Group.xml0000664000175000017500000016066512470405660021146 0ustar jrjr Copyright © 2005-2009 Collabora Limited Copyright © 2005-2009 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A structure representing a contact whose attempt to join a group is to be confirmed by the local user using AddMembers. The contact to be added to the group The contact requesting or causing the change The reason for the change A human-readable message from the Actor, or an empty string if there is no message An array of contact handles to invite to the channel A string message, which can be blank if desired

Invite all the given contacts into the channel, or accept requests for channel membership for contacts on the pending local list.

A message may be provided along with the request, which will be sent to the server if supported. See the CHANNEL_GROUP_FLAG_MESSAGE_ADD and CHANNEL_GROUP_FLAG_MESSAGE_ACCEPT GroupFlags to see in which cases this message should be provided.

Attempting to add contacts who are already members is allowed; connection managers must silently accept this, without error.

Use GetAll on the D-Bus Properties D-Bus interface to get properties including Members, RemotePendingMembers and LocalPendingMembers instead, falling back to this method and GetLocalPendingMembersWithInfo if necessary. array of handles of current members array of handles of local pending members array of handles of remote pending members Returns arrays of all current, local and remote pending channel members. The AddMembers method can be used to add or invite members who are not already in the local pending list (which is always valid). The RemoveMembers method can be used to remove channel members (removing those on the pending local list is always valid). The RemoveMembers method can be used on people on the remote pending list. A message may be sent to the server when calling AddMembers on contacts who are not currently pending members. A message may be sent to the server when calling RemoveMembers on contacts who are currently channel members. A message may be sent to the server when calling AddMembers on contacts who are locally pending. A message may be sent to the server when calling RemoveMembers on contacts who are locally pending. A message may be sent to the server when calling RemoveMembers on contacts who are remote pending.

The members of this group have handles which are specific to this channel, and are not valid as general-purpose handles on the connection. Depending on the channel, it may be possible to check the HandleOwners property or call GetHandleOwners to find the owners of these handles, which should be done if you wish to (e.g.) subscribe to the contact's presence.

Connection managers must ensure that any given handle is not simultaneously a general-purpose handle and a channel-specific handle.

Placing a contact in multiple groups of this type is not allowed and will raise NotAvailable (on services where contacts may only be in one user-defined group, user-defined groups will have this flag). In rooms with channel specific handles (ie Channel_Specific_Handles flag is set), this flag indicates that no handle owners are available, apart from the owner of the SelfHandle. This used to be an important optimization to avoid repeated GetHandleOwners calls, before we introduced the HandleOwners property and HandleOwnersChanged signal. This flag indicates that all the properties introduced in specification 0.17.6 are fully supported. Indicates that MembersChangedDetailed will be emitted for changes to this group's members in addition to MembersChanged. Clients can then connect to the former and ignore emission of the latter. This flag's state MUST NOT change over the lifetime of a channel. If it were allowed to change, client bindings would have to always connect to MembersChanged just in case the flag ever went away (and generally be unnecessarily complicated), which would mostly negate the point of having this flag in the first place. A message may be sent to the server when calling RemoveMembers on the SelfHandle. This would be set for XMPP Multi-User Chat or IRC channels, but not for a typical implementation of streamed media calls.
An integer representing the bitwise-OR of flags on this channel. The user interface can use this to present information about which operations are currently valid. Change notification is via the GroupFlagsChanged signal. For backwards compatibility, clients should fall back to calling GetGroupFlags if Channel_Group_Flag_Properties is not present. The value of the GroupFlags property Returns the value of the GroupFlags property. Use GetAll on the D-Bus Properties D-Bus interface to get properties including GroupFlags instead, falling back to this method if necessary. A map from channel-specific handles to their owners. For backwards compatibility, clients should fall back to calling GetHandleOwners if Channel_Group_Flag_Properties is not present. A nonzero channel-specific handle The global handle that owns the corresponding channel-specific handle, or 0 if this could not be determined A map from channel-specific handles to their owners, including at least all of the channel-specific handles in this channel's members, local-pending or remote-pending sets as keys. Any handle not in the keys of this mapping is not channel-specific in this channel. Handles which are channel-specific, but for which the owner is unknown, MUST appear in this mapping with 0 as owner. Change notification is via the HandleOwnersChanged signal. Emitted whenever the HandleOwners property changes. This signal should not be relied on unless Channel_Group_Flag_Properties is present. Clients should listen to HandleOwnersChangedDetailed instead to get the new identifiers as well. A map from channel-specific handles to their owners, in which the keys include all the handles that were added to the keys of the HandleOwners property, and all the handles in that property whose owner has changed The channel-specific handles that were removed from the keys of the HandleOwners property, as a result of the contact leaving this group in a previous MembersChanged signal

Emitted whenever the HandleOwners property changes.

Clients can assume this signal is emitted by the Connection Manager if the MemberIdentifiers property exists

A map from channel-specific handles to their owners, in which the keys include all the handles that were added to the keys of the HandleOwners property, and all the handles in that property whose owner has changed The channel-specific handles that were removed from the keys of the HandleOwners property, as a result of the contact leaving this group in a previous MembersChanged signal The string identifiers for handles mentioned in this signal, to give clients the minimal information necessary to create contacts without waiting for round-trips. Connection managers MUST include at least the identifiers for all handles in the Added map, and MAY include those from Removed array.
A list of integer handles representing members of the channel An array of integer handles representing the owner handles of the given room members, in the same order, or 0 if the owner is not available If the CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES flag is set on the channel, then the handles of the group members are specific to this channel, and are not meaningful in a connection-wide context such as contact lists. This method allows you to find the owner of the handle if it can be discovered in this channel, or 0 if the owner is not available. Clients should use the HandleOwners property and HandleOwnersChanged signal if Channel_Group_Flag_Properties is present. This channel doesn't have the CHANNEL_SPECIFIC_HANDLES flag, so handles in this channel are globally meaningful and calling this method is not necessary One of the given handles is not a member Returns the To_Be_Added handle (only) for each structure in the LocalPendingMembers property. Use the LocalPendingMembers property, if Channel_Group_Flag_Properties is present. Returns the LocalPendingMembers property. Use the LocalPendingMembers property, if Channel_Group_Flag_Properties is present. An array of structs containing:
  • A handle representing the contact requesting channel membership
  • A handle representing the contact making the request, or 0 if unknown
  • The reason for the request: one of the values of Channel_Group_Change_Reason
  • A string message containing the reason for the request if any (or blank if none)
An array of structs containing handles representing contacts requesting channel membership and awaiting local approval with AddMembers. If Channel_Group_Flag_Properties is not present, clients should fall back to using the deprecated GetLocalPendingMembersWithInfo method, or fall back from that to the deprecated GetAllMembers method. The members of this channel. If Channel_Group_Flag_Properties is not set, fall back to calling GetAllMembers. Returns the Members property. Use the Members property, if Channel_Group_Flag_Properties is present. An array of handles representing contacts who have been invited to the channel and are awaiting remote approval. If Channel_Group_Flag_Properties is not set, fall back to calling GetAllMembers. Returns an array of handles representing contacts who have been invited to the channel and are awaiting remote approval. Use the RemotePendingMembers property, if Channel_Group_Flag_Properties is present. Emitted whenever the SelfHandle property changes. This signal should not be relied on unless Channel_Group_Flag_Properties is present. Clients should listen to SelfContactChanged instead to get the new identifier as well. The new value of the SelfHandle property.

Emitted whenever the SelfHandle property changes.

Clients can assume this signal is emitted by the Connection Manager if the MemberIdentifiers property exists.

The new value of the SelfHandle property. The new value of the SelfHandle property's identifier.
The handle for the user on this channel (which can also be a local or remote pending member), or 0 if the user is not a member at all (which is likely to be the case, for instance, on ContactList channels). Note that this is different from the result of Connection.GetSelfHandle on some protocols, so the value of this handle should always be used with the methods of this interface. For backwards compatibility, clients should fall back to calling GetSelfHandle if Channel_Group_Flag_Properties is not present. The string identifiers for handles mentioned in this channel, to give clients the minimal information necessary to create contacts without waiting for round-trips. Connection managers MUST include at least the identifiers for SelfHandle, Members, LocalPendingMembers (and their actors if any), RemotePendingMembers and HandleOwners. Returns the value of the SelfHandle property. Clients should retrieve the SelfHandle property using GetAll instead, if Channel_Group_Flag_Properties is present. A bitwise OR of the flags which have been set A bitwise OR of the flags which have been cleared Emitted when the flags as returned by GetGroupFlags are changed. The user interface should be updated as appropriate.

The reason for a set of handles to move to one of Members, LocalPendingMembers or RemotePendingMembers, or to be removed from the group. A client may supply a reason when attempting to remove members from a group with RemoveMembersWithReason, and reasons are supplied by the CM when emitting MembersChanged and MembersChangedDetailed. Some reason codes have different meanings depending on the Actor in a MembersChanged signal.

No reason was provided for this change.

In particular, this reason SHOULD be used when representing users joining a named chatroom in the usual way, users leaving a chatroom by their own request, and normal termination of a StreamedMedia call by the remote user.

If the SelfHandle is removed from a group for this reason and the actor is not the SelfHandle, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Terminated.

If the SelfHandle is removed from a group for this reason and the actor is also the SelfHandle, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Cancelled.

The change is due to a user going offline. Also used when user is already offline, but this wasn't known previously.

If a one-to-one StreamedMedia call fails because the contact being called is offline, the connection manager SHOULD indicate this by removing both the SelfHandle and the other contact's handle from the Group interface with reason Offline.

For 1-1 calls, the call terminates as a result of removing the remote contact, so the SelfHandle should be removed at the same time as the remote contact and for the same reason.

If a handle is removed from a group for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Offline.

The change is due to a kick operation.

If the SelfHandle is removed from a group for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Channel.Kicked.

The change is due to a busy indication.

If a one-to-one StreamedMedia call fails because the contact being called is busy, the connection manager SHOULD indicate this by removing both the SelfHandle and the other contact's handle from the Group interface with reason Busy.

For 1-1 calls, the call terminates as a result of removing the remote contact, so the SelfHandle should be removed at the same time as the remote contact and for the same reason.

If the SelfHandle is removed from a group for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Busy.

The change is due to an invitation. This reason SHOULD only be used when contacts are added to the remote-pending set (to indicate that the contact has been invited) or to the members (to indicate that the contact has accepted the invitation). Otherwise, what would it mean?

The change is due to a kick+ban operation.

If the SelfHandle is removed from a group for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.Channel.Banned.

The change is due to an error occurring.

The change is because the requested contact does not exist.

For instance, if the user invites a nonexistent contact to a chatroom or attempts to call a nonexistent contact, this could be indicated by the CM adding that contact's handle to remote-pending for reason None or Invited, then removing it for reason Invalid_Contact. In the case of a 1-1 StreamedMedia call, the CM SHOULD remove the self handle from the Group in the same signal.

For 1-1 calls, the call terminates as a result of removing the remote contact, so the SelfHandle should be removed at the same time as the remote contact and for the same reason.

If a contact is removed from a group for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.DoesNotExist.

The change is because the requested contact did not respond.

If a one-to-one StreamedMedia call fails because the contact being called did not respond, or the local user did not respond to an incoming call, the connection manager SHOULD indicate this by removing both the SelfHandle and the other contact's handle from the Group interface with reason No_Answer.

Documenting existing practice.

If a contact is removed from a group for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.NoAnswer.

The change is because a contact's unique identifier changed. There must be exactly one handle in the removed set and exactly one handle in one of the added sets. The Renamed signal on the Renaming interface will have been emitted for the same handles, shortly before this MembersChanged signal is emitted.

The change is because there was no permission to contact the requested handle.

If a contact is removed from a group for this reason, the equivalent D-Bus error is org.freedesktop.Telepathy.Error.PermissionDenied.

If members are removed with this reason code, the change is because the group has split into unconnected parts which can only communicate within themselves (e.g. netsplits on IRC use this reason code).

If members are added with this reason code, the change is because unconnected parts of the group have rejoined. If this channel carries messages (e.g. Text or Tubes channels) applications must assume that the contacts being added are likely to have missed some messages as a result of the separation, and that the contacts in the group are likely to have missed some messages from the contacts being added.

Note that from the added contacts' perspective, they have been in the group all along, and the contacts we indicate to be in the group (including the local user) have just rejoined the group with reason Separated. Application protocols in Tubes should be prepared to cope with this situation.

The SelfHandle SHOULD NOT be removed from channels with this reason.

A string message from the server, or blank if not A list of members added to the channel A list of members removed from the channel A list of members who are pending local approval A list of members who are pending remote approval The contact handle of the person who made the change, or 0 if not known A reason for the change

Emitted when contacts join any of the three lists (members, local pending or remote pending) or when they leave any of the three lists. There may also be a message from the server regarding this change, which may be displayed to the user if desired.

All channel-specific handles that are mentioned in this signal MUST be represented in the value of the HandleOwners property. In practice, this will mean that HandleOwnersChanged is emitted before emitting a MembersChanged signal in which channel-specific handles are added, but that it is emitted after emitting a MembersChanged signal in which channel-specific handles are removed.

See StreamedMedia for an overview of how group state changes are used to indicate the progress of a call.

A map from handles to the corresponding normalized string identifier. A nonzero handle The same string that would be returned by InspectHandles for this handle. A list of members added to the channel A list of members removed from the channel A list of members who are pending local approval A list of members who are pending remote approval

Information about the change, which may include the following well-known keys:

actor (u — Contact_Handle)
The contact handle of the person who made the change; 0 or omitted if unknown or not applicable.
change-reason (u — Channel_Group_Change_Reason)
A reason for the change.
contact-ids (a{us} — Handle_Identifier_Map)

The string identifiers for handles mentioned in this signal, to give clients the minimal information necessary to react to the event without waiting for round-trips. Connection managers SHOULD include the identifiers for members added to the group and for the actor (if any); they MAY omit the identifiers for handles which have been removed from the group.

On IRC, an event such as a netsplit could cause the vast majority of a channel to leave. Given that clients should already know the identifiers of a channel's members, including potentially hundreds of strings in the netsplit signal is unnecessary.

Clients MUST NOT assume that the presence or absence of a handle in this mapping is meaningful. This mapping is merely an optimization for round-trip reduction, and connection managers MAY add additional handles, omit some handles, or omit the mapping completely.

message (s)
A string message from the server regarding the change
error (s — DBus_Error_Name)
A (possibly implementation-specific) DBus error describing the change, providing more specific information than the Channel_Group_Change_Reason enum allows. This MUST only be present if it is strictly more informative than 'change-reason'; if present, 'change-reason' MUST be set to the closest available reason. A SIP connection manager might want to signal "402 Payment required" as something more specific than Error or Permission_Denied so that a SIP-aware UI could handle it specially; including a namespaced error permits this to be done without Channel_Group_Change_Reason being extended to encompass every error any CM ever wants to report.
debug-message (s)
Debugging information on the change. SHOULD NOT be shown to users in normal circumstances.

Emitted when contacts join any of the three lists (members, local pending or remote pending) or when they leave any of the three lists. This signal provides a superset of the information provided by MembersChanged; if the channel's GroupFlags contains Members_Changed_Detailed, then clients may listen exclusively to this signal in preference to that signal.

All channel-specific handles that are mentioned in this signal MUST be represented in the value of the HandleOwners property. In practice, this will mean that HandleOwnersChanged is emitted before emitting a MembersChangedDetailed signal in which channel-specific handles are added, but that it is emitted after emitting a MembersChangedDetailed signal in which channel-specific handles are removed.

See StreamedMedia for an overview of how group state changes are used to indicate the progress of a call.

An array of contact handles to remove from the channel A string message, which can be blank if desired

Requests the removal of contacts from a channel, reject their request for channel membership on the pending local list, or rescind their invitation on the pending remote list.

If the SelfHandle is in a Group, it can be removed via this method, in order to leave the group gracefully. This is the recommended way to leave a chatroom, close or reject a StreamedMedia call, and so on.

Accordingly, connection managers SHOULD support doing this, regardless of the value of GroupFlags. If doing so fails with PermissionDenied, this is considered to a bug in the connection manager, but clients MUST recover by falling back to closing the channel with the Close method.

Removing any contact from the local pending list is always allowed. Removing contacts other than the SelfHandle from the channel's members is allowed if and only if Channel_Group_Flag_Can_Remove is in the GroupFlags, while removing contacts other than the SelfHandle from the remote pending list is allowed if and only if Channel_Group_Flag_Can_Rescind is in the GroupFlags.

A message may be provided along with the request, which will be sent to the server if supported. See the Channel_Group_Flag_Message_Remove, Channel_Group_Flag_Message_Depart, Channel_Group_Flag_Message_Reject and Channel_Group_Flag_Message_Rescind GroupFlags to see in which cases this message should be provided.

An array of contact handles to remove from the channel A string message, which can be blank if desired A reason for the change As RemoveMembers, but a reason code may be provided where appropriate. The reason code may be ignored if the underlying protocol is unable to represent the given reason. The provided reason code was invalid.

Interface for channels which have multiple members, and where the members of the channel can change during its lifetime. Your presence in the channel cannot be presumed by the channel's existence (for example, a channel you may request membership of but your request may not be granted).

This interface implements three lists: a list of current members (Members), and two lists of local pending and remote pending members (LocalPendingMembers and RemotePendingMembers, respectively). Contacts on the remote pending list have been invited to the channel, but the remote user has not accepted the invitation. Contacts on the local pending list have requested membership of the channel, but the local user of the framework must accept their request before they may join. A single contact should never appear on more than one of the three lists. The lists are empty when the channel is created, and the MembersChanged signal (and, if the channel's GroupFlags contains Members_Changed_Detailed, the MembersChangedDetailed signal) should be emitted when information is retrieved from the server, or changes occur.

If the MembersChanged or MembersChangedDetailed signal indicates that the SelfHandle has been removed from the channel, and the channel subsequently emits Closed, clients SHOULD consider the details given in the MembersChanged or MembersChangedDetailed signal to be the reason why the channel closed.

Addition of members to the channel may be requested by using AddMembers. If remote acknowledgement is required, use of the AddMembers method will cause users to appear on the remote pending list. If no acknowledgement is required, AddMembers will add contacts to the member list directly. If a contact is awaiting authorisation on the local pending list, AddMembers will grant their membership request.

Removal of contacts from the channel may be requested by using RemoveMembers. If a contact is awaiting authorisation on the local pending list, RemoveMembers will refuse their membership request. If a contact is on the remote pending list but has not yet accepted the invitation, RemoveMembers will rescind the request if possible.

It should not be presumed that the requester of a channel implementing this interface is immediately granted membership, or indeed that they are a member at all, unless they appear in the list. They may, for instance, be placed into the remote pending list until a connection has been established or the request acknowledged remotely.

If the local user joins a Group channel whose members or other state cannot be discovered until the user joins (e.g. many chat room implementations), the connection manager should ensure that the channel is, as far as possible, in a consistent state before adding the local contact to the members set; until this happens, the local contact should be in the remote-pending set. For instance, if the connection manager queries the server to find out the initial members list for the channel, it should leave the local contact in the remote-pending set until it has finished receiving the initial members list.

If the protocol provides no reliable way to tell whether the complete initial members list has been received yet, the connection manager should make a best-effort attempt to wait for the full list (in the worst case, waiting for a suitable arbitrary timeout) rather than requiring user interfaces to do so on its behalf.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Privacy.xml0000664000175000017500000001041512470405660022201 0ustar jrjr Copyright (C) 2005, 2006 Collabora Limited Copyright (C) 2005, 2006 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A string representing the current privacy mode Return the current privacy mode, which must be one of the values returned by GetPrivacyModes. An array of valid privacy modes for this connection Returns the privacy modes available on this connection. The following well-known names should be used where appropriate:
allow-all
any contact may initiate communication
allow-specified
only contacts on your 'allow' list may initiate communication
allow-subscribed
only contacts on your subscription list may initiate communication
The current privacy mode Emitted when the privacy mode is changed or the value has been initially received from the server. The desired privacy mode Request that the privacy mode be changed to the given value, which must be one of the values returned by GetPrivacyModes. Success is indicated by the method returning and the PrivacyModeChanged signal being emitted. An interface to support getting and setting privacy modes to configure situations such as not being contactable by people who are not on your subscribe list. If this interface is not implemented, the default can be presumed to be allow-all (as defined in GetPrivacyModes).
telepathy-qt-0.9.6~git1/spec/Channel_Interface_Picture.xml0000664000175000017500000001740312470405660021454 0ustar jrjr Copyright © 2011 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

An interface channels can implement to support a picture. Most of the time this will be implemented by channels implementing the Room2 interface. Note that this interface is not restricted to Text channels, and can also be used on Call channels.

This is a separate interface from RoomConfig1 because (a) it's possible some protocol might support pictures for 1:1 chats; and (b) it avoids downloading an unwanted picture in a GetAll request.
The new picture. The MIME type.

Set the room's picture. Clients SHOULD look at the picture flags before calling this method as the user might not have permission to set the picture.

A successful return of this method indicates a successful change in picture, but clients should still listen for changes to the Picture property for further changes by other users or the server.

Picture is somehow invalid: e.g. unsupported MIME type, too big, etc.

The picture representing this channel.

This property may change during the lifetime of the channel and MUST not be included in a channel request.

The normalized contact ID representing who last modified the picture, or the empty string if it is not known.

The handle corresponding to Actor, or 0 if the Actor is unknown.

A unix timestamp indicating when the picture was last modified, or INT_MAX64 if unknown.

TRUE if the Picture property can be set by the user by calling SetPicture, otherwise FALSE.

If implementations are unsure of what this value should be it SHOULD still be set to what it believes the value is. As a result, clients should be aware that SetPicture can still fail even with this property set to TRUE.

An array of supported MIME types (e.g. "image/jpeg"). Clients MAY assume that the first type in this array is preferred. The minimum height in pixels of the picture, which MAY be 0. The minimum width in pixels of the picture, which MAY be 0. The recommended height in pixels of the picture, or 0 if there is no preferred height. The recommended width in pixels of the picture, or 0 if there is no preferred width. The maximum height in pixels of the picture, or 0 if there is no limit. The maximum width in pixels of the picture, or 0 if there is no limit. The maximum size in bytes of the picture, or 0 if there is no limit.
telepathy-qt-0.9.6~git1/spec/Channel_Type_File_Transfer.xml0000664000175000017500000006726012470405660021613 0ustar jrjr Copyright © 2008-2009 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library 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.

(as stable API)

A channel type for transferring files. The transmission of data between contacts is achieved by reading from or writing to a socket. The type of the socket (local Unix, IPv4, etc.) is decided on when the file transfer is offered or accepted.

A socket approach is used to make the transfer less dependent on both client and connection manager knowing the same protocols. As an example, when browsing an SMB share in a file manager, one selects "Send file" and chooses a contact. Instead of passing a URL which would then require the connection manager to connect to the SMB share itself, the client passes a stream from which the connection manager reads, requiring no further connection to the share. It also allows connection managers to be more restricted in their access to the system, allowing tighter security policies with eg SELinux, or more flexible deployments which cross user or system boundaries.

The Telepathy client should connect to the socket or address that the connection manager has set up and provided back to the clients through the two methods.

  • In order to send a file, one should request a FileTransfer channel for a contact, including at least the mandatory properties (Filename, Size and ContentType). Then, one should call ProvideFile to configure the socket that will be used to transfer the file.
  • In order to receive an incoming file transfer, one should call AcceptFile and then wait until the state changes to Open. When the receiver wants to resume a transfer, the Offset argument should be should be set to a non-zero value when calling AcceptFile.
  • Once the offset has been negotiated, the InitialOffsetDefined signal is emitted and the InitialOffset property is defined. The InitialOffsetDefined signal is emitted before channel becomes Open. The receiver MUST check the value of InitialOffset for a difference in offset from the requested value in AcceptFile.
  • When the state changes to Open, Clients can start the transfer of the file using the offset previously announced.

If something goes wrong with the transfer, Channel.Close should be called on the channel.

The File channel type may be requested for handles of type HANDLE_TYPE_CONTACT. If the channel is requested for any other handle type then the behaviour is undefined.

Connection managers SHOULD NOT advertise support for file transfer to other contacts unless it has been indicated by a call to UpdateCapabilities.

People would send us files, and it would always fail. That would be silly.

The state of the file transfer as described by the File_Transfer_State enum.

The file's MIME type. This cannot change once the channel has been created.

This property is mandatory when requesting the channel with the Connection.Interface.Requests.CreateChannel method. Protocols which do not have a content-type property with file transfers should set this value to application/octet-stream.

The name of the file on the sender's side. This is therefore given as a suggested filename for the receiver. This cannot change once the channel has been created.

This property should be the basename of the file being sent. For example, if the sender sends the file /home/user/monkey.pdf then this property should be set to monkey.pdf.

This property is mandatory when requesting the channel with the Connection.Interface.Requests.CreateChannel method. This property cannot be empty and MUST be set to a sensible value.

The size of the file. If this property is set, then the file transfer is guaranteed to be this size. This cannot change once the channel has been created.

When you are creating a channel with this property, its value MUST be accurate and in bytes. However, when receiving a file, this property still MUST be in bytes but might not be entirely accurate to the byte.

This property is mandatory when requesting the channel with the Connection.Interface.Requests.CreateChannel method. If this information isn't provided in the protocol, connection managers MUST set it to UINT64_MAX.

The type of the ContentHash property.

This property is optional when requesting the channel with the Connection.Interface.Requests.CreateChannel method. However, if you wish to include the ContentHash property you MUST also include this property. If you omit this property from a Connection.Interface.Requests.CreateChannel method call then its value will be assumed to be File_Hash_Type_None.

For each supported hash type, implementations SHOULD include an entry in RequestableChannelClasses with this property fixed to that hash type. If the protocol supports offering a file without a content hash, implementations SHOULD list this property in Allowed in a requestable channel class, mapping hash types they don't understand to None.

Hash of the contents of the file transfer, of type described in the value of the ContentHashType property.

This property is optional when requesting the channel with the Connection.Interface.Requests.CreateChannel method. Its value MUST correspond to the appropriate type of the ContentHashType property. If the ContentHashType property is not set, or set to File_Hash_Type_None, then this property will not even be looked at.

Description of the file transfer. This cannot change once the channel has been created.

This property is optional when requesting the channel with the Connection.Interface.Requests.CreateChannel method. If this property was not provided by the remote party, connection managers MUST set it to the empty string.

The last modification time of the file being transferred. This cannot change once the channel has been created

This property is optional when requesting the channel with the Connection.Interface.Requests.CreateChannel method.

A mapping from address types (members of Socket_Address_Type) to arrays of access-control type (members of Socket_Access_Control) that the connection manager supports for sockets with that address type. For simplicity, if a CM supports offering a particular type of file transfer, it is assumed to support accepting it. Connection Managers MUST support at least Socket_Address_Type_IPv4.

A typical value for a host without IPv6 support:

          {
            Socket_Address_Type_IPv4:
              [Socket_Access_Control_Localhost, Socket_Access_Control_Port,
               Socket_Access_Control_Netmask],
            Socket_Address_Type_Unix:
              [Socket_Access_Control_Localhost, Socket_Access_Control_Credentials]
          }
        

The number of bytes that have been transferred at the time of requesting the property. This will be updated as the file transfer continues.

The offset in bytes from where the file should be sent. This MUST be respected by both the receiver and the sender after the state becomes Open, but before any data is sent or received. Until the InitialOffsetDefined signal is emitted, this property is undefined.

Before setting the State property to Open, the connection manager MUST set the InitialOffset property, possibly to 0.

This property MUST NOT change after the state of the transfer has changed to Open.

For outgoing file transfers, this requestable property allows the channel requester to inform observers (and the handler, if it is not the requester itself) of the URI of the file being transferred. Note that the connection manager SHOULD NOT read this file directly; the handler streams the file into the CM through the socket negotiated using ProvideFile.

On outgoing file transfers, this property MUST NOT change after the channel is requested.

For incoming file transfers, this property MAY be set by the channel handler before calling AcceptFile to inform observers where the incoming file will be saved. If set by an approver, the handler MUST save the file to that location. Setting this property once AcceptFile has been called MUST fail. Once this property has been set URIDefined is emitted.

If set, this URI SHOULD generally point to a file on the local system, as defined by RFC 1738 §3.10; that is, it should be of the form file:///path/to/file or file://localhost/path/to/file. For outgoing files, this URI MAY use a different scheme, such as http:, if a remote resource is being transferred to a contact.

An invalid state type used as a null value. This value MUST NOT appear in the State property. The file transfer is waiting to be accepted/closed by the receiver. The receiver has to call AcceptFile, then wait for the state to change to Open and check the offset value. The receiver has accepted the transfer. The sender now has to call ProvideFile to actually start the transfer. The receiver should now wait for the state to change to Open and check the offset value. The file transfer is open for traffic. The file transfer has been completed successfully. The file transfer has been cancelled. No reason was specified. The change in state was requested. The file transfer was cancelled by the local user. The file transfer was cancelled by the remote user. The file transfer was cancelled because of a local error. The file transfer was cancelled because of a remote error. No hash. MD5 digest as a string of 32 ASCII hex digits. SHA1 digest as a string of ASCII hex digits. SHA256 digest as a string of ASCII hex digits. Accept a file transfer that's in the Pending state. The file transfer's state becomes Accepted after this method is called. At this point the client can connect to the socket. CM MUST emit InitialOffsetDefined and change the state to Open before writing to the socket. Then InitialOffset should be respected in case its value differs from the offset that was specified as an argument to AcceptFile. The type of address the connection manager should listen on. The type of access control the connection manager should apply to the socket. A parameter for the access control type, to be interpreted as specified in the documentation for the Socket_Access_Control enum. The desired offset in bytes where the file transfer should start. The offset is taken from the beginning of the file. Specifying an offset of zero will start the transfer from the beginning of the file. The offset that is actually given in the InitialOffset property can differ from this argument where the requested offset is not supported. (For example, some protocols do not support offsets at all so the InitialOffset property will always be 0.) The address on which the connection manager will listen for connections for this file transfer. The given address type or access-control mechanism is not supported. Your address type, access control, access control parameter, offset, or a combination of all four is invalid. The file transfer is not in the Pending state, there isn't or there is a local error with acquiring a socket. Provide the file for an outgoing file transfer which has been offered. Opens a socket that the client can use to provide a file to the connection manager. The channel MUST have been requested, and will change state to Open when this method is called if its state was Accepted. The type of address the connection manager should listen on. The type of access control the connection manager should apply to the socket. A parameter for the access control type, to be interpreted as specified in the documentation for the Socket_Access_Control enum. The address on which the connection manager will listen for connections for this file transfer. The given address type or access-control mechanism is not supported. Your address type, access control, access control parameter, or a combination of all three is invalid. Channel is not an outgoing transfer, ProvideFile has already been called, or there was a local error acquiring the socket. Emitted when the state of a file transfer changes. The new state of the file transfer; see the File_Transfer_State enumeration. The reason for the state change; see the File_Transfer_State_Change_Reason enumeration. The value will always be File_Transfer_State_Change_Reason_None, except when changing state to cancelled. Emitted when the number of transferred bytes changes. This will not be signalled with every single byte change. Instead, the most frequent this signal will be emitted is once a second. This should be sufficient, and the TransferredBytes property SHOULD NOT be polled. The number of already transferred bytes. Emitted when the value of the InitialOffset property has been negotiated. This signal MUST be emitted before the channel becomes Open and clients have to use this offset when transferring the file. The value of the InitialOffset property. Emitted when the value of the URI property has been set. This signal MUST only be emitted on incoming file transfers, and only if the handler sets the URI property before accepting the file. The value of the URI property.

The collection of files to which this channel belongs, or the empty string if this channel does not belong to a collection of files.

A channel's FileCollection property can never change.

At least on GTalk and apparently also on iChat the user can send a set of files to a contact and that contact can then pick and choose which files to actually receive.

The CM should emit all new FT channels belonging to one collection at the same time. UIs supporting this feature can then bundle all these channels together in some way, and show a nice UI. UIs not supporting it will treat them as separate transfers, which is not great but a reasonable fallback.

No mechanism is currently defined to indicate whether the UI should expect any more files in the same collection. UIs SHOULD assume that more file transfers may be added to a collection. It is possible that a "no more channels in this collection" indication will be added in a future version of this specification.

telepathy-qt-0.9.6~git1/spec/Connection_Interface_Resources.xml0000664000175000017500000002166312470405660022545 0ustar jrjr Copyright © 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(draft 1)

An interface on connections to show contact attributes for specific resources of a contact, if the protocol supports multiple resources. Resources are most common in XMPP, hence the name of this interface, but they are also present in MSN, where they are called points of presence.

When a client requests some attribute of a contact using its handle on the connection, the CM uses an algorithm to choose the most appropriate resource for the job. If there is only one resource, then the choice is obvious. If, however, there is more than one resource connected at any one time, the CM either aggregates all appropriate information to return (in the case of capabilities), or chooses one specific resource (in the case of presence).

Resources in XMPP have names, and it can be extremely useful for the user to be able to know which resources of a contact are online, providing the names are human-readable. Before now, resources have not been exposed in Telepathy, but this interface attempts to change this.

When using this interface, it is a little like using the Contacts interface, but only resource-specific attributes are ever returned. The resource-specific contact attributes are decided on by the CM, but XMPP's are listed below:

  • SimplePresence/presence
  • ContactCapabilities/capabilities
  • ClientTypes/client-types
Return the resource information of the given contacts. If any of the contact attributes for specific resources of the given contacts' are not known return immediately without waiting for a reply. The contacts whose resource attributes should be returned.

The contacts' resources and the contact attributes specific to each resource. If contact attributes are not immediately known, the behaviour is defined by the interface; the attribute should either be omitted from the result or replaced with a default value.

For every contact handle passed into this method, it is guaranteed that there will be a key in the returned map that corresponds to said handle. If there is no information regarding the contact the resource information map will be empty.

The resource string is never human-readable. The resource string might be human-readable.

Whether the resources returned from GetResources are human readable or not.

If the connection manager knows that all resource names are automatically generated, then the resource strings mean nothing to the user. Showing these strings in the UI would be confusing, so by setting this to Resources_Human_Readability_Never, the UI is advised not to show resources.

If on the other hand, all resources are set to nice names (such as "office" or "home") then it might be wise to expose these strings in the UI, so this property would be set to Resources_Human_Readability_Maybe. This is the case in XMPP -- most resources are set in a way that the user can deduce some information from them. The absence of an Always enum value is because in the case of XMPP, the resource string could be partially human-readable (as on Google Talk, where a resource of "home" is changed by the server to a unique string like "home_1234fdec") or not at all human-readable.

Emitted when a contact has a resource added or removed, or any contact attribute for any resource changes. The contact. The contact's resource information. All resource information is given, not just the details which have changed. A map of a contact's resources to their resource-specific information.

The name of the resource.

A map of contact attributes whose data is specific to this resource.
Mapping returned by GetResources, representing a collection of Contacts, their resources, and their resource-specific contact attributes. A contact. A map of the contact's resources to their resource-specific information.

The same mapping that would be returned by GetResources for this contact.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Chat_State.xml0000664000175000017500000001424212470405660022056 0ustar jrjr Copyright (C) 2007 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

A map from contacts to their chat states. A contact The contact's chat state

A map containing the chat states of all contacts in this channel whose chat state is not Inactive.

Contacts in this channel, but who are not listed in this map, may be assumed to be in the Inactive state.

In implementations that do not have this property, its value may be assumed to be empty until a ChatStateChanged signal indicates otherwise.

This property was not present in older versions of telepathy-spec, because chat states in XMPP are not state-recoverable (if you miss the change notification signal, there's no way to know the state). However, this property still allows clients to recover state changes that were seen by the CM before the client started to deal with the channel.

In CMs that follow older spec versions, assuming Inactive will mean that initial chat states will always be assumed to be Inactive, which is the best we can do. XEP 0085 specifies Inactive as the "neutral" state to be assumed unless told otherwise.

The new state. Set the local state and notify other members of the channel that it has changed. An integer handle for the contact. The new state of this contact. Emitted when the state of a member of the channel has changed. This includes local state. The contact has effectively ceased participating in the chat. The contact has not been active for some time. The contact is actively participating in the chat. The contact has paused composing a message. The contact is composing a message to be sent to the chat.

An interface for channels for receiving notifications of remote contacts' state, and for notifying remote contacts of the local state.

Clients should assume that a contact's state is Channel_Chat_State_Inactive unless they receive a notification otherwise.

The Channel_Chat_State_Gone state is treated differently to other states:

  • It may not be used for multi-user chats
  • It may not be explicitly sent
  • It should be automatically sent when the channel is closed
  • It must not be sent to the peer if a channel is closed without being used
  • Receiving it must not cause a new channel to be opened

The different states are defined by XEP-0085, but may be applied to any suitable protocol.

telepathy-qt-0.9.6~git1/spec/Channel.xml0000664000175000017500000006454312470405660016010 0ustar jrjr Copyright © 2005-2009 Collabora Limited Copyright © 2005-2009 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

The channel's type. This cannot change once the channel has been created.

For compatibility between older connection managers and newer clients, if this is unavailable or is an empty string, clients MUST use the result of calling GetChannelType.

The GetAll method lets clients retrieve all properties in one round-trip, which is desirable.

When requesting a channel, the request MUST specify a channel type, and the request MUST fail if the specified channel type cannot be supplied.

Common sense.

Extra interfaces provided by this channel. This SHOULD NOT include the channel type and the Channel interface itself, and cannot change once the channel has been created.

For compatibility between older connection managers and newer clients, if this is unavailable, or if this is an empty list and ChannelType is an empty string, clients MUST use the result of calling GetInterfaces instead. If this is an empty list but ChannelType is non-empty, clients SHOULD NOT call GetInterfaces; this implies that connection managers that implement the ChannelType property MUST also implement the Interfaces property correctly.

The GetAll method lets clients retrieve all properties in one round-trip, which is desirable.

When requesting a channel with a particular value for this property, the request must fail without side-effects unless the connection manager expects to be able to provide a channel whose interfaces include at least the interfaces requested.

The handle (a representation for the identifier) of the contact, chatroom, etc. with which this handle communicates. Its type is given by the TargetHandleType property.

This is fixed for the lifetime of the channel, so channels which could potentially be used to communicate with multiple contacts, and do not have an identity of their own (such as a Handle_Type_Room handle), must have TargetHandleType set to Handle_Type_None and TargetHandle set to 0.

Unlike in the telepathy-spec 0.16 API, there is no particular uniqueness guarantee - there can be many channels with the same (channel type, handle type, handle) tuple. This is necessary to support conversation threads in XMPP and SIP, for example.

If this is present in a channel request, it must be nonzero, TargetHandleType MUST be present and not Handle_Type_None, and TargetID MUST NOT be present. Properties from Addressing1 MUST NOT be present.

The channel that satisfies the request MUST either:

  • have the specified TargetHandle property; or
  • have TargetHandleType = Handle_Type_None, TargetHandle = 0, and be configured such that it could communicate with the specified handle in some other way (e.g. have the requested contact handle in its Group interface)

The string that would result from inspecting the TargetHandle property (i.e. the identifier in the IM protocol of the contact, room, etc. with which this channel communicates), or the empty string if the TargetHandle is 0.

The presence of this property avoids the following race condition:

  • New channel C is signalled with target handle T
  • Client calls InspectHandles(CONTACT, [T])
  • Channel C closes, removing the last reference to handle T
  • InspectHandles(CONTACT, [T]) returns an error

If this is present in a channel request, TargetHandleType MUST be present and not Handle_Type_None, and TargetHandle MUST NOT be present. Properties from Addressing1 MUST NOT be present.The request MUST fail with error InvalidHandle, without side-effects, if the requested TargetID would not be accepted by RequestHandles.

The returned channel must be related to the handle corresponding to the given identifier, in the same way as if TargetHandle had been part of the request instead.

Requesting channels with a string identifier saves a round-trip (the call to RequestHandles). It also allows the channel dispatcher to accept a channel request for an account that is not yet connected (and thus has no valid handles), bring the account online, and pass on the same parameters to the new connection's CreateChannel method.

The type of TargetHandle.

If this is omitted from a channel request, connection managers SHOULD treat this as equivalent to Handle_Type_None.

If this is omitted or is Handle_Type_None, TargetHandle and TargetID MUST be omitted from the request.

Request that the channel be closed. This is not the case until the Closed signal has been emitted, and depending on the connection manager this may simply remove you from the channel on the server, rather than causing it to stop existing entirely. Some channels such as contact list channels may not be closed. This channel may never be closed, e.g. a contact list This channel is not currently in a state where it can be closed, e.g. a non-empty user-defined contact group Emitted when the channel has been closed. Method calls on the channel are no longer valid after this signal has been emitted, and the connection manager may then remove the object from the bus at any point. Use the ChannelType property if possible. The interface name Returns the interface name for the type of this channel. Clients SHOULD use the ChannelType property instead, falling back to this method only if necessary. The GetAll method lets clients retrieve all properties in one round-trip. Use the TargetHandleType and TargetHandle properties if possible. The same as TargetHandleType. The same as TargetHandle. Returns the handle type and number if this channel represents a communication with a particular contact, room or server-stored list, or zero if it is transient and defined only by its contents. Clients SHOULD use the TargetHandle and TargetHandleType properties instead, falling back to this method only if necessary. The GetAll method lets clients retrieve all properties in one round-trip. Use the Interfaces property if possible. An array of the D-Bus interface names Get the optional interfaces implemented by the channel. Clients SHOULD use the Interfaces property instead, falling back to this method only if necessary. The GetAll method lets clients retrieve all properties in one round-trip. (as stable API)

True if this channel was created in response to a local request, such as a call to Connection.RequestChannel or Connection.Interface.Requests.CreateChannel.

The idea of this property is to distinguish between "incoming" and "outgoing" channels, in a way that doesn't break down when considering special cases like contact lists that are automatically created on connection to the server, or chatrooms that an IRC proxy/bouncer like irssi-proxy or bip was already in.

The reason we want to make that distinction is that UIs for things that the user explicitly requested should start up automatically, whereas for incoming messages and VoIP calls we should first ask the user whether they want to open the messaging UI or accept the call.

If the channel was not explicitly requested (even if it was created as a side-effect of a call to one of those functions, e.g. because joining a Tube in a MUC context on XMPP implies joining that MUC), then this property is false.

For compatibility with older connection managers, clients SHOULD assume that this property is true if they see a channel announced by the Connection.NewChannel signal with the suppress_handler parameter set to true.

In a correct connection manager, the only way to get such a channel is to request it.

Clients MAY additionally assume that this property is false if they see a channel announced by the NewChannel signal with the suppress_handler parameter set to false.

This is more controversial, since it's possible to get that parameter set to false by requesting a channel. However, there's no good reason to do so, and we've deprecated this practice.

In the particular case of the channel dispatcher, the only side-effect of wrongly thinking a channel is unrequested is likely to be that the user has to confirm that they want to use it, so it seems fairly harmless to assume in the channel dispatcher that channels with suppress_handler false are indeed unrequested.

It does not make sense for this property to be in channel requests—it will always be true for channels returned by CreateChannel, and callers of EnsureChannel cannot control whether an existing channel was originally requested locally—so it MUST NOT be accepted.

(as stable API)

The contact who initiated the channel; for instance, the contact who invited the local user to a chatroom, or the contact who initiated a call.

This does not necessarily represent the contact who created the underlying protocol-level construct. For instance, if Rob creates a chatroom, Will joins that chatroom, and Will invites Simon to join it, then Simon will see Will as the InitiatorHandle of the channel representing the chatroom.

The room creator is generally a less useful piece of information than the inviter, is less likely to be available at invitation time (i.e. can't necessarily be an immutable property), and is less likely to be available at all. The creator of a chatroom is not currently available via Telepathy; if added in future, it is likely to be made available as a property on the Chatroom interface (bug 23151).

For channels requested by the local user, this MUST be the value of Connection.SelfHandle at the time the channel was created (i.e. not a channel-specific handle).

On some protocols, the SelfHandle may change (as signalled by Connection.SelfContactChanged), but this property is immutable. Hence, locally-requested channels' InitiatorHandle and InitiatorID may not match the current SelfHandle; Requested can be used to determine whether the channel was created locally.

For channels requested by a remote user, this MUST be their handle. If unavailable or not applicable, this MUST be 0 (for instance, contact lists are not really initiated by anyone in particular, and it's easy to imagine a protocol where chatroom invitations can be anonymous).

For channels with the Group interface, this SHOULD be the same contact who is signalled as the "Actor" causing the self-handle to be placed in the local-pending set.

This SHOULD NOT be a channel-specific handle, if possible.

It does not make sense for this property to be in channel requests - the initiator will always be the local user - so it MUST NOT be accepted.

(as stable API)

The string that would result from inspecting the InitiatorHandle property (i.e. the initiator's identifier in the IM protocol).

The presence of this property avoids the following race condition:

  • New StreamedMedia channel C is signalled with initiator handle I
  • Client calls InspectHandles(CONTACT, [I])
  • Channel C closes, removing the last reference to handle I
  • InspectHandles(CONTACT, [I]) returns an error
  • Client can indicate that a call was missed, but not who called!

It does not make sense for this property to be in channel requests - the initiator will always be the local user - so it MUST NOT be accepted.

All communication in the Telepathy framework is carried out via channel objects which are created and managed by connections. This interface must be implemented by all channel objects, along with one single channel type, such as Channel.Type.ContactList which represents a list of people (such as a buddy list) or Channel.Type.Text which represents a channel over which textual messages are sent and received.

Each Channel's object path MUST start with the object path of its associated Connection, followed by '/'. There MAY be any number of additional object-path components, which clients MUST NOT attempt to parse.

This ensures that Channel object paths are unique, even between Connections and CMs, because Connection object paths are guaranteed-unique via their link to the well-known bus name.

If all connection managers in use are known to comply with at least spec version 0.17.10, then the Connection's object path can even be determined from the Channel's without any additional information, by taking the first 7 components.

Each channel has a number of immutable properties (which cannot vary after the channel has been announced with NewChannels), provided to clients in the ObserveChannels, AddDispatchOperation and HandleChannels methods to permit immediate identification of the channel. This interface contains immutable properties common to all channels. In brief:

  • ChannelType specifies the kind of communication carried out on this channel;
  • TargetHandleType, TargetHandle and TargetID specify the entity with which this channel communicates, such as the other party in a 1-1 call, or the name of a multi-user chat room;
  • InitiatorHandle and InitiatorID specify who created this channel;
  • Requested indicates whether the local user requested this channel, or whether it is an incoming call, a text conversation started by a remote contact, a chatroom invitation, etc.

Other optional Interfaces can be implemented to indicate other available functionality, such as Channel.Interface.Group if the channel contains a number of contacts, Channel.Interface.Password to indicate that a channel may have a password set to require entry, and Channel.Interface.ChatState for typing notifications. The interfaces implemented may not vary after the channel has been created. These other interfaces (along with the interface named by ChannelType) may themselves specify immutable properties to be announced up-front along with the properties on this interface.

Some channels are “anonymous”, with TargetHandleType set to None, which indicates that the channel is defined by some other properties. For instance, transient ad-hoc chat rooms may be defined only by their members (as visible through the Group interface), and ContactSearch channels represent a single search attempt for a particular Server.

Specific connection manager implementations may implement channel types and interfaces which are not contained within this specification in order to support further functionality. To aid interoperability between client and connection manager implementations, the interfaces specified here should be used wherever applicable, and new interfaces made protocol-independent wherever possible. Because of the potential for 3rd party interfaces adding methods or signals with conflicting names, the D-Bus interface names should always be used to invoke methods and bind signals.

Previously we guaranteed that, for any handle type other than Handle_Type_None, and for any channel type and any handle, there would be no more than one channel with that combination of channel type, handle type and handle. This guarantee has now been removed in order to accommodate features like message threads. Previously we did not explicitly guarantee that Channels' object paths had the Connection's object path as a prefix.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_IRC_Command1.xml0000664000175000017500000000520012470405660022714 0ustar jrjr Copyright (C) 2013 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

The command followed by its arguments.

Send an arbitrary IRC command to the server.

For example, an IRC client receiving /bip blreset from the user might call this method with BIP blreset as argument which will send BIP blreset to the server.

The command is supplied in UTF-8 (because strings on D-Bus are always UTF-8). It is transcoded into the connection's configured character set, if different, before sending to the server.

The connection manager MAY raise this error for commands that have a more appropriate D-Bus API.
An interface to send arbitrary IRC commands to the server.
telepathy-qt-0.9.6~git1/spec/Media_Stream_Handler.xml0000664000175000017500000011104512470405660020415 0ustar jrjr Copyright (C) 2005-2008 Collabora Limited Copyright (C) 2005-2008 Nokia Corporation Copyright (C) 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

Handles signalling the information pertaining to a specific media stream. A client should provide information to this handler as and when it is available. Information about a codec supported by a client or a peer's client. The codec's payload identifier, as per RFC 3551 (static or dynamic) The codec's name Type of stream this codec supports Sampling frequency in Hertz Number of supported channels Codec-specific optional parameters The IP addresses of possible STUN servers to use for NAT traversal, as dotted-quad IPv4 address literals or RFC2373 IPv6 address literals. This property cannot change once the stream has been created, so there is no change notification. The IP addresses MUST NOT be given as DNS hostnames. High-quality connection managers already need an asynchronous DNS resolver, so they might as well resolve this name to an IP to make life easier for streaming implementations. True if we were the creator of this stream, false otherwise. This information is needed for some nat traversal mechanisms, such as ICE-UDP, where the creator gets the role of the controlling agent.

The transport (NAT traversal technique) to be used for this stream. Well-known values include:

none
Raw UDP, with or without STUN, should be used. If the STUNServers property is non-empty, STUN SHOULD be used.
stun
A deprecated synonym for 'none'.
gtalk-p2p
Google Talk peer-to-peer connectivity establishment should be used, as implemented in libjingle 0.3.
ice-udp
Interactive Connectivity Establishment should be used, as defined by the IETF MMUSIC working group.
wlm-8.5
The transport used by Windows Live Messenger 8.5 or later, which resembles ICE draft 6, should be used.
wlm-2009
The transport used by Windows Live Messenger 2009 or later, which resembles ICE draft 19, should be used.

This property cannot change once the stream has been created, so there is no change notification.

A list of mappings describing TURN or Google relay servers available for the client to use in its candidate gathering, as determined from the protocol. Map keys are:

ip - s
The IP address of the relay server as a dotted-quad IPv4 address literal or an RFC2373 IPv6 address literal. This MUST NOT be a DNS hostname. High-quality connection managers already need an asynchronous DNS resolver, so they might as well resolve this name to an IP and make life easier for streaming implementations.
type - s

Either udp for UDP (UDP MUST be assumed if this key is omitted), tcp for TCP, or tls.

The precise meaning of this key depends on the NATTraversal property: if NATTraversal is ice-udp, tls means TLS over TCP as referenced by ICE draft 19, and if NATTraversal is gtalk-p2p, tls means a fake SSL session over TCP as implemented by libjingle.

port - q
The UDP or TCP port of the relay server as an ASCII unsigned integer
username - s
The username to use
password - s
The password to use
component - u
The component number to use this relay server for, as an ASCII unsigned integer; if not included, this relay server may be used for any or all components. In ICE draft 6, as used by Google Talk, credentials are only valid once, so each component needs relaying separately.

An equivalent of the gtalk-p2p-relay-token property on MediaSignalling channels is not included here. The connection manager should be responsible for making the necessary HTTP requests to turn the token into a username and password.

The type of relay server that this represents depends on the value of the NATTraversal property. If NATTraversal is ice-udp, this is a TURN server; if NATTraversal is gtalk-p2p, this is a Google relay server; otherwise, the meaning of RelayInfo is undefined.

If relaying is not possible for this stream, the list is empty.

This property cannot change once the stream has been created, so there is no change notification.

String identifier for this candidate Array of transports for this candidate with fields, as defined in NewNativeCandidate Signal emitted when the connection manager wishes to inform the client of a new remote candidate. Signal emitted when the connection manager wishes the stream to be closed. Inform the connection manager of codec used to receive data. ID of error, from the MediaStreamError enumeration String describing the error Inform the connection manager that an error occured in this stream. The connection manager should emit the StreamError signal for the stream on the relevant channel, and remove the stream from the session. An unknown error occured. The end of the stream was reached. This error has no use anywhere. In Farsight 1 times, it was used to indicate a GStreamer EOS (when the end of a file is reached). But since this is for live calls, it makes no sense. There are no common codecs between the local side and the other particpants in the call. The possible codecs are not signalled here: the streaming implementation is assumed to report them in an implementation-dependent way, e.g. Farsight should use GstMissingElement. A network connection for the Media could not be established or was lost. There was an error in the networking stack (other than the connection failure). There are no installed codecs for this media type. The CM is doing something wrong. There was an error in the media processing stack. Informs the connection manager that all possible native candisates have been discovered for the moment. Informs the connection manager that a valid candidate pair has been discovered and streaming is in progress.

Informs the connection manager that a valid transport pair has been discovered and streaming is in progress. Component id MUST be the same for both transports and the pair is only valid for that component.

The connection manager might need to send the details of the active transport pair (e.g. c and o parameters of SDP body need to contain address of selected native RTP transport as stipulated by RFC 5245). However, the candidate ID might not be enough to determine these info if the transport was found after NativeCandidatesPrepared has been called (e.g. peer reflexive ICE candidate).

This method must be called before NewActiveCandidatePair.

This way, connection managers supporting this method can safely ignore subsequent NewActiveCandidatePair call.

Connection managers SHOULD NOT implement this method unless they need to inform the peer about selected transports. As a result, streaming implementations MUST NOT treat errors raised by this method as fatal.

Usually, connection managers only need to do one answer/offer round-trip. However, some protocols give the possibility to to send an updated offer (e.g. ICE defines such mechanism to avoid some race conditions and to properly set the state of gateway devices).

UDP (User Datagram Protocol) TCP (Transmission Control Protocol) String identifier for this candidate Array of transports for this candidate, with fields:
  • component number
  • IP address (as a string)
  • port
  • base network protocol (one of the values of MediaStreamBaseProto)
  • proto subtype (e.g. RTP)
  • proto profile (e.g. AVP)
  • our preference value of this transport (double in range 0.0-1.0 inclusive); 1 signals the most preferred transport
  • transport type, one of the values of MediaStreamTransportType
  • username if authentication is required
  • password if authentication is required
Inform this MediaStreamHandler that a new native transport candidate has been ascertained.
A local address An external address derived by a method such as STUN An external stream relay Locally-supported codecs. Inform the connection manager that a client is ready to handle this StreamHandler. Also provide it with info about all supported codecs. Locally-supported codecs

Used to provide codecs after Ready(), so the media client can go ready for an incoming call and exchange candidates/codecs before knowing what local codecs are available.

This is useful for gatewaying calls between two connection managers. Given an incoming call, you need to call Ready to get the remote codecs before you can use them as the "local" codecs to place the outgoing call, and hence receive the outgoing call's remote codecs to use as the incoming call's "local" codecs.

In this situation, you would pass an empty list of codecs to the incoming call's Ready method, then later call SetLocalCodecs on the incoming call in order to respond to the offer.

String identifier for remote candidate to drop There is no case where you want to release candidates (except for an ICE reset, and there you'd want to replace then all, using SetRemoteCandidateList). Signal emitted when the connection manager wishes to inform the client that the remote end has removed a previously usable candidate. It seemed like a good idea at the time, but wasn't. Emitted by the connection manager to inform the client that a valid candidate pair has been discovered by the remote end and streaming is in progress. A list of candidate id and a list of transports as defined in NewNativeCandidate Signal emitted when the connection manager wishes to inform the client of all the available remote candidates at once. Codecs supported by the remote peer. Signal emitted when the connection manager wishes to inform the client of the codecs supported by the remote end. If these codecs are compatible with the remote codecs, then the client must call SupportedCodecs, otherwise call Error. If emitted with argument TRUE, this means that the connection manager wishes to set the stream playing; this means that the streaming implementation should expect to receive data. If emitted with argument FALSE this signal is basically meaningless and should be ignored. We're very sorry. Signal emitted when the connection manager wishes to set whether or not the stream sends to the remote end. A telephony event code. Request that a telephony event (as defined by RFC 4733) is transmitted over this stream until StopTelephonyEvent is called. A telephony event code as defined by RFC 4733. The payload type to use when sending events. The value 0xFFFFFFFF means to send with the already configured event type instead of using the specified one. Request that a telephony event (as defined by RFC 4733) is transmitted over this stream until StopTelephonyEvent is called. This differs from StartTelephonyEvent in that you force the event to be transmitted as a RFC 4733 named event, not as sound. You can also force a specific Codec ID. A telephony event code as defined by RFC 4733. Request that a telephony event (as defined by RFC 4733) is transmitted over this stream until StopTelephonyEvent is called. This differs from StartTelephonyEvent in that you force the event to be transmitted as sound instead of as a named event. Request that any ongoing telephony events (as defined by RFC 4733) being transmitted over this stream are stopped. Informs the connection manager of the stream's current state, as as specified in Channel.Type.StreamedMedia::ListStreams. Locally supported codecs. Inform the connection manager of the supported codecs for this session. This is called after the connection manager has emitted SetRemoteCodecs to notify what codecs are supported by the peer, and will thus be an intersection of all locally supported codecs (passed to Ready) and those supported by the peer. Locally supported codecs, which SHOULD be the same as were previously in effect, but possibly with different parameters. Inform the connection manager that the parameters of the supported codecs for this session have changed. The connection manager should send the new parameters to the remote contact. This is required for H.264 and Theora, for example.

Emitted when the connection manager wishes to place the stream on hold (so the streaming client should free hardware or software resources) or take the stream off hold (so the streaming client should reacquire the necessary resources).

When placing a channel's streams on hold, the connection manager SHOULD notify the remote contact that this will be done (if appropriate in the protocol) before it emits this signal.

It is assumed that relinquishing a resource will not fail. If it does, the call is probably doomed anyway.

When unholding a channel's streams, the connection manager SHOULD emit this signal and wait for success to be indicated via HoldState before it notifies the remote contact that the channel has been taken off hold.

This means that if a resource is unavailable, the remote contact will never even be told that we tried to acquire it.

If true, the stream is to be placed on hold.
Notify the connection manager that the stream's hold state has been changed successfully in response to SetStreamHeld. If true, the stream is now on hold. Notify the connection manager that an attempt to reacquire the necessary hardware or software resources to unhold the stream, in response to SetStreamHeld, has failed. This struct is also used by Call, but in call, the CM should know about RTP profiles, and never use MAXUINT as a default value, because it complicates things unnecessarily. The minimum interval between two regular RTCP packets in milliseconds for this content. If no special value is desired, one should put MAXUINT (0xFFFFFFFF). Implementors and users of Call's RTCPFeedback should not use the MAXUINT default. Instead, in RTP/AVP, the default should be 5000 (5 seconds). If using the RTP/AVPF profile, it can be set to a lower value, the default being 0. The RTCP feedback messages for this codec. A struct defining an RTCP feedback message. Feedback type, for example "ack", "nack", or "ccm". Feedback subtype, according to the Type, can be an empty string (""), if there is no subtype. For example, generic nack is Type="nack" Subtype="". Feedback parameters as a string. Format is defined in the relevant RFC A map of codec and its feedback properties. Numeric identifier for the codec. This will be used as the PT in the SDP or content description. The RTCP feedback properties for this codec. Remote Feedback messages desired by the remote side Signal emitted when the connection manager wishes to inform the client of the feedback messages supported by the remote end. This signal is emitted before SetRemoteCodecs. If the client supports any of these messages, it must call SupportedFeedbackMessages before calling SupportedCodecs. Locally supported feedback messages. Inform the connection manager of the supported feedback messages for this session. This is called a before calling SupportedCodecs, Ready or CodecsUpdated to indicate the local, or negotiated feedback messages. A struct defining a RTP Header extension Identifier to be negotiated Direction in which the Header Extension is negotiated. URI defining the extension Feedback parameters as a string. Format is defined in the relevant RFC Header extensions desired by the remote side Signal emitted when the connection manager wishes to inform the client of the RTP header extensions supported by the remote end. This signal is emitted before SetRemoteCodecs. If the client supports any of these messages, it must call SupportedHeaderExtensions before calling SupportedCodecs. Locally supported RTP header extensions. Inform the connection manager of the supported RTP header extensions for this session. This is called before calling SupportedCodecs, Ready or CodecsUpdated to indicate the local or negotiated RTP header extensions.
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Anonymity.xml0000664000175000017500000001702512470405660022557 0ustar jrjr Copyright © 2008-2010 Nokia Corporation Copyright © 2010 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as stable API)

An interface to support anonymity settings on a per-connection basis. This defines what personal identifying information a remote contact may or may not see. For example, GSM might use this for CLIR, while SIP might use this for privacy service requests.

Flags for the various types of anonymity modes. These modes are solely to inform the CM of the desired anonymous settings. It is up to the CM to determine whether the anonymity modes should be handled within the CM itself, or whether the network that a CM might be talking to should be enforcing anonymity.

CMs MAY support only a subset of these modes, and specific connections MAY support none at all.

Obscure any information that provides user identification, user-agent identification or personal details. Examples of this information might be GSM CallerID, SIP from address, various informational email headers, etc.

The CM should scrub/replace any of this information before passing messages or data onto the network. Note that a CM which has the option of obscuring the information at the CM or privacy service level would choose both (anonymity services are opaque to clients of this interface).

Clients SHOULD NOT set both Client_Info and Show_Client_Info modes. If they are set, the CM MUST respect Client_Info and ignore Show_Client_Info.

Explicitly request showing of client information. In connection context, this can be used to override service default. In channel context, this overrides connection anonymity modes.

In GSM, it's possible to have CLIR enabled by default, and explicitly suppress CLIR for a single phone call.

Clients SHOULD NOT set both Client_Info and Show_Client_Info modes. If they are set, the CM MUST respect Client_Info and ignore Show_Client_Info. The CM MAY set both Client_Info and Show_Client_Info in SupportedAnonymityModes to indicate its support for explicitly hiding and publicising client information.

Obscure any originating IP address information, contact URIs, and anonymize all traffic involved with sending/receiving any media streams or call content. Examples of this include the "headers" portions of RFC 3323 as well as the History-Info (described in RFC 4244) for a SIP CM.

This SHOULD have the effect of hiding address information from the remote contact (ie, the contact cannot know what IP address the session is originated from). Obviously the network still needs to be able to route information between contacts, so this provides no guarantees of what can be seen by intermediaries.

The anonymity modes supported by the CM for this connection. Once Connection.Status has moved to Connected, this property MUST NOT change.

This specifies whether or not the anonymity settings MUST be respected by the CM and any intermediaries between the local and remote contacts. If this is set to true but anonymity settings cannot be followed, then the session MUST be denied with a org.freedesktop.Telepathy.Error.WouldBreakAnonymity error. Any client that sets AnonymityModes SHOULD also set this property first (rather than accepting the CM's default value).

The currently enabled anonymity modes for the connection. Setting has the effect of requesting new modes for the connection, and may raise an error if the unsupported modes are set. Successfully changing the modes will result in emission of AnonymityModesChanged signal.

An unsupported mode was supplied. Supported modes are specified in the SupportedAnonymityModes property, and this should be checked prior to setting AnonymityModes.
Emitted when the anonymity mode has changed. The new anonymity modes for this connection.
telepathy-qt-0.9.6~git1/spec/Channel_Interface_Addressing.xml0000664000175000017500000001221712470405660022122 0ustar jrjr Copyright © 2010 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(as draft)

This interface provides properties that can be used for requesting channels through different contact addressing schemes like vCard addresses or URIs.

The vCard field, normalized to lower case, TargetVCardAddress refers to.

The url vCard field MUST NOT appear here; see TargetURI instead.

In practice, protocols have a limited set of URI schemes that make sense to resolve as a contact.

If this is omitted from a request, TargetVCardAddress MUST be omitted as well.

The URI scheme used in TargetURI

While this seems redundant, since the scheme is included in TargetURI, it exists for constructing RequestableChannelClasses that support a limited set of URI schemes.

If this is omitted from a request, TargetURI MUST be omitted as well.

The vCard address of the Channel's target.

If this is present in a channel request, TargetVCardField MUST be present, and TargetHandle, TargetID, and TargetURI MUST NOT be present. TargetHandleType must either not be present or set to Handle_Type_Contact. The request MUST fail with error InvalidHandle, without side-effects, if the requested vCard address cannot be found.

The URI of the Channel's target. The URI's scheme (i.e. the part before the first colon) MUST be identical to TargetURIScheme.

If this is present in a channel request, TargetVCardField MUST be present, and TargetHandle, TargetID, and TargetVCardAddress MUST NOT be present. TargetHandleType must either not be present or set to Handle_Type_Contact. The request MUST fail with error InvalidHandle, without side-effects, if the requested vCard address cannot be found.

telepathy-qt-0.9.6~git1/spec/Account_Manager.xml0000664000175000017500000003057412470405660017463 0ustar jrjr Copyright © 2008-2009 Collabora Ltd. Copyright © 2008-2009 Nokia Corporation

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

The account manager is a central service used to store account details.

The current account manager is defined to be the process that owns the well-known bus name org.freedesktop.Telepathy.AccountManager on the session bus. This process must export an /org/freedesktop/Telepathy/AccountManager object with the AccountManager interface.

A list of the interfaces provided by the account manager object. A list of the valid (complete, usable) Accounts. Change notification is via AccountValidityChanged. This split between valid and invalid accounts makes it easy to ignore the invalid ones. The only things that should be manipulating invalid accounts are account-editing UIs, which might be able to rescue them. A list of incomplete or otherwise unusable Accounts. Change notification is via AccountValidityChanged. The given account has been removed. This is effectively change notification for the valid and invalid accounts lists. On emission of this signal, the Account indicated will no longer be present in either of the lists. An Account, which must not be used any more. The validity of the given account has changed. New accounts are also indicated by this signal, as an account validity change (usually to True) on an account that did not previously exist. This is effectively change notification for the valid and invalid accounts lists. An Account. True if the account is now valid.

A list of the fully qualified names of properties that can be set via the Properties argument to CreateAccount when an account is created.

Examples of good properties to support here include Icon, Enabled, Nickname, AutomaticPresence, ConnectAutomatically, Supersedes, RequestedPresence and Avatar.

Examples of properties that would make no sense here include Valid, Connection, ConnectionStatus, ConnectionStatusReason, CurrentPresence and NormalizedName.

This property MUST NOT include include the DisplayName and Parameters properties, which are set using separate arguments.

This property MAY include the names of properties that, after account creation, will be read-only: this indicates that the property can be set at account creation but not changed later.

For example, an account manager might support migration tools that use this to preserve the HasBeenOnline property, even though that property is usually read-only.

Request the creation of a new Account. The account manager SHOULD NOT allow invalid accounts to be created. added the Properties argument The name of the connection manager, e.g. "salut". The protocol, e.g. "local-xmpp". The initial value of the new account's DisplayName property. The account manager SHOULD modify this to make it unique if an Account already exists with the same display name, for instance by appending a number or the 'account' parameter. Account manager implementations SHOULD accept an empty string, but account editing user interfaces should avoid passing an empty string for this parameter.

The account creation UI may ask the user for a name for the new account. If the author of the UI chooses not to do this, the account creation UI is better able to suggest a default display name because it has protocol-specific knowledge which the account manager does not.

The account manager always knows the complete list of accounts so it can easily tell whether it should append something to the display name to avoid presenting two identically-named accounts to the user.

Initial parameter values, as would be passed to RequestConnection.

The values of any other properties to be set immediately on the new Account.

Only the properties mentioned in SupportedAccountProperties are acceptable here. In particular, the DisplayName and Parameters properties are never allowed here, since they are set using the other arguments to this method.

Account manager implementations SHOULD support creating accounts with an empty value for this argument.

The new Account.

The Connection_Manager is not installed or does not implement the given Protocol.

The Parameters provided were unacceptable: they might omit a Required parameter, include an unsupported parameter, or have a value of the wrong type.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_Password.xml0000664000175000017500000001161012470405660021635 0ustar jrjr Copyright © 2005-2011 Collabora Limited Copyright © 2005-2009 Nokia Corporation Copyright © 2006 INdT This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY 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. The ProvidePassword method must be called now for the user to join the channel The RoomConfig1.PasswordHint contains a hint for the password. An integer with the logical OR of all the flags set (values of ChannelPasswordFlags) Returns the bitwise-OR of the flags relevant to the password on this channel. The user interface can use this to present information about which operations are currently valid. A bitwise OR of the flags which have been set A bitwise OR of the flags which have been cleared Emitted when the flags as returned by GetPasswordFlags are changed. The user interface should be updated as appropriate. The password A boolean indicating whether or not the password was correct Provide the password so that the channel can be joined. Must be called with the correct password in order for channel joining to proceed if the 'provide' password flag is set.

Interface for channels that may have a password set that users need to provide before being able to join. The GetPasswordFlags method and the associated PasswordFlagsChanged signal indicate whether the user must now provide a password to join the channel.

Once the user has joined the channel, the current password-protectedness of the room can be checked (and possibly modified) using the RoomConfig1 interface, if implemented.

telepathy-qt-0.9.6~git1/spec/Channel_Interface_File_Transfer_Metadata.xml0000664000175000017500000001062112470405660024357 0ustar jrjr Copyright (C) 2011 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

This interface exists to provide a mechanism to include arbitrary additional information in file transfers. For example, one might want to send a document and include the number of times the character P appeared in the file, so would add NumberOfPs=42 to the Metadata property.

ServiceName living in its own property makes it easier for specific applications to send files to each other, bypassing the standard handler. For example, the Banshee Telepathy plugin handler could match on ServiceName so the Empathy file transfer is not used instead.

A string representing the service name that will be used over the file transfer channel. This property is equivalent to the Channel.Type.DBusTube.ServiceName and Channel.Type.StreamTube.Service properties. If no service name is given then this property will be the empty string.

Additional information about the file transfer set by the channel initiator. If no additional information is given then this property will be empty.

A mapping from string key to a list of strings, used in the Metadata property. To emulate a simple string → string hash table one should have exactly one member in the value string list. This property is an a{sas} primarily because this maps easily to XEP-0004 Data Forms, and allows more structured metadata than a{ss} would. (For instance, a list of RDF triples could be expressed as one long array of strings, or as three-element values for a series of dummy key names, rather than as one big string blob.) While it might be convenient for applications to allow keys of arbitrary types, the added convenience would be outweighed by having to define the XMPP representation
telepathy-qt-0.9.6~git1/spec/Channel_Interface_DTMF.xml0000664000175000017500000003642512470405660020600 0ustar jrjr Copyright © 2005-2010 Collabora Limited Copyright © 2005-2010 Nokia Corporation Copyright © 2006 INdT

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

The only part of this spec that should be used with a Call1 channel is the "InitialTones" property. The Stream_IDs in this interface can now be ignored by CMs. An interface that gives a Channel the ability to send DTMF events over audio streams which have been established using the StreamedMedia channel type. The event codes used are in common with those defined in RFC4733, and are listed in the DTMF_Event enumeration. The Stream_ID parameter became vestigial. A stream ID as defined in the StreamedMedia channel type. This argument is included for backwards compatibility and MUST be ignored by the implementations - the tone SHOULD be sent to all eligible streams in the channel. A numeric event code from the DTMF_Event enum.

Start sending a DTMF tone to all eligible streams in the channel. Where possible, the tone will continue until StopTone is called. On certain protocols, it may only be possible to send events with a predetermined length. In this case, the implementation MAY emit a fixed-length tone, and the StopTone method call SHOULD return NotAvailable.

The client may wish to control the exact duration and timing of the tones sent as a result of user's interaction with the dialpad, thus starting and stopping the tone sending explicitly.

Tone overlaping or queueing is not supported, so this method can only be called if no DTMF tones are already being played.

The given stream ID was invalid. Deprecated, since stream IDs are ignored. There are no eligible audio streams. DTMF tones are already being played.
The Stream_ID parameter became vestigial. A stream ID as defined in the StreamedMedia channel type. This argument is included for backwards compatibility and MUST be ignored by the implementations - the sending SHOULD be stoped in all eligible streams in the channel. Stop sending any DTMF tones which have been started using the StartTone or MultipleTones methods. If there is no current tone, this method will do nothing. If MultipleTones was used, the client should not assume the sending has stopped immediately; instead, the client should wait for the StoppedTones signal. On some protocols it might be impossible to cancel queued tones immediately. The given stream ID was invalid. Deprecated, since stream IDs are ignored. Continuous tones are not supported by this stream. Deprecated, since stream IDs are ignored. The characters [pPxXwW,] must also be supported.

A string representation of one or more DTMF events. Implementations of this method MUST support all of the following characters in this string:

  • the digits 0-9, letters A-D and a-d, and symbols '*' and '#' correspond to the members of DTMF_Event
  • any of 'p', 'P', 'x', 'X' or ',' (comma) results in an implementation-defined pause, typically for 3 seconds
  • 'w' or 'W' waits for the user to continue, by stopping interpretation of the string, and if there is more to be played, emitting the TonesDeferred signal with the rest of the string as its argument: see that signal for details

Send multiple DTMF events to all eligible streams in the channel. Each tone will be played for an implementation-defined number of milliseconds (typically 250ms), followed by a gap before the next tone is played (typically 100ms). The duration and gap are defined by the protocol or connection manager.

In cases where the client knows in advance the tone sequence it wants to send, it's easier to use this method than manually start and stop each tone in the sequence.

The tone and gap lengths may need to vary for interoperability, according to the protocol and other implementations' ability to recognise tones. At the time of writing, GStreamer uses a minimum of 250ms tones and 100ms gaps when playing in-band DTMF in the normal audio stream, or 70ms tones and 50ms gaps when encoding DTMF as audio/telephone-event.

Tone overlaping or queueing is not supported, so this method can only be called if no DTMF tones are already being played.

The supplied Tones string was invalid. There are no eligible audio streams. DTMF tones are already being played.
Indicates whether there are DTMF tones currently being sent in the channel. If so, the client should wait for StoppedTones signal before trying to send more tones.

If non-empty in a channel request that will create a new channel, the connection manager should send the tones immediately after at least one eligible audio stream has been created in the channel.

This should only be used with InitialAudio=true.

This property is immutable (cannot change).

The tones waiting for the user to continue, if any.

When this property is set to a non-empty value, TonesDeferred is emitted. When any tones are played (i.e. whenever SendingTones is emitted), this property is reset to the empty string.

The new non-empty value of DeferredTones.

Emitted when 'w' or 'W', indicating "wait for the user to continue", is encountered while playing a DTMF string queued by MultipleTones or InitialTones. Any queued DTMF events after the 'w', which have not yet been played, are placed in the DeferredTones property and copied into this signal's argument.

When the channel handler is ready to continue, it MAY pass the value of DeferredTones to MultipleTones, to resume sending. Alternatively, it MAY ignore the deferred tones, or even play different tones instead. Any deferred tones are discarded the next time a tone is played.

This signal SHOULD NOT be emitted if there is nothing left to play, i.e. if the 'w' was the last character in the DTMF string.

DTMF string (one or more events) that is to be played.

DTMF tone(s)are being sent to all eligible streams in the channel. The signal is provided to indicating the fact that the streams are currently being used to send one or more DTMF tones, so any other media input is not getting through to the audio stream. It also serves as a cue for the StopTone method.

True if the DTMF tones were actively cancelled via StopTone.

DTMF tones have finished playing on streams in this channel.

0 1 2 3 4 5 6 7 8 9 * # A B C D
telepathy-qt-0.9.6~git1/spec/Connection_Interface_Power_Saving.xml0000664000175000017500000001172712470405660023176 0ustar jrjr Copyright © 2007-2010 Collabora Limited

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library 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.

(as stable API)

Some protocols support mechanisms for reducing bandwidth usage—and hence power usage, on mobile devices—when the user is not directly interacting with their IM client. For instance, Google Talk's XMPP server supports queueing incoming presence updates at the client's instruction; the client can instruct the server to deliver all outstanding presence updates at a later time. This interface may be used to instruct the connection manager to enable and disable such protocol-level features when a screensaver is activated, the device screen is locked, and so on, by calling the SetPowerSaving method.

Enabling power saving SHOULD NOT change behaviour in any way that is noticable to a user not actively interacting with their client. For example, delaying presence updates somewhat is unlikely to be noticed by a user not staring at their device waiting for a contact to come online; on the other hand, requesting that the server queue incoming messages would be noticable by the user, so is not an acceptable effect of calling SetPowerSaving.

Turn power saving mode on or off.

Depending on the device's activity level, the connection can have its power saving mode turned on or off.

Errors raised by this method indicate that power saving could not be enabled, which SHOULD NOT generally be treated as fatal.

If the CM cannot switch modes, either because of the protocol (NotImplemented), or because of the service (NotAvailable), Mission Control (or whoever manages this) should be made aware. The error could be ignored or, in the extreme, be fascist and disconnect the account.
True if protocol-level power saving features should be activated; False if they should be de-activated. The current connection has no power saving features.

True if protocol-level power saving features are currently activated. This property can be changed using the SetPowerSaving method; change notifications is via the PowerSavingChanged signal.

The new state of the power saving feature. The PowerSavingActive property changed.
telepathy-qt-0.9.6~git1/spec/Channel_Interface_Subject.xml0000664000175000017500000001337512470405660021444 0ustar jrjr Copyright © 2010–2011 Collabora Ltd.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY 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.

(version 2)

An interface channels can implement to support subjects. Most of the time this will be implemented by channels implementing the Room2 interface, but some protocols support subjects in 1-to-1 chats (such as XMPP). Note that this interface is not restricted to Text channels, and can also be used on Call channels.

The new subject.

Set the room's subject. Clients SHOULD look at the subject flags before calling this method as the user might not have permission to set the subject.

A successful return of this method indicates a successful change in subject, but clients should still listen for changes to the Subject property for further changes by other users or the server.

The human-readable subject on the channel such as the topic in an IRC channel, or the room name in XMPP MUCs.

This property replaces the subject Telepathy property of Text channels, as Telepathy properties are soon to be deprecated completely.

This property may change during the lifetime of the channel and MUST not be included in a channel request.

The normalized contact ID representing who last modified the subject, or the empty string if it is not known.

This property replaces the subject-contact Telepathy property of Text channels, as Telepathy properties are soon to be deprecated completely.

The handle corresponding to Actor, or 0 if the Actor is unknown.

A unix timestamp indicating when the subject was last modified, or INT_MAX64 if unknown.

This property replaces the subject-timestamp Telepathy property of Text channels, as Telepathy properties are soon to be deprecated completely.

TRUE if the Subject property can be set by the user by calling SetSubject, otherwise FALSE.

If implementations are unsure of what this value should be it SHOULD still be set to what it believes the value is. As a result, clients should be aware that SetSubject can still fail even with this property set to TRUE.

In XMPP it is impossible to know whether an occupant can set the subject as XMPP server implementations are wildly inconsistent.
telepathy-qt-0.9.6~git1/TelepathyQt/0000775000175000017500000000000012470405660015214 5ustar jrjrtelepathy-qt-0.9.6~git1/TelepathyQt/stable-interfaces.xml0000664000175000017500000000220612470405660021331 0ustar jrjr Telepathy D-Bus Interface Specification, TelepathyQt copy 0.17.7 telepathy-qt-0.9.6~git1/TelepathyQt/groups.dox0000664000175000017500000000765412470405660017263 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \defgroup clientsideproxies Client-side proxies * * Proxy objects representing remote service objects accessed via D-Bus. * * In addition to providing direct access to methods, signals and properties * exported by the remote objects, some of these proxies offer features like * automatic inspection of remote object capabilities, property tracking, * backwards compatibility helpers for older services and other utilities. */ /** * \defgroup clientaccount Account proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy account objects and their * optional interfaces. */ /** * \defgroup clientam Account manager proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy account manager objects and their * optional interfaces. */ /** * \defgroup clientchannel Channel proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy Channel objects and their * optional interfaces. */ /** * \defgroup clientchanneldispatcher ChannelDispatcher proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy ChannelDispatcher objects and * their optional interfaces. */ /** * \defgroup clientchanneldispatchoperation ChannelDispatchOperation proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy ChannelDispatchOperation objects * and their optional interfaces. */ /** * \defgroup clientchannelrequest ChannelRequest proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy ChannelRequest objects and their * optional interfaces. */ /** * \defgroup clientclient Client proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy Client objects (approvers, * handlers and observers) and their optional interfaces. */ /** * \defgroup clientcm Connection manager proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy ConnectionManager objects and * their optional interfaces. */ /** * \defgroup clientconn Connection proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy Connection objects and their * optional interfaces. */ /** * \defgroup servicesideimpl Service-side implementation * * Classes to implement service D-Bus objects. */ /** * \defgroup servicechannel Channel service implementation * \ingroup servicesideimpl * * Classes to implement Telepathy Channel objects and their * optional interfaces. */ /** * \defgroup servicecm Connection manager service implementation * \ingroup servicesideimpl * * Classes to implement Telepathy ConnectionManager objects and their * optional interfaces. */ /** * \defgroup serviceconn Connection service implementation * \ingroup servicesideimpl * * Classes to implement Telepathy Connection objects and their * optional interfaces. */ /** * \defgroup wrappers Wrapper classes * * Wrapper classes representing a Telepathy type. */ /** * \defgroup utils Utililty classes * * Utility classes. */ telepathy-qt-0.9.6~git1/TelepathyQt/channel.cpp0000664000175000017500000037644212470405660017350 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/channel-internal.h" #include "TelepathyQt/_gen/cli-channel-body.hpp" #include "TelepathyQt/_gen/cli-channel.moc.hpp" #include "TelepathyQt/_gen/channel.moc.hpp" #include "TelepathyQt/_gen/channel-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/future-internal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { using TpFuture::Client::ChannelInterfaceMergeableConferenceInterface; using TpFuture::Client::ChannelInterfaceSplittableInterface; struct TP_QT_NO_EXPORT Channel::Private { Private(Channel *parent, const ConnectionPtr &connection, const QVariantMap &immutableProperties); ~Private(); static void introspectMain(Private *self); void introspectMainProperties(); void introspectMainFallbackChannelType(); void introspectMainFallbackHandle(); void introspectMainFallbackInterfaces(); void introspectGroup(); void introspectGroupFallbackFlags(); void introspectGroupFallbackMembers(); void introspectGroupFallbackLocalPendingWithInfo(); void introspectGroupFallbackSelfHandle(); void introspectConference(); static void introspectConferenceInitialInviteeContacts(Private *self); void continueIntrospection(); void extractMainProps(const QVariantMap &props); void extract0176GroupProps(const QVariantMap &props); void nowHaveInterfaces(); void nowHaveInitialMembers(); bool setGroupFlags(uint groupFlags); void buildContacts(); void doMembersChangedDetailed(const UIntList &, const UIntList &, const UIntList &, const UIntList &, const QVariantMap &); void processMembersChanged(); void updateContacts(const QList &contacts = QList()); bool fakeGroupInterfaceIfNeeded(); void setReady(); QString groupMemberChangeDetailsTelepathyError( const GroupMemberChangeDetails &details); inline ChannelInterfaceMergeableConferenceInterface *mergeableConferenceInterface( InterfaceSupportedChecking check = CheckInterfaceSupported) const { return parent->optionalInterface(check); } inline ChannelInterfaceSplittableInterface *splittableInterface( InterfaceSupportedChecking check = CheckInterfaceSupported) const { return parent->optionalInterface(check); } void processConferenceChannelRemoved(); struct GroupMembersChangedInfo; struct ConferenceChannelRemovedInfo; // Public object Channel *parent; // Instance of generated interface class Client::ChannelInterface *baseInterface; // Mandatory properties interface proxy Client::DBus::PropertiesInterface *properties; // Owning connection - it can be a SharedPtr as Connection does not cache // channels ConnectionPtr connection; QVariantMap immutableProperties; // Optional interface proxies Client::ChannelInterfaceGroupInterface *group; Client::ChannelInterfaceConferenceInterface *conference; ReadinessHelper *readinessHelper; // Introspection QQueue introspectQueue; // Introspected properties // Main interface QString channelType; uint targetHandleType; uint targetHandle; QString targetId; ContactPtr targetContact; bool requested; uint initiatorHandle; ContactPtr initiatorContact; // Group flags uint groupFlags; bool usingMembersChangedDetailed; // Group member introspection bool groupHaveMembers; bool buildingContacts; // Queue of received MCD signals to process QQueue groupMembersChangedQueue; GroupMembersChangedInfo *currentGroupMembersChangedInfo; // Pending from the MCD signal currently processed, but contacts not yet built QSet pendingGroupMembers; QSet pendingGroupLocalPendingMembers; QSet pendingGroupRemotePendingMembers; UIntList groupMembersToRemove; UIntList groupLocalPendingMembersToRemove; UIntList groupRemotePendingMembersToRemove; // Initial members UIntList groupInitialMembers; LocalPendingInfoList groupInitialLP; UIntList groupInitialRP; // Current members QHash groupContacts; QHash groupLocalPendingContacts; QHash groupRemotePendingContacts; // Stored change info QHash groupLocalPendingContactsChangeInfo; GroupMemberChangeDetails groupSelfContactRemoveInfo; // Group handle owners bool groupAreHandleOwnersAvailable; HandleOwnerMap groupHandleOwners; // Group self identity bool pendingRetrieveGroupSelfContact; bool groupIsSelfHandleTracked; uint groupSelfHandle; ContactPtr groupSelfContact; // Conference bool introspectingConference; QHash conferenceChannels; QHash conferenceInitialChannels; QString conferenceInvitationMessage; QHash conferenceOriginalChannels; UIntList conferenceInitialInviteeHandles; Contacts conferenceInitialInviteeContacts; QQueue conferenceChannelRemovedQueue; bool buildingConferenceChannelRemovedActorContact; static const QString keyActor; }; struct TP_QT_NO_EXPORT Channel::Private::GroupMembersChangedInfo { GroupMembersChangedInfo(const UIntList &added, const UIntList &removed, const UIntList &localPending, const UIntList &remotePending, const QVariantMap &details) : added(added), removed(removed), localPending(localPending), remotePending(remotePending), details(details), // TODO most of these probably should be removed once the rest of the code using them is sanitized actor(qdbus_cast(details.value(keyActor))), reason(qdbus_cast(details.value(keyChangeReason))), message(qdbus_cast(details.value(keyMessage))) { } UIntList added; UIntList removed; UIntList localPending; UIntList remotePending; QVariantMap details; uint actor; uint reason; QString message; static const QString keyChangeReason; static const QString keyMessage; static const QString keyContactIds; }; struct TP_QT_NO_EXPORT Channel::Private::ConferenceChannelRemovedInfo { ConferenceChannelRemovedInfo(const QDBusObjectPath &channelPath, const QVariantMap &details) : channelPath(channelPath), details(details) { } QDBusObjectPath channelPath; QVariantMap details; }; const QString Channel::Private::keyActor(QLatin1String("actor")); const QString Channel::Private::GroupMembersChangedInfo::keyChangeReason( QLatin1String("change-reason")); const QString Channel::Private::GroupMembersChangedInfo::keyMessage(QLatin1String("message")); const QString Channel::Private::GroupMembersChangedInfo::keyContactIds(QLatin1String("contact-ids")); Channel::Private::Private(Channel *parent, const ConnectionPtr &connection, const QVariantMap &immutableProperties) : parent(parent), baseInterface(new Client::ChannelInterface(parent)), properties(parent->interface()), connection(connection), immutableProperties(immutableProperties), group(0), conference(0), readinessHelper(parent->readinessHelper()), targetHandleType(0), targetHandle(0), requested(false), initiatorHandle(0), groupFlags(0), usingMembersChangedDetailed(false), groupHaveMembers(false), buildingContacts(false), currentGroupMembersChangedInfo(0), groupAreHandleOwnersAvailable(false), pendingRetrieveGroupSelfContact(false), groupIsSelfHandleTracked(false), groupSelfHandle(0), introspectingConference(false), buildingConferenceChannelRemovedActorContact(false) { debug() << "Creating new Channel:" << parent->objectPath(); if (connection->isValid()) { debug() << " Connecting to Channel::Closed() signal"; parent->connect(baseInterface, SIGNAL(Closed()), SLOT(onClosed())); debug() << " Connection to owning connection's lifetime signals"; parent->connect(connection.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onConnectionInvalidated())); } else { warning() << "Connection given as the owner for a Channel was " "invalid! Channel will be stillborn."; parent->invalidate(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Connection given as the owner of this channel was invalid")); } ReadinessHelper::Introspectables introspectables; // As Channel does not have predefined statuses let's simulate one (0) ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMain, this); introspectables[FeatureCore] = introspectableCore; // As Channel does not have predefined statuses let's simulate one (0) ReadinessHelper::Introspectable introspectableConferenceInitialInviteeContacts( QSet() << 0, // makesSenseForStatuses Features() << FeatureCore, // dependsOnFeatures QStringList() << TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectConferenceInitialInviteeContacts, this); introspectables[FeatureConferenceInitialInviteeContacts] = introspectableConferenceInitialInviteeContacts; readinessHelper->addIntrospectables(introspectables); } Channel::Private::~Private() { delete currentGroupMembersChangedInfo; foreach (GroupMembersChangedInfo *info, groupMembersChangedQueue) { delete info; } foreach (ConferenceChannelRemovedInfo *info, conferenceChannelRemovedQueue) { delete info; } } void Channel::Private::introspectMain(Channel::Private *self) { // Make sure connection object is ready, as we need to use some methods that // are only available after connection object gets ready. debug() << "Calling Connection::becomeReady()"; self->parent->connect(self->connection->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onConnectionReady(Tp::PendingOperation*))); } void Channel::Private::introspectMainProperties() { QVariantMap props; QString key; bool needIntrospectMainProps = false; const unsigned numNames = 8; const static QString names[numNames] = { QLatin1String("ChannelType"), QLatin1String("Interfaces"), QLatin1String("TargetHandleType"), QLatin1String("TargetHandle"), QLatin1String("TargetID"), QLatin1String("Requested"), QLatin1String("InitiatorHandle"), QLatin1String("InitiatorID") }; const static QString qualifiedNames[numNames] = { TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL + QLatin1String(".Interfaces"), TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), TP_QT_IFACE_CHANNEL + QLatin1String(".Requested"), TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle"), TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorID") }; for (unsigned i = 0; i < numNames; ++i) { const QString &qualified = qualifiedNames[i]; if (!immutableProperties.contains(qualified)) { needIntrospectMainProps = true; break; } props.insert(names[i], immutableProperties.value(qualified)); } // Save Requested and InitiatorHandle here, so even if the GetAll return doesn't have them but // the given immutable props do (eg. due to the PendingChannel fallback guesses) we use them requested = qdbus_cast(props[QLatin1String("Requested")]); initiatorHandle = qdbus_cast(props[QLatin1String("InitiatorHandle")]); if (props.contains(QLatin1String("InitiatorID"))) { QString initiatorId = qdbus_cast(props[QLatin1String("InitiatorID")]); connection->lowlevel()->injectContactId(initiatorHandle, initiatorId); } if (needIntrospectMainProps) { debug() << "Calling Properties::GetAll(Channel)"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( properties->GetAll(TP_QT_IFACE_CHANNEL), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotMainProperties(QDBusPendingCallWatcher*))); } else { extractMainProps(props); continueIntrospection(); } } void Channel::Private::introspectMainFallbackChannelType() { debug() << "Calling Channel::GetChannelType()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(baseInterface->GetChannelType(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotChannelType(QDBusPendingCallWatcher*))); } void Channel::Private::introspectMainFallbackHandle() { debug() << "Calling Channel::GetHandle()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(baseInterface->GetHandle(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotHandle(QDBusPendingCallWatcher*))); } void Channel::Private::introspectMainFallbackInterfaces() { debug() << "Calling Channel::GetInterfaces()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(baseInterface->GetInterfaces(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotInterfaces(QDBusPendingCallWatcher*))); } void Channel::Private::introspectGroup() { Q_ASSERT(properties != 0); if (!group) { group = parent->interface(); Q_ASSERT(group != 0); } debug() << "Introspecting Channel.Interface.Group for" << parent->objectPath(); parent->connect(group, SIGNAL(GroupFlagsChanged(uint,uint)), SLOT(onGroupFlagsChanged(uint,uint))); parent->connect(group, SIGNAL(MembersChanged(QString,Tp::UIntList, Tp::UIntList,Tp::UIntList, Tp::UIntList,uint,uint)), SLOT(onMembersChanged(QString,Tp::UIntList, Tp::UIntList,Tp::UIntList, Tp::UIntList,uint,uint))); parent->connect(group, SIGNAL(MembersChangedDetailed(Tp::UIntList, Tp::UIntList,Tp::UIntList, Tp::UIntList,QVariantMap)), SLOT(onMembersChangedDetailed(Tp::UIntList, Tp::UIntList,Tp::UIntList, Tp::UIntList,QVariantMap))); parent->connect(group, SIGNAL(HandleOwnersChanged(Tp::HandleOwnerMap, Tp::UIntList)), SLOT(onHandleOwnersChanged(Tp::HandleOwnerMap, Tp::UIntList))); parent->connect(group, SIGNAL(SelfHandleChanged(uint)), SLOT(onSelfHandleChanged(uint))); debug() << "Calling Properties::GetAll(Channel.Interface.Group)"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( properties->GetAll(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotGroupProperties(QDBusPendingCallWatcher*))); } void Channel::Private::introspectGroupFallbackFlags() { Q_ASSERT(group != 0); debug() << "Calling Channel.Interface.Group::GetGroupFlags()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(group->GetGroupFlags(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotGroupFlags(QDBusPendingCallWatcher*))); } void Channel::Private::introspectGroupFallbackMembers() { Q_ASSERT(group != 0); debug() << "Calling Channel.Interface.Group::GetAllMembers()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(group->GetAllMembers(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotAllMembers(QDBusPendingCallWatcher*))); } void Channel::Private::introspectGroupFallbackLocalPendingWithInfo() { Q_ASSERT(group != 0); debug() << "Calling Channel.Interface.Group::GetLocalPendingMembersWithInfo()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(group->GetLocalPendingMembersWithInfo(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotLocalPendingMembersWithInfo(QDBusPendingCallWatcher*))); } void Channel::Private::introspectGroupFallbackSelfHandle() { Q_ASSERT(group != 0); debug() << "Calling Channel.Interface.Group::GetSelfHandle()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(group->GetSelfHandle(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotSelfHandle(QDBusPendingCallWatcher*))); } void Channel::Private::introspectConference() { Q_ASSERT(properties != 0); Q_ASSERT(conference == 0); debug() << "Introspecting Conference interface"; conference = parent->interface(); Q_ASSERT(conference != 0); introspectingConference = true; debug() << "Connecting to Channel.Interface.Conference.ChannelMerged/Removed"; parent->connect(conference, SIGNAL(ChannelMerged(QDBusObjectPath,uint,QVariantMap)), SLOT(onConferenceChannelMerged(QDBusObjectPath,uint,QVariantMap))); parent->connect(conference, SIGNAL(ChannelRemoved(QDBusObjectPath,QVariantMap)), SLOT(onConferenceChannelRemoved(QDBusObjectPath,QVariantMap))); debug() << "Calling Properties::GetAll(Channel.Interface.Conference)"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( properties->GetAll(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotConferenceProperties(QDBusPendingCallWatcher*))); } void Channel::Private::introspectConferenceInitialInviteeContacts(Private *self) { if (!self->conferenceInitialInviteeHandles.isEmpty()) { ContactManagerPtr manager = self->connection->contactManager(); PendingContacts *pendingContacts = manager->contactsForHandles( self->conferenceInitialInviteeHandles); self->parent->connect(pendingContacts, SIGNAL(finished(Tp::PendingOperation *)), SLOT(gotConferenceInitialInviteeContacts(Tp::PendingOperation *))); } else { self->readinessHelper->setIntrospectCompleted( FeatureConferenceInitialInviteeContacts, true); } } void Channel::Private::continueIntrospection() { if (introspectQueue.isEmpty()) { // this should always be true, but let's make sure if (!parent->isReady(Channel::FeatureCore)) { if (groupMembersChangedQueue.isEmpty() && !buildingContacts && !introspectingConference) { debug() << "Both the IS and the MCD queue empty for the first time. Ready."; setReady(); } else { debug() << "Introspection done before contacts done - contacts sets ready"; } } } else { (this->*(introspectQueue.dequeue()))(); } } void Channel::Private::extractMainProps(const QVariantMap &props) { const static QString keyChannelType(QLatin1String("ChannelType")); const static QString keyInterfaces(QLatin1String("Interfaces")); const static QString keyTargetHandle(QLatin1String("TargetHandle")); const static QString keyTargetHandleType(QLatin1String("TargetHandleType")); bool haveProps = props.size() >= 4 && props.contains(keyChannelType) && !qdbus_cast(props[keyChannelType]).isEmpty() && props.contains(keyInterfaces) && props.contains(keyTargetHandle) && props.contains(keyTargetHandleType); if (!haveProps) { warning() << "Channel properties specified in 0.17.7 not found"; introspectQueue.enqueue(&Private::introspectMainFallbackChannelType); introspectQueue.enqueue(&Private::introspectMainFallbackHandle); introspectQueue.enqueue(&Private::introspectMainFallbackInterfaces); } else { parent->setInterfaces(qdbus_cast(props[keyInterfaces])); readinessHelper->setInterfaces(parent->interfaces()); channelType = qdbus_cast(props[keyChannelType]); targetHandle = qdbus_cast(props[keyTargetHandle]); targetHandleType = qdbus_cast(props[keyTargetHandleType]); const static QString keyTargetId(QLatin1String("TargetID")); const static QString keyRequested(QLatin1String("Requested")); const static QString keyInitiatorHandle(QLatin1String("InitiatorHandle")); const static QString keyInitiatorId(QLatin1String("InitiatorID")); if (props.contains(keyTargetId)) { targetId = qdbus_cast(props[keyTargetId]); if (targetHandleType == HandleTypeContact) { connection->lowlevel()->injectContactId(targetHandle, targetId); } } if (props.contains(keyRequested)) { requested = qdbus_cast(props[keyRequested]); } if (props.contains(keyInitiatorHandle)) { initiatorHandle = qdbus_cast(props[keyInitiatorHandle]); } if (props.contains(keyInitiatorId)) { QString initiatorId = qdbus_cast(props[keyInitiatorId]); connection->lowlevel()->injectContactId(initiatorHandle, initiatorId); } if (!fakeGroupInterfaceIfNeeded() && !parent->interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP) && initiatorHandle) { // No group interface, so nobody will build the poor fellow for us. Will do it ourselves // out of pity for him. // TODO: needs testing. I would imagine some of the elaborate updateContacts logic // tripping over with just this. buildContacts(); } nowHaveInterfaces(); } debug() << "Have initiator handle:" << (initiatorHandle ? "yes" : "no"); } void Channel::Private::extract0176GroupProps(const QVariantMap &props) { const static QString keyGroupFlags(QLatin1String("GroupFlags")); const static QString keyHandleOwners(QLatin1String("HandleOwners")); const static QString keyLPMembers(QLatin1String("LocalPendingMembers")); const static QString keyMembers(QLatin1String("Members")); const static QString keyRPMembers(QLatin1String("RemotePendingMembers")); const static QString keySelfHandle(QLatin1String("SelfHandle")); bool haveProps = props.size() >= 6 && (props.contains(keyGroupFlags) && (qdbus_cast(props[keyGroupFlags]) & ChannelGroupFlagProperties)) && props.contains(keyHandleOwners) && props.contains(keyLPMembers) && props.contains(keyMembers) && props.contains(keyRPMembers) && props.contains(keySelfHandle); if (!haveProps) { warning() << " Properties specified in 0.17.6 not found"; warning() << " Handle owners and self handle tracking disabled"; introspectQueue.enqueue(&Private::introspectGroupFallbackFlags); introspectQueue.enqueue(&Private::introspectGroupFallbackMembers); introspectQueue.enqueue(&Private::introspectGroupFallbackLocalPendingWithInfo); introspectQueue.enqueue(&Private::introspectGroupFallbackSelfHandle); } else { debug() << " Found properties specified in 0.17.6"; groupAreHandleOwnersAvailable = true; groupIsSelfHandleTracked = true; setGroupFlags(qdbus_cast(props[keyGroupFlags])); groupHandleOwners = qdbus_cast(props[keyHandleOwners]); groupInitialMembers = qdbus_cast(props[keyMembers]); groupInitialLP = qdbus_cast(props[keyLPMembers]); groupInitialRP = qdbus_cast(props[keyRPMembers]); uint propSelfHandle = qdbus_cast(props[keySelfHandle]); // Don't overwrite the self handle we got from the Connection with 0 if (propSelfHandle) { groupSelfHandle = propSelfHandle; } nowHaveInitialMembers(); } } void Channel::Private::nowHaveInterfaces() { debug() << "Channel has" << parent->interfaces().size() << "optional interfaces:" << parent->interfaces(); QStringList interfaces = parent->interfaces(); if (interfaces.contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { introspectQueue.enqueue(&Private::introspectGroup); } if (interfaces.contains(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE)) { introspectQueue.enqueue(&Private::introspectConference); } } void Channel::Private::nowHaveInitialMembers() { // Must be called with no contacts anywhere in the first place Q_ASSERT(!parent->isReady(Channel::FeatureCore)); Q_ASSERT(!buildingContacts); Q_ASSERT(pendingGroupMembers.isEmpty()); Q_ASSERT(pendingGroupLocalPendingMembers.isEmpty()); Q_ASSERT(pendingGroupRemotePendingMembers.isEmpty()); Q_ASSERT(groupContacts.isEmpty()); Q_ASSERT(groupLocalPendingContacts.isEmpty()); Q_ASSERT(groupRemotePendingContacts.isEmpty()); // Set groupHaveMembers so we start queueing fresh MCD signals Q_ASSERT(!groupHaveMembers); groupHaveMembers = true; // Synthesize MCD for current + RP groupMembersChangedQueue.enqueue(new GroupMembersChangedInfo( groupInitialMembers, // Members UIntList(), // Removed - obviously, none UIntList(), // LP - will be handled separately, see below groupInitialRP, // Remote pending QVariantMap())); // No details for members + RP // Synthesize one MCD for each initial LP member - they might have different details foreach (const LocalPendingInfo &info, groupInitialLP) { QVariantMap details; if (info.actor != 0) { details.insert(QLatin1String("actor"), info.actor); } if (info.reason != ChannelGroupChangeReasonNone) { details.insert(QLatin1String("change-reason"), info.reason); } if (!info.message.isEmpty()) { details.insert(QLatin1String("message"), info.message); } groupMembersChangedQueue.enqueue(new GroupMembersChangedInfo(UIntList(), UIntList(), UIntList() << info.toBeAdded, UIntList(), details)); } // At least our added MCD event to process processMembersChanged(); } bool Channel::Private::setGroupFlags(uint newGroupFlags) { if (groupFlags == newGroupFlags) { return false; } groupFlags = newGroupFlags; // this shouldn't happen but let's make sure if (!parent->interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { return false; } if ((groupFlags & ChannelGroupFlagMembersChangedDetailed) && !usingMembersChangedDetailed) { usingMembersChangedDetailed = true; debug() << "Starting to exclusively listen to MembersChangedDetailed for" << parent->objectPath(); parent->disconnect(group, SIGNAL(MembersChanged(QString,Tp::UIntList, Tp::UIntList,Tp::UIntList, Tp::UIntList,uint,uint)), parent, SLOT(onMembersChanged(QString,Tp::UIntList, Tp::UIntList,Tp::UIntList, Tp::UIntList,uint,uint))); } else if (!(groupFlags & ChannelGroupFlagMembersChangedDetailed) && usingMembersChangedDetailed) { warning() << " Channel service did spec-incompliant removal of MCD from GroupFlags"; usingMembersChangedDetailed = false; parent->connect(group, SIGNAL(MembersChanged(QString,Tp::UIntList, Tp::UIntList,Tp::UIntList, Tp::UIntList,uint,uint)), parent, SLOT(onMembersChanged(QString,Tp::UIntList, Tp::UIntList,Tp::UIntList, Tp::UIntList,uint,uint))); } return true; } void Channel::Private::buildContacts() { buildingContacts = true; ContactManagerPtr manager = connection->contactManager(); UIntList toBuild = QSet(pendingGroupMembers + pendingGroupLocalPendingMembers + pendingGroupRemotePendingMembers).toList(); if (currentGroupMembersChangedInfo && currentGroupMembersChangedInfo->actor != 0) { toBuild.append(currentGroupMembersChangedInfo->actor); } if (!initiatorContact && initiatorHandle) { // No initiator contact, but Yes initiator handle - might do something about it with just // that information toBuild.append(initiatorHandle); } if (!targetContact && targetHandleType == HandleTypeContact && targetHandle != 0) { toBuild.append(targetHandle); } // always try to retrieve selfContact and check if it changed on // updateContacts or on gotContacts, in case we were not able to retrieve it if (groupSelfHandle) { toBuild.append(groupSelfHandle); } // group self handle changed to 0 <- strange but it may happen, and contacts // were being built at the time, so check now if (toBuild.isEmpty()) { if (!groupSelfHandle && groupSelfContact) { groupSelfContact.reset(); if (parent->isReady(Channel::FeatureCore)) { emit parent->groupSelfContactChanged(); } } buildingContacts = false; return; } PendingContacts *pendingContacts = manager->contactsForHandles( toBuild); parent->connect(pendingContacts, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotContacts(Tp::PendingOperation*))); } void Channel::Private::processMembersChanged() { Q_ASSERT(!buildingContacts); if (groupMembersChangedQueue.isEmpty()) { if (pendingRetrieveGroupSelfContact) { pendingRetrieveGroupSelfContact = false; // nothing queued but selfContact changed buildContacts(); return; } if (!parent->isReady(Channel::FeatureCore)) { if (introspectQueue.isEmpty()) { debug() << "Both the MCD and the introspect queue empty for the first time. Ready!"; if (initiatorHandle && !initiatorContact) { warning() << " Unable to create contact object for initiator with handle" << initiatorHandle; } if (targetHandleType == HandleTypeContact && targetHandle != 0 && !targetContact) { warning() << " Unable to create contact object for target with handle" << targetHandle; } if (groupSelfHandle && !groupSelfContact) { warning() << " Unable to create contact object for self handle" << groupSelfHandle; } continueIntrospection(); } else { debug() << "Contact queue empty but introspect queue isn't. IS will set ready."; } } return; } Q_ASSERT(pendingGroupMembers.isEmpty()); Q_ASSERT(pendingGroupLocalPendingMembers.isEmpty()); Q_ASSERT(pendingGroupRemotePendingMembers.isEmpty()); // always set this to false here, as buildContacts will always try to // retrieve the selfContact and updateContacts will check if the built // contact is the same as the current contact. pendingRetrieveGroupSelfContact = false; currentGroupMembersChangedInfo = groupMembersChangedQueue.dequeue(); foreach (uint handle, currentGroupMembersChangedInfo->added) { if (!groupContacts.contains(handle)) { pendingGroupMembers.insert(handle); } // the member was added to current members, check if it was in the // local/pending lists and if true, schedule for removal from that list if (groupLocalPendingContacts.contains(handle)) { groupLocalPendingMembersToRemove.append(handle); } else if(groupRemotePendingContacts.contains(handle)) { groupRemotePendingMembersToRemove.append(handle); } } foreach (uint handle, currentGroupMembersChangedInfo->localPending) { if (!groupLocalPendingContacts.contains(handle)) { pendingGroupLocalPendingMembers.insert(handle); } } foreach (uint handle, currentGroupMembersChangedInfo->remotePending) { if (!groupRemotePendingContacts.contains(handle)) { pendingGroupRemotePendingMembers.insert(handle); } } foreach (uint handle, currentGroupMembersChangedInfo->removed) { groupMembersToRemove.append(handle); } // Always go through buildContacts - we might have a self/initiator/whatever handle to build buildContacts(); } void Channel::Private::updateContacts(const QList &contacts) { Contacts groupContactsAdded; Contacts groupLocalPendingContactsAdded; Contacts groupRemotePendingContactsAdded; ContactPtr actorContact; bool selfContactUpdated = false; debug() << "Entering Chan::Priv::updateContacts() with" << contacts.size() << "contacts"; // FIXME: simplify. Some duplication of logic present. foreach (ContactPtr contact, contacts) { uint handle = contact->handle()[0]; if (pendingGroupMembers.contains(handle)) { groupContactsAdded.insert(contact); groupContacts[handle] = contact; } else if (pendingGroupLocalPendingMembers.contains(handle)) { groupLocalPendingContactsAdded.insert(contact); groupLocalPendingContacts[handle] = contact; // FIXME: should set the details and actor here too groupLocalPendingContactsChangeInfo[handle] = GroupMemberChangeDetails(); } else if (pendingGroupRemotePendingMembers.contains(handle)) { groupRemotePendingContactsAdded.insert(contact); groupRemotePendingContacts[handle] = contact; } if (groupSelfHandle == handle && groupSelfContact != contact) { groupSelfContact = contact; selfContactUpdated = true; } if (!initiatorContact && initiatorHandle == handle) { // No initiator contact stored, but there's a contact for the initiator handle // We can use that! initiatorContact = contact; } if (!targetContact && targetHandleType == HandleTypeContact && targetHandle == handle) { targetContact = contact; if (targetId.isEmpty()) { // For some reason, TargetID was missing from the property map. We can initialize it // here in that case. targetId = targetContact->id(); } } if (currentGroupMembersChangedInfo && currentGroupMembersChangedInfo->actor == contact->handle()[0]) { actorContact = contact; } } if (!groupSelfHandle && groupSelfContact) { groupSelfContact.reset(); selfContactUpdated = true; } pendingGroupMembers.clear(); pendingGroupLocalPendingMembers.clear(); pendingGroupRemotePendingMembers.clear(); // FIXME: This shouldn't be needed. Clearer would be to first scan for the actor being present // in the contacts supplied. foreach (ContactPtr contact, contacts) { uint handle = contact->handle()[0]; if (groupLocalPendingContactsChangeInfo.contains(handle)) { groupLocalPendingContactsChangeInfo[handle] = GroupMemberChangeDetails(actorContact, currentGroupMembersChangedInfo ? currentGroupMembersChangedInfo->details : QVariantMap()); } } Contacts groupContactsRemoved; ContactPtr contactToRemove; foreach (uint handle, groupMembersToRemove) { if (groupContacts.contains(handle)) { contactToRemove = groupContacts[handle]; groupContacts.remove(handle); } else if (groupLocalPendingContacts.contains(handle)) { contactToRemove = groupLocalPendingContacts[handle]; groupLocalPendingContacts.remove(handle); } else if (groupRemotePendingContacts.contains(handle)) { contactToRemove = groupRemotePendingContacts[handle]; groupRemotePendingContacts.remove(handle); } if (groupLocalPendingContactsChangeInfo.contains(handle)) { groupLocalPendingContactsChangeInfo.remove(handle); } if (contactToRemove) { groupContactsRemoved.insert(contactToRemove); } } groupMembersToRemove.clear(); // FIXME: drop the LPToRemove and RPToRemove sets - they're redundant foreach (uint handle, groupLocalPendingMembersToRemove) { groupLocalPendingContacts.remove(handle); } groupLocalPendingMembersToRemove.clear(); foreach (uint handle, groupRemotePendingMembersToRemove) { groupRemotePendingContacts.remove(handle); } groupRemotePendingMembersToRemove.clear(); if (!groupContactsAdded.isEmpty() || !groupLocalPendingContactsAdded.isEmpty() || !groupRemotePendingContactsAdded.isEmpty() || !groupContactsRemoved.isEmpty()) { GroupMemberChangeDetails details( actorContact, currentGroupMembersChangedInfo ? currentGroupMembersChangedInfo->details : QVariantMap()); if (currentGroupMembersChangedInfo && currentGroupMembersChangedInfo->removed.contains(groupSelfHandle)) { // Update groupSelfContactRemoveInfo with the proper actor in case // the actor was not available by the time onMembersChangedDetailed // was called. groupSelfContactRemoveInfo = details; } if (parent->isReady(Channel::FeatureCore)) { // Channel is ready, we can signal membership changes to the outside world without // confusing anyone's fragile logic. emit parent->groupMembersChanged( groupContactsAdded, groupLocalPendingContactsAdded, groupRemotePendingContactsAdded, groupContactsRemoved, details); } } delete currentGroupMembersChangedInfo; currentGroupMembersChangedInfo = 0; if (selfContactUpdated && parent->isReady(Channel::FeatureCore)) { emit parent->groupSelfContactChanged(); } processMembersChanged(); } bool Channel::Private::fakeGroupInterfaceIfNeeded() { if (parent->interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { return false; } else if (targetHandleType != HandleTypeContact) { return false; } // fake group interface if (connection->selfHandle() && targetHandle) { // Fake groupSelfHandle and initial members, let the MCD handling take care of the rest // TODO connect to Connection::selfHandleChanged groupSelfHandle = connection->selfHandle(); groupInitialMembers = UIntList() << groupSelfHandle << targetHandle; debug().nospace() << "Faking a group on channel with self handle=" << groupSelfHandle << " and other handle=" << targetHandle; nowHaveInitialMembers(); } else { warning() << "Connection::selfHandle is 0 or targetHandle is 0, " "not faking a group on channel"; } return true; } void Channel::Private::setReady() { Q_ASSERT(!parent->isReady(Channel::FeatureCore)); debug() << "Channel fully ready"; debug() << " Channel type" << channelType; debug() << " Target handle" << targetHandle; debug() << " Target handle type" << targetHandleType; if (parent->interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { debug() << " Group: flags" << groupFlags; if (groupAreHandleOwnersAvailable) { debug() << " Group: Number of handle owner mappings" << groupHandleOwners.size(); } else { debug() << " Group: No handle owners property present"; } debug() << " Group: Number of current members" << groupContacts.size(); debug() << " Group: Number of local pending members" << groupLocalPendingContacts.size(); debug() << " Group: Number of remote pending members" << groupRemotePendingContacts.size(); debug() << " Group: Self handle" << groupSelfHandle << "tracked:" << (groupIsSelfHandleTracked ? "yes" : "no"); } readinessHelper->setIntrospectCompleted(FeatureCore, true); } QString Channel::Private::groupMemberChangeDetailsTelepathyError( const GroupMemberChangeDetails &details) { QString error; uint reason = details.reason(); switch (reason) { case ChannelGroupChangeReasonOffline: error = TP_QT_ERROR_OFFLINE; break; case ChannelGroupChangeReasonKicked: error = TP_QT_ERROR_CHANNEL_KICKED; break; case ChannelGroupChangeReasonBanned: error = TP_QT_ERROR_CHANNEL_BANNED; break; case ChannelGroupChangeReasonBusy: error = TP_QT_ERROR_BUSY; break; case ChannelGroupChangeReasonNoAnswer: error = TP_QT_ERROR_NO_ANSWER; break; case ChannelGroupChangeReasonPermissionDenied: error = TP_QT_ERROR_PERMISSION_DENIED; break; case ChannelGroupChangeReasonInvalidContact: error = TP_QT_ERROR_DOES_NOT_EXIST; break; // The following change reason are being mapped to default // case ChannelGroupChangeReasonNone: // case ChannelGroupChangeReasonInvited: // shouldn't happen // case ChannelGroupChangeReasonError: // case ChannelGroupChangeReasonRenamed: // case ChannelGroupChangeReasonSeparated: // shouldn't happen default: // let's use the actor handle and selfHandle here instead of the // contacts, as the contacts may not be ready. error = ((qdbus_cast(details.allDetails().value(QLatin1String("actor"))) == groupSelfHandle) ? TP_QT_ERROR_CANCELLED : TP_QT_ERROR_TERMINATED); break; } return error; } void Channel::Private::processConferenceChannelRemoved() { if (buildingConferenceChannelRemovedActorContact || conferenceChannelRemovedQueue.isEmpty()) { return; } ConferenceChannelRemovedInfo *info = conferenceChannelRemovedQueue.first(); if (!conferenceChannels.contains(info->channelPath.path())) { info = conferenceChannelRemovedQueue.dequeue(); delete info; processConferenceChannelRemoved(); return; } buildingConferenceChannelRemovedActorContact = true; if (info->details.contains(keyActor)) { ContactManagerPtr manager = connection->contactManager(); PendingContacts *pendingContacts = manager->contactsForHandles( UIntList() << qdbus_cast(info->details.value(keyActor))); parent->connect(pendingContacts, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotConferenceChannelRemovedActorContact(Tp::PendingOperation*))); } else { parent->gotConferenceChannelRemovedActorContact(0); } } struct TP_QT_NO_EXPORT Channel::GroupMemberChangeDetails::Private : public QSharedData { Private(const ContactPtr &actor, const QVariantMap &details) : actor(actor), details(details) {} ContactPtr actor; QVariantMap details; }; /** * \class Channel::GroupMemberChangeDetails * \ingroup clientchannel * \headerfile TelepathyQt/channel.h * * \brief The Channel::GroupMemberChangeDetails class represents the details of a group membership * change. * * Extended information is not always available; this will be reflected by * the return value of isValid(). */ /** * Constructs a new invalid GroupMemberChangeDetails instance. */ Channel::GroupMemberChangeDetails::GroupMemberChangeDetails() { } /** * Copy constructor. */ Channel::GroupMemberChangeDetails::GroupMemberChangeDetails(const GroupMemberChangeDetails &other) : mPriv(other.mPriv) { } /** * Class destructor. */ Channel::GroupMemberChangeDetails::~GroupMemberChangeDetails() { } /** * Assigns all information (validity, details) from other to this. */ Channel::GroupMemberChangeDetails &Channel::GroupMemberChangeDetails::operator=( const GroupMemberChangeDetails &other) { this->mPriv = other.mPriv; return *this; } /** * \fn bool Channel::GroupMemberChangeDetails::isValid() const * * Return whether the details are valid (have actually been received from the service). * * \return \c true if valid, \c false otherwise. */ /** * Return whether the details specify an actor. * * If present, actor() will return the contact object representing the person who made the change. * * \return \c true if the actor is known, \c false otherwise. * \sa actor() */ bool Channel::GroupMemberChangeDetails::hasActor() const { return isValid() && !mPriv->actor.isNull(); } /** * Return the contact object representing the person who made the change (actor), if known. * * \return A pointer to the Contact object, or a null ContactPtr if the actor is unknown. * \sa hasActor() */ ContactPtr Channel::GroupMemberChangeDetails::actor() const { return isValid() ? mPriv->actor : ContactPtr(); } /** * \fn bool Channel::GroupMemberChangeDetails::hasReason() const * * Return whether the details specify the reason for the change. * * \return \c true if the reason is known, \c false otherwise. * \sa reason() */ /** * \fn ChannelGroupChangeReason Channel::GroupMemberChangeDetails::reason() const * * Return the reason for the change, if known. * * \return The change reason as #ChannelGroupChangeReason, or #ChannelGroupChangeReasonNone * if the reason is unknown. * \sa hasReason() */ /** * \fn bool Channel::GroupMemberChangeDetails::hasMessage() const * * Return whether the details specify a human-readable message from the contact represented by * actor() pertaining to the change. * * \return \c true if the message is known, \c false otherwise. * \sa message() */ /** * \fn QString Channel::GroupMemberChangeDetails::message() const * * Return a human-readable message from the contact represented by actor() pertaining to the change, * if known. * * \return The message, or an empty string if the message is unknown. * \sa hasMessage() */ /** * \fn bool Channel::GroupMemberChangeDetails::hasError() const * * Return whether the details specify a D-Bus error describing the change. * * \return \c true if the error is known, \c false otherwise. * \sa error() */ /** * \fn QString Channel::GroupMemberChangeDetails::error() const * * Return the D-Bus error describing the change, if known. * * The D-Bus error provides more specific information than the reason() and should be used if * applicable. * * \return A D-Bus error describing the change, or an empty string if the error is unknown. * \sa hasError() */ /** * \fn bool Channel::GroupMemberChangeDetails::hasDebugMessage() const * * Return whether the details specify a debug message. * * \return \c true if debug message is present, \c false otherwise. * \sa debugMessage() */ /** * \fn QString Channel::GroupMemberChangeDetails::debugMessage() const * * Return the debug message specified by the details, if any. * * The debug message is purely informational, offered for display for bug reporting purposes, and * should not be attempted to be parsed. * * \return The debug message, or an empty string if there is none. * \sa hasDebugMessage() */ /** * Return a map containing all details of the group members change. * * This is useful for accessing domain-specific additional details. * * \return The details of the group members change as QVariantMap. */ QVariantMap Channel::GroupMemberChangeDetails::allDetails() const { return isValid() ? mPriv->details : QVariantMap(); } Channel::GroupMemberChangeDetails::GroupMemberChangeDetails(const ContactPtr &actor, const QVariantMap &details) : mPriv(new Private(actor, details)) { } /** * \class Channel * \ingroup clientchannel * \headerfile TelepathyQt/channel.h * * \brief The Channel class represents a Telepathy channel. * * All communication in the Telepathy framework is carried out via channel * objects. Specialized classes for some specific channel types such as * StreamedMediaChannel, TextChannel, FileTransferChannel are provided. * * The remote object accessor functions on this object (channelType(), targetHandleType(), * and so on) don't make any D-Bus calls; instead, they return/use * values cached from a previous introspection run. The introspection process * populates their values in the most efficient way possible based on what the * service implements. * * To avoid unnecessary D-Bus traffic, some accessors only return valid * information after specific features have been enabled. * For instance, to retrieve the initial invitee contacts in a conference channel, * it is necessary to enable the feature Channel::FeatureConferenceInitialInviteeContacts. * See the individual methods descriptions for more details. * * Channel features can be enabled by constructing a ChannelFactory and enabling * the desired features, and passing it to AccountManager, Account or ClientRegistrar * when creating them as appropriate. However, if a particular * feature is only ever used in a specific circumstance, such as an user opening * some settings dialog separate from the general view of the application, * features can be later enabled as needed by calling becomeReady() with the additional * features, and waiting for the resulting PendingOperation to finish. * * Each channel is owned by a connection. If the Connection object becomes invalidated * the Channel object will also get invalidated. * * \section chan_usage_sec Usage * * \subsection chan_create_sec Creating a channel object * * Channel objects can be created in various ways, but the preferred way is * trough Account channel creation methods such as Account::ensureTextChat(), * Account::createFileTransfer(), which uses the channel dispatcher. * * If you already know the object path, you can just call create(). * For example: * * \code * * ChannelPtr chan = Channel::create(connection, objectPath, * immutableProperties); * * \endcode * * \subsection chan_ready_sec Making channel ready to use * * A Channel object needs to become ready before usage, meaning that the * introspection process finished and the object accessors can be used. * * To make the object ready, use becomeReady() and wait for the * PendingOperation::finished() signal to be emitted. * * \code * * class MyClass : public QObject * { * QOBJECT * * public: * MyClass(QObject *parent = 0); * ~MyClass() { } * * private Q_SLOTS: * void onChannelReady(Tp::PendingOperation*); * * private: * ChannelPtr chan; * }; * * MyClass::MyClass(const ConnectionPtr &connection, * const QString &objectPath, const QVariantMap &immutableProperties) * : QObject(parent) * chan(Channel::create(connection, objectPath, immutableProperties)) * { * connect(chan->becomeReady(), * SIGNAL(finished(Tp::PendingOperation*)), * SLOT(onChannelReady(Tp::PendingOperation*))); * } * * void MyClass::onChannelReady(Tp::PendingOperation *op) * { * if (op->isError()) { * qWarning() << "Channel cannot become ready:" << * op->errorName() << "-" << op->errorMessage(); * return; * } * * // Channel is now ready * } * * \endcode * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the Channel * object usable. * * Note that this feature must be enabled in order to use most Channel methods. * See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature Channel::FeatureCore = Feature(QLatin1String(Channel::staticMetaObject.className()), 0, true); /** * Feature used in order to access the conference initial invitee contacts info. * * \sa conferenceInitialInviteeContacts() */ const Feature Channel::FeatureConferenceInitialInviteeContacts = Feature(QLatin1String(Channel::staticMetaObject.className()), 1, true); /** * Create a new Channel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A ChannelPtr object pointing to the newly created Channel object. * * \todo \a immutableProperties should be used to populate the corresponding accessors (such as * channelType()) already on construction, not only when making FeatureCore ready (fd.o #41654) */ ChannelPtr Channel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return ChannelPtr(new Channel(connection, objectPath, immutableProperties, Channel::FeatureCore)); } /** * Construct a new Channel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type. The corresponding introspectable should * depend on Channel::FeatureCore. */ Channel::Channel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : StatefulDBusProxy(connection->dbusConnection(), connection->busName(), objectPath, coreFeature), OptionalInterfaceFactory(this), mPriv(new Private(this, connection, immutableProperties)) { } /** * Class destructor. */ Channel::~Channel() { delete mPriv; } /** * Return the connection owning this channel. * * \return A pointer to the Connection object. */ ConnectionPtr Channel::connection() const { return mPriv->connection; } /** * Return the immutable properties of the channel. * * If the channel is ready (isReady(Channel::FeatureCore) returns true), the following keys are * guaranteed to be present: * org.freedesktop.Telepathy.Channel.ChannelType, * org.freedesktop.Telepathy.Channel.TargetHandleType, * org.freedesktop.Telepathy.Channel.TargetHandle and * org.freedesktop.Telepathy.Channel.Requested. * * The keys and values in this map are defined by the \telepathy_spec, * or by third-party extensions to that specification. * These are the properties that cannot change over the lifetime of the * channel; they're announced in the result of the request, for efficiency. * * \return The immutable properties as QVariantMap. */ QVariantMap Channel::immutableProperties() const { if (isReady(Channel::FeatureCore)) { QString key; key = TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"); if (!mPriv->immutableProperties.contains(key)) { mPriv->immutableProperties.insert(key, mPriv->channelType); } key = TP_QT_IFACE_CHANNEL + QLatin1String(".Interfaces"); if (!mPriv->immutableProperties.contains(key)) { mPriv->immutableProperties.insert(key, interfaces()); } key = TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"); if (!mPriv->immutableProperties.contains(key)) { mPriv->immutableProperties.insert(key, mPriv->targetHandleType); } key = TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"); if (!mPriv->immutableProperties.contains(key)) { mPriv->immutableProperties.insert(key, mPriv->targetHandle); } key = TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"); if (!mPriv->immutableProperties.contains(key)) { mPriv->immutableProperties.insert(key, mPriv->targetId); } key = TP_QT_IFACE_CHANNEL + QLatin1String(".Requested"); if (!mPriv->immutableProperties.contains(key)) { mPriv->immutableProperties.insert(key, mPriv->requested); } key = TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle"); if (!mPriv->immutableProperties.contains(key)) { mPriv->immutableProperties.insert(key, mPriv->initiatorHandle); } key = TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorID"); if (!mPriv->immutableProperties.contains(key) && !mPriv->initiatorContact.isNull()) { mPriv->immutableProperties.insert(key, mPriv->initiatorContact->id()); } } return mPriv->immutableProperties; } /** * Return the D-Bus interface name for the type of this channel. * * This method requires Channel::FeatureCore to be ready. * * \return The D-Bus interface name for the type of the channel. */ QString Channel::channelType() const { // Similarly, we don't want warnings triggered when using the type interface // proxies internally. if (!isReady(Channel::FeatureCore) && mPriv->channelType.isEmpty()) { warning() << "Channel::channelType() before the channel type has " "been received"; } else if (!isValid()) { warning() << "Channel::channelType() used with channel closed"; } return mPriv->channelType; } /** * Return the type of the handle returned by targetHandle() as specified in * #HandleType. * * This method requires Channel::FeatureCore to be ready. * * \return The target handle type as #HandleType. * \sa targetHandle(), targetId() */ HandleType Channel::targetHandleType() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::targetHandleType() used channel not ready"; } return (HandleType) mPriv->targetHandleType; } /** * Return the handle of the remote party with which this channel * communicates. * * This method requires Channel::FeatureCore to be ready. * * \return An integer representing the target handle, which is of the type * targetHandleType() indicates. * \sa targetHandleType(), targetId() */ uint Channel::targetHandle() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::targetHandle() used channel not ready"; } return mPriv->targetHandle; } /** * Return the persistent unique ID of the remote party with which this channel communicates. * * If targetHandleType() is #HandleTypeContact, this will be the ID of the remote contact, and * similarly the unique ID of the room when targetHandleType() is #HandleTypeRoom. * * This is not necessarily the best identifier to display to the user, though. In particular, for * contacts, their alias should be displayed instead. It can be used for matching channels and UI * elements for them across reconnects, though, at which point the old channels and contacts are * invalidated. * * This method requires Channel::FeatureCore to be ready. * * \return The target identifier. * \sa targetHandle(), targetContact() */ QString Channel::targetId() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::targetId() used, but the channel is not ready"; } return mPriv->targetId; } /** * Return the contact with which this channel communicates for its lifetime, if applicable. * * This method requires Channel::FeatureCore to be ready. * * \return A pointer to the Contact object, or a null ContactPtr if targetHandleType() is not * #HandleTypeContact. * \sa targetHandle(), targetId() */ ContactPtr Channel::targetContact() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::targetContact() used, but the channel is not ready"; } else if (targetHandleType() != HandleTypeContact) { warning() << "Channel::targetContact() used with targetHandleType() != Contact"; } return mPriv->targetContact; } /** * Return whether this channel was created in response to a * local request. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if the channel was created in response to a local request, * \c false otherwise. */ bool Channel::isRequested() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::isRequested() used channel not ready"; } return mPriv->requested; } /** * Return the contact who initiated this channel. * * This method requires Channel::FeatureCore to be ready. * * \return A pointer to the Contact object representing the contact who initiated the channel, * or a null ContactPtr if it can't be retrieved. */ ContactPtr Channel::initiatorContact() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::initiatorContact() used channel not ready"; } return mPriv->initiatorContact; } /** * Start an asynchronous request that this channel be closed. * * The returned PendingOperation object will signal the success or failure * of this request; under normal circumstances, it can be expected to * succeed. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa requestLeave() */ PendingOperation *Channel::requestClose() { // Closing a channel does not make sense if it is already closed, // just silently Return. if (!isValid()) { return new PendingSuccess(ChannelPtr(this)); } return new PendingVoid(mPriv->baseInterface->Close(), ChannelPtr(this)); } Channel::PendingLeave::PendingLeave(const ChannelPtr &chan, const QString &message, ChannelGroupChangeReason reason) : PendingOperation(chan) { Q_ASSERT(chan->mPriv->group != NULL); QDBusPendingCall call = chan->mPriv->group->RemoveMembersWithReason( UIntList() << chan->mPriv->groupSelfHandle, message, reason); connect(chan.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), this, SLOT(onChanInvalidated(Tp::DBusProxy*))); connect(new PendingVoid(call, chan), SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(onRemoveFinished(Tp::PendingOperation*))); } void Channel::PendingLeave::onChanInvalidated(Tp::DBusProxy *proxy) { if (isFinished()) { return; } debug() << "Finishing PendingLeave successfully as the channel was invalidated"; setFinished(); } void Channel::PendingLeave::onRemoveFinished(Tp::PendingOperation *op) { if (isFinished()) { return; } ChannelPtr chan = ChannelPtr::staticCast(object()); if (op->isValid()) { debug() << "We left the channel" << chan->objectPath(); ContactPtr c = chan->groupSelfContact(); if (chan->groupContacts().contains(c) || chan->groupLocalPendingContacts().contains(c) || chan->groupRemotePendingContacts().contains(c)) { debug() << "Waiting for self remove to be picked up"; connect(chan.data(), SIGNAL(groupMembersChanged(Tp::Contacts,Tp::Contacts,Tp::Contacts,Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)), this, SLOT(onMembersChanged(Tp::Contacts,Tp::Contacts,Tp::Contacts,Tp::Contacts))); } else { setFinished(); } return; } debug() << "Leave RemoveMembersWithReason failed with " << op->errorName() << op->errorMessage() << "- falling back to Close"; // If the channel has been closed or otherwise invalidated already in this mainloop iteration, // the requestClose() operation will early-succeed connect(chan->requestClose(), SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(onCloseFinished(Tp::PendingOperation*))); } void Channel::PendingLeave::onMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &removed) { if (isFinished()) { return; } ChannelPtr chan = ChannelPtr::staticCast(object()); ContactPtr c = chan->groupSelfContact(); if (removed.contains(c)) { debug() << "Leave event picked up for" << chan->objectPath(); setFinished(); } } void Channel::PendingLeave::onCloseFinished(Tp::PendingOperation *op) { if (isFinished()) { return; } ChannelPtr chan = ChannelPtr::staticCast(object()); if (op->isError()) { warning() << "Closing the channel" << chan->objectPath() << "as a fallback for leaving it failed with" << op->errorName() << op->errorMessage() << "- so didn't leave"; setFinishedWithError(op->errorName(), op->errorMessage()); } else { debug() << "We left (by closing) the channel" << chan->objectPath(); setFinished(); } } /** * Start an asynchronous request to leave this channel as gracefully as possible. * * If leaving any more gracefully is not possible, this will revert to the same as requestClose(). * In particular, this will be the case for channels with no group interface * (#TP_QT_IFACE_CHANNEL_INTERFACE_GROUP not in the list returned by interfaces()). * * The returned PendingOperation object will signal the success or failure * of this request; under normal circumstances, it can be expected to * succeed. * * A message and a reason may be provided along with the request, which will be sent to the server * if supported, which is indicated by #ChannelGroupFlagMessageDepart and/or * #ChannelGroupFlagMessageReject. * * Attempting to leave again when we have already left, either by our request or forcibly, will be a * no-op, with the returned PendingOperation immediately finishing successfully. * * \param message The message, which can be blank if desired. * \param reason A reason for leaving. * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *Channel::requestLeave(const QString &message, ChannelGroupChangeReason reason) { // Leaving a channel does not make sense if it is already closed, // just silently Return. if (!isValid()) { return new PendingSuccess(ChannelPtr(this)); } if (!isReady(Channel::FeatureCore)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel::FeatureCore must be ready to leave a channel"), ChannelPtr(this)); } if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { return requestClose(); } ContactPtr self = groupSelfContact(); if (!groupContacts().contains(self) && !groupLocalPendingContacts().contains(self) && !groupRemotePendingContacts().contains(self)) { debug() << "Channel::requestLeave() called for " << objectPath() << "which we aren't a member of"; return new PendingSuccess(ChannelPtr(this)); } return new PendingLeave(ChannelPtr(this), message, reason); } /** * \name Group interface * * Cached access to state of the group interface on the associated remote * object, if the interface is present. * * Some methods can be used when targetHandleType() == #HandleTypeContact, such * as groupFlags(), groupCanAddContacts(), groupCanRemoveContacts(), * groupSelfContact() and groupContacts(). * * As the group interface state can change freely during the lifetime of the * channel due to events like new contacts joining the group, the cached state * is automatically kept in sync with the remote object's state by hooking * to the change notification signals present in the D-Bus interface. * * As the cached value changes, change notification signals are emitted. * * Signals such as groupMembersChanged(), groupSelfContactChanged(), etc., are emitted to * indicate that properties have changed. * * Check the individual signals' descriptions for details. */ //@{ /** * Return a set of flags indicating the capabilities and behaviour of the * group on this channel. * * Change notification is via the groupFlagsChanged() signal. * * This method requires Channel::FeatureCore to be ready. * * \return The bitfield combination of flags as #ChannelGroupFlags. * \sa groupFlagsChanged() */ ChannelGroupFlags Channel::groupFlags() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupFlags() used channel not ready"; } return (ChannelGroupFlags) mPriv->groupFlags; } /** * Return whether contacts can be added or invited to this channel. * * Change notification is via the groupCanAddContactsChanged() signal. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if contacts can be added or invited to the channel, * \c false otherwise. * \sa groupFlags(), groupAddContacts() */ bool Channel::groupCanAddContacts() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupCanAddContacts() used channel not ready"; } return mPriv->groupFlags & ChannelGroupFlagCanAdd; } /** * Return whether a message is expected when adding/inviting contacts, who * are not already members, to this channel. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if a message is expected, \c false otherwise. * \sa groupFlags(), groupAddContacts() */ bool Channel::groupCanAddContactsWithMessage() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupCanAddContactsWithMessage() used when channel not ready"; } return mPriv->groupFlags & ChannelGroupFlagMessageAdd; } /** * Return whether a message is expected when accepting contacts' requests to * join this channel. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if a message is expected, \c false otherwise. * \sa groupFlags(), groupAddContacts() */ bool Channel::groupCanAcceptContactsWithMessage() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupCanAcceptContactsWithMessage() used when channel not ready"; } return mPriv->groupFlags & ChannelGroupFlagMessageAccept; } /** * Add contacts to this channel. * * Contacts on the local pending list (those waiting for permission to join * the channel) can always be added. If groupCanAcceptContactsWithMessage() * returns \c true, an optional message is expected when doing this; if not, * the message parameter is likely to be ignored (so the user should not be * asked for a message, and the message parameter should be left empty). * * Other contacts can only be added if groupCanAddContacts() returns \c true. * If groupCanAddContactsWithMessage() returns \c true, an optional message is * expected when doing this, and if not, the message parameter is likely to be * ignored. * * This method requires Channel::FeatureCore to be ready. * * \param contacts Contacts to be added. * \param message A string message, which can be blank if desired. * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa groupCanAddContacts(), groupCanAddContactsWithMessage(), groupCanAcceptContactsWithMessage() */ PendingOperation *Channel::groupAddContacts(const QList &contacts, const QString &message) { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupAddContacts() used channel not ready"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), ChannelPtr(this)); } else if (contacts.isEmpty()) { warning() << "Channel::groupAddContacts() used with empty contacts param"; return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("contacts cannot be an empty list"), ChannelPtr(this)); } foreach (const ContactPtr &contact, contacts) { if (!contact) { warning() << "Channel::groupAddContacts() used but contacts param contains " "invalid contact"; return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Unable to add invalid contacts"), ChannelPtr(this)); } } if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { warning() << "Channel::groupAddContacts() used with no group interface"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Channel does not support group interface"), ChannelPtr(this)); } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } return new PendingVoid(mPriv->group->AddMembers(handles, message), ChannelPtr(this)); } /** * Return whether contacts in groupRemotePendingContacts() can be removed from * this channel (i.e. whether an invitation can be rescinded). * * Change notification is via the groupCanRescindContactsChanged() signal. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if contacts can be removed, \c false otherwise. * \sa groupFlags(), groupRemoveContacts() */ bool Channel::groupCanRescindContacts() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupCanRescindContacts() used channel not ready"; } return mPriv->groupFlags & ChannelGroupFlagCanRescind; } /** * Return whether a message is expected when removing contacts who are in * groupRemotePendingContacts() from this channel (i.e. rescinding an * invitation). * * This method requires Channel::FeatureCore to be ready. * * \return \c true if a message is expected, \c false otherwise. * \sa groupFlags(), groupRemoveContacts() */ bool Channel::groupCanRescindContactsWithMessage() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupCanRescindContactsWithMessage() used when channel not ready"; } return mPriv->groupFlags & ChannelGroupFlagMessageRescind; } /** * Return if contacts in groupContacts() can be removed from this channel. * * Note that contacts in local pending lists, and the groupSelfContact(), can * always be removed from the channel. * * Change notification is via the groupCanRemoveContactsChanged() signal. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if contacts can be removed, \c false otherwise. * \sa groupFlags(), groupRemoveContacts() */ bool Channel::groupCanRemoveContacts() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupCanRemoveContacts() used channel not ready"; } return mPriv->groupFlags & ChannelGroupFlagCanRemove; } /** * Return whether a message is expected when removing contacts who are in * groupContacts() from this channel. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if a message is expected, \c false otherwise. * \sa groupFlags(), groupRemoveContacts() */ bool Channel::groupCanRemoveContactsWithMessage() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupCanRemoveContactsWithMessage() used when channel not ready"; } return mPriv->groupFlags & ChannelGroupFlagMessageRemove; } /** * Return whether a message is expected when removing contacts who are in * groupLocalPendingContacts() from this channel (i.e. rejecting a request to * join). * * This method requires Channel::FeatureCore to be ready. * * \return \c true if a message is expected, \c false otherwise. * \sa groupFlags(), groupRemoveContacts() */ bool Channel::groupCanRejectContactsWithMessage() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupCanRejectContactsWithMessage() used when channel not ready"; } return mPriv->groupFlags & ChannelGroupFlagMessageReject; } /** * Return whether a message is expected when removing the groupSelfContact() * from this channel (i.e. departing from the channel). * * \return \c true if a message is expected, \c false otherwise. * \sa groupFlags(), groupRemoveContacts() */ bool Channel::groupCanDepartWithMessage() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupCanDepartWithMessage() used when channel not ready"; } return mPriv->groupFlags & ChannelGroupFlagMessageDepart; } /** * Remove contacts from this channel. * * Contacts on the local pending list (those waiting for permission to join * the channel) can always be removed. If groupCanRejectContactsWithMessage() * returns \c true, an optional message is expected when doing this; if not, * the message parameter is likely to be ignored (so the user should not be * asked for a message, and the message parameter should be left empty). * * The groupSelfContact() can also always be removed, as a way to leave the * group with an optional departure message and/or departure reason indication. * If groupCanDepartWithMessage() returns \c true, an optional message is * expected when doing this, and if not, the message parameter is likely to * be ignored. * * Contacts in the group can only be removed (e.g. kicked) if * groupCanRemoveContacts() returns \c true. If * groupCanRemoveContactsWithMessage() returns \c true, an optional message is * expected when doing this, and if not, the message parameter is likely to be * ignored. * * Contacts in the remote pending list (those who have been invited to the * channel) can only be removed (have their invitations rescinded) if * groupCanRescindContacts() returns \c true. If * groupCanRescindContactsWithMessage() returns \c true, an optional message is * expected when doing this, and if not, the message parameter is likely to be * ignored. * * This method requires Channel::FeatureCore to be ready. * * \param contacts Contacts to be removed. * \param message A string message, which can be blank if desired. * \param reason Reason of the change, as specified in * #ChannelGroupChangeReason * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa groupCanRemoveContacts(), groupCanRemoveContactsWithMessage(), * groupCanRejectContactsWithMessage(), groupCanRescindContacts(), * groupCanRescindContacts(), groupCanRescindContactsWithMessage(), * groupCanDepartWithMessage() */ PendingOperation *Channel::groupRemoveContacts(const QList &contacts, const QString &message, ChannelGroupChangeReason reason) { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupRemoveContacts() used channel not ready"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), ChannelPtr(this)); } if (contacts.isEmpty()) { warning() << "Channel::groupRemoveContacts() used with empty contacts param"; return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("contacts param cannot be an empty list"), ChannelPtr(this)); } foreach (const ContactPtr &contact, contacts) { if (!contact) { warning() << "Channel::groupRemoveContacts() used but contacts param contains " "invalid contact:"; return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Unable to remove invalid contacts"), ChannelPtr(this)); } } if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { warning() << "Channel::groupRemoveContacts() used with no group interface"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Channel does not support group interface"), ChannelPtr(this)); } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } return new PendingVoid( mPriv->group->RemoveMembersWithReason(handles, message, reason), ChannelPtr(this)); } /** * Return the current contacts of the group. * * It is possible to omit the contact representing the local user, even if * the contact is in the set, by passing \c false as the parameter \a * includeSelfContact. * * Change notification is via the groupMembersChanged() signal. * * This method requires Channel::FeatureCore to be ready. * * \param includeSelfContact Whether to include the self contact in the returned set. * \return A set of pointers to the Contact objects. * \sa groupLocalPendingContacts(), groupRemotePendingContacts() */ Contacts Channel::groupContacts(bool includeSelfContact) const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupMembers() used channel not ready"; } Contacts ret = mPriv->groupContacts.values().toSet(); if (!includeSelfContact) { ret.remove(groupSelfContact()); } return ret; } /** * Return the contacts currently waiting for local approval to join the * group. * * It is possible to omit the contact representing the local user, even if * the contact is in the set, by passing \c false as the parameter \a * includeSelfContact. * * Change notification is via the groupMembersChanged() signal. * * This method requires Channel::FeatureCore to be ready. * * \param includeSelfContact Whether to include the self contact in the returned set. * \return A set of pointers to the Contact objects. * \sa groupContacts(), groupRemotePendingContacts() */ Contacts Channel::groupLocalPendingContacts(bool includeSelfContact) const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupLocalPendingContacts() used channel not ready"; } else if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { warning() << "Channel::groupLocalPendingContacts() used with no group interface"; } Contacts ret = mPriv->groupLocalPendingContacts.values().toSet(); if (!includeSelfContact) { ret.remove(groupSelfContact()); } return ret; } /** * Return the contacts currently waiting for remote approval to join the * group. * * It is possible to omit the contact representing the local user, even if * the contact is in the set, by passing \c false as the parameter \a * includeSelfContact. * * Change notification is via the groupMembersChanged() signal. * * This method requires Channel::FeatureCore to be ready. * * \param includeSelfContact Whether to include the self contact in the returned set. * \return A set of pointers to the Contact objects. * \sa groupContacts(), groupLocalPendingContacts() */ Contacts Channel::groupRemotePendingContacts(bool includeSelfContact) const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupRemotePendingContacts() used channel not ready"; } else if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { warning() << "Channel::groupRemotePendingContacts() used with no " "group interface"; } Contacts ret = mPriv->groupRemotePendingContacts.values().toSet(); if (!includeSelfContact) { ret.remove(groupSelfContact()); } return ret; } /** * Return information of a local pending contact change. If * no information is available, an object for which * GroupMemberChangeDetails::isValid() returns false is returned. * * This method requires Channel::FeatureCore to be ready. * * \param contact A Contact object that is on the local pending contacts list. * \return The change info as a GroupMemberChangeDetails object. */ Channel::GroupMemberChangeDetails Channel::groupLocalPendingContactChangeInfo( const ContactPtr &contact) const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupLocalPendingContactChangeInfo() used channel not ready"; } else if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { warning() << "Channel::groupLocalPendingContactChangeInfo() used with no group interface"; } else if (!contact) { warning() << "Channel::groupLocalPendingContactChangeInfo() used with null contact param"; return GroupMemberChangeDetails(); } uint handle = contact->handle()[0]; return mPriv->groupLocalPendingContactsChangeInfo.value(handle); } /** * Return information on the removal of the local user from the group. If * the user hasn't been removed from the group, an object for which * GroupMemberChangeDetails::isValid() returns false is returned. * * This method should be called only after you've left the channel. * This is useful for getting the remove information after missing the * corresponding groupMembersChanged() signal, as the local user being * removed usually causes the channel to be closed. * * The returned information is not guaranteed to be correct if * groupIsSelfHandleTracked() returns false and a self handle change has * occurred on the remote object. * * This method requires Channel::FeatureCore to be ready. * * \return The remove info as a GroupMemberChangeDetails object. */ Channel::GroupMemberChangeDetails Channel::groupSelfContactRemoveInfo() const { // Oftentimes, the channel will be closed as a result from being left - so checking a channel's // self remove info when it has been closed and hence invalidated is valid if (isValid() && !isReady(Channel::FeatureCore)) { warning() << "Channel::groupSelfContactRemoveInfo() used before Channel::FeatureCore is ready"; } else if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { warning() << "Channel::groupSelfContactRemoveInfo() used with " "no group interface"; } return mPriv->groupSelfContactRemoveInfo; } /** * Return whether globally valid handles can be looked up using the * channel-specific handle on this channel using this object. * * Handle owner lookup is only available if: *
    *
  • The object is ready *
  • The list returned by interfaces() contains #TP_QT_IFACE_CHANNEL_INTERFACE_GROUP
  • *
  • The set of flags returned by groupFlags() contains * #GroupFlagProperties and #GroupFlagChannelSpecificHandles
  • *
* * If this function returns \c false, the return value of * groupHandleOwners() is undefined and groupHandleOwnersChanged() will * never be emitted. * * The value returned by this function will stay fixed for the entire time * the object is ready, so no change notification is provided. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if handle owner lookup functionality is available, \c false otherwise. */ bool Channel::groupAreHandleOwnersAvailable() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupAreHandleOwnersAvailable() used channel not ready"; } else if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { warning() << "Channel::groupAreHandleOwnersAvailable() used with " "no group interface"; } return mPriv->groupAreHandleOwnersAvailable; } /** * Return a mapping of handles specific to this channel to globally valid * handles. * * The mapping includes at least all of the channel-specific handles in this * channel's members, local-pending and remote-pending sets as keys. Any * handle not in the keys of this mapping is not channel-specific in this * channel. Handles which are channel-specific, but for which the owner is * unknown, appear in this mapping with 0 as owner. * * Change notification is via the groupHandleOwnersChanged() signal. * * This method requires Channel::FeatureCore to be ready. * * \return A mapping from group-specific handles to globally valid handles. */ HandleOwnerMap Channel::groupHandleOwners() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupHandleOwners() used channel not ready"; } else if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { warning() << "Channel::groupAreHandleOwnersAvailable() used with no " "group interface"; } else if (!groupAreHandleOwnersAvailable()) { warning() << "Channel::groupAreHandleOwnersAvailable() used, but handle " "owners not available"; } return mPriv->groupHandleOwners; } /** * Return whether the value returned by groupSelfContact() is guaranteed to * accurately represent the local user even after nickname changes, etc. * * This should always be \c true for new services implementing the group interface. * * Older services not providing group properties don't necessarily * emit the SelfHandleChanged signal either, so self contact changes can't be * reliably tracked. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if changes to the self contact are tracked, \c false otherwise. */ bool Channel::groupIsSelfContactTracked() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupIsSelfHandleTracked() used channel not ready"; } else if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP)) { warning() << "Channel::groupIsSelfHandleTracked() used with " "no group interface"; } return mPriv->groupIsSelfHandleTracked; } /** * Return a Contact object representing the user in the group if at all possible, otherwise a * Contact object representing the user globally. * * Change notification is via the groupSelfContactChanged() signal. * * This method requires Channel::FeatureCore to be ready. * * \return A pointer to the Contact object. */ ContactPtr Channel::groupSelfContact() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupSelfContact() used channel not ready"; } return mPriv->groupSelfContact; } /** * Return whether the local user is in the "local pending" state. This * indicates that the local user needs to take action to accept an invitation, * an incoming call, etc. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if local user is in the channel's local-pending set, \c false otherwise. */ bool Channel::groupSelfHandleIsLocalPending() const { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupSelfHandleIsLocalPending() used when " "channel not ready"; return false; } return mPriv->groupLocalPendingContacts.contains(mPriv->groupSelfHandle); } /** * Attempt to add the local user to this channel. In some channel types, * such as Text and StreamedMedia, this is used to accept an invitation or an * incoming call. * * This method requires Channel::FeatureCore to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *Channel::groupAddSelfHandle() { if (!isReady(Channel::FeatureCore)) { warning() << "Channel::groupAddSelfHandle() used when channel not " "ready"; return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Channel object not ready"), ChannelPtr(this)); } UIntList handles; if (mPriv->groupSelfHandle == 0) { handles << mPriv->connection->selfHandle(); } else { handles << mPriv->groupSelfHandle; } return new PendingVoid( mPriv->group->AddMembers(handles, QLatin1String("")), ChannelPtr(this)); } //@} /** * Return whether this channel implements the conference interface * (#TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE is in the list returned by interfaces()). * * This method requires Channel::FeatureCore to be ready. * * \return \c true if the conference interface is supported, \c false otherwise. */ bool Channel::isConference() const { return hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE); } /** * Return a list of contacts invited to this conference when it was created. * * This method requires Channel::FeatureConferenceInitialInviteeContacts to be ready. * * \return A set of pointers to the Contact objects. */ Contacts Channel::conferenceInitialInviteeContacts() const { return mPriv->conferenceInitialInviteeContacts; } /** * Return the individual channels that are part of this conference. * * Change notification is via the conferenceChannelMerged() and * conferenceChannelRemoved() signals. * * Note that the returned channels are not guaranteed to be ready. Calling * Channel::becomeReady() may be needed. * * This method requires Channel::FeatureCore to be ready. * * \return A list of pointers to Channel objects containing all channels in the conference. * \sa conferenceInitialChannels(), conferenceOriginalChannels() */ QList Channel::conferenceChannels() const { return mPriv->conferenceChannels.values(); } /** * Return the initial value of conferenceChannels(). * * Note that the returned channels are not guaranteed to be ready. Calling * Channel::becomeReady() may be needed. * * This method requires Channel::FeatureCore to be ready. * * \return A list of pointers to Channel objects containing all channels that were initially * part of the conference. * \sa conferenceChannels(), conferenceOriginalChannels() */ QList Channel::conferenceInitialChannels() const { return mPriv->conferenceInitialChannels.values(); } /** * Return a map between channel specific handles and the corresponding channels of this conference. * * This method is only relevant on GSM conference calls where it is possible to have the same phone * number in a conference twice; for instance, it could be the number of a corporate switchboard. * This is represented using channel-specific handles; whether or not a channel uses * channel-specific handles is reported in groupFlags(). The groupHandleOwners() specifies the * mapping from opaque channel-specific handles to actual numbers; this property specifies the * original 1-1 channel corresponding to each channel-specific handle in the conference. * * In protocols where this situation cannot arise, such as XMPP, this method will return an empty * hash. * * Example, consider this situation: * 1. Place a call (with path /call/to/simon) to the contact +441234567890 (which is assigned the * handle h, say), and ask to be put through to Simon McVittie; * 2. Put that call on hold; * 3. Place another call (with path /call/to/jonny) to +441234567890, and ask to be put through to * Jonny Lamb; * 4. Request a new conference channel with initial channels: ['/call/to/simon', '/call/to/jonny']. * * The new channel will have the following properties, for some handles s and j: * * { * groupFlags(): ChannelGroupFlagChannelSpecificHandles | (other flags), * groupMembers(): [self handle, s, j], * groupHandleOwners(): { s: h, j: h }, * conferenceInitialChannels(): ['/call/to/simon', '/call/to/jonny'], * conferenceChannels(): ['/call/to/simon', '/call/to/jonny'], * conferenceOriginalChannels(): { s: '/call/to/simon', j: '/call/to/jonny' }, * # ... * } * * Note that the returned channels are not guaranteed to be ready. Calling * Channel::becomeReady() may be needed. * * This method requires Channel::FeatureCore to be ready. * * \return A map of channel specific handles to pointers to Channel objects. * \sa conferenceChannels(), conferenceInitialChannels() */ QHash Channel::conferenceOriginalChannels() const { return mPriv->conferenceOriginalChannels; } /** * Return whether this channel supports conference merging using conferenceMergeChannel(). * * This method requires Channel::FeatureCore to be ready. * * \return \c true if the interface is supported, \c false otherwise. * \sa conferenceMergeChannel() */ bool Channel::supportsConferenceMerging() const { return interfaces().contains(TP_QT_FUTURE_IFACE_CHANNEL_INTERFACE_MERGEABLE_CONFERENCE); } /** * Request that the given channel be incorporated into this channel. * * This method requires Channel::FeatureCore to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa supportsConferenceMerging() */ PendingOperation *Channel::conferenceMergeChannel(const ChannelPtr &channel) { if (!supportsConferenceMerging()) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Channel does not support MergeableConference interface"), ChannelPtr(this)); } return new PendingVoid(mPriv->mergeableConferenceInterface()->Merge( QDBusObjectPath(channel->objectPath())), ChannelPtr(this)); } /** * Return whether this channel supports splitting using conferenceSplitChannel(). * * This method requires Channel::FeatureCore to be ready. * * \return \c true if the interface is supported, \c false otherwise. * \sa conferenceSplitChannel() */ bool Channel::supportsConferenceSplitting() const { return interfaces().contains(TP_QT_FUTURE_IFACE_CHANNEL_INTERFACE_SPLITTABLE); } /** * Request that this channel is removed from any conference of which it is * a part. * * This method requires Channel::FeatureCore to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa supportsConferenceSplitting() */ PendingOperation *Channel::conferenceSplitChannel() { if (!supportsConferenceSplitting()) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Channel does not support Splittable interface"), ChannelPtr(this)); } return new PendingVoid(mPriv->splittableInterface()->Split(), ChannelPtr(this)); } /** * Return the Client::ChannelInterface interface proxy object for this channel. * This method is protected since the convenience methods provided by this * class should generally be used instead of calling D-Bus methods * directly. * * \return A pointer to the existing Client::ChannelInterface object for this * Channel object. */ Client::ChannelInterface *Channel::baseInterface() const { return mPriv->baseInterface; } void Channel::gotMainProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; QVariantMap props; if (!reply.isError()) { debug() << "Got reply to Properties::GetAll(Channel)"; props = reply.value(); } else { warning().nospace() << "Properties::GetAll(Channel) failed with " << reply.error().name() << ": " << reply.error().message(); } mPriv->extractMainProps(props); mPriv->continueIntrospection(); } void Channel::gotChannelType(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Channel::GetChannelType() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead"; invalidate(reply.error()); return; } debug() << "Got reply to fallback Channel::GetChannelType()"; mPriv->channelType = reply.value(); mPriv->continueIntrospection(); } void Channel::gotHandle(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Channel::GetHandle() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead"; invalidate(reply.error()); return; } debug() << "Got reply to fallback Channel::GetHandle()"; mPriv->targetHandleType = reply.argumentAt<0>(); mPriv->targetHandle = reply.argumentAt<1>(); mPriv->continueIntrospection(); } void Channel::gotInterfaces(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Channel::GetInterfaces() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead"; invalidate(reply.error()); return; } debug() << "Got reply to fallback Channel::GetInterfaces()"; setInterfaces(reply.value()); mPriv->readinessHelper->setInterfaces(interfaces()); mPriv->nowHaveInterfaces(); mPriv->fakeGroupInterfaceIfNeeded(); mPriv->continueIntrospection(); } void Channel::onClosed() { debug() << "Got Channel::Closed"; QString error; QString message; if (mPriv->groupSelfContactRemoveInfo.isValid() && mPriv->groupSelfContactRemoveInfo.hasReason()) { error = mPriv->groupMemberChangeDetailsTelepathyError( mPriv->groupSelfContactRemoveInfo); message = mPriv->groupSelfContactRemoveInfo.message(); } else { error = TP_QT_ERROR_CANCELLED; message = QLatin1String("channel closed"); } invalidate(error, message); } void Channel::onConnectionReady(PendingOperation *op) { if (op->isError()) { invalidate(op->errorName(), op->errorMessage()); return; } // FIXME: should connect to selfHandleChanged and act accordingly, but that is a PITA for // keeping the Contacts built and even if we don't do it, the new code is better than the // old one anyway because earlier on we just wouldn't have had a self contact. // // besides, the only thing which breaks without connecting in the world likely is if you're // using idle and decide to change your nick, which I don't think we necessarily even have API // to do from tp-qt anyway (or did I make idle change the nick when setting your alias? can't // remember) // // Simply put, I just don't care ATM. // Will be overwritten by the group self handle, if we can discover any. Q_ASSERT(!mPriv->groupSelfHandle); mPriv->groupSelfHandle = mPriv->connection->selfHandle(); mPriv->introspectMainProperties(); } void Channel::onConnectionInvalidated() { debug() << "Owning connection died leaving an orphan Channel, " "changing to closed"; invalidate(TP_QT_ERROR_ORPHANED, QLatin1String("Connection given as the owner of this channel was invalidated")); } void Channel::gotGroupProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; QVariantMap props; if (!reply.isError()) { debug() << "Got reply to Properties::GetAll(Channel.Interface.Group)"; props = reply.value(); } else { warning().nospace() << "Properties::GetAll(Channel.Interface.Group) " "failed with " << reply.error().name() << ": " << reply.error().message(); } mPriv->extract0176GroupProps(props); // Add extraction (and possible fallbacks) in similar functions, called from here mPriv->continueIntrospection(); } void Channel::gotGroupFlags(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Channel.Interface.Group::GetGroupFlags() failed with " << reply.error().name() << ": " << reply.error().message(); } else { debug() << "Got reply to fallback Channel.Interface.Group::GetGroupFlags()"; mPriv->setGroupFlags(reply.value()); if (mPriv->groupFlags & ChannelGroupFlagProperties) { warning() << " Reply included ChannelGroupFlagProperties, even " "though properties specified in 0.17.7 didn't work! - unsetting"; mPriv->groupFlags &= ~ChannelGroupFlagProperties; } } mPriv->continueIntrospection(); } void Channel::gotAllMembers(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Channel.Interface.Group::GetAllMembers() failed with " << reply.error().name() << ": " << reply.error().message(); } else { debug() << "Got reply to fallback Channel.Interface.Group::GetAllMembers()"; mPriv->groupInitialMembers = reply.argumentAt<0>(); mPriv->groupInitialRP = reply.argumentAt<2>(); foreach (uint handle, reply.argumentAt<1>()) { LocalPendingInfo info = {handle, 0, ChannelGroupChangeReasonNone, QLatin1String("")}; mPriv->groupInitialLP.push_back(info); } } mPriv->continueIntrospection(); } void Channel::gotLocalPendingMembersWithInfo(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Channel.Interface.Group::GetLocalPendingMembersWithInfo() " "failed with " << reply.error().name() << ": " << reply.error().message(); warning() << " Falling back to what GetAllMembers returned with no extended info"; } else { debug() << "Got reply to fallback " "Channel.Interface.Group::GetLocalPendingMembersWithInfo()"; // Overrides the previous vague list provided by gotAllMembers mPriv->groupInitialLP = reply.value(); } mPriv->continueIntrospection(); } void Channel::gotSelfHandle(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Channel.Interface.Group::GetSelfHandle() failed with " << reply.error().name() << ": " << reply.error().message(); } else { debug() << "Got reply to fallback Channel.Interface.Group::GetSelfHandle()"; // Don't overwrite the self handle we got from the connection with 0 if (reply.value()) { mPriv->groupSelfHandle = reply.value(); } } mPriv->nowHaveInitialMembers(); mPriv->continueIntrospection(); } void Channel::gotContacts(PendingOperation *op) { PendingContacts *pending = qobject_cast(op); mPriv->buildingContacts = false; QList contacts; if (pending->isValid()) { contacts = pending->contacts(); if (!pending->invalidHandles().isEmpty()) { warning() << "Unable to construct Contact objects for handles:" << pending->invalidHandles(); if (mPriv->groupSelfHandle && pending->invalidHandles().contains(mPriv->groupSelfHandle)) { warning() << "Unable to retrieve self contact"; mPriv->groupSelfContact.reset(); emit groupSelfContactChanged(); } } } else { warning().nospace() << "Getting contacts failed with " << pending->errorName() << ":" << pending->errorMessage(); } mPriv->updateContacts(contacts); } void Channel::onGroupFlagsChanged(uint added, uint removed) { debug().nospace() << "Got Channel.Interface.Group::GroupFlagsChanged(" << hex << added << ", " << removed << ")"; added &= ~(mPriv->groupFlags); removed &= mPriv->groupFlags; debug().nospace() << "Arguments after filtering (" << hex << added << ", " << removed << ")"; uint groupFlags = mPriv->groupFlags; groupFlags |= added; groupFlags &= ~removed; // just emit groupFlagsChanged and related signals if the flags really // changed and we are ready if (mPriv->setGroupFlags(groupFlags) && isReady(Channel::FeatureCore)) { debug() << "Emitting groupFlagsChanged with" << mPriv->groupFlags << "value" << added << "added" << removed << "removed"; emit groupFlagsChanged((ChannelGroupFlags) mPriv->groupFlags, (ChannelGroupFlags) added, (ChannelGroupFlags) removed); if (added & ChannelGroupFlagCanAdd || removed & ChannelGroupFlagCanAdd) { debug() << "Emitting groupCanAddContactsChanged"; emit groupCanAddContactsChanged(groupCanAddContacts()); } if (added & ChannelGroupFlagCanRemove || removed & ChannelGroupFlagCanRemove) { debug() << "Emitting groupCanRemoveContactsChanged"; emit groupCanRemoveContactsChanged(groupCanRemoveContacts()); } if (added & ChannelGroupFlagCanRescind || removed & ChannelGroupFlagCanRescind) { debug() << "Emitting groupCanRescindContactsChanged"; emit groupCanRescindContactsChanged(groupCanRescindContacts()); } } } void Channel::onMembersChanged(const QString &message, const UIntList &added, const UIntList &removed, const UIntList &localPending, const UIntList &remotePending, uint actor, uint reason) { // Ignore the signal if we're using the MCD signal to not duplicate events if (mPriv->usingMembersChangedDetailed) { return; } debug() << "Got Channel.Interface.Group::MembersChanged with" << added.size() << "added," << removed.size() << "removed," << localPending.size() << "moved to LP," << remotePending.size() << "moved to RP," << actor << "being the actor," << reason << "the reason and" << message << "the message"; debug() << " synthesizing a corresponding MembersChangedDetailed signal"; QVariantMap details; if (!message.isEmpty()) { details.insert(QLatin1String("message"), message); } if (actor != 0) { details.insert(QLatin1String("actor"), actor); } details.insert(QLatin1String("change-reason"), reason); mPriv->doMembersChangedDetailed(added, removed, localPending, remotePending, details); } void Channel::onMembersChangedDetailed( const UIntList &added, const UIntList &removed, const UIntList &localPending, const UIntList &remotePending, const QVariantMap &details) { // Ignore the signal if we aren't (yet) using MCD to not duplicate events if (!mPriv->usingMembersChangedDetailed) { return; } debug() << "Got Channel.Interface.Group::MembersChangedDetailed with" << added.size() << "added," << removed.size() << "removed," << localPending.size() << "moved to LP," << remotePending.size() << "moved to RP and with" << details.size() << "details"; mPriv->doMembersChangedDetailed(added, removed, localPending, remotePending, details); } void Channel::Private::doMembersChangedDetailed( const UIntList &added, const UIntList &removed, const UIntList &localPending, const UIntList &remotePending, const QVariantMap &details) { if (!groupHaveMembers) { debug() << "Still waiting for initial group members, " "so ignoring delta signal..."; return; } if (added.isEmpty() && removed.isEmpty() && localPending.isEmpty() && remotePending.isEmpty()) { debug() << "Nothing really changed, so skipping membersChanged"; return; } // let's store groupSelfContactRemoveInfo here as we may not have time // to build the contacts in case self contact is removed, // as Closed will be emitted right after if (removed.contains(groupSelfHandle)) { if (qdbus_cast(details.value(QLatin1String("change-reason"))) == ChannelGroupChangeReasonRenamed) { if (removed.size() != 1 || (added.size() + localPending.size() + remotePending.size()) != 1) { // spec-incompliant CM, ignoring members changed warning() << "Received MembersChangedDetailed with reason " "Renamed and removed.size != 1 or added.size + " "localPending.size + remotePending.size != 1. Ignoring"; return; } uint newHandle = 0; if (!added.isEmpty()) { newHandle = added.first(); } else if (!localPending.isEmpty()) { newHandle = localPending.first(); } else if (!remotePending.isEmpty()) { newHandle = remotePending.first(); } parent->onSelfHandleChanged(newHandle); return; } // let's try to get the actor contact from contact manager if available groupSelfContactRemoveInfo = GroupMemberChangeDetails( connection->contactManager()->lookupContactByHandle( qdbus_cast(details.value(QLatin1String("actor")))), details); } HandleIdentifierMap contactIds = qdbus_cast( details.value(GroupMembersChangedInfo::keyContactIds)); connection->lowlevel()->injectContactIds(contactIds); groupMembersChangedQueue.enqueue( new Private::GroupMembersChangedInfo( added, removed, localPending, remotePending, details)); if (!buildingContacts) { // if we are building contacts, we should wait it to finish so we don't // present the user with wrong information processMembersChanged(); } } void Channel::onHandleOwnersChanged(const HandleOwnerMap &added, const UIntList &removed) { debug() << "Got Channel.Interface.Group::HandleOwnersChanged with" << added.size() << "added," << removed.size() << "removed"; if (!mPriv->groupAreHandleOwnersAvailable) { debug() << "Still waiting for initial handle owners, so ignoring " "delta signal..."; return; } UIntList emitAdded; UIntList emitRemoved; for (HandleOwnerMap::const_iterator i = added.begin(); i != added.end(); ++i) { uint handle = i.key(); uint global = i.value(); if (!mPriv->groupHandleOwners.contains(handle) || mPriv->groupHandleOwners[handle] != global) { debug() << " +++/changed" << handle << "->" << global; mPriv->groupHandleOwners[handle] = global; emitAdded.append(handle); } } foreach (uint handle, removed) { if (mPriv->groupHandleOwners.contains(handle)) { debug() << " ---" << handle; mPriv->groupHandleOwners.remove(handle); emitRemoved.append(handle); } } // just emit groupHandleOwnersChanged if it really changed and // we are ready if ((emitAdded.size() || emitRemoved.size()) && isReady(Channel::FeatureCore)) { debug() << "Emitting groupHandleOwnersChanged with" << emitAdded.size() << "added" << emitRemoved.size() << "removed"; emit groupHandleOwnersChanged(mPriv->groupHandleOwners, emitAdded, emitRemoved); } } void Channel::onSelfHandleChanged(uint selfHandle) { debug().nospace() << "Got Channel.Interface.Group::SelfHandleChanged"; if (selfHandle != mPriv->groupSelfHandle) { mPriv->groupSelfHandle = selfHandle; debug() << " Emitting groupSelfHandleChanged with new self handle" << selfHandle; // FIXME: fix self contact building with no group mPriv->pendingRetrieveGroupSelfContact = true; } } void Channel::gotConferenceProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; QVariantMap props; mPriv->introspectingConference = false; if (!reply.isError()) { debug() << "Got reply to Properties::GetAll(Channel.Interface.Conference)"; props = reply.value(); ConnectionPtr conn = connection(); ChannelFactoryConstPtr chanFactory = conn->channelFactory(); ObjectPathList channels = qdbus_cast(props[QLatin1String("Channels")]); foreach (const QDBusObjectPath &channelPath, channels) { if (mPriv->conferenceChannels.contains(channelPath.path())) { continue; } PendingReady *readyOp = chanFactory->proxy(conn, channelPath.path(), QVariantMap()); ChannelPtr channel(ChannelPtr::qObjectCast(readyOp->proxy())); Q_ASSERT(!channel.isNull()); mPriv->conferenceChannels.insert(channelPath.path(), channel); } ObjectPathList initialChannels = qdbus_cast(props[QLatin1String("InitialChannels")]); foreach (const QDBusObjectPath &channelPath, initialChannels) { if (mPriv->conferenceInitialChannels.contains(channelPath.path())) { continue; } PendingReady *readyOp = chanFactory->proxy(conn, channelPath.path(), QVariantMap()); ChannelPtr channel(ChannelPtr::qObjectCast(readyOp->proxy())); Q_ASSERT(!channel.isNull()); mPriv->conferenceInitialChannels.insert(channelPath.path(), channel); } mPriv->conferenceInitialInviteeHandles = qdbus_cast(props[QLatin1String("InitialInviteeHandles")]); QStringList conferenceInitialInviteeIds = qdbus_cast(props[QLatin1String("InitialInviteeIDs")]); if (mPriv->conferenceInitialInviteeHandles.size() == conferenceInitialInviteeIds.size()) { HandleIdentifierMap contactIds; int i = 0; foreach (uint handle, mPriv->conferenceInitialInviteeHandles) { contactIds.insert(handle, conferenceInitialInviteeIds.at(i++)); } mPriv->connection->lowlevel()->injectContactIds(contactIds); } mPriv->conferenceInvitationMessage = qdbus_cast(props[QLatin1String("InvitationMessage")]); ChannelOriginatorMap originalChannels = qdbus_cast( props[QLatin1String("OriginalChannels")]); for (ChannelOriginatorMap::const_iterator i = originalChannels.constBegin(); i != originalChannels.constEnd(); ++i) { PendingReady *readyOp = chanFactory->proxy(conn, i.value().path(), QVariantMap()); ChannelPtr channel(ChannelPtr::qObjectCast(readyOp->proxy())); Q_ASSERT(!channel.isNull()); mPriv->conferenceOriginalChannels.insert(i.key(), channel); } } else { warning().nospace() << "Properties::GetAll(Channel.Interface.Conference) " "failed with " << reply.error().name() << ": " << reply.error().message(); } mPriv->continueIntrospection(); } void Channel::gotConferenceInitialInviteeContacts(PendingOperation *op) { PendingContacts *pending = qobject_cast(op); if (pending->isValid()) { mPriv->conferenceInitialInviteeContacts = pending->contacts().toSet(); } else { warning().nospace() << "Getting conference initial invitee contacts " "failed with " << pending->errorName() << ":" << pending->errorMessage(); } mPriv->readinessHelper->setIntrospectCompleted( FeatureConferenceInitialInviteeContacts, true); } void Channel::onConferenceChannelMerged(const QDBusObjectPath &channelPath, uint channelSpecificHandle, const QVariantMap &properties) { if (mPriv->conferenceChannels.contains(channelPath.path())) { return; } ConnectionPtr conn = connection(); ChannelFactoryConstPtr chanFactory = conn->channelFactory(); PendingReady *readyOp = chanFactory->proxy(conn, channelPath.path(), properties); ChannelPtr channel(ChannelPtr::qObjectCast(readyOp->proxy())); Q_ASSERT(!channel.isNull()); mPriv->conferenceChannels.insert(channelPath.path(), channel); emit conferenceChannelMerged(channel); if (channelSpecificHandle != 0) { mPriv->conferenceOriginalChannels.insert(channelSpecificHandle, channel); } } void Channel::onConferenceChannelMerged(const QDBusObjectPath &channelPath) { onConferenceChannelMerged(channelPath, 0, QVariantMap()); } void Channel::onConferenceChannelRemoved(const QDBusObjectPath &channelPath, const QVariantMap &details) { if (!mPriv->conferenceChannels.contains(channelPath.path())) { return; } HandleIdentifierMap contactIds = qdbus_cast( details.value(Private::GroupMembersChangedInfo::keyContactIds)); mPriv->connection->lowlevel()->injectContactIds(contactIds); mPriv->conferenceChannelRemovedQueue.enqueue( new Private::ConferenceChannelRemovedInfo(channelPath, details)); mPriv->processConferenceChannelRemoved(); } void Channel::onConferenceChannelRemoved(const QDBusObjectPath &channelPath) { onConferenceChannelRemoved(channelPath, QVariantMap()); } void Channel::gotConferenceChannelRemovedActorContact(PendingOperation *op) { ContactPtr actorContact; if (op) { PendingContacts *pc = qobject_cast(op); if (pc->isValid()) { Q_ASSERT(pc->contacts().size() == 1); actorContact = pc->contacts().first(); } else { warning().nospace() << "Getting conference channel removed actor " "failed with " << pc->errorName() << ":" << pc->errorMessage(); } } Private::ConferenceChannelRemovedInfo *info = mPriv->conferenceChannelRemovedQueue.dequeue(); ChannelPtr channel = mPriv->conferenceChannels[info->channelPath.path()]; mPriv->conferenceChannels.remove(info->channelPath.path()); emit conferenceChannelRemoved(channel, GroupMemberChangeDetails(actorContact, info->details)); for (QHash::iterator i = mPriv->conferenceOriginalChannels.begin(); i != mPriv->conferenceOriginalChannels.end();) { if (i.value() == channel) { i = mPriv->conferenceOriginalChannels.erase(i); } else { ++i; } } delete info; mPriv->buildingConferenceChannelRemovedActorContact = false; mPriv->processConferenceChannelRemoved(); } /** * \fn void Channel::groupFlagsChanged(uint flags, uint added, uint removed) * * Emitted when the value of groupFlags() changes. * * \param flags The value which would now be returned by groupFlags(). * \param added Flags added compared to the previous value. * \param removed Flags removed compared to the previous value. */ /** * \fn void Channel::groupCanAddContactsChanged(bool canAddContacts) * * Emitted when the value of groupCanAddContacts() changes. * * \param canAddContacts Whether a contact can be added to this channel. * \sa groupCanAddContacts() */ /** * \fn void Channel::groupCanRemoveContactsChanged(bool canRemoveContacts) * * Emitted when the value of groupCanRemoveContacts() changes. * * \param canRemoveContacts Whether a contact can be removed from this channel. * \sa groupCanRemoveContacts() */ /** * \fn void Channel::groupCanRescindContactsChanged(bool canRescindContacts) * * Emitted when the value of groupCanRescindContacts() changes. * * \param canRescindContacts Whether contact invitations can be rescinded. * \sa groupCanRescindContacts() */ /** * \fn void Channel::groupMembersChanged( * const Tp::Contacts &groupMembersAdded, * const Tp::Contacts &groupLocalPendingMembersAdded, * const Tp::Contacts &groupRemotePendingMembersAdded, * const Tp::Contacts &groupMembersRemoved, * const Channel::GroupMemberChangeDetails &details) * * Emitted when the value returned by groupContacts(), groupLocalPendingContacts() or * groupRemotePendingContacts() changes. * * \param groupMembersAdded The contacts that were added to this channel. * \param groupLocalPendingMembersAdded The local pending contacts that were * added to this channel. * \param groupRemotePendingMembersAdded The remote pending contacts that were * added to this channel. * \param groupMembersRemoved The contacts removed from this channel. * \param details Additional details such as the contact requesting or causing * the change. */ /** * \fn void Channel::groupHandleOwnersChanged(const HandleOwnerMap &owners, * const Tp::UIntList &added, const Tp::UIntList &removed) * * Emitted when the value returned by groupHandleOwners() changes. * * \param owners The value which would now be returned by * groupHandleOwners(). * \param added Handles which have been added to the mapping as keys, or * existing handle keys for which the mapped-to value has changed. * \param removed Handles which have been removed from the mapping. */ /** * \fn void Channel::groupSelfContactChanged() * * Emitted when the value returned by groupSelfContact() changes. */ /** * \fn void Channel::conferenceChannelMerged(const Tp::ChannelPtr &channel) * * Emitted when a new channel is added to the value of conferenceChannels(). * * \param channel The channel that was added to conferenceChannels(). */ /** * \fn void Channel::conferenceChannelRemoved(const Tp::ChannelPtr &channel, * const Tp::Channel::GroupMemberChangeDetails &details) * * Emitted when a new channel is removed from the value of conferenceChannels(). * * \param channel The channel that was removed from conferenceChannels(). * \param details The change details. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/CallContentMediaDescriptionInterfaceRTCPFeedbackInterface0000664000175000017500000000053612470405660030255 0ustar jrjr#ifndef _TelepathyQt_CallContentMediaDescriptionInterfaceRTCPFeedbackInterface_HEADER_GUARD_ #define _TelepathyQt_CallContentMediaDescriptionInterfaceRTCPFeedbackInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/call-stream-endpoint.cpp0000664000175000017500000000212012470405660021735 0ustar jrjr/* * This file is part of TelepathyQt4 * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/cli-call-stream-endpoint-body.hpp" #include "TelepathyQt/_gen/cli-call-stream-endpoint.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/profile.cpp0000664000175000017500000010235612470405660017367 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/manager-file.h" #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT Profile::Private { Private(); void setServiceName(const QString &serviceName); void setFileName(const QString &fileName); void lookupProfile(); bool parse(QFile *file); void invalidate(); struct Data { Data(); void clear(); QString type; QString provider; QString name; QString iconName; QString cmName; QString protocolName; Profile::ParameterList parameters; bool allowOtherPresences; Profile::PresenceList presences; RequestableChannelClassSpecList unsupportedChannelClassSpecs; }; class XmlHandler; QString serviceName; bool valid; bool fake; bool allowNonIMType; Data data; }; Profile::Private::Data::Data() : allowOtherPresences(false) { } void Profile::Private::Data::clear() { type = QString(); provider = QString(); name = QString(); iconName = QString(); protocolName = QString(); parameters = Profile::ParameterList(); allowOtherPresences = false; presences = Profile::PresenceList(); unsupportedChannelClassSpecs = RequestableChannelClassSpecList(); } class TP_QT_NO_EXPORT Profile::Private::XmlHandler : public QXmlDefaultHandler { public: XmlHandler(const QString &serviceName, bool allowNonIMType, Profile::Private::Data *outputData); bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &attributes); bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName); bool characters(const QString &str); bool fatalError(const QXmlParseException &exception); QString errorString() const; private: bool attributeValueAsBoolean(const QXmlAttributes &attributes, const QString &qName); QString mServiceName; bool allowNonIMType; Profile::Private::Data *mData; QStack mElements; QString mCurrentText; Profile::Parameter mCurrentParameter; RequestableChannelClass mCurrentCC; QString mCurrentPropertyName; QString mCurrentPropertyType; QString mErrorString; bool mMetServiceTag; static const QString xmlNs; static const QString elemService; static const QString elemName; static const QString elemParams; static const QString elemParam; static const QString elemPresences; static const QString elemPresence; static const QString elemUnsupportedCCs; static const QString elemCC; static const QString elemProperty; static const QString elemAttrId; static const QString elemAttrName; static const QString elemAttrType; static const QString elemAttrProvider; static const QString elemAttrManager; static const QString elemAttrProtocol; static const QString elemAttrIcon; static const QString elemAttrLabel; static const QString elemAttrMandatory; static const QString elemAttrAllowOthers; static const QString elemAttrMessage; static const QString elemAttrDisabled; }; const QString Profile::Private::XmlHandler::xmlNs = QLatin1String("http://telepathy.freedesktop.org/wiki/service-profile-v1"); const QString Profile::Private::XmlHandler::elemService = QLatin1String("service"); const QString Profile::Private::XmlHandler::elemName = QLatin1String("name"); const QString Profile::Private::XmlHandler::elemParams = QLatin1String("parameters"); const QString Profile::Private::XmlHandler::elemParam = QLatin1String("parameter"); const QString Profile::Private::XmlHandler::elemPresences = QLatin1String("presences"); const QString Profile::Private::XmlHandler::elemPresence = QLatin1String("presence"); const QString Profile::Private::XmlHandler::elemUnsupportedCCs = QLatin1String("unsupported-channel-classes"); const QString Profile::Private::XmlHandler::elemCC = QLatin1String("channel-class"); const QString Profile::Private::XmlHandler::elemProperty = QLatin1String("property"); const QString Profile::Private::XmlHandler::elemAttrId = QLatin1String("id"); const QString Profile::Private::XmlHandler::elemAttrName = QLatin1String("name"); const QString Profile::Private::XmlHandler::elemAttrType = QLatin1String("type"); const QString Profile::Private::XmlHandler::elemAttrProvider = QLatin1String("provider"); const QString Profile::Private::XmlHandler::elemAttrManager = QLatin1String("manager"); const QString Profile::Private::XmlHandler::elemAttrProtocol = QLatin1String("protocol"); const QString Profile::Private::XmlHandler::elemAttrLabel = QLatin1String("label"); const QString Profile::Private::XmlHandler::elemAttrMandatory = QLatin1String("mandatory"); const QString Profile::Private::XmlHandler::elemAttrAllowOthers = QLatin1String("allow-others"); const QString Profile::Private::XmlHandler::elemAttrIcon = QLatin1String("icon"); const QString Profile::Private::XmlHandler::elemAttrMessage = QLatin1String("message"); const QString Profile::Private::XmlHandler::elemAttrDisabled = QLatin1String("disabled"); Profile::Private::XmlHandler::XmlHandler(const QString &serviceName, bool allowNonIMType, Profile::Private::Data *outputData) : mServiceName(serviceName), allowNonIMType(allowNonIMType), mData(outputData), mMetServiceTag(false) { } bool Profile::Private::XmlHandler::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &attributes) { if (!mMetServiceTag && qName != elemService) { mErrorString = QLatin1String("the file is not a profile file"); return false; } if (namespaceURI != xmlNs) { // ignore all elements with unknown xmlns debug() << "Ignoring unknown xmlns" << namespaceURI; return true; } #define CHECK_ELEMENT_IS_CHILD_OF(parentElement) \ if (mElements.top() != parentElement) { \ mErrorString = QString(QLatin1String("element '%1' is not a " \ "child of element '%2'")) \ .arg(qName) \ .arg(parentElement); \ return false; \ } #define CHECK_ELEMENT_ATTRIBUTES_COUNT(value) \ if (attributes.count() != value) { \ mErrorString = QString(QLatin1String("element '%1' contains more " \ "than %2 attributes")) \ .arg(qName) \ .arg(value); \ return false; \ } #define CHECK_ELEMENT_HAS_ATTRIBUTE(attribute) \ if (attributes.index(attribute) == -1) { \ mErrorString = QString(QLatin1String("mandatory attribute '%1' " \ "missing on element '%2'")) \ .arg(attribute) \ .arg(qName); \ return false; \ } #define CHECK_ELEMENT_ATTRIBUTES(allowedAttrs) \ for (int i = 0; i < attributes.count(); ++i) { \ bool valid = false; \ QString attrName = attributes.qName(i); \ foreach (const QString &allowedAttr, allowedAttrs) { \ if (attrName == allowedAttr) { \ valid = true; \ break; \ } \ } \ if (!valid) { \ mErrorString = QString(QLatin1String("invalid attribute '%1' on " \ "element '%2'")) \ .arg(attrName) \ .arg(qName); \ return false; \ } \ } if (qName == elemService) { CHECK_ELEMENT_HAS_ATTRIBUTE(elemAttrId); CHECK_ELEMENT_HAS_ATTRIBUTE(elemAttrType); CHECK_ELEMENT_HAS_ATTRIBUTE(elemAttrManager); CHECK_ELEMENT_HAS_ATTRIBUTE(elemAttrProtocol); QStringList allowedAttrs = QStringList() << elemAttrId << elemAttrType << elemAttrManager << elemAttrProtocol << elemAttrProvider << elemAttrIcon; CHECK_ELEMENT_ATTRIBUTES(allowedAttrs); if (attributes.value(elemAttrId) != mServiceName) { mErrorString = QString(QLatin1String("the '%1' attribute of the " "element '%2' does not match the file name")) .arg(elemAttrId) .arg(elemService); return false; } mMetServiceTag = true; mData->type = attributes.value(elemAttrType); if (mData->type != QLatin1String("IM") && !allowNonIMType) { mErrorString = QString(QLatin1String("unknown value of element " "'type': %1")) .arg(mCurrentText); return false; } mData->provider = attributes.value(elemAttrProvider); mData->cmName = attributes.value(elemAttrManager); mData->protocolName = attributes.value(elemAttrProtocol); mData->iconName = attributes.value(elemAttrIcon); } else if (qName == elemParams) { CHECK_ELEMENT_IS_CHILD_OF(elemService); CHECK_ELEMENT_ATTRIBUTES_COUNT(0); } else if (qName == elemParam) { CHECK_ELEMENT_IS_CHILD_OF(elemParams); CHECK_ELEMENT_HAS_ATTRIBUTE(elemAttrName); QStringList allowedAttrs = QStringList() << elemAttrName << elemAttrType << elemAttrMandatory << elemAttrLabel; CHECK_ELEMENT_ATTRIBUTES(allowedAttrs); QString paramType = attributes.value(elemAttrType); if (paramType.isEmpty()) { paramType = QLatin1String("s"); } mCurrentParameter.setName(attributes.value(elemAttrName)); mCurrentParameter.setDBusSignature(QDBusSignature(paramType)); mCurrentParameter.setLabel(attributes.value(elemAttrLabel)); mCurrentParameter.setMandatory(attributeValueAsBoolean(attributes, elemAttrMandatory)); } else if (qName == elemPresences) { CHECK_ELEMENT_IS_CHILD_OF(elemService); QStringList allowedAttrs = QStringList() << elemAttrAllowOthers; CHECK_ELEMENT_ATTRIBUTES(allowedAttrs); mData->allowOtherPresences = attributeValueAsBoolean(attributes, elemAttrAllowOthers); } else if (qName == elemPresence) { CHECK_ELEMENT_IS_CHILD_OF(elemPresences); CHECK_ELEMENT_HAS_ATTRIBUTE(elemAttrId); QStringList allowedAttrs = QStringList() << elemAttrId << elemAttrLabel << elemAttrIcon << elemAttrMessage << elemAttrDisabled; CHECK_ELEMENT_ATTRIBUTES(allowedAttrs); mData->presences.append(Profile::Presence( attributes.value(elemAttrId), attributes.value(elemAttrLabel), attributes.value(elemAttrIcon), attributes.value(elemAttrMessage), attributeValueAsBoolean(attributes, elemAttrDisabled))); } else if (qName == elemUnsupportedCCs) { CHECK_ELEMENT_IS_CHILD_OF(elemService); CHECK_ELEMENT_ATTRIBUTES_COUNT(0); } else if (qName == elemCC) { CHECK_ELEMENT_IS_CHILD_OF(elemUnsupportedCCs); CHECK_ELEMENT_ATTRIBUTES_COUNT(0); } else if (qName == elemProperty) { CHECK_ELEMENT_IS_CHILD_OF(elemCC); CHECK_ELEMENT_ATTRIBUTES_COUNT(2); CHECK_ELEMENT_HAS_ATTRIBUTE(elemAttrName); CHECK_ELEMENT_HAS_ATTRIBUTE(elemAttrType); mCurrentPropertyName = attributes.value(elemAttrName); mCurrentPropertyType = attributes.value(elemAttrType); } else { if (qName != elemName) { Tp::warning() << "Ignoring unknown element" << qName; } else { // check if we are inside CHECK_ELEMENT_IS_CHILD_OF(elemService); // no element here supports attributes CHECK_ELEMENT_ATTRIBUTES_COUNT(0); } } #undef CHECK_ELEMENT_IS_CHILD_OF #undef CHECK_ELEMENT_ATTRIBUTES_COUNT #undef CHECK_ELEMENT_HAS_ATTRIBUTE #undef CHECK_ELEMENT_ATTRIBUTES mElements.push(qName); mCurrentText.clear(); return true; } bool Profile::Private::XmlHandler::endElement(const QString &namespaceURI, const QString &localName, const QString &qName) { if (namespaceURI != xmlNs) { // ignore all elements with unknown xmlns debug() << "Ignoring unknown xmlns" << namespaceURI; return true; } else if (qName == elemName) { mData->name = mCurrentText; } else if (qName == elemParam) { mCurrentParameter.setValue(parseValueWithDBusSignature(mCurrentText, mCurrentParameter.dbusSignature().signature())); mData->parameters.append(Profile::Parameter(mCurrentParameter)); } else if (qName == elemCC) { mData->unsupportedChannelClassSpecs.append(RequestableChannelClassSpec(mCurrentCC)); mCurrentCC.fixedProperties.clear(); } else if (qName == elemProperty) { mCurrentCC.fixedProperties[mCurrentPropertyName] = parseValueWithDBusSignature(mCurrentText, mCurrentPropertyType); } mElements.pop(); return true; } bool Profile::Private::XmlHandler::characters(const QString &str) { mCurrentText += str; return true; } bool Profile::Private::XmlHandler::fatalError( const QXmlParseException &exception) { mErrorString = QString(QLatin1String("parse error at line %1, column %2: " "%3")) .arg(exception.lineNumber()) .arg(exception.columnNumber()) .arg(exception.message()); return false; } QString Profile::Private::XmlHandler::errorString() const { return mErrorString; } bool Profile::Private::XmlHandler::attributeValueAsBoolean( const QXmlAttributes &attributes, const QString &qName) { QString tmpStr = attributes.value(qName); if (tmpStr == QLatin1String("1") || tmpStr == QLatin1String("true")) { return true; } else { return false; } } Profile::Private::Private() : valid(false), fake(false), allowNonIMType(false) { } void Profile::Private::setServiceName(const QString &serviceName_) { invalidate(); allowNonIMType = false; serviceName = serviceName_; lookupProfile(); } void Profile::Private::setFileName(const QString &fileName) { invalidate(); allowNonIMType = true; QFileInfo fi(fileName); serviceName = fi.baseName(); debug() << "Loading profile file" << fileName; QFile file(fileName); if (!file.exists()) { warning() << QString(QLatin1String("Error parsing profile file %1: file does not exist")) .arg(file.fileName()); return; } if (!file.open(QFile::ReadOnly)) { warning() << QString(QLatin1String("Error parsing profile file %1: " "cannot open file for readonly access")) .arg(file.fileName()); return; } if (parse(&file)) { debug() << "Profile file" << fileName << "loaded successfully"; } } void Profile::Private::lookupProfile() { debug() << "Searching profile for service" << serviceName; QStringList searchDirs = Profile::searchDirs(); bool found = false; foreach (const QString searchDir, searchDirs) { QString fileName = searchDir + serviceName + QLatin1String(".profile"); QFile file(fileName); if (!file.exists()) { continue; } if (!file.open(QFile::ReadOnly)) { continue; } if (parse(&file)) { debug() << "Profile for service" << serviceName << "found:" << fileName; found = true; break; } } if (!found) { debug() << "Cannot find valid profile for service" << serviceName; } } bool Profile::Private::parse(QFile *file) { invalidate(); fake = false; QFileInfo fi(file->fileName()); XmlHandler xmlHandler(serviceName, allowNonIMType, &data); QXmlSimpleReader xmlReader; xmlReader.setContentHandler(&xmlHandler); xmlReader.setErrorHandler(&xmlHandler); QXmlInputSource xmlInputSource(file); if (!xmlReader.parse(xmlInputSource)) { warning() << QString(QLatin1String("Error parsing profile file %1: %2")) .arg(file->fileName()) .arg(xmlHandler.errorString()); invalidate(); return false; } valid = true; return true; } void Profile::Private::invalidate() { valid = false; data.clear(); } /** * \class Profile * \ingroup utils * \headerfile TelepathyQt/profile.h * * \brief The Profile class provides an easy way to read Telepathy profile * files according to http://telepathy.freedesktop.org/wiki/service-profile-v1. * * Note that profiles with xml element different than "IM" are considered * invalid. */ /** * Create a new Profile object used to read .profiles compliant files. * * \param serviceName The profile service name. * \return A ProfilePtr object pointing to the newly created Profile object. */ ProfilePtr Profile::createForServiceName(const QString &serviceName) { ProfilePtr profile = ProfilePtr(new Profile()); profile->setServiceName(serviceName); return profile; } /** * Create a new Profile object used to read .profiles compliant files. * * \param fileName The profile file name. * \return A ProfilePtr object pointing to the newly created Profile object. */ ProfilePtr Profile::createForFileName(const QString &fileName) { ProfilePtr profile = ProfilePtr(new Profile()); profile->setFileName(fileName); return profile; } /** * Construct a new Profile object used to read .profiles compliant files. * * \param serviceName The profile service name. */ Profile::Profile() : mPriv(new Private()) { } /** * Construct a fake profile using the given \a serviceName, \a cmName, * \a protocolName and \a protocolInfo. * * - isFake() will return \c true * - type() will return "IM" * - provider() will return an empty string * - serviceName() will return \a serviceName * - name() and protocolName() will return \a protocolName * - iconName() will return "im-\a protocolName" * - cmName() will return \a cmName * - parameters() will return a list matching CM default parameters * - presences() will return an empty list and allowOtherPresences will return * \c true, meaning that CM presences should be used * - unsupportedChannelClassSpecs() will return an empty list * * \param serviceName The service name. * \param cmName The connection manager name. * \param protocolName The protocol name. * \param protocolInfo The protocol info for the protocol \a protocolName. */ Profile::Profile(const QString &serviceName, const QString &cmName, const QString &protocolName, const ProtocolInfo &protocolInfo) : mPriv(new Private()) { mPriv->serviceName = serviceName; mPriv->data.type = QString(QLatin1String("IM")); // provider is empty mPriv->data.name = protocolName; mPriv->data.iconName = QString(QLatin1String("im-%1")).arg(protocolName); mPriv->data.cmName = cmName; mPriv->data.protocolName = protocolName; foreach (const ProtocolParameter &protocolParam, protocolInfo.parameters()) { if (!protocolParam.defaultValue().isNull()) { mPriv->data.parameters.append(Profile::Parameter( protocolParam.name(), protocolParam.dbusSignature(), protocolParam.defaultValue(), QString(), // label false)); // mandatory } } // parameters will be the same as CM parameters // set allow others to true meaning that the standard CM presences are // supported mPriv->data.allowOtherPresences = true; // presences will be the same as CM presences // unsupported channel classes is empty mPriv->valid = true; mPriv->fake = true; } /** * Class destructor. */ Profile::~Profile() { delete mPriv; } /** * Return the unique name of the service to which this profile applies. * * \return The unique name of the service. */ QString Profile::serviceName() const { return mPriv->serviceName; } /** * Return whether this profile is valid. * * \return \c true if valid, otherwise \c false. */ bool Profile::isValid() const { return mPriv->valid; } /** * Return whether this profile is fake. * * Fake profiles are profiles created for services not providing a .profile * file. * * \return \c true if fake, otherwise \c false. */ bool Profile::isFake() const { return mPriv->fake; } /** * Return the type of the service to which this profile applies. * * In general, services of interest of Telepathy should be of type 'IM'. * Other service types exist but are unlikely to affect Telepathy in any way. * * \return The type of the service. */ QString Profile::type() const { return mPriv->data.type; } /** * Return the name of the vendor/organisation/provider who actually runs the * service to which this profile applies. * * \return The provider of the service. */ QString Profile::provider() const { return mPriv->data.provider; } /** * Return the human-readable name for the service to which this profile applies. * * \return The Human-readable name of the service. */ QString Profile::name() const { return mPriv->data.name; } /** * Return the base name of the icon for the service to which this profile * applies. * * \return The base name of the icon for the service. */ QString Profile::iconName() const { return mPriv->data.iconName; } /** * Return the connection manager name for the service to which this profile * applies. * * \return The connection manager name for the service. */ QString Profile::cmName() const { return mPriv->data.cmName; } /** * Return the protocol name for the service to which this profile applies. * * \return The protocol name for the service. */ QString Profile::protocolName() const { return mPriv->data.protocolName; } /** * Return a list of parameters defined for the service to which this profile * applies. * * \return A list of Profile::Parameter. */ Profile::ParameterList Profile::parameters() const { return mPriv->data.parameters; } /** * Return whether this profile defines the parameter named \a name. * * \return \c true if parameter is defined, otherwise \c false. */ bool Profile::hasParameter(const QString &name) const { foreach (const Parameter ¶meter, mPriv->data.parameters) { if (parameter.name() == name) { return true; } } return false; } /** * Return the parameter for a given \a name. * * \return A Profile::Parameter. */ Profile::Parameter Profile::parameter(const QString &name) const { foreach (const Parameter ¶meter, mPriv->data.parameters) { if (parameter.name() == name) { return parameter; } } return Profile::Parameter(); } /** * Return whether the standard CM presences not defined in presences() are * supported. * * \return \c true if standard CM presences are supported, otherwise \c false. */ bool Profile::allowOtherPresences() const { return mPriv->data.allowOtherPresences; } /** * Return a list of presences defined for the service to which this profile * applies. * * \return A list of Profile::Presence. */ Profile::PresenceList Profile::presences() const { return mPriv->data.presences; } /** * Return whether this profile defines the presence with id \a id. * * \return \c true if presence is defined, otherwise \c false. */ bool Profile::hasPresence(const QString &id) const { foreach (const Presence &presence, mPriv->data.presences) { if (presence.id() == id) { return true; } } return false; } /** * Return the presence for a given \a id. * * \return A Profile::Presence. */ Profile::Presence Profile::presence(const QString &id) const { foreach (const Presence &presence, mPriv->data.presences) { if (presence.id() == id) { return presence; } } return Profile::Presence(); } /** * A list of channel classes not supported by the service to which this profile * applies. * * \return A list of RequestableChannelClassSpec. */ RequestableChannelClassSpecList Profile::unsupportedChannelClassSpecs() const { return mPriv->data.unsupportedChannelClassSpecs; } void Profile::setServiceName(const QString &serviceName) { mPriv->setServiceName(serviceName); } void Profile::setFileName(const QString &fileName) { mPriv->setFileName(fileName); } QStringList Profile::searchDirs() { QStringList ret; QString xdgDataHome = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME")); if (xdgDataHome.isEmpty()) { ret << QDir::homePath() + QLatin1String("/.local/share/data/telepathy/profiles/"); } else { ret << xdgDataHome + QLatin1String("/telepathy/profiles/"); } QString xdgDataDirsEnv = QString::fromLocal8Bit(qgetenv("XDG_DATA_DIRS")); if (xdgDataDirsEnv.isEmpty()) { ret << QLatin1String("/usr/local/share/telepathy/profiles/"); ret << QLatin1String("/usr/share/telepathy/profiles/"); } else { QStringList xdgDataDirs = xdgDataDirsEnv.split(QLatin1Char(':')); foreach (const QString xdgDataDir, xdgDataDirs) { ret << xdgDataDir + QLatin1String("/telepathy/profiles/"); } } return ret; } struct TP_QT_NO_EXPORT Profile::Parameter::Private { QString name; QDBusSignature dbusSignature; QVariant value; QString label; bool mandatory; }; /** * \class Profile::Parameter * \ingroup utils * \headerfile TelepathyQt/profile.h * * \brief The Profile::Parameter class represents a parameter defined in * .profile files. */ /** * Construct a new Profile::Parameter object. */ Profile::Parameter::Parameter() : mPriv(new Private) { mPriv->mandatory = false; } /** * Construct a new Profile::Parameter object that is a copy of \a other. */ Profile::Parameter::Parameter(const Parameter &other) : mPriv(new Private) { mPriv->name = other.mPriv->name; mPriv->dbusSignature = other.mPriv->dbusSignature; mPriv->value = other.mPriv->value; mPriv->label = other.mPriv->label; mPriv->mandatory = other.mPriv->mandatory; } /** * Construct a new Profile::Parameter object. * * \param name The parameter name. * \param dbusSignature The parameter D-Bus signature. * \param value The parameter value. * \param label The parameter label. * \param mandatory Whether this parameter is mandatory. */ Profile::Parameter::Parameter(const QString &name, const QDBusSignature &dbusSignature, const QVariant &value, const QString &label, bool mandatory) : mPriv(new Private) { mPriv->name = name; mPriv->dbusSignature = dbusSignature; mPriv->value = value; mPriv->label = label; mPriv->mandatory = mandatory; } /** * Class destructor. */ Profile::Parameter::~Parameter() { delete mPriv; } /** * Return the name of this parameter. * * \return The name of this parameter. */ QString Profile::Parameter::name() const { return mPriv->name; } void Profile::Parameter::setName(const QString &name) { mPriv->name = name; } /** * Return the D-Bus signature of this parameter. * * \return The D-Bus signature of this parameter. */ QDBusSignature Profile::Parameter::dbusSignature() const { return mPriv->dbusSignature; } void Profile::Parameter::setDBusSignature(const QDBusSignature &dbusSignature) { mPriv->dbusSignature = dbusSignature; } /** * Return the QVariant::Type of this parameter, constructed using * dbusSignature(). * * \return The QVariant::Type of this parameter. */ QVariant::Type Profile::Parameter::type() const { return variantTypeFromDBusSignature(mPriv->dbusSignature.signature()); } /** * Return the value of this parameter. * * If mandatory() returns \c true, the value must not be modified and should be * used as is when creating accounts for this profile. * * \return The value of this parameter. */ QVariant Profile::Parameter::value() const { return mPriv->value; } void Profile::Parameter::setValue(const QVariant &value) { mPriv->value = value; } /** * Return the human-readable label of this parameter. * * \return The human-readable label of this parameter. */ QString Profile::Parameter::label() const { return mPriv->label; } void Profile::Parameter::setLabel(const QString &label) { mPriv->label = label; } /** * Return whether this parameter is mandatory, or whether the value returned by * value() should be used as is when creating accounts for this profile. * * \return \c true if mandatory, otherwise \c false. */ bool Profile::Parameter::isMandatory() const { return mPriv->mandatory; } void Profile::Parameter::setMandatory(bool mandatory) { mPriv->mandatory = mandatory; } Profile::Parameter &Profile::Parameter::operator=(const Profile::Parameter &other) { mPriv->name = other.mPriv->name; mPriv->dbusSignature = other.mPriv->dbusSignature; mPriv->value = other.mPriv->value; mPriv->label = other.mPriv->label; mPriv->mandatory = other.mPriv->mandatory; return *this; } struct TP_QT_NO_EXPORT Profile::Presence::Private { QString id; QString label; QString iconName; QString message; bool disabled; }; /** * \class Profile::Presence * \ingroup utils * \headerfile TelepathyQt/profile.h * * \brief The Profile::Presence class represents a presence defined in * .profile files. */ /** * Construct a new Profile::Presence object. */ Profile::Presence::Presence() : mPriv(new Private) { mPriv->disabled = false; } /** * Construct a new Profile::Presence object that is a copy of \a other. */ Profile::Presence::Presence(const Presence &other) : mPriv(new Private) { mPriv->id = other.mPriv->id; mPriv->label = other.mPriv->label; mPriv->iconName = other.mPriv->iconName; mPriv->message = other.mPriv->message; mPriv->disabled = other.mPriv->disabled; } /** * Construct a new Profile::Presence object. * * \param id The presence id. * \param label The presence label. * \param iconName The presence icon name. * \param message The presence message. * \param disabled Whether this presence is supported. */ Profile::Presence::Presence(const QString &id, const QString &label, const QString &iconName, const QString &message, bool disabled) : mPriv(new Private) { mPriv->id = id; mPriv->label = label; mPriv->iconName = iconName; mPriv->message = message; mPriv->disabled = disabled; } /** * Class destructor. */ Profile::Presence::~Presence() { delete mPriv; } /** * Return the Telepathy presence id for this presence. * * \return The Telepathy presence id for this presence. */ QString Profile::Presence::id() const { return mPriv->id; } void Profile::Presence::setId(const QString &id) { mPriv->id = id; } /** * Return the label that should be used for this presence. * * \return The label for this presence. */ QString Profile::Presence::label() const { return mPriv->label; } void Profile::Presence::setLabel(const QString &label) { mPriv->label = label; } /** * Return the icon name of this presence. * * \return The icon name of this presence. */ QString Profile::Presence::iconName() const { return mPriv->iconName; } void Profile::Presence::setIconName(const QString &iconName) { mPriv->iconName = iconName; } /** * Return whether user-defined text-message can be attached to this presence. * * \return \c true if user-defined text-message can be attached to this presence, \c false * otherwise. */ bool Profile::Presence::canHaveStatusMessage() const { if (mPriv->message == QLatin1String("1") || mPriv->message == QLatin1String("true")) { return true; } return false; } void Profile::Presence::setMessage(const QString &message) { mPriv->message = message; } /** * Return whether this presence is supported for the service to which this * profile applies. * * \return \c true if supported, otherwise \c false. */ bool Profile::Presence::isDisabled() const { return mPriv->disabled; } void Profile::Presence::setDisabled(bool disabled) { mPriv->disabled = disabled; } Profile::Presence &Profile::Presence::operator=(const Profile::Presence &other) { mPriv->id = other.mPriv->id; mPriv->label = other.mPriv->label; mPriv->iconName = other.mPriv->iconName; mPriv->message = other.mPriv->message; mPriv->disabled = other.mPriv->disabled; return *this; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/client-registrar-internal.h0000664000175000017500000002724212470405660022464 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_client_registrar_internal_h_HEADER_GUARD_ #define _TelepathyQt_client_registrar_internal_h_HEADER_GUARD_ #include #include #include #include #include #include #include "TelepathyQt/fake-handler-manager-internal.h" namespace Tp { class PendingOperation; class TP_QT_NO_EXPORT ClientAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Client") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" "") Q_PROPERTY(QStringList Interfaces READ Interfaces) public: ClientAdaptor(ClientRegistrar *registrar, const QStringList &interfaces, QObject *parent); virtual ~ClientAdaptor(); inline const ClientRegistrar *registrar() const { return mRegistrar; } public: // Properties inline QStringList Interfaces() const { return mInterfaces; } private: ClientRegistrar *mRegistrar; QStringList mInterfaces; }; class TP_QT_NO_EXPORT ClientObserverAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Client.Observer") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(Tp::ChannelClassList ObserverChannelFilter READ ObserverChannelFilter) Q_PROPERTY(bool Recover READ Recover) public: ClientObserverAdaptor(ClientRegistrar *registrar, AbstractClientObserver *client, QObject *parent); virtual ~ClientObserverAdaptor(); inline const ClientRegistrar *registrar() const { return mRegistrar; } public: // Properties inline Tp::ChannelClassList ObserverChannelFilter() const { return mClient->observerFilter().bareClasses(); } inline bool Recover() const { return mClient->shouldRecover(); } public Q_SLOTS: // Methods void ObserveChannels(const QDBusObjectPath &account, const QDBusObjectPath &connection, const Tp::ChannelDetailsList &channels, const QDBusObjectPath &dispatchOperation, const Tp::ObjectPathList &requestsSatisfied, const QVariantMap &observerInfo, const QDBusMessage &message); private Q_SLOTS: void onReadyOpFinished(Tp::PendingOperation *); private: struct InvocationData : RefCounted { InvocationData() : readyOp(0) {} PendingOperation *readyOp; QString error, message; MethodInvocationContextPtr<> ctx; AccountPtr acc; ConnectionPtr conn; QList chans; ChannelDispatchOperationPtr dispatchOp; QList chanReqs; AbstractClientObserver::ObserverInfo observerInfo; }; QLinkedList > mInvocations; ClientRegistrar *mRegistrar; QDBusConnection mBus; AbstractClientObserver *mClient; }; class TP_QT_NO_EXPORT ClientApproverAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Client.Approver") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(Tp::ChannelClassList ApproverChannelFilter READ ApproverChannelFilter) public: ClientApproverAdaptor(ClientRegistrar *registrar, AbstractClientApprover *client, QObject *parent); virtual ~ClientApproverAdaptor(); inline const ClientRegistrar *registrar() const { return mRegistrar; } public: // Properties inline Tp::ChannelClassList ApproverChannelFilter() const { return mClient->approverFilter().bareClasses(); } public Q_SLOTS: // Methods void AddDispatchOperation(const Tp::ChannelDetailsList &channels, const QDBusObjectPath &dispatchOperation, const QVariantMap &properties, const QDBusMessage &message); private Q_SLOTS: void onReadyOpFinished(Tp::PendingOperation *); private: struct InvocationData : RefCounted { InvocationData() : readyOp(0) {} PendingOperation *readyOp; QString error, message; MethodInvocationContextPtr<> ctx; QList chans; ChannelDispatchOperationPtr dispatchOp; }; QLinkedList > mInvocations; private: ClientRegistrar *mRegistrar; QDBusConnection mBus; AbstractClientApprover *mClient; }; class TP_QT_NO_EXPORT ClientHandlerAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Client.Handler") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") Q_PROPERTY(Tp::ChannelClassList HandlerChannelFilter READ HandlerChannelFilter) Q_PROPERTY(bool BypassApproval READ BypassApproval) Q_PROPERTY(QStringList Capabilities READ Capabilities) Q_PROPERTY(Tp::ObjectPathList HandledChannels READ HandledChannels) public: ClientHandlerAdaptor(ClientRegistrar *registrar, AbstractClientHandler *client, QObject *parent); virtual ~ClientHandlerAdaptor(); inline const ClientRegistrar *registrar() const { return mRegistrar; } public: // Properties inline Tp::ChannelClassList HandlerChannelFilter() const { return mClient->handlerFilter().bareClasses(); } inline bool BypassApproval() const { return mClient->bypassApproval(); } inline QStringList Capabilities() const { return mClient->handlerCapabilities().allTokens(); } inline Tp::ObjectPathList HandledChannels() const { return FakeHandlerManager::instance()->handledChannels(mBus); } public Q_SLOTS: // Methods void HandleChannels(const QDBusObjectPath &account, const QDBusObjectPath &connection, const Tp::ChannelDetailsList &channels, const Tp::ObjectPathList &requestsSatisfied, qulonglong userActionTime, const QVariantMap &handlerInfo, const QDBusMessage &message); private Q_SLOTS: void onReadyOpFinished(Tp::PendingOperation *); private: struct InvocationData : RefCounted { InvocationData() : readyOp(0) {} PendingOperation *readyOp; QString error, message; MethodInvocationContextPtr<> ctx; AccountPtr acc; ConnectionPtr conn; QList chans; QList chanReqs; QDateTime time; AbstractClientHandler::HandlerInfo handlerInfo; }; QLinkedList > mInvocations; private: static void onContextFinished(const MethodInvocationContextPtr<> &context, const QList &channels, ClientHandlerAdaptor *self); ClientRegistrar *mRegistrar; QDBusConnection mBus; AbstractClientHandler *mClient; static QHash, QList > mAdaptorsForConnection; }; class TP_QT_NO_EXPORT ClientHandlerRequestsAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Telepathy.Client.Interface.Requests") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: ClientHandlerRequestsAdaptor(ClientRegistrar *registrar, AbstractClientHandler *client, QObject *parent); virtual ~ClientHandlerRequestsAdaptor(); inline const ClientRegistrar *registrar() const { return mRegistrar; } public Q_SLOTS: // Methods void AddRequest(const QDBusObjectPath &request, const QVariantMap &requestProperties, const QDBusMessage &message); void RemoveRequest(const QDBusObjectPath &request, const QString &errorName, const QString &errorMessage, const QDBusMessage &message); private: ClientRegistrar *mRegistrar; QDBusConnection mBus; AbstractClientHandler *mClient; }; } // Tp Q_DECLARE_METATYPE(Tp::ClientAdaptor*) Q_DECLARE_METATYPE(Tp::ClientApproverAdaptor*) Q_DECLARE_METATYPE(Tp::ClientHandlerAdaptor*) Q_DECLARE_METATYPE(Tp::ClientHandlerRequestsAdaptor*) Q_DECLARE_METATYPE(Tp::ClientObserverAdaptor*) #endif telepathy-qt-0.9.6~git1/TelepathyQt/readiness-helper.cpp0000664000175000017500000005473312470405660021166 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/readiness-helper.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ReadinessHelper::Introspectable::Private : public QSharedData { Private(const QSet &makesSenseForStatuses, const Features &dependsOnFeatures, const QStringList &dependsOnInterfaces, IntrospectFunc introspectFunc, void *introspectFuncData, bool critical) : makesSenseForStatuses(makesSenseForStatuses), dependsOnFeatures(dependsOnFeatures), dependsOnInterfaces(dependsOnInterfaces), introspectFunc(introspectFunc), introspectFuncData(introspectFuncData), critical(critical) {} QSet makesSenseForStatuses; Features dependsOnFeatures; QStringList dependsOnInterfaces; IntrospectFunc introspectFunc; void *introspectFuncData; bool critical; }; ReadinessHelper::Introspectable::Introspectable() : mPriv(new Private(QSet(), Features(), QStringList(), 0, 0, false)) { } ReadinessHelper::Introspectable::Introspectable(const QSet &makesSenseForStatuses, const Features &dependsOnFeatures, const QStringList &dependsOnInterfaces, IntrospectFunc introspectFunc, void *introspectFuncData, bool critical) : mPriv(new Private(makesSenseForStatuses, dependsOnFeatures, dependsOnInterfaces, introspectFunc, introspectFuncData, critical)) { } ReadinessHelper::Introspectable::Introspectable(const Introspectable &other) : mPriv(other.mPriv) { } ReadinessHelper::Introspectable::~Introspectable() { } ReadinessHelper::Introspectable &ReadinessHelper::Introspectable::operator=( const Introspectable &other) { mPriv = other.mPriv; return *this; } struct TP_QT_NO_EXPORT ReadinessHelper::Private { Private(ReadinessHelper *parent, RefCounted *object, uint currentStatus, const Introspectables &introspectables); Private(ReadinessHelper *parent, DBusProxy *proxy, uint currentStatus, const Introspectables &introspectables); ~Private(); void setCurrentStatus(uint newStatus); void setIntrospectCompleted(const Feature &feature, bool success, const QString &errorName = QString(), const QString &errorMessage = QString()); void iterateIntrospection(); Features depsFor(const Feature &feature); // Recursive dependencies for a feature void abortOperations(const QString &errorName, const QString &errorMessage); ReadinessHelper *parent; RefCounted *object; DBusProxy *proxy; uint currentStatus; QStringList interfaces; Introspectables introspectables; QSet supportedStatuses; Features supportedFeatures; Features satisfiedFeatures; Features requestedFeatures; Features missingFeatures; Features pendingFeatures; Features inFlightFeatures; QHash > missingFeaturesErrors; QList pendingOperations; bool pendingStatusChange; uint pendingStatus; }; ReadinessHelper::Private::Private( ReadinessHelper *parent, RefCounted *object, uint currentStatus, const Introspectables &introspectables) : parent(parent), object(object), proxy(0), currentStatus(currentStatus), introspectables(introspectables), pendingStatusChange(false), pendingStatus(-1) { for (Introspectables::const_iterator i = introspectables.constBegin(); i != introspectables.constEnd(); ++i) { Feature feature = i.key(); Introspectable introspectable = i.value(); Q_ASSERT(introspectable.mPriv->introspectFunc != 0); supportedStatuses += introspectable.mPriv->makesSenseForStatuses; supportedFeatures += feature; } } ReadinessHelper::Private::Private( ReadinessHelper *parent, DBusProxy *proxy, uint currentStatus, const Introspectables &introspectables) : parent(parent), object(proxy), proxy(proxy), currentStatus(currentStatus), introspectables(introspectables), pendingStatusChange(false), pendingStatus(-1) { Q_ASSERT(proxy != 0); for (Introspectables::const_iterator i = introspectables.constBegin(); i != introspectables.constEnd(); ++i) { Feature feature = i.key(); Introspectable introspectable = i.value(); Q_ASSERT(introspectable.mPriv->introspectFunc != 0); supportedStatuses += introspectable.mPriv->makesSenseForStatuses; supportedFeatures += feature; } } ReadinessHelper::Private::~Private() { const static QString messageDestroyed(QLatin1String("Destroyed")); abortOperations(TP_QT_ERROR_CANCELLED, messageDestroyed); } void ReadinessHelper::Private::setCurrentStatus(uint newStatus) { if (currentStatus == newStatus) { return; } if (inFlightFeatures.isEmpty()) { currentStatus = newStatus; satisfiedFeatures.clear(); missingFeatures.clear(); // Make all features that were requested for the new status pending again pendingFeatures = requestedFeatures; // becomeReady ensures that the recursive dependencies of the requested features are already // in the requested set, so we don't have to re-add them here if (supportedStatuses.contains(currentStatus)) { QTimer::singleShot(0, parent, SLOT(iterateIntrospection())); } else { emit parent->statusReady(currentStatus); } } else { debug() << "status changed while introspection process was running"; pendingStatusChange = true; pendingStatus = newStatus; } } void ReadinessHelper::Private::setIntrospectCompleted(const Feature &feature, bool success, const QString &errorName, const QString &errorMessage) { debug() << "ReadinessHelper::setIntrospectCompleted: feature:" << feature << "- success:" << success; if (pendingStatusChange) { debug() << "ReadinessHelper::setIntrospectCompleted called while there is " "a pending status change - ignoring"; inFlightFeatures.remove(feature); // ignore all introspection completed as the state changed if (!inFlightFeatures.isEmpty()) { return; } pendingStatusChange = false; setCurrentStatus(pendingStatus); return; } Q_ASSERT(pendingFeatures.contains(feature)); Q_ASSERT(inFlightFeatures.contains(feature)); if (success) { satisfiedFeatures.insert(feature); } else { missingFeatures.insert(feature); missingFeaturesErrors.insert(feature, QPair(errorName, errorMessage)); if (errorName.isEmpty()) { warning() << "ReadinessHelper::setIntrospectCompleted: Feature" << feature << "introspection failed but no error message was given"; } } pendingFeatures.remove(feature); inFlightFeatures.remove(feature); QTimer::singleShot(0, parent, SLOT(iterateIntrospection())); } void ReadinessHelper::Private::iterateIntrospection() { if (proxy && !proxy->isValid()) { debug() << "ReadinessHelper: not iterating as the proxy is invalidated"; return; } // When there's a pending status change, we MUST NOT // - finish PendingReadys (as they'd not be finished in the new status) // - claim a status as being ready (because the new one isn't) // and SHOULD NOT // - fire new introspection jobs (as that would just delay the pending status change even more) // and NEED NOT // - flag features as missing (as the completed features will be cleared anyway when starting // introspection for the new status) // // So we can safely skip the rest of this function here. if (pendingStatusChange) { debug() << "ReadinessHelper: not iterating as a status change is pending"; return; } // Flag the currently pending reverse dependencies of any previously discovered missing features // as missing foreach (const Feature &feature, pendingFeatures) { if (!depsFor(feature).intersect(missingFeatures).isEmpty()) { missingFeatures.insert(feature); missingFeaturesErrors.insert(feature, QPair(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Feature depends on other features that are not available"))); } } const Features completedFeatures = satisfiedFeatures + missingFeatures; // check if any pending operations for becomeReady should finish now // based on their requested features having nothing more than what // satisfiedFeatures + missingFeatures has QString errorName; QString errorMessage; foreach (PendingReady *operation, pendingOperations) { if ((operation->requestedFeatures() - completedFeatures).isEmpty()) { if (parent->isReady(operation->requestedFeatures(), &errorName, &errorMessage)) { operation->setFinished(); } else { operation->setFinishedWithError(errorName, errorMessage); } // Remove the operation from tracking, so we don't double-finish it // // Qt foreach makes a copy of the container, which will be detached at this point, so // this is perfectly safe pendingOperations.removeOne(operation); } } if ((requestedFeatures - completedFeatures).isEmpty()) { // Otherwise, we'd emit statusReady with currentStatus although we are supposed to be // introspecting the pendingStatus and only when that is complete, emit statusReady Q_ASSERT(!pendingStatusChange); // all requested features satisfied or missing emit parent->statusReady(currentStatus); return; } // update pendingFeatures with the difference of requested and // satisfied + missing pendingFeatures -= completedFeatures; // find out which features don't have dependencies that are still pending Features readyToIntrospect; foreach (const Feature &feature, pendingFeatures) { // missing doesn't have to be considered here anymore if ((introspectables[feature].mPriv->dependsOnFeatures - satisfiedFeatures).isEmpty()) { readyToIntrospect.insert(feature); } } // now readyToIntrospect should contain all the features which have // all their feature dependencies satisfied foreach (const Feature &feature, readyToIntrospect) { if (inFlightFeatures.contains(feature)) { continue; } inFlightFeatures.insert(feature); Introspectable introspectable = introspectables[feature]; if (!introspectable.mPriv->makesSenseForStatuses.contains(currentStatus)) { // No-op satisfy features for which nothing has to be done in // the current state setIntrospectCompleted(feature, true); return; // will be called with a single-shot soon again } foreach (const QString &interface, introspectable.mPriv->dependsOnInterfaces) { if (!interfaces.contains(interface)) { // If a feature is ready to introspect and depends on a interface // that is not present the feature can't possibly be satisfied debug() << "feature" << feature << "depends on interfaces" << introspectable.mPriv->dependsOnInterfaces << ", but interface" << interface << "is not present"; setIntrospectCompleted(feature, false, TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Feature depend on interfaces that are not available")); return; // will be called with a single-shot soon again } } // yes, with the dependency info, we can even parallelize // introspection of several features at once, reducing total round trip // time considerably with many independent features! (*(introspectable.mPriv->introspectFunc))(introspectable.mPriv->introspectFuncData); } } Features ReadinessHelper::Private::depsFor(const Feature &feature) { Features deps; foreach (Feature dep, introspectables[feature].mPriv->dependsOnFeatures) { deps += dep; deps += depsFor(dep); } return deps; } void ReadinessHelper::Private::abortOperations(const QString &errorName, const QString &errorMessage) { foreach (PendingReady *operation, pendingOperations) { operation->setFinishedWithError(errorName, errorMessage); } pendingOperations.clear(); } /** * \class ReadinessHelper * \ingroup utils * \headerfile TelepathyQt/readiness-helper.h * * \brief The ReadinessHelper class is a helper class used by the introspection * process. */ /** * \class ReadinessHelper::Introspectable * \ingroup utils * \headerfile TelepathyQt/readiness-helper.h * * \brief The ReadinessHelper::Introspectable class represents a introspectable * used by ReadinessHelper. */ ReadinessHelper::ReadinessHelper(RefCounted *object, uint currentStatus, const Introspectables &introspectables, QObject *parent) : QObject(parent), mPriv(new Private(this, object, currentStatus, introspectables)) { } ReadinessHelper::ReadinessHelper(DBusProxy *proxy, uint currentStatus, const Introspectables &introspectables, QObject *parent) : QObject(parent), mPriv(new Private(this, proxy, currentStatus, introspectables)) { } ReadinessHelper::~ReadinessHelper() { delete mPriv; } void ReadinessHelper::addIntrospectables(const Introspectables &introspectables) { // QMap::unite will create multiple items if the key is already in the map // so let's make sure we don't duplicate keys for (Introspectables::const_iterator i = introspectables.constBegin(); i != introspectables.constEnd(); ++i) { Feature feature = i.key(); if (mPriv->introspectables.contains(feature)) { warning() << "ReadinessHelper::addIntrospectables: trying to add an " "introspectable for feature" << feature << "but introspectable " "for this feature already exists"; } else { Introspectable introspectable = i.value(); mPriv->introspectables.insert(feature, introspectable); mPriv->supportedStatuses += introspectable.mPriv->makesSenseForStatuses; mPriv->supportedFeatures += feature; } } debug() << "ReadinessHelper: new supportedStatuses =" << mPriv->supportedStatuses; debug() << "ReadinessHelper: new supportedFeatures =" << mPriv->supportedFeatures; } uint ReadinessHelper::currentStatus() const { return mPriv->currentStatus; } void ReadinessHelper::setCurrentStatus(uint currentStatus) { mPriv->setCurrentStatus(currentStatus); } /** * Force the current internal status to \a currentStatus. * * Note that this method will not start a new introspection or restart the * current one in case one is running. * * This is useful for example when the status is unknown initially but it will * become known in the first introspection run and there is no need to re-run * the introspection. * * \param currentStatus The status to set. */ void ReadinessHelper::forceCurrentStatus(uint currentStatus) { mPriv->currentStatus = currentStatus; } QStringList ReadinessHelper::interfaces() const { return mPriv->interfaces; } void ReadinessHelper::setInterfaces(const QStringList &interfaces) { mPriv->interfaces = interfaces; } Features ReadinessHelper::requestedFeatures() const { return mPriv->requestedFeatures; } Features ReadinessHelper::actualFeatures() const { return mPriv->satisfiedFeatures; } Features ReadinessHelper::missingFeatures() const { return mPriv->missingFeatures; } bool ReadinessHelper::isReady(const Feature &feature, QString *errorName, QString *errorMessage) const { if (mPriv->proxy && !mPriv->proxy->isValid()) { if (errorName) { *errorName = mPriv->proxy->invalidationReason(); } if (errorMessage) { *errorMessage = mPriv->proxy->invalidationMessage(); } return false; } if (!mPriv->supportedFeatures.contains(feature)) { if (errorName) { *errorName = TP_QT_ERROR_INVALID_ARGUMENT; } if (errorMessage) { *errorMessage = QLatin1String("Unsupported feature"); } return false; } bool ret = true; if (feature.isCritical()) { if (!mPriv->satisfiedFeatures.contains(feature)) { ret = false; } } else { if (!mPriv->satisfiedFeatures.contains(feature) && !mPriv->missingFeatures.contains(feature)) { ret = false; } } if (!ret) { QPair error = mPriv->missingFeaturesErrors[feature]; if (errorName) { *errorName = error.first; } if (errorMessage) { *errorMessage = error.second; } } return ret; } bool ReadinessHelper::isReady(const Features &features, QString *errorName, QString *errorMessage) const { if (mPriv->proxy && !mPriv->proxy->isValid()) { if (errorName) { *errorName = mPriv->proxy->invalidationReason(); } if (errorMessage) { *errorMessage = mPriv->proxy->invalidationMessage(); } return false; } Q_ASSERT(!features.isEmpty()); foreach (const Feature &feature, features) { if (!isReady(feature, errorName, errorMessage)) { return false; } } return true; } PendingReady *ReadinessHelper::becomeReady(const Features &requestedFeatures) { Q_ASSERT(!requestedFeatures.isEmpty()); if (mPriv->proxy) { connect(mPriv->proxy, SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), this, SLOT(onProxyInvalidated(Tp::DBusProxy*,QString,QString)), Qt::UniqueConnection); if (!mPriv->proxy->isValid()) { PendingReady *operation = new PendingReady(SharedPtr(mPriv->object), requestedFeatures); operation->setFinishedWithError(mPriv->proxy->invalidationReason(), mPriv->proxy->invalidationMessage()); return operation; } } Features supportedFeatures = mPriv->supportedFeatures; if (supportedFeatures.intersect(requestedFeatures) != requestedFeatures) { warning() << "ReadinessHelper::becomeReady called with invalid features: requestedFeatures =" << requestedFeatures << "- supportedFeatures =" << mPriv->supportedFeatures; PendingReady *operation = new PendingReady(SharedPtr(mPriv->object), requestedFeatures); operation->setFinishedWithError( TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Requested features contains unsupported feature")); return operation; } if (mPriv->proxy && !mPriv->proxy->isValid()) { PendingReady *operation = new PendingReady(SharedPtr(mPriv->object), requestedFeatures); operation->setFinishedWithError(mPriv->proxy->invalidationReason(), mPriv->proxy->invalidationMessage()); return operation; } PendingReady *operation; foreach (operation, mPriv->pendingOperations) { if (operation->requestedFeatures() == requestedFeatures) { return operation; } } // Insert the dependencies of the requested features too Features requestedWithDeps = requestedFeatures; foreach (const Feature &feature, requestedFeatures) { requestedWithDeps.unite(mPriv->depsFor(feature)); } mPriv->requestedFeatures += requestedWithDeps; mPriv->pendingFeatures += requestedWithDeps; // will be updated in iterateIntrospection operation = new PendingReady(SharedPtr(mPriv->object), requestedFeatures); mPriv->pendingOperations.append(operation); // Only we finish these PendingReadys, so we don't need destroyed or finished handling for them // - we already know when that happens, as we caused it! QTimer::singleShot(0, this, SLOT(iterateIntrospection())); return operation; } void ReadinessHelper::setIntrospectCompleted(const Feature &feature, bool success, const QString &errorName, const QString &errorMessage) { if (mPriv->proxy && !mPriv->proxy->isValid()) { // proxy became invalid, ignore here return; } mPriv->setIntrospectCompleted(feature, success, errorName, errorMessage); } void ReadinessHelper::setIntrospectCompleted(const Feature &feature, bool success, const QDBusError &error) { setIntrospectCompleted(feature, success, error.name(), error.message()); } void ReadinessHelper::iterateIntrospection() { mPriv->iterateIntrospection(); } void ReadinessHelper::onProxyInvalidated(DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { // clear satisfied and missing features as we have public methods to get them mPriv->satisfiedFeatures.clear(); mPriv->missingFeatures.clear(); mPriv->abortOperations(errorName, errorMessage); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/stream-tube-server.h0000664000175000017500000001762212470405660021131 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_stream_tube_server_h_HEADER_GUARD_ #define _TelepathyQt_stream_tube_server_h_HEADER_GUARD_ #include #include #include #include #include #include #include #include class QHostAddress; class QTcpServer; namespace Tp { class TP_QT_EXPORT StreamTubeServer : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(StreamTubeServer) class TubeWrapper; public: class ParametersGenerator { public: virtual QVariantMap nextParameters(const AccountPtr &account, const OutgoingStreamTubeChannelPtr &tube, const ChannelRequestHints &hints) = 0; protected: virtual ~ParametersGenerator() {} }; class RemoteContact : public QPair { public: RemoteContact(); RemoteContact(const AccountPtr &account, const ContactPtr &contact); RemoteContact(const RemoteContact &other); ~RemoteContact(); bool isValid() const { return mPriv.constData() != 0; } RemoteContact &operator=(const RemoteContact &other); const AccountPtr &account() const { return first; } const ContactPtr &contact() const { return second; } private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; class Tube : public QPair { public: Tube(); Tube(const AccountPtr &account, const OutgoingStreamTubeChannelPtr &channel); Tube(const Tube &other); ~Tube(); bool isValid() const { return mPriv.constData() != 0; } Tube &operator=(const Tube &other); const AccountPtr &account() const { return first; } const OutgoingStreamTubeChannelPtr &channel() const { return second; } private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; static StreamTubeServerPtr create( const QStringList &p2pServices, const QStringList &roomServices = QStringList(), const QString &clientName = QString(), bool monitorConnections = false, const AccountFactoryConstPtr &accountFactory = AccountFactory::create(QDBusConnection::sessionBus()), const ConnectionFactoryConstPtr &connectionFactory = ConnectionFactory::create(QDBusConnection::sessionBus()), const ChannelFactoryConstPtr &channelFactory = ChannelFactory::create(QDBusConnection::sessionBus()), const ContactFactoryConstPtr &contactFactory = ContactFactory::create()); static StreamTubeServerPtr create( const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const QStringList &p2pServices, const QStringList &roomServices = QStringList(), const QString &clientName = QString(), bool monitorConnections = false); static StreamTubeServerPtr create( const AccountManagerPtr &accountManager, const QStringList &p2pServices, const QStringList &roomServices = QStringList(), const QString &clientName = QString(), bool monitorConnections = false); static StreamTubeServerPtr create( const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices = QStringList(), const QString &clientName = QString(), bool monitorConnections = false); virtual ~StreamTubeServer(); ClientRegistrarPtr registrar() const; QString clientName() const; bool isRegistered() const; bool monitorsConnections() const; QPair exportedTcpSocketAddress() const; QVariantMap exportedParameters() const; void exportTcpSocket( const QHostAddress &address, quint16 port, const QVariantMap ¶meters = QVariantMap()); void exportTcpSocket( const QTcpServer *server, const QVariantMap ¶meters = QVariantMap()); void exportTcpSocket( const QHostAddress &address, quint16 port, ParametersGenerator *generator); void exportTcpSocket( const QTcpServer *server, ParametersGenerator *generator); QList tubes() const; QHash, RemoteContact> tcpConnections() const; Q_SIGNALS: void tubeRequested( const Tp::AccountPtr &account, const Tp::OutgoingStreamTubeChannelPtr &tube, const QDateTime &userActionTime, const Tp::ChannelRequestHints &hints); void tubeClosed( const Tp::AccountPtr &account, const Tp::OutgoingStreamTubeChannelPtr &tube, const QString &error, const QString &message); void newTcpConnection( const QHostAddress &sourceAddress, quint16 sourcePort, const Tp::AccountPtr &account, const Tp::ContactPtr &contact, const Tp::OutgoingStreamTubeChannelPtr &tube); void tcpConnectionClosed( const QHostAddress &sourceAddress, quint16 sourcePort, const Tp::AccountPtr &account, const Tp::ContactPtr &contact, const QString &error, const QString &message, const Tp::OutgoingStreamTubeChannelPtr &tube); private Q_SLOTS: TP_QT_NO_EXPORT void onInvokedForTube( const Tp::AccountPtr &account, const Tp::StreamTubeChannelPtr &tube, const QDateTime &userActionTime, const Tp::ChannelRequestHints &requestHints); TP_QT_NO_EXPORT void onOfferFinished( TubeWrapper *wrapper, Tp::PendingOperation *op); TP_QT_NO_EXPORT void onTubeInvalidated( Tp::DBusProxy *proxy, const QString &error, const QString &message); TP_QT_NO_EXPORT void onNewConnection( TubeWrapper *wrapper, uint conn); TP_QT_NO_EXPORT void onConnectionClosed( TubeWrapper *wrapper, uint conn, const QString &error, const QString &message); private: TP_QT_NO_EXPORT StreamTubeServer( const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections); struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/MediaSessionHandlerInterface0000664000175000017500000000043312470405660022641 0ustar jrjr#ifndef _TelepathyQt_MediaSessionHandlerInterface_HEADER_GUARD_ #define _TelepathyQt_MediaSessionHandlerInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/base-call-internal.h0000664000175000017500000000767412470405660021040 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2013 Matthias Gehre * @copyright Copyright 2013 Canonical Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/_gen/svc-call.h" #include #include #include #include #include "TelepathyQt/debug-internal.h" namespace Tp { class TP_QT_NO_EXPORT BaseCallContent::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name) Q_PROPERTY(uint type READ type) Q_PROPERTY(uint disposition READ disposition) Q_PROPERTY(Tp::ObjectPathList streams READ streams) Q_PROPERTY(QStringList interfaces READ interfaces) public: Adaptee(const QDBusConnection &dbusConnection, BaseCallContent *content); ~Adaptee(); QStringList interfaces() const; QString name() const { return mContent->name(); } uint type() const { return mContent->type(); } uint disposition() const { return mContent->disposition(); } Tp::ObjectPathList streams() const { return mContent->streams(); } public Q_SLOTS: void remove(const Tp::Service::CallContentAdaptor::RemoveContextPtr &context); Q_SIGNALS: void streamsAdded(const Tp::ObjectPathList &streams); void streamsRemoved(const Tp::ObjectPathList &streams, const Tp::CallStateReason &reason); private: BaseCallContent *mContent; Service::CallContentAdaptor *mAdaptor; }; class TP_QT_NO_EXPORT BaseCallMuteInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(uint localMuteState READ localMuteState) public: Adaptee(BaseCallMuteInterface *content); ~Adaptee(); QStringList interfaces() const; uint localMuteState() const { return mInterface->localMuteState(); } public Q_SLOTS: void requestMuted(bool muted, const Tp::Service::CallInterfaceMuteAdaptor::RequestMutedContextPtr &context); Q_SIGNALS: void muteStateChanged(uint muteState); public: BaseCallMuteInterface *mInterface; Service::CallInterfaceMuteAdaptor *mAdaptor; }; class TP_QT_NO_EXPORT BaseCallContentDTMFInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(bool currentlySendingTones READ currentlySendingTones) Q_PROPERTY(QString deferredTones READ deferredTones) public: Adaptee(BaseCallContentDTMFInterface *interface); ~Adaptee(); QStringList interfaces() const; bool currentlySendingTones() const { return mInterface->currentlySendingTones(); } QString deferredTones() const { return mInterface->deferredTones(); } public Q_SLOTS: void multipleTones(const QString& tones, const Tp::Service::CallContentInterfaceDTMFAdaptor::MultipleTonesContextPtr &context); void startTone(uchar event, const Tp::Service::CallContentInterfaceDTMFAdaptor::StartToneContextPtr &context); void stopTone(const Tp::Service::CallContentInterfaceDTMFAdaptor::StopToneContextPtr &context); Q_SIGNALS: void tonesDeferred(const QString& tones); void sendingTones(const QString& tones); void stoppedTones(bool cancelled); public: BaseCallContentDTMFInterface *mInterface; Service::CallContentInterfaceDTMFAdaptor *mAdaptor; }; } telepathy-qt-0.9.6~git1/TelepathyQt/call-interfaces.xml0000664000175000017500000000036512470405660020776 0ustar jrjr Call interfaces, version 1 telepathy-qt-0.9.6~git1/TelepathyQt/CallContentInterfaceAudioControlInterface0000664000175000017500000000045412470405660025335 0ustar jrjr#ifndef _TelepathyQt_CallContentInterfaceAudioControlInterface_HEADER_GUARD_ #define _TelepathyQt_CallContentInterfaceAudioControlInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/IncomingDBusTubeChannel0000664000175000017500000000042612470405660021573 0ustar jrjr#ifndef _TelepathyQt_IncomingDBusTubeChannel_HEADER_GUARD_ #define _TelepathyQt_IncomingDBusTubeChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/connection-manager.h0000664000175000017500000001056712470405660021145 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_connection_manager_h_HEADER_GUARD_ #define _TelepathyQt_connection_manager_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { class ConnectionManagerLowlevel; class PendingConnection; class PendingStringList; class TP_QT_EXPORT ConnectionManager : public StatelessDBusProxy, public OptionalInterfaceFactory { Q_OBJECT Q_DISABLE_COPY(ConnectionManager) Q_PROPERTY(QString name READ name) Q_PROPERTY(QStringList supportedProtocols READ supportedProtocols) Q_PROPERTY(ProtocolInfoList protocols READ protocols) public: static const Feature FeatureCore; static ConnectionManagerPtr create(const QDBusConnection &bus, const QString &name); static ConnectionManagerPtr create(const QString &name, const ConnectionFactoryConstPtr &connectionFactory = ConnectionFactory::create(QDBusConnection::sessionBus()), const ChannelFactoryConstPtr &channelFactory = ChannelFactory::create(QDBusConnection::sessionBus()), const ContactFactoryConstPtr &contactFactory = ContactFactory::create()); static ConnectionManagerPtr create(const QDBusConnection &bus, const QString &name, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory = ContactFactory::create()); virtual ~ConnectionManager(); QString name() const; ConnectionFactoryConstPtr connectionFactory() const; ChannelFactoryConstPtr channelFactory() const; ContactFactoryConstPtr contactFactory() const; QStringList supportedProtocols() const; const ProtocolInfoList &protocols() const; bool hasProtocol(const QString &protocolName) const; ProtocolInfo protocol(const QString &protocolName) const; static PendingStringList *listNames( const QDBusConnection &bus = QDBusConnection::sessionBus()); #if defined(BUILDING_TP_QT) || defined(TP_QT_ENABLE_LOWLEVEL_API) ConnectionManagerLowlevelPtr lowlevel(); ConnectionManagerLowlevelConstPtr lowlevel() const; #endif protected: ConnectionManager(const QDBusConnection &bus, const QString &name, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory); Client::ConnectionManagerInterface *baseInterface() const; private Q_SLOTS: TP_QT_NO_EXPORT void gotMainProperties(Tp::PendingOperation *op); TP_QT_NO_EXPORT void gotProtocolsLegacy(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotParametersLegacy(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onProtocolReady(Tp::PendingOperation *watcher); private: friend class PendingConnection; struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/GenericCapabilityFilter0000664000175000017500000000042512470405660021664 0ustar jrjr#ifndef _TelepathyQt_GenericCapabilityFilter_HEADER_GUARD_ #define _TelepathyQt_GenericCapabilityFilter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/CallContentMediaDescriptionInterface0000664000175000017500000000046412470405660024336 0ustar jrjr#ifndef _TelepathyQt_CallContentMediaDescriptionInterface_HEADER_GUARD_ #define _TelepathyQt_CallContentMediaDescriptionInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AccountPropertyFilter0000664000175000017500000000041712470405660021450 0ustar jrjr#ifndef _TelepathyQt_AccountPropertyFilter_HEADER_GUARD_ #define _TelepathyQt_AccountPropertyFilter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/client.xml0000664000175000017500000000065412470405660017221 0ustar jrjr Client interfaces telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfacePresenceInterface0000664000175000017500000000044012470405660024363 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfacePresenceInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfacePresenceInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceDestroyableInterface0000664000175000017500000000043512470405660024351 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceDestroyableInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceDestroyableInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Global0000664000175000017500000000034012470405660016334 0ustar jrjr#ifndef _TelepathyQt_Global_HEADER_GUARD_ #define _TelepathyQt_Global_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Channel0000664000175000017500000000034312470405660016507 0ustar jrjr#ifndef _TelepathyQt_Channel_HEADER_GUARD_ #define _TelepathyQt_Channel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel-request.h0000664000175000017500000001124412470405660020465 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_channel_request_h_HEADER_GUARD_ #define _TelepathyQt_channel_request_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { class ChannelRequestHints; class PendingOperation; class TP_QT_EXPORT ChannelRequest : public StatefulDBusProxy, public OptionalInterfaceFactory { Q_OBJECT Q_DISABLE_COPY(ChannelRequest) public: static const Feature FeatureCore; static ChannelRequestPtr create(const QDBusConnection &bus, const QString &objectPath, const QVariantMap &immutableProperties, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory); static ChannelRequestPtr create(const AccountPtr &account, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~ChannelRequest(); AccountPtr account() const; QDateTime userActionTime() const; QString preferredHandler() const; QualifiedPropertyValueMapList requests() const; ChannelRequestHints hints() const; QVariantMap immutableProperties() const; PendingOperation *cancel(); ChannelPtr channel() const; Q_SIGNALS: void failed(const QString &errorName, const QString &errorMessage); void succeeded(const Tp::ChannelPtr &channel); protected: ChannelRequest(const QDBusConnection &bus, const QString &objectPath, const QVariantMap &immutableProperties, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory); ChannelRequest(const AccountPtr &account, const QString &objectPath, const QVariantMap &immutableProperties); Client::ChannelRequestInterface *baseInterface() const; private Q_SLOTS: TP_QT_NO_EXPORT void gotMainProperties(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onAccountReady(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onLegacySucceeded(); TP_QT_NO_EXPORT void onSucceededWithChannel(const QDBusObjectPath &connPath, const QVariantMap &connProps, const QDBusObjectPath &chanPath, const QVariantMap &chanProps); TP_QT_NO_EXPORT void onChanBuilt(Tp::PendingOperation *op); private: friend class PendingChannelRequest; PendingOperation *proceed(); struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT ChannelRequestHints { public: ChannelRequestHints(); ChannelRequestHints(const QVariantMap &hints); ChannelRequestHints(const ChannelRequestHints &other); ~ChannelRequestHints(); ChannelRequestHints &operator=(const ChannelRequestHints &other); bool isValid() const; bool hasHint(const QString &reversedDomain, const QString &localName) const; QVariant hint(const QString &reversedDomain, const QString &localName) const; void setHint(const QString &reversedDomain, const QString &localName, const QVariant &value); QVariantMap allHints() const; private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::ChannelRequestHints); #endif telepathy-qt-0.9.6~git1/TelepathyQt/PendingReady0000664000175000017500000000036312470405660017512 0ustar jrjr#ifndef _TelepathyQt_PendingReady_HEADER_GUARD_ #define _TelepathyQt_PendingReady_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PropertiesInterfaceInterface0000664000175000017500000000042012470405660022731 0ustar jrjr#ifndef _TelepathyQt_PropertiesInterfaceInterface_HEADER_GUARD_ #define _TelepathyQt_PropertiesInterfaceInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/BaseCall0000664000175000017500000000034712470405660016611 0ustar jrjr#ifndef _TelepathyQt_BaseCall_HEADER_GUARD_ #define _TelepathyQt_BaseCall_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/streamed-media-channel.h0000664000175000017500000001613312470405660021660 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_streamed_media_channel_h_HEADER_GUARD_ #define _TelepathyQt_streamed_media_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include namespace Tp { class StreamedMediaChannel; typedef QList StreamedMediaStreams; class TP_QT_EXPORT_DEPRECATED PendingStreamedMediaStreams : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingStreamedMediaStreams) public: ~PendingStreamedMediaStreams(); StreamedMediaChannelPtr channel() const; StreamedMediaStreams streams() const; private Q_SLOTS: TP_QT_NO_EXPORT void gotStreams(QDBusPendingCallWatcher *op); TP_QT_NO_EXPORT void onStreamRemoved(const Tp::StreamedMediaStreamPtr &stream); TP_QT_NO_EXPORT void onStreamReady(Tp::PendingOperation *op); private: friend class StreamedMediaChannel; TP_QT_NO_EXPORT PendingStreamedMediaStreams(const StreamedMediaChannelPtr &channel, const ContactPtr &contact, const QList &types); struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT_DEPRECATED StreamedMediaStream : public Object, private ReadyObject { Q_OBJECT Q_DISABLE_COPY(StreamedMediaStream) public: enum SendingState { SendingStateNone = 0, SendingStatePendingSend = 1, SendingStateSending = 2 }; ~StreamedMediaStream(); StreamedMediaChannelPtr channel() const; uint id() const; ContactPtr contact() const; MediaStreamState state() const; MediaStreamType type() const; SendingState localSendingState() const; SendingState remoteSendingState() const; bool sending() const; bool receiving() const; bool localSendingRequested() const; bool remoteSendingRequested() const; MediaStreamDirection direction() const; MediaStreamPendingSend pendingSend() const; PendingOperation *requestSending(bool send); PendingOperation *requestReceiving(bool receive); PendingOperation *requestDirection(MediaStreamDirection direction); PendingOperation *requestDirection(bool send, bool receive); PendingOperation *startDTMFTone(DTMFEvent event); PendingOperation *stopDTMFTone(); Q_SIGNALS: void localSendingStateChanged(Tp::StreamedMediaStream::SendingState localSendingState); void remoteSendingStateChanged(Tp::StreamedMediaStream::SendingState remoteSendingState); private Q_SLOTS: TP_QT_NO_EXPORT void gotContact(Tp::PendingOperation *op); private: friend class PendingStreamedMediaStreams; friend class StreamedMediaChannel; static const Feature FeatureCore; TP_QT_NO_EXPORT StreamedMediaStream(const StreamedMediaChannelPtr &channel, const MediaStreamInfo &info); TP_QT_NO_EXPORT void gotDirection(uint direction, uint pendingSend); TP_QT_NO_EXPORT void gotStreamState(uint state); struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT_DEPRECATED StreamedMediaChannel : public Channel { Q_OBJECT Q_DISABLE_COPY(StreamedMediaChannel) Q_ENUMS(StateChangeReason) public: static const Feature FeatureCore; static const Feature FeatureStreams; static const Feature FeatureLocalHoldState; enum StateChangeReason { StateChangeReasonUnknown = 0, StateChangeReasonUserRequested = 1 }; static StreamedMediaChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~StreamedMediaChannel(); bool awaitingLocalAnswer() const; bool awaitingRemoteAnswer() const; PendingOperation *acceptCall(); PendingOperation *hangupCall(); StreamedMediaStreams streams() const; StreamedMediaStreams streamsForType(MediaStreamType type) const; PendingStreamedMediaStreams *requestStream(const ContactPtr &contact, MediaStreamType type); PendingStreamedMediaStreams *requestStreams(const ContactPtr &contact, QList types); PendingOperation *removeStream(const StreamedMediaStreamPtr &stream); PendingOperation *removeStreams(const StreamedMediaStreams &streams); bool handlerStreamingRequired() const; LocalHoldState localHoldState() const; LocalHoldStateReason localHoldStateReason() const; PendingOperation *requestHold(bool hold); Q_SIGNALS: void streamAdded(const Tp::StreamedMediaStreamPtr &stream); void streamRemoved(const Tp::StreamedMediaStreamPtr &stream); void streamDirectionChanged(const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamDirection direction, Tp::MediaStreamPendingSend pendingSend); void streamStateChanged(const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamState state); void streamError(const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamError errorCode, const QString &errorMessage); void localHoldStateChanged(Tp::LocalHoldState state, Tp::LocalHoldStateReason reason); protected: StreamedMediaChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = StreamedMediaChannel::FeatureCore); private Q_SLOTS: TP_QT_NO_EXPORT void onStreamReady(Tp::PendingOperation *op); TP_QT_NO_EXPORT void gotStreams(QDBusPendingCallWatcher *); TP_QT_NO_EXPORT void onStreamAdded(uint, uint, uint); TP_QT_NO_EXPORT void onStreamRemoved(uint); TP_QT_NO_EXPORT void onStreamDirectionChanged(uint, uint, uint); TP_QT_NO_EXPORT void onStreamStateChanged(uint streamId, uint streamState); TP_QT_NO_EXPORT void onStreamError(uint, uint, const QString &); TP_QT_NO_EXPORT void gotLocalHoldState(QDBusPendingCallWatcher *); TP_QT_NO_EXPORT void onLocalHoldStateChanged(uint, uint); private: friend class PendingStreamedMediaStreams; StreamedMediaStreamPtr addStream(const MediaStreamInfo &streamInfo); StreamedMediaStreamPtr lookupStreamById(uint streamId); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/manager-file.cpp0000664000175000017500000004512612470405660020257 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/manager-file.h" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/key-file.h" #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ManagerFile::Private { Private(); Private(const QString &cnName); void init(); bool parse(const QString &fileName); bool isValid() const; bool hasParameter(const QString &protocol, const QString ¶mName) const; ParamSpec *getParameter(const QString &protocol, const QString ¶mName); QStringList protocols() const; ParamSpecList parameters(const QString &protocol) const; QVariant valueForKey(const QString ¶m, const QString &dbusSignature); struct ProtocolInfo { ProtocolInfo() {} ProtocolInfo(const ParamSpecList ¶ms, const PresenceSpecList &statuses) : params(params), statuses(statuses) { } ParamSpecList params; QString vcardField; QString englishName; QString iconName; RequestableChannelClassList rccs; PresenceSpecList statuses; AvatarSpec avatarRequirements; QStringList addressableVCardFields; QStringList addressableUriSchemes; }; QString cmName; KeyFile keyFile; QHash protocolsMap; bool valid; }; ManagerFile::Private::Private() : valid(false) { } ManagerFile::Private::Private(const QString &cmName) : cmName(cmName), valid(false) { init(); } void ManagerFile::Private::init() { // TODO: should we cache the configDirs anywhere? QStringList configDirs; QString xdgDataHome = QString::fromLocal8Bit(qgetenv("XDG_DATA_HOME")); if (xdgDataHome.isEmpty()) { configDirs << QDir::homePath() + QLatin1String("/.local/share/data/telepathy/managers/"); } else { configDirs << xdgDataHome + QLatin1String("/telepathy/managers/"); } QString xdgDataDirsEnv = QString::fromLocal8Bit(qgetenv("XDG_DATA_DIRS")); if (xdgDataDirsEnv.isEmpty()) { configDirs << QLatin1String("/usr/local/share/telepathy/managers/"); configDirs << QLatin1String("/usr/share/telepathy/managers/"); } else { QStringList xdgDataDirs = xdgDataDirsEnv.split(QLatin1Char(':')); foreach (const QString xdgDataDir, xdgDataDirs) { configDirs << xdgDataDir + QLatin1String("/telepathy/managers/"); } } foreach (const QString configDir, configDirs) { QString fileName = configDir + cmName + QLatin1String(".manager"); if (QFile::exists(fileName)) { debug() << "parsing manager file" << fileName; protocolsMap.clear(); if (!parse(fileName)) { warning() << "error parsing manager file" << fileName; continue; } valid = true; return; } } } bool ManagerFile::Private::parse(const QString &fileName) { keyFile.setFileName(fileName); if (keyFile.status() != KeyFile::NoError) { return false; } /* read supported protocols and parameters */ QString protocol; QStringList groups = keyFile.allGroups(); foreach (const QString group, groups) { if (group.startsWith(QLatin1String("Protocol "))) { protocol = group.right(group.length() - 9); keyFile.setGroup(group); ParamSpecList paramSpecList; SimpleStatusSpecMap statuses; QString param; QStringList params = keyFile.keys(); foreach (param, params) { ParamSpec spec; SimpleStatusSpec status; spec.flags = 0; QStringList values = keyFile.value(param).split(QLatin1String(" ")); if (param.startsWith(QLatin1String("param-"))) { spec.name = param.right(param.length() - 6); if (values.length() == 0) { warning() << "param" << spec.name << "set but no signature defined"; return false; } if (spec.name.endsWith(QLatin1String("password"))) { spec.flags |= ConnMgrParamFlagSecret; } spec.signature = values[0]; if (values.contains(QLatin1String("secret"))) { spec.flags |= ConnMgrParamFlagSecret; } if (values.contains(QLatin1String("dbus-property"))) { spec.flags |= ConnMgrParamFlagDBusProperty; } if (values.contains(QLatin1String("required"))) { spec.flags |= ConnMgrParamFlagRequired; } if (values.contains(QLatin1String("register"))) { spec.flags |= ConnMgrParamFlagRegister; } paramSpecList.append(spec); } else if (param.startsWith(QLatin1String("status-"))) { QString statusName = param.right(param.length() - 7); if (values.length() == 0) { warning() << "status" << statusName << "set but no type defined"; return false; } bool ok; status.type = values[0].toUInt(&ok); if (!ok) { warning() << "status" << statusName << "set but type is not an uint"; return false; } if (values.contains(QLatin1String("settable"))) { status.maySetOnSelf = true; } else { status.maySetOnSelf = false; } if (values.contains(QLatin1String("message"))) { status.canHaveMessage = true; } else { status.canHaveMessage = false; } if (statuses.contains(statusName)) { warning() << "status" << statusName << "defined more than once, " "replacing it"; } statuses.insert(statusName, status); } } protocolsMap.insert(protocol, ProtocolInfo(paramSpecList, PresenceSpecList(statuses))); /* now that we have all param-* created, let's find their default values */ foreach (param, params) { if (param.startsWith(QLatin1String("default-"))) { QString paramName = param.right(param.length() - 8); if (!hasParameter(protocol, paramName)) { warning() << "param" << paramName << "has default value set, but not a definition"; continue; } ParamSpec *spec = getParameter(protocol, paramName); spec->flags |= ConnMgrParamFlagHasDefault; /* map based on the param dbus signature, otherwise use * QString */ QVariant value = valueForKey(param, spec->signature); if (value.type() == QVariant::Invalid) { warning() << "param" << paramName << "has invalid signature"; protocolsMap.clear(); return false; } spec->defaultValue = QDBusVariant(value); } } ProtocolInfo &info = protocolsMap[protocol]; info.vcardField = keyFile.value(QLatin1String("VCardField")); info.englishName = keyFile.value(QLatin1String("EnglishName")); if (info.englishName.isEmpty()) { QStringList words = protocol.split(QLatin1Char('-')); for (int i = 0; i < words.size(); ++i) { words[i][0] = words[i].at(0).toUpper(); } info.englishName = words.join(QLatin1String(" ")); } info.iconName = keyFile.value(QLatin1String("Icon")); if (info.iconName.isEmpty()) { info.iconName = QString(QLatin1String("im-%1")).arg(protocol); } QStringList supportedMimeTypes = keyFile.valueAsStringList( QLatin1String("SupportedAvatarMIMETypes")); uint minHeight = keyFile.value(QLatin1String("MinimumAvatarHeight")).toUInt(); uint maxHeight = keyFile.value(QLatin1String("MaximumAvatarHeight")).toUInt(); uint recommendedHeight = keyFile.value( QLatin1String("RecommendedAvatarHeight")).toUInt(); uint minWidth = keyFile.value(QLatin1String("MinimumAvatarWidth")).toUInt(); uint maxWidth = keyFile.value(QLatin1String("MaximumAvatarWidth")).toUInt(); uint recommendedWidth = keyFile.value( QLatin1String("RecommendedAvatarWidth")).toUInt(); uint maxBytes = keyFile.value(QLatin1String("MaximumAvatarBytes")).toUInt(); info.avatarRequirements = AvatarSpec(supportedMimeTypes, minHeight, maxHeight, recommendedHeight, minWidth, maxWidth, recommendedWidth, maxBytes); info.addressableVCardFields = keyFile.valueAsStringList( QLatin1String("AddressableVCardFields")); info.addressableUriSchemes = keyFile.valueAsStringList( QLatin1String("AddressableURISchemes")); QStringList rccGroups = keyFile.valueAsStringList( QLatin1String("RequestableChannelClasses")); RequestableChannelClass rcc; foreach (const QString &rccGroup, rccGroups) { keyFile.setGroup(rccGroup); foreach (const QString &key, keyFile.keys()) { int spaceIdx = key.indexOf(QLatin1String(" ")); if (spaceIdx == -1) { continue; } QString propertyName = key.mid(0, spaceIdx); QString signature = key.mid(spaceIdx + 1); QString param = keyFile.value(key); QVariant value = valueForKey(key, signature); rcc.fixedProperties.insert(propertyName, value); } rcc.allowedProperties = keyFile.valueAsStringList( QLatin1String("allowed")); info.rccs.append(rcc); rcc.fixedProperties.clear(); rcc.allowedProperties.clear(); } } } return true; } bool ManagerFile::Private::isValid() const { return ((keyFile.status() == KeyFile::NoError) && (valid)); } bool ManagerFile::Private::hasParameter(const QString &protocol, const QString ¶mName) const { ParamSpecList paramSpecList = protocolsMap[protocol].params; foreach (const ParamSpec ¶mSpec, paramSpecList) { if (paramSpec.name == paramName) { return true; } } return false; } ParamSpec *ManagerFile::Private::getParameter(const QString &protocol, const QString ¶mName) { ParamSpecList ¶mSpecList = protocolsMap[protocol].params; for (int i = 0; i < paramSpecList.size(); ++i) { ParamSpec ¶mSpec = paramSpecList[i]; if (paramSpec.name == paramName) { return ¶mSpec; } } return NULL; } QStringList ManagerFile::Private::protocols() const { return protocolsMap.keys(); } ParamSpecList ManagerFile::Private::parameters(const QString &protocol) const { return protocolsMap.value(protocol).params; } QVariant ManagerFile::Private::valueForKey(const QString ¶m, const QString &dbusSignature) { QString value = keyFile.rawValue(param); return parseValueWithDBusSignature(value, dbusSignature); } /** * \class ManagerFile * \ingroup utils * \headerfile TelepathyQt/manager-file.h * * \brief The ManagerFile class provides an easy way to read Telepathy manager * files according to the \telepathy_spec. */ /** * Create a ManagerFile object used to read .manager compliant files. */ ManagerFile::ManagerFile() : mPriv(new Private()) { } /** * Create a ManagerFile object used to read .manager compliant files. * * \param cmName Name of the connection manager to read the file for. */ ManagerFile::ManagerFile(const QString &cmName) : mPriv(new Private(cmName)) { } /** * Create a ManagerFile object used to read .manager compliant files. */ ManagerFile::ManagerFile(const ManagerFile &other) : mPriv(new Private()) { mPriv->cmName = other.mPriv->cmName; mPriv->keyFile = other.mPriv->keyFile; mPriv->protocolsMap = other.mPriv->protocolsMap; mPriv->valid = other.mPriv->valid; } /** * Class destructor. */ ManagerFile::~ManagerFile() { delete mPriv; } ManagerFile &ManagerFile::operator=(const ManagerFile &other) { mPriv->cmName = other.mPriv->cmName; mPriv->keyFile = other.mPriv->keyFile; mPriv->protocolsMap = other.mPriv->protocolsMap; mPriv->valid = other.mPriv->valid; return *this; } /** * Check whether or not a ManagerFile object is valid. If the file for the * specified connection manager cannot be found it will be considered invalid. * * \return true if valid, false otherwise. */ bool ManagerFile::isValid() const { return mPriv->isValid(); } /** * Return a list of all protocols defined in the manager file. * * \return List of all protocols defined in the file. */ QStringList ManagerFile::protocols() const { return mPriv->protocols(); } /** * Return a list of parameters for the given \a protocol. * * \param protocol Name of the protocol to look for. * \return List of ParamSpec of a specific protocol defined in the file, or an * empty list if the protocol is not defined. */ ParamSpecList ManagerFile::parameters(const QString &protocol) const { return mPriv->parameters(protocol); } /** * Return the name of the most common vcard field used for the given \a protocol's * contact identifiers, normalized to lower case. * * \param protocol Name of the protocol to look for. * \return The most common vcard field used for the given protocol's contact * identifiers, or an empty string if there is no such field or the * protocol is not defined. */ QString ManagerFile::vcardField(const QString &protocol) const { return mPriv->protocolsMap.value(protocol).vcardField; } QStringList ManagerFile::addressableVCardFields(const QString &protocol) const { return mPriv->protocolsMap.value(protocol).addressableVCardFields; } QStringList ManagerFile::addressableUriSchemes(const QString &protocol) const { return mPriv->protocolsMap.value(protocol).addressableUriSchemes; } /** * Return the English-language name of the given \a protocol, such as "AIM" or "Yahoo!". * * The name can be used as a fallback if an application doesn't have a localized name for the * protocol. * * If the manager file doesn't specify the english name, it is inferred from the protocol name, such * that for example "google-talk" becomes "Google Talk", but "local-xmpp" becomes "Local Xmpp". * * \param protocol Name of the protocol to look for. * \return An English-language name for the given \a protocol. */ QString ManagerFile::englishName(const QString &protocol) const { return mPriv->protocolsMap.value(protocol).englishName; } /** * Return the name of an icon for the given \a protocol in the system's icon * theme, such as "im-msn". * * If the manager file doesn't specify the icon name, "im-" is assumed. * * \param protocol Name of the protocol to look for. * \return The likely name of an icon for the given \a protocol. */ QString ManagerFile::iconName(const QString &protocol) const { return mPriv->protocolsMap.value(protocol).iconName; } /** * Return a list of channel classes which might be requestable from a connection * to the given \a protocol. * * \param protocol Name of the protocol to look for. * \return A list of channel classes which might be requestable from a * connection to the given \a protocol or a default constructed * RequestableChannelClassList instance if the protocol is not defined. */ RequestableChannelClassList ManagerFile::requestableChannelClasses( const QString &protocol) const { return mPriv->protocolsMap.value(protocol).rccs; } /** * Return a list of PresenceSpec representing the possible presence statuses * from a connection to the given \a protocol. * * \param protocol Name of the protocol to look for. * \return A list of PresenceSpec representing the possible presence statuses * from a connection to the given \a protocol or an empty list * if the protocol is not defined. */ PresenceSpecList ManagerFile::allowedPresenceStatuses(const QString &protocol) const { return mPriv->protocolsMap.value(protocol).statuses; } /** * Return the requirements (size limits, supported MIME types, etc) * for avatars used on the given \a protocol. * * \param protocol Name of the protocol to look for. * \return The requirements for avatars used on the given \a protocol or an invalid * AvatarSpec if the protocol is not defined. */ AvatarSpec ManagerFile::avatarRequirements(const QString &protocol) const { return mPriv->protocolsMap.value(protocol).avatarRequirements; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/contact.h0000664000175000017500000001776312470405660017036 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_contact_h_HEADER_GUARD_ #define _TelepathyQt_contact_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include namespace Tp { struct AvatarData; class ContactCapabilities; class LocationInfo; class ContactManager; class PendingContactInfo; class PendingOperation; class PendingStringList; class Presence; class ReferencedHandles; class TP_QT_EXPORT Contact : public Object { Q_OBJECT Q_DISABLE_COPY(Contact) public: static const Feature FeatureAlias; static const Feature FeatureAvatarData; static const Feature FeatureAvatarToken; static const Feature FeatureCapabilities; static const Feature FeatureInfo; static const Feature FeatureLocation; static const Feature FeatureSimplePresence; static const Feature FeatureAddresses; static const Feature FeatureClientTypes; enum PresenceState { PresenceStateNo, PresenceStateAsk, PresenceStateYes }; class InfoFields { public: InfoFields(); InfoFields(const ContactInfoFieldList &fields); InfoFields(const InfoFields &other); ~InfoFields(); bool isValid() const { return mPriv.constData() != 0; } InfoFields &operator=(const InfoFields &other); ContactInfoFieldList fields(const QString &name) const; ContactInfoFieldList allFields() const; private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; ~Contact(); ContactManagerPtr manager() const; ReferencedHandles handle() const; // TODO filter: exact, prefix, substring match QString id() const; Features requestedFeatures() const; Features actualFeatures() const; // TODO filter: exact, prefix, substring match QString alias() const; QMap vcardAddresses() const; QStringList uris() const; bool isAvatarTokenKnown() const; QString avatarToken() const; AvatarData avatarData() const; void requestAvatarData(); /* * TODO filter: * - exact match of presence().type(), presence().status() * - ANY 1 of a number of presence types/statuses * - presence().type() greater or less than a set value * - have/don't have presence().message() AND exact/prefix/substring */ Presence presence() const; // TODO filter: the same as Account filtering by caps ContactCapabilities capabilities() const; // TODO filter: is it available, how accurate, are they near me LocationInfo location() const; // TODO filter: having a specific field, having ANY field, // (field: exact, contents: exact/prefix/substring) bool isContactInfoKnown() const; InfoFields infoFields() const; PendingOperation *refreshInfo(); PendingContactInfo *requestInfo(); /* * Filters on exact values of these, but also the "in your contact list at all or not" usecase */ bool isSubscriptionStateKnown() const; bool isSubscriptionRejected() const; PresenceState subscriptionState() const; bool isPublishStateKnown() const; bool isPublishCancelled() const; PresenceState publishState() const; QString publishStateMessage() const; PendingOperation *requestPresenceSubscription(const QString &message = QString()); PendingOperation *removePresenceSubscription(const QString &message = QString()); PendingOperation *authorizePresencePublication(const QString &message = QString()); PendingOperation *removePresencePublication(const QString &message = QString()); /* * Filter on being blocked or not */ bool isBlocked() const; PendingOperation *block(); PendingOperation *blockAndReportAbuse(); PendingOperation *unblock(); /* * Filter on the groups they're in - to show a specific group only * * Also prefix/substring match on ANY of the groups of the contact */ QStringList groups() const; PendingOperation *addToGroup(const QString &group); PendingOperation *removeFromGroup(const QString &group); QStringList clientTypes() const; PendingStringList *requestClientTypes(); Q_SIGNALS: void aliasChanged(const QString &alias); void avatarTokenChanged(const QString &avatarToken); void avatarDataChanged(const Tp::AvatarData &avatarData); void presenceChanged(const Tp::Presence &presence); void capabilitiesChanged(const Tp::ContactCapabilities &caps); void locationUpdated(const Tp::LocationInfo &location); void infoFieldsChanged(const Tp::Contact::InfoFields &infoFields); void subscriptionStateChanged(Tp::Contact::PresenceState state); void publishStateChanged(Tp::Contact::PresenceState state, const QString &message); void blockStatusChanged(bool blocked); void addedToGroup(const QString &group); void removedFromGroup(const QString &group); void clientTypesChanged(const QStringList &clientTypes); // TODO: consider how the Renaming interface should work and map to Contacts // I guess it would be something like: // void renamedTo(Tp::ContactPtr) // with that contact getting the same features requested as the current one. Or would we rather // want to signal that change right away with a handle? protected: Contact(ContactManager *manager, const ReferencedHandles &handle, const Features &requestedFeatures, const QVariantMap &attributes); virtual void augment(const Features &requestedFeatures, const QVariantMap &attributes); private: static const Feature FeatureRosterGroups; TP_QT_NO_EXPORT void receiveAlias(const QString &alias); TP_QT_NO_EXPORT void receiveAvatarToken(const QString &avatarToken); TP_QT_NO_EXPORT void setAvatarToken(const QString &token); TP_QT_NO_EXPORT void receiveAvatarData(const AvatarData &); TP_QT_NO_EXPORT void receiveSimplePresence(const SimplePresence &presence); TP_QT_NO_EXPORT void receiveCapabilities(const RequestableChannelClassList &caps); TP_QT_NO_EXPORT void receiveLocation(const QVariantMap &location); TP_QT_NO_EXPORT void receiveInfo(const ContactInfoFieldList &info); TP_QT_NO_EXPORT void receiveAddresses(const QMap &addresses, const QStringList &uris); TP_QT_NO_EXPORT void receiveClientTypes(const QStringList &clientTypes); TP_QT_NO_EXPORT static PresenceState subscriptionStateToPresenceState(uint subscriptionState); TP_QT_NO_EXPORT void setSubscriptionState(SubscriptionState state); TP_QT_NO_EXPORT void setPublishState(SubscriptionState state, const QString &message = QString()); TP_QT_NO_EXPORT void setBlocked(bool value); TP_QT_NO_EXPORT void setAddedToGroup(const QString &group); TP_QT_NO_EXPORT void setRemovedFromGroup(const QString &group); struct Private; friend class Connection; friend class ContactFactory; friend class ContactManager; friend struct Private; Private *mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::Contact::InfoFields); #endif telepathy-qt-0.9.6~git1/TelepathyQt/call-content.h0000664000175000017500000000641012470405660017751 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_call_content_h_HEADER_GUARD_ #define _TelepathyQt_call_content_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { typedef QList CallContents; class TP_QT_EXPORT CallContent : public StatefulDBusProxy, public OptionalInterfaceFactory { Q_OBJECT Q_DISABLE_COPY(CallContent) public: ~CallContent(); CallChannelPtr channel() const; QString name() const; MediaStreamType type() const; CallContentDisposition disposition() const; CallStreams streams() const; PendingOperation *remove(); bool supportsDTMF() const; PendingOperation *startDTMFTone(DTMFEvent event); PendingOperation *stopDTMFTone(); Q_SIGNALS: void streamAdded(const Tp::CallStreamPtr &stream); void streamRemoved(const Tp::CallStreamPtr &stream, const Tp::CallStateReason &reason); private Q_SLOTS: TP_QT_NO_EXPORT void gotMainProperties(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onStreamsAdded(const Tp::ObjectPathList &streamPath); TP_QT_NO_EXPORT void onStreamsRemoved(const Tp::ObjectPathList &streamPath, const Tp::CallStateReason &reason); TP_QT_NO_EXPORT void onStreamReady(Tp::PendingOperation *op); private: friend class CallChannel; friend class PendingCallContent; TP_QT_NO_EXPORT static const Feature FeatureCore; TP_QT_NO_EXPORT CallContent(const CallChannelPtr &channel, const QDBusObjectPath &contentPath); struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT PendingCallContent : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingCallContent) public: ~PendingCallContent(); CallContentPtr content() const; private Q_SLOTS: TP_QT_NO_EXPORT void gotContent(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onContentReady(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onContentRemoved(const Tp::CallContentPtr &content); private: friend class CallChannel; TP_QT_NO_EXPORT PendingCallContent(const CallChannelPtr &channel, const QString &contentName, MediaStreamType type, MediaStreamDirection direction); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/capabilities-base.cpp0000664000175000017500000003200312470405660021257 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include namespace Tp { struct TP_QT_NO_EXPORT CapabilitiesBase::Private : public QSharedData { Private(bool specificToContact); Private(const RequestableChannelClassSpecList &rccSpecs, bool specificToContact); RequestableChannelClassSpecList rccSpecs; bool specificToContact; }; CapabilitiesBase::Private::Private(bool specificToContact) : specificToContact(specificToContact) { } CapabilitiesBase::Private::Private(const RequestableChannelClassSpecList &rccSpecs, bool specificToContact) : rccSpecs(rccSpecs), specificToContact(specificToContact) { } /** * \class CapabilitiesBase * \ingroup clientconn * \headerfile TelepathyQt/capabilities-base.h * * \brief The CapabilitiesBase class represents the capabilities a Connection * or a Contact supports. */ /** * Construct a new CapabilitiesBase object. */ CapabilitiesBase::CapabilitiesBase() : mPriv(new Private(false)) { } /** * Construct a new CapabilitiesBase object. * * \param specificToContact Whether this object describes the capabilities of a * particular contact. */ CapabilitiesBase::CapabilitiesBase(bool specificToContact) : mPriv(new Private(specificToContact)) { } /** * Construct a new CapabilitiesBase object using the given \a rccs. * * \param rccs RequestableChannelClassList representing the capabilities of a * connection or contact. * \param specificToContact Whether this object describes the capabilities of a * particular contact. */ CapabilitiesBase::CapabilitiesBase(const RequestableChannelClassList &rccs, bool specificToContact) : mPriv(new Private(RequestableChannelClassSpecList(rccs), specificToContact)) { } /** * Construct a new CapabilitiesBase object using the given \a rccSpecs. * * \param rccSpecs RequestableChannelClassSpecList representing the capabilities of a * connection or contact. * \param specificToContact Whether this object describes the capabilities of a * particular contact. */ CapabilitiesBase::CapabilitiesBase(const RequestableChannelClassSpecList &rccSpecs, bool specificToContact) : mPriv(new Private(rccSpecs, specificToContact)) { } CapabilitiesBase::CapabilitiesBase(const CapabilitiesBase &other) : mPriv(other.mPriv) { } /** * Class destructor. */ CapabilitiesBase::~CapabilitiesBase() { } CapabilitiesBase &CapabilitiesBase::operator=(const CapabilitiesBase &other) { this->mPriv = other.mPriv; return *this; } /** * Return the list of requestable channel class spec representing the requests that can succeed. * * This can be used by advanced clients to determine whether an unusually * complex request would succeed. See the \telepathy_spec * for details of how to interpret the returned list. * * The higher-level methods like textChats() are likely to be more * useful to the majority of clients. * * \return A RequestableChannelClassSpecList indicating the parameters to * Account::createChannel, Account::ensureChannel, * Connection::createChannel and Connection::ensureChannel * that can be expected to work. */ RequestableChannelClassSpecList CapabilitiesBase::allClassSpecs() const { return mPriv->rccSpecs; } void CapabilitiesBase::updateRequestableChannelClasses( const RequestableChannelClassList &rccs) { mPriv->rccSpecs = RequestableChannelClassSpecList(rccs); } /** * Return whether this object accurately describes the capabilities of a * particular contact, or if it's only a guess based on the * capabilities of the underlying connection. * * In protocols like XMPP where each contact advertises their capabilities * to others, Contact::capabilities() will generally return an object where * this method returns true. * * In protocols like SIP where contacts' capabilities are not known, * Contact::capabilities() will return an object where this method returns * false, whose methods textChats() etc. are based on what the * underlying connection supports. * * This reflects the fact that the best assumption an application can make is * that every contact supports every channel type supported by the connection, * while indicating that requests to communicate might fail if the contact * does not actually have the necessary functionality. * * \return \c true if this object describes the capabilities of a particular * contact, \c false otherwise. */ bool CapabilitiesBase::isSpecificToContact() const { return mPriv->specificToContact; } /** * Return whether private text channels can be established by providing * a contact identifier. * * If the protocol is such that text chats can be established, but only via * a more elaborate D-Bus API than normal (because more information is needed), * then this method will return false. * * \return \c true if Account::ensureTextChat() can be expected to work, * \c false otherwise. */ bool CapabilitiesBase::textChats() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::textChat())) { return true; } } return false; } bool CapabilitiesBase::audioCalls() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::audioCall())) { return true; } } return false; } bool CapabilitiesBase::videoCalls() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::videoCall())) { return true; } } return false; } bool CapabilitiesBase::videoCallsWithAudio() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::videoCallWithAudioAllowed()) || rccSpec.supports(RequestableChannelClassSpec::audioCallWithVideoAllowed())) { return true; } } return false; } bool CapabilitiesBase::upgradingCalls() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.channelType() == TP_QT_IFACE_CHANNEL_TYPE_CALL && rccSpec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".MutableContents"))) { return true; } } return false; } /** * Return whether private audio and/or video calls can be established by * providing a contact identifier. * * If the protocol is such that these calls can be established, but only via * a more elaborate D-Bus API than normal (because more information is needed), * then this method will return false. * * \return \c true if Account::ensureStreamedMediaCall() can be expected to work, * \c false otherwise. * \sa streamedMediaAudioCalls(), streamedMediaVideoCalls(), * streamedMediaVideoCallsWithAudio() */ bool CapabilitiesBase::streamedMediaCalls() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::streamedMediaCall())) { return true; } } return false; } /** * Return whether private audio calls can be established by providing a * contact identifier. * * Call upgradingCalls() to determine whether such calls are * likely to be upgradable to have a video stream later. * * If the protocol is such that these calls can be established, but only via * a more elaborate D-Bus API than normal (because more information is needed), * then this method will return false. * * In some older connection managers, streamedMediaAudioCalls() and * streamedMediaVideoCalls() might both return false, even though streamedMediaCalls() returns * true. This indicates that only an older API is supported - clients of these connection managers * must call Account::ensureStreamedMediaCall() to get an empty call, then add audio and/or * video streams to it. * * \return \c true if Account::ensureStreamedMediaAudioCall() can be expected to work, * \c false otherwise. * \sa streamedMediaCalls(), streamedMediaVideoCalls(), streamedMediaVideoCallsWithAudio() */ bool CapabilitiesBase::streamedMediaAudioCalls() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::streamedMediaAudioCall())) { return true; } } return false; } /** * Return whether private video calls can be established by providing a * contact identifier. * * The same comments as for streamedMediaAudioCalls() apply to this method. * * \return \c true if Account::ensureStreamedMediaVideoCall() can be expected to work, * if given \c false as \a withAudio parameter, \c false otherwise. * \sa streamedMediaCalls(), streamedMediaAudioCalls(), streamedMediaVideoCallsWithAudio() */ bool CapabilitiesBase::streamedMediaVideoCalls() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::streamedMediaVideoCall())) { return true; } } return false; } /** * Return whether private video calls with audio can be established by providing a * contact identifier. * * The same comments as for streamedMediaAudioCalls() apply to this method. * * \return \c true if Account::ensureStreamedMediaVideoCall() can be expected to work, * if given \c true as \a withAudio parameter, \c false otherwise. * \sa streamedMediaCalls(), streamedMediaAudioCalls(), streamedMediaVideoCalls() */ bool CapabilitiesBase::streamedMediaVideoCallsWithAudio() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio())) { return true; } } return false; } /** * Return whether the protocol supports adding streams of a different type * to ongoing media calls. * * In some protocols and clients (such as XMPP Jingle), all calls potentially * support both audio and video. This is indicated by returning true. * * In other protocols and clients (such as MSN, and the variant of XMPP Jingle * used by Google clients), the streams are fixed at the time the call is * started, so if you will ever want video, you have to ask for it at the * beginning, for instance with ensureStreamedMediaVideoCall(). This is indicated by * returning false. * * User interfaces can use this method as a UI hint. If it returns false, * then a UI wishing to support both audio and video calls will have to * provide separate "audio call" and "video call" buttons or menu items; * if it returns true, a single button that makes an audio call is sufficient, * because video can be added later. * * (The underlying Telepathy feature is the ImmutableStreams property; if this * method returns true, then ImmutableStreams is false, and vice versa). * * \return \c true if audio calls can be upgraded to audio + video, * \c false otherwise. */ bool CapabilitiesBase::upgradingStreamedMediaCalls() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.channelType() == TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA && !rccSpec.allowsProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".ImmutableStreams"))) { // TODO should we test all classes that have channelType // StreamedMedia or just one is fine? return true; } } return false; } /** * Return whether file transfer can be established by providing a contact identifier * * \return \c true if file transfers can be expected to work, * \c false otherwise. */ bool CapabilitiesBase::fileTransfers() const { foreach (const RequestableChannelClassSpec &rccSpec, mPriv->rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::fileTransfer())) { return true; } } return false; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/abstract-client.cpp0000664000175000017500000010476712470405660021016 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT AbstractClient::Private { Private() : registered(false) { } bool registered; }; /** * \class AbstractClient * \ingroup clientclient * \headerfile TelepathyQt/abstract-client.h * * \brief The AbstractClient class represents a Telepathy client. * * Clients are programs used to process channels, approving, handling or * observing them. User interface processes are the obvious example of clients, * but they can provide other functionality, such as address-book * synchronization, message logging, etc. * * Each client is either an observer, an approver, a handler, or some * combination of these. * * Clients can be activatable services (those with a D-Bus .service file) * so that they can run in response to channel creation, or non-activatable * services (those that do not register a D-Bus .service file * for their well-known name, but do request it at runtime) so * that they can process channels, but only if they are already * running - for instance, a full-screen media center application might do this. * * As an optimization, service-activatable clients should install a file * $XDG_DATA_DIRS/telepathy/clients/clientname.client containing a cached version * of their immutable properties. The syntax of these files is documented in the * Telepathy specification. * * Non-activatable clients may install a .client file, but there's not much * point in them doing so. * * This is a base class and should not be used directly, use the * specialized classes AbstractClientObserver, AbstractClientApprover and * AbstractClientHandler instead. * * If the same process wants to be either a mix of observer, approver and * handler, or a combination of those it can multiple inherit the specialized * abstract classes. * * \sa AbstractClientObserver, AbstractClientApprover, AbstractClientHandler */ /** * Construct a new AbstractClient object. * * Note that this is a base class and should not be used directly, use the * specialized classes AbstractClientObserver, AbstractClientApprover and * AbstractClientHandler instead. */ AbstractClient::AbstractClient() : mPriv(new Private()) { } /** * Class destructor. */ AbstractClient::~AbstractClient() { delete mPriv; } /** * Return whether this client is registered. * * \return \c true if registered, \c false otherwise. */ bool AbstractClient::isRegistered() const { return mPriv->registered; } void AbstractClient::setRegistered(bool registered) { mPriv->registered = registered; } struct TP_QT_NO_EXPORT AbstractClientObserver::Private { Private(const ChannelClassList &channelFilter, bool shouldRecover) : channelFilter(channelFilter), shouldRecover(shouldRecover) { } ChannelClassList channelFilter; bool shouldRecover; }; /** * \class AbstractClientObserver * \ingroup clientclient * \headerfile TelepathyQt/abstract-client.h * * \brief The AbstractClientObserver class represents a Telepathy observer. * * Observers are clients that monitor the creation of new channels. * This functionality can be used for things like message logging. * * Observers should not modify the state of a channel except via user * interaction. * * Observers must not carry out actions that exactly one process must take * responsibility for (e.g. acknowledging text messages, or carrying out * the actual file transfer), since arbitrarily many observers can be * activated for each channel. The handler is responsible for such tasks. * * Handlers may, of course, delegate responsibility for these tasks to other * clients (including those run as observers), but this must be done * explicitly via a request from the handler to the observer. * * Whenever a collection of new channels is signalled, the channel dispatcher * will notify all running or activatable observers whose filter indicates that * they are interested in some of the channels. * * Observers are activated for all channels in which they have registered an * interest - incoming, outgoing or automatically created - although of course * the filter property can be set to filter specific channels. * * To become an observer one should inherit AbstractClientObserver and * implement the pure virtual observeChannels() method. After that the object * representing the observer must be registered using * ClientRegistrar::registerClient(). * * When new channels in which the observer has registered an interest are * announced, the method observeChannels() is invoked. All observers are * notified simultaneously. * * \section observer_usage_sec Usage * * \subsection observer_create_sec Implementing an observer * * \code * * class MyObserver : public AbstractClientObserver * { * public: * MyObserver(const ChannelClassSpecList &channelFilter); * ~MyObserver() { } * * void observeChannels(const MethodInvocationContextPtr<> &context, * const AccountPtr &account, * const ConnectionPtr &connection, * const QList &channels, * const ChannelDispatchOperationPtr &dispatchOperation, * const QList &requestsSatisfied, * const AbstractClientObserver::ObserverInfo &observerInfo); * }; * * MyObserver::MyObserver(const ChannelClassSpecList &channelFilter) * : AbstractClientObserver(channelFilter) * { * } * * void MyObserver::observeChannels(const MethodInvocationContextPtr<> &context, * const AccountPtr &account, * const ConnectionPtr &connection, * const QList &channels, * const ChannelDispatchOperationPtr &dispatchOperation, * const QList &requestsSatisfied, * const AbstractClientObserver::ObserverInfo &observerInfo) * { * // do something, log messages, ... * * context->setFinished(); * } * * \endcode * * \subsection observer_register_sec Registering an observer * * \code * * ClientRegistrar registrar = ClientRegistrar::create(); * AbstractClientPtr observer = AbstractClientPtr::dynamicCast( * SharedPtr(new MyObserver( * ChannelClassSpecList() << ChannelClassSpec::textChat()))); * registrar->registerClient(observer, "myobserver"); * * \endcode * * \sa AbstractClient */ /** * \class AbstractClientObserver::ObserverInfo * \ingroup clientclient * \headerfile TelepathyQt/abstract-client.h * * \brief The AbstractClientObserver::ObserverInfo class provides a wrapper * around the additional info about the channels passed to observeChannels(). * * \sa AbstractClientObserver */ struct TP_QT_NO_EXPORT AbstractClientObserver::ObserverInfo::Private : public QSharedData { Private(const QVariantMap &info) : info(info) {} QVariantMap info; }; AbstractClientObserver::ObserverInfo::ObserverInfo(const QVariantMap &info) : mPriv(new Private(info)) { } AbstractClientObserver::ObserverInfo::ObserverInfo(const ObserverInfo &other) : mPriv(other.mPriv) { } AbstractClientObserver::ObserverInfo::~ObserverInfo() { } AbstractClientObserver::ObserverInfo &AbstractClientObserver::ObserverInfo::operator=( const ObserverInfo &other) { if (this == &other) { return *this; } mPriv = other.mPriv; return *this; } QVariantMap AbstractClientObserver::ObserverInfo::allInfo() const { return mPriv->info; } /** * Construct a new AbstractClientObserver object. * * \param channelFilter A specification of the channels in which this observer * is interested. * \param shouldRecover Whether upon the startup of this observer, * observeChannels() will be called for every already * existing channel matching its observerChannelFilter(). */ AbstractClientObserver::AbstractClientObserver( const ChannelClassSpecList &channelFilter, bool shouldRecover) : mPriv(new Private(channelFilter.bareClasses(), shouldRecover)) // The channel filter is converted here to the low-level class so that any warnings are // emitted immediately rather than only when the CD introspects this Client { } /** * Class destructor. */ AbstractClientObserver::~AbstractClientObserver() { delete mPriv; } /** * Return the property containing a specification of the channels that this * channel observer is interested. The observeChannels() method should be called * by the channel dispatcher whenever any of the newly created channels match * this description. * * See * the Telepathy specification for documentation about the allowed * types and how to define filters. * * This property never changes while the observer process owns its client bus * name. If an observer wants to add extra channels to its list of interests at * runtime, it can register an additional client bus name using * ClientRegistrar::registerClient(). * To remove those filters, it can release the bus name using * ClientRegistrar::unregisterClient(). * * The same principle is applied to approvers and handlers. * * \return A specification of the channels that this channel observer is * interested as a list of ChannelClassSpec objects. * \sa observeChannels() */ ChannelClassSpecList AbstractClientObserver::observerFilter() const { return ChannelClassSpecList(mPriv->channelFilter); } /** * Return whether upon the startup of this observer, observeChannels() * will be called for every already existing channel matching its * observerChannelFilter(). * * \param \c true if this observer observerChannels() will be called for every * already existing channel matching its observerChannelFilter(), * \c false otherwise. */ bool AbstractClientObserver::shouldRecover() const { return mPriv->shouldRecover; } /** * \fn void AbstractClientObserver::observeChannels( * const MethodInvocationContextPtr<> &context, * const AccountPtr &account, * const ConnectionPtr &connection, * const QList &channels, * const ChannelDispatchOperationPtr &dispatchOperation, * const QList &requestsSatisfied, * const ObserverInfo &observerInfo); * * Called by the channel dispatcher when channels in which the observer has * registered an interest are announced. * * If the announced channels contains channels that match the * observerChannelFilter(), and some that do not, then only a subset of the * channels (those that do match the filter) are passed to this method. * * If the channel dispatcher will split up the channels from a single * announcement and dispatch them separately (for instance because no * installed handler can handle all of them), it will call this method * several times. * * The observer must not call MethodInvocationContext::setFinished() until it * is ready for a handler for the channel to run (which may change the * channel's state). For instance the received \a context object should be * stored until this method is finished processing and then * MethodInvocationContext::setFinished() or * MethodInvocationContext::setFinishedWithError() should be called on the * received \a context object. * * Specialized observers must reimplement this method. * * \param context A MethodInvocationContextPtr object that must be used to * indicate whether this method finished processing. * \param account The account with which the channels are associated. * \param connection The connection with which the channels are associated. * \param channels The channels to be observed. * \param dispatchOperation The dispatch operation for these channels. * The object will be invalid (DBusProxy::isValid() * will be false) if there is no dispatch * operation in place (because the channels were * requested, not incoming). * If the Observer calls * ChannelDispatchOperation::claim() or * ChannelDispatchOperation::handleWith() on this * object, it must be careful to avoid deadlock, since * these methods cannot return until the observer has * returned from observeChannels(). * \param requestsSatisfied The requests satisfied by these channels. * \param observerInfo Additional information about these channels. */ struct TP_QT_NO_EXPORT AbstractClientApprover::Private { Private(const ChannelClassList &channelFilter) : channelFilter(channelFilter) { } ChannelClassList channelFilter; }; /** * \class AbstractClientApprover * \ingroup clientclient * \headerfile TelepathyQt/abstract-client.h * * \brief The AbstractClientApprover class represents a Telepathy approver. * * Approvers are clients that notify the user that new channels have been * created, and allow the user to accept or reject those channels. * * Approvers can also select which channel handler will be used for the channel, * for instance by offering the user a list of possible handlers rather than * just an accept/reject choice. However, the channel dispatcher must be able to * prioritize possible handlers on its own using some reasonable heuristic, * probably based on user configuration. * * It is possible (and useful) to have an approver and a channel handler in the * same process; this is particularly useful if a channel handler wants to claim * responsibility for particular channels itself. * * All approvers are notified simultaneously. For instance, in a desktop system, * there might be one approver that displays a notification-area icon, one that * is part of a contact list window and highlights contacts there, and one that * is part of a full-screen media player. * * Any approver can approve the handling of a channel dispatch operation with a * particular channel handler by calling the * ChannelDispatchOperation::handleWith() method. Approvers can also attempt to * claim channels by calling ChannelDispatchOperation::claim(). If this * succeeds, the approver may handle the channels itself (if it is also a * handler), or close the channels in order to reject them. * * Approvers wishing to reject channels should call the * ChannelDispatchOperation::claim() method, then (if it succeeds) close the * channels in any way they see fit. * * The first approver to reply gets its decision acted on; any other approvers * that reply at approximately the same time will get an error, indicating that * the channel has already been dealt with. * * Approvers should usually prompt the user and ask for confirmation, rather * than dispatching the channel to a handler straight away. * * To become an approver one should inherit AbstractClientApprover and * implement the pure virtual addDispatchOperation() method. After that the * object representing the approver must be registered using * ClientRegistrar::registerClient(). * * When new channels in which the approver has registered an interest are * ready to be dispatched, the method addDispatchOperation() is invoked. * The new channels are represented by a ChannelDispatchOperation object, which * is passed to the addDispatchOperation() method. * All approvers are notified simultaneously. * * \section approver_usage_sec Usage * * \subsection approver_create_sec Implementing an approver * * \code * * class MyApprover : public AbstractClientApprover * { * public: * MyApprover(const ChannelClassSpecSpecList &channelFilter); * ~MyApprover() { } * * void addDispatchOperation(const MethodInvocationContextPtr<> &context, * const ChannelDispatchOperationPtr &dispatchOperation); * }; * * MyApprover::MyApprover(const ChannelClassSpecList &channelFilter) * : AbstractClientApprover(channelFilter) * { * } * * void MyApprover::addDispatchOperation( * const MethodInvocationContextPtr<> &context, * const ChannelDispatchOperationPtr &dispatchOperation) * { * // do something with dispatchOperation * * context->setFinished(); * } * * \endcode * * \subsection approver_register_sec Registering an approver * * \code * * ClientRegistrar registrar = ClientRegistrar::create(); * AbstractClientPtr approver = AbstractClientPtr::dynamicCast( * SharedPtr(new MyApprover( * ChannelClassSpecList() << ChannelClassSpec::textChat()))); * registrar->registerClient(approver, "myapprover"); * * \endcode * * \sa AbstractClient */ /** * Construct a new AbstractClientApprover object. * * \param channelFilter A specification of the channels in which this approver * is interested. */ AbstractClientApprover::AbstractClientApprover( const ChannelClassSpecList &channelFilter) : mPriv(new Private(channelFilter.bareClasses())) { } /** * Class destructor. */ AbstractClientApprover::~AbstractClientApprover() { delete mPriv; } /** * Return the property containing a specification of the channels that this * channel approver is interested. The addDispatchOperation() method should be * called by the channel dispatcher whenever at least one of the channels in * a channel dispatch operation matches this description. * * This method works in exactly the same way as the * AbstractClientObserver::observerChannelFilter() method. In particular, the * returned value cannot change while the handler process continues to own the * corresponding client bus name. * * In the .client file, represented in the same way as observer channel * filter, the group is #TP_QT_IFACE_CLIENT_APPROVER followed by * ApproverChannelFilter instead. * * \return A specification of the channels that this channel approver is * interested as a list of ChannelClassSpec objects. * \sa addDispatchOperation() */ ChannelClassSpecList AbstractClientApprover::approverFilter() const { return ChannelClassSpecList(mPriv->channelFilter); } /** * \fn void AbstractClientApprover::addDispatchOperation( * const MethodInvocationContextPtr<> &context, * const ChannelDispatchOperationPtr &dispatchOperation); * * Called by the channel dispatcher when a dispatch operation in which the * approver has registered an interest is created, or when the approver starts * up while such channel dispatch operations already exist. * * The received \a context object should be stored until this * method is finished processing and then MethodInvocationContext::setFinished() * or MethodInvocationContext::setFinishedWithError() should be called on the * received \a context object. * * Specialized approvers must reimplement this method. * * \param context A MethodInvocationContextPtr object that must be used to * indicate whether this method finished processing. * \param dispatchOperation The dispatch operation to be processed. */ struct TP_QT_NO_EXPORT AbstractClientHandler::Private { Private(const ChannelClassList &channelFilter, const Capabilities &capabilities, bool wantsRequestNotification) : channelFilter(channelFilter), capabilities(capabilities), wantsRequestNotification(wantsRequestNotification) { } ChannelClassList channelFilter; Capabilities capabilities; bool wantsRequestNotification; }; /** * \class AbstractClientHandler * \ingroup clientclient * \headerfile TelepathyQt/abstract-client.h * * \brief The AbstractClientHandler class represents a Telepathy handler. * * Handlers are the user interface for a channel. They turn an abstract * channel into something the user wants to see, like a text message * stream or an audio and/or video call. * * For its entire lifetime, each channel on a connection known to the channel * dispatcher is either being processed by the channel dispatcher, or being * handled by precisely one handler. * * Because each channel is only handled by one handler, handlers may perform * actions that only make sense to do once, such as acknowledging text messages, * transferring the file, etc. * * When a new incoming channel is offered to approvers by the channel * dispatcher, it also offers the approvers a list of all the running or * activatable handlers whose filter indicates that they are able to handle * the channel. The approvers can choose one of those channel handlers to * handle the channel. * * When a new outgoing channel appears, the channel dispatcher passes it to * an appropriate channel handler automatically. * * To become an handler one should inherit AbstractClientHandler and * implement the pure virtual bypassApproval() and handleChannels() methods. * After that the object representing the handler must be registered using * ClientRegistrar::registerClient(). * * When new channels in which the approver has registered an interest are * ready to be handled, the method handleChannels() is invoked. * * \section handler_usage_sec Usage * * \subsection handler_create_sec Implementing a handler * * \code * * class MyHandler : public AbstractClientHandler * { * public: * MyHandler(const ChannelClassSpecList &channelFilter); * ~MyHandler() { } * * void bypassApproval() const; * * void handleChannels(const MethodInvocationContextPtr<> &context, * const AccountPtr &account, * const ConnectionPtr &connection, * const QList &channels, * const QList &requestsSatisfied, * const QDateTime &userActionTime, * const AbstractClientHandler::HandlerInfo &handlerInfo); * }; * * MyHandler::MyHandler(const ChannelClassSpecList &channelFilter) * : AbstractClientHandler(channelFilter) * { * } * * void MyHandler::bypassApproval() const * { * return false; * } * * void MyHandler::handleChannels(const MethodInvocationContextPtr<> &context, * const AccountPtr &account, * const ConnectionPtr &connection, * const QList &channels, * const QList &requestsSatisfied, * const QDateTime &userActionTime, * const AbstractClientHandler::HandlerInfo &handlerInfo) * { * // do something * * context->setFinished(); * } * * \endcode * * \subsection handler_register_sec Registering a handler * * \code * * ClientRegistrar registrar = ClientRegistrar::create(); * AbstractClientPtr handler = AbstractClientPtr::dynamicCast( * SharedPtr(new MyHandler( * ChannelClassSpecList() << ChannelClassSpec::textChat()))); * registrar->registerClient(handler, "myhandler"); * * \endcode * * \sa AbstractClient */ /** * \class AbstractClientHandler::Capabilities * \ingroup clientclient * \headerfile TelepathyQt/abstract-client.h * * \brief The AbstractClientHandler::Capabilities class provides a wrapper * around the capabilities of a handler. * * \sa AbstractClientHandler */ /** * \class AbstractClientHandler::HandlerInfo * \ingroup clientclient * \headerfile TelepathyQt/abstract-client.h * * \brief The AbstractClientHandler::HandlerInfo class provides a wrapper * around the additional info about the channels passed to handleChannels(). * * \sa AbstractClientHandler */ struct TP_QT_NO_EXPORT AbstractClientHandler::Capabilities::Private : public QSharedData { Private(const QStringList &tokens) : tokens(QSet::fromList(tokens)) {} QSet tokens; }; AbstractClientHandler::Capabilities::Capabilities(const QStringList &tokens) : mPriv(new Private(tokens)) { } AbstractClientHandler::Capabilities::Capabilities(const Capabilities &other) : mPriv(other.mPriv) { } AbstractClientHandler::Capabilities::~Capabilities() { } AbstractClientHandler::Capabilities &AbstractClientHandler::Capabilities::operator=( const Capabilities &other) { if (this == &other) { return *this; } mPriv = other.mPriv; return *this; } bool AbstractClientHandler::Capabilities::hasToken(const QString &token) const { return mPriv->tokens.contains(token); } void AbstractClientHandler::Capabilities::setToken(const QString &token) { mPriv->tokens.insert(token); } void AbstractClientHandler::Capabilities::unsetToken(const QString &token) { mPriv->tokens.remove(token); } QStringList AbstractClientHandler::Capabilities::allTokens() const { return mPriv->tokens.toList(); } struct TP_QT_NO_EXPORT AbstractClientHandler::HandlerInfo::Private : public QSharedData { Private(const QVariantMap &info) : info(info) {} QVariantMap info; }; AbstractClientHandler::HandlerInfo::HandlerInfo(const QVariantMap &info) : mPriv(new Private(info)) { } AbstractClientHandler::HandlerInfo::HandlerInfo(const HandlerInfo &other) : mPriv(other.mPriv) { } AbstractClientHandler::HandlerInfo::~HandlerInfo() { } AbstractClientHandler::HandlerInfo &AbstractClientHandler::HandlerInfo::operator=( const HandlerInfo &other) { if (this == &other) { return *this; } mPriv = other.mPriv; return *this; } QVariantMap AbstractClientHandler::HandlerInfo::allInfo() const { return mPriv->info; } /** * Construct a new AbstractClientHandler object. * * \param channelFilter A specification of the channels in which this observer * is interested. * \param wantsRequestNotification Whether this handler wants to receive channel * requests notification via addRequest() and * removeRequest(). * \param capabilities The set of additional capabilities supported by this * handler. */ AbstractClientHandler::AbstractClientHandler(const ChannelClassSpecList &channelFilter, const Capabilities &capabilities, bool wantsRequestNotification) : mPriv(new Private(channelFilter.bareClasses(), capabilities, wantsRequestNotification)) { } /** * Class destructor. */ AbstractClientHandler::~AbstractClientHandler() { delete mPriv; } /** * Return the property containing a specification of the channels that this * channel handler can deal with. It will be offered to approvers as a potential * channel handler for bundles that contain only suitable channels, or for * suitable channels that must be handled separately. * * This method works in exactly the same way as the * AbstractClientObserver::observerChannelFilter() method. In particular, the * returned value cannot change while the handler process continues to own the * corresponding client bus name. * * In the .client file, represented in the same way as observer channel * filter, the group is #TP_QT_IFACE_CLIENT_HANDLER suffixed * by HandlerChannelFilter instead. * * \return A specification of the channels that this channel handler can deal * with as a list of ChannelClassSpec objects. */ ChannelClassSpecList AbstractClientHandler::handlerFilter() const { return ChannelClassSpecList(mPriv->channelFilter); } /** * Return the set of additional capabilities supported by this handler. * * \return The capabilities as an AbstractClientHandler::Capabilities object. */ AbstractClientHandler::Capabilities AbstractClientHandler::handlerCapabilities() const { return mPriv->capabilities; } /** * \fn bool AbstractClientHandler::bypassApproval() const; * * Return whether channels destined for this handler are automatically * handled, without invoking approvers. * * \return \c true if automatically handled, \c false otherwise. */ /** * \fn void AbstractClientHandler::handleChannels( * const MethodInvocationContextPtr<> &context, * const AccountPtr &account, * const ConnectionPtr &connection, * const QList &channels, * const QList &requestsSatisfied, * const QDateTime &userActionTime, * const HandlerInfo &handlerInfo); * * Called by the channel dispatcher when this handler should handle these * channels, or when this handler should present channels that it is already * handling to the user (e.g. bring them into the foreground). * * Clients are expected to know what channels they're already handling, and * which channel object corresponds to which window or tab. * * After handleChannels() replies successfully by calling * MethodInvocationContext::setFinished(), the client process is considered * to be responsible for the channel until it its unique name disappears from * the bus. * * If a process has multiple client bus names - some temporary and some * long-lived - and drops one of the temporary bus names in order to reduce the * set of channels that it will handle, any channels that it is already handling * will remain unaffected. * * The received \a context object should be stored until this * method is finished processing and then MethodInvocationContext::setFinished() * or MethodInvocationContext::setFinishedWithError() should be called on the * received \a context object. * * Specialized handlers must reimplement this method. * * \param context A MethodInvocationContextPtr object that must be used to * indicate whether this method finished processing. * \param account The account with which the channels are associated. * \param connection The connection with which the channels are associated. * \param channels The channels to be handled. * \param dispatchOperation The dispatch operation for these channels. * The object will be invalid (DBusProxy::isValid() * will be false) if there is no dispatch * operation in place (because the channels were * requested, not incoming). * \param requestsSatisfied The requests satisfied by these channels. * \param userActionTime The time at which user action occurred, or 0 if this * channel is to be handled for some reason not involving * user action. Handlers should use this for * focus-stealing prevention, if applicable. * \param handlerInfo Additional information about these channels. */ /** * Return whether this handler wants to receive notification of channel requests * via addRequest() and removeRequest(). * * This property is set by the constructor and cannot be changed after that. * * \return \c true if receiving channel requests notification is desired, * \c false otherwise. */ bool AbstractClientHandler::wantsRequestNotification() const { return mPriv->wantsRequestNotification; } /** * Called by the channel dispatcher to indicate that channels have been * requested, and that if the request is successful, they will probably be * handled by this handler. * * This allows the UI to start preparing to handle the channels in advance * (e.g. render a window with an "in progress" message), improving perceived * responsiveness. * * If the request succeeds and is given to the expected handler, the * requestsSatisfied parameter to handleChannels() can be used to match the * channel to a previous addRequest() call. * * This lets the UI direct the channels to the window that it already opened. * * If the request fails, the expected handler is notified by the channel * dispatcher calling its removeRequest() method. * * This lets the UI close the window or display the error. * * The channel dispatcher will attempt to ensure that handleChannels() is called * on the same handler that received addRequest(). If that isn't possible, * removeRequest() will be called on the handler that previously received * addRequest(), with the special error #TP_QT_ERROR_NOT_YOURS, which * indicates that some other handler received the channel instead. * * Expected handling is for the UI to close the window it previously opened. * * Specialized handlers that want to be notified of newly requested channel * should reimplement this method. * * \param channelRequest The newly created channel request. * \sa removeRequest() */ void AbstractClientHandler::addRequest( const ChannelRequestPtr &channelRequest) { // do nothing, subclasses that want to listen requests should reimplement // this method } /** * Called by the ChannelDispatcher to indicate that a request previously passed * to addRequest() has failed and should be disregarded. * * Specialized handlers that want to be notified of removed channel requests * should reimplement this method. * * \param channelRequest The channel request that failed. * \param errorName The name of the D-Bus error with which the request failed. * If this is #TP_QT_ERROR_NOT_YOURS, this indicates that * the request succeeded, but all the resulting channels were * given to some other handler. * \param errorMessage Any message supplied with the D-Bus error. */ void AbstractClientHandler::removeRequest( const ChannelRequestPtr &channelRequest, const QString &errorName, const QString &errorMessage) { // do nothing, subclasses that want to listen requests should reimplement // this method } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/SharedPtr0000664000175000017500000000035212470405660017033 0ustar jrjr#ifndef _TelepathyQt_SharedPtr_HEADER_GUARD_ #define _TelepathyQt_SharedPtr_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/simple-call-observer.cpp0000664000175000017500000003212612470405660021753 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/simple-call-observer.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT SimpleCallObserver::Private { Private(SimpleCallObserver *parent, const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization, CallDirection direction); SimpleCallObserver *parent; AccountPtr account; QString contactIdentifier; CallDirection direction; SimpleObserverPtr observer; }; SimpleCallObserver::Private::Private(SimpleCallObserver *parent, const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization, CallDirection direction) : parent(parent), account(account), contactIdentifier(contactIdentifier), direction(direction) { debug() << "Creating a new SimpleCallObserver"; ChannelClassSpec channelFilterSMC = ChannelClassSpec::streamedMediaCall(); ChannelClassSpec channelFilterCall = ChannelClassSpec::mediaCall(); if (direction == CallDirectionIncoming) { channelFilterSMC.setRequested(false); channelFilterCall.setRequested(false); } else if (direction == CallDirectionOutgoing) { channelFilterSMC.setRequested(true); channelFilterCall.setRequested(true); } observer = SimpleObserver::create(account, ChannelClassSpecList() << channelFilterSMC << channelFilterCall, contactIdentifier, requiresNormalization, QList()); parent->connect(observer.data(), SIGNAL(newChannels(QList)), SLOT(onNewChannels(QList))); parent->connect(observer.data(), SIGNAL(channelInvalidated(Tp::ChannelPtr,QString,QString)), SLOT(onChannelInvalidated(Tp::ChannelPtr,QString,QString))); } /** * \class SimpleCallObserver * \ingroup utils * \headerfile TelepathyQt/simple-call-observer.h * * \brief The SimpleCallObserver class provides an easy way to track calls * in an account and can be optionally filtered by a contact and/or * call direction. */ /** * Create a new SimpleCallObserver object. * * Events will be signalled for all calls in \a account that respect \a direction. * * \param account The account used to listen to events. * \param direction The direction of the calls used to filter events. * \return An SimpleCallObserverPtr object pointing to the newly created * SimpleCallObserver object. */ SimpleCallObserverPtr SimpleCallObserver::create(const AccountPtr &account, CallDirection direction) { return create(account, QString(), false, direction); } /** * Create a new SimpleCallObserver object. * * Events will be signalled for all calls in \a account established with \a contact and * that respect \a direction. * * \param account The account used to listen to events. * \param contact The contact used to filter events. * \param direction The direction of the calls used to filter events. * \return An SimpleCallObserverPtr object pointing to the newly created * SimpleCallObserver object. */ SimpleCallObserverPtr SimpleCallObserver::create(const AccountPtr &account, const ContactPtr &contact, CallDirection direction) { if (contact) { return create(account, contact->id(), false, direction); } return create(account, QString(), false, direction); } /** * Create a new SimpleCallObserver object. * * Events will be signalled for all calls in \a account established with a contact identified by \a * contactIdentifier and that respect \a direction. * * \param account The account used to listen to events. * \param contactIdentifier The identifier of the contact used to filter events. * \param direction The direction of the calls used to filter events. * \return An SimpleCallObserverPtr object pointing to the newly created * SimpleCallObserver object. */ SimpleCallObserverPtr SimpleCallObserver::create(const AccountPtr &account, const QString &contactIdentifier, CallDirection direction) { return create(account, contactIdentifier, true, direction); } SimpleCallObserverPtr SimpleCallObserver::create(const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization, CallDirection direction) { return SimpleCallObserverPtr( new SimpleCallObserver(account, contactIdentifier, requiresNormalization, direction)); } /** * Construct a new SimpleCallObserver object. * * \param account The account used to listen to events. * \param contactIdentifier The identifier of the contact used to filter events. * \param requiresNormalization Whether \a contactIdentifier needs to be * normalized. * \param direction The direction of the calls used to filter events. * \return An SimpleCallObserverPtr object pointing to the newly created * SimpleCallObserver object. */ SimpleCallObserver::SimpleCallObserver(const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization, CallDirection direction) : mPriv(new Private(this, account, contactIdentifier, requiresNormalization, direction)) { } /** * Class destructor. */ SimpleCallObserver::~SimpleCallObserver() { delete mPriv; } /** * Return the account used to listen to events. * * \return A pointer to the Account object. */ AccountPtr SimpleCallObserver::account() const { return mPriv->account; } /** * Return the identifier of the contact used to filter events, or an empty string if none was * provided at construction. * * \return The identifier of the contact. */ QString SimpleCallObserver::contactIdentifier() const { return mPriv->contactIdentifier; } /** * Return the direction of the calls used to filter events. * * \return The direction of the calls as SimpleCallObserver::CallDirection. */ SimpleCallObserver::CallDirection SimpleCallObserver::direction() const { return mPriv->direction; } /** * Return the list of calls currently being observed. * * \return A list of pointers to CallChannel objects. */ QList SimpleCallObserver::calls() const { QList ret; foreach (const ChannelPtr &channel, mPriv->observer->channels()) { CallChannelPtr callChannel = CallChannelPtr::qObjectCast(channel); if (callChannel) { ret << callChannel; } } return ret; } /** * Return the list of streamed media calls currently being observed. * * \deprecated Use calls() instead. Modern clients shouldn't use StreamedMedia channels. * \return A list of pointers to StreamedMediaChannel objects. */ QList SimpleCallObserver::streamedMediaCalls() const { QList ret; foreach (const ChannelPtr &channel, mPriv->observer->channels()) { StreamedMediaChannelPtr smChannel = StreamedMediaChannelPtr::qObjectCast(channel); if (smChannel) { ret << smChannel; } } return ret; } void SimpleCallObserver::onNewChannels(const QList &channels) { foreach (const ChannelPtr &channel, channels) { if (channel->channelType() == TP_QT_IFACE_CHANNEL_TYPE_CALL) { CallChannelPtr callChannel = CallChannelPtr::qObjectCast(channel); if (!callChannel) { warning() << "Channel received to observe is not a subclass of " "CallChannel. ChannelFactory set on this observer's account must " "construct CallChannel subclasses for channels of type Call. " "Ignoring channel"; continue; } emit callStarted(callChannel); } else if (channel->channelType() == TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) { StreamedMediaChannelPtr smChannel = StreamedMediaChannelPtr::qObjectCast(channel); if (!smChannel) { warning() << "Channel received to observe is not a subclass of " "StreamedMediaChannel. ChannelFactory set on this observer's account must " "construct StreamedMediaChannel subclasses for channels of type StreamedMedia. " "Ignoring channel"; continue; } emit streamedMediaCallStarted(smChannel); } else { warning() << "Channel received to observe is not of type Call or StreamedMedia, " "service confused. Ignoring channel"; continue; } } } void SimpleCallObserver::onChannelInvalidated(const ChannelPtr &channel, const QString &errorName, const QString &errorMessage) { if (channel->channelType() == TP_QT_IFACE_CHANNEL_TYPE_CALL) { CallChannelPtr callChannel = CallChannelPtr::qObjectCast(channel); if (!callChannel) { warning() << "Channel received to observe is not a subclass of " "CallChannel. ChannelFactory set on this observer's account must " "construct CallChannel subclasses for channels of type Call. " "Ignoring channel"; return; } emit callEnded(callChannel, errorName, errorMessage); } else if (channel->channelType() == TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) { StreamedMediaChannelPtr smChannel = StreamedMediaChannelPtr::qObjectCast(channel); if (!smChannel) { warning() << "Channel received to observe is not a subclass of " "StreamedMediaChannel. ChannelFactory set on this observer's account must " "construct StreamedMediaChannel subclasses for channels of type StreamedMedia. " "Ignoring channel"; return; } emit streamedMediaCallEnded(smChannel, errorName, errorMessage); } else { warning() << "Channel received to observe is not of type Call or StreamedMedia, " "service confused. Ignoring channel"; } } /** * \fn void SimpleCallObserver::callStarted(const Tp::CallChannelPtr &channel) * * Emitted whenever a call that matches this observer's criteria is started. * * \param channel The channel representing the call that started. */ /** * \fn void SimpleCallObserver::callEnded(const Tp::CallChannelPtr &channel, * const QString &errorName, const QString &errorMessage) * * Emitted whenever a call that matches this observer's criteria has ended. * * \param channel The channel representing the call that ended. * \param errorName A D-Bus error name (a string in a subset * of ASCII, prefixed with a reversed domain name). * \param errorMessage A debugging message associated with the error. */ /** * \fn void SimpleCallObserver::streamedMediaCallStarted(const Tp::StreamedMediaChannelPtr &channel) * * Emitted whenever a streamed media call that matches this observer's criteria is * started. * * \param channel The channel representing the streamed media call that started. * \deprecated Use callStarted() instead. Modern clients shouldn't use StreamedMedia channels. */ /** * \fn void SimpleCallObserver::streamedMediaCallEnded(const Tp::StreamedMediaChannelPtr &channel, * const QString &errorName, const QString &errorMessage) * * Emitted whenever a streamed media call that matches this observer's criteria has * ended. * * \param channel The channel representing the streamed media call that ended. * \param errorName A D-Bus error name (a string in a subset * of ASCII, prefixed with a reversed domain name). * \param errorMessage A debugging message associated with the error. * \deprecated Use callEnded() instead. Modern clients shouldn't use StreamedMedia channels. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/outgoing-file-transfer-channel.h0000664000175000017500000000462112470405660023370 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_outgoing_file_transfer_channel_h_HEADER_GUARD_ #define _TelepathyQt_outgoing_file_transfer_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT OutgoingFileTransferChannel : public FileTransferChannel { Q_OBJECT Q_DISABLE_COPY(OutgoingFileTransferChannel) public: static const Feature FeatureCore; static OutgoingFileTransferChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~OutgoingFileTransferChannel(); PendingOperation *provideFile(QIODevice *input); protected: OutgoingFileTransferChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = OutgoingFileTransferChannel::FeatureCore); private Q_SLOTS: TP_QT_NO_EXPORT void onProvideFileFinished(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onSocketConnected(); TP_QT_NO_EXPORT void onSocketDisconnected(); TP_QT_NO_EXPORT void onSocketError(QAbstractSocket::SocketError error); TP_QT_NO_EXPORT void onInputAboutToClose(); TP_QT_NO_EXPORT void doTransfer(); private: TP_QT_NO_EXPORT void connectToHost(); TP_QT_NO_EXPORT void setFinished(); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceTubeInterface0000664000175000017500000000041712470405660022773 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceTubeInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceTubeInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-contact-attributes.cpp0000664000175000017500000001576612470405660023200 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-contact-attributes.moc.hpp" #include #include #include "TelepathyQt/debug-internal.h" namespace Tp { /** * \class PendingContactAttributes * \ingroup clientconn * \headerfile TelepathyQt/pending-contact-attributes.h * * \brief The PendingContactAttributes class represents the parameters of and * the reply to an asynchronous request for raw contact attributes, as used in * the ConnectionLowlevel::contactAttributes() low-level convenience method wrapping the * Client::ConnectionInterfaceContactsInterface::GetContactAttributes() D-Bus * method. * * See \ref async_model */ struct TP_QT_NO_EXPORT PendingContactAttributes::Private { UIntList contactsRequested; QStringList interfacesRequested; bool shouldReference; ReferencedHandles validHandles; UIntList invalidHandles; ContactAttributesMap attributes; }; PendingContactAttributes::PendingContactAttributes(const ConnectionPtr &connection, const UIntList &handles, const QStringList &interfaces, bool reference) : PendingOperation(connection), mPriv(new Private) { mPriv->contactsRequested = handles; mPriv->interfacesRequested = interfaces; mPriv->shouldReference = reference; } /** * Class destructor. */ PendingContactAttributes::~PendingContactAttributes() { delete mPriv; } /** * Return the connection through which the request was made. * * \return A pointer to the Connection object. */ ConnectionPtr PendingContactAttributes::connection() const { return ConnectionPtr(qobject_cast((Connection*) object().data())); } /** * Return the contacts for which attributes were requested. * * \return Reference to a list with the handles of the contacts. */ const UIntList &PendingContactAttributes::contactsRequested() const { return mPriv->contactsRequested; } /** * Return the interfaces the corresponding attributes of which were requested. * * \return Reference to a list of D-Bus interface names. */ const QStringList &PendingContactAttributes::interfacesRequested() const { return mPriv->interfacesRequested; } /** * Return whether it was requested that the contact handles should be referenced in addition to * fetching their attributes. This corresponds to the reference argument to * Connection::contactAttributes(). * * \return Whether the handles should be referenced or not. */ bool PendingContactAttributes::shouldReference() const { return mPriv->shouldReference; } /** * If referencing the handles was requested (as indicated by shouldReference()), returns the * now-referenced handles resulting from the operation. If the operation has not (yet) finished * successfully (isFinished() returns false), or referencing was not requested, the * return value is undefined. * * Even if referencing was requested, the list will not always contain all of the handles in * contactsRequested(), only the ones which were valid. The valid handles will be in the same order * as in contactsRequested(), though. * * \return ReferencedHandles instance containing the handles. */ ReferencedHandles PendingContactAttributes::validHandles() const { if (!isFinished()) { warning() << "PendingContactAttributes::validHandles() called before finished"; } else if (isError()) { warning() << "PendingContactAttributes::validHandles() called when errored"; } else if (!shouldReference()) { warning() << "PendingContactAttributes::validHandles() called but weren't asked to" << "reference handles"; } return mPriv->validHandles; } /** * Return the handles which were found to be invalid while processing the operation. If the * operation has not (yet) finished successfully (isFinished() returns false), the * return value is undefined. * * \return A list with the invalid handles. */ UIntList PendingContactAttributes::invalidHandles() const { if (!isFinished()) { warning() << "PendingContactAttributes::validHandles() called before finished"; } else if (isError()) { warning() << "PendingContactAttributes::validHandles() called when errored"; } return mPriv->invalidHandles; } /** * Return a dictionary mapping the valid contact handles in contactsRequested() (when also * referencing, this means the contents of validHandles()) to contact attributes. If the operation * has not (yet) finished successfully (isFinished() returns false), the return value * is undefined. * * \return Mapping from handles to variant maps containing the attributes. */ ContactAttributesMap PendingContactAttributes::attributes() const { if (!isFinished()) { warning() << "PendingContactAttributes::validHandles() called before finished"; } else if (isError()) { warning() << "PendingContactAttributes::validHandles() called when errored"; } return mPriv->attributes; } void PendingContactAttributes::onCallFinished(QDBusPendingCallWatcher* watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { debug().nospace() << "GetCAs: error " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } else { mPriv->attributes = reply.value(); UIntList validHandles; foreach (uint contact, mPriv->contactsRequested) { if (mPriv->attributes.contains(contact)) { validHandles << contact; } else { mPriv->invalidHandles << contact; } } if (shouldReference()) { mPriv->validHandles = ReferencedHandles(connection(), HandleTypeContact, validHandles); } setFinished(); } connection()->handleRequestLanded(HandleTypeContact); watcher->deleteLater(); } void PendingContactAttributes::failImmediately(const QString &error, const QString &errorMessage) { setFinishedWithError(error, errorMessage); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceSMSInterface0000664000175000017500000000041512470405660022534 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceSMSInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceSMSInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/DBusProxyFactory0000664000175000017500000000040012470405660020360 0ustar jrjr#ifndef _TelepathyQt_DBusProxyFactory_HEADER_GUARD_ #define _TelepathyQt_DBusProxyFactory_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/simple-pending-operations.h0000664000175000017500000000547712470405660022476 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_operations_h_HEADER_GUARD_ #define _TelepathyQt_pending_operations_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT PendingSuccess : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingSuccess) public: PendingSuccess(const SharedPtr &object) : PendingOperation(object) { setFinished(); } }; class TP_QT_EXPORT PendingFailure : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingFailure) public: PendingFailure(const QString &name, const QString &message, const SharedPtr &object) : PendingOperation(object) { setFinishedWithError(name, message); } PendingFailure(const QDBusError &error, const SharedPtr &object) : PendingOperation(object) { setFinishedWithError(error); } }; class TP_QT_EXPORT PendingVoid : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingVoid) public: PendingVoid(QDBusPendingCall call, const SharedPtr &object); private Q_SLOTS: TP_QT_NO_EXPORT void watcherFinished(QDBusPendingCallWatcher*); private: struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT PendingComposite : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingComposite) public: PendingComposite(const QList &operations, const SharedPtr &object); PendingComposite(const QList &operations, bool failOnFirstError, const SharedPtr &object); ~PendingComposite(); private Q_SLOTS: TP_QT_NO_EXPORT void onOperationFinished(Tp::PendingOperation *); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/DebugReceiver0000664000175000017500000000036612470405660017657 0ustar jrjr#ifndef _TelepathyQt_DebugReceiver_HEADER_GUARD_ #define _TelepathyQt_DebugReceiver_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/global.h.in0000664000175000017500000001226212470405660017235 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_global_h_HEADER_GUARD_ #define _TelepathyQt_global_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #define TP_QT_MAJOR_VERSION @TP_QT_MAJOR_VERSION@ #define TP_QT_MINOR_VERSION @TP_QT_MINOR_VERSION@ #define TP_QT_MICRO_VERSION @TP_QT_MICRO_VERSION@ #define TP_QT_VERSION ((TP_QT_MAJOR_VERSION<<16)|(TP_QT_MINOR_VERSION<<8)|(TP_QT_MICRO_VERSION)) /** * @def TP_QT_VERSION_CHECK * @ingroup macros * * The TP_QT_VERSION_CHECK macro can be used to do condition compilation * in TelepathyQt-based applications and libraries. * * \code * #if (TP_QT_VERSION >= TP_QT_VERSION_CHECK(0, 9, 6)) * Tp::BaseConnectionAvatarsInterfacePtr avatarsIface; * #endif * \endcode */ #define TP_QT_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) #ifdef BUILDING_TP_QT # define TP_QT_EXPORT Q_DECL_EXPORT #else # define TP_QT_EXPORT Q_DECL_IMPORT #endif #if !defined(Q_OS_WIN) && defined(QT_VISIBILITY_AVAILABLE) # define TP_QT_NO_EXPORT __attribute__((visibility("hidden"))) #endif #ifndef TP_QT_NO_EXPORT # define TP_QT_NO_EXPORT #endif /** * @def TP_QT_DEPRECATED * @ingroup macros * * The TP_QT_DEPRECATED macro can be used to trigger compile-time * warnings with newer compilers when deprecated functions are used. * * For non-inline functions, the macro gets inserted at front of the * function declaration, right before the return type: * * \code * TP_QT_DEPRECATED void deprecatedFunctionA(); * TP_QT_DEPRECATED int deprecatedFunctionB() const; * \endcode * * For functions which are implemented inline, * the TP_QT_DEPRECATED macro is inserted at the front, right before the * return type, but after "static", "inline" or "virtual": * * \code * TP_QT_DEPRECATED void deprecatedInlineFunctionA() { .. } * virtual TP_QT_DEPRECATED int deprecatedInlineFunctionB() { .. } * static TP_QT_DEPRECATED bool deprecatedInlineFunctionC() { .. } * inline TP_QT_DEPRECATED bool deprecatedInlineFunctionD() { .. } * \endcode * * You can also mark whole structs or classes as deprecated, by inserting the * TP_QT_DEPRECATED macro after the struct/class keyword, but before the * name of the struct/class: * * \code * class TP_QT_DEPRECATED DeprecatedClass { }; * struct TP_QT_DEPRECATED DeprecatedStruct { }; * \endcode * * \note If the class you want to deprecate is a QObject and needs to be exported, * you should use TP_QT_EXPORT_DEPRECATED instead. * * \note * It does not make much sense to use the TP_QT_DEPRECATED keyword for a * Qt signal; this is because usually get called by the class which they belong * to, and one would assume that a class author does not use deprecated methods * of his own class. The only exception to this are signals which are connected * to other signals; they get invoked from moc-generated code. In any case, * printing a warning message in either case is not useful. * For slots, it can make sense (since slots can be invoked directly) but be * aware that if the slots get triggered by a signal, they will get called from * moc code as well and thus the warnings are useless. * * \note * TP_QT_DEPRECATED cannot be used for constructors. */ #ifndef TP_QT_DEPRECATED # ifdef TP_QT_DEPRECATED_WARNINGS # ifdef BUILDING_TP_QT # define TP_QT_DEPRECATED # else # define TP_QT_DEPRECATED Q_DECL_DEPRECATED # endif # else # define TP_QT_DEPRECATED # endif #endif /** * @def TP_QT_EXPORT_DEPRECATED * @ingroup macros * * The TP_QT_EXPORT_DEPRECATED macro can be used to trigger compile-time * warnings with newer compilers when deprecated functions are used, and * export the symbol. * * This macro simply expands to TP_QT_DEPRECATED TP_QT_EXPORT, and needs * to be used only when you need to deprecate a class which is a QObject * and needs to be exported. This is because the following: * * \code * class TP_QT_DEPRECATED TP_QT_EXPORT Class : public QObject * \endcode * * Wouldn't be recognized from moc to be a valid QObject class, and hence * would be skipped. Instead, you should do: * * \code * class TP_QT_EXPORT_DEPRECATED Class : public QObject * \endcode * * For any other use, please use TP_QT_DEPRECATED instead. */ #ifndef TP_QT_EXPORT_DEPRECATED # define TP_QT_EXPORT_DEPRECATED TP_QT_DEPRECATED TP_QT_EXPORT #endif #endif telepathy-qt-0.9.6~git1/TelepathyQt/CallContentMediaDescriptionInterfaceRTCPExtendedReportsInterface0000664000175000017500000000055412470405660031710 0ustar jrjr#ifndef _TelepathyQt_CallContentMediaDescriptionInterfaceRTCPExtendedReportsInterface_HEADER_GUARD_ #define _TelepathyQt_CallContentMediaDescriptionInterfaceRTCPExtendedReportsInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/future-interfaces.xml0000664000175000017500000000062712470405660021376 0ustar jrjr Extensions from the future telepathy-qt-0.9.6~git1/TelepathyQt/not-filter.dox0000664000175000017500000000233412470405660020015 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \class Tp::NotFilter * \ingroup utils * \headerfile TelepathyQt/not-filter.h * * \brief The NotFilter class provides a generic filter object to be used * in conjunction of other filters. * * The NotFilter will match if its given filter does not match its criteria. */ telepathy-qt-0.9.6~git1/TelepathyQt/tube-channel.h0000664000175000017500000000401512470405660017732 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_tube_channel_h_HEADER_GUARD_ #define _TelepathyQt_tube_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class TP_QT_EXPORT TubeChannel : public Channel { Q_OBJECT Q_DISABLE_COPY(TubeChannel) public: static const Feature FeatureCore; static TubeChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~TubeChannel(); TubeChannelState state() const; QVariantMap parameters() const; Q_SIGNALS: void stateChanged(Tp::TubeChannelState state); protected: TubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = TubeChannel::FeatureCore); void setParameters(const QVariantMap ¶meters); private Q_SLOTS: TP_QT_NO_EXPORT void onTubeChannelStateChanged(uint newstate); TP_QT_NO_EXPORT void gotTubeProperties(Tp::PendingOperation *op); private: struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/stream-tube-server-internal.h0000664000175000017500000000355712470405660022745 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include namespace Tp { class TP_QT_NO_EXPORT StreamTubeServer::TubeWrapper : public QObject { Q_OBJECT Q_DISABLE_COPY(TubeWrapper) public: TubeWrapper(const AccountPtr &acc, const OutgoingStreamTubeChannelPtr &tube, const QHostAddress &exportedAddr, quint16 exportedPort, const QVariantMap ¶ms, StreamTubeServer *parent); ~TubeWrapper() { } AccountPtr mAcc; OutgoingStreamTubeChannelPtr mTube; Q_SIGNALS: void offerFinished(TubeWrapper *wrapper, Tp::PendingOperation *op); void newConnection(TubeWrapper *wrapper, uint conn); void connectionClosed(TubeWrapper *wrapper, uint conn, const QString &error, const QString &message); private Q_SLOTS: void onTubeOffered(Tp::PendingOperation *); void onNewConnection(uint); void onConnectionClosed(uint, const QString &, const QString &); }; } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/Account0000664000175000017500000000034312470405660016533 0ustar jrjr#ifndef _TelepathyQt_Account_HEADER_GUARD_ #define _TelepathyQt_Account_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/base-connection-manager.h0000664000175000017500000000656412470405660022057 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_base_connection_manager_h_HEADER_GUARD_ #define _TelepathyQt_base_connection_manager_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include class QString; namespace Tp { class TP_QT_EXPORT BaseConnectionManager : public DBusService { Q_OBJECT Q_DISABLE_COPY(BaseConnectionManager) public: static BaseConnectionManagerPtr create(const QString &name) { return BaseConnectionManagerPtr(new BaseConnectionManager( QDBusConnection::sessionBus(), name)); } template static SharedPtr create(const QString &name) { return SharedPtr(new BaseConnectionManagerSubclass( QDBusConnection::sessionBus(), name)); } static BaseConnectionManagerPtr create(const QDBusConnection &dbusConnection, const QString &name) { return BaseConnectionManagerPtr(new BaseConnectionManager(dbusConnection, name)); } template static SharedPtr create(const QDBusConnection &dbusConnection, const QString &name) { return SharedPtr(new BaseConnectionManagerSubclass( dbusConnection, name)); } virtual ~BaseConnectionManager(); QString name() const; QVariantMap immutableProperties() const; QList protocols() const; BaseProtocolPtr protocol(const QString &protocolName) const; bool hasProtocol(const QString &protocolName) const; bool addProtocol(const BaseProtocolPtr &protocol); bool registerObject(DBusError *error = NULL); QList connections() const; Q_SIGNALS: void newConnection(const BaseConnectionPtr &connection); protected: BaseConnectionManager(const QDBusConnection &dbusConnection, const QString &name); virtual bool registerObject(const QString &busName, const QString &objectPath, DBusError *error); private Q_SLOTS: TP_QT_NO_EXPORT void removeConnection(); private: TP_QT_NO_EXPORT void addConnection(const BaseConnectionPtr &connection); class Adaptee; friend class Adaptee; class Private; friend class Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/tube-channel.cpp0000664000175000017500000001767112470405660020301 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/tube-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include namespace Tp { struct TP_QT_NO_EXPORT TubeChannel::Private { Private(TubeChannel *parent); static void introspectTube(TubeChannel::Private *self); void extractTubeProperties(const QVariantMap &props); // Public object TubeChannel *parent; ReadinessHelper *readinessHelper; // Introspection TubeChannelState state; QVariantMap parameters; }; TubeChannel::Private::Private(TubeChannel *parent) : parent(parent), readinessHelper(parent->readinessHelper()), state((TubeChannelState) -1) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableTube( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList() << TP_QT_IFACE_CHANNEL_INTERFACE_TUBE, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &TubeChannel::Private::introspectTube, this); introspectables[TubeChannel::FeatureCore] = introspectableTube; readinessHelper->addIntrospectables(introspectables); } void TubeChannel::Private::introspectTube(TubeChannel::Private *self) { TubeChannel *parent = self->parent; debug() << "Introspecting tube properties"; Client::ChannelInterfaceTubeInterface *tubeInterface = parent->interface(); parent->connect(tubeInterface, SIGNAL(TubeChannelStateChanged(uint)), SLOT(onTubeChannelStateChanged(uint))); PendingVariantMap *pvm = tubeInterface->requestAllProperties(); parent->connect(pvm, SIGNAL(finished(Tp::PendingOperation *)), SLOT(gotTubeProperties(Tp::PendingOperation *))); } void TubeChannel::Private::extractTubeProperties(const QVariantMap &props) { state = (Tp::TubeChannelState) qdbus_cast(props[QLatin1String("State")]); parameters = qdbus_cast(props[QLatin1String("Parameters")]); } /** * \class TubeChannel * \ingroup clientchannel * \headerfile TelepathyQt/tube-channel.h * * \brief The TubeChannel class is a base class for all tube types. * * A tube is a mechanism for arbitrary data transfer between two or more IM users, * used to allow applications on the users' systems to communicate without having * to establish network connections themselves. * * Note that TubeChannel should never be instantiated directly, instead one of its * subclasses (e.g. IncomingStreamTubeChannel or OutgoingStreamTubeChannel) should be used. * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * TubeChannel object usable. * * Note that this feature must be enabled in order to use most * TubeChannel methods. * See specific methods documentation for more details. */ const Feature TubeChannel::FeatureCore = Feature(QLatin1String(TubeChannel::staticMetaObject.className()), 0); /** * Create a new TubeChannel channel. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A TubeChannelPtr object pointing to the newly created * TubeChannel object. */ TubeChannelPtr TubeChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return TubeChannelPtr(new TubeChannel(connection, objectPath, immutableProperties)); } /** * Construct a new TubeChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on TubeChannel::FeatureCore. */ TubeChannel::TubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : Channel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ TubeChannel::~TubeChannel() { delete mPriv; } /** * Return the parameters associated with this tube, if any. * * The parameters are populated when an outgoing tube is offered, but they are most useful in the * receiving end, where the parameters passed to the offer can be extracted for the tube's entire * lifetime to bootstrap legacy protocols. All parameters are passed unchanged. * * This method requires TubeChannel::FeatureCore to be ready. * * \return The parameters as QVariantMap. */ QVariantMap TubeChannel::parameters() const { if (!isReady(FeatureCore)) { warning() << "TubeChannel::parameters() used with FeatureCore not ready"; return QVariantMap(); } return mPriv->parameters; } /** * Return the state of this tube. * * Change notification is via the stateChanged() signal. * * This method requires TubeChannel::FeatureCore to be ready. * * \return The state as #TubeChannelState. * \sa stateChanged() */ TubeChannelState TubeChannel::state() const { if (!isReady(FeatureCore)) { warning() << "TubeChannel::state() used with FeatureCore not ready"; return TubeChannelStateNotOffered; } return mPriv->state; } void TubeChannel::setParameters(const QVariantMap ¶meters) { mPriv->parameters = parameters; } void TubeChannel::onTubeChannelStateChanged(uint newState) { if (newState == mPriv->state) { return; } uint oldState = mPriv->state; debug() << "Tube state changed to" << newState; mPriv->state = (Tp::TubeChannelState) newState; /* only emit stateChanged if we already received the state from initial introspection */ if (oldState != (uint) -1) { emit stateChanged((Tp::TubeChannelState) newState); } } void TubeChannel::gotTubeProperties(PendingOperation *op) { if (!op->isError()) { PendingVariantMap *pvm = qobject_cast(op); mPriv->extractTubeProperties(pvm->result()); debug() << "Got reply to Properties::GetAll(TubeChannel)"; mPriv->readinessHelper->setIntrospectCompleted(TubeChannel::FeatureCore, true); } else { warning().nospace() << "Properties::GetAll(TubeChannel) failed " "with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(TubeChannel::FeatureCore, false, op->errorName(), op->errorMessage()); } } /** * \fn void TubeChannel::stateChanged(Tp::TubeChannelState state) * * Emitted when the value of state() changes. * * \sa state The new state of this tube. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelClassFeatures0000664000175000017500000000041412470405660021173 0ustar jrjr#ifndef _TelepathyQt_ChannelClassFeatures_HEADER_GUARD_ #define _TelepathyQt_ChannelClassFeatures_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/protocol-info.cpp0000664000175000017500000003455212470405660020523 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ProtocolInfo::Private : public QSharedData { Private() : dbusConnection(QDBusConnection::sessionBus()), // make the compiler happy addressingIface(0) { } Private(const ConnectionManagerPtr &cm, const QString &name) : dbusConnection(cm->dbusConnection()), busName(cm->busName()), cmName(cm->name()), name(name), iconName(QString(QLatin1String("im-%1")).arg(name)), addressingIface(0) { QString escapedProtocolName = name; escapedProtocolName.replace(QLatin1Char('-'), QLatin1Char('_')); objectPath = QString(QLatin1String("%1/%2")).arg(cm->objectPath()).arg(escapedProtocolName); } ~Private() { delete addressingIface; } Client::ProtocolInterfaceAddressingInterface *addressingInterface() { if (!addressingIface) { addressingIface = new Client::ProtocolInterfaceAddressingInterface( dbusConnection, busName, objectPath); } return addressingIface; } QDBusConnection dbusConnection; QString busName; QString objectPath; QString cmName; QString name; ProtocolParameterList params; ConnectionCapabilities caps; QString vcardField; QString englishName; QString iconName; PresenceSpecList statuses; AvatarSpec avatarRequirements; QStringList addressableVCardFields; QStringList addressableUriSchemes; Client::ProtocolInterfaceAddressingInterface *addressingIface; }; /** * \class ProtocolInfo * \ingroup clientcm * \headerfile TelepathyQt/protocol-info.h * * \brief The ProtocolInfo class represents a Telepathy Protocol. */ ProtocolInfo::ProtocolInfo() { } /** * Construct a new ProtocolInfo object. * * \param cm Connection manager owning this ProtocolInfo. * \param name Protocol name. */ ProtocolInfo::ProtocolInfo(const ConnectionManagerPtr &cm, const QString &name) : mPriv(new Private(cm, name)) { } ProtocolInfo::ProtocolInfo(const ProtocolInfo &other) : mPriv(other.mPriv) { } /** * Class destructor. */ ProtocolInfo::~ProtocolInfo() { } ProtocolInfo &ProtocolInfo::operator=(const ProtocolInfo &other) { this->mPriv = other.mPriv; return *this; } /** * Return the short name of the connection manager (e.g. "gabble") for this protocol. * * \return The name of the connection manager for this protocol. */ QString ProtocolInfo::cmName() const { if (!isValid()) { return QString(); } return mPriv->cmName; } /** * Return the string identifying this protocol as described in the \telepathy_spec * (e.g. "jabber"). * * This identifier is not intended to be displayed to users directly; user * interfaces are responsible for mapping them to localized strings. * * \return A string identifying this protocol. */ QString ProtocolInfo::name() const { if (!isValid()) { return QString(); } return mPriv->name; } /** * Return all supported parameters for this protocol. The parameters' names * may either be the well-known strings specified by the \telepathy_spec * (e.g. "account" and "password"), or implementation-specific strings. * * \return A list of parameters for this protocol. */ ProtocolParameterList ProtocolInfo::parameters() const { if (!isValid()) { return ProtocolParameterList(); } return mPriv->params; } /** * Return whether a given parameter can be passed to the connection * manager when creating a connection to this protocol. * * \param name The name of a parameter. * \return true if the given parameter exists. */ bool ProtocolInfo::hasParameter(const QString &name) const { if (!isValid()) { return false; } foreach (const ProtocolParameter ¶m, mPriv->params) { if (param.name() == name) { return true; } } return false; } /** * Return whether it might be possible to register new accounts on this * protocol, by setting the special parameter named * register to true. * * \return The same thing as hasParameter("register"). * \sa hasParameter() */ bool ProtocolInfo::canRegister() const { if (!isValid()) { return false; } return hasParameter(QLatin1String("register")); } /** * Return the capabilities that are expected to be available from a connection * to this protocol, i.e. those for which Connection::createChannel() can * reasonably be expected to succeed. * User interfaces can use this information to show or hide UI components. * * @return An object representing the capabilities expected to be available from * a connection to this protocol. */ ConnectionCapabilities ProtocolInfo::capabilities() const { if (!isValid()) { return ConnectionCapabilities(); } return mPriv->caps; } /** * Return the name of the most common vcard field used for this protocol's * contact identifiers, normalized to lower case. * * One valid use of this field is to answer the question: given a contact's * vcard containing an X-JABBER field, how can you communicate with the contact? * By iterating through protocols looking for an x-jabber VCardField, one can * build up a list of protocols that handle x-jabber, then offer the user a list * of accounts for those protocols and/or the option to create a new account for * one of those protocols. * It is not necessarily valid to interpret contacts' identifiers as values of * this vcard field. For instance, telepathy-sofiasip supports contacts whose * identifiers are of the form sip:jenny@example.com or tel:8675309, which would * not normally both be represented by any single vcard field. * * \return The most common vcard field used for this protocol's contact * identifiers, or an empty string if there is no such field. */ QString ProtocolInfo::vcardField() const { if (!isValid()) { return QString(); } return mPriv->vcardField; } /** * Return the English-language name of this protocol, such as "AIM" or "Yahoo!". * * The name can be used as a fallback if an application doesn't have a localized name for this * protocol. * * If the manager file or the CM service doesn't specify the english name, it is inferred from this * protocol name, such that for example "google-talk" becomes "Google Talk", but "local-xmpp" * becomes "Local Xmpp". * * \return An English-language name for this protocol. */ QString ProtocolInfo::englishName() const { if (!isValid()) { return QString(); } return mPriv->englishName; } /** * Return the name of an icon for this protocol in the system's icon theme, such as "im-msn". * * If the manager file or the CM service doesn't specify the icon name, "im-" is * assumed. * * \return The likely name of an icon for this protocol. */ QString ProtocolInfo::iconName() const { if (!isValid()) { return QString(); } return mPriv->iconName; } /** * Return a list of PresenceSpec representing the possible presence statuses * from a connection to this protocol. * * \return A list of PresenceSpec representing the possible presence statuses * from a connection to this protocol. */ PresenceSpecList ProtocolInfo::allowedPresenceStatuses() const { if (!isValid()) { return PresenceSpecList(); } return mPriv->statuses; } /** * Return the requirements (size limits, supported MIME types, etc) * for avatars used on to this protocol. * * \return The requirements for avatars used on this protocol. */ AvatarSpec ProtocolInfo::avatarRequirements() const { if (!isValid()) { return AvatarSpec(); } return mPriv->avatarRequirements; } /** * Return the vcard fields that can be used to request a contact with on this protocol, * normalized to lower case. * * \return The vcard fields normalized to lower case. * \sa addressableUriSchemes() */ QStringList ProtocolInfo::addressableVCardFields() const { if (!isValid()) { return QStringList(); } return mPriv->addressableVCardFields; } /** * Return the URI schemes that are supported by this protocol. * * \return The URI schemes. * \sa addressableVCardFields() */ QStringList ProtocolInfo::addressableUriSchemes() const { if (!isValid()) { return QStringList(); } return mPriv->addressableUriSchemes; } /** * Attempt to normalize the given \a vcardAddress. * * For example, a vcard TEL field formatted as +1 (206) 555 1234, * could be normalized to +12065551234. * * If a vcard address X would be normalized to Y, a successful ContactManager * contact request using ContactManager::contactsForVCardAddresses() for * vcard address X would result in a contact with Y reported as an * address that can identify it in Contact::vcardAddresses(). * * \param vcardField The vcard field the \a vcardAddress belongs to. * \param vcardAddress The address to normalize. * \return A PendingString which will emit PendingString::finished * when the address has been normalized or an error occurred. * \sa normalizeContactUri() */ PendingString *ProtocolInfo::normalizeVCardAddress(const QString &vcardField, const QString &vcardAddress) { if (!isValid()) { return new PendingString(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Protocol object is invalid")); } Client::ProtocolInterfaceAddressingInterface *iface = mPriv->addressingInterface(); if (!iface->isValid()) { // cm is still valid but no Protocol object found return new PendingString(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("ConnectionManager does not support Protocol.I.Addressing")); } return new PendingString(iface->NormalizeVCardAddress(vcardField, vcardAddress), SharedPtr()); } /** * Attempt to normalize the given contact \a uri. * * If the URI has extra information beyond what's necessary to identify a particular contact, such * as an XMPP resource or an action to carry out, this extra information wil be removed. * * An example would be xmpp:romeo@Example.Com/Empathy?message;body=Hello, which would be normalized * to xmpp:romeo@example.com. * * If a URI address X would be normalized to Y, a successful ContactManager * contact request using ContactManager::contactsForUris() for * URI address X would result in a contact with Y reported as an * address that can identify it in Contact::uris(). * * \param uri The URI to normalize. * \return A PendingString which will emit PendingString::finished * when the \a uri has been normalized or an error occurred. * \sa normalizeVCardAddress() */ PendingString *ProtocolInfo::normalizeContactUri(const QString &uri) { if (!isValid()) { return new PendingString(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Protocol object is invalid")); } Client::ProtocolInterfaceAddressingInterface *iface = mPriv->addressingInterface(); if (!iface->isValid()) { // cm is still valid but no Protocol object found return new PendingString(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("ConnectionManager does not support Protocol.I.Addressing")); } return new PendingString(iface->NormalizeContactURI(uri), SharedPtr()); } void ProtocolInfo::addParameter(const ParamSpec &spec) { if (!isValid()) { mPriv = new Private; } QVariant defaultValue; if (spec.flags & ConnMgrParamFlagHasDefault) { defaultValue = spec.defaultValue.variant(); } uint flags = spec.flags; if (spec.name.endsWith(QLatin1String("password"))) { flags |= ConnMgrParamFlagSecret; } ProtocolParameter param(spec.name, QDBusSignature(spec.signature), (ConnMgrParamFlag) flags, defaultValue); mPriv->params.append(param); } void ProtocolInfo::setVCardField(const QString &vcardField) { if (!isValid()) { mPriv = new Private; } mPriv->vcardField = vcardField; } void ProtocolInfo::setEnglishName(const QString &englishName) { if (!isValid()) { mPriv = new Private; } mPriv->englishName = englishName; } void ProtocolInfo::setIconName(const QString &iconName) { if (!isValid()) { mPriv = new Private; } mPriv->iconName = iconName; } void ProtocolInfo::setRequestableChannelClasses( const RequestableChannelClassList &caps) { if (!isValid()) { mPriv = new Private; } mPriv->caps.updateRequestableChannelClasses(caps); } void ProtocolInfo::setAllowedPresenceStatuses(const PresenceSpecList &statuses) { if (!isValid()) { mPriv = new Private; } mPriv->statuses = statuses; } void ProtocolInfo::setAvatarRequirements(const AvatarSpec &avatarRequirements) { if (!isValid()) { mPriv = new Private; } mPriv->avatarRequirements = avatarRequirements; } void ProtocolInfo::setAddressableVCardFields(const QStringList &vcardFields) { if (!isValid()) { mPriv = new Private; } mPriv->addressableVCardFields = vcardFields; } void ProtocolInfo::setAddressableUriSchemes(const QStringList &uriSchemes) { if (!isValid()) { mPriv = new Private; } mPriv->addressableUriSchemes = uriSchemes; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceAddressingInterface0000664000175000017500000000044412470405660024706 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceAddressingInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceAddressingInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceChatStateInterface0000664000175000017500000000043112470405660023750 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceChatStateInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceChatStateInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/FileTransferChannelCreationProperties0000664000175000017500000000050112470405660024552 0ustar jrjr#ifndef _TelepathyQt_FileTransferChannelCreationProperties_HEADER_GUARD_ #define _TelepathyQt_FileTransferChannelCreationProperties_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/not-filter.h0000664000175000017500000000371512470405660017456 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_not_filter_h_HEADER_GUARD_ #define _TelepathyQt_not_filter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { template class NotFilter : public Filter { public: static SharedPtr > create( const SharedPtr > &filter = SharedPtr >()) { return SharedPtr >(new NotFilter(filter)); } inline virtual ~NotFilter() { } inline virtual bool isValid() const { return mFilter && mFilter->isValid(); } inline virtual bool matches(const SharedPtr &t) const { if (!isValid()) { return false; } return !mFilter->matches(t); } inline SharedPtr > filter() const { return mFilter; } private: NotFilter(const SharedPtr > &filter) : Filter(), mFilter(filter) { } SharedPtr > mFilter; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/PropertiesInterface0000664000175000017500000000037012470405660021114 0ustar jrjr#ifndef _TelepathyQt_PropertiesInterface_HEADER_GUARD_ #define _TelepathyQt_PropertiesInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ProfileManager0000664000175000017500000000037112470405660020033 0ustar jrjr#ifndef _TelepathyQt_ProfileManager_HEADER_GUARD_ #define _TelepathyQt_ProfileManager_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ready-object.cpp0000664000175000017500000001076112470405660020275 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/debug-internal.h" #include #include namespace Tp { struct TP_QT_NO_EXPORT ReadyObject::Private { Private(ReadyObject *parent, RefCounted *object, Feature featureCore); Private(ReadyObject *parent, DBusProxy *proxy, Feature featureCore); ~Private(); ReadyObject *parent; const Features coreFeatures; ReadinessHelper *readinessHelper; }; ReadyObject::Private::Private(ReadyObject *parent, RefCounted *object, Feature featureCore) : parent(parent), coreFeatures(Features() << featureCore), readinessHelper(new ReadinessHelper(object)) { } ReadyObject::Private::Private(ReadyObject *parent, DBusProxy *proxy, Feature featureCore) : parent(parent), coreFeatures(Features() << featureCore), readinessHelper(new ReadinessHelper(proxy)) { } ReadyObject::Private::~Private() { delete readinessHelper; } /** * \class ReadyObject * \ingroup clientreadiness * \headerfile TelepathyQt/ready-object.h> */ /** * Construct a new ReadyObject object. * * \param object The RefCounted the object refers to. * \param featureCore The core feature of the object. */ ReadyObject::ReadyObject(RefCounted *object, const Feature &featureCore) : mPriv(new Private(this, object, featureCore)) { } /** * Construct a new ReadyObject object. * * \param proxy The DBusProxy the object refers to. * \param featureCore The core feature of the object. */ ReadyObject::ReadyObject(DBusProxy *proxy, const Feature &featureCore) : mPriv(new Private(this, proxy, featureCore)) { } /** * Class destructor. */ ReadyObject::~ReadyObject() { delete mPriv; } /** * Return whether this object has finished its initial setup. * * This is mostly useful as a sanity check, in code that shouldn't be run * until the object is ready. To wait for the object to be ready, call * becomeReady() and connect to the finished signal on the result. * * \param features The features which should be tested * \return \c true if the object has finished its initial setup for basic * functionality plus the given features */ bool ReadyObject::isReady(const Features &features) const { if (features.isEmpty()) { return mPriv->readinessHelper->isReady(mPriv->coreFeatures); } return mPriv->readinessHelper->isReady(features); } /** * Return a pending operation which will succeed when this object finishes * its initial setup, or will fail if a fatal error occurs during this * initial setup. * * If an empty set is used FeatureCore will be considered as the requested * feature. * * \param requestedFeatures The features which should be enabled * \return A PendingReady object which will emit finished * when this object has finished or failed initial setup for basic * functionality plus the given features */ PendingReady *ReadyObject::becomeReady(const Features &requestedFeatures) { if (requestedFeatures.isEmpty()) { return mPriv->readinessHelper->becomeReady(mPriv->coreFeatures); } return mPriv->readinessHelper->becomeReady(requestedFeatures); } Features ReadyObject::requestedFeatures() const { return mPriv->readinessHelper->requestedFeatures(); } Features ReadyObject::actualFeatures() const { return mPriv->readinessHelper->actualFeatures(); } Features ReadyObject::missingFeatures() const { return mPriv->readinessHelper->missingFeatures(); } ReadinessHelper *ReadyObject::readinessHelper() const { return mPriv->readinessHelper; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/pending-captchas.cpp0000664000175000017500000003232012470405660021130 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/_gen/pending-captchas.moc.hpp" #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingCaptchas::Private { Private(PendingCaptchas *parent); ~Private(); CaptchaAuthentication::ChallengeType stringToChallengeType(const QString &string) const; void appendCaptchaResult(const QString &mimeType, const QString &label, const QByteArray &data, CaptchaAuthentication::ChallengeType type, uint id); // Public object PendingCaptchas *parent; CaptchaAuthentication::ChallengeTypes preferredTypes; QStringList preferredMimeTypes; bool multipleRequired; QList captchas; int captchasLeft; CaptchaAuthenticationPtr captchaAuthentication; ChannelPtr channel; }; PendingCaptchas::Private::Private(PendingCaptchas *parent) : parent(parent) { } PendingCaptchas::Private::~Private() { } CaptchaAuthentication::ChallengeType PendingCaptchas::Private::stringToChallengeType(const QString &string) const { if (string == QLatin1String("audio_recog")) { return CaptchaAuthentication::AudioRecognitionChallenge; } else if (string == QLatin1String("ocr")) { return CaptchaAuthentication::OCRChallenge; } else if (string == QLatin1String("picture_q")) { return CaptchaAuthentication::PictureQuestionChallenge; } else if (string == QLatin1String("picture_recog")) { return CaptchaAuthentication::PictureRecognitionChallenge; } else if (string == QLatin1String("qa")) { return CaptchaAuthentication::TextQuestionChallenge; } else if (string == QLatin1String("speech_q")) { return CaptchaAuthentication::SpeechQuestionChallenge; } else if (string == QLatin1String("speech_recog")) { return CaptchaAuthentication::SpeechRecognitionChallenge; } else if (string == QLatin1String("video_q")) { return CaptchaAuthentication::VideoQuestionChallenge; } else if (string == QLatin1String("video_recog")) { return CaptchaAuthentication::VideoRecognitionChallenge; } // Not really making sense... return CaptchaAuthentication::UnknownChallenge; } void PendingCaptchas::Private::appendCaptchaResult(const QString &mimeType, const QString &label, const QByteArray &data, CaptchaAuthentication::ChallengeType type, uint id) { // Add to the list Captcha captchaItem(mimeType, label, data, type, id); captchas.append(captchaItem); --captchasLeft; if (!captchasLeft) { parent->setFinished(); } } /** * \class PendingCaptchas * \ingroup client * \headerfile TelepathyQt/pending-captchas.h * * \brief The PendingCaptchas class represents an asynchronous * operation for retrieving a captcha challenge from a connection manager. * * See \ref async_model */ PendingCaptchas::PendingCaptchas( const QDBusPendingCall &call, const QStringList &preferredMimeTypes, CaptchaAuthentication::ChallengeTypes preferredTypes, const CaptchaAuthenticationPtr &captchaAuthentication) : PendingOperation(captchaAuthentication), mPriv(new Private(this)) { mPriv->captchaAuthentication = captchaAuthentication; mPriv->channel = captchaAuthentication->channel(); mPriv->preferredMimeTypes = preferredMimeTypes; mPriv->preferredTypes = preferredTypes; /* keep track of channel invalidation */ connect(mPriv->channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString))); connect(new QDBusPendingCallWatcher(call), SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onGetCaptchasWatcherFinished(QDBusPendingCallWatcher*))); } PendingCaptchas::PendingCaptchas( const QString& errorName, const QString& errorMessage, const CaptchaAuthenticationPtr &captchaAuthentication) : PendingOperation(captchaAuthentication), mPriv(new PendingCaptchas::Private(this)) { warning() << "PendingCaptchas created with instant failure"; setFinishedWithError(errorName, errorMessage); } /** * Class destructor. */ PendingCaptchas::~PendingCaptchas() { delete mPriv; } void PendingCaptchas::onChannelInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { Q_UNUSED(proxy); if (isFinished()) { return; } warning().nospace() << "PendingCaptchas failed because channel was invalidated with " << errorName << ": " << errorMessage; setFinishedWithError(errorName, errorMessage); } void PendingCaptchas::onGetCaptchasWatcherFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { debug().nospace() << "PendingDBusCall failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); watcher->deleteLater(); return; } debug() << "Got reply to PendingDBusCall"; Tp::CaptchaInfoList list = qdbus_cast(reply.argumentAt(0)); int howManyRequired = reply.argumentAt(1).toUInt(); // Compute which captchas are required QList > finalList; foreach (const Tp::CaptchaInfo &info, list) { // First of all, mimetype check QString mimeType; if (info.availableMIMETypes.isEmpty()) { // If it's one of the types which might not have a payload, go for it CaptchaAuthentication::ChallengeTypes noPayloadChallenges( CaptchaAuthentication::TextQuestionChallenge | CaptchaAuthentication::UnknownChallenge); if (mPriv->stringToChallengeType(info.type) & noPayloadChallenges) { // Ok, move on } else { // In this case, there's something wrong warning() << "Got a captcha with type " << info.type << " which does not " "expose any available mimetype for its payload. Something might be " "wrong with the connection manager."; continue; } } else if (mPriv->preferredMimeTypes.isEmpty()) { // No preference, let's take the first of the list mimeType = info.availableMIMETypes.first(); } else { QSet supportedMimeTypes = info.availableMIMETypes.toSet().intersect( mPriv->preferredMimeTypes.toSet()); if (supportedMimeTypes.isEmpty()) { // Apparently our handler does not support any of this captcha's mimetypes, skip continue; } // Ok, use the first one mimeType = *supportedMimeTypes.constBegin(); } // If it's required, easy if (info.flags & CaptchaFlagRequired) { finalList.append(qMakePair(info, mimeType)); continue; } // Otherwise, let's see if the mimetype matches if (mPriv->preferredTypes & mPriv->stringToChallengeType(info.type)) { finalList.append(qMakePair(info, mimeType)); } if (finalList.size() == howManyRequired) { break; } } if (finalList.size() != howManyRequired) { warning() << "No captchas available matching the specified preferences"; setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("No captchas matching the handler's request")); return; } // Now, get the infos for all the required captchas in our final list. mPriv->captchasLeft = finalList.size(); mPriv->multipleRequired = howManyRequired > 1 ? true : false; for (QList >::const_iterator i = finalList.constBegin(); i != finalList.constEnd(); ++i) { QString mimeType = (*i).second; Tp::CaptchaInfo captchaInfo = (*i).first; // If the captcha does not have a mimetype, we can add it straight if (mimeType.isEmpty()) { mPriv->appendCaptchaResult(mimeType, captchaInfo.label, QByteArray(), mPriv->stringToChallengeType(captchaInfo.type), captchaInfo.ID); continue; } QDBusPendingCall call = mPriv->channel->interface()->GetCaptchaData( captchaInfo.ID, mimeType); QDBusPendingCallWatcher *dataWatcher = new QDBusPendingCallWatcher(call); dataWatcher->setProperty("__Tp_Qt_CaptchaID", captchaInfo.ID); dataWatcher->setProperty("__Tp_Qt_CaptchaMimeType", mimeType); dataWatcher->setProperty("__Tp_Qt_CaptchaLabel", captchaInfo.label); dataWatcher->setProperty("__Tp_Qt_CaptchaType", mPriv->stringToChallengeType(captchaInfo.type)); connect(dataWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onGetCaptchaDataWatcherFinished(QDBusPendingCallWatcher*))); } watcher->deleteLater(); } void PendingCaptchas::onGetCaptchaDataWatcherFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { debug().nospace() << "PendingDBusCall failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); watcher->deleteLater(); return; } debug() << "Got reply to PendingDBusCall"; // Add to the list mPriv->appendCaptchaResult(watcher->property("__Tp_Qt_CaptchaMimeType").toString(), watcher->property("__Tp_Qt_CaptchaLabel").toString(), reply.value(), static_cast( watcher->property("__Tp_Qt_CaptchaType").toUInt()), watcher->property("__Tp_Qt_CaptchaID").toUInt()); watcher->deleteLater(); } /** * Return the main captcha of the request. This captcha is guaranteed to be compatible * with any constraint specified in CaptchaAuthentication::requestCaptchas(). * * This is a convenience method which should be used when requiresMultipleCaptchas() * is false - otherwise, you should use captchaList. * * The returned Captcha can be answered through CaptchaAuthentication::answer() by * using its id. * * This method will return a meaningful value only if the operation was completed * successfully. * * \return The main captcha for the pending request. * \sa captchaList() * CaptchaAuthentication::requestCaptchas() * requiresMultipleCaptchas() * CaptchaAuthentication::answer() */ Captcha PendingCaptchas::captcha() const { if (!isFinished()) { return Captcha(); } return mPriv->captchas.first(); } /** * Return all the captchas of the request. These captchas are guaranteed to be compatible * with any constraint specified in CaptchaAuthentication::requestCaptchas(). * * If requiresMultipleCaptchas() is false, you probably want to use the convenience method * captcha() instead. * * The returned Captchas can be answered through CaptchaAuthentication::answer() by * using their ids. * * This method will return a meaningful value only if the operation was completed * successfully. * * \return All the captchas for the pending request. * \sa captcha() * CaptchaAuthentication::requestCaptchas() * requiresMultipleCaptchas() * CaptchaAuthentication::answer() */ QList PendingCaptchas::captchaList() const { if (!isFinished()) { return QList(); } return mPriv->captchas; } /** * Return whether this request requires more than one captcha to be answered or not. * * This method should always be checked before answering to find out what the * connection manager expects. Depending on the result, you might want to use the * result from captcha() if just a single answer is required, or from captchaList() * otherwise. * * This method will return a meaningful value only if the operation was completed * successfully. * * \return The main captcha for the pending request. * \sa captcha() * captchaList() */ bool PendingCaptchas::requiresMultipleCaptchas() const { return mPriv->multipleRequired; } } telepathy-qt-0.9.6~git1/TelepathyQt/ContactManager0000664000175000017500000000037112470405660020026 0ustar jrjr#ifndef _TelepathyQt_ContactManager_HEADER_GUARD_ #define _TelepathyQt_ContactManager_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/debug.cpp0000664000175000017500000001055712470405660017016 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #define IN_TP_QT_HEADER #include "debug.h" #include "debug-internal.h" #include "config-version.h" /** * \defgroup debug Common debug support * * TelepathyQt has an internal mechanism for displaying debugging output. It * uses the Qt debugging subsystem, so if you want to redirect the messages, * use qInstallMsgHandler() from <QtGlobal>. * * Debugging output is divided into two categories: normal debug output and * warning messages. Normal debug output results in the normal operation of the * library, warning messages are output only when something goes wrong. Each * category can be invidually enabled. */ namespace Tp { /** * \fn void enableDebug(bool enable) * \ingroup debug * * Enable or disable normal debug output from the library. If the library is not * compiled with debug support enabled, this has no effect; no output is * produced in any case. * * The default is false ie. no debug output. * * \param enable Whether debug output should be enabled or not. */ /** * \fn void enableWarnings(bool enable) * \ingroup debug * * Enable or disable warning output from the library. If the library is not * compiled with debug support enabled, this has no effect; no output is * produced in any case. * * The default is true ie. warning output enabled. * * \param enable Whether warnings should be enabled or not. */ /** * \typedef DebugCallback * \ingroup debug * * \code * typedef QDebug (*DebugCallback)(const QString &libraryName, * const QString &libraryVersion, * QtMsgType type, * const QString &msg) * \endcode */ /** * \fn void setDebugCallback(DebugCallback cb) * \ingroup debug * * Set the callback method that will handle the debug output. * * If \p cb is NULL this method will set the defaultDebugCallback instead. * The default callback function will print the output using default Qt debug * system. * * \param cb A function pointer to the callback method or NULL. * \sa DebugCallback */ #ifdef ENABLE_DEBUG namespace { bool debugEnabled = false; bool warningsEnabled = true; DebugCallback debugCallback = NULL; } void enableDebug(bool enable) { debugEnabled = enable; } void enableWarnings(bool enable) { warningsEnabled = enable; } void setDebugCallback(DebugCallback cb) { debugCallback = cb; } Debug enabledDebug() { if (debugEnabled) { return Debug(QtDebugMsg); } else { return Debug(); } } Debug enabledWarning() { if (warningsEnabled) { return Debug(QtWarningMsg); } else { return Debug(); } } void Debug::invokeDebugCallback() { if (debugCallback) { debugCallback(QLatin1String("tp-qt"), QLatin1String(PACKAGE_VERSION), type, msg); } else { switch (type) { case QtDebugMsg: qDebug() << "tp-qt " PACKAGE_VERSION " DEBUG:" << qPrintable(msg); break; case QtWarningMsg: qWarning() << "tp-qt " PACKAGE_VERSION " WARN:" << qPrintable(msg); break; default: break; } } } #else /* !defined(ENABLE_DEBUG) */ void enableDebug(bool enable) { } void enableWarnings(bool enable) { } void setDebugCallback(DebugCallback cb) { } Debug enabledDebug() { return Debug(); } Debug enabledWarning() { return Debug(); } void Debug::invokeDebugCallback() { } #endif /* !defined(ENABLE_DEBUG) */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/referenced-handles.h0000664000175000017500000001303712470405660021107 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_referenced_handles_h_HEADER_GUARD_ #define _TelepathyQt_referenced_handles_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #ifndef QT_NO_STL # include #endif #include #include #include #include namespace Tp { class Connection; class TP_QT_EXPORT ReferencedHandles { public: typedef UIntList::const_iterator const_iterator; typedef UIntList::ConstIterator ConstIterator; typedef UIntList::const_pointer const_pointer; typedef UIntList::const_reference const_reference; typedef UIntList::difference_type difference_type; typedef UIntList::pointer pointer; typedef UIntList::reference reference; typedef UIntList::size_type size_type; typedef UIntList::value_type value_type; ReferencedHandles(); ReferencedHandles(const ReferencedHandles &other); ~ReferencedHandles(); ConnectionPtr connection() const; HandleType handleType() const; uint at(int i) const; inline uint back() const { return last(); } inline uint first() const { return at(0); } inline uint front() const { return first(); } inline uint last() const { return at(size() - 1); } uint value(int i, uint defaultValue = 0) const; const_iterator begin() const; inline const_iterator constBegin() const { return begin(); } inline const_iterator constEnd() const { return end(); } const_iterator end() const; bool contains(uint handle) const; int count(uint handle) const; inline int count() const { return size(); } inline bool empty() const { return isEmpty(); } inline bool endsWith(uint handle) const { return !isEmpty() && last() == handle; } int indexOf(uint handle, int from = 0) const; bool isEmpty() const; int lastIndexOf(uint handle, int from = -1) const; inline int length() const { return count(); } ReferencedHandles mid(int pos, int length = -1) const; int size() const; inline bool startsWith(uint handle) const { return !isEmpty() && first() == handle; } inline void append(const ReferencedHandles& another) { *this = *this + another; } void clear(); void move(int from, int to); inline void pop_back() { return removeLast(); } inline void pop_front() { return removeFirst(); } int removeAll(uint handle); void removeAt(int i); inline void removeFirst() { return removeAt(0); } inline void removeLast() { return removeAt(size() - 1); } bool removeOne(uint handle); void swap(int i, int j); uint takeAt(int i); inline uint takeFirst() { return takeAt(0); } inline uint takeLast() { return takeAt(size() - 1); } bool operator!=(const ReferencedHandles& another) const { return !(*this == another); } bool operator!=(const UIntList& another) const { return !(*this == another); } ReferencedHandles operator+(const ReferencedHandles& another) const; inline ReferencedHandles& operator+=(const ReferencedHandles& another) { return *this = (*this + another); } ReferencedHandles& operator<<(const ReferencedHandles& another) { return *this += another; } ReferencedHandles& operator=(const ReferencedHandles& another); bool operator==(const ReferencedHandles& another) const; bool operator==(const UIntList& list) const; inline uint operator[](int i) const { return at(i); } UIntList toList() const; inline QSet toSet() const { return toList().toSet(); } #ifndef QT_NO_STL inline std::list toStdList() const { return toList().toStdList(); } #endif inline QVector toVector() const { return toList().toVector(); } private: // For access to the "prime" constructor friend class ContactManager; friend class PendingContactAttributes; friend class PendingContacts; friend class PendingHandles; TP_QT_NO_EXPORT ReferencedHandles(const ConnectionPtr &connection, HandleType handleType, const UIntList& handles); struct Private; friend struct Private; QSharedDataPointer mPriv; }; typedef QListIterator ReferencedHandlesIterator; } // Tp Q_DECLARE_METATYPE(Tp::ReferencedHandles); #endif telepathy-qt-0.9.6~git1/TelepathyQt/client-registrar.cpp0000664000175000017500000011535212470405660021205 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/client-registrar-internal.h" #include "TelepathyQt/_gen/client-registrar.moc.hpp" #include "TelepathyQt/_gen/client-registrar-internal.moc.hpp" #include "TelepathyQt/channel-factory.h" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/request-temporary-handler-internal.h" #include #include #include #include #include #include #include #include #include namespace Tp { class HandleChannelsInvocationContext : public MethodInvocationContext<> { Q_DISABLE_COPY(HandleChannelsInvocationContext) public: typedef void (*FinishedCb)(const MethodInvocationContextPtr<> &context, const QList &channels, void *data); static MethodInvocationContextPtr<> create(const QDBusConnection &bus, const QDBusMessage &message, const QList &channels, FinishedCb finishedCb, void *finishedCbData) { return SharedPtr >( new HandleChannelsInvocationContext(bus, message, channels, finishedCb, finishedCbData)); } private: HandleChannelsInvocationContext(const QDBusConnection &connection, const QDBusMessage &message, const QList &channels, FinishedCb finishedCb, void *finishedCbData) : MethodInvocationContext<>(connection, message), mChannels(channels), mFinishedCb(finishedCb), mFinishedCbData(finishedCbData) { } void onFinished() { if (mFinishedCb) { mFinishedCb(MethodInvocationContextPtr<>(this), mChannels, mFinishedCbData); } } QList mChannels; FinishedCb mFinishedCb; void *mFinishedCbData; }; ClientAdaptor::ClientAdaptor(ClientRegistrar *registrar, const QStringList &interfaces, QObject *parent) : QDBusAbstractAdaptor(parent), mRegistrar(registrar), mInterfaces(interfaces) { } ClientAdaptor::~ClientAdaptor() { } ClientObserverAdaptor::ClientObserverAdaptor(ClientRegistrar *registrar, AbstractClientObserver *client, QObject *parent) : QDBusAbstractAdaptor(parent), mRegistrar(registrar), mBus(registrar->dbusConnection()), mClient(client) { } ClientObserverAdaptor::~ClientObserverAdaptor() { } void ClientObserverAdaptor::ObserveChannels(const QDBusObjectPath &accountPath, const QDBusObjectPath &connectionPath, const Tp::ChannelDetailsList &channelDetailsList, const QDBusObjectPath &dispatchOperationPath, const Tp::ObjectPathList &requestsSatisfied, const QVariantMap &observerInfo, const QDBusMessage &message) { debug() << "ObserveChannels: account:" << accountPath.path() << ", connection:" << connectionPath.path(); AccountFactoryConstPtr accFactory = mRegistrar->accountFactory(); ConnectionFactoryConstPtr connFactory = mRegistrar->connectionFactory(); ChannelFactoryConstPtr chanFactory = mRegistrar->channelFactory(); ContactFactoryConstPtr contactFactory = mRegistrar->contactFactory(); SharedPtr invocation(new InvocationData()); QList readyOps; PendingReady *accReady = accFactory->proxy(TP_QT_ACCOUNT_MANAGER_BUS_NAME, accountPath.path(), connFactory, chanFactory, contactFactory); invocation->acc = AccountPtr::qObjectCast(accReady->proxy()); readyOps.append(accReady); QString connectionBusName = connectionPath.path().mid(1).replace( QLatin1String("/"), QLatin1String(".")); PendingReady *connReady = connFactory->proxy(connectionBusName, connectionPath.path(), chanFactory, contactFactory); invocation->conn = ConnectionPtr::qObjectCast(connReady->proxy()); readyOps.append(connReady); foreach (const ChannelDetails &channelDetails, channelDetailsList) { PendingReady *chanReady = chanFactory->proxy(invocation->conn, channelDetails.channel.path(), channelDetails.properties); ChannelPtr channel = ChannelPtr::qObjectCast(chanReady->proxy()); invocation->chans.append(channel); readyOps.append(chanReady); } // Yes, we don't give the choice of making CDO and CR ready or not - however, readifying them is // 0-1 D-Bus calls each, for CR mostly 0 - and their constructors start making them ready // automatically, so we wouldn't save any D-Bus traffic anyway if (!dispatchOperationPath.path().isEmpty() && dispatchOperationPath.path() != QLatin1String("/")) { QVariantMap props; // TODO: push to tp spec having all of the CDO immutable props be contained in observerInfo // so we don't have to introspect the CDO either - then we can pretty much do: // // props = qdbus_cast( // observerInfo.value(QLatin1String("dispatch-operation-properties"))); // // Currently something like the following can be used for testing the CDO "we've got // everything we need" codepath: // // props.insert(TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".Account"), // QVariant::fromValue(QDBusObjectPath(accountPath.path()))); // props.insert(TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".Connection"), // QVariant::fromValue(QDBusObjectPath(connectionPath.path()))); // props.insert(TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".Interfaces"), // QVariant::fromValue(QStringList())); // props.insert(TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".PossibleHandlers"), // QVariant::fromValue(QStringList())); invocation->dispatchOp = ChannelDispatchOperation::create(mBus, dispatchOperationPath.path(), props, invocation->chans, accFactory, connFactory, chanFactory, contactFactory); readyOps.append(invocation->dispatchOp->becomeReady()); } invocation->observerInfo = AbstractClientObserver::ObserverInfo(observerInfo); ObjectImmutablePropertiesMap reqPropsMap = qdbus_cast( observerInfo.value(QLatin1String("request-properties"))); foreach (const QDBusObjectPath &reqPath, requestsSatisfied) { //don't load the channelRequest objects in requestsSatisfied if the properties are not supplied with the handler info //as the channelRequest is probably invalid //this works around https://bugs.freedesktop.org/show_bug.cgi?id=77986 if (reqPropsMap.value(reqPath).isEmpty()) { continue; } ChannelRequestPtr channelRequest = ChannelRequest::create(invocation->acc, reqPath.path(), reqPropsMap.value(reqPath)); invocation->chanReqs.append(channelRequest); readyOps.append(channelRequest->becomeReady()); } invocation->ctx = MethodInvocationContextPtr<>(new MethodInvocationContext<>(mBus, message)); invocation->readyOp = new PendingComposite(readyOps, invocation->ctx); connect(invocation->readyOp, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onReadyOpFinished(Tp::PendingOperation*))); mInvocations.append(invocation); debug() << "Preparing proxies for ObserveChannels of" << channelDetailsList.size() << "channels" << "for client" << mClient; } void ClientObserverAdaptor::onReadyOpFinished(Tp::PendingOperation *op) { Q_ASSERT(!mInvocations.isEmpty()); Q_ASSERT(op->isFinished()); for (QLinkedList >::iterator i = mInvocations.begin(); i != mInvocations.end(); ++i) { if ((*i)->readyOp != op) { continue; } (*i)->readyOp = 0; if (op->isError()) { warning() << "Preparing proxies for ObserveChannels failed with" << op->errorName() << op->errorMessage(); (*i)->error = op->errorName(); (*i)->message = op->errorMessage(); } break; } while (!mInvocations.isEmpty() && !mInvocations.first()->readyOp) { SharedPtr invocation = mInvocations.takeFirst(); if (!invocation->error.isEmpty()) { // We guarantee that the proxies were ready - so we can't invoke the client if they // weren't made ready successfully. Fix the introspection code if this happens :) invocation->ctx->setFinishedWithError(invocation->error, invocation->message); continue; } debug() << "Invoking application observeChannels with" << invocation->chans.size() << "channels on" << mClient; mClient->observeChannels(invocation->ctx, invocation->acc, invocation->conn, invocation->chans, invocation->dispatchOp, invocation->chanReqs, invocation->observerInfo); } } ClientApproverAdaptor::ClientApproverAdaptor(ClientRegistrar *registrar, AbstractClientApprover *client, QObject *parent) : QDBusAbstractAdaptor(parent), mRegistrar(registrar), mBus(registrar->dbusConnection()), mClient(client) { } ClientApproverAdaptor::~ClientApproverAdaptor() { } void ClientApproverAdaptor::AddDispatchOperation(const Tp::ChannelDetailsList &channelDetailsList, const QDBusObjectPath &dispatchOperationPath, const QVariantMap &properties, const QDBusMessage &message) { AccountFactoryConstPtr accFactory = mRegistrar->accountFactory(); ConnectionFactoryConstPtr connFactory = mRegistrar->connectionFactory(); ChannelFactoryConstPtr chanFactory = mRegistrar->channelFactory(); ContactFactoryConstPtr contactFactory = mRegistrar->contactFactory(); QList readyOps; QDBusObjectPath connectionPath = qdbus_cast( properties.value( TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".Connection"))); debug() << "addDispatchOperation: connection:" << connectionPath.path(); QString connectionBusName = connectionPath.path().mid(1).replace( QLatin1String("/"), QLatin1String(".")); PendingReady *connReady = connFactory->proxy(connectionBusName, connectionPath.path(), chanFactory, contactFactory); ConnectionPtr connection = ConnectionPtr::qObjectCast(connReady->proxy()); readyOps.append(connReady); SharedPtr invocation(new InvocationData); foreach (const ChannelDetails &channelDetails, channelDetailsList) { PendingReady *chanReady = chanFactory->proxy(connection, channelDetails.channel.path(), channelDetails.properties); invocation->chans.append(ChannelPtr::qObjectCast(chanReady->proxy())); readyOps.append(chanReady); } invocation->dispatchOp = ChannelDispatchOperation::create(mBus, dispatchOperationPath.path(), properties, invocation->chans, accFactory, connFactory, chanFactory, contactFactory); readyOps.append(invocation->dispatchOp->becomeReady()); invocation->ctx = MethodInvocationContextPtr<>(new MethodInvocationContext<>(mBus, message)); invocation->readyOp = new PendingComposite(readyOps, invocation->ctx); connect(invocation->readyOp, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onReadyOpFinished(Tp::PendingOperation*))); mInvocations.append(invocation); } void ClientApproverAdaptor::onReadyOpFinished(Tp::PendingOperation *op) { Q_ASSERT(!mInvocations.isEmpty()); Q_ASSERT(op->isFinished()); for (QLinkedList >::iterator i = mInvocations.begin(); i != mInvocations.end(); ++i) { if ((*i)->readyOp != op) { continue; } (*i)->readyOp = 0; if (op->isError()) { warning() << "Preparing proxies for AddDispatchOperation failed with" << op->errorName() << op->errorMessage(); (*i)->error = op->errorName(); (*i)->message = op->errorMessage(); } break; } while (!mInvocations.isEmpty() && !mInvocations.first()->readyOp) { SharedPtr invocation = mInvocations.takeFirst(); if (!invocation->error.isEmpty()) { // We guarantee that the proxies were ready - so we can't invoke the client if they // weren't made ready successfully. Fix the introspection code if this happens :) invocation->ctx->setFinishedWithError(invocation->error, invocation->message); continue; } debug() << "Invoking application addDispatchOperation with CDO" << invocation->dispatchOp->objectPath() << "on" << mClient; mClient->addDispatchOperation(invocation->ctx, invocation->dispatchOp); } } QHash, QList > ClientHandlerAdaptor::mAdaptorsForConnection; ClientHandlerAdaptor::ClientHandlerAdaptor(ClientRegistrar *registrar, AbstractClientHandler *client, QObject *parent) : QDBusAbstractAdaptor(parent), mRegistrar(registrar), mBus(registrar->dbusConnection()), mClient(client) { QList &handlerAdaptors = mAdaptorsForConnection[qMakePair(mBus.name(), mBus.baseService())]; handlerAdaptors.append(this); } ClientHandlerAdaptor::~ClientHandlerAdaptor() { QPair busId = qMakePair(mBus.name(), mBus.baseService()); QList &handlerAdaptors = mAdaptorsForConnection[busId]; handlerAdaptors.removeOne(this); if (handlerAdaptors.isEmpty()) { mAdaptorsForConnection.remove(busId); } } void ClientHandlerAdaptor::HandleChannels(const QDBusObjectPath &accountPath, const QDBusObjectPath &connectionPath, const Tp::ChannelDetailsList &channelDetailsList, const Tp::ObjectPathList &requestsSatisfied, qulonglong userActionTime_t, const QVariantMap &handlerInfo, const QDBusMessage &message) { debug() << "HandleChannels: account:" << accountPath.path() << ", connection:" << connectionPath.path(); AccountFactoryConstPtr accFactory = mRegistrar->accountFactory(); ConnectionFactoryConstPtr connFactory = mRegistrar->connectionFactory(); ChannelFactoryConstPtr chanFactory = mRegistrar->channelFactory(); ContactFactoryConstPtr contactFactory = mRegistrar->contactFactory(); SharedPtr invocation(new InvocationData()); QList readyOps; RequestTemporaryHandler *tempHandler = dynamic_cast(mClient); if (tempHandler) { debug() << " This is a temporary handler for the Request & Handle API," << "giving an early signal of the invocation"; tempHandler->setDBusHandlerInvoked(); } PendingReady *accReady = accFactory->proxy(TP_QT_ACCOUNT_MANAGER_BUS_NAME, accountPath.path(), connFactory, chanFactory, contactFactory); invocation->acc = AccountPtr::qObjectCast(accReady->proxy()); readyOps.append(accReady); QString connectionBusName = connectionPath.path().mid(1).replace( QLatin1String("/"), QLatin1String(".")); PendingReady *connReady = connFactory->proxy(connectionBusName, connectionPath.path(), chanFactory, contactFactory); invocation->conn = ConnectionPtr::qObjectCast(connReady->proxy()); readyOps.append(connReady); foreach (const ChannelDetails &channelDetails, channelDetailsList) { PendingReady *chanReady = chanFactory->proxy(invocation->conn, channelDetails.channel.path(), channelDetails.properties); ChannelPtr channel = ChannelPtr::qObjectCast(chanReady->proxy()); invocation->chans.append(channel); readyOps.append(chanReady); } invocation->handlerInfo = AbstractClientHandler::HandlerInfo(handlerInfo); ObjectImmutablePropertiesMap reqPropsMap = qdbus_cast( handlerInfo.value(QLatin1String("request-properties"))); foreach (const QDBusObjectPath &reqPath, requestsSatisfied) { //don't load the channelRequest objects in requestsSatisfied if the properties are not supplied with the handler info //as the channelRequest is probably invalid //this works around https://bugs.freedesktop.org/show_bug.cgi?id=77986 if (reqPropsMap.value(reqPath).isEmpty()) { continue; } ChannelRequestPtr channelRequest = ChannelRequest::create(invocation->acc, reqPath.path(), reqPropsMap.value(reqPath)); invocation->chanReqs.append(channelRequest); readyOps.append(channelRequest->becomeReady()); } // FIXME See http://bugs.freedesktop.org/show_bug.cgi?id=21690 if (userActionTime_t != 0) { invocation->time = QDateTime::fromTime_t((uint) userActionTime_t); } invocation->ctx = HandleChannelsInvocationContext::create(mBus, message, invocation->chans, reinterpret_cast( &ClientHandlerAdaptor::onContextFinished), this); invocation->readyOp = new PendingComposite(readyOps, invocation->ctx); connect(invocation->readyOp, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onReadyOpFinished(Tp::PendingOperation*))); mInvocations.append(invocation); debug() << "Preparing proxies for HandleChannels of" << channelDetailsList.size() << "channels" << "for client" << mClient; } void ClientHandlerAdaptor::onReadyOpFinished(Tp::PendingOperation *op) { Q_ASSERT(!mInvocations.isEmpty()); Q_ASSERT(op->isFinished()); for (QLinkedList >::iterator i = mInvocations.begin(); i != mInvocations.end(); ++i) { if ((*i)->readyOp != op) { continue; } (*i)->readyOp = 0; if (op->isError()) { warning() << "Preparing proxies for HandleChannels failed with" << op->errorName() << op->errorMessage(); (*i)->error = op->errorName(); (*i)->message = op->errorMessage(); } break; } while (!mInvocations.isEmpty() && !mInvocations.first()->readyOp) { SharedPtr invocation = mInvocations.takeFirst(); if (!invocation->error.isEmpty()) { RequestTemporaryHandler *tempHandler = dynamic_cast(mClient); if (tempHandler) { debug() << " This is a temporary handler for the Request & Handle API, indicating failure"; tempHandler->setDBusHandlerErrored(invocation->error, invocation->message); } // We guarantee that the proxies were ready - so we can't invoke the client if they // weren't made ready successfully. Fix the introspection code if this happens :) invocation->ctx->setFinishedWithError(invocation->error, invocation->message); continue; } debug() << "Invoking application handleChannels with" << invocation->chans.size() << "channels on" << mClient; mClient->handleChannels(invocation->ctx, invocation->acc, invocation->conn, invocation->chans, invocation->chanReqs, invocation->time, invocation->handlerInfo); } } void ClientHandlerAdaptor::onContextFinished( const MethodInvocationContextPtr<> &context, const QList &channels, ClientHandlerAdaptor *self) { if (!context->isError()) { debug() << "HandleChannels context finished successfully, " "updating handled channels"; // register the channels in FakeHandlerManager so we report HandledChannels correctly FakeHandlerManager::instance()->registerChannels(channels); } } ClientHandlerRequestsAdaptor::ClientHandlerRequestsAdaptor( ClientRegistrar *registrar, AbstractClientHandler *client, QObject *parent) : QDBusAbstractAdaptor(parent), mRegistrar(registrar), mBus(registrar->dbusConnection()), mClient(client) { } ClientHandlerRequestsAdaptor::~ClientHandlerRequestsAdaptor() { } void ClientHandlerRequestsAdaptor::AddRequest( const QDBusObjectPath &request, const QVariantMap &requestProperties, const QDBusMessage &message) { debug() << "AddRequest:" << request.path(); message.setDelayedReply(true); mBus.send(message.createReply()); mClient->addRequest(ChannelRequest::create(mBus, request.path(), requestProperties, mRegistrar->accountFactory(), mRegistrar->connectionFactory(), mRegistrar->channelFactory(), mRegistrar->contactFactory())); } void ClientHandlerRequestsAdaptor::RemoveRequest( const QDBusObjectPath &request, const QString &errorName, const QString &errorMessage, const QDBusMessage &message) { debug() << "RemoveRequest:" << request.path() << "-" << errorName << "-" << errorMessage; message.setDelayedReply(true); mBus.send(message.createReply()); mClient->removeRequest(ChannelRequest::create(mBus, request.path(), QVariantMap(), mRegistrar->accountFactory(), mRegistrar->connectionFactory(), mRegistrar->channelFactory(), mRegistrar->contactFactory()), errorName, errorMessage); } struct TP_QT_NO_EXPORT ClientRegistrar::Private { Private(const QDBusConnection &bus, const AccountFactoryConstPtr &accFactory, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) : bus(bus), accFactory(accFactory), connFactory(connFactory), chanFactory(chanFactory), contactFactory(contactFactory) { if (accFactory->dbusConnection().name() != bus.name()) { warning() << " The D-Bus connection in the account factory is not the proxy connection"; } if (connFactory->dbusConnection().name() != bus.name()) { warning() << " The D-Bus connection in the connection factory is not the proxy connection"; } if (chanFactory->dbusConnection().name() != bus.name()) { warning() << " The D-Bus connection in the channel factory is not the proxy connection"; } } QDBusConnection bus; AccountFactoryConstPtr accFactory; ConnectionFactoryConstPtr connFactory; ChannelFactoryConstPtr chanFactory; ContactFactoryConstPtr contactFactory; QHash clients; QHash clientObjects; QSet services; }; /** * \class ClientRegistrar * \ingroup serverclient * \headerfile TelepathyQt/client-registrar.h * * \brief The ClientRegistrar class is responsible for registering Telepathy * clients (Observer, Approver, Handler). * * Clients should inherit AbstractClientObserver, AbstractClientApprover, * AbstractClientHandler or some combination of these, by using multiple * inheritance, and register themselves using registerClient(). * * See the individual classes descriptions for more details. * * \section cr_usage_sec Usage * * \subsection cr_create_sec Creating a client registrar object * * One way to create a ClientRegistrar object is to just call the create method. * For example: * * \code ClientRegistrarPtr cr = ClientRegistrar::create(); \endcode * * You can also provide a D-Bus connection as a QDBusConnection: * * \code ClientRegistrarPtr cr = ClientRegistrar::create(QDBusConnection::systemBus()); \endcode * * \subsection cr_registering_sec Registering a client * * To register a client, just call registerClient() with a given AbstractClientPtr * pointing to a valid AbstractClient instance. * * \code * * class MyClient : public AbstractClientObserver, public AbstractClientHandler * { * ... * }; * * ... * * ClientRegistrarPtr cr = ClientRegistrar::create(); * SharedPtr client = SharedPtr(new MyClient(...)); * cr->registerClient(AbstractClientPtr::dynamicCast(client), "myclient"); * * \endcode * * \sa AbstractClientObserver, AbstractClientApprover, AbstractClientHandler * * See \ref async_model, \ref shared_ptr */ /** * Create a new client registrar object using the given \a bus. * * The instance will use an account factory creating Tp::Account objects with no features * ready, a connection factory creating Tp::Connection objects with no features ready, and a channel * factory creating stock Telepathy-Qt channel subclasses, as appropriate, with no features ready. * * \param bus QDBusConnection to use. * \return A ClientRegistrarPtr object pointing to the newly created ClientRegistrar object. */ ClientRegistrarPtr ClientRegistrar::create(const QDBusConnection &bus) { return create(bus, AccountFactory::create(bus), ConnectionFactory::create(bus), ChannelFactory::create(bus), ContactFactory::create()); } /** * Create a new client registrar object using QDBusConnection::sessionBus() and the given factories. * * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return A ClientRegistrarPtr object pointing to the newly created ClientRegistrar object. */ ClientRegistrarPtr ClientRegistrar::create( const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return create(QDBusConnection::sessionBus(), accountFactory, connectionFactory, channelFactory, contactFactory); } /** * Create a new client registrar object using the given \a bus and the given factories. * * \param bus QDBusConnection to use. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return A ClientRegistrarPtr object pointing to the newly created ClientRegistrar object. */ ClientRegistrarPtr ClientRegistrar::create(const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return ClientRegistrarPtr(new ClientRegistrar(bus, accountFactory, connectionFactory, channelFactory, contactFactory)); } /** * Create a new client registrar object using the bus and factories of the given Account \a manager. * * Using this create method will enable (like any other way of passing the same factories to an AM * and a registrar) getting the same Account/Connection etc. proxy instances from both * AccountManager and AbstractClient implementations. * * \param manager The AccountManager the bus and factories of which should be used. * \return A ClientRegistrarPtr object pointing to the newly ClientRegistrar object. */ ClientRegistrarPtr ClientRegistrar::create(const AccountManagerPtr &manager) { if (!manager) { return ClientRegistrarPtr(); } return create(manager->dbusConnection(), manager->accountFactory(), manager->connectionFactory(), manager->channelFactory(), manager->contactFactory()); } /** * Construct a new client registrar object using the given \a bus and the given factories. * * \param bus QDBusConnection to use. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. */ ClientRegistrar::ClientRegistrar(const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) : Object(), mPriv(new Private(bus, accountFactory, connectionFactory, channelFactory, contactFactory)) { } /** * Class destructor. */ ClientRegistrar::~ClientRegistrar() { unregisterClients(); delete mPriv; } /** * Return the D-Bus connection being used by this client registrar. * * \return A QDBusConnection object. */ QDBusConnection ClientRegistrar::dbusConnection() const { return mPriv->bus; } /** * Get the account factory used by this client registrar. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the registrar would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the AccountFactory object. */ AccountFactoryConstPtr ClientRegistrar::accountFactory() const { return mPriv->accFactory; } /** * Get the connection factory used by this client registrar. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the registrar would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ConnectionFactory object. */ ConnectionFactoryConstPtr ClientRegistrar::connectionFactory() const { return mPriv->connFactory; } /** * Get the channel factory used by this client registrar. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the registrar would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ChannelFactory object. */ ChannelFactoryConstPtr ClientRegistrar::channelFactory() const { return mPriv->chanFactory; } /** * Get the contact factory used by this client registrar. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the registrar would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ContactFactory object. */ ContactFactoryConstPtr ClientRegistrar::contactFactory() const { return mPriv->contactFactory; } /** * Return the list of clients registered using registerClient() on this client * registrar. * * \return A list of pointers to AbstractClient objects. * \sa registerClient(), unregisterClient() */ QList ClientRegistrar::registeredClients() const { return mPriv->clients.keys(); } /** * Register a client on D-Bus. * * The client registrar will export the appropriate D-Bus interfaces, * based on the abstract classes subclassed by \param client. * * If each of a client instance should be able to manipulate channels * separately, set unique to true. * * The client name MUST be a non-empty string of ASCII digits, letters, dots * and/or underscores, starting with a letter, and without sets of * two consecutive dots or a dot followed by a digit. * * This method will do nothing if the client is already registered, and \c true * will be returned. * * To unregister a client use unregisterClient(). * * \param client The client to register. * \param clientName The client name used to register. * \param unique Whether each of a client instance is able to manipulate * channels separately. * \return \c true if \a client was successfully registered, \c false otherwise. * \sa registeredClients(), unregisterClient() */ bool ClientRegistrar::registerClient(const AbstractClientPtr &client, const QString &clientName, bool unique) { if (!client) { warning() << "Unable to register a null client"; return false; } if (mPriv->clients.contains(client)) { debug() << "Client already registered"; return true; } QString busName = QLatin1String("org.freedesktop.Telepathy.Client."); busName.append(clientName); if (unique) { // o.f.T.Client.clientName._ should be enough to identify // an unique identifier busName.append(QString(QLatin1String(".%1_%2")) .arg(mPriv->bus.baseService() .replace(QLatin1String(":"), QLatin1String("_")) .replace(QLatin1String("."), QLatin1String("_"))) .arg((quintptr) client.data(), 0, 16)); } if (mPriv->services.contains(busName) || !mPriv->bus.registerService(busName)) { warning() << "Unable to register client: busName" << busName << "already registered"; return false; } QObject *object = new QObject(this); QStringList interfaces; AbstractClientHandler *handler = dynamic_cast(client.data()); if (handler) { // export o.f.T.Client.Handler new ClientHandlerAdaptor(this, handler, object); interfaces.append( QLatin1String("org.freedesktop.Telepathy.Client.Handler")); if (handler->wantsRequestNotification()) { // export o.f.T.Client.Interface.Requests new ClientHandlerRequestsAdaptor(this, handler, object); interfaces.append( QLatin1String( "org.freedesktop.Telepathy.Client.Interface.Requests")); } } AbstractClientObserver *observer = dynamic_cast(client.data()); if (observer) { // export o.f.T.Client.Observer new ClientObserverAdaptor(this, observer, object); interfaces.append( QLatin1String("org.freedesktop.Telepathy.Client.Observer")); } AbstractClientApprover *approver = dynamic_cast(client.data()); if (approver) { // export o.f.T.Client.Approver new ClientApproverAdaptor(this, approver, object); interfaces.append( QLatin1String("org.freedesktop.Telepathy.Client.Approver")); } if (interfaces.isEmpty()) { warning() << "Client does not implement any known interface"; // cleanup mPriv->bus.unregisterService(busName); return false; } // export o.f.T.Client interface new ClientAdaptor(this, interfaces, object); QString objectPath = QString(QLatin1String("/%1")).arg(busName); objectPath.replace(QLatin1String("."), QLatin1String("/")); if (!mPriv->bus.registerObject(objectPath, object)) { // this shouldn't happen, but let's make sure warning() << "Unable to register client: objectPath" << objectPath << "already registered"; // cleanup delete object; mPriv->bus.unregisterService(busName); return false; } if (handler) { handler->setRegistered(true); } debug() << "Client registered - busName:" << busName << "objectPath:" << objectPath << "interfaces:" << interfaces; mPriv->services.insert(busName); mPriv->clients.insert(client, objectPath); mPriv->clientObjects.insert(client, object); return true; } /** * Unregister a client registered using registerClient() on this client * registrar. * * If \a client was not registered previously, \c false will be returned. * * \param client The client to unregister. * \return \c true if \a client was successfully unregistered, \c false otherwise. * \sa registeredClients(), registerClient() */ bool ClientRegistrar::unregisterClient(const AbstractClientPtr &client) { if (!mPriv->clients.contains(client)) { warning() << "Trying to unregister an unregistered client"; return false; } AbstractClientHandler *handler = dynamic_cast(client.data()); if (handler) { handler->setRegistered(false); } QString objectPath = mPriv->clients.value(client); mPriv->bus.unregisterObject(objectPath); mPriv->clients.remove(client); QObject *object = mPriv->clientObjects.value(client); // delete object here and it's children (adaptors), to make sure if adaptor // is keeping a static list of adaptors per connection, the list is updated. delete object; mPriv->clientObjects.remove(client); QString busName = objectPath.mid(1).replace(QLatin1String("/"), QLatin1String(".")); mPriv->bus.unregisterService(busName); mPriv->services.remove(busName); debug() << "Client unregistered - busName:" << busName << "objectPath:" << objectPath; return true; } /** * Unregister all clients registered using registerClient() on this client * registrar. * * \sa registeredClients(), registerClient(), unregisterClient() */ void ClientRegistrar::unregisterClients() { // copy the hash as it will be modified QHash clients = mPriv->clients; QHash::const_iterator end = clients.constEnd(); QHash::const_iterator it = clients.constBegin(); while (it != end) { unregisterClient(it.key()); ++it; } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/message.cpp0000664000175000017500000005665112470405660017361 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "TelepathyQt/debug-internal.h" #include #include #include namespace Tp { namespace { QVariant valueFromPart(const MessagePartList &parts, uint index, const char *key) { return parts.at(index).value(QLatin1String(key)).variant(); } uint uintOrZeroFromPart(const MessagePartList &parts, uint index, const char *key) { return valueFromPart(parts, index, key).toUInt(); } QString stringOrEmptyFromPart(const MessagePartList &parts, uint index, const char *key) { QString s = valueFromPart(parts, index, key).toString(); if (s.isNull()) { s = QLatin1String(""); } return s; } bool booleanFromPart(const MessagePartList &parts, uint index, const char *key, bool assumeIfAbsent) { QVariant v = valueFromPart(parts, index, key); if (v.isValid() && v.type() == QVariant::Bool) { return v.toBool(); } return assumeIfAbsent; } MessagePartList partsFromPart(const MessagePartList &parts, uint index, const char *key) { return qdbus_cast(valueFromPart(parts, index, key)); } bool partContains(const MessagePartList &parts, uint index, const char *key) { return parts.at(index).contains(QLatin1String(key)); } } struct TP_QT_NO_EXPORT Message::Private : public QSharedData { Private(const MessagePartList &parts); ~Private(); uint senderHandle() const; QString senderId() const; uint pendingId() const; void clearSenderHandle(); MessagePartList parts; // if the Text interface says "non-text" we still only have the text, // because the interface can't tell us anything else... bool forceNonText; // for received messages only WeakPtr textChannel; ContactPtr sender; }; Message::Private::Private(const MessagePartList &parts) : parts(parts), forceNonText(false), sender(0) { } Message::Private::~Private() { } inline uint Message::Private::senderHandle() const { return uintOrZeroFromPart(parts, 0, "message-sender"); } inline QString Message::Private::senderId() const { return stringOrEmptyFromPart(parts, 0, "message-sender-id"); } inline uint Message::Private::pendingId() const { return uintOrZeroFromPart(parts, 0, "pending-message-id"); } void Message::Private::clearSenderHandle() { parts[0].remove(QLatin1String("message-sender")); } /** * \class Message * \ingroup clientchannel * \headerfile TelepathyQt/message.h * * \brief The Message class represents a Telepathy message in a TextChannel. * * This class is implicitly shared, like QString. */ /** * \internal Default constructor. */ Message::Message() : mPriv(new Private(MessagePartList())) { } /** * Construct a new Message object. * * \param parts The parts of a message as defined by the \telepathy_spec. * This list must have length at least 1. */ Message::Message(const MessagePartList &parts) : mPriv(new Private(parts)) { Q_ASSERT(parts.size() > 0); } /** * Construct a new Message object. * * \param timestamp The time the message was sent. * \param type The message type. * \param text The message body. */ Message::Message(uint timestamp, uint type, const QString &text) : mPriv(new Private(MessagePartList() << MessagePart() << MessagePart())) { mPriv->parts[0].insert(QLatin1String("message-sent"), QDBusVariant(static_cast(timestamp))); mPriv->parts[0].insert(QLatin1String("message-type"), QDBusVariant(type)); mPriv->parts[1].insert(QLatin1String("content-type"), QDBusVariant(QLatin1String("text/plain"))); mPriv->parts[1].insert(QLatin1String("content"), QDBusVariant(text)); } /** * Construct a new Message object. * * \param type The message type. * \param text The message body. */ Message::Message(ChannelTextMessageType type, const QString &text) : mPriv(new Private(MessagePartList() << MessagePart() << MessagePart())) { mPriv->parts[0].insert(QLatin1String("message-type"), QDBusVariant(static_cast(type))); mPriv->parts[1].insert(QLatin1String("content-type"), QDBusVariant(QLatin1String("text/plain"))); mPriv->parts[1].insert(QLatin1String("content"), QDBusVariant(text)); } /** * Copy constructor. */ Message::Message(const Message &other) : mPriv(other.mPriv) { } /** * Assignment operator. */ Message &Message::operator=(const Message &other) { if (this != &other) { mPriv = other.mPriv; } return *this; } /** * Equality operator. */ bool Message::operator==(const Message &other) const { return this->mPriv == other.mPriv; } /** * Class destructor. */ Message::~Message() { } /** * Return the time the message was sent, or QDateTime() if that time is * unknown. * * \return The timestamp as QDateTime. */ QDateTime Message::sent() const { // FIXME See http://bugs.freedesktop.org/show_bug.cgi?id=21690 uint stamp = valueFromPart(mPriv->parts, 0, "message-sent").toUInt(); if (stamp != 0) { return QDateTime::fromTime_t(stamp); } else { return QDateTime(); } } /** * Return the type of this message, or #ChannelTextMessageTypeNormal * if the type is not recognised. * * \return The type as #ChannelTextMessageType. */ ChannelTextMessageType Message::messageType() const { uint raw = valueFromPart(mPriv->parts, 0, "message-type").toUInt(); if (raw < static_cast(NUM_CHANNEL_TEXT_MESSAGE_TYPES)) { return ChannelTextMessageType(raw); } else { return ChannelTextMessageTypeNormal; } } /** * Return whether this message was truncated during delivery. * * \return \c true if truncated, \c false otherwise. */ bool Message::isTruncated() const { for (int i = 1; i < size(); i++) { if (booleanFromPart(mPriv->parts, i, "truncated", false)) { return true; } } return false; } /** * Return whether this message contains parts not representable as plain * text. * * \return \c true if it cannot completely be represented as plain text, \c false * otherwise. */ bool Message::hasNonTextContent() const { if (mPriv->forceNonText || size() <= 1 || isSpecificToDBusInterface()) { return true; } QSet texts; QSet textNeeded; for (int i = 1; i < size(); i++) { QString altGroup = stringOrEmptyFromPart(mPriv->parts, i, "alternative"); QString contentType = stringOrEmptyFromPart(mPriv->parts, i, "content-type"); if (contentType == QLatin1String("text/plain")) { if (!altGroup.isEmpty()) { // we can use this as an alternative for a non-text part // with the same altGroup texts << altGroup; } } else { QString alt = stringOrEmptyFromPart(mPriv->parts, i, "alternative"); if (altGroup.isEmpty()) { // we can't possibly rescue this part by using a text/plain // alternative, because it's not in any alternative group return true; } else { // maybe we'll find a text/plain alternative for this textNeeded << altGroup; } } } textNeeded -= texts; return !textNeeded.isEmpty(); } /** * Return the unique token identifying this message (e.g. the id attribute * for XMPP messages), or an empty string if there is no suitable token. * * \return The non-empty message identifier, or an empty string if none. */ QString Message::messageToken() const { return stringOrEmptyFromPart(mPriv->parts, 0, "message-token"); } /** * Return whether this message is specific to a D-Bus interface. This is * \c false in almost all cases. * * If this function returns \c true, the message is specific to the interface * indicated by dbusInterface(). Clients that don't understand that interface * should not display the message. However, if the client would acknowledge * an ordinary message, it must also acknowledge this interface-specific * message. * * \return \c true if dbusInterface() would return a non-empty string, \c false otherwise. * \sa dbusInterface() */ bool Message::isSpecificToDBusInterface() const { return !dbusInterface().isEmpty(); } /** * Return the D-Bus interface to which this message is specific, or an * empty string for normal messages. * * \return The D-Bus interface name, or an empty string. * \sa isSpecificToDBusInterface() */ QString Message::dbusInterface() const { return stringOrEmptyFromPart(mPriv->parts, 0, "interface"); } /** * Return the message body containing all "text/plain" parts. * * \return The body text. */ QString Message::text() const { // Alternative-groups for which we've already emitted an alternative QSet altGroupsUsed; QString text; for (int i = 1; i < size(); i++) { QString altGroup = stringOrEmptyFromPart(mPriv->parts, i, "alternative"); QString contentType = stringOrEmptyFromPart(mPriv->parts, i, "content-type"); if (contentType == QLatin1String("text/plain")) { if (!altGroup.isEmpty()) { if (altGroupsUsed.contains(altGroup)) { continue; } else { altGroupsUsed << altGroup; } } QVariant content = valueFromPart(mPriv->parts, i, "content"); if (content.type() == QVariant::String) { text += content.toString(); } else { // O RLY? debug() << "allegedly text/plain part wasn't"; } } } return text; } /** * Return the message's header part, as defined by the \telepathy_spec. * * This is provided for advanced clients that need to access * additional information not available through the normal Message API. * * \return The header as a MessagePart object. The same thing as part(0). */ MessagePart Message::header() const { return part(0); } /** * Return the number of parts in this message. * * \return 1 greater than the largest valid argument to part(). * \sa part(), parts() */ int Message::size() const { return mPriv->parts.size(); } /** * Return the message's part for \a index, as defined by the \telepathy_spec. * * This is provided for advanced clients that need to access * additional information not available through the normal Message API. * * \param index The part to access, which must be strictly less than size(); * part number 0 is the header, parts numbered 1 or greater * are the body of the message. * \return A MessagePart object. */ MessagePart Message::part(uint index) const { return mPriv->parts.at(index); } /** * Return the list of message parts forming this message. * * \return The list of MessagePart objects. */ MessagePartList Message::parts() const { return mPriv->parts; } /** * \class ReceivedMessage * \ingroup clientchannel * \headerfile TelepathyQt/message.h * * \brief The ReceivedMessage class is a subclass of Message, representing a * received message only. * * It contains additional information that's generally only * available on received messages. */ /** * \class ReceivedMessage::DeliveryDetails * \ingroup clientchannel * \headerfile TelepathyQt/message.h * * \brief The ReceivedMessage::DeliveryDetails class represents the details of a delivery report. */ struct TP_QT_NO_EXPORT ReceivedMessage::DeliveryDetails::Private : public QSharedData { Private(const MessagePartList &parts) : parts(parts) { } MessagePartList parts; }; /** * Default constructor. */ ReceivedMessage::DeliveryDetails::DeliveryDetails() { } /** * Copy constructor. */ ReceivedMessage::DeliveryDetails::DeliveryDetails(const DeliveryDetails &other) : mPriv(other.mPriv) { } /** * Construct a new ReceivedMessage::DeliveryDetails object. * * \param The message parts. */ ReceivedMessage::DeliveryDetails::DeliveryDetails(const MessagePartList &parts) : mPriv(new Private(parts)) { } /** * Class destructor. */ ReceivedMessage::DeliveryDetails::~DeliveryDetails() { } /** * Assignment operator. */ ReceivedMessage::DeliveryDetails &ReceivedMessage::DeliveryDetails::operator=( const DeliveryDetails &other) { this->mPriv = other.mPriv; return *this; } /** * Return the delivery status of a message. * * \return The delivery status as #DeliveryStatus. */ DeliveryStatus ReceivedMessage::DeliveryDetails::status() const { if (!isValid()) { return DeliveryStatusUnknown; } return static_cast(uintOrZeroFromPart(mPriv->parts, 0, "delivery-status")); } /** * Return whether this delivery report contains an identifier for the message to which it * refers. * * \return \c true if an original message token is known, \c false otherwise. * \sa originalToken() */ bool ReceivedMessage::DeliveryDetails::hasOriginalToken() const { if (!isValid()) { return false; } return partContains(mPriv->parts, 0, "delivery-token"); } /** * Return an identifier for the message to which this delivery report refers, or an empty string if * hasOriginalToken() returns \c false. * * Clients may match this against the token produced by the TextChannel::send() method and * TextChannel::messageSent() signal. A status report with no token could match any sent message, * and a sent message with an empty token could match any status report. * If multiple sent messages match, clients should use some reasonable heuristic. * * \return The message token if hasOriginalToken() returns \c true, an empty string otherwise. * \sa hasOriginalToken(). */ QString ReceivedMessage::DeliveryDetails::originalToken() const { if (!isValid()) { return QString(); } return stringOrEmptyFromPart(mPriv->parts, 0, "delivery-token"); } /** * Return whether the delivery of the message this delivery report refers to, failed. * * \return \c true if the message delivery failed, \c false otherwise. * \sa error() */ bool ReceivedMessage::DeliveryDetails::isError() const { if (!isValid()) { return false; } DeliveryStatus st(status()); return st == DeliveryStatusTemporarilyFailed || st == DeliveryStatusPermanentlyFailed; } /** * Return the reason for the delivery failure if known. * * \return The reason as #ChannelTextSendError. * \sa isError() */ ChannelTextSendError ReceivedMessage::DeliveryDetails::error() const { if (!isValid()) { return ChannelTextSendErrorUnknown; } return static_cast(uintOrZeroFromPart(mPriv->parts, 0, "delivery-error")); } /** * Return whether this delivery report contains a debugging information on why the message it refers * to could not be delivered. * * \return \c true if a debugging information is provided, \c false otherwise. * \sa debugMessage() */ bool ReceivedMessage::DeliveryDetails::hasDebugMessage() const { if (!isValid()) { return false; } return partContains(mPriv->parts, 0, "delivery-error-message"); } /** * Return the debugging information on why the message this delivery report refers to could not be * delivered. * * \return The debug string. * \sa hasDebugMessage() */ QString ReceivedMessage::DeliveryDetails::debugMessage() const { if (!isValid()) { return QString(); } return stringOrEmptyFromPart(mPriv->parts, 0, "delivery-error-message"); } /** * Return the reason for the delivery failure if known, specified as a * (possibly implementation-specific) D-Bus error. * * \return The D-Bus error string representing the error. */ QString ReceivedMessage::DeliveryDetails::dbusError() const { if (!isValid()) { return QString(); } QString ret = stringOrEmptyFromPart(mPriv->parts, 0, "delivery-dbus-error"); if (ret.isEmpty()) { switch (error()) { case ChannelTextSendErrorOffline: ret = TP_QT_ERROR_OFFLINE; break; case ChannelTextSendErrorInvalidContact: ret = TP_QT_ERROR_DOES_NOT_EXIST; break; case ChannelTextSendErrorPermissionDenied: ret = TP_QT_ERROR_PERMISSION_DENIED; break; case ChannelTextSendErrorTooLong: ret = TP_QT_ERROR_INVALID_ARGUMENT; break; case ChannelTextSendErrorNotImplemented: ret = TP_QT_ERROR_NOT_IMPLEMENTED; break; default: ret = TP_QT_ERROR_NOT_AVAILABLE; } } return ret; } /** * Return whether the message content for the message this delivery report refers to is known. * * \return \c true if the original message content is known, \c false otherwise. * \sa echoedMessage() */ bool ReceivedMessage::DeliveryDetails::hasEchoedMessage() const { if (!isValid()) { return false; } return partContains(mPriv->parts, 0, "delivery-echo"); } /** * Return the Message object for the message this delivery report refers to, omitted if the message * is unknown. * *
*
Rationale:
*
* Some protocols, like XMPP, echo the failing message back to the sender. This is sometimes the * only way to match it against the sent message, so we include it here. *
*
* * \return The Message object, or an empty Message object if hasEchoedMessage() * returns \c false. * \sa hasEchoedMessage() */ Message ReceivedMessage::DeliveryDetails::echoedMessage() const { if (!isValid()) { return Message(); } return Message(partsFromPart(mPriv->parts, 0, "delivery-echo")); } /** * \internal Default constructor. */ ReceivedMessage::ReceivedMessage() { } /** * Construct a new ReceivedMessage object. * * \param parts The parts of a message as defined by the \telepathy_spec. * This list must have length at least 1. * \param channel The channel owning this message. */ ReceivedMessage::ReceivedMessage(const MessagePartList &parts, const TextChannelPtr &channel) : Message(parts) { if (!mPriv->parts[0].contains(QLatin1String("message-received"))) { mPriv->parts[0].insert(QLatin1String("message-received"), QDBusVariant(static_cast( QDateTime::currentDateTime().toTime_t()))); } mPriv->textChannel = channel; } /** * Copy constructor. */ ReceivedMessage::ReceivedMessage(const ReceivedMessage &other) : Message(other) { } /** * Assignment operator. */ ReceivedMessage &ReceivedMessage::operator=(const ReceivedMessage &other) { if (this != &other) { mPriv = other.mPriv; } return *this; } /** * Class destructor. */ ReceivedMessage::~ReceivedMessage() { } /** * Return the time the message was received. * * \return The timestamp as QDateTime, or QDateTime() if unknown. */ QDateTime ReceivedMessage::received() const { // FIXME See http://bugs.freedesktop.org/show_bug.cgi?id=21690 uint stamp = valueFromPart(mPriv->parts, 0, "message-received").toUInt(); if (stamp != 0) { return QDateTime::fromTime_t(stamp); } else { return QDateTime(); } } /** * Return the contact who sent the message. * * \return A pointer to the Contact object. * \sa senderNickname() */ ContactPtr ReceivedMessage::sender() const { return mPriv->sender; } /** * Return the nickname chosen by the sender of the message, which can be different for each * message in a conversation. * * \return The nickname. * \sa sender() */ QString ReceivedMessage::senderNickname() const { QString ret = stringOrEmptyFromPart(mPriv->parts, 0, "sender-nickname"); if (ret.isEmpty() && mPriv->sender) { ret = mPriv->sender->alias(); } return ret; } /** * If this message replaces a previous message, return the value of * messageToken() for that previous message. Otherwise, return an empty string. * * For instance, a user interface could replace the superseded * message with this message, or grey out the superseded message. * * \return The message token of the superseded message or an empty string if none. */ QString ReceivedMessage::supersededToken() const { return stringOrEmptyFromPart(mPriv->parts, 0, "supersedes"); } /** * Return whether the incoming message was part of a replay of message * history. * * If \c true, loggers can use this to improve their heuristics for elimination * of duplicate messages (a simple, correct implementation would be to avoid * logging any message that has this flag). * * \return \c true if the scrollback flag is set, \c false otherwise. */ bool ReceivedMessage::isScrollback() const { return booleanFromPart(mPriv->parts, 0, "scrollback", false); } /** * Return whether the incoming message was seen in a previous channel during * the lifetime of the connection, but was not acknowledged before that * channel closed, causing the channel in which it now appears to open. * * If \c true, loggers should not log this message again. * * \return \c true if the rescued flag is set, \c false otherwise. */ bool ReceivedMessage::isRescued() const { return booleanFromPart(mPriv->parts, 0, "rescued", false); } /** * Return whether the incoming message is a delivery report. * * \return \c true if a delivery report, \c false otherwise. * \sa deliveryDetails() */ bool ReceivedMessage::isDeliveryReport() const { return messageType() == ChannelTextMessageTypeDeliveryReport; } /** * Return the details of a delivery report. * * This method should only be used if isDeliveryReport() returns \c true. * * \return The delivery report as a ReceivedMessage::DeliveryDetails object. * \sa isDeliveryReport() */ ReceivedMessage::DeliveryDetails ReceivedMessage::deliveryDetails() const { return DeliveryDetails(parts()); } /** * Return whether this message is from \a channel. * * \return \c true if the message is from \a channel, \c false otherwise. */ bool ReceivedMessage::isFromChannel(const TextChannelPtr &channel) const { return TextChannelPtr(mPriv->textChannel) == channel; } uint ReceivedMessage::pendingId() const { return mPriv->pendingId(); } uint ReceivedMessage::senderHandle() const { return mPriv->senderHandle(); } QString ReceivedMessage::senderId() const { return mPriv->senderId(); } void ReceivedMessage::setForceNonText() { mPriv->forceNonText = true; } void ReceivedMessage::clearSenderHandle() { mPriv->clearSenderHandle(); } void ReceivedMessage::setSender(const ContactPtr &sender) { mPriv->sender = sender; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/captcha.h0000664000175000017500000000346512470405660017000 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_captcha_h_HEADER_GUARD_ #define _TelepathyQt_captcha_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class PendingCaptchas; class TP_QT_EXPORT Captcha { public: Captcha(); Captcha(const Captcha &other); ~Captcha(); bool isValid() const { return mPriv.constData() != 0; } Captcha &operator=(const Captcha &rhs); QString mimeType() const; QString label() const; QByteArray data() const; CaptchaAuthentication::ChallengeType type() const; uint id() const; private: struct Private; friend struct Private; friend class PendingCaptchas; Captcha(const QString &mimeType, const QString &label, const QByteArray &data, CaptchaAuthentication::ChallengeType type, uint id); QSharedDataPointer mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/Connection0000664000175000017500000000035412470405660017240 0ustar jrjr#ifndef _TelepathyQt_Connection_HEADER_GUARD_ #define _TelepathyQt_Connection_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel.xml0000664000175000017500000000426412470405660017354 0ustar jrjr Channel interfaces telepathy-qt-0.9.6~git1/TelepathyQt/RefCounted0000664000175000017500000000035412470405660017177 0ustar jrjr#ifndef _TelepathyQt_RefCounted_HEADER_GUARD_ #define _TelepathyQt_RefCounted_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeCallInterface0000664000175000017500000000040512470405660021765 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeCallInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeCallInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/profile-manager.h0000664000175000017500000000423112470405660020435 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_profile_manager_h_HEADER_GUARD_ #define _TelepathyQt_profile_manager_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include namespace Tp { class PendingOperation; class TP_QT_EXPORT ProfileManager : public Object, public ReadyObject { Q_OBJECT Q_DISABLE_COPY(ProfileManager); public: static const Feature FeatureCore; static const Feature FeatureFakeProfiles; static ProfileManagerPtr create(const QDBusConnection &bus = QDBusConnection::sessionBus()); ~ProfileManager(); QList profiles() const; QList profilesForCM(const QString &cmName) const; QList profilesForProtocol(const QString &protocolName) const; ProfilePtr profileForService(const QString &serviceName) const; private Q_SLOTS: TP_QT_NO_EXPORT void onCmNamesRetrieved(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onCMsReady(Tp::PendingOperation *op); private: ProfileManager(const QDBusConnection &bus); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/CallContentMediaDescription0000664000175000017500000000044212470405660022511 0ustar jrjr#ifndef _TelepathyQt_CallContentMediaDescription_HEADER_GUARD_ #define _TelepathyQt_CallContentMediaDescription_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/object.h0000664000175000017500000000304412470405660016634 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_object_h_HEADER_GUARD_ #define _TelepathyQt_object_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include namespace Tp { class TP_QT_EXPORT Object : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(Object) public: virtual ~Object(); Q_SIGNALS: void propertyChanged(const QString &propertyName); protected: Object(); void notify(const char *propertyName); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ChannelRequestInterface0000664000175000017500000000041312470405660021677 0ustar jrjr#ifndef _TelepathyQt_ChannelRequestInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelRequestInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/HandledChannelNotifier0000664000175000017500000000042212470405660021465 0ustar jrjr#ifndef _TelepathyQt_HandledChannelNotifier_HEADER_GUARD_ #define _TelepathyQt_HandledChannelNotifier_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/file-transfer-channel.cpp0000664000175000017500000005260312470405660022075 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/file-transfer-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include namespace Tp { struct TP_QT_NO_EXPORT FileTransferChannel::Private { Private(FileTransferChannel *parent); ~Private(); static void introspectProperties(Private *self); void extractProperties(const QVariantMap &props); // Public object FileTransferChannel *parent; Client::ChannelTypeFileTransferInterface *fileTransferInterface; Client::DBus::PropertiesInterface *properties; ReadinessHelper *readinessHelper; // Introspection uint pendingState; uint pendingStateReason; uint state; uint stateReason; QString contentType; QString fileName; QString uri; QString contentHash; QString description; QDateTime lastModificationTime; FileHashType contentHashType; qulonglong initialOffset; qulonglong size; qulonglong transferredBytes; SupportedSocketMap availableSocketTypes; bool connected; bool finished; }; FileTransferChannel::Private::Private(FileTransferChannel *parent) : parent(parent), fileTransferInterface(parent->interface()), properties(parent->interface()), readinessHelper(parent->readinessHelper()), pendingState(FileTransferStateNone), pendingStateReason(FileTransferStateChangeReasonNone), state(pendingState), stateReason(pendingStateReason), contentHashType(FileHashTypeNone), initialOffset(0), size(0), transferredBytes(0), connected(false), finished(false) { parent->connect(fileTransferInterface, SIGNAL(InitialOffsetDefined(qulonglong)), SLOT(onInitialOffsetDefined(qulonglong))); parent->connect(fileTransferInterface, SIGNAL(FileTransferStateChanged(uint,uint)), SLOT(onStateChanged(uint,uint))); parent->connect(fileTransferInterface, SIGNAL(TransferredBytesChanged(qulonglong)), SLOT(onTransferredBytesChanged(qulonglong))); ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectProperties, this); introspectables[FeatureCore] = introspectableCore; readinessHelper->addIntrospectables(introspectables); } FileTransferChannel::Private::~Private() { } void FileTransferChannel::Private::introspectProperties( FileTransferChannel::Private *self) { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->GetAll( TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER), self->parent); self->parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotProperties(QDBusPendingCallWatcher*))); } void FileTransferChannel::Private::extractProperties(const QVariantMap &props) { pendingState = state = qdbus_cast(props[QLatin1String("State")]); contentType = qdbus_cast(props[QLatin1String("ContentType")]); fileName = qdbus_cast(props[QLatin1String("Filename")]); uri = qdbus_cast(props[QLatin1String("URI")]); contentHash = qdbus_cast(props[QLatin1String("ContentHash")]); description = qdbus_cast(props[QLatin1String("Description")]); lastModificationTime.setTime_t((uint) qdbus_cast(props[QLatin1String("Date")])); contentHashType = (FileHashType) qdbus_cast(props[QLatin1String("ContentHashType")]); initialOffset = qdbus_cast(props[QLatin1String("InitialOffset")]); size = qdbus_cast(props[QLatin1String("Size")]); transferredBytes = qdbus_cast(props[QLatin1String("TransferredBytes")]); availableSocketTypes = qdbus_cast(props[QLatin1String("AvailableSocketTypes")]); } /** * \class FileTransferChannel * \ingroup clientchannel * \headerfile TelepathyQt/file-transfer-channel.h * * \brief The FileTransferChannel class represents a Telepathy channel of type * FileTransfer. * * For more specialized file transfer classes, please refer to * OutgoingFileTransferChannel and IncomingFileTransferChannel. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * FileTransferChannel object usable. * * Note that this feature must be enabled in order to use most * FileTransferChannel methods. * See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature FileTransferChannel::FeatureCore = Feature(QLatin1String(FileTransferChannel::staticMetaObject.className()), 0); /** * Create a new FileTransferChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A FileTransferChannelPtr object pointing to the newly created * FileTransferChannel object. */ FileTransferChannelPtr FileTransferChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return FileTransferChannelPtr(new FileTransferChannel(connection, objectPath, immutableProperties, FileTransferChannel::FeatureCore)); } /** * Construct a new FileTransferChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on FileTransferChannel::FeatureCore. */ FileTransferChannel::FileTransferChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : Channel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ FileTransferChannel::~FileTransferChannel() { delete mPriv; } /** * Return the state of the file transfer as described by #FileTransferState. * * Change notification is via the stateChanged() signal. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The state as #FileTransferState. * \sa stateReason() */ FileTransferState FileTransferChannel::state() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling state"; } return (FileTransferState) mPriv->state; } /** * Return the reason for the state change as described by the #FileTransferStateChangeReason. * * Change notification is via the stateChanged() signal. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The state reason as #FileTransferStateChangeReason. * \sa state() */ FileTransferStateChangeReason FileTransferChannel::stateReason() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling stateReason"; } return (FileTransferStateChangeReason) mPriv->stateReason; } /** * Return the name of the file on the sender's side. This is given as * a suggested filename for the receiver. * * This property should be the basename of the file being sent. For example, if * the sender sends the file /home/user/monkey.pdf then this property should be * set to monkey.pdf. * * This property cannot change once the channel has been created. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The suggested filename for the receiver. */ QString FileTransferChannel::fileName() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling fileName"; } return mPriv->fileName; } /** * Return the file's MIME type. * * This property cannot change once the channel has been created. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The file's MIME type. */ QString FileTransferChannel::contentType() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling contentType"; } return mPriv->contentType; } /** * Return the size of the file. * * Note that the size is not guaranteed to be exactly right for * incoming files. This is merely a hint and should not be used to know when the * transfer finished. * * For unknown sizes the return value can be UINT64_MAX. * * This property cannot change once the channel has been created. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The file size. */ qulonglong FileTransferChannel::size() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling size"; } return mPriv->size; } /** * Return the URI of the file. * * On outgoing file transfers, this property cannot change after the channel * is requested. For incoming file transfers, this property may be set by the * channel handler before calling AcceptFile to inform observers where the * incoming file will be saved. When the URI property is set, the signal * IncomingFileTransferChannel::uriDefined() is emitted. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The file uri. * \sa IncomingFileTransferChannel::uriDefined() */ QString FileTransferChannel::uri() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling uri"; } return mPriv->uri; } /** * Return the type of the contentHash(). * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The content hash type as #FileHashType. * \sa contentHash() */ FileHashType FileTransferChannel::contentHashType() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling contentHashType"; } return mPriv->contentHashType; } /** * Return the hash of the contents of the file transfer, of type described in * the value of the contentHashType(). * * Its value MUST correspond to the appropriate type of the contentHashType(). * If the contentHashType() is set to #FileHashTypeNone, then the * returned value is an empty string. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The hash of the contents. * \sa contentHashType() */ QString FileTransferChannel::contentHash() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling contentHash"; } if (mPriv->contentHashType == FileHashTypeNone) { return QString(); } return mPriv->contentHash; } /** * Return the description of the file transfer. * * This property cannot change once the channel has been created. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The description. */ QString FileTransferChannel::description() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling description"; } return mPriv->description; } /** * Return the last modification time of the file being transferred. This cannot * change once the channel has been created. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The file modification time as QDateTime. */ QDateTime FileTransferChannel::lastModificationTime() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling lastModificationTime"; } return mPriv->lastModificationTime; } /** * Return the offset in bytes from which the file will be sent. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The offset in bytes. * \sa initialOffsetDefined() */ qulonglong FileTransferChannel::initialOffset() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling initialOffset"; } return mPriv->initialOffset; } /** * Return the number of bytes that have been transferred. * * Change notification is via the transferredBytesChanged() signal. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The number of bytes. * \sa transferredBytesChanged() */ qulonglong FileTransferChannel::transferredBytes() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling transferredBytes"; } return mPriv->transferredBytes; } /** * Return a mapping from address types (members of #SocketAddressType) to arrays * of access-control type (members of #SocketAccessControl) that the CM * supports for sockets with that address type. * * For simplicity, if a CM supports offering a particular type of file transfer, * it is assumed to support accepting it. All CMs support at least * SocketAddressTypeIPv4. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \return The available socket types as a map from address types to arrays of access-control type. */ SupportedSocketMap FileTransferChannel::availableSocketTypes() const { if (!isReady(FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling availableSocketTypes"; } return mPriv->availableSocketTypes; } /** * Cancel a file transfer. * * \return A PendingOperation object which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *FileTransferChannel::cancel() { return requestClose(); } /** * Protected virtual method called when the state becomes * #FileTransferStateOpen. * * Specialized classes should reimplement this method and call setConnected() * when the connection is established. * * \sa setConnected() */ void FileTransferChannel::connectToHost() { // do nothing } /** * Return whether a connection has been established. * * \return \c true if the connections has been established, \c false otherwise. * \sa setConnected() */ bool FileTransferChannel::isConnected() const { return mPriv->connected; } /** * Indicate whether a connection has been established. * * Specialized classes that reimplement connectToHost() must call this method * once the connection has been established or setFinished() if an error * occurred. * * \sa isConnected(), connectToHost(), setFinished() */ void FileTransferChannel::setConnected() { mPriv->connected = true; } /** * Return whether sending/receiving has finished. * * \return \c true if sending/receiving has finished, \c false otherwise. */ bool FileTransferChannel::isFinished() const { return mPriv->finished; } /** * Protected virtual method called when an error occurred and the transfer * should finish. * * Specialized classes should reimplement this method and close the IO devices * and do all the needed cleanup. * * Note that for specialized classes that reimplement connectToHost() and set * isConnected() to true, the state will not change to * #FileTransferStateCompleted once the state change is received. * * When finished sending/receiving the specialized class MUST call this method * and then the state will change to the latest pending state. */ void FileTransferChannel::setFinished() { mPriv->finished = true; // do the actual state change, in case we are in // FileTransferStateCompleted pendingState changeState(); } void FileTransferChannel::gotProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { QVariantMap props = reply.value(); mPriv->extractProperties(props); debug() << "Got reply to Properties::GetAll(FileTransferChannel)"; mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } else { warning().nospace() << "Properties::GetAll(FileTransferChannel) failed " "with " << reply.error().name() << ": " << reply.error().message(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); } } void FileTransferChannel::changeState() { if (mPriv->state == mPriv->pendingState) { return; } mPriv->state = mPriv->pendingState; mPriv->stateReason = mPriv->pendingStateReason; emit stateChanged((FileTransferState) mPriv->state, (FileTransferStateChangeReason) mPriv->stateReason); } void FileTransferChannel::onStateChanged(uint state, uint stateReason) { if (state == (uint) mPriv->pendingState) { return; } debug() << "File transfer state changed to" << state << "with reason" << stateReason; mPriv->pendingState = (FileTransferState) state; mPriv->pendingStateReason = (FileTransferStateChangeReason) stateReason; switch (state) { case FileTransferStateOpen: // try to connect to host, for handlers this // connect to host, as the user called Accept/ProvideFile // and have the host addr, for observers this will do nothing and // everything will keep working connectToHost(); changeState(); break; case FileTransferStateCompleted: //iIf already finished sending/receiving, just change the state, // if not completed will only be set when: // IncomingChannel: // - The input socket closes // OutgoingChannel: // - Input EOF is reached or the output socket is closed // // we also check for connected as observers will never be connected // and finished will never be set, but we need to work anyway. if (mPriv->finished || !mPriv->connected) { changeState(); } break; case FileTransferStateCancelled: // if already finished sending/receiving, just change the state, // if not finish now and change the state if (!mPriv->finished) { setFinished(); } else { changeState(); } break; default: changeState(); break; } } void FileTransferChannel::onInitialOffsetDefined(qulonglong initialOffset) { mPriv->initialOffset = initialOffset; emit initialOffsetDefined(initialOffset); } void FileTransferChannel::onTransferredBytesChanged(qulonglong count) { mPriv->transferredBytes = count; emit transferredBytesChanged(count); } void FileTransferChannel::onUriDefined(const QString &uri) { mPriv->uri = uri; // Signal is emitted only by IncomingFileTransferChannels } /** * \fn void FileTransferChannel::stateChanged(Tp::FileTransferState state, * Tp::FileTransferStateChangeReason reason) * * Emitted when the value of state() changes. * * \param state The new state of this file transfer channel. * \param reason The reason for the change of state. * \sa state() */ /** * \fn void FileTransferChannel::initialOffsetDefined(qulonglong initialOffset) * * Emitted when the initial offset for the file transfer is * defined. * * \param initialOffset The new initial offset for the file transfer. * \sa initialOffset() */ /** * \fn void FileTransferChannel::transferredBytesChanged(qulonglong count); * * Emitted when the value of transferredBytes() changes. * * \param count The new number of bytes transferred. * \sa transferredBytes() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/AbstractInterface0000664000175000017500000000040212470405660020517 0ustar jrjr#ifndef _TelepathyQt_AbstractInterface_HEADER_GUARD_ #define _TelepathyQt_AbstractInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/connection-factory.cpp0000664000175000017500000001371112470405660021527 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include namespace Tp { /** * \class ConnectionFactory * \ingroup utils * \headerfile TelepathyQt/connection-factory.h * * \brief The ConnectionFactory class is responsible for constructing Connection * objects according to application-defined settings. * * The class is used by Account and other classes which construct Connection proxy * instances to enable sharing instances of application-defined Connection * subclasses with certain features always ready. */ /** * Create a new ConnectionFactory object. * * Optionally, the \a features to make ready on all constructed proxies can be specified. The * default is to make no features ready. It should be noted that unlike Connection::becomeReady(), * FeatureCore isn't assumed. If no features are specified, which is the default behavior, no * Connection::becomeReady() call is made at all and the proxy won't be Connection::isReady(). * * \param bus The QDBusConnection for proxies constructed using this factory to use. * \param features The features to make ready on constructed Connections. * \return A ConnectionFactoryPtr object pointing to the newly created * ConnectionFactory object. */ ConnectionFactoryPtr ConnectionFactory::create(const QDBusConnection &bus, const Features &features) { return ConnectionFactoryPtr(new ConnectionFactory(bus, features)); } /** * Construct a new ConnectionFactory object. * * As in create(), it should be noted that unlike Connection::becomeReady(), FeatureCore isn't * assumed. If no \a features are specified, no Connection::becomeReady() call is made at all and * the proxy won't be Connection::isReady(). * * \param bus The QDBusConnection for proxies constructed using this factory to use. * \param features The features to make ready on constructed Connections. */ ConnectionFactory::ConnectionFactory(const QDBusConnection &bus, const Features &features) : FixedFeatureFactory(bus) { addFeatures(features); } /** * Class destructor. */ ConnectionFactory::~ConnectionFactory() { } /** * Constructs a Connection proxy and begins making it ready. * * If a valid proxy already exists in the factory cache for the given combination of \a busName and * \a objectPath, it is returned instead. All newly created proxies are automatically cached until * they're either DBusProxy::invalidated() or the last reference to them outside the factory has * been dropped. * * The proxy can be accessed immediately after this function returns using PendingReady::proxy(). * The ready operation only finishes, however, when the features specified by features(), if any, * are made ready as much as possible. If the service doesn't support a given feature, they won't * obviously be ready even if the operation finished successfully, as is the case for * Connection::becomeReady(). * * \param busName The bus/service name of the D-Bus connection object the proxy is constructed for. * \param objectPath The object path of the connection. * \param chanFactory The channel factory to use for the Connection. * \param contactFactory The channel factory to use for the Connection. * \return A PendingReady operation with the proxy in PendingReady::proxy(). */ PendingReady *ConnectionFactory::proxy(const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const { DBusProxyPtr proxy = cachedProxy(busName, objectPath); if (proxy.isNull()) { proxy = construct(busName, objectPath, chanFactory, contactFactory); } return nowHaveProxy(proxy); } /** * Can be used by subclasses to override the Connection subclass constructed by the factory. * * This is automatically called by proxy() to construct proxy instances if no valid cached proxy is * found. * * The default implementation constructs Tp::Connection objects. * * \param busName The bus/service name of the D-Bus Connection object the proxy is constructed for. * \param objectPath The object path of the connection. * \param chanFactory The channel factory to use for the Connection. * \param contactFactory The channel factory to use for the Connection. * \return A pointer to the constructed Connection object. */ ConnectionPtr ConnectionFactory::construct(const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const { return Connection::create(dbusConnection(), busName, objectPath, chanFactory, contactFactory); } /** * Transforms well-known names to the corresponding unique names, as is appropriate for Connection * * \param uniqueOrWellKnown The name to transform. * \return The unique name corresponding to \a uniqueOrWellKnown (which may be it itself). */ QString ConnectionFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const { return StatefulDBusProxy::uniqueNameFrom(dbusConnection(), uniqueOrWellKnown); } } telepathy-qt-0.9.6~git1/TelepathyQt/dbus-error.cpp0000664000175000017500000000747112470405660020015 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include namespace Tp { struct TP_QT_NO_EXPORT DBusError::Private { Private(const QString &name, const QString &message) : name(name), message(message) { } QString name; QString message; }; /** * \class DBusError * \ingroup servicesideimpl * \headerfile TelepathyQt/dbus-error.h * * \brief Small container class, containing a D-Bus error */ /** * Construct an empty DBusError */ DBusError::DBusError() : mPriv(0) { } /** * Construct a DBusError with the given error \a name and \a message. * * \param name The D-Bus error name. * \param message A human-readable description of the error. */ DBusError::DBusError(const QString &name, const QString &message) : mPriv(new Private(name, message)) { } /** * Class destructor. */ DBusError::~DBusError() { } /** * Compare this error with another one. * * \param other The other error to compare to. * \return \c true if the two errors have the same name and message * or \c false otherwise. */ bool DBusError::operator==(const DBusError &other) const { if (!isValid() || !other.isValid()) { if (!isValid() && !other.isValid()) { return true; } return false; } return mPriv->name == other.mPriv->name && mPriv->message == other.mPriv->message; } /** * Compare this error with another one. * * \param other The other error to compare to. * \return \c false if the two errors have the same name and message * or \c true otherwise. */ bool DBusError::operator!=(const DBusError &other) const { if (!isValid() || !other.isValid()) { if (!isValid() && !other.isValid()) { return false; } return true; } return mPriv->name != other.mPriv->name || mPriv->message != other.mPriv->message; } /** * Return the D-Bus name of this error. * * \return The D-Bus name of this error. */ QString DBusError::name() const { if (!isValid()) { return QString(); } return mPriv->name; } /** * Return the human-readable description of the error. * * \return The human-readable description of the error. */ QString DBusError::message() const { if (!isValid()) { return QString(); } return mPriv->message; } /** * Set this DBusError to contain the given error \a name and \a message. * * \param name The D-Bus error name to set. * \param message The description of the error to set. */ void DBusError::set(const QString &name, const QString &message) { if (!isValid()) { mPriv = new Private(name, message); return; } mPriv->name = name; mPriv->message = message; } /** * \fn bool DBusError::isValid() const * * Return whether this DBusError is set to contain an error or not. * * \return \c true if the error name and message have been set, * or \c false otherwise. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/tls-certificate.xml0000664000175000017500000000036312470405660021022 0ustar jrjr TLSCertificate telepathy-qt-0.9.6~git1/TelepathyQt/StatelessDBusProxy0000664000175000017500000000037412470405660020732 0ustar jrjr#ifndef _TelepathyQt_StatelessDBusProxy_HEADER_GUARD_ #define _TelepathyQt_StatelessDBusProxy_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/method-invocation-context.dox0000664000175000017500000000345312470405660023046 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \class Tp::MethodInvocationContext * \ingroup utils * \headerfile TelepathyQt/method-invocation-context.h * * \brief The MethodInvocationContext class provides a way for the service implementation to * respond to method calls. * * The methods setFinished() and setFinishedWithError() can be used to indicate * whether the method call succeeded or failed. * * If neither setFinished() nor setFinishedWithError() is called explicitly, * the method call will be considered to have failed. * " In case an asynchronous operation needs to be performed when implementing a method call * receiving a MethodInvocationContextPtr object, a reference to this object may be kept around * until all asynchronous operations finish, and the appropriate finish method * should be called to indicate whether the method call succeeded or failed later. */ telepathy-qt-0.9.6~git1/TelepathyQt/ContactFactory0000664000175000017500000000037112470405660020063 0ustar jrjr#ifndef _TelepathyQt_ContactFactory_HEADER_GUARD_ #define _TelepathyQt_ContactFactory_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/message-content-part.cpp0000664000175000017500000000462112470405660021763 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include namespace Tp { struct TP_QT_NO_EXPORT MessageContentPart::Private : public QSharedData { Private(const MessagePart &mp) : mp(mp) {} MessagePart mp; }; /** * \class MessageContentPart * \ingroup wrappers * \headerfile TelepathyQt/message-content-part.h * * \brief The MessageContentPart class represents a Telepathy message part. */ MessageContentPart::MessageContentPart() { } MessageContentPart::MessageContentPart(const MessagePart &mp) : mPriv(new Private(mp)) { } MessageContentPart::MessageContentPart(const MessageContentPart &other) : mPriv(other.mPriv) { } MessageContentPart::~MessageContentPart() { } MessageContentPart &MessageContentPart::operator=(const MessageContentPart &other) { this->mPriv = other.mPriv; return *this; } bool MessageContentPart::operator==(const MessageContentPart &other) const { if (!isValid() || !other.isValid()) { if (!isValid() && !other.isValid()) { return true; } return false; } return mPriv->mp == other.mPriv->mp; } MessagePart MessageContentPart::barePart() const { return isValid() ? mPriv->mp : MessagePart(); } /** * \class MessageContentPartList * \ingroup wrappers * \headerfile TelepathyQt/message-content-part.h * * \brief The MessageContentPartList class represents a list of * MessageContentPart. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/PendingStringList0000664000175000017500000000040312470405660020543 0ustar jrjr#ifndef _TelepathyQt_PendingStringList_HEADER_GUARD_ #define _TelepathyQt_PendingStringList_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/simple-stream-tube-handler.cpp0000664000175000017500000002066112470405660023057 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/simple-stream-tube-handler.h" #include "TelepathyQt/_gen/simple-stream-tube-handler.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include namespace Tp { namespace { ChannelClassSpecList buildFilter(const QStringList &p2pServices, const QStringList &roomServices, bool requested) { ChannelClassSpecList filter; // Convert to QSet to weed out duplicates foreach (const QString &service, p2pServices.toSet()) { filter.append(requested ? ChannelClassSpec::outgoingStreamTube(service) : ChannelClassSpec::incomingStreamTube(service)); } // Convert to QSet to weed out duplicates foreach (const QString &service, roomServices.toSet()) { filter.append(requested ? ChannelClassSpec::outgoingRoomStreamTube(service) : ChannelClassSpec::incomingRoomStreamTube(service)); } return filter; } } SharedPtr SimpleStreamTubeHandler::create( const QStringList &p2pServices, const QStringList &roomServices, bool requested, bool monitorConnections, bool bypassApproval) { return SharedPtr( new SimpleStreamTubeHandler( p2pServices, roomServices, requested, monitorConnections, bypassApproval)); } SimpleStreamTubeHandler::SimpleStreamTubeHandler( const QStringList &p2pServices, const QStringList &roomServices, bool requested, bool monitorConnections, bool bypassApproval) : AbstractClient(), AbstractClientHandler(buildFilter(p2pServices, roomServices, requested)), mMonitorConnections(monitorConnections), mBypassApproval(bypassApproval) { } SimpleStreamTubeHandler::~SimpleStreamTubeHandler() { if (!mTubes.empty()) { debug() << "~SSTubeHandler(): Closing" << mTubes.size() << "leftover tubes"; foreach (const StreamTubeChannelPtr &tube, mTubes.keys()) { tube->requestClose(); } } } void SimpleStreamTubeHandler::handleChannels( const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const QList &requestsSatisfied, const QDateTime &userActionTime, const HandlerInfo &handlerInfo) { debug() << "SimpleStreamTubeHandler::handleChannels() invoked for " << channels.size() << "channels on account" << account->objectPath(); SharedPtr invocation(new InvocationData()); QList readyOps; foreach (const ChannelPtr &chan, channels) { StreamTubeChannelPtr tube = StreamTubeChannelPtr::qObjectCast(chan); if (!tube) { // TODO: if Channel ever starts utilizing its immutable props for the immutable // accessors, use Channel::channelType() here const QString channelType = chan->immutableProperties()[TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")].toString(); if (channelType != TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE) { debug() << "We got a non-StreamTube channel" << chan->objectPath() << "of type" << channelType << ", ignoring"; } else { warning() << "The channel factory used for a simple StreamTube handler must" << "construct StreamTubeChannel subclasses for stream tubes"; } continue; } Features features = StreamTubeChannel::FeatureCore; if (mMonitorConnections) { features.insert(StreamTubeChannel::FeatureConnectionMonitoring); } readyOps.append(tube->becomeReady(features)); invocation->tubes.append(tube); } invocation->ctx = context; invocation->acc = account; invocation->time = userActionTime; if (!requestsSatisfied.isEmpty()) { invocation->hints = requestsSatisfied.first()->hints(); } mInvocations.append(invocation); if (invocation->tubes.isEmpty()) { warning() << "SSTH::HandleChannels got no suitable channels, admitting we're Confused"; invocation->readyOp = 0; invocation->error = TP_QT_ERROR_CONFUSED; invocation->message = QLatin1String("Got no suitable channels"); onReadyOpFinished(0); } else { invocation->readyOp = new PendingComposite(readyOps, SharedPtr(this)); connect(invocation->readyOp, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onReadyOpFinished(Tp::PendingOperation*))); } } void SimpleStreamTubeHandler::onReadyOpFinished(Tp::PendingOperation *op) { Q_ASSERT(!mInvocations.isEmpty()); Q_ASSERT(!op || op->isFinished()); for (QLinkedList >::iterator i = mInvocations.begin(); op != 0 && i != mInvocations.end(); ++i) { if ((*i)->readyOp != op) { continue; } (*i)->readyOp = 0; if (op->isError()) { warning() << "Preparing proxies for SSTubeHandler failed with" << op->errorName() << op->errorMessage(); (*i)->error = op->errorName(); (*i)->message = op->errorMessage(); } break; } while (!mInvocations.isEmpty() && !mInvocations.first()->readyOp) { SharedPtr invocation = mInvocations.takeFirst(); if (!invocation->error.isEmpty()) { // We guarantee that the proxies were ready - so we can't invoke the client if they // weren't made ready successfully. Fix the introspection code if this happens :) invocation->ctx->setFinishedWithError(invocation->error, invocation->message); continue; } debug() << "Emitting SSTubeHandler::invokedForTube for" << invocation->tubes.size() << "tubes"; foreach (const StreamTubeChannelPtr &tube, invocation->tubes) { if (!tube->isValid()) { debug() << "Skipping already invalidated tube" << tube->objectPath(); continue; } if (!mTubes.contains(tube)) { connect(tube.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onTubeInvalidated(Tp::DBusProxy*,QString,QString))); mTubes.insert(tube, invocation->acc); } emit invokedForTube( invocation->acc, tube, invocation->time, invocation->hints); } invocation->ctx->setFinished(); } } void SimpleStreamTubeHandler::onTubeInvalidated(DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { StreamTubeChannelPtr tube(qobject_cast(proxy)); Q_ASSERT(!tube.isNull()); Q_ASSERT(mTubes.contains(tube)); debug() << "Tube" << tube->objectPath() << "invalidated - " << errorName << ':' << errorMessage; AccountPtr acc = mTubes.value(tube); mTubes.remove(tube); emit tubeInvalidated( acc, tube, errorName, errorMessage); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceServicePointInterface0000664000175000017500000000043712470405660024510 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceServicePointInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceServicePointInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/feature.cpp0000664000175000017500000000404212470405660017353 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include namespace Tp { struct TP_QT_NO_EXPORT Feature::Private : public QSharedData { Private(bool critical) : critical(critical) {} bool critical; }; /** * \class Feature * \ingroup utils * \headerfile TelepathyQt/feature.h * * \brief The Feature class represents a feature that can be enabled * on demand. */ Feature::Feature() : QPair() { } Feature::Feature(const QString &className, uint id, bool critical) : QPair(className, id), mPriv(new Private(critical)) { } Feature::Feature(const Feature &other) : QPair(other.first, other.second), mPriv(other.mPriv) { } Feature::~Feature() { } Feature &Feature::operator=(const Feature &other) { *this = other; this->mPriv = other.mPriv; return *this; } bool Feature::isCritical() const { if (!isValid()) { return false; } return mPriv->critical; } /** * \class Features * \ingroup utils * \headerfile TelepathyQt/feature.h * * \brief The Features class represents a list of Feature. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/channel-class-spec.cpp0000664000175000017500000005002512470405660021365 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/future-constants.h" #include "TelepathyQt/debug-internal.h" namespace Tp { struct TP_QT_NO_EXPORT ChannelClassSpec::Private : public QSharedData { QVariantMap props; }; /** * \class ChannelClassSpec * \ingroup wrappers * \headerfile TelepathyQt/channel-class-spec.h * * \brief The ChannelClassSpec class represents a Telepathy channel class. */ ChannelClassSpec::ChannelClassSpec() { } ChannelClassSpec::ChannelClassSpec(const ChannelClass &cc) : mPriv(new Private) { foreach (QString key, cc.keys()) { setProperty(key, cc.value(key).variant()); } } ChannelClassSpec::ChannelClassSpec(const QVariantMap &props) : mPriv(new Private) { setChannelType(qdbus_cast( props.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")))); setTargetHandleType((HandleType) qdbus_cast( props.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")))); foreach (QString propName, props.keys()) { setProperty(propName, props.value(propName)); } } ChannelClassSpec::ChannelClassSpec(const QString &channelType, HandleType targetHandleType, const QVariantMap &otherProperties) : mPriv(new Private) { setChannelType(channelType); setTargetHandleType(targetHandleType); foreach (QString key, otherProperties.keys()) { setProperty(key, otherProperties.value(key)); } } ChannelClassSpec::ChannelClassSpec(const QString &channelType, HandleType targetHandleType, bool requested, const QVariantMap &otherProperties) : mPriv(new Private) { setChannelType(channelType); setTargetHandleType(targetHandleType); setRequested(requested); foreach (QString key, otherProperties.keys()) { setProperty(key, otherProperties.value(key)); } } ChannelClassSpec::ChannelClassSpec(const ChannelClassSpec &other, const QVariantMap &additionalProperties) : mPriv(other.mPriv) { if (!additionalProperties.isEmpty()) { foreach (QString key, additionalProperties.keys()) { setProperty(key, additionalProperties.value(key)); } } } ChannelClassSpec::~ChannelClassSpec() { } bool ChannelClassSpec::isValid() const { return mPriv.constData() != 0 && !(qdbus_cast( mPriv->props.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"))) .isEmpty()) && mPriv->props.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")); } ChannelClassSpec &ChannelClassSpec::operator=(const ChannelClassSpec &other) { if (this == &other) { return *this; } this->mPriv = other.mPriv; return *this; } bool ChannelClassSpec::isSubsetOf(const ChannelClassSpec &other) const { if (!mPriv) { // Invalid instances have no properties - hence they're subset of anything return true; } foreach (QString propName, mPriv->props.keys()) { if (!other.hasProperty(propName)) { return false; } else if (property(propName) != other.property(propName)) { return false; } } // other had all of the properties we have and they all had the same values return true; } bool ChannelClassSpec::matches(const QVariantMap &immutableProperties) const { // We construct a ChannelClassSpec for comparison so the StreamedMedia props are normalized // consistently etc return this->isSubsetOf(ChannelClassSpec(immutableProperties)); } bool ChannelClassSpec::hasProperty(const QString &qualifiedName) const { return mPriv.constData() != 0 ? mPriv->props.contains(qualifiedName) : false; } QVariant ChannelClassSpec::property(const QString &qualifiedName) const { return mPriv.constData() != 0 ? mPriv->props.value(qualifiedName) : QVariant(); } void ChannelClassSpec::setProperty(const QString &qualifiedName, const QVariant &value) { if (mPriv.constData() == 0) { mPriv = new Private; } mPriv->props.insert(qualifiedName, value); } void ChannelClassSpec::unsetProperty(const QString &qualifiedName) { if (mPriv.constData() == 0) { // No properties set for sure, so don't have to unset any return; } mPriv->props.remove(qualifiedName); } QVariantMap ChannelClassSpec::allProperties() const { return mPriv.constData() != 0 ? mPriv->props : QVariantMap(); } ChannelClass ChannelClassSpec::bareClass() const { ChannelClass cc; if (!isValid()) { warning() << "Tried to convert an invalid ChannelClassSpec to a ChannelClass"; return ChannelClass(); } QVariantMap props = mPriv->props; foreach (QString propName, props.keys()) { QVariant value = props.value(propName); cc.insert(propName, QDBusVariant(value)); } return cc; } ChannelClassSpec ChannelClassSpec::textChat(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_TEXT, HandleTypeContact); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::textChatroom(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_TEXT, HandleTypeRoom); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::unnamedTextChat(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_TEXT, HandleTypeNone); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::mediaCall(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.isValid()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_CALL, HandleTypeContact); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::audioCall(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.isValid()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_CALL, HandleTypeContact); spec.setCallInitialAudioFlag(); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::videoCall(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.isValid()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_CALL, HandleTypeContact); spec.setCallInitialVideoFlag(); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::videoCallWithAudio(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.isValid()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_CALL, HandleTypeContact); spec.setCallInitialAudioFlag(); spec.setCallInitialVideoFlag(); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::streamedMediaCall(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, HandleTypeContact); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::streamedMediaAudioCall(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, HandleTypeContact); spec.setStreamedMediaInitialAudioFlag(); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::streamedMediaVideoCall(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, HandleTypeContact); spec.setStreamedMediaInitialVideoFlag(); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::streamedMediaVideoCallWithAudio(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, HandleTypeContact); spec.setStreamedMediaInitialAudioFlag(); spec.setStreamedMediaInitialVideoFlag(); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::unnamedStreamedMediaCall(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, HandleTypeNone); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::unnamedStreamedMediaAudioCall(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, HandleTypeNone); spec.setStreamedMediaInitialAudioFlag(); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::unnamedStreamedMediaVideoCall(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, HandleTypeNone); spec.setStreamedMediaInitialVideoFlag(); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::unnamedStreamedMediaVideoCallWithAudio(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, HandleTypeNone); spec.setStreamedMediaInitialAudioFlag(); spec.setStreamedMediaInitialVideoFlag(); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } Tp::ChannelClassSpec ChannelClassSpec::serverAuthentication(const QVariantMap &additionalProperties) { static Tp::ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION, HandleTypeNone); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::roomList(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_ROOM_LIST, HandleTypeNone); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::outgoingFileTransfer(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER, HandleTypeContact, true); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::incomingFileTransfer(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER, HandleTypeContact, false); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::outgoingStreamTube(const QString &service, const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE, HandleTypeContact, true); } QVariantMap props = additionalProperties; if (!service.isEmpty()) { props.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QLatin1String(".Service"), service); } if (props.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, props); } } ChannelClassSpec ChannelClassSpec::incomingStreamTube(const QString &service, const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE, HandleTypeContact, false); } QVariantMap props = additionalProperties; if (!service.isEmpty()) { props.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QLatin1String(".Service"), service); } if (props.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, props); } } ChannelClassSpec ChannelClassSpec::outgoingRoomStreamTube(const QString &service, const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE, HandleTypeRoom, true); } QVariantMap props = additionalProperties; if (!service.isEmpty()) { props.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QLatin1String(".Service"), service); } if (props.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, props); } } ChannelClassSpec ChannelClassSpec::incomingRoomStreamTube(const QString &service, const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE, HandleTypeRoom, false); } QVariantMap props = additionalProperties; if (!service.isEmpty()) { props.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QLatin1String(".Service"), service); } if (props.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, props); } } ChannelClassSpec ChannelClassSpec::outgoingDBusTube(const QString &serviceName, const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.isValid()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE, HandleTypeContact, true); } if (!serviceName.isEmpty()) { spec.setProperty(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName"), serviceName); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::incomingDBusTube(const QString &serviceName, const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.isValid()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE, HandleTypeContact, false); } if (!serviceName.isEmpty()) { spec.setProperty(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName"), serviceName); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } ChannelClassSpec ChannelClassSpec::outgoingRoomDBusTube(const QString &serviceName, const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE, HandleTypeRoom, true); } QVariantMap props = additionalProperties; if (!serviceName.isEmpty()) { props.insert(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName"), serviceName); } if (props.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, props); } } ChannelClassSpec ChannelClassSpec::incomingRoomDBusTube(const QString &serviceName, const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE, HandleTypeRoom, false); } QVariantMap props = additionalProperties; if (!serviceName.isEmpty()) { props.insert(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName"), serviceName); } if (props.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, props); } } ChannelClassSpec ChannelClassSpec::contactSearch(const QVariantMap &additionalProperties) { static ChannelClassSpec spec; if (!spec.mPriv.constData()) { spec = ChannelClassSpec(TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, HandleTypeNone); } if (additionalProperties.isEmpty()) { return spec; } else { return ChannelClassSpec(spec, additionalProperties); } } /** * \class ChannelClassSpecList * \ingroup wrappers * \headerfile TelepathyQt/channel-class-spec.h * * \brief The ChannelClassSpecList class represents a list of ChannelClassSpec. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/generic-property-filter.h0000664000175000017500000000426612470405660022156 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_generic_property_filter_h_HEADER_GUARD_ #define _TelepathyQt_generic_property_filter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { template class GenericPropertyFilter : public Filter { public: inline virtual ~GenericPropertyFilter() { } inline virtual bool isValid() const { return true; } inline virtual bool matches(const SharedPtr &t) const { for (QVariantMap::const_iterator i = mFilter.constBegin(); i != mFilter.constEnd(); ++i) { QString propertyName = i.key(); QVariant propertyValue = i.value(); if (t->property(propertyName.toLatin1().constData()) != propertyValue) { return false; } } return true; } inline QVariantMap filter() const { return mFilter; } inline void addProperty(const QString &propertyName, const QVariant &propertyValue) { mFilter.insert(propertyName, propertyValue); } inline void setProperties(const QVariantMap &filter) { mFilter = filter; } protected: inline GenericPropertyFilter() : Filter() { } private: QVariantMap mFilter; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/CallContentInterfaceDTMFInterface0000664000175000017500000000043412470405660023463 0ustar jrjr#ifndef _TelepathyQt_CallContentInterfaceDTMFInterface_HEADER_GUARD_ #define _TelepathyQt_CallContentInterfaceDTMFInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/TubeChannel0000664000175000017500000000036012470405660017326 0ustar jrjr#ifndef _TelepathyQt_TubeChannel_HEADER_GUARD_ #define _TelepathyQt_TubeChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/outgoing-dbus-tube-channel.cpp0000664000175000017500000001646212470405660023062 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/outgoing-dbus-tube-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT OutgoingDBusTubeChannel::Private { Private(OutgoingDBusTubeChannel *parent); // Public object OutgoingDBusTubeChannel *parent; }; OutgoingDBusTubeChannel::Private::Private(OutgoingDBusTubeChannel *parent) : parent(parent) { } /** * \class OutgoingDBusTubeChannel * \ingroup clientchannel * \headerfile TelepathyQt/outgoing-dbus-tube-channel.h * * \brief The OutgoingDBusTubeChannel class represents an outgoing Telepathy channel * of type DBusTube. * * Outgoing (locally initiated/requested) tubes are initially in the #TubeChannelStateNotOffered state. * When offerTube is called, the connection manager takes care of instantiating a new DBus server, * at which point the tube state becomes #TubeChannelStateRemotePending. * * If the target accepts the connection request, the state goes #TubeChannelStateOpen and both sides * can start using the new private bus, the address of which can be retrieved from the completed * PendingDBusTubeConnection or from this class. * * \note If you plan to use QtDBus for the DBus connection, please note you should always use * QDBusConnection::connectToPeer(), regardless of the fact this tube is a p2p or a group one. * The above function has been introduced in Qt 4.8, previous versions of Qt do not allow the use * of DBus Tubes through QtDBus. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Create a new OutgoingDBusTubeChannel channel. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The object path of this channel. * \param immutableProperties The immutable properties of this channel. * \return A OutgoingDBusTubeChannelPtr object pointing to the newly created * OutgoingDBusTubeChannel object. */ OutgoingDBusTubeChannelPtr OutgoingDBusTubeChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return OutgoingDBusTubeChannelPtr(new OutgoingDBusTubeChannel(connection, objectPath, immutableProperties)); } /** * Construct a new OutgoingDBusTubeChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The object path of this channel. * \param immutableProperties The immutable properties of this channel. */ OutgoingDBusTubeChannel::OutgoingDBusTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) : DBusTubeChannel(connection, objectPath, immutableProperties), mPriv(new Private(this)) { } /** * Class destructor. */ OutgoingDBusTubeChannel::~OutgoingDBusTubeChannel() { delete mPriv; } /** * Offer the tube * * This method sets up a private DBus connection to the channel target(s), and offers it through the tube. * * The %PendingDBusTubeConnection returned by this method will be completed as soon as the tube is * opened and ready to be used. * * This method requires DBusTubeChannel::FeatureCore to be enabled. * * \param parameters A dictionary of arbitrary Parameters to send with the tube offer. * The other end will receive this QVariantMap in the parameters() method * of the corresponding IncomingDBusTubeChannel. * \param allowOtherUsers Whether the server should allow other users to connect to this tube more * than just the current one. If your application has no specific needs, it is * advisable not to modify the default value of this argument. * * \note If allowOtherUsers == false, but one of the ends does not support current user restriction, * the tube will be offered regardless, falling back to allowing any connection. If your * application requires strictly this condition to be enforced, you should check * DBusTubeChannel::supportsRestrictingToCurrentUser before offering the tube, * and take action from there. * The tube is guaranteed either to be offered with the desired * restriction or to fail the accept phase if supportsRestrictingToCurrentUser is true * and allowOtherUsers is false. * * \returns A %PendingDBusTubeConnection which will finish as soon as the tube is ready to be used * (hence in the Open state) */ PendingDBusTubeConnection *OutgoingDBusTubeChannel::offerTube(const QVariantMap ¶meters, bool allowOtherUsers) { SocketAccessControl accessControl = allowOtherUsers ? SocketAccessControlLocalhost : SocketAccessControlCredentials; if (!isReady(DBusTubeChannel::FeatureCore)) { warning() << "DBusTubeChannel::FeatureCore must be ready before " "calling offerTube"; return new PendingDBusTubeConnection(QLatin1String(TP_QT_ERROR_NOT_AVAILABLE), QLatin1String("Channel not ready"), OutgoingDBusTubeChannelPtr(this)); } // The tube must be not offered if (state() != TubeChannelStateNotOffered) { warning() << "You can not expose more than a bus for each DBus Tube"; return new PendingDBusTubeConnection(QLatin1String(TP_QT_ERROR_NOT_AVAILABLE), QLatin1String("Channel busy"), OutgoingDBusTubeChannelPtr(this)); } // Let's offer the tube if (!allowOtherUsers && !supportsRestrictingToCurrentUser()) { warning() << "Current user restriction is not available for this tube, " "falling back to allowing any connection"; accessControl = SocketAccessControlLocalhost; } PendingString *ps = new PendingString( interface()->Offer( parameters, accessControl), OutgoingDBusTubeChannelPtr(this)); PendingDBusTubeConnection *op = new PendingDBusTubeConnection(ps, accessControl == SocketAccessControlLocalhost, parameters, OutgoingDBusTubeChannelPtr(this)); return op; } } telepathy-qt-0.9.6~git1/TelepathyQt/abstract-client.h0000664000175000017500000002265012470405660020451 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_abstract_client_h_HEADER_GUARD_ #define _TelepathyQt_abstract_client_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include namespace Tp { class ClientRegistrar; class ChannelClassSpecList; class TP_QT_EXPORT AbstractClient : public RefCounted { Q_DISABLE_COPY(AbstractClient) public: AbstractClient(); virtual ~AbstractClient(); bool isRegistered() const; private: friend class ClientRegistrar; void setRegistered(bool registered); struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT AbstractClientObserver : public virtual AbstractClient { Q_DISABLE_COPY(AbstractClientObserver) public: class ObserverInfo { public: ObserverInfo(const QVariantMap &info = QVariantMap()); ObserverInfo(const ObserverInfo &other); ~ObserverInfo(); ObserverInfo &operator=(const ObserverInfo &other); bool isRecovering() const { return qdbus_cast(allInfo().value(QLatin1String("recovering"))); } QVariantMap allInfo() const; private: struct Private; QSharedDataPointer mPriv; }; virtual ~AbstractClientObserver(); ChannelClassSpecList observerFilter() const; bool shouldRecover() const; virtual void observeChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const ChannelDispatchOperationPtr &dispatchOperation, const QList &requestsSatisfied, const ObserverInfo &observerInfo) = 0; protected: AbstractClientObserver(const ChannelClassSpecList &channelFilter, bool shouldRecover = false); private: struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT AbstractClientApprover : public virtual AbstractClient { Q_DISABLE_COPY(AbstractClientApprover) public: virtual ~AbstractClientApprover(); ChannelClassSpecList approverFilter() const; virtual void addDispatchOperation(const MethodInvocationContextPtr<> &context, const ChannelDispatchOperationPtr &dispatchOperation) = 0; protected: AbstractClientApprover(const ChannelClassSpecList &channelFilter); private: struct Private; friend struct Private; Private *mPriv; }; /* * TODO: use case specific subclasses: * - StreamTubeHandler(QString(List) protocol(s)) * - handleTube(DBusTubeChannelPtr, userActionTime) * - DBusTubeHandler(QString(List) serviceName(s)) * - handleTube(DBusTubeChannelPtr, userActionTime) */ class TP_QT_EXPORT AbstractClientHandler : public virtual AbstractClient { Q_DISABLE_COPY(AbstractClientHandler) public: class Capabilities { public: Capabilities(const QStringList &tokens = QStringList()); Capabilities(const Capabilities &other); ~Capabilities(); Capabilities &operator=(const Capabilities &other); bool hasGTalkP2PNATTraversalToken() const { return hasToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/gtalk-p2p")); } void setGTalkP2PNATTraversalToken() { setToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/gtalk-p2p")); } void unsetGTalkP2PNATTraversalToken() { unsetToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/gtalk-p2p")); } bool hasICEUDPNATTraversalToken() const { return hasToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/ice-udp")); } void setICEUDPNATTraversalToken() { setToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/ice-udp")); } void unsetICEUDPNATTraversalToken() { unsetToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/ice-udp")); } bool hasWLM85NATTraversalToken() const { return hasToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/wlm-8.5")); } void setWLM85NATTraversalToken() { setToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/wlm-8.5")); } void unsetWLM85NATTraversalToken() { unsetToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/wlm-8.5")); } bool hasWLM2009NATTraversalToken() const { return hasToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/wlm-2009")); } void setWLM2009NATTraversalToken() { setToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/wlm-2009")); } void unsetWLM2009NATTraversalToken() { unsetToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/wlm-2009")); } bool hasAudioCodecToken(const QString &mimeSubType) const { return hasToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/audio/") + mimeSubType.toLower()); } void setAudioCodecToken(const QString &mimeSubType) { setToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/audio/") + mimeSubType.toLower()); } void unsetAudioCodecToken(const QString &mimeSubType) { unsetToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/audio/") + mimeSubType.toLower()); } bool hasVideoCodecToken(const QString &mimeSubType) const { return hasToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/video/") + mimeSubType.toLower()); } void setVideoCodecToken(const QString &mimeSubType) { setToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/video/") + mimeSubType.toLower()); } void unsetVideoCodecToken(const QString &mimeSubType) { unsetToken(TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING + QLatin1String("/video/") + mimeSubType.toLower()); } bool hasToken(const QString &token) const; void setToken(const QString &token); void unsetToken(const QString &token); QStringList allTokens() const; private: struct Private; QSharedDataPointer mPriv; }; class HandlerInfo { public: HandlerInfo(const QVariantMap &info = QVariantMap()); HandlerInfo(const HandlerInfo &other); ~HandlerInfo(); HandlerInfo &operator=(const HandlerInfo &other); QVariantMap allInfo() const; private: struct Private; QSharedDataPointer mPriv; }; virtual ~AbstractClientHandler(); ChannelClassSpecList handlerFilter() const; Capabilities handlerCapabilities() const; virtual bool bypassApproval() const = 0; virtual void handleChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const QList &requestsSatisfied, const QDateTime &userActionTime, const HandlerInfo &handlerInfo) = 0; bool wantsRequestNotification() const; virtual void addRequest(const ChannelRequestPtr &request); virtual void removeRequest(const ChannelRequestPtr &request, const QString &errorName, const QString &errorMessage); protected: AbstractClientHandler(const ChannelClassSpecList &channelFilter, const Capabilities &capabilities = Capabilities(), bool wantsRequestNotification = false); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::AbstractClientObserver::ObserverInfo); Q_DECLARE_METATYPE(Tp::AbstractClientHandler::Capabilities); Q_DECLARE_METATYPE(Tp::AbstractClientHandler::HandlerInfo); #endif telepathy-qt-0.9.6~git1/TelepathyQt/debug-receiver.xml0000664000175000017500000000033312470405660020625 0ustar jrjr Debug interface telepathy-qt-0.9.6~git1/TelepathyQt/BaseConnection0000664000175000017500000000037112470405660020032 0ustar jrjr#ifndef _TelepathyQt_BaseConnection_HEADER_GUARD_ #define _TelepathyQt_BaseConnection_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/protocol-info.h0000664000175000017500000000651012470405660020161 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_protocol_info_h_HEADER_GUARD_ #define _TelepathyQt_protocol_info_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include namespace Tp { class ConnectionCapabilities; class PendingString; class TP_QT_EXPORT ProtocolInfo { public: ProtocolInfo(); ProtocolInfo(const ProtocolInfo &other); ~ProtocolInfo(); bool isValid() const { return mPriv.constData() != 0; } ProtocolInfo &operator=(const ProtocolInfo &other); QString cmName() const; QString name() const; ProtocolParameterList parameters() const; bool hasParameter(const QString &name) const; bool canRegister() const; ConnectionCapabilities capabilities() const; QString vcardField() const; QString englishName() const; QString iconName() const; PresenceSpecList allowedPresenceStatuses() const; AvatarSpec avatarRequirements() const; QStringList addressableVCardFields() const; QStringList addressableUriSchemes() const; PendingString *normalizeVCardAddress(const QString &vcardField, const QString &vcardAddress); PendingString *normalizeContactUri(const QString &uri); private: friend class ConnectionManager; TP_QT_NO_EXPORT ProtocolInfo(const ConnectionManagerPtr &cm, const QString &name); TP_QT_NO_EXPORT void addParameter(const ParamSpec &spec); TP_QT_NO_EXPORT void setVCardField(const QString &vcardField); TP_QT_NO_EXPORT void setEnglishName(const QString &englishName); TP_QT_NO_EXPORT void setIconName(const QString &iconName); TP_QT_NO_EXPORT void setRequestableChannelClasses(const RequestableChannelClassList &caps); TP_QT_NO_EXPORT void setAllowedPresenceStatuses(const PresenceSpecList &statuses); TP_QT_NO_EXPORT void setAvatarRequirements(const AvatarSpec &avatarRequirements); TP_QT_NO_EXPORT void setAddressableVCardFields(const QStringList &vcardFields); TP_QT_NO_EXPORT void setAddressableUriSchemes(const QStringList &uriSchemes); struct Private; friend struct Private; QSharedDataPointer mPriv; }; typedef QList ProtocolInfoList; } // Tp Q_DECLARE_METATYPE(Tp::ProtocolInfo); Q_DECLARE_METATYPE(Tp::ProtocolInfoList); #endif telepathy-qt-0.9.6~git1/TelepathyQt/StreamTubeClient0000664000175000017500000000040012470405660020343 0ustar jrjr#ifndef _TelepathyQt_StreamTubeClient_HEADER_GUARD_ #define _TelepathyQt_StreamTubeClient_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/simple-call-observer.h0000664000175000017500000000662512470405660021425 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_simple_call_observer_h_HEADER_GUARD_ #define _TelepathyQt_simple_call_observer_h_HEADER_GUARD_ #include #include #include namespace Tp { class PendingOperation; class TP_QT_EXPORT SimpleCallObserver : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(SimpleCallObserver) Q_FLAGS(CallDirection CallDirections) public: enum CallDirection { CallDirectionIncoming = 0x01, CallDirectionOutgoing = 0x02, CallDirectionBoth = CallDirectionIncoming | CallDirectionOutgoing }; Q_DECLARE_FLAGS(CallDirections, CallDirection) static SimpleCallObserverPtr create(const AccountPtr &account, CallDirection direction = CallDirectionBoth); static SimpleCallObserverPtr create(const AccountPtr &account, const ContactPtr &contact, CallDirection direction = CallDirectionBoth); static SimpleCallObserverPtr create(const AccountPtr &account, const QString &contactIdentifier, CallDirection direction = CallDirectionBoth); virtual ~SimpleCallObserver(); AccountPtr account() const; QString contactIdentifier() const; CallDirection direction() const; QList calls() const; TP_QT_DEPRECATED QList streamedMediaCalls() const; Q_SIGNALS: void callStarted(const Tp::CallChannelPtr &channel); void callEnded(const Tp::CallChannelPtr &channel, const QString &errorName, const QString &errorMessage); void streamedMediaCallStarted(const Tp::StreamedMediaChannelPtr &channel); void streamedMediaCallEnded(const Tp::StreamedMediaChannelPtr &channel, const QString &errorName, const QString &errorMessage); private Q_SLOTS: TP_QT_NO_EXPORT void onNewChannels(const QList &channels); TP_QT_NO_EXPORT void onChannelInvalidated(const Tp::ChannelPtr &channel, const QString &errorName, const QString &errorMessage); private: TP_QT_NO_EXPORT static SimpleCallObserverPtr create( const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization, CallDirection direction); TP_QT_NO_EXPORT SimpleCallObserver(const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization, CallDirection direction); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ProtocolInterface0000664000175000017500000000040212470405660020555 0ustar jrjr#ifndef _TelepathyQt_ProtocolInterface_HEADER_GUARD_ #define _TelepathyQt_ProtocolInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/client-registrar.h0000664000175000017500000000666212470405660020655 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_client_registrar_h_HEADER_GUARD_ #define _TelepathyQt_client_registrar_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include namespace Tp { class TP_QT_EXPORT ClientRegistrar : public Object { Q_OBJECT Q_DISABLE_COPY(ClientRegistrar) public: static ClientRegistrarPtr create(const QDBusConnection &bus); static ClientRegistrarPtr create( const AccountFactoryConstPtr &accountFactory = AccountFactory::create(QDBusConnection::sessionBus()), const ConnectionFactoryConstPtr &connectionFactory = ConnectionFactory::create(QDBusConnection::sessionBus()), const ChannelFactoryConstPtr &channelFactory = ChannelFactory::create(QDBusConnection::sessionBus()), const ContactFactoryConstPtr &contactFactory = ContactFactory::create()); static ClientRegistrarPtr create(const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory); static ClientRegistrarPtr create(const AccountManagerPtr &accountManager); ~ClientRegistrar(); QDBusConnection dbusConnection() const; AccountFactoryConstPtr accountFactory() const; ConnectionFactoryConstPtr connectionFactory() const; ChannelFactoryConstPtr channelFactory() const; ContactFactoryConstPtr contactFactory() const; QList registeredClients() const; bool registerClient(const AbstractClientPtr &client, const QString &clientName, bool unique = false); bool unregisterClient(const AbstractClientPtr &client); void unregisterClients(); private: ClientRegistrar(const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory); struct Private; friend struct Private; Private *mPriv; static QHash, ClientRegistrar *> registrarForConnection; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeDBusTubeInterface0000664000175000017500000000041512470405660022570 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeDBusTubeInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeDBusTubeInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel-request.xml0000664000175000017500000000035712470405660021041 0ustar jrjr Channel Request interface telepathy-qt-0.9.6~git1/TelepathyQt/WeakPtr0000664000175000017500000000034612470405660016517 0ustar jrjr#ifndef _TelepathyQt_WeakPtr_HEADER_GUARD_ #define _TelepathyQt_WeakPtr_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/contact-capabilities.cpp0000664000175000017500000001201312470405660021777 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include namespace Tp { /** * \class ContactCapabilities * \ingroup clientconn * \headerfile TelepathyQt/contact-capabilities.h * * \brief The ContactCapabilities class represents the capabilities of a * Contact. */ /** * Construct a new ContactCapabilities object. */ ContactCapabilities::ContactCapabilities() : CapabilitiesBase() { } /** * Construct a new ContactCapabilities object. */ ContactCapabilities::ContactCapabilities(bool specificToContact) : CapabilitiesBase(specificToContact) { } /** * Construct a new ContactCapabilities object using the give \a rccs. * * \param rccs RequestableChannelClassList representing the capabilities of a * contact. */ ContactCapabilities::ContactCapabilities(const RequestableChannelClassList &rccs, bool specificToContact) : CapabilitiesBase(rccs, specificToContact) { } /** * Construct a new ContactCapabilities object using the give \a rccSpecs. * * \param rccSpecs RequestableChannelClassList representing the capabilities of a * contact. */ ContactCapabilities::ContactCapabilities(const RequestableChannelClassSpecList &rccSpecs, bool specificToContact) : CapabilitiesBase(rccSpecs, specificToContact) { } /** * Class destructor. */ ContactCapabilities::~ContactCapabilities() { } /** * Returns whether creating a DBusTube channel with the given service targeting this contact is * expected to succeed. * * \return \c true if supported, \c false otherwise. */ bool ContactCapabilities::dbusTubes(const QString &serviceName) const { RequestableChannelClassSpec dbusTubeSpec = RequestableChannelClassSpec::dbusTube(serviceName); RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(dbusTubeSpec)) { return true; } } return false; } /** * Return the supported DBusTube services. * * \return A list of supported DBusTube services. */ QStringList ContactCapabilities::dbusTubeServices() const { QSet ret; RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.channelType() == TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE && rccSpec.targetHandleType() == HandleTypeContact && rccSpec.hasFixedProperty( TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName"))) { ret << rccSpec.fixedProperty( TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName")).toString(); } } return ret.toList(); } /** * Return whether creating a StreamTube channel, using the given \a service, by providing a * contact identifier is supported. * * \return \c true if supported, \c false otherwise. */ bool ContactCapabilities::streamTubes(const QString &service) const { RequestableChannelClassSpec streamTubeSpec = RequestableChannelClassSpec::streamTube(service); RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(streamTubeSpec)) { return true; } } return false; } /** * Return the supported StreamTube services. * * \return A list of supported StreamTube services. */ QStringList ContactCapabilities::streamTubeServices() const { QSet ret; RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.channelType() == TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE && rccSpec.targetHandleType() == HandleTypeContact && rccSpec.hasFixedProperty( TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QLatin1String(".Service"))) { ret << rccSpec.fixedProperty( TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QLatin1String(".Service")).toString(); } } return ret.toList(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/Filter0000664000175000017500000000034012470405660016361 0ustar jrjr#ifndef _TelepathyQt_Filter_HEADER_GUARD_ #define _TelepathyQt_Filter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PeerInterface0000664000175000017500000000035412470405660017655 0ustar jrjr#ifndef _TelepathyQt_PeerInterface_HEADER_GUARD_ #define _TelepathyQt_PeerInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/TelepathyQt-uninstalled.pc.in0000664000175000017500000000137712470405660022741 0ustar jrjrprefix=/nonexistent exec_prefix=/nonexistent abs_top_builddir=${CMAKE_BINARY_DIR} abs_top_srcdir=${CMAKE_SOURCE_DIR} Name: TelepathyQt${QT_VERSION_MAJOR} (uninstalled copy) Description: Qt utility library for the Telepathy framework Version: ${PACKAGE_VERSION} Requires.private: Qt${QT_VERSION_PC}Core >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Core < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}DBus >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}DBus < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}Network >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Network < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}Xml >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Xml < ${QT_MAX_VERSION} Libs: ${CMAKE_BINARY_DIR}/TelepathyQt/libtelepathy-qt${QT_VERSION_MAJOR}.so Cflags: -I${CMAKE_SOURCE_DIR} -I${CMAKE_BINARY_DIR} telepathy-qt-0.9.6~git1/TelepathyQt/pending-channel-request.h0000664000175000017500000000470212470405660022110 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_channel_request_h_HEADER_GUARD_ #define _TelepathyQt_pending_channel_request_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include class QDBusPendingCallWatcher; namespace Tp { class Account; class ChannelRequestHints; class TP_QT_EXPORT PendingChannelRequest : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingChannelRequest) public: ~PendingChannelRequest(); AccountPtr account() const; ChannelRequestPtr channelRequest() const; PendingOperation *cancel(); Q_SIGNALS: void channelRequestCreated(const Tp::ChannelRequestPtr &channelRequest); private Q_SLOTS: TP_QT_NO_EXPORT void onWatcherFinished(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onProceedOperationFinished(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onCancelOperationFinished(Tp::PendingOperation *op); private: friend class Account; TP_QT_NO_EXPORT PendingChannelRequest(const AccountPtr &account, const QVariantMap &requestedProperties, const QDateTime &userActionTime, const QString &preferredHandler, bool create, const ChannelRequestHints &hints); TP_QT_NO_EXPORT PendingChannelRequest(const AccountPtr &account, const QString &errorName, const QString &errorMessage); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/dbus-tube-channel.cpp0000664000175000017500000004460312470405660021227 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/dbus-tube-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/outgoing-stream-tube-channel-internal.h" #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT DBusTubeChannel::Private { Private(DBusTubeChannel *parent); void extractProperties(const QVariantMap &props); void extractParticipants(const Tp::DBusTubeParticipants &participants); static void introspectDBusTube(Private *self); static void introspectBusNamesMonitoring(Private *self); ReadinessHelper *readinessHelper; // Public object DBusTubeChannel *parent; // Properties UIntList accessControls; QString serviceName; QHash contactsForBusNames; QString address; QHash pendingNewBusNamesToAdd; QList pendingNewBusNamesToRemove; QueuedContactFactory *queuedContactFactory; }; DBusTubeChannel::Private::Private(DBusTubeChannel *parent) : parent(parent), queuedContactFactory(new QueuedContactFactory(parent->connection()->contactManager(), parent)) { parent->connect(queuedContactFactory, SIGNAL(contactsRetrieved(QUuid,QList)), SLOT(onContactsRetrieved(QUuid,QList))); // Initialize readinessHelper + introspectables here readinessHelper = parent->readinessHelper(); ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableDBusTube( QSet() << 0, // makesSenseForStatuses Features() << TubeChannel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectDBusTube, this); introspectables[DBusTubeChannel::FeatureCore] = introspectableDBusTube; ReadinessHelper::Introspectable introspectableBusNamesMonitoring( QSet() << 0, // makesSenseForStatuses Features() << DBusTubeChannel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectBusNamesMonitoring, this); introspectables[DBusTubeChannel::FeatureBusNameMonitoring] = introspectableBusNamesMonitoring; readinessHelper->addIntrospectables(introspectables); } void DBusTubeChannel::Private::extractProperties(const QVariantMap &props) { serviceName = qdbus_cast(props[TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName")]); accessControls = qdbus_cast(props[TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".SupportedAccessControls")]); } void DBusTubeChannel::Private::extractParticipants(const Tp::DBusTubeParticipants &participants) { contactsForBusNames.clear(); for (DBusTubeParticipants::const_iterator i = participants.constBegin(); i != participants.constEnd(); ++i) { QUuid uuid = queuedContactFactory->appendNewRequest(UIntList() << i.key()); pendingNewBusNamesToAdd.insert(uuid, i.value()); } } void DBusTubeChannel::Private::introspectBusNamesMonitoring(DBusTubeChannel::Private *self) { DBusTubeChannel *parent = self->parent; Client::ChannelTypeDBusTubeInterface *dbusTubeInterface = parent->interface(); // It must be present Q_ASSERT(dbusTubeInterface); // It makes sense only if this is a room, if that's not the case just spit a warning if (parent->targetHandleType() == static_cast(Tp::HandleTypeRoom)) { parent->connect(dbusTubeInterface, SIGNAL(DBusNamesChanged(Tp::DBusTubeParticipants,Tp::UIntList)), parent, SLOT(onDBusNamesChanged(Tp::DBusTubeParticipants,Tp::UIntList))); // Request the current DBusNames property connect(dbusTubeInterface->requestPropertyDBusNames(), SIGNAL(finished(Tp::PendingOperation*)), parent, SLOT(onRequestPropertyDBusNamesFinished(Tp::PendingOperation*))); } else { debug() << "FeatureBusNameMonitoring does not make sense in a P2P context"; self->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureBusNameMonitoring, false); } } void DBusTubeChannel::Private::introspectDBusTube(DBusTubeChannel::Private *self) { DBusTubeChannel *parent = self->parent; debug() << "Introspect dbus tube properties"; if (parent->immutableProperties().contains(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName")) && parent->immutableProperties().contains(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".SupportedAccessControls"))) { self->extractProperties(parent->immutableProperties()); self->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureCore, true); } else { Client::ChannelTypeDBusTubeInterface *dbusTubeInterface = parent->interface(); parent->connect(dbusTubeInterface->requestAllProperties(), SIGNAL(finished(Tp::PendingOperation*)), parent, SLOT(onRequestAllPropertiesFinished(Tp::PendingOperation*))); } } /** * \class DBusTubeChannel * \ingroup clientchannel * \headerfile TelepathyQt/dbus-tube-channel.h * * \brief The DBusTubeChannel class represents a Telepathy channel of type DBusTube. * * It provides a private bus which can be used as a peer-to-peer connection in case of a * Contact Channel, or as a full-fledged bus in case of a Room Channel. * * DBusTubeChannel is an intermediate base class; OutgoingDBusTubeChannel and * IncomingDBusTubeChannel are the specialized classes used for locally and remotely initiated * tubes respectively. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ // Features declaration and documentation /** * Feature representing the core that needs to become ready to make the * DBusTubeChannel object usable. * * Note that this feature must be enabled in order to use most * DBusTubeChannel methods. * See specific methods documentation for more details. */ const Feature DBusTubeChannel::FeatureCore = Feature(QLatin1String(DBusTubeChannel::staticMetaObject.className()), 0); /** * Feature used in order to monitor bus names in this DBus tube. * * See bus name monitoring specific methods' documentation for more details. * * \sa busNameAdded(), busNameRemoved() */ const Feature DBusTubeChannel::FeatureBusNameMonitoring = Feature(QLatin1String(DBusTubeChannel::staticMetaObject.className()), 1); /** * Create a new DBusTubeChannel channel. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The object path of this channel. * \param immutableProperties The immutable properties of this channel. * \return A DBusTubeChannelPtr object pointing to the newly created * DBusTubeChannel object. */ DBusTubeChannelPtr DBusTubeChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return DBusTubeChannelPtr(new DBusTubeChannel(connection, objectPath, immutableProperties)); } /** * Construct a new DBusTubeChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The object path of this channel. * \param immutableProperties The immutable properties of this channel. */ DBusTubeChannel::DBusTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) : TubeChannel(connection, objectPath, immutableProperties), mPriv(new Private(this)) { } /** * Class destructor. */ DBusTubeChannel::~DBusTubeChannel() { delete mPriv; } /** * Returns the service name which will be used over the tube. This should be a * well-known and valid DBus service name, in the form "org.my.service". * * This method requires DBusTubeChannel::FeatureCore to be enabled. * * \return the service name that will be used over the tube */ QString DBusTubeChannel::serviceName() const { if (!isReady(FeatureCore)) { warning() << "DBusTubeChannel::serviceName() used with " "FeatureCore not ready"; return QString(); } return mPriv->serviceName; } /** * Checks if this tube is capable to accept or offer a private bus which * will allow connections only from the current user * * This method is useful only if your appliance is really security-sensitive: * in general, this restriction is always enabled by default on all tubes offered * or accepted from Telepathy-Qt, falling back to a general connection allowance * if this feature is not available. * * If your application does not have specific needs regarding DBus credentials, * you can trust Telepathy-Qt to do the right thing - in any case, the most secure * method available will be used by default. * * This method requires DBusTubeChannel::FeatureCore to be enabled. * * \return Whether this DBus tube is capable to accept or offer a private bus * restricting access to it to the current user only. * * \sa IncomingDBusTubeChannel::acceptTube * \sa OutgoingDBusTubeChannel::offerTube */ bool DBusTubeChannel::supportsRestrictingToCurrentUser() const { if (!isReady(FeatureCore)) { warning() << "DBusTubeChannel::supportsRestrictingToCurrentUser() used with " "FeatureCore not ready"; return false; } return mPriv->accessControls.contains(static_cast(Tp::SocketAccessControlCredentials)); } /** * If the tube has been opened, this function returns the private bus address you should be connecting * to for using this tube. * * Please note this function will return a meaningful value only if the tube has already * been opened successfully: in case of failure or the tube being still pending, an empty QString will be * returned. * * \note If you plan to use QtDBus for the DBus connection, please note you should always use * QDBusConnection::connectToPeer(), regardless of the fact this tube is a p2p or a group one. * The above function has been introduced in Qt 4.8, previous versions of Qt do not allow the use * of DBus Tubes through QtDBus. * * \returns The address of the private bus opened by this tube */ QString DBusTubeChannel::address() const { if (state() != TubeChannelStateOpen) { warning() << "DBusTubeChannel::address() can be called only if " "the tube has already been opened"; return QString(); } return mPriv->address; } /** * This function returns all the known active bus names in this tube. It requires * FeatureBusNameMonitoring to be activated; however, even a late activation of the * feature will make this function return a full list of all the connected bus * names, including the ones which appeared before the activation of the feature * itself. * * This function will always return an empty hash in case the tube is p2p, even if * FeatureBusNameMonitoring has been activated. * * This method requires FeatureBusNameMonitoring to be enabled. * * \returns A list of active connection ids known to this tube */ QHash DBusTubeChannel::contactsForBusNames() const { if (!isReady(FeatureBusNameMonitoring)) { warning() << "DBusTubeChannel::contactsForBusNames() used with " "FeatureBusNameMonitoring not ready"; return QHash(); } return mPriv->contactsForBusNames; } void DBusTubeChannel::onRequestAllPropertiesFinished(PendingOperation *op) { if (!op->isError()) { debug() << "RequestAllProperties succeeded"; PendingVariantMap *result = qobject_cast(op); QVariantMap map = result->result(); QVariantMap qualifiedMap; for (QVariantMap::const_iterator i = map.constBegin(); i != map.constEnd(); ++i) { qualifiedMap.insert(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1Char('.') + i.key(), i.value()); } mPriv->extractProperties(qualifiedMap); mPriv->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureCore, true); } else { warning().nospace() << "RequestAllProperties failed " "with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureCore, false); } } void DBusTubeChannel::onRequestPropertyDBusNamesFinished(PendingOperation *op) { if (!op->isError()) { debug() << "RequestPropertyDBusNames succeeded"; PendingVariant *result = qobject_cast(op); DBusTubeParticipants participants = qdbus_cast(result->result()); if (participants.isEmpty()) { // Nothing to do actually, simply mark the feature as ready. mPriv->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureBusNameMonitoring, true); } else { // Wait for the queue to complete connect(mPriv->queuedContactFactory, SIGNAL(queueCompleted()), this, SLOT(onQueueCompleted())); // Extract the participants, populating the QueuedContactFactory mPriv->extractParticipants(participants); } } else { warning().nospace() << "RequestPropertyDBusNames failed " "with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureBusNameMonitoring, false); } } void DBusTubeChannel::onQueueCompleted() { debug() << "Queue was completed"; // Set the feature as completed, and disconnect the signal as it's no longer useful mPriv->readinessHelper->setIntrospectCompleted(DBusTubeChannel::FeatureBusNameMonitoring, true); disconnect(mPriv->queuedContactFactory, SIGNAL(queueCompleted()), this, SLOT(onQueueCompleted())); } void DBusTubeChannel::onDBusNamesChanged(const Tp::DBusTubeParticipants &added, const Tp::UIntList &removed) { for (DBusTubeParticipants::const_iterator i = added.constBegin(); i != added.constEnd(); ++i) { QUuid uuid = mPriv->queuedContactFactory->appendNewRequest(UIntList() << i.key()); // Add it to our hash as well mPriv->pendingNewBusNamesToAdd.insert(uuid, i.value()); } foreach (uint handle, removed) { QUuid uuid = mPriv->queuedContactFactory->appendNewRequest(UIntList() << handle); // Add it to pending removed as well mPriv->pendingNewBusNamesToRemove << uuid; } } void DBusTubeChannel::onContactsRetrieved(const QUuid &uuid, const QList &contacts) { // Retrieve our hash if (mPriv->pendingNewBusNamesToAdd.contains(uuid)) { QString busName = mPriv->pendingNewBusNamesToAdd.take(uuid); // Add it to our connections hash foreach (const Tp::ContactPtr &contact, contacts) { mPriv->contactsForBusNames.insert(busName, contact); // Time for us to emit the signal - if the feature is ready if (isReady(FeatureBusNameMonitoring)) { emit busNameAdded(busName, contact); } } } else if (mPriv->pendingNewBusNamesToRemove.contains(uuid)) { mPriv->pendingNewBusNamesToRemove.removeOne(uuid); // Remove it from our connections hash foreach (const Tp::ContactPtr &contact, contacts) { if (mPriv->contactsForBusNames.values().contains(contact)) { QString busName = mPriv->contactsForBusNames.key(contact); mPriv->contactsForBusNames.remove(busName); // Time for us to emit the signal - if the feature is ready if (isReady(FeatureBusNameMonitoring)) { emit busNameRemoved(busName, contact); } } else { warning() << "Trying to remove a bus name for contact " << contact->id() << " which has not been retrieved previously!"; } } } else { warning() << "Contacts retrieved but no pending bus names were found"; return; } } void DBusTubeChannel::setAddress(const QString& address) { mPriv->address = address; } // Signals documentation /** * \fn void DBusTubeChannel::busNameAdded(const QString &busName, const Tp::ContactPtr &contact) * * Emitted when a new participant joins this tube. * * This signal will be emitted only if the tube is a group tube (not p2p), and if the * FeatureBusNameMonitoring feature has been enabled. * * \param busName The bus name of the new participant * \param contact The ContactPtr identifying the participant */ /** * \fn void DBusTubeChannel::busNameRemoved(const QString &busName, const Tp::ContactPtr &contact) * * Emitted when a participant leaves this tube. * * This signal will be emitted only if the tube is a group tube (not p2p), and if the * FeatureBusNameMonitoring feature has been enabled. * * \param busName The bus name of the participant leaving * \param contact The ContactPtr identifying the participant */ } telepathy-qt-0.9.6~git1/TelepathyQt/callbacks.dox0000664000175000017500000001114012470405660017644 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \page callbacks Callbacks Usage * * \section callbacks_overview Overview * * Callbacks are used in Telepathy-Qt by the service side high-level APIs * to expose methods that may/should be overriden in implementations. * * Ideally we would use virtual methods for this, but as new methods * can be added freely (when interfaces change), we would not be able * to guarantee a stable API/ABI. Other options, such as virtual padding, * virtual_hook and Qt slots also have their own drawbacks. * * There are 8 Callback classes, Tp::Callback0 to Tp::Callback7, which * define a callback with 0 to 7 arguments respectively. The first template * argument is always the return value type and the rest template arguments * are the types of the callback arguments in the order that they are passed * to the callback. * * Callback classes can be constructed from a functor. To make it easy to * use function pointers as functors, Telepathy-Qt also provides two helper * functions, Tp::memFun and Tp::ptrFun. * * Here is an example of their usage: * \code * // assuming a member function QString MyImpl::myFunc(const QString & s, int i); * Tp::Callback2 cb = Tp::memFun(myObj, &MyImpl::myFunc); * * // assuming a non-member or static member function QString myFunc(const QString & s, int i); * Tp::Callback2 cb = Tp::ptrFun(&myFunc); * * // assuming Tp::BaseConnectionPtr MyProtocolImpl::createConnection(const QVariantMap ¶meters, DBusError *error); * myBaseProtocol->setCreateConnectionCallback(Tp::memFun(myProtocolImpl, &MyProtocolImpl::createConnection)); * \endcode * * You are also free to use any other mechanism for constructing functors, * such as boost::bind, C++11's module or even C++11 lambda functions. */ /** * \class Tp::BaseCallback * \ingroup utils * \headerfile TelepathyQt/callbacks.h * * \brief Base class for all the callback classes * * See \ref callbacks */ /** * \fn bool Tp::BaseCallback::isValid() const * * Return whether this callback object has a valid functor assigned to it * or if it's a default-constructed dummy callback object. * * \return \c false if this is a default-constructed callback or * \c true if this callback was constructed from a functor. */ /** * \class Tp::Callback0 * \ingroup utils * \headerfile TelepathyQt/callbacks.h * * \brief Callback with 0 arguments * * See \ref callbacks */ /** * \class Tp::Callback1 * \ingroup utils * \headerfile TelepathyQt/callbacks.h * * \brief Callback with 1 argument * * See \ref callbacks */ /** * \class Tp::Callback2 * \ingroup utils * \headerfile TelepathyQt/callbacks.h * * \brief Callback with 2 arguments * * See \ref callbacks */ /** * \class Tp::Callback3 * \ingroup utils * \headerfile TelepathyQt/callbacks.h * * \brief Callback with 3 arguments * * See \ref callbacks */ /** * \class Tp::Callback4 * \ingroup utils * \headerfile TelepathyQt/callbacks.h * * \brief Callback with 4 arguments * * See \ref callbacks */ /** * \class Tp::Callback5 * \ingroup utils * \headerfile TelepathyQt/callbacks.h * * \brief Callback with 5 arguments * * See \ref callbacks */ /** * \class Tp::Callback6 * \ingroup utils * \headerfile TelepathyQt/callbacks.h * * \brief Callback with 6 arguments * * See \ref callbacks */ /** * \class Tp::Callback7 * \ingroup utils * \headerfile TelepathyQt/callbacks.h * * \brief Callback with 7 arguments * * See \ref callbacks */ telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeStreamedMediaInterface0000664000175000017500000000042712470405660023622 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeStreamedMediaInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeStreamedMediaInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Debug0000664000175000017500000000033512470405660016166 0ustar jrjr#ifndef _TelepathyQt_Debug_HEADER_GUARD_ #define _TelepathyQt_Debug_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/CallStreamEndpointInterface0000664000175000017500000000043012470405660022505 0ustar jrjr#ifndef _TelepathyQt_CallStreamEndpointInterface_HEADER_GUARD_ #define _TelepathyQt_CallStreamEndpointInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/contact-manager.h0000664000175000017500000001632212470405660020434 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_contact_manager_h_HEADER_GUARD_ #define _TelepathyQt_contact_manager_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include #include #include #include namespace Tp { class Connection; class PendingContacts; class PendingOperation; class TP_QT_EXPORT ContactManager : public Object { Q_OBJECT Q_DISABLE_COPY(ContactManager) public: virtual ~ContactManager(); ConnectionPtr connection() const; Features supportedFeatures() const; ContactListState state() const; Contacts allKnownContacts() const; QStringList allKnownGroups() const; PendingOperation *addGroup(const QString &group); PendingOperation *removeGroup(const QString &group); Contacts groupContacts(const QString &group) const; PendingOperation *addContactsToGroup(const QString &group, const QList &contacts); PendingOperation *removeContactsFromGroup(const QString &group, const QList &contacts); bool canRequestPresenceSubscription() const; bool subscriptionRequestHasMessage() const; PendingOperation *requestPresenceSubscription( const QList &contacts, const QString &message = QString()); bool canRemovePresenceSubscription() const; bool subscriptionRemovalHasMessage() const; bool canRescindPresenceSubscriptionRequest() const; bool subscriptionRescindingHasMessage() const; PendingOperation *removePresenceSubscription( const QList &contacts, const QString &message = QString()); bool canAuthorizePresencePublication() const; bool publicationAuthorizationHasMessage() const; PendingOperation *authorizePresencePublication( const QList &contacts, const QString &message = QString()); bool publicationRejectionHasMessage() const; bool canRemovePresencePublication() const; bool publicationRemovalHasMessage() const; PendingOperation *removePresencePublication( const QList &contacts, const QString &message = QString()); PendingOperation *removeContacts( const QList &contacts, const QString &message = QString()); bool canBlockContacts() const; bool canReportAbuse() const; PendingOperation *blockContacts(const QList &contacts); PendingOperation *blockContactsAndReportAbuse(const QList &contacts); PendingOperation *unblockContacts(const QList &contacts); PendingContacts *contactsForHandles(const UIntList &handles, const Features &features = Features()); PendingContacts *contactsForHandles(const ReferencedHandles &handles, const Features &features = Features()); PendingContacts *contactsForHandles(const HandleIdentifierMap &handles, const Features &features = Features()); PendingContacts *contactsForIdentifiers(const QStringList &identifiers, const Features &features = Features()); PendingContacts *contactsForVCardAddresses(const QString &vcardField, const QStringList &vcardAddresses, const Features &features = Features()); PendingContacts *contactsForUris(const QStringList &uris, const Features &features = Features()); PendingContacts *upgradeContacts(const QList &contacts, const Features &features); void requestContactAvatars(const QList &contacts); PendingOperation *refreshContactInfo(const QList &contact); Q_SIGNALS: void stateChanged(Tp::ContactListState state); void presencePublicationRequested(const Tp::Contacts &contacts); void groupAdded(const QString &group); void groupRenamed(const QString &oldGroup, const QString &newGroup); void groupRemoved(const QString &group); void groupMembersChanged(const QString &group, const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupMembersRemoved, const Tp::Channel::GroupMemberChangeDetails &details); void allKnownContactsChanged(const Tp::Contacts &contactsAdded, const Tp::Contacts &contactsRemoved, const Tp::Channel::GroupMemberChangeDetails &details); private Q_SLOTS: TP_QT_NO_EXPORT void onAliasesChanged(const Tp::AliasPairList &); TP_QT_NO_EXPORT void doRequestAvatars(); TP_QT_NO_EXPORT void onAvatarUpdated(uint, const QString &); TP_QT_NO_EXPORT void onAvatarRetrieved(uint, const QString &, const QByteArray &, const QString &); TP_QT_NO_EXPORT void onPresencesChanged(const Tp::SimpleContactPresences &); TP_QT_NO_EXPORT void onCapabilitiesChanged(const Tp::ContactCapabilitiesMap &); TP_QT_NO_EXPORT void onLocationUpdated(uint, const QVariantMap &); TP_QT_NO_EXPORT void onContactInfoChanged(uint, const Tp::ContactInfoFieldList &); TP_QT_NO_EXPORT void onClientTypesUpdated(uint, const QStringList &); TP_QT_NO_EXPORT void doRefreshInfo(); private: class PendingRefreshContactInfo; class Roster; friend class Channel; friend class Connection; friend class PendingContacts; friend class PendingRefreshContactInfo; friend class Roster; TP_QT_NO_EXPORT ContactManager(Connection *parent); TP_QT_NO_EXPORT ContactPtr lookupContactByHandle(uint handle); TP_QT_NO_EXPORT ContactPtr ensureContact(const ReferencedHandles &handle, const Features &features, const QVariantMap &attributes); TP_QT_NO_EXPORT ContactPtr ensureContact(uint bareHandle, const QString &id, const Features &features); TP_QT_NO_EXPORT static QString featureToInterface(const Feature &feature); TP_QT_NO_EXPORT void ensureTracking(const Feature &feature); TP_QT_NO_EXPORT PendingOperation *introspectRoster(); TP_QT_NO_EXPORT PendingOperation *introspectRosterGroups(); TP_QT_NO_EXPORT void resetRoster(); TP_QT_NO_EXPORT PendingOperation *refreshContactInfo(Contact *contact); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/StreamedMediaStream0000664000175000017500000000041212470405660021014 0ustar jrjr#ifndef _TelepathyQt_StreamedMediaStream_HEADER_GUARD_ #define _TelepathyQt_StreamedMediaStream_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/filter.h0000664000175000017500000000303612470405660016654 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_filter_h_HEADER_GUARD_ #define _TelepathyQt_filter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { template class Filter : public RefCounted { Q_DISABLE_COPY(Filter) public: virtual ~Filter() {} virtual bool isValid() const { return false; } virtual bool matches(const SharedPtr &t) const { Q_UNUSED(t); return false; } protected: Filter() {} private: struct Private; Private *mPriv; // Just a placeholder really }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/TextChannel0000664000175000017500000000036012470405660017353 0ustar jrjr#ifndef _TelepathyQt_TextChannel_HEADER_GUARD_ #define _TelepathyQt_TextChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/TelepathyQtConfig.cmake.in0000664000175000017500000000323412470405660022217 0ustar jrjr# TelepathyQt@QT_VERSION_MAJOR@Config.cmake is generated by CMake from TelepathyQt/TelepathyQtConfig.cmake.in. # Any changed value in this file will be overwritten by CMake. if(NOT TelepathyQt@QT_VERSION_MAJOR@_FOUND) # set the version number set(TELEPATHY_QT@QT_VERSION_MAJOR@_VERSION_MAJOR @TP_QT_MAJOR_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_VERSION_MINOR @TP_QT_MINOR_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_VERSION_MICRO @TP_QT_MICRO_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_VERSION_NANO @TP_QT_NANO_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_VERSION @PACKAGE_VERSION@) # set the directories if(NOT TELEPATHY_QT@QT_VERSION_MAJOR@_INSTALL_DIR) set(TELEPATHY_QT@QT_VERSION_MAJOR@_INSTALL_DIR "@CMAKE_INSTALL_PREFIX@") endif(NOT TELEPATHY_QT@QT_VERSION_MAJOR@_INSTALL_DIR) set(TELEPATHY_QT@QT_VERSION_MAJOR@_INCLUDE_DIR "@TELEPATHY_QT_INCLUDE_DIR@") set(TELEPATHY_QT@QT_VERSION_MAJOR@_LIB_DIR "@TELEPATHY_QT_LIB_DIR@") set(TELEPATHY_QT@QT_VERSION_MAJOR@_SHARE_DIR "@TELEPATHY_QT_DATA_DIR@") # attempt to find the generated TelepathyQt4Targets.cmake in the same directory get_filename_component(_TPQT@QT_VERSION_MAJOR@_CONFIG_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) find_file(_TPQT@QT_VERSION_MAJOR@_TARGETS_FILE TelepathyQt@QT_VERSION_MAJOR@Targets.cmake PATHS ${_TPQT@QT_VERSION_MAJOR@_CONFIG_DIR} NO_DEFAULT_PATH) # set the TELEPATHY_QT@QT_VERSION_MAJOR@_LIBRARIES variable include(${_TPQT@QT_VERSION_MAJOR@_TARGETS_FILE}) set(TELEPATHY_QT@QT_VERSION_MAJOR@_LIBRARIES telepathy-qt@QT_VERSION_MAJOR@) endif(NOT TelepathyQt@QT_VERSION_MAJOR@_FOUND) telepathy-qt-0.9.6~git1/TelepathyQt/pending-handles.cpp0000664000175000017500000003761412470405660020773 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-handles.moc.hpp" #include #include #include "TelepathyQt/debug-internal.h" namespace Tp { struct TP_QT_NO_EXPORT PendingHandles::Private { HandleType handleType; bool isRequest; QStringList namesRequested; UIntList handlesToReference; ReferencedHandles handles; ReferencedHandles alreadyHeld; UIntList invalidHandles; QStringList validNames; QHash > invalidNames; // one to one requests (ids) QHash handlesForWatchers; QHash idsForWatchers; QHash handlesForIds; int requestsFinished; }; /** * \class PendingHandles * \ingroup clientconn * \headerfile TelepathyQt/pending-handles.h * * \brief The PendingHandles class represents the parameters of and the reply to * an asynchronous handle request/hold. * * Instances of this class cannot be constructed directly; the only way to get * one is to use Connection::requestHandles() or Connection::referenceHandles(). * * See \ref async_model */ PendingHandles::PendingHandles(const ConnectionPtr &connection, HandleType handleType, const QStringList &names) : PendingOperation(connection), mPriv(new Private) { debug() << "PendingHandles(request)"; mPriv->handleType = handleType; mPriv->isRequest = true; mPriv->namesRequested = names; mPriv->requestsFinished = 0; // try to request all handles at once QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( connection->baseInterface()->RequestHandles(mPriv->handleType, names), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onRequestHandlesFinished(QDBusPendingCallWatcher*))); } PendingHandles::PendingHandles(const ConnectionPtr &connection, HandleType handleType, const UIntList &handles, const UIntList &alreadyHeld, const UIntList ¬YetHeld) : PendingOperation(connection), mPriv(new Private) { debug() << "PendingHandles(reference)"; mPriv->handleType = handleType; mPriv->isRequest = false; mPriv->handlesToReference = handles; mPriv->alreadyHeld = ReferencedHandles(connection, mPriv->handleType, alreadyHeld); mPriv->requestsFinished = 0; if (notYetHeld.isEmpty()) { debug() << " All handles already held, finishing up instantly"; mPriv->handles = mPriv->alreadyHeld; setFinished(); } else { debug() << " Calling HoldHandles"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( connection->baseInterface()->HoldHandles(mPriv->handleType, notYetHeld), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onHoldHandlesFinished(QDBusPendingCallWatcher*))); } } PendingHandles::PendingHandles(const QString &errorName, const QString &errorMessage) : PendingOperation(ConnectionPtr()), mPriv(new Private) { setFinishedWithError(errorName, errorMessage); } /** * Class destructor. */ PendingHandles::~PendingHandles() { delete mPriv; } /** * Return the connection through which the operation was made. * * \return A pointer to the Connection object. */ ConnectionPtr PendingHandles::connection() const { return ConnectionPtr(qobject_cast((Connection*) object().data())); } /** * Return the handle type specified in the operation. * * \return The target handle type as #HandleType. */ HandleType PendingHandles::handleType() const { return mPriv->handleType; } /** * Return whether the operation was a handle request (as opposed to a * reference of existing handles). * * \return \c true if the operation was a request (== !isReference()), \c false otherwise. * \sa isReference() */ bool PendingHandles::isRequest() const { return mPriv->isRequest; } /** * Return whether the operation was a handle reference (as opposed to a * request for new handles). * * \return \c true if the operation was a reference (== !isRequest()), \c false otherwise. * \sa isRequest() */ bool PendingHandles::isReference() const { return !mPriv->isRequest; } /** * If the operation was a request (as returned by isRequest()), returns the * names of the entities for which handles were requested for. Otherwise, * returns an empty list. * * \return Reference to a list of the names of the entities. */ const QStringList &PendingHandles::namesRequested() const { return mPriv->namesRequested; } QStringList PendingHandles::validNames() const { if (!isFinished()) { warning() << "PendingHandles::validNames called before finished"; return QStringList(); } else if (!isValid()) { warning() << "PendingHandles::validNames called when not valid"; return QStringList(); } return mPriv->validNames; } QHash > PendingHandles::invalidNames() const { if (!isFinished()) { warning() << "PendingHandles::invalidNames called before finished"; return QHash >(); } return mPriv->invalidNames; } /** * If the operation was a reference (as returned by isReference()), returns * the handles which were to be referenced. Otherwise, returns an empty * list. * * \return Reference to a list of the handles specified to be referenced. */ const UIntList &PendingHandles::handlesToReference() const { return mPriv->handlesToReference; } /** * Return the now-referenced handles resulting from the operation. If the * operation has not (yet) finished successfully (isFinished() returns * false), the return value is undefined. * * For requests of new handles, handles()[i] will be the handle * corresponding to the entity name namesToRequest()[i]. For * references of existing handles, handles()[i] == * handlesToReference()[i] will be true for any i. * * \return ReferencedHandles object containing the handles. */ ReferencedHandles PendingHandles::handles() const { if (!isFinished()) { warning() << "PendingHandles::handles() called before finished"; return ReferencedHandles(); } else if (!isValid()) { warning() << "PendingHandles::handles() called when not valid"; return ReferencedHandles(); } return mPriv->handles; } UIntList PendingHandles::invalidHandles() const { if (!isFinished()) { warning() << "PendingHandles::invalidHandles called before finished"; } return mPriv->invalidHandles; } void PendingHandles::onRequestHandlesFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { QDBusError error = reply.error(); if (error.name() != TP_QT_ERROR_INVALID_HANDLE && error.name() != TP_QT_ERROR_INVALID_ARGUMENT && error.name() != TP_QT_ERROR_NOT_AVAILABLE) { // do not fallback foreach (const QString &name, mPriv->namesRequested) { mPriv->invalidNames.insert(name, QPair(error.name(), error.message())); } setFinishedWithError(error); connection()->handleRequestLanded(mPriv->handleType); watcher->deleteLater(); return; } if (mPriv->namesRequested.size() == 1) { debug().nospace() << " Failure: error " << reply.error().name() << ": " << reply.error().message(); mPriv->invalidNames.insert(mPriv->namesRequested.first(), QPair(error.name(), error.message())); setFinished(); connection()->handleRequestLanded(mPriv->handleType); watcher->deleteLater(); return; } // try to request one handles at a time foreach (const QString &name, mPriv->namesRequested) { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( connection()->baseInterface()->RequestHandles( mPriv->handleType, QStringList() << name), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onRequestHandlesFallbackFinished(QDBusPendingCallWatcher*))); mPriv->idsForWatchers.insert(watcher, name); } } else { debug() << "Received reply to RequestHandles"; mPriv->handles = ReferencedHandles(connection(), mPriv->handleType, reply.value()); mPriv->validNames.append(mPriv->namesRequested); setFinished(); connection()->handleRequestLanded(mPriv->handleType); } } void PendingHandles::onHoldHandlesFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; debug() << "Received reply to HoldHandles"; if (reply.isError()) { debug().nospace() << " Failure: error " << reply.error().name() << ": " << reply.error().message(); QDBusError error = reply.error(); if (error.name() != TP_QT_ERROR_INVALID_HANDLE && error.name() != TP_QT_ERROR_INVALID_ARGUMENT && error.name() != TP_QT_ERROR_NOT_AVAILABLE) { // do not fallback mPriv->invalidHandles = mPriv->handlesToReference; setFinishedWithError(error); watcher->deleteLater(); return; } if (mPriv->handlesToReference.size() == 1) { debug().nospace() << " Failure: error " << reply.error().name() << ": " << reply.error().message(); mPriv->invalidHandles = mPriv->handlesToReference; setFinished(); watcher->deleteLater(); return; } // try to request one handles at a time foreach (uint handle, mPriv->handlesToReference) { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( connection()->baseInterface()->HoldHandles( mPriv->handleType, UIntList() << handle), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onHoldHandlesFallbackFinished(QDBusPendingCallWatcher*))); mPriv->handlesForWatchers.insert(watcher, handle); } } else { mPriv->handles = ReferencedHandles(connection(), mPriv->handleType, mPriv->handlesToReference); setFinished(); } watcher->deleteLater(); } void PendingHandles::onRequestHandlesFallbackFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; Q_ASSERT(mPriv->idsForWatchers.contains(watcher)); QString id = mPriv->idsForWatchers.value(watcher); debug() << "Received reply to RequestHandles(" << id << ")"; if (reply.isError()) { debug().nospace() << " Failure: error " << reply.error().name() << ": " << reply.error().message(); // if the error is disconnected for example, fail immediately QDBusError error = reply.error(); if (error.name() != TP_QT_ERROR_INVALID_HANDLE && error.name() != TP_QT_ERROR_INVALID_ARGUMENT && error.name() != TP_QT_ERROR_NOT_AVAILABLE) { foreach (const QString &name, mPriv->namesRequested) { mPriv->invalidNames.insert(name, QPair(error.name(), error.message())); } setFinishedWithError(error); connection()->handleRequestLanded(mPriv->handleType); watcher->deleteLater(); return; } mPriv->invalidNames.insert(id, QPair(reply.error().name(), reply.error().message())); } else { Q_ASSERT(reply.value().size() == 1); uint handle = reply.value().first(); mPriv->handlesForIds.insert(id, handle); } if (++mPriv->requestsFinished == mPriv->namesRequested.size()) { if (mPriv->handlesForIds.size() == 0) { // all requests failed setFinished(); } else { // all requests either failed or finished successfully // we need to return the handles in the same order as requested UIntList handles; foreach (const QString &name, mPriv->namesRequested) { if (!mPriv->invalidNames.contains(name)) { Q_ASSERT(mPriv->handlesForIds.contains(name)); handles.append(mPriv->handlesForIds.value(name)); mPriv->validNames.append(name); } } mPriv->handles = ReferencedHandles(connection(), mPriv->handleType, handles); setFinished(); } debug() << " namesRequested:" << mPriv->namesRequested; debug() << " invalidNames :" << mPriv->invalidNames; debug() << " validNames :" << mPriv->validNames; connection()->handleRequestLanded(mPriv->handleType); } watcher->deleteLater(); } void PendingHandles::onHoldHandlesFallbackFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; Q_ASSERT(mPriv->handlesForWatchers.contains(watcher)); uint handle = mPriv->handlesForWatchers.value(watcher); debug() << "Received reply to HoldHandles(" << handle << ")"; if (reply.isError()) { debug().nospace() << " Failure: error " << reply.error().name() << ": " << reply.error().message(); // if the error is disconnected for example, fail immediately QDBusError error = reply.error(); if (error.name() != TP_QT_ERROR_INVALID_HANDLE && error.name() != TP_QT_ERROR_INVALID_ARGUMENT && error.name() != TP_QT_ERROR_NOT_AVAILABLE) { mPriv->invalidHandles = mPriv->handlesToReference; setFinishedWithError(error); watcher->deleteLater(); return; } mPriv->invalidHandles.append(handle); } if (++mPriv->requestsFinished == mPriv->namesRequested.size()) { // we need to return the handles in the same order as requested UIntList handles; foreach (uint handle, mPriv->handlesToReference) { if (!mPriv->invalidHandles.contains(handle)) { handles.append(handle); } } if (handles.size() != 0) { mPriv->handles = ReferencedHandles(connection(), mPriv->handleType, handles); } setFinished(); } watcher->deleteLater(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/OutgoingStreamTubeChannel0000664000175000017500000000043412470405660022220 0ustar jrjr#ifndef _TelepathyQt_OutgoingStreamTubeChannel_HEADER_GUARD_ #define _TelepathyQt_OutgoingStreamTubeChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PendingContactAttributes0000664000175000017500000000043012470405660022103 0ustar jrjr#ifndef _TelepathyQt_PendingContactAttributes_HEADER_GUARD_ #define _TelepathyQt_PendingContactAttributes_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PendingVoid0000664000175000017500000000037512470405660017352 0ustar jrjr#ifndef _TelepathyQt_PendingVoid_HEADER_GUARD_ #define _TelepathyQt_PendingVoid_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-contacts.h0000664000175000017500000001057212470405660020632 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2011 Collabora Ltd. * @copyright Copyright (C) 2008-2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_contacts_h_HEADER_GUARD_ #define _TelepathyQt_pending_contacts_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include namespace Tp { class ContactManager; class TP_QT_EXPORT PendingContacts : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingContacts); public: ~PendingContacts(); ContactManagerPtr manager() const; Features features() const; bool isForHandles() const; UIntList handles() const; bool isForIdentifiers() const; QStringList identifiers() const; bool isForVCardAddresses() const; QString vcardField() const; QStringList vcardAddresses() const; bool isForUris() const; QStringList uris() const; bool isUpgrade() const; QList contactsToUpgrade() const; QList contacts() const; UIntList invalidHandles() const; QStringList validIdentifiers() const; QHash > invalidIdentifiers() const; QStringList validVCardAddresses() const; QStringList invalidVCardAddresses() const; QStringList validUris() const; QStringList invalidUris() const; private Q_SLOTS: TP_QT_NO_EXPORT void onAttributesFinished(Tp::PendingOperation *); TP_QT_NO_EXPORT void onRequestHandlesFinished(Tp::PendingOperation *); TP_QT_NO_EXPORT void onAddressingGetContactsFinished(Tp::PendingOperation *); TP_QT_NO_EXPORT void onReferenceHandlesFinished(Tp::PendingOperation *); TP_QT_NO_EXPORT void onNestedFinished(Tp::PendingOperation *); TP_QT_NO_EXPORT void onInspectHandlesFinished(QDBusPendingCallWatcher *); private: friend class ContactManager; enum RequestType { ForHandles, ForIdentifiers, ForVCardAddresses, ForUris, Upgrade }; // If errorName is non-empty, these will fail instantly TP_QT_NO_EXPORT PendingContacts(const ContactManagerPtr &manager, const UIntList &handles, const Features &features, const Features &missingFeatures, const QStringList &interfaces, const QMap &satisfyingContacts, const QSet &otherContacts, const QString &errorName = QString(), const QString &errorMessage = QString()); TP_QT_NO_EXPORT PendingContacts(const ContactManagerPtr &manager, const QStringList &list, RequestType requestType, const Features &features, const QStringList &interfaces, const QString &errorName = QString(), const QString &errorMessage = QString()); TP_QT_NO_EXPORT PendingContacts(const ContactManagerPtr &manager, const QString &vcardField, const QStringList &vcardAddresses, const Features &features, const QStringList &interfaces, const QString &errorName = QString(), const QString &errorMessage = QString()); TP_QT_NO_EXPORT PendingContacts(const ContactManagerPtr &manager, const QList &contacts, const Features &features, const QString &errorName = QString(), const QString &errorMessage = QString()); TP_QT_NO_EXPORT void allAttributesFetched(); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ChannelFactory0000664000175000017500000000037112470405660020040 0ustar jrjr#ifndef _TelepathyQt_ChannelFactory_HEADER_GUARD_ #define _TelepathyQt_ChannelFactory_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-contact-info.h0000664000175000017500000000336112470405660021376 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_contact_info_h_HEADER_GUARD_ #define _TelepathyQt_pending_contact_info_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include class QDBusPendingCallWatcher; namespace Tp { class TP_QT_EXPORT PendingContactInfo : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingContactInfo); public: ~PendingContactInfo(); ContactPtr contact() const; Contact::InfoFields infoFields() const; private Q_SLOTS: TP_QT_NO_EXPORT void onCallFinished(QDBusPendingCallWatcher *watcher); private: friend class Contact; TP_QT_NO_EXPORT PendingContactInfo(const ContactPtr &contact); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/PendingContacts0000664000175000017500000000037412470405660020226 0ustar jrjr#ifndef _TelepathyQt_PendingContacts_HEADER_GUARD_ #define _TelepathyQt_PendingContacts_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PendingStreamedMediaStreams0000664000175000017500000000043212470405660022506 0ustar jrjr#ifndef _TelepathyQt_PendingStreamedMediaStreams_HEADER_GUARD_ #define _TelepathyQt_PendingStreamedMediaStreams_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/account-manager.cpp0000664000175000017500000012234012470405660020766 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/account-manager.moc.hpp" #include "TelepathyQt/_gen/cli-account-manager.moc.hpp" #include "TelepathyQt/_gen/cli-account-manager-body.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT AccountManager::Private { Private(AccountManager *parent, const AccountFactoryConstPtr &accFactory, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory); ~Private(); void init(); static void introspectMain(Private *self); void checkIntrospectionCompleted(); QSet getAccountPathsFromProp(const QVariant &prop); QSet getAccountPathsFromProps(const QVariantMap &props); void addAccountForPath(const QString &accountObjectPath); // Public object AccountManager *parent; // Instance of generated interface class Client::AccountManagerInterface *baseInterface; // Mandatory properties interface proxy Client::DBus::PropertiesInterface *properties; ReadinessHelper *readinessHelper; AccountFactoryConstPtr accFactory; ConnectionFactoryConstPtr connFactory; ChannelFactoryConstPtr chanFactory; ContactFactoryConstPtr contactFactory; // Introspection int reintrospectionRetries; bool gotInitialAccounts; QHash incompleteAccounts; QHash accounts; QStringList supportedAccountProperties; }; static const int maxReintrospectionRetries = 5; static const int reintrospectionRetryInterval = 3; AccountManager::Private::Private(AccountManager *parent, const AccountFactoryConstPtr &accFactory, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) : parent(parent), baseInterface(new Client::AccountManagerInterface(parent)), properties(parent->interface()), readinessHelper(parent->readinessHelper()), accFactory(accFactory), connFactory(connFactory), chanFactory(chanFactory), contactFactory(contactFactory), reintrospectionRetries(0), gotInitialAccounts(false) { debug() << "Creating new AccountManager:" << parent->busName(); if (accFactory->dbusConnection().name() != parent->dbusConnection().name()) { warning() << " The D-Bus connection in the account factory is not the proxy connection"; } if (connFactory->dbusConnection().name() != parent->dbusConnection().name()) { warning() << " The D-Bus connection in the connection factory is not the proxy connection"; } if (chanFactory->dbusConnection().name() != parent->dbusConnection().name()) { warning() << " The D-Bus connection in the channel factory is not the proxy connection"; } ReadinessHelper::Introspectables introspectables; // As AccountManager does not have predefined statuses let's simulate one (0) ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMain, this); introspectables[FeatureCore] = introspectableCore; readinessHelper->addIntrospectables(introspectables); readinessHelper->becomeReady(Features() << FeatureCore); init(); } AccountManager::Private::~Private() { delete baseInterface; } void AccountManager::Private::init() { if (!parent->isValid()) { return; } parent->connect(baseInterface, SIGNAL(AccountValidityChanged(QDBusObjectPath,bool)), SLOT(onAccountValidityChanged(QDBusObjectPath,bool))); parent->connect(baseInterface, SIGNAL(AccountRemoved(QDBusObjectPath)), SLOT(onAccountRemoved(QDBusObjectPath))); } void AccountManager::Private::introspectMain(AccountManager::Private *self) { debug() << "Calling Properties::GetAll(AccountManager)"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->GetAll( TP_QT_IFACE_ACCOUNT_MANAGER), self->parent); self->parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotMainProperties(QDBusPendingCallWatcher*))); } void AccountManager::Private::checkIntrospectionCompleted() { if (!parent->isReady(FeatureCore) && incompleteAccounts.size() == 0) { readinessHelper->setIntrospectCompleted(FeatureCore, true); } } QSet AccountManager::Private::getAccountPathsFromProp( const QVariant &prop) { QSet set; ObjectPathList paths = qdbus_cast(prop); if (paths.size() == 0) { /* maybe the AccountManager is buggy, like Mission Control * 5.0.beta45, and returns an array of strings rather than * an array of object paths? */ QStringList wronglyTypedPaths = qdbus_cast(prop); if (wronglyTypedPaths.size() > 0) { warning() << "AccountManager returned wrong type for" "Valid/InvalidAccounts (expected 'ao', got 'as'); " "working around it"; foreach (QString path, wronglyTypedPaths) { set << path; } } } else { foreach (const QDBusObjectPath &path, paths) { set << path.path(); } } return set; } QSet AccountManager::Private::getAccountPathsFromProps( const QVariantMap &props) { return getAccountPathsFromProp(props[QLatin1String("ValidAccounts")]).unite( getAccountPathsFromProp(props[QLatin1String("InvalidAccounts")])); } void AccountManager::Private::addAccountForPath(const QString &path) { // Also check incompleteAccounts, because otherwise we end up introspecting an account twice // when getting an AccountValidityChanged signal for a new account before we get the initial // introspection accounts list from the GetAll return (the GetAll return function // unconditionally calls addAccountForPath if (accounts.contains(path) || incompleteAccounts.contains(path)) { return; } PendingReady *readyOp = accFactory->proxy(parent->busName(), path, connFactory, chanFactory, contactFactory); AccountPtr account(AccountPtr::qObjectCast(readyOp->proxy())); Q_ASSERT(!account.isNull()); parent->connect(readyOp, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountReady(Tp::PendingOperation*))); incompleteAccounts.insert(path, account); } /** * \class AccountManager * \ingroup clientam * \headerfile TelepathyQt/account-manager.h * * \brief The AccountManager class represents a Telepathy account manager. * * The remote object accessor functions on this object (allAccounts(), * validAccounts(), and so on) don't make any D-Bus calls; instead, they return/use * values cached from a previous introspection run. The introspection process * populates their values in the most efficient way possible based on what the * service implements. * * To avoid unnecessary D-Bus traffic, some accessors only return valid * information after AccountManager::FeatureCore has been enabled. * See the individual methods descriptions for more details. * * AccountManager features can be enabled by calling becomeReady() * with the desired set of features as an argument (currently only AccountManager::FeatureCore is * supported), and waiting for the resulting PendingOperation to finish. * * All accounts returned by AccountManager are guaranteed to have the features set in the * AccountFactory used by it ready. * * A signal is emitted to indicate that accounts are added. See newCreated() for more details. * * \section am_usage_sec Usage * * \subsection am_create_sec Creating an AccountManager object * * One way to create an AccountManager object is to just call the create method. * For example: * * \code AccountManagerPtr am = AccountManager::create(); \endcode * * An AccountManagerPtr object is returned, which will automatically keep * track of object lifetime. * * You can also provide a D-Bus connection as a QDBusConnection: * * \code AccountManagerPtr am = AccountManager::create(QDBusConnection::sessionBus()); \endcode * * \subsection am_ready_sec Making AccountManager ready to use * * An AccountManager object needs to become ready before usage, meaning that the * introspection process finished and the object accessors can be used. * * To make the object ready, use becomeReady() and wait for the * PendingOperation::finished() signal to be emitted. * * \code * * class MyClass : public QObject * { * QOBJECT * * public: * MyClass(QObject *parent = 0); * ~MyClass() { } * * private Q_SLOTS: * void onAccountManagerReady(Tp::PendingOperation*); * * private: * AccountManagerPtr mAM; * }; * * MyClass::MyClass(QObject *parent) * : QObject(parent) * mAM(AccountManager::create()) * { * connect(mAM->becomeReady(), * SIGNAL(finished(Tp::PendingOperation*)), * SLOT(onAccountManagerReady(Tp::PendingOperation*))); * } * * void MyClass::onAccountManagerReady(Tp::PendingOperation *op) * { * if (op->isError()) { * qWarning() << "Account manager cannot become ready:" << * op->errorName() << "-" << op->errorMessage(); * return; * } * * // AccountManager is now ready * qDebug() << "All accounts:"; * foreach (const Tp::AccountPtr &acc, mAM->allAccounts()) { * qDebug() << " path:" << acc->objectPath(); * } * } * * \endcode * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * AccountManager object usable. * * Note that this feature must be enabled in order to use most AccountManager * methods. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature AccountManager::FeatureCore = Feature(QLatin1String(AccountManager::staticMetaObject.className()), 0, true); /** * Create a new AccountManager object using the given \a bus. * * The instance will use an account factory creating Tp::Account objects with Account::FeatureCore * ready, a connection factory creating Tp::Connection objects with no features ready, a channel * factory creating stock Tp::Channel subclasses, as appropriate, with no features ready, and a * contact factory creating Tp::Contact objects with no features ready. * * \param bus QDBusConnection to use. * \return An AccountManagerPtr object pointing to the newly created * AccountManager object. */ AccountManagerPtr AccountManager::create(const QDBusConnection &bus) { return AccountManagerPtr(new AccountManager(bus, AccountFactory::create(bus, Account::FeatureCore), ConnectionFactory::create(bus), ChannelFactory::create(bus), ContactFactory::create(), AccountManager::FeatureCore)); } /** * Create a new AccountManager using QDBusConnection::sessionBus() and the given factories. * * The connection, channel and contact factories are passed to any Account objects created by this * account manager object. In fact, they're not used directly by AccountManager at all. * * A warning is printed if the factories are for a bus different from QDBusConnection::sessionBus(). * * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return An AccountManagerPtr object pointing to the newly created * AccountManager object. */ AccountManagerPtr AccountManager::create(const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return AccountManagerPtr(new AccountManager(QDBusConnection::sessionBus(), accountFactory, connectionFactory, channelFactory, contactFactory, AccountManager::FeatureCore)); } /** * Create a new AccountManager using the given \a bus and the given factories. * * The connection, channel and contact factories are passed to any Account objects created by this * account manager object. In fact, they're not used directly by AccountManager at all. * * A warning is printed if the factories are not for \a bus. * * \param bus QDBusConnection to use. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return An AccountManagerPtr object pointing to the newly created * AccountManager object. */ AccountManagerPtr AccountManager::create(const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return AccountManagerPtr(new AccountManager(bus, accountFactory, connectionFactory, channelFactory, contactFactory, AccountManager::FeatureCore)); } /** * Construct a new AccountManager object using the given \a bus and the given factories. * * The connection, channel and contact factories are passed to any Account objects created by this * account manager object. In fact, they're not used directly by AccountManager at all. * * A warning is printed if the factories are not for \a bus. * * \param bus QDBusConnection to use. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \param coreFeature The core feature of the Account subclass. The corresponding introspectable * should depend on AccountManager::FeatureCore. */ AccountManager::AccountManager(const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const Feature &coreFeature) : StatelessDBusProxy(bus, TP_QT_ACCOUNT_MANAGER_BUS_NAME, TP_QT_ACCOUNT_MANAGER_OBJECT_PATH, coreFeature), OptionalInterfaceFactory(this), mPriv(new Private(this, accountFactory, connectionFactory, channelFactory, contactFactory)) { } /** * Class destructor. */ AccountManager::~AccountManager() { delete mPriv; } /** * Return the account factory used by this account manager. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the manager would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the AccountFactory object. */ AccountFactoryConstPtr AccountManager::accountFactory() const { return mPriv->accFactory; } /** * Return the connection factory used by this account manager. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the manager would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ConnectionFactory object. */ ConnectionFactoryConstPtr AccountManager::connectionFactory() const { return mPriv->connFactory; } /** * Return the channel factory used by this account manager. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the manager would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ChannelFactory object. */ ChannelFactoryConstPtr AccountManager::channelFactory() const { return mPriv->chanFactory; } /** * Return the contact factory used by this account manager. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the manager would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ContactFactory object. */ ContactFactoryConstPtr AccountManager::contactFactory() const { return mPriv->contactFactory; } /** * Return a list containing all accounts. * * Newly accounts added and/or discovered are signaled via newAccount(). * * This method requires AccountManager::FeatureCore to be ready. * * \return A list of pointers to Account objects. */ QList AccountManager::allAccounts() const { QList ret; foreach (const AccountPtr &account, mPriv->accounts) { ret << account; } return ret; } /** * Return a set of accounts containing all valid accounts. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::validAccounts() const { QVariantMap filter; filter.insert(QLatin1String("valid"), true); return filterAccounts(filter); } /** * Return a set of accounts containing all invalid accounts. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::invalidAccounts() const { QVariantMap filter; filter.insert(QLatin1String("valid"), false); return filterAccounts(filter); } /** * Return a set of accounts containing all enabled accounts. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::enabledAccounts() const { QVariantMap filter; filter.insert(QLatin1String("enabled"), true); return filterAccounts(filter); } /** * Return a set of accounts containing all disabled accounts. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::disabledAccounts() const { QVariantMap filter; filter.insert(QLatin1String("enabled"), false); return filterAccounts(filter); } /** * Return a set of accounts containing all online accounts. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::onlineAccounts() const { QVariantMap filter; filter.insert(QLatin1String("online"), true); return filterAccounts(filter); } /** * Return a set of accounts containing all offline accounts. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::offlineAccounts() const { QVariantMap filter; filter.insert(QLatin1String("online"), false); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that support text chats by * providing a contact identifier. * * For this method to work, you must use an AccountFactory which makes Account::FeatureCapabilities * ready. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::textChatAccounts() const { if (!accountFactory()->features().contains(Account::FeatureCapabilities)) { warning() << "Account filtering by capabilities can only be used with an AccountFactory" << "which makes Account::FeatureCapabilities ready"; return filterAccounts(AccountFilterConstPtr()); } AccountCapabilityFilterPtr filter = AccountCapabilityFilter::create(); filter->addRequestableChannelClassSubset(RequestableChannelClassSpec::textChat()); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that support text chat * rooms. * * For this method to work, you must use an AccountFactory which makes Account::FeatureCapabilities * ready. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::textChatroomAccounts() const { if (!accountFactory()->features().contains(Account::FeatureCapabilities)) { warning() << "Account filtering by capabilities can only be used with an AccountFactory" << "which makes Account::FeatureCapabilities ready"; return filterAccounts(AccountFilterConstPtr()); } AccountCapabilityFilterPtr filter = AccountCapabilityFilter::create(); filter->addRequestableChannelClassSubset(RequestableChannelClassSpec::textChatroom()); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that support audio calls (using the * Call interface) by providing a contact identifier. * * For this method to work, you must use an AccountFactory which makes Account::FeatureCapabilities * ready. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::audioCallAccounts() const { if (!accountFactory()->features().contains(Account::FeatureCapabilities)) { warning() << "Account filtering by capabilities can only be used with an AccountFactory" << "which makes Account::FeatureCapabilities ready"; return filterAccounts(AccountFilterConstPtr()); } AccountCapabilityFilterPtr filter = AccountCapabilityFilter::create(); filter->addRequestableChannelClassSubset(RequestableChannelClassSpec::audioCall()); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that support video calls (using the * Call interface) by providing a contact identifier. * * For this method to work, you must use an AccountFactory which makes Account::FeatureCapabilities * ready. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::videoCallAccounts() const { if (!accountFactory()->features().contains(Account::FeatureCapabilities)) { warning() << "Account filtering by capabilities can only be used with an AccountFactory" << "which makes Account::FeatureCapabilities ready"; return filterAccounts(AccountFilterConstPtr()); } AccountCapabilityFilterPtr filter = AccountCapabilityFilter::create(); filter->addRequestableChannelClassSubset(RequestableChannelClassSpec::videoCall()); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that support media calls (using the * StreamedMedia interface) by providing a contact identifier. * * For this method to work, you must use an AccountFactory which makes Account::FeatureCapabilities * ready. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::streamedMediaCallAccounts() const { if (!accountFactory()->features().contains(Account::FeatureCapabilities)) { warning() << "Account filtering by capabilities can only be used with an AccountFactory" << "which makes Account::FeatureCapabilities ready"; return filterAccounts(AccountFilterConstPtr()); } AccountCapabilityFilterPtr filter = AccountCapabilityFilter::create(); filter->addRequestableChannelClassSubset(RequestableChannelClassSpec::streamedMediaCall()); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that support audio calls (using the * StreamedMedia interface) by providing a contact identifier. * * For this method to work, you must use an AccountFactory which makes Account::FeatureCapabilities * ready. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::streamedMediaAudioCallAccounts() const { if (!accountFactory()->features().contains(Account::FeatureCapabilities)) { warning() << "Account filtering by capabilities can only be used with an AccountFactory" << "which makes Account::FeatureCapabilities ready"; return filterAccounts(AccountFilterConstPtr()); } AccountCapabilityFilterPtr filter = AccountCapabilityFilter::create(); filter->addRequestableChannelClassSubset(RequestableChannelClassSpec::streamedMediaAudioCall()); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that support video calls (using the * StreamedMedia interface) by providing a contact identifier. * * For this method to work, you must use an AccountFactory which makes Account::FeatureCapabilities * ready. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::streamedMediaVideoCallAccounts() const { if (!accountFactory()->features().contains(Account::FeatureCapabilities)) { warning() << "Account filtering by capabilities can only be used with an AccountFactory" << "which makes Account::FeatureCapabilities ready"; return filterAccounts(AccountFilterConstPtr()); } AccountCapabilityFilterPtr filter = AccountCapabilityFilter::create(); filter->addRequestableChannelClassSubset(RequestableChannelClassSpec::streamedMediaVideoCall()); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that support video calls with audio (using the * StreamedMedia interface) by providing a contact identifier. * * For this method to work, you must use an AccountFactory which makes Account::FeatureCapabilities * ready. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::streamedMediaVideoCallWithAudioAccounts() const { if (!accountFactory()->features().contains(Account::FeatureCapabilities)) { warning() << "Account filtering by capabilities can only be used with an AccountFactory" << "which makes Account::FeatureCapabilities ready"; return filterAccounts(AccountFilterConstPtr()); } AccountCapabilityFilterPtr filter = AccountCapabilityFilter::create(); filter->addRequestableChannelClassSubset( RequestableChannelClassSpec::streamedMediaVideoCallWithAudio()); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that support file transfers by * providing a contact identifier. * * For this method to work, you must use an AccountFactory which makes Account::FeatureCapabilities * ready. * * This method requires AccountManager::FeatureCore to be ready. * * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::fileTransferAccounts() const { if (!accountFactory()->features().contains(Account::FeatureCapabilities)) { warning() << "Account filtering by capabilities can only be used with an AccountFactory" << "which makes Account::FeatureCapabilities ready"; return filterAccounts(AccountFilterConstPtr()); } AccountCapabilityFilterPtr filter = AccountCapabilityFilter::create(); filter->addRequestableChannelClassSubset(RequestableChannelClassSpec::fileTransfer()); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts for the given \a * protocolName. * * This method requires AccountManager::FeatureCore to be ready. * * \param protocolName The name of the protocol used to filter accounts. * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::accountsByProtocol( const QString &protocolName) const { if (!isReady(FeatureCore)) { warning() << "Account filtering requires AccountManager to be ready"; return filterAccounts(AccountFilterConstPtr()); } QVariantMap filter; filter.insert(QLatin1String("protocolName"), protocolName); return filterAccounts(filter); } /** * Return a set of accounts containing all accounts that match the given \a * filter criteria. * * For AccountCapabilityFilter filtering, an AccountFactory which makes * Account::FeatureCapabilities ready must be used. * * See AccountSet documentation for more details. * * This method requires AccountManager::FeatureCore to be ready. * * \param filter The desired filter. * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::filterAccounts(const AccountFilterConstPtr &filter) const { if (!isReady(FeatureCore)) { warning() << "Account filtering requires AccountManager to be ready"; return AccountSetPtr(new AccountSet(AccountManagerPtr( (AccountManager *) this), AccountFilterConstPtr())); } return AccountSetPtr(new AccountSet(AccountManagerPtr( (AccountManager *) this), filter)); } /** * Return a set of accounts containing all accounts that match the given \a * filter criteria. * * The \a filter is composed by Account property names and values as map items. * * The following example will return all jabber accounts that are enabled: * * \code * * void MyClass::init() * { * mAM = AccountManager::create(); * connect(mAM->becomeReady(), * SIGNAL(finished(Tp::PendingOperation*)), * SLOT(onAccountManagerReady(Tp::PendingOperation*))); * } * * void MyClass::onAccountManagerReady(Tp::PendingOperation *op) * { * if (op->isError()) { * qWarning() << "Account manager cannot become ready:" << * op->errorName() << "-" << op->errorMessage(); * return; * } * * QVariantMap filter; * filter.insert(QLatin1String("protocolName"), QLatin1String("jabber")); * filter.insert(QLatin1String("enabled"), true); * filteredAccountSet = mAM->filterAccounts(filter); * // connect to AccountSet::accountAdded/accountRemoved signals * QList accounts = filteredAccountSet->accounts(); * // do something with accounts * } * * \endcode * * See AccountSet documentation for more details. * * This method requires AccountManager::FeatureCore to be ready. * * \param filter The desired filter. * \return A pointer to an AccountSet object containing the matching accounts. */ AccountSetPtr AccountManager::filterAccounts(const QVariantMap &filter) const { if (!isReady(FeatureCore)) { warning() << "Account filtering requires AccountManager to be ready"; return AccountSetPtr(new AccountSet(AccountManagerPtr( (AccountManager *) this), QVariantMap())); } return AccountSetPtr(new AccountSet(AccountManagerPtr( (AccountManager *) this), filter)); } /** * Return the account for the given \a path. * * This method requires AccountManager::FeatureCore to be ready. * * \param path The account object path. * \return A pointer to an AccountSet object containing the matching accounts. * \sa allAccounts(), accountsForObjectPaths() */ AccountPtr AccountManager::accountForObjectPath(const QString &path) const { if (!isReady(FeatureCore)) { return AccountPtr(); } return mPriv->accounts.value(path); } /** * \deprecated See accountForObjectPath() */ AccountPtr AccountManager::accountForPath(const QString &path) const { return accountForObjectPath(path); } /** * Return a list of accounts for the given \a paths. * * The returned list will have one AccountPtr object for each given path. If * a given path is invalid the returned AccountPtr object will point to 0. * AccountPtr::isNull() will return true. * * This method requires AccountManager::FeatureCore to be ready. * * \param paths List of accounts object paths. * \return A list of pointers to Account objects for the given * \a paths. Null AccountPtr objects will be used as list elements for each invalid path. * \sa allAccounts(), accountForObjectPath() */ QList AccountManager::accountsForObjectPaths(const QStringList &paths) const { if (!isReady(FeatureCore)) { return QList(); } QList result; foreach (const QString &path, paths) { result << accountForObjectPath(path); } return result; } /** * \deprecated See accountsForObjectPaths() */ QList AccountManager::accountsForPaths(const QStringList &paths) const { return accountsForObjectPaths(paths); } /** * Return a list of the fully qualified names of properties that can be set * when calling createAccount(). * * \return A list of fully qualified D-Bus property names, * such as "org.freedesktop.Telepathy.Account.Enabled". * \sa createAccount() */ QStringList AccountManager::supportedAccountProperties() const { return mPriv->supportedAccountProperties; } /** * Create an account with the given parameters. * * The optional \a properties argument can be used to set any property listed in * supportedAccountProperties() at the time the account is created. * * \param connectionManager The name of the connection manager to create the account * for. * \param protocol The name of the protocol to create the account for. * \param displayName The account display name. * \param parameters The account parameters. * \param properties An optional map from fully qualified D-Bus property * names such as "org.freedesktop.Telepathy.Account.Enabled" * to their values. * \return A PendingAccount object which will emit PendingAccount::finished * when the account has been created of failed its creation process. * \sa supportedAccountProperties() */ PendingAccount *AccountManager::createAccount(const QString &connectionManager, const QString &protocol, const QString &displayName, const QVariantMap ¶meters, const QVariantMap &properties) { return new PendingAccount(AccountManagerPtr(this), connectionManager, protocol, displayName, parameters, properties); } /** * Return the Client::AccountManagerInterface interface proxy object for this * account manager. This method is protected since the convenience methods * provided by this class should generally be used instead of calling D-Bus * methods directly. * * \return A pointer to the existing Client::AccountManagerInterface object for * this AccountManager object. */ Client::AccountManagerInterface *AccountManager::baseInterface() const { return mPriv->baseInterface; } void AccountManager::introspectMain() { mPriv->introspectMain(mPriv); } void AccountManager::gotMainProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; QVariantMap props; if (!reply.isError()) { mPriv->gotInitialAccounts = true; debug() << "Got reply to Properties.GetAll(AccountManager)"; props = reply.value(); if (props.contains(QLatin1String("Interfaces"))) { setInterfaces(qdbus_cast(props[QLatin1String("Interfaces")])); mPriv->readinessHelper->setInterfaces(interfaces()); } if (props.contains(QLatin1String("SupportedAccountProperties"))) { mPriv->supportedAccountProperties = qdbus_cast(props[QLatin1String("SupportedAccountProperties")]); } QSet paths = mPriv->getAccountPathsFromProps(props); foreach (const QString &path, paths) { mPriv->addAccountForPath(path); } mPriv->checkIntrospectionCompleted(); } else { if (mPriv->reintrospectionRetries++ < maxReintrospectionRetries) { int retryInterval = reintrospectionRetryInterval; if (reply.error().type() == QDBusError::TimedOut) { retryInterval = 0; } QTimer::singleShot(retryInterval, this, SLOT(introspectMain())); } else { warning() << "GetAll(AccountManager) failed with" << reply.error().name() << ":" << reply.error().message(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); } } watcher->deleteLater(); } void AccountManager::onAccountReady(Tp::PendingOperation *op) { PendingReady *pr = qobject_cast(op); AccountPtr account(AccountPtr::qObjectCast(pr->proxy())); QString path = account->objectPath(); /* Some error occurred or the account was removed before become ready */ if (op->isError() || !mPriv->incompleteAccounts.contains(path)) { mPriv->incompleteAccounts.remove(path); mPriv->checkIntrospectionCompleted(); return; } mPriv->incompleteAccounts.remove(path); // We shouldn't end up here twice for the same account - that would also mean newAccount being // emitted twice for an account, and AccountSets getting confused as a result Q_ASSERT(!mPriv->accounts.contains(path)); mPriv->accounts.insert(path, account); if (isReady(FeatureCore)) { emit newAccount(account); } mPriv->checkIntrospectionCompleted(); } void AccountManager::onAccountValidityChanged(const QDBusObjectPath &objectPath, bool valid) { if (!mPriv->gotInitialAccounts) { return; } QString path = objectPath.path(); if (!mPriv->incompleteAccounts.contains(path) && !mPriv->accounts.contains(path)) { debug() << "New account" << path; mPriv->addAccountForPath(path); } } void AccountManager::onAccountRemoved(const QDBusObjectPath &objectPath) { if (!mPriv->gotInitialAccounts) { return; } QString path = objectPath.path(); /* the account is either in mPriv->incompleteAccounts or mPriv->accounts */ if (mPriv->accounts.contains(path)) { mPriv->accounts.remove(path); if (isReady(FeatureCore)) { debug() << "Account" << path << "removed"; } else { debug() << "Account" << path << "removed while the AM " "was not completely introspected"; } } else if (mPriv->incompleteAccounts.contains(path)) { mPriv->incompleteAccounts.remove(path); debug() << "Account" << path << "was removed, but it was " "not completely introspected, ignoring"; } else { debug() << "Got AccountRemoved for unknown account" << path << ", ignoring"; } } /** * \fn void AccountManager::newAccount(const Tp::AccountPtr &account) * * Emitted when a new account is created. * * The new \a account will have the features set in the AccountFactory used by this * account manager ready and the same connection, channel and contact factories as used by this * account manager. * * \param account The newly created account. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceMessagesInterface0000664000175000017500000000042712470405660023644 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceMessagesInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceMessagesInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel-class-spec.h0000664000175000017500000002651612470405660021042 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_channel_class_spec_h_HEADER_GUARD_ #define _TelepathyQt_channel_class_spec_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include namespace Tp { class TP_QT_EXPORT ChannelClassSpec { public: ChannelClassSpec(); ChannelClassSpec(const ChannelClass &cc); ChannelClassSpec(const QVariantMap &props); ChannelClassSpec(const QString &channelType, HandleType targetHandleType, const QVariantMap &otherProperties = QVariantMap()); ChannelClassSpec(const QString &channelType, HandleType targetHandleType, bool requested, const QVariantMap &otherProperties = QVariantMap()); ChannelClassSpec(const ChannelClassSpec &other, const QVariantMap &additionalProperties = QVariantMap()); ~ChannelClassSpec(); bool isValid() const; ChannelClassSpec &operator=(const ChannelClassSpec &other); bool operator==(const ChannelClassSpec &other) const { return this->allProperties() == other.allProperties(); } bool isSubsetOf(const ChannelClassSpec &other) const; bool matches(const QVariantMap &immutableProperties) const; QString channelType() const { return qdbus_cast( property(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"))); } void setChannelType(const QString &type) { setProperty(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), QVariant::fromValue(type)); } HandleType targetHandleType() const { return (HandleType) qdbus_cast( property( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"))); } void setTargetHandleType(HandleType type) { setProperty(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), QVariant::fromValue((uint) type)); } bool hasRequested() const { return hasProperty(TP_QT_IFACE_CHANNEL + QLatin1String(".Requested")); } bool isRequested() const { return qdbus_cast( property(TP_QT_IFACE_CHANNEL + QLatin1String(".Requested"))); } void setRequested(bool requested) { setProperty(TP_QT_IFACE_CHANNEL + QLatin1String(".Requested"), QVariant::fromValue(requested)); } void unsetRequested() { unsetProperty(TP_QT_IFACE_CHANNEL + QLatin1String(".Requested")); } bool hasCallInitialAudioFlag() const { return qdbus_cast( property(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"))); } void setCallInitialAudioFlag() { setProperty(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"), QVariant::fromValue(true)); } void unsetCallInitialAudioFlag() { unsetProperty(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio")); } bool hasCallInitialVideoFlag() const { return qdbus_cast( property(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo"))); } void setCallInitialVideoFlag() { setProperty(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo"), QVariant::fromValue(true)); } void unsetCallInitialVideoFlag() { unsetProperty(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo")); } TP_QT_DEPRECATED bool hasStreamedMediaInitialAudioFlag() const { return qdbus_cast( property(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio"))); } TP_QT_DEPRECATED void setStreamedMediaInitialAudioFlag() { setProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio"), QVariant::fromValue(true)); } TP_QT_DEPRECATED void unsetStreamedMediaInitialAudioFlag() { unsetProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio")); } TP_QT_DEPRECATED bool hasStreamedMediaInitialVideoFlag() const { return qdbus_cast( property(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo"))); } TP_QT_DEPRECATED void setStreamedMediaInitialVideoFlag() { setProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo"), QVariant::fromValue(true)); } TP_QT_DEPRECATED void unsetStreamedMediaInitialVideoFlag() { unsetProperty(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo")); } bool hasProperty(const QString &qualifiedName) const; QVariant property(const QString &qualifiedName) const; void setProperty(const QString &qualifiedName, const QVariant &value); void unsetProperty(const QString &qualifiedName); QVariantMap allProperties() const; ChannelClass bareClass() const; static ChannelClassSpec textChat(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec textChatroom(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec unnamedTextChat(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec mediaCall(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec audioCall(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec videoCall(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec videoCallWithAudio(const QVariantMap &additionalProperties = QVariantMap()); TP_QT_DEPRECATED static ChannelClassSpec streamedMediaCall(const QVariantMap &additionalProperties = QVariantMap()); TP_QT_DEPRECATED static ChannelClassSpec streamedMediaAudioCall(const QVariantMap &additionalProperties = QVariantMap()); TP_QT_DEPRECATED static ChannelClassSpec streamedMediaVideoCall(const QVariantMap &additionalProperties = QVariantMap()); TP_QT_DEPRECATED static ChannelClassSpec streamedMediaVideoCallWithAudio(const QVariantMap &additionalProperties = QVariantMap()); TP_QT_DEPRECATED static ChannelClassSpec unnamedStreamedMediaCall(const QVariantMap &additionalProperties = QVariantMap()); TP_QT_DEPRECATED static ChannelClassSpec unnamedStreamedMediaAudioCall(const QVariantMap &additionalProperties = QVariantMap()); TP_QT_DEPRECATED static ChannelClassSpec unnamedStreamedMediaVideoCall(const QVariantMap &additionalProperties = QVariantMap()); TP_QT_DEPRECATED static ChannelClassSpec unnamedStreamedMediaVideoCallWithAudio(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec serverAuthentication(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec roomList(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec outgoingFileTransfer(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec incomingFileTransfer(const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec outgoingStreamTube(const QString &service = QString(), const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec incomingStreamTube(const QString &service = QString(), const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec outgoingRoomStreamTube(const QString &service = QString(), const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec incomingRoomStreamTube(const QString &service = QString(), const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec outgoingDBusTube(const QString &serviceName = QString(), const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec incomingDBusTube(const QString &serviceName = QString(), const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec outgoingRoomDBusTube(const QString &serviceName = QString(), const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec incomingRoomDBusTube(const QString &serviceName = QString(), const QVariantMap &additionalProperties = QVariantMap()); static ChannelClassSpec contactSearch(const QVariantMap &additionalProperties = QVariantMap()); private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; class TP_QT_EXPORT ChannelClassSpecList : public QList { public: ChannelClassSpecList() { } ChannelClassSpecList(const ChannelClassSpec &spec) { append(spec); } ChannelClassSpecList(const QList &other) : QList(other) { } ChannelClassSpecList(const ChannelClassList &classes) { // Why doesn't Qt have range constructors like STL... stupid, so stupid. Q_FOREACH (const ChannelClass &cc, classes) { append(cc); } } ChannelClassList bareClasses() const { ChannelClassList list; Q_FOREACH (const ChannelClassSpec &spec, *this) { list.append(spec.bareClass()); } return list; } }; inline uint qHash(const ChannelClassSpec &spec) { uint ret = 0; QVariantMap::const_iterator it = spec.allProperties().constBegin(); QVariantMap::const_iterator end = spec.allProperties().constEnd(); int i = spec.allProperties().size() + 1; for (; it != end; ++it) { // all D-Bus types should be convertible to QString QPair p(it.key(), it.value().toString()); int h = qHash(p); ret ^= ((h << (2 << i)) | (h >> (2 >> i))); i--; } return ret; } inline uint qHash(const QSet &specSet) { int ret = 0; Q_FOREACH (const ChannelClassSpec &spec, specSet) { int h = qHash(spec); ret ^= h; } return ret; } inline uint qHash(const ChannelClassSpecList &specList) { // Make it unique by converting to QSet QSet uniqueSet = specList.toSet(); return qHash(uniqueSet); } } // Tp Q_DECLARE_METATYPE(Tp::ChannelClassSpec); Q_DECLARE_METATYPE(Tp::ChannelClassSpecList); #endif telepathy-qt-0.9.6~git1/TelepathyQt/dbus-proxy-factory-internal.h0000664000175000017500000000312312470405660022757 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef BUILDING_TP_QT #error "This file is a TpQt internal header not to be included by applications" #endif #include #include #include #include namespace Tp { class DBusProxy; class TP_QT_NO_EXPORT DBusProxyFactory::Cache : public QObject { Q_OBJECT public: typedef QPair Key; Cache(); ~Cache(); DBusProxyPtr get(const Key &key) const; void put(const DBusProxyPtr &proxy); private Q_SLOTS: void onProxyInvalidated(Tp::DBusProxy *proxy); // The error itself is not interesting private: QHash > proxies; }; } telepathy-qt-0.9.6~git1/TelepathyQt/ChannelDispatcherInterface0000664000175000017500000000042412470405660022337 0ustar jrjr#ifndef _TelepathyQt_ChannelDispatcherInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelDispatcherInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ContactMessenger0000664000175000017500000000037712470405660020412 0ustar jrjr#ifndef _TelepathyQt_ContactMessenger_HEADER_GUARD_ #define _TelepathyQt_ContactMessenger_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelRequestHints0000664000175000017500000000040312470405660021063 0ustar jrjr#ifndef _TelepathyQt_ChannelRequestHints_HEADER_GUARD_ #define _TelepathyQt_ChannelRequestHints_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceMediaSignallingInterface0000664000175000017500000000044512470405660025124 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceMediaSignallingInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceMediaSignallingInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/account-property-filter.cpp0000664000175000017500000000526012470405660022524 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/debug-internal.h" #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT AccountPropertyFilter::Private { Private() { if (supportedAccountProperties.isEmpty()) { const QMetaObject metaObject = Account::staticMetaObject; for (int i = metaObject.propertyOffset(); i < metaObject.propertyCount(); ++i) { supportedAccountProperties << QLatin1String(metaObject.property(i).name()); } } } static QStringList supportedAccountProperties; }; QStringList AccountPropertyFilter::Private::supportedAccountProperties; /** * \class Tp::AccountPropertyFilter * \ingroup utils * \headerfile TelepathyQt/account-property-filter.h * * \brief The AccountPropertyFilter class provides a filter object to be used * to filter accounts by properties. */ AccountPropertyFilter::AccountPropertyFilter() : GenericPropertyFilter(), mPriv(new Private()) { } AccountPropertyFilter::~AccountPropertyFilter() { delete mPriv; } bool AccountPropertyFilter::isValid() const { QVariantMap mFilter = filter(); if (mFilter.isEmpty()) { return false; } QVariantMap::const_iterator i = mFilter.constBegin(); QVariantMap::const_iterator end = mFilter.constEnd(); while (i != end) { QString propertyName = i.key(); if (!mPriv->supportedAccountProperties.contains(propertyName)) { warning() << "Invalid filter key" << propertyName << "while filtering account by properties"; return false; } ++i; } return true; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/PendingString0000664000175000017500000000036612470405660017717 0ustar jrjr#ifndef _TelepathyQt_PendingString_HEADER_GUARD_ #define _TelepathyQt_PendingString_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/call-stream-endpoint.xml0000664000175000017500000000037312470405660021763 0ustar jrjr Call misc interfaces, version 1 telepathy-qt-0.9.6~git1/TelepathyQt/pending-stream-tube-connection.cpp0000664000175000017500000002047512470405660023737 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-stream-tube-connection.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include "TelepathyQt/types-internal.h" namespace Tp { struct TP_QT_NO_EXPORT PendingStreamTubeConnection::Private { Private(PendingStreamTubeConnection *parent); ~Private(); // Public object PendingStreamTubeConnection *parent; IncomingStreamTubeChannelPtr tube; SocketAddressType type; QHostAddress hostAddress; quint16 port; QString socketPath; bool requiresCredentials; uchar credentialByte; }; PendingStreamTubeConnection::Private::Private(PendingStreamTubeConnection *parent) : parent(parent), requiresCredentials(false), credentialByte(0) { } PendingStreamTubeConnection::Private::~Private() { } /** * \class PendingStreamTubeConnection * \ingroup clientchannel * \headerfile TelepathyQt/incoming-stream-tube-channel.h * * \brief The PendingStreamTubeConnection class represents an asynchronous * operation for accepting an incoming stream tube. * * See \ref async_model */ PendingStreamTubeConnection::PendingStreamTubeConnection( PendingVariant *acceptOperation, SocketAddressType type, bool requiresCredentials, uchar credentialByte, const IncomingStreamTubeChannelPtr &channel) : PendingOperation(channel), mPriv(new Private(this)) { mPriv->tube = channel; mPriv->type = type; mPriv->requiresCredentials = requiresCredentials; mPriv->credentialByte = credentialByte; /* keep track of channel invalidation */ connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString))); debug() << "Calling StreamTube.Accept"; if (acceptOperation->isFinished()) { onAcceptFinished(acceptOperation); } else { connect(acceptOperation, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAcceptFinished(Tp::PendingOperation*))); } } PendingStreamTubeConnection::PendingStreamTubeConnection( const QString& errorName, const QString& errorMessage, const IncomingStreamTubeChannelPtr &channel) : PendingOperation(channel), mPriv(new PendingStreamTubeConnection::Private(this)) { setFinishedWithError(errorName, errorMessage); } /** * Class destructor. */ PendingStreamTubeConnection::~PendingStreamTubeConnection() { delete mPriv; } /** * Return the type of the opened stream tube socket. * * \return The socket type as #SocketAddressType. * \see localAddress(), ipAddress() */ SocketAddressType PendingStreamTubeConnection::addressType() const { return mPriv->tube->addressType(); } /** * Return the local address of the opened stream tube socket. * * This method will return a meaningful value only if the incoming stream tube * was accepted as an Unix socket. * * \return Unix socket address if using an Unix socket, * or an undefined value otherwise. * \see addressType(), ipAddress() */ QString PendingStreamTubeConnection::localAddress() const { return mPriv->tube->localAddress(); } /** * Return the IP address/port combination of the opened stream tube socket. * * This method will return a meaningful value only if the incoming stream tube * was accepted as a TCP socket. * * \return Pair of IP address as QHostAddress and port if using a TCP socket, * or an undefined value otherwise. * \see addressType(), localAddress() */ QPair PendingStreamTubeConnection::ipAddress() const { return mPriv->tube->ipAddress(); } /** * Return whether sending a credential byte once connecting to the socket is required. * * Note that if this method returns \c true, one should send a SCM_CREDS or SCM_CREDENTIALS * and the credentialByte() once connected. If SCM_CREDS or SCM_CREDENTIALS cannot be sent, * the credentialByte() should still be sent. * * \return \c true if sending credentials is required, \c false otherwise. * \sa credentialByte() */ bool PendingStreamTubeConnection::requiresCredentials() const { return mPriv->requiresCredentials; } /** * Return the credential byte to send once connecting to the socket if requiresCredentials() is \c * true. * * \return The credential byte. * \sa requiresCredentials() */ uchar PendingStreamTubeConnection::credentialByte() const { return mPriv->credentialByte; } void PendingStreamTubeConnection::onChannelInvalidated(DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { Q_UNUSED(proxy); if (isFinished()) { return; } warning().nospace() << "StreamTube.Accept failed because channel was invalidated with " << errorName << ": " << errorMessage; setFinishedWithError(errorName, errorMessage); } void PendingStreamTubeConnection::onAcceptFinished(PendingOperation *op) { if (isFinished()) { return; } if (op->isError()) { warning().nospace() << "StreamTube.Accept failed with " << op->errorName() << ": " << op->errorMessage(); setFinishedWithError(op->errorName(), op->errorMessage()); return; } debug() << "StreamTube.Accept returned successfully"; PendingVariant *pv = qobject_cast(op); // Build the address if (mPriv->type == SocketAddressTypeIPv4) { SocketAddressIPv4 addr = qdbus_cast(pv->result()); debug().nospace() << "Got address " << addr.address << ":" << addr.port; mPriv->hostAddress = QHostAddress(addr.address); mPriv->port = addr.port; } else if (mPriv->type == SocketAddressTypeIPv6) { SocketAddressIPv6 addr = qdbus_cast(pv->result()); debug().nospace() << "Got address " << addr.address << ":" << addr.port; mPriv->hostAddress = QHostAddress(addr.address); mPriv->port = addr.port; } else { // Unix socket mPriv->socketPath = QLatin1String(qdbus_cast(pv->result())); debug() << "Got socket " << mPriv->socketPath; } // It might have been already opened - check if (mPriv->tube->state() == TubeChannelStateOpen) { onTubeStateChanged(mPriv->tube->state()); } else { // Wait until the tube gets opened on the other side connect(mPriv->tube.data(), SIGNAL(stateChanged(Tp::TubeChannelState)), this, SLOT(onTubeStateChanged(Tp::TubeChannelState))); } } void PendingStreamTubeConnection::onTubeStateChanged(TubeChannelState state) { debug() << "Tube state changed to " << state; if (state == TubeChannelStateOpen) { // The tube is ready, populate its properties if (mPriv->type == SocketAddressTypeIPv4 || mPriv->type == SocketAddressTypeIPv6) { mPriv->tube->setIpAddress(qMakePair(mPriv->hostAddress, mPriv->port)); } else { // Unix socket mPriv->tube->setLocalAddress(mPriv->socketPath); } // Mark the operation as finished setFinished(); } else if (state != TubeChannelStateLocalPending) { // Something happened setFinishedWithError(QLatin1String("Connection refused"), QLatin1String("The connection to this tube was refused")); } } } telepathy-qt-0.9.6~git1/TelepathyQt/MediaStreamHandlerInterface0000664000175000017500000000043012470405660022446 0ustar jrjr#ifndef _TelepathyQt_MediaStreamHandlerInterface_HEADER_GUARD_ #define _TelepathyQt_MediaStreamHandlerInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ClientHandlerInterface0000664000175000017500000000040012470405660021466 0ustar jrjr#ifndef _TelepathyQt_ClientHandlerInterface_HEADER_GUARD_ #define _TelepathyQt_ClientHandlerInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/handled-channel-notifier.h0000664000175000017500000000426212470405660022213 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_handled_channel_notifier_h_HEADER_GUARD_ #define _TelepathyQt_handled_channel_notifier_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class ChannelRequestHints; class RequestTemporaryHandler; class TP_QT_EXPORT HandledChannelNotifier : public QObject { Q_OBJECT Q_DISABLE_COPY(HandledChannelNotifier) public: ~HandledChannelNotifier(); ChannelPtr channel() const; Q_SIGNALS: void handledAgain(const QDateTime &userActionTime, const Tp::ChannelRequestHints &requestHints); protected: #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) void connectNotify(const QMetaMethod &signal); #else void connectNotify(const char *signal); #endif private Q_SLOTS: TP_QT_NO_EXPORT void onChannelReceived(const Tp::ChannelPtr &channel, const QDateTime &userActionTime, const Tp::ChannelRequestHints &requestHints); TP_QT_NO_EXPORT void onChannelInvalidated(); private: friend class PendingChannel; HandledChannelNotifier(const ClientRegistrarPtr &cr, const SharedPtr &handler); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/DBusDaemonInterface0000664000175000017500000000037012470405660020741 0ustar jrjr#ifndef _TelepathyQt_DBusDaemonInterface_HEADER_GUARD_ #define _TelepathyQt_DBusDaemonInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceAnonymityInterface0000664000175000017500000000044212470405660024610 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceAnonymityInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceAnonymityInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/DBus0000664000175000017500000000033212470405660015772 0ustar jrjr#ifndef _TelepathyQt_DBus_HEADER_GUARD_ #define _TelepathyQt_DBus_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/call-stream.h0000664000175000017500000000616512470405660017601 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_call_stream_h_HEADER_GUARD_ #define _TelepathyQt_call_stream_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include namespace Tp { typedef QList CallStreams; class TP_QT_EXPORT CallStream : public StatefulDBusProxy, public OptionalInterfaceFactory { Q_OBJECT Q_DISABLE_COPY(CallStream) public: ~CallStream(); CallContentPtr content() const; Contacts remoteMembers() const; bool canRequestReceiving() const; SendingState localSendingState() const; SendingState remoteSendingState(const ContactPtr &contact) const; PendingOperation *requestSending(bool send); PendingOperation *requestReceiving(const ContactPtr &contact, bool receive); Q_SIGNALS: void localSendingStateChanged(Tp::SendingState localSendingState, const Tp::CallStateReason &reason); void remoteSendingStateChanged( const QHash &remoteSendingStates, const Tp::CallStateReason &reason); void remoteMembersRemoved(const Tp::Contacts &remoteMembers, const Tp::CallStateReason &reason); private Q_SLOTS: TP_QT_NO_EXPORT void gotMainProperties(Tp::PendingOperation *op); TP_QT_NO_EXPORT void gotRemoteMembersContacts(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onRemoteMembersChanged(const Tp::ContactSendingStateMap &updates, const Tp::HandleIdentifierMap &identifiers, const Tp::UIntList &removed, const Tp::CallStateReason &reason); TP_QT_NO_EXPORT void onLocalSendingStateChanged(uint, const Tp::CallStateReason &reason); private: friend class CallChannel; friend class CallContent; TP_QT_NO_EXPORT static const Feature FeatureCore; TP_QT_NO_EXPORT CallStream(const CallContentPtr &content, const QDBusObjectPath &streamPath); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/file-transfer-channel-creation-properties.cpp0000664000175000017500000002704612470405660026074 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "TelepathyQt/debug-internal.h" #include #include #include namespace Tp { struct TP_QT_NO_EXPORT FileTransferChannelCreationProperties::Private : public QSharedData { Private(const QString &suggestedFileName, const QString &contentType, qulonglong size) : contentType(contentType), size(size), contentHashType(FileHashTypeNone) { QFileInfo fileInfo(suggestedFileName); this->suggestedFileName = fileInfo.fileName(); } Private(const QString &path, const QString &contentType) : contentType(contentType), contentHashType(FileHashTypeNone) { QFileInfo fileInfo(path); if (fileInfo.exists()) { // Set mandatory parameters suggestedFileName = fileInfo.fileName(); size = fileInfo.size(); QUrl fileUri = QUrl::fromLocalFile(fileInfo.canonicalFilePath()); uri = fileUri.toString(); // Set optional parameters lastModificationTime = fileInfo.lastModified(); } else { warning() << path << "is not a local file."; } } /* mandatory parameters */ QString suggestedFileName; QString contentType; qulonglong size; /* optional parameters */ FileHashType contentHashType; QString contentHash; QString description; QDateTime lastModificationTime; QString uri; }; /** * \class FileTransferChannelCreationProperties * \ingroup clientchannel * \headerfile TelepathyQt/file-transfer-channel-creation-properties.h * * \brief The FileTransferChannelCreationProperties class represents the * properties of a file transfer channel request. */ /** * Create an invalid FileTransferChannelCreationProperties. */ FileTransferChannelCreationProperties::FileTransferChannelCreationProperties() { } /** * Create a FileTransferChannelCreationProperties. * * If \a suggestedFileName or \a contentType are empty or if \a size is equal to * zero, the channel request will fail. * \a suggestedFileName will be cleaned of any path. * * \param suggestedFileName The name of the file on the sender's side. This is * therefore given as a suggested filename for the * receiver. * \param contentType The content type (MIME) of the file. * \param size The size of the content of the file. * \sa setUri() */ FileTransferChannelCreationProperties::FileTransferChannelCreationProperties( const QString &suggestedFileName, const QString &contentType, qulonglong size) : mPriv(new Private(suggestedFileName, contentType, size)) { } /** * Create a FileTransferChannelCreationProperties. * * This constructor accepts the path to a local file and sets the properties * that can be deducted from the file. * If \a path is not a local file the FileTransferChannelCreationProperties * will be invalid. * * \param path The path to the local file to be sent. */ FileTransferChannelCreationProperties::FileTransferChannelCreationProperties( const QString &path, const QString &contentType) : mPriv(new Private(path, contentType)) { if (mPriv->suggestedFileName.isEmpty()) { mPriv = QSharedDataPointer(NULL); } } /** * Copy constructor. */ FileTransferChannelCreationProperties::FileTransferChannelCreationProperties( const FileTransferChannelCreationProperties &other) : mPriv(other.mPriv) { } /** * Class destructor. */ FileTransferChannelCreationProperties::~FileTransferChannelCreationProperties() { } FileTransferChannelCreationProperties &FileTransferChannelCreationProperties::operator=( const FileTransferChannelCreationProperties &other) { this->mPriv = other.mPriv; return *this; } bool FileTransferChannelCreationProperties::operator==( const FileTransferChannelCreationProperties &other) const { return mPriv == other.mPriv; } /** * Set the content hash of the file and its type for the request. * * \param contentHashType The type of content hash. * \param contentHash The hash of the file, of type \a contentHashType. * \return This FileTransferChannelCreationProperties. * \sa hasContentHash(), contentHash(), contentHashType() */ FileTransferChannelCreationProperties &FileTransferChannelCreationProperties::setContentHash( FileHashType contentHashType, const QString &contentHash) { if (!isValid()) { // there is no point in updating content hash if not valid, as we miss filename, content // type and size return *this; } mPriv->contentHashType = contentHashType; mPriv->contentHash = contentHash; return *this; } /** * Set a description of the file for the request. * * \param description The description of the file. * \return This FileTransferChannelCreationProperties. * \sa hasDescription(), description() */ FileTransferChannelCreationProperties &FileTransferChannelCreationProperties::setDescription( const QString &description) { if (!isValid()) { // there is no point in updating description if not valid, as we miss filename, content // type and size return *this; } mPriv->description = description; return *this; } /** * Set the last modification time of the file for the request. * * \param lastModificationTime The last modification time of the file. * \return This FileTransferChannelCreationProperties. * \sa hasLastModificationTime(), lastModificationTime() */ FileTransferChannelCreationProperties &FileTransferChannelCreationProperties::setLastModificationTime( const QDateTime &lastModificationTime) { if (!isValid()) { // there is no point in updating last modification time if not valid, as we miss filename, // content type and size return *this; } mPriv->lastModificationTime = lastModificationTime; return *this; } /** * Set the URI of the file for the request. * * \param uri The URI of the file. * \return This FileTransferChannelCreationProperties. * \sa uri() */ FileTransferChannelCreationProperties &FileTransferChannelCreationProperties::setUri( const QString &uri) { if (!isValid()) { // there is no point in updating uri if not valid, as we miss filename, content // type and size return *this; } mPriv->uri = uri; return *this; } /** * Return the suggested file name for the request. * If the suggested file name is empty, the channel request will fail. * * \return The suggested file name for the request. */ QString FileTransferChannelCreationProperties::suggestedFileName() const { if (!isValid()) { return QString(); } return mPriv->suggestedFileName; } /** * Return the content type (MIME) of the file for the request. * If the content type is empty, the channel request will fail. * * \return The content type of the file. */ QString FileTransferChannelCreationProperties::contentType() const { if (!isValid()) { return QString(); } return mPriv->contentType; } /** * Return the size of the contents of the file for the request. * If size is zero, the channel request will fail. * * \return The size of the contents of file. */ qulonglong FileTransferChannelCreationProperties::size() const { if (!isValid()) { return 0; } return mPriv->size; } /** * Return whether the request will have a content hash. * * \return \c true whether it will have a content hash, \c false otherwise. * \sa contentHash(), contentHashType(), setContentHash() */ bool FileTransferChannelCreationProperties::hasContentHash() const { if (!isValid()) { return false; } return (mPriv->contentHashType != FileHashTypeNone); } /** * Return the type of the content hash for the request. * * \return The type of the content hash. * \sa hasContentHash(), contentHash(), setContentHash() */ FileHashType FileTransferChannelCreationProperties::contentHashType() const { if (!isValid()) { return FileHashTypeNone; } return mPriv->contentHashType; } /** * Return the content hash of the file for the request. * * \return The hash of the contents of the file transfer, of type returned by * contentHashType(). * \sa hasContentHash(), contentHashType(), setContentHash() */ QString FileTransferChannelCreationProperties::contentHash() const { if (!isValid()) { return QString(); } return mPriv->contentHash; } /** * Return whether the request will have a descriprion. * * \return \c true whether it will have description, \c false otherwise. * \sa description(), setDescription() */ bool FileTransferChannelCreationProperties::hasDescription() const { if (!isValid()) { return false; } return (!mPriv->description.isEmpty()); } /** * Return the description of the file for the request. * * \return The description of the file. * \sa hasDescription(), setDescription() */ QString FileTransferChannelCreationProperties::description() const { if (!isValid()) { return QString(); } return mPriv->description; } /** * Return whether the request will have a last modification time. * * \return \c true whether it will have a last modification time, \c false * otherwise. * \sa lastModificationTime(), setLastModificationTime() */ bool FileTransferChannelCreationProperties::hasLastModificationTime() const { if (!isValid()) { return false; } return (mPriv->lastModificationTime.isValid()); } /** * Return the last modification time of the file for the request. * * \return The last modification time of the file. * \sa hasLastModificationTime(), setLastModificationTime() */ QDateTime FileTransferChannelCreationProperties::lastModificationTime() const { if (!isValid()) { return QDateTime(); } return mPriv->lastModificationTime; } /** * Return whether the request will have an URI. * * \return \c true whether it will have URI, \c false otherwise. * \sa uri(), setUri() */ bool FileTransferChannelCreationProperties::hasUri() const { if (!isValid()) { return false; } return (!mPriv->uri.isEmpty()); } /** * Return the URI of the file for the request. * If the URI property is empty and the file transfer is handled by an handler * that is not this process, then it won't be able to initiate the file * transfer. * * \return The URI of the file. * \sa setUri() */ QString FileTransferChannelCreationProperties::uri() const { if (!isValid()) { return QString(); } return mPriv->uri; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/DBusProxy0000664000175000017500000000035212470405660017036 0ustar jrjr#ifndef _TelepathyQt_DBusProxy_HEADER_GUARD_ #define _TelepathyQt_DBusProxy_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/base-call.h0000664000175000017500000001344712470405660017221 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2013 Matthias Gehre * @copyright Copyright 2013 Canonical Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_base_call_h_HEADER_GUARD_ #define _TelepathyQt_base_call_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include class QString; namespace Tp { class TP_QT_EXPORT AbstractCallContentInterface : public AbstractDBusServiceInterface { Q_OBJECT Q_DISABLE_COPY(AbstractCallContentInterface) public: AbstractCallContentInterface(const QString &interfaceName); virtual ~AbstractCallContentInterface(); private: friend class BaseCallContent; class Private; friend class Private; Private *mPriv; }; class TP_QT_EXPORT BaseCallContent : public DBusService { Q_OBJECT Q_DISABLE_COPY(BaseCallContent) public: static BaseCallContentPtr create(const QDBusConnection &dbusConnection, BaseChannel* channel, const QString &name, const Tp::MediaStreamType &type, const Tp::MediaStreamDirection &direction) { return BaseCallContentPtr(new BaseCallContent(dbusConnection, channel, name, type, direction)); } virtual ~BaseCallContent(); QVariantMap immutableProperties() const; bool registerObject(DBusError *error = NULL); virtual QString uniqueName() const; QList interfaces() const; AbstractCallContentInterfacePtr interface(const QString &interfaceName) const; bool plugInterface(const AbstractCallContentInterfacePtr &interface); QString name() const; Tp::MediaStreamType type() const; Tp::CallContentDisposition disposition() const; Tp::ObjectPathList streams() const; protected: BaseCallContent(const QDBusConnection &dbusConnection, BaseChannel* channel, const QString &name, const Tp::MediaStreamType &type, const Tp::MediaStreamDirection &direction); virtual bool registerObject(const QString &busName, const QString &objectPath, DBusError *error); void remove(); private: class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseCallMuteInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseCallMuteInterface) public: static BaseCallMuteInterfacePtr create() { return BaseCallMuteInterfacePtr(new BaseCallMuteInterface()); } template static SharedPtr create() { return SharedPtr( new BaseCallMuteInterfaceSubclass()); } virtual ~BaseCallMuteInterface(); QVariantMap immutableProperties() const; Tp::LocalMuteState localMuteState() const; void setMuteState(const Tp::LocalMuteState &state); typedef Callback2 SetMuteStateCallback; void setSetMuteStateCallback(const SetMuteStateCallback &cb); Q_SIGNALS: void muteStateChanged(const Tp::LocalMuteState &state); private: BaseCallMuteInterface(); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseCallContentDTMFInterface : public AbstractCallContentInterface { Q_OBJECT Q_DISABLE_COPY(BaseCallContentDTMFInterface) public: static BaseCallContentDTMFInterfacePtr create() { return BaseCallContentDTMFInterfacePtr(new BaseCallContentDTMFInterface()); } template static SharedPtr create() { return SharedPtr( new BaseCallContentDTMFInterfaceSubclass()); } virtual ~BaseCallContentDTMFInterface(); QVariantMap immutableProperties() const; bool currentlySendingTones() const; void setCurrentlySendingTones(bool sendingTones); QString deferredTones() const; void setDeferredTones(const QString &deferredTones); typedef Callback2 StartToneCallback; void setStartToneCallback(const StartToneCallback &cb); typedef Callback1 StopToneCallback; void setStopToneCallback(const StopToneCallback &cb); typedef Callback2 MultipleTonesCallback; void setMultipleTonesCallback(const MultipleTonesCallback &cb); Q_SIGNALS: private: BaseCallContentDTMFInterface(); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/ReceivedMessage0000664000175000017500000000036312470405660020174 0ustar jrjr#ifndef _TelepathyQt_ReceivedMessage_HEADER_GUARD_ #define _TelepathyQt_ReceivedMessage_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceSubjectInterface0000664000175000017500000000042512470405660023472 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceSubjectInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceSubjectInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/file-transfer-channel-creation-properties.h0000664000175000017500000000613712470405660025537 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_file_transfer_channel_creation_properties_h_HEADER_GUARD_ #define _TelepathyQt_file_transfer_channel_creation_properties_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include namespace Tp { class TP_QT_EXPORT FileTransferChannelCreationProperties { public: FileTransferChannelCreationProperties(); FileTransferChannelCreationProperties(const QString &suggestedFileName, const QString &contentType, qulonglong size); FileTransferChannelCreationProperties(const QString &path, const QString &contentType); FileTransferChannelCreationProperties( const FileTransferChannelCreationProperties &other); ~FileTransferChannelCreationProperties(); bool isValid() const { return mPriv.constData() != 0; } FileTransferChannelCreationProperties &operator=( const FileTransferChannelCreationProperties &other); bool operator==(const FileTransferChannelCreationProperties &other) const; FileTransferChannelCreationProperties &setContentHash( FileHashType contentHashType, const QString &contentHash); FileTransferChannelCreationProperties &setDescription( const QString &description); FileTransferChannelCreationProperties &setLastModificationTime( const QDateTime &lastModificationTime); FileTransferChannelCreationProperties &setUri(const QString &uri); /* mandatory parameters */ QString suggestedFileName() const; QString contentType() const; qulonglong size() const; /* optional parameters */ bool hasContentHash() const; FileHashType contentHashType() const; QString contentHash() const; bool hasDescription() const; QString description() const; bool hasLastModificationTime() const; QDateTime lastModificationTime() const; bool hasUri() const; QString uri() const; private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::FileTransferChannelCreationProperties); #endif telepathy-qt-0.9.6~git1/TelepathyQt/CallContent0000664000175000017500000000036012470405660017344 0ustar jrjr#ifndef _TelepathyQt_CallContent_HEADER_GUARD_ #define _TelepathyQt_CallContent_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/future-misc.xml0000664000175000017500000000031412470405660020177 0ustar jrjr Miscellaneous extensions from the future telepathy-qt-0.9.6~git1/TelepathyQt/account.h0000664000175000017500000007123412470405660017030 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_account_h_HEADER_GUARD_ #define _TelepathyQt_account_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { class Account; class Connection; class PendingChannel; class PendingChannelRequest; class PendingConnection; class PendingOperation; class PendingReady; class PendingStringList; class TP_QT_EXPORT Account : public StatelessDBusProxy, public OptionalInterfaceFactory { Q_OBJECT Q_DISABLE_COPY(Account) Q_PROPERTY(bool valid READ isValidAccount NOTIFY validityChanged) Q_PROPERTY(bool enabled READ isEnabled NOTIFY stateChanged) Q_PROPERTY(QString cmName READ cmName) Q_PROPERTY(QString protocolName READ protocolName) Q_PROPERTY(QString serviceName READ serviceName NOTIFY serviceNameChanged) Q_PROPERTY(ProfilePtr profile READ profile NOTIFY profileChanged) Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged) Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged) Q_PROPERTY(QString nickname READ nickname NOTIFY nicknameChanged) Q_PROPERTY(AvatarSpec avatarRequirements READ avatarRequirements) Q_PROPERTY(Avatar avatar READ avatar NOTIFY avatarChanged) Q_PROPERTY(QVariantMap parameters READ parameters NOTIFY parametersChanged) Q_PROPERTY(ProtocolInfo protocolInfo READ protocolInfo) Q_PROPERTY(ConnectionCapabilities capabilities READ capabilities NOTIFY capabilitiesChanged) Q_PROPERTY(bool hasBeenOnline READ hasBeenOnline) Q_PROPERTY(bool connectsAutomatically READ connectsAutomatically NOTIFY connectsAutomaticallyPropertyChanged) Q_PROPERTY(ConnectionStatus connectionStatus READ connectionStatus NOTIFY connectionStatusChanged) Q_PROPERTY(ConnectionStatusReason connectionStatusReason READ connectionStatusReason) Q_PROPERTY(QString connectionError READ connectionError) Q_PROPERTY(Tp::Connection::ErrorDetails connectionErrorDetails READ connectionErrorDetails) Q_PROPERTY(ConnectionPtr connection READ connection NOTIFY connectionChanged) Q_PROPERTY(bool changingPresence READ isChangingPresence NOTIFY changingPresence) Q_PROPERTY(Presence automaticPresence READ automaticPresence NOTIFY automaticPresenceChanged) Q_PROPERTY(Presence currentPresence READ currentPresence NOTIFY currentPresenceChanged) Q_PROPERTY(Presence requestedPresence READ requestedPresence NOTIFY requestedPresenceChanged) Q_PROPERTY(bool online READ isOnline NOTIFY onlinenessChanged) Q_PROPERTY(QString uniqueIdentifier READ uniqueIdentifier) Q_PROPERTY(QString normalizedName READ normalizedName NOTIFY normalizedNameChanged) public: static const Feature FeatureCore; static const Feature FeatureAvatar; static const Feature FeatureProtocolInfo; static const Feature FeatureCapabilities; static const Feature FeatureProfile; static AccountPtr create(const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connectionFactory = ConnectionFactory::create(QDBusConnection::sessionBus()), const ChannelFactoryConstPtr &channelFactory = ChannelFactory::create(QDBusConnection::sessionBus()), const ContactFactoryConstPtr &contactFactory = ContactFactory::create()); static AccountPtr create(const QDBusConnection &bus, const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory = ContactFactory::create()); virtual ~Account(); ConnectionFactoryConstPtr connectionFactory() const; ChannelFactoryConstPtr channelFactory() const; ContactFactoryConstPtr contactFactory() const; bool isValidAccount() const; bool isEnabled() const; PendingOperation *setEnabled(bool value); QString cmName() const; QString protocolName() const; QString serviceName() const; PendingOperation *setServiceName(const QString &value); ProfilePtr profile() const; QString displayName() const; PendingOperation *setDisplayName(const QString &value); QString iconName() const; PendingOperation *setIconName(const QString &value); QString nickname() const; PendingOperation *setNickname(const QString &value); AvatarSpec avatarRequirements() const; // TODO: We probably want to expose the avatar file name once we have the avatar token and MC // starts sharing the cache used by tp-qt and tp-glib and use Tp::AvatarData to represent // it as used in Tp::Contact const Avatar &avatar() const; PendingOperation *setAvatar(const Avatar &avatar); QVariantMap parameters() const; PendingStringList *updateParameters(const QVariantMap &set, const QStringList &unset); ProtocolInfo protocolInfo() const; ConnectionCapabilities capabilities() const; bool connectsAutomatically() const; PendingOperation *setConnectsAutomatically(bool value); bool hasBeenOnline() const; ConnectionStatus connectionStatus() const; ConnectionStatusReason connectionStatusReason() const; QString connectionError() const; Connection::ErrorDetails connectionErrorDetails() const; ConnectionPtr connection() const; bool isChangingPresence() const; PresenceSpecList allowedPresenceStatuses(bool includeAllStatuses = false) const; uint maxPresenceStatusMessageLength() const; // TODO: Add overload methods to set presence from a Profile::Presence // TODO: Add usablePresences() that would return a list of presences that could be set on the // account Presence automaticPresence() const; PendingOperation *setAutomaticPresence(const Presence &presence); Presence currentPresence() const; Presence requestedPresence() const; PendingOperation *setRequestedPresence(const Presence &presence); bool isOnline() const; QString uniqueIdentifier() const; QString normalizedName() const; PendingOperation *reconnect(); PendingOperation *remove(); bool supportsRequestHints() const; bool requestsSucceedWithChannel() const; PendingChannelRequest *ensureTextChat( const QString &contactIdentifier, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *ensureTextChat( const ContactPtr &contact, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *ensureTextChatroom( const QString &roomName, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *ensureAudioCall( const QString &contactIdentifier, const QString &initialAudioContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *ensureAudioCall( const ContactPtr &contact, const QString &initialAudioContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *ensureVideoCall( const QString &contactIdentifier, const QString &initialVideoContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *ensureVideoCall( const ContactPtr &contact, const QString &initialVideoContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *ensureAudioVideoCall( const QString &contactIdentifier, const QString &initialAudioContentName = QString(), const QString &initialVideoContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *ensureAudioVideoCall( const ContactPtr &contact, const QString &initialAudioContentName = QString(), const QString &initialVideoContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); TP_QT_DEPRECATED PendingChannelRequest *ensureStreamedMediaCall( const QString &contactIdentifier, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); TP_QT_DEPRECATED PendingChannelRequest *ensureStreamedMediaCall( const ContactPtr &contact, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); TP_QT_DEPRECATED PendingChannelRequest *ensureStreamedMediaAudioCall( const QString &contactIdentifier, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); TP_QT_DEPRECATED PendingChannelRequest *ensureStreamedMediaAudioCall( const ContactPtr &contact, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); TP_QT_DEPRECATED PendingChannelRequest *ensureStreamedMediaVideoCall( const QString &contactIdentifier, bool withAudio = true, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); TP_QT_DEPRECATED PendingChannelRequest *ensureStreamedMediaVideoCall( const ContactPtr &contact, bool withAudio = false, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createFileTransfer( const QString &contactIdentifier, const FileTransferChannelCreationProperties &properties, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createFileTransfer( const ContactPtr &contact, const FileTransferChannelCreationProperties &properties, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createStreamTube( const QString &contactIdentifier, const QString &service, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createStreamTube( const ContactPtr &contact, const QString &service, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createDBusTube( const QString &contactIdentifier, const QString &serviceName, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createDBusTube( const ContactPtr &contact, const QString &serviceName, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createDBusTubeRoom( const QString &room, const QString &serviceName, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); TP_QT_DEPRECATED PendingChannelRequest *createConferenceStreamedMediaCall( const QList &channels, const QStringList &initialInviteeContactsIdentifiers = QStringList(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); TP_QT_DEPRECATED PendingChannelRequest *createConferenceStreamedMediaCall( const QList &channels, const QList &initialInviteeContacts = QList(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createConferenceCall( const QList &channels, const QStringList &initialInviteeContactsIdentifiers = QStringList(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createConferenceCall( const QList &channels, const QList &initialInviteeContacts = QList(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createConferenceTextChat( const QList &channels, const QList &initialInviteeContacts = QList(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createConferenceTextChat( const QList &channels, const QStringList &initialInviteeContactsIdentifiers = QStringList(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createConferenceTextChatroom( const QString &roomName, const QList &channels, const QStringList &initialInviteeContactsIdentifiers = QStringList(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *createConferenceTextChatroom( const QString &roomName, const QList &channels, const QList &initialInviteeContacts = QList(), const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannel *createAndHandleConferenceCall( const QList &channels, const QStringList &initialInviteeContactsIdentifiers = QStringList(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleConferenceCall( const QList &channels, const QList &initialInviteeContacts = QList(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannelRequest *createContactSearch( const QString &server, uint limit = 0, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannel *ensureAndHandleTextChat( const QString &contactIdentifier, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *ensureAndHandleTextChat( const ContactPtr &contact, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *ensureAndHandleTextChatroom( const QString &roomName, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *ensureAndHandleAudioCall( const QString &contactIdentifier, const QString &initialAudioContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *ensureAndHandleAudioCall( const ContactPtr &contact, const QString &initialAudioContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *ensureAndHandleVideoCall( const QString &contactIdentifier, const QString &initialVideoContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *ensureAndHandleVideoCall( const ContactPtr &contact, const QString &initialVideoContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *ensureAndHandleAudioVideoCall( const QString &contactIdentifier, const QString &initialAudioContentName = QString(), const QString &initialVideoContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *ensureAndHandleAudioVideoCall( const ContactPtr &contact, const QString &initialAudioContentName = QString(), const QString &initialVideoContentName = QString(), const QDateTime &userActionTime = QDateTime::currentDateTime()); TP_QT_DEPRECATED PendingChannel *ensureAndHandleStreamedMediaCall( const QString &contactIdentifier, const QDateTime &userActionTime = QDateTime::currentDateTime()); TP_QT_DEPRECATED PendingChannel *ensureAndHandleStreamedMediaCall( const ContactPtr &contact, const QDateTime &userActionTime = QDateTime::currentDateTime()); TP_QT_DEPRECATED PendingChannel *ensureAndHandleStreamedMediaAudioCall( const QString &contactIdentifier, const QDateTime &userActionTime = QDateTime::currentDateTime()); TP_QT_DEPRECATED PendingChannel *ensureAndHandleStreamedMediaAudioCall( const ContactPtr &contact, const QDateTime &userActionTime = QDateTime::currentDateTime()); TP_QT_DEPRECATED PendingChannel *ensureAndHandleStreamedMediaVideoCall( const QString &contactIdentifier, bool withAudio = true, const QDateTime &userActionTime = QDateTime::currentDateTime()); TP_QT_DEPRECATED PendingChannel *ensureAndHandleStreamedMediaVideoCall( const ContactPtr &contact, bool withAudio = true, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleFileTransfer( const QString &contactIdentifier, const FileTransferChannelCreationProperties &properties, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleFileTransfer( const ContactPtr &contact, const FileTransferChannelCreationProperties &properties, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleStreamTube( const QString &contactIdentifier, const QString &service, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleStreamTube( const ContactPtr &contact, const QString &service, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleDBusTube( const QString &contactIdentifier, const QString &serviceName, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleDBusTube( const ContactPtr &contact, const QString &serviceName, const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleConferenceTextChat( const QList &channels, const QList &initialInviteeContacts = QList(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleConferenceTextChat( const QList &channels, const QStringList &initialInviteeContactsIdentifiers = QStringList(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleConferenceTextChatroom( const QString &roomName, const QList &channels, const QStringList &initialInviteeContactsIdentifiers = QStringList(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleConferenceTextChatroom( const QString &roomName, const QList &channels, const QList &initialInviteeContacts = QList(), const QDateTime &userActionTime = QDateTime::currentDateTime()); TP_QT_DEPRECATED PendingChannel *createAndHandleConferenceStreamedMediaCall( const QList &channels, const QStringList &initialInviteeContactsIdentifiers = QStringList(), const QDateTime &userActionTime = QDateTime::currentDateTime()); TP_QT_DEPRECATED PendingChannel *createAndHandleConferenceStreamedMediaCall( const QList &channels, const QList &initialInviteeContacts = QList(), const QDateTime &userActionTime = QDateTime::currentDateTime()); PendingChannel *createAndHandleContactSearch( const QString &server = QString(), uint limit = 0, const QDateTime &userActionTime = QDateTime::currentDateTime()); // advanced PendingChannelRequest *createChannel( const QVariantMap &requestedProperties, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannelRequest *ensureChannel( const QVariantMap &requestedProperties, const QDateTime &userActionTime = QDateTime::currentDateTime(), const QString &preferredHandler = QString(), const ChannelRequestHints &hints = ChannelRequestHints()); PendingChannel *createAndHandleChannel( const QVariantMap &requestedProperties, const QDateTime &userActionTime); PendingChannel *ensureAndHandleChannel( const QVariantMap &requestedProperties, const QDateTime &userActionTime); Q_SIGNALS: void removed(); void serviceNameChanged(const QString &serviceName); void profileChanged(const Tp::ProfilePtr &profile); void displayNameChanged(const QString &displayName); void iconNameChanged(const QString &iconName); void nicknameChanged(const QString &nickname); void normalizedNameChanged(const QString &normalizedName); void validityChanged(bool validity); void stateChanged(bool state); void capabilitiesChanged(const Tp::ConnectionCapabilities &capabilities); void connectsAutomaticallyPropertyChanged(bool connectsAutomatically); void firstOnline(); void parametersChanged(const QVariantMap ¶meters); void changingPresence(bool value); void automaticPresenceChanged(const Tp::Presence &automaticPresence); void currentPresenceChanged(const Tp::Presence ¤tPresence); void requestedPresenceChanged(const Tp::Presence &requestedPresence); void onlinenessChanged(bool online); void avatarChanged(const Tp::Avatar &avatar); void connectionStatusChanged(Tp::ConnectionStatus status); void connectionChanged(const Tp::ConnectionPtr &connection); protected: friend class PendingChannelRequest; // to access dispatcherInterface() Account(const QDBusConnection &bus, const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const Feature &coreFeature); Client::AccountInterface *baseInterface() const; Client::ChannelDispatcherInterface *dispatcherInterface() const; private Q_SLOTS: TP_QT_NO_EXPORT void onDispatcherIntrospected(Tp::PendingOperation *op); TP_QT_NO_EXPORT void gotMainProperties(QDBusPendingCallWatcher *); TP_QT_NO_EXPORT void gotAvatar(QDBusPendingCallWatcher *); TP_QT_NO_EXPORT void onAvatarChanged(); TP_QT_NO_EXPORT void onConnectionManagerReady(Tp::PendingOperation *); TP_QT_NO_EXPORT void onConnectionReady(Tp::PendingOperation *); TP_QT_NO_EXPORT void onPropertyChanged(const QVariantMap &delta); TP_QT_NO_EXPORT void onRemoved(); TP_QT_NO_EXPORT void onConnectionBuilt(Tp::PendingOperation *); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/abstract-interface.h0000664000175000017500000000517412470405660021135 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_abstract_interface_h_HEADER_GUARD_ #define _TelepathyQt_abstract_interface_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class DBusProxy; class PendingVariant; class PendingOperation; class PendingVariantMap; class TP_QT_EXPORT AbstractInterface : public QDBusAbstractInterface { Q_OBJECT Q_DISABLE_COPY(AbstractInterface) public: virtual ~AbstractInterface(); bool isValid() const; QString invalidationReason() const; QString invalidationMessage() const; void setMonitorProperties(bool monitorProperties); bool isMonitoringProperties() const; Q_SIGNALS: void propertiesChanged(const QVariantMap &changedProperties, const QStringList &invalidatedProperties); protected Q_SLOTS: virtual void invalidate(Tp::DBusProxy *proxy, const QString &error, const QString &message); protected: AbstractInterface(DBusProxy *proxy, const QLatin1String &interface); AbstractInterface(const QString &busName, const QString &path, const QLatin1String &interface, const QDBusConnection &connection, QObject *parent); PendingVariant *internalRequestProperty(const QString &name) const; PendingOperation *internalSetProperty(const QString &name, const QVariant &newValue); PendingVariantMap *internalRequestAllProperties() const; private Q_SLOTS: TP_QT_NO_EXPORT void onPropertiesChanged(const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/call-content.xml0000664000175000017500000000100112470405660020311 0ustar jrjr Call Content interfaces, version 1 telepathy-qt-0.9.6~git1/TelepathyQt/connection-manager-internal.h0000664000175000017500000001254112470405660022751 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_connection_manager_internal_h_HEADER_GUARD_ #define _TelepathyQt_connection_manager_internal_h_HEADER_GUARD_ #include #include #include #include #include #include namespace Tp { class ConnectionManager; class ReadinessHelper; struct TP_QT_NO_EXPORT ConnectionManager::Private { Private(ConnectionManager *parent, const QString &name, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory); ~Private(); bool parseConfigFile(); static void introspectMain(Private *self); void introspectProtocolsLegacy(); void introspectParametersLegacy(); static QString makeBusName(const QString &name); static QString makeObjectPath(const QString &name); class PendingNames; class ProtocolWrapper; // Public object ConnectionManager *parent; ConnectionManagerLowlevelPtr lowlevel; QString name; // Instance of generated interface class Client::ConnectionManagerInterface *baseInterface; // Mandatory properties interface proxy Client::DBus::PropertiesInterface *properties; ReadinessHelper *readinessHelper; ConnectionFactoryConstPtr connFactory; ChannelFactoryConstPtr chanFactory; ContactFactoryConstPtr contactFactory; // Introspection QQueue parametersQueue; ProtocolInfoList protocols; QSet > wrappers; }; struct TP_QT_NO_EXPORT ConnectionManagerLowlevel::Private { Private(ConnectionManager *cm) : cm(cm) { } WeakPtr cm; }; class TP_QT_NO_EXPORT ConnectionManager::Private::PendingNames : public PendingStringList { Q_OBJECT public: PendingNames(const QDBusConnection &bus); ~PendingNames() {}; private Q_SLOTS: void onCallFinished(QDBusPendingCallWatcher *); void continueProcessing(); private: void invokeMethod(const QLatin1String &method); void parseResult(const QStringList &names); QQueue mMethodsQueue; QSet mResult; QDBusConnection mBus; }; class TP_QT_NO_EXPORT ConnectionManager::Private::ProtocolWrapper : public StatelessDBusProxy, public OptionalInterfaceFactory { Q_OBJECT public: static const Feature FeatureCore; ProtocolWrapper(const ConnectionManagerPtr &cm, const QString &objectPath, const QString &name, const QVariantMap &props); ~ProtocolWrapper(); ProtocolInfo info() const { return mInfo; } inline Client::ProtocolInterface *baseInterface() const { return interface(); } inline Client::ProtocolInterfaceAvatarsInterface *avatarsInterface() const { return interface(); } inline Client::ProtocolInterfacePresenceInterface *presenceInterface() const { return interface(); } inline Client::ProtocolInterfaceAddressingInterface *addressingInterface() const { return interface(); } private Q_SLOTS: void gotMainProperties(Tp::PendingOperation *op); void gotAvatarsProperties(Tp::PendingOperation *op); void gotPresenceProperties(Tp::PendingOperation *op); void gotAddressingProperties(Tp::PendingOperation *op); private: static void introspectMain(ProtocolWrapper *self); void introspectMainProperties(); void introspectInterfaces(); void introspectAvatars(); void introspectPresence(); void introspectAddressing(); void continueIntrospection(); QVariantMap qualifyProperties(const QString &ifaceName, const QVariantMap &unqualifiedProps); void fillRCCs(); bool extractImmutableProperties(); void extractMainProperties(const QVariantMap &props); void extractAvatarsProperties(const QVariantMap &props); void extractPresenceProperties(const QVariantMap &props); void extractAddressingProperties(const QVariantMap &props); ReadinessHelper *mReadinessHelper; ProtocolInfo mInfo; QVariantMap mImmutableProps; bool mHasMainProps; bool mHasAvatarsProps; bool mHasPresenceProps; bool mHasAddressingProps; QQueue introspectQueue; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/connection.cpp0000664000175000017500000026670112470405660020073 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "TelepathyQt/connection-internal.h" #include "TelepathyQt/_gen/cli-connection.moc.hpp" #include "TelepathyQt/_gen/cli-connection-body.hpp" #include "TelepathyQt/_gen/connection.moc.hpp" #include "TelepathyQt/_gen/connection-internal.moc.hpp" #include "TelepathyQt/_gen/connection-lowlevel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT Connection::Private { Private(Connection *parent, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory); ~Private(); void init(); static void introspectMain(Private *self); void introspectMainFallbackStatus(); void introspectMainFallbackInterfaces(); void introspectMainFallbackSelfHandle(); void introspectCapabilities(); void introspectContactAttributeInterfaces(); static void introspectSelfContact(Private *self); static void introspectSimplePresence(Private *self); static void introspectRoster(Private *self); static void introspectRosterGroups(Private *self); static void introspectBalance(Private *self); static void introspectConnected(Private *self); void continueMainIntrospection(); void setCurrentStatus(uint status); void forceCurrentStatus(uint status); void setInterfaces(const QStringList &interfaces); // Should always be used instead of directly using baseclass invalidate() void invalidateResetCaps(const QString &errorName, const QString &errorMessage); struct HandleContext; // Public object Connection *parent; ConnectionLowlevelPtr lowlevel; // Factories ChannelFactoryConstPtr chanFactory; ContactFactoryConstPtr contactFactory; // Instance of generated interface class Client::ConnectionInterface *baseInterface; // Mandatory properties interface proxy Client::DBus::PropertiesInterface *properties; // Optional interface proxies Client::ConnectionInterfaceSimplePresenceInterface *simplePresence; ReadinessHelper *readinessHelper; // Introspection QQueue introspectMainQueue; // FeatureCore // keep pendingStatus and pendingStatusReason until we emit statusChanged // so Connection::status() and Connection::statusReason() are consistent bool introspectingConnected; uint pendingStatus; uint pendingStatusReason; uint status; uint statusReason; ErrorDetails errorDetails; uint selfHandle; bool immortalHandles; ConnectionCapabilities caps; ContactManagerPtr contactManager; // FeatureSelfContact bool introspectingSelfContact; bool reintrospectSelfContactRequired; ContactPtr selfContact; QStringList contactAttributeInterfaces; // FeatureSimplePresence SimpleStatusSpecMap simplePresenceStatuses; uint maxPresenceStatusMessageLength; // FeatureAccountBalance CurrencyAmount accountBalance; // misc // (Bus connection name, service name) -> HandleContext static QHash, HandleContext *> handleContexts; static QMutex handleContextsLock; HandleContext *handleContext; QString cmName; QString protocolName; }; struct TP_QT_NO_EXPORT ConnectionLowlevel::Private { Private(Connection *conn) : conn(conn) { } WeakPtr conn; HandleIdentifierMap contactsIds; }; // Handle tracking struct TP_QT_NO_EXPORT Connection::Private::HandleContext { struct Type { QHash refcounts; QSet toRelease; uint requestsInFlight; bool releaseScheduled; Type() : requestsInFlight(0), releaseScheduled(false) { } }; HandleContext() : refcount(0) { } int refcount; QMutex lock; QHash types; }; Connection::Private::Private(Connection *parent, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) : parent(parent), lowlevel(ConnectionLowlevelPtr(new ConnectionLowlevel(parent))), chanFactory(chanFactory), contactFactory(contactFactory), baseInterface(new Client::ConnectionInterface(parent)), properties(parent->interface()), simplePresence(0), readinessHelper(parent->readinessHelper()), introspectingConnected(false), pendingStatus((uint) -1), pendingStatusReason(ConnectionStatusReasonNoneSpecified), status((uint) -1), statusReason(ConnectionStatusReasonNoneSpecified), selfHandle(0), immortalHandles(false), contactManager(ContactManagerPtr(new ContactManager(parent))), introspectingSelfContact(false), reintrospectSelfContactRequired(false), maxPresenceStatusMessageLength(0), handleContext(0) { accountBalance.amount = 0; accountBalance.scale = 0; Q_ASSERT(properties != 0); if (chanFactory->dbusConnection().name() != parent->dbusConnection().name()) { warning() << " The D-Bus connection in the channel factory is not the proxy connection"; } init(); ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableCore( QSet() << (uint) -1 << ConnectionStatusDisconnected << ConnectionStatusConnected, // makesSenseForStatuses Features(), // dependsOnFeatures (none) QStringList(), // dependsOnInterfaces (none) (ReadinessHelper::IntrospectFunc) &Private::introspectMain, this); introspectables[FeatureCore] = introspectableCore; ReadinessHelper::Introspectable introspectableSelfContact( QSet() << ConnectionStatusConnected, // makesSenseForStatuses Features() << FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectSelfContact, this); introspectables[FeatureSelfContact] = introspectableSelfContact; ReadinessHelper::Introspectable introspectableSimplePresence( QSet() << ConnectionStatusDisconnected << ConnectionStatusConnected, // makesSenseForStatuses Features() << FeatureCore, // dependsOnFeatures (core) QStringList() << TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectSimplePresence, this); introspectables[FeatureSimplePresence] = introspectableSimplePresence; ReadinessHelper::Introspectable introspectableRoster( QSet() << ConnectionStatusConnected, // makesSenseForStatuses Features() << FeatureCore, // dependsOnFeatures (core) QStringList() << TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectRoster, this); introspectables[FeatureRoster] = introspectableRoster; ReadinessHelper::Introspectable introspectableRosterGroups( QSet() << ConnectionStatusConnected, // makesSenseForStatuses Features() << FeatureRoster, // dependsOnFeatures (core) QStringList() << TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectRosterGroups, this); introspectables[FeatureRosterGroups] = introspectableRosterGroups; ReadinessHelper::Introspectable introspectableBalance( QSet() << ConnectionStatusConnected, // makesSenseForStatuses Features() << FeatureCore, // dependsOnFeatures (core) QStringList() << TP_QT_IFACE_CONNECTION_INTERFACE_BALANCE, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectBalance, this); introspectables[FeatureAccountBalance] = introspectableBalance; ReadinessHelper::Introspectable introspectableConnected( QSet() << (uint) -1 << ConnectionStatusDisconnected << ConnectionStatusConnecting << ConnectionStatusConnected, // makesSenseForStatuses Features() << FeatureCore, // dependsOnFeatures (none) QStringList(), // dependsOnInterfaces (none) (ReadinessHelper::IntrospectFunc) &Private::introspectConnected, this); introspectables[FeatureConnected] = introspectableConnected; readinessHelper->addIntrospectables(introspectables); readinessHelper->setCurrentStatus(status); parent->connect(readinessHelper, SIGNAL(statusReady(uint)), SLOT(onStatusReady(uint))); // FIXME: QRegExp probably isn't the most efficient possible way to parse // this :-) QRegExp rx(QLatin1String("^") + TP_QT_CONNECTION_OBJECT_PATH_BASE + QLatin1String( "([_A-Za-z][_A-Za-z0-9]*)" // cap(1) is the CM "/([_A-Za-z][_A-Za-z0-9]*)" // cap(2) is the protocol "/([_A-Za-z][_A-Za-z0-9]*)" // account-specific part )); if (rx.exactMatch(parent->objectPath())) { cmName = rx.cap(1); protocolName = rx.cap(2); } else { warning() << "Connection object path is not spec-compliant, " "trying again with a different account-specific part check"; rx = QRegExp(QLatin1String("^") + TP_QT_CONNECTION_OBJECT_PATH_BASE + QLatin1String( "([_A-Za-z][_A-Za-z0-9]*)" // cap(1) is the CM "/([_A-Za-z][_A-Za-z0-9]*)" // cap(2) is the protocol "/([_A-Za-z0-9]*)" // account-specific part )); if (rx.exactMatch(parent->objectPath())) { cmName = rx.cap(1); protocolName = rx.cap(2); } else { warning() << "Not a valid Connection object path:" << parent->objectPath(); } } } Connection::Private::~Private() { contactManager->resetRoster(); // Clear selfContact so its handle will be released cleanly before the // handleContext selfContact.reset(); QMutexLocker locker(&handleContextsLock); // All handle contexts locked, so safe if (!--handleContext->refcount) { if (!immortalHandles) { debug() << "Destroying HandleContext"; foreach (uint handleType, handleContext->types.keys()) { HandleContext::Type type = handleContext->types[handleType]; if (!type.refcounts.empty()) { debug() << " Still had references to" << type.refcounts.size() << "handles, releasing now"; baseInterface->ReleaseHandles(handleType, type.refcounts.keys()); } if (!type.toRelease.empty()) { debug() << " Was going to release" << type.toRelease.size() << "handles, doing that now"; baseInterface->ReleaseHandles(handleType, type.toRelease.toList()); } } } handleContexts.remove(qMakePair(baseInterface->connection().name(), parent->objectPath())); delete handleContext; } else { Q_ASSERT(handleContext->refcount > 0); } } void Connection::Private::init() { debug() << "Connecting to ConnectionError()"; parent->connect(baseInterface, SIGNAL(ConnectionError(QString,QVariantMap)), SLOT(onConnectionError(QString,QVariantMap))); debug() << "Connecting to StatusChanged()"; parent->connect(baseInterface, SIGNAL(StatusChanged(uint,uint)), SLOT(onStatusChanged(uint,uint))); debug() << "Connecting to SelfHandleChanged()"; parent->connect(baseInterface, SIGNAL(SelfHandleChanged(uint)), SLOT(onSelfHandleChanged(uint))); QMutexLocker locker(&handleContextsLock); QString busConnectionName = baseInterface->connection().name(); if (handleContexts.contains(qMakePair(busConnectionName, parent->objectPath()))) { debug() << "Reusing existing HandleContext for" << parent->objectPath(); handleContext = handleContexts[ qMakePair(busConnectionName, parent->objectPath())]; } else { debug() << "Creating new HandleContext for" << parent->objectPath(); handleContext = new HandleContext; handleContexts[ qMakePair(busConnectionName, parent->objectPath())] = handleContext; } // All handle contexts locked, so safe ++handleContext->refcount; } void Connection::Private::introspectMain(Connection::Private *self) { debug() << "Calling Properties::GetAll(Connection)"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->GetAll(TP_QT_IFACE_CONNECTION), self->parent); self->parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotMainProperties(QDBusPendingCallWatcher*))); } void Connection::Private::introspectMainFallbackStatus() { debug() << "Calling GetStatus()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(baseInterface->GetStatus(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotStatus(QDBusPendingCallWatcher*))); } void Connection::Private::introspectMainFallbackInterfaces() { debug() << "Calling GetInterfaces()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(baseInterface->GetInterfaces(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotInterfaces(QDBusPendingCallWatcher*))); } void Connection::Private::introspectMainFallbackSelfHandle() { debug() << "Calling GetSelfHandle()"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(baseInterface->GetSelfHandle(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotSelfHandle(QDBusPendingCallWatcher*))); } void Connection::Private::introspectCapabilities() { debug() << "Retrieving capabilities"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( properties->Get( TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS, QLatin1String("RequestableChannelClasses")), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotCapabilities(QDBusPendingCallWatcher*))); } void Connection::Private::introspectContactAttributeInterfaces() { debug() << "Retrieving contact attribute interfaces"; QDBusPendingCall call = properties->Get( TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS, QLatin1String("ContactAttributeInterfaces")); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotContactAttributeInterfaces(QDBusPendingCallWatcher*))); } void Connection::Private::introspectSelfContact(Connection::Private *self) { debug() << "Building self contact"; Q_ASSERT(!self->introspectingSelfContact); self->introspectingSelfContact = true; self->reintrospectSelfContactRequired = false; PendingContacts *contacts = self->contactManager->contactsForHandles( UIntList() << self->selfHandle); self->parent->connect(contacts, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotSelfContact(Tp::PendingOperation*))); } void Connection::Private::introspectSimplePresence(Connection::Private *self) { Q_ASSERT(self->properties != 0); debug() << "Calling Properties::Get(" "Connection.I.SimplePresence.Statuses)"; QDBusPendingCall call = self->properties->GetAll( TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, self->parent); self->parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotSimpleStatuses(QDBusPendingCallWatcher*))); } void Connection::Private::introspectRoster(Connection::Private *self) { debug() << "Introspecting roster"; PendingOperation *op = self->contactManager->introspectRoster(); self->parent->connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onIntrospectRosterFinished(Tp::PendingOperation*))); } void Connection::Private::introspectRosterGroups(Connection::Private *self) { debug() << "Introspecting roster groups"; PendingOperation *op = self->contactManager->introspectRosterGroups(); self->parent->connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onIntrospectRosterGroupsFinished(Tp::PendingOperation*))); } void Connection::Private::introspectBalance(Connection::Private *self) { debug() << "Introspecting balance"; // we already checked if balance interface exists, so bypass requests // interface checking Client::ConnectionInterfaceBalanceInterface *iface = self->parent->interface(); debug() << "Connecting to Balance.BalanceChanged"; self->parent->connect(iface, SIGNAL(BalanceChanged(Tp::CurrencyAmount)), SLOT(onBalanceChanged(Tp::CurrencyAmount))); debug() << "Retrieving balance"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->Get( TP_QT_IFACE_CONNECTION_INTERFACE_BALANCE, QLatin1String("AccountBalance")), self->parent); self->parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotBalance(QDBusPendingCallWatcher*))); } void Connection::Private::introspectConnected(Connection::Private *self) { Q_ASSERT(!self->introspectingConnected); self->introspectingConnected = true; if (self->pendingStatus == ConnectionStatusConnected) { self->readinessHelper->setIntrospectCompleted(FeatureConnected, true); self->introspectingConnected = false; } } void Connection::Private::continueMainIntrospection() { if (!parent->isValid()) { debug() << parent << "stopping main introspection, as it has been invalidated"; return; } if (introspectMainQueue.isEmpty()) { readinessHelper->setIntrospectCompleted(FeatureCore, true); } else { (this->*(introspectMainQueue.dequeue()))(); } } void Connection::Private::setCurrentStatus(uint status) { // ReadinessHelper waits for all in-flight introspection ops to finish for the current status // before proceeding to a new one. // // Therefore we don't need any safeguarding here to prevent finishing introspection when there // is a pending status change. However, we can speed up the process slightly by canceling any // pending introspect ops from our local introspection queue when it's waiting for us. introspectMainQueue.clear(); if (introspectingConnected) { // On the other hand, we have to finish the Connected introspection for now, as // ReadinessHelper would otherwise wait indefinitely for it to land debug() << "Finishing FeatureConnected for status" << this->status << "to allow ReadinessHelper to introspect new status" << status; readinessHelper->setIntrospectCompleted(FeatureConnected, true); introspectingConnected = false; } readinessHelper->setCurrentStatus(status); } void Connection::Private::forceCurrentStatus(uint status) { // only update the status if we did not get it from StatusChanged if (pendingStatus == (uint) -1) { debug() << "Got status:" << status; pendingStatus = status; // No need to re-run introspection as we just received the status. Let // the introspection continue normally but update readinessHelper with // the correct status. readinessHelper->forceCurrentStatus(status); } } void Connection::Private::setInterfaces(const QStringList &interfaces) { debug() << "Got interfaces:" << interfaces; parent->setInterfaces(interfaces); readinessHelper->setInterfaces(interfaces); } void Connection::Private::invalidateResetCaps(const QString &error, const QString &message) { caps.updateRequestableChannelClasses(RequestableChannelClassList()); parent->invalidate(error, message); } /** * \class ConnectionLowlevel * \ingroup clientconn * \headerfile TelepathyQt/connection-lowlevel.h * * \brief The ConnectionLowlevel class extends Connection with support to * low-level features. */ ConnectionLowlevel::ConnectionLowlevel(Connection *conn) : mPriv(new Private(conn)) { } ConnectionLowlevel::~ConnectionLowlevel() { delete mPriv; } bool ConnectionLowlevel::isValid() const { return !(connection().isNull()); } ConnectionPtr ConnectionLowlevel::connection() const { return ConnectionPtr(mPriv->conn); } Connection::PendingConnect::PendingConnect(const ConnectionPtr &connection, const Features &requestedFeatures) : PendingReady(connection, requestedFeatures) { if (!connection) { // Called when the connection had already been destroyed return; } QDBusPendingCall call = connection->baseInterface()->Connect(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); connect(connection.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), this, SLOT(onConnInvalidated(Tp::DBusProxy*,QString,QString))); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onConnectReply(QDBusPendingCallWatcher*))); } void Connection::PendingConnect::onConnectReply(QDBusPendingCallWatcher *watcher) { ConnectionPtr connection = ConnectionPtr::qObjectCast(proxy()); if (watcher->isError()) { debug() << "Connect failed with" << watcher->error().name() << ": " << watcher->error().message(); setFinishedWithError(watcher->error()); connection->disconnect( this, SLOT(onConnInvalidated(Tp::DBusProxy*,QString,QString))); } else { if (connection->status() == ConnectionStatusConnected) { onStatusChanged(ConnectionStatusConnected); } else { // Wait for statusChanged()! Connect returning just means that the connection has // started to connect - spec quoted for truth: // // Connect () -> nothing // Request that the connection be established. This will be done asynchronously and // errors will be returned by emitting StatusChanged signals. // // Which should actually say progress and/or errors IMO, but anyway... connect(connection.data(), SIGNAL(statusChanged(Tp::ConnectionStatus)), SLOT(onStatusChanged(Tp::ConnectionStatus))); } } watcher->deleteLater(); } void Connection::PendingConnect::onStatusChanged(ConnectionStatus newStatus) { ConnectionPtr connection = ConnectionPtr::qObjectCast(proxy()); if (newStatus == ConnectionStatusDisconnected) { debug() << "Connection became disconnected while a PendingConnect was underway"; setFinishedWithError(connection->invalidationReason(), connection->invalidationMessage()); connection->disconnect(this, SLOT(onConnInvalidated(Tp::DBusProxy*,QString,QString))); return; } if (newStatus == ConnectionStatusConnected) { // OK, the connection is Connected now - finally, we'll get down to business connect(connection->becomeReady(requestedFeatures()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onBecomeReadyReply(Tp::PendingOperation*))); } } void Connection::PendingConnect::onBecomeReadyReply(Tp::PendingOperation *op) { ConnectionPtr connection = ConnectionPtr::qObjectCast(proxy()); // We don't care about future disconnects even if they happen before we are destroyed // (which happens two mainloop iterations from now) connection->disconnect(this, SLOT(onStatusChanged(Tp::ConnectionStatus))); connection->disconnect(this, SLOT(onConnInvalidated(Tp::DBusProxy*,QString,QString))); if (op->isError()) { debug() << "Connection->becomeReady failed with" << op->errorName() << ": " << op->errorMessage(); setFinishedWithError(op->errorName(), op->errorMessage()); } else { debug() << "Connected"; if (connection->isValid()) { setFinished(); } else { debug() << " ... but the Connection was immediately invalidated!"; setFinishedWithError(connection->invalidationReason(), connection->invalidationMessage()); } } } void Connection::PendingConnect::onConnInvalidated(Tp::DBusProxy *proxy, const QString &error, const QString &message) { ConnectionPtr connection = ConnectionPtr::qObjectCast(this->proxy()); Q_ASSERT(proxy == connection.data()); if (!isFinished()) { debug() << "Unable to connect. Connection invalidated"; setFinishedWithError(error, message); } connection->disconnect(this, SLOT(onStatusChanged(Tp::ConnectionStatus))); } QHash, Connection::Private::HandleContext*> Connection::Private::handleContexts; QMutex Connection::Private::handleContextsLock; /** * \class Connection * \ingroup clientconn * \headerfile TelepathyQt/connection.h * * \brief The Connection class represents a Telepathy connection. * * This models a connection to a single user account on a communication service. * * Contacts, and server-stored lists (such as subscribed contacts, * block lists, or allow lists) on a service are all represented using the * ContactManager object on the connection, which is valid only for the lifetime * of the connection object. * * The remote object accessor functions on this object (status(), * statusReason(), and so on) don't make any D-Bus calls; instead, they return/use * values cached from a previous introspection run. The introspection process * populates their values in the most efficient way possible based on what the * service implements. * * To avoid unnecessary D-Bus traffic, some accessors only return valid * information after specific features have been enabled. * For instance, to retrieve the connection self contact, it is necessary to * enable the feature Connection::FeatureSelfContact. * See the individual methods descriptions for more details. * * Connection features can be enabled by constructing a ConnectionFactory and enabling * the desired features, and passing it to AccountManager, Account or ClientRegistrar * when creating them as appropriate. However, if a particular * feature is only ever used in a specific circumstance, such as an user opening * some settings dialog separate from the general view of the application, * features can be later enabled as needed by calling becomeReady() with the additional * features, and waiting for the resulting PendingOperation to finish. * * As an addition to accessors, signals are emitted to indicate that properties have changed, * for example statusChanged()(), selfContactChanged(), etc. * * \section conn_usage_sec Usage * * \subsection conn_create_sec Creating a connection object * * The easiest way to create connection objects is through Account. One can * just use the Account::connection method to get an account active connection. * * If you already know the object path, you can just call create(). * For example: * * \code ConnectionPtr conn = Connection::create(busName, objectPath); \endcode * * A ConnectionPtr object is returned, which will automatically keep * track of object lifetime. * * You can also provide a D-Bus connection as a QDBusConnection: * * \code * * ConnectionPtr conn = Connection::create(QDBusConnection::sessionBus(), * busName, objectPath); * * \endcode * * \subsection conn_ready_sec Making connection ready to use * * A Connection object needs to become ready before usage, meaning that the * introspection process finished and the object accessors can be used. * * To make the object ready, use becomeReady() and wait for the * PendingOperation::finished() signal to be emitted. * * \code * * class MyClass : public QObject * { * QOBJECT * * public: * MyClass(QObject *parent = 0); * ~MyClass() { } * * private Q_SLOTS: * void onConnectionReady(Tp::PendingOperation*); * * private: * ConnectionPtr conn; * }; * * MyClass::MyClass(const QString &busName, const QString &objectPath, * QObject *parent) * : QObject(parent) * conn(Connection::create(busName, objectPath)) * { * // connect and become ready * connect(conn->requestConnect(), * SIGNAL(finished(Tp::PendingOperation*)), * SLOT(onConnectionReady(Tp::PendingOperation*))); * } * * void MyClass::onConnectionReady(Tp::PendingOperation *op) * { * if (op->isError()) { * qWarning() << "Account cannot become ready:" << * op->errorName() << "-" << op->errorMessage(); * return; * } * * // Connection is now ready * } * * \endcode * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * Connection object usable. * * Note that this feature must be enabled in order to use most Connection * methods. * See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature Connection::FeatureCore = Feature(QLatin1String(Connection::staticMetaObject.className()), 0, true); /** * Feature used to retrieve the connection self contact. * * See self contact specific methods' documentation for more details. * * \sa selfContact(), selfContactChanged() */ const Feature Connection::FeatureSelfContact = Feature(QLatin1String(Connection::staticMetaObject.className()), 1); /** * Feature used to retrieve/keep track of the connection self presence. * * See simple presence specific methods' documentation for more details. */ const Feature Connection::FeatureSimplePresence = Feature(QLatin1String(Connection::staticMetaObject.className()), 2); /** * Feature used to enable roster support on Connection::contactManager. * * See ContactManager roster specific methods' documentation for more details. * * \sa ContactManager::allKnownContacts() */ const Feature Connection::FeatureRoster = Feature(QLatin1String(Connection::staticMetaObject.className()), 4); /** * Feature used to enable roster groups support on Connection::contactManager. * * See ContactManager roster groups specific methods' documentation for more * details. * * \sa ContactManager::allKnownGroups() */ const Feature Connection::FeatureRosterGroups = Feature(QLatin1String(Connection::staticMetaObject.className()), 5); /** * Feature used to retrieve/keep track of the connection account balance. * * See account balance specific methods' documentation for more details. * * \sa accountBalance(), accountBalanceChanged() */ const Feature Connection::FeatureAccountBalance = Feature(QLatin1String(Connection::staticMetaObject.className()), 6); /** * When this feature is prepared, it means that the connection status() is * ConnectionStatusConnected. * * Note that if ConnectionFactory is being used with FeatureConnected set, Connection objects will * only be signalled by the library when the corresponding connection is in status() * ConnectionStatusConnected. */ const Feature Connection::FeatureConnected = Feature(QLatin1String(Connection::staticMetaObject.className()), 7); /** * Create a new connection object using QDBusConnection::sessionBus(). * * A warning is printed if the factories are not for QDBusConnection::sessionBus(). * * \param busName The connection well-known bus name (sometimes called a * "service name"). * \param objectPath The connection object path. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return A ConnectionPtr object pointing to the newly created Connection object. */ ConnectionPtr Connection::create(const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return ConnectionPtr(new Connection(QDBusConnection::sessionBus(), busName, objectPath, channelFactory, contactFactory, Connection::FeatureCore)); } /** * Create a new connection object using the given \a bus. * * A warning is printed if the factories are not for \a bus. * * \param bus QDBusConnection to use. * \param busName The connection well-known bus name (sometimes called a * "service name"). * \param objectPath The connection object path. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return A ConnectionPtr object pointing to the newly created Connection object. */ ConnectionPtr Connection::create(const QDBusConnection &bus, const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return ConnectionPtr(new Connection(bus, busName, objectPath, channelFactory, contactFactory, Connection::FeatureCore)); } /** * Construct a new connection object using the given \a bus. * * A warning is printed if the factories are not for \a bus. * * \param bus QDBusConnection to use. * \param busName The connection's well-known bus name (sometimes called a * "service name"). * \param objectPath The connection object path. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \param coreFeature The core feature of the Connection subclass. The corresponding introspectable * should depend on Connection::FeatureCore. */ Connection::Connection(const QDBusConnection &bus, const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const Feature &coreFeature) : StatefulDBusProxy(bus, busName, objectPath, coreFeature), OptionalInterfaceFactory(this), mPriv(new Private(this, channelFactory, contactFactory)) { } /** * Class destructor. */ Connection::~Connection() { delete mPriv; } /** * Return the channel factory used by this connection. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the account would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ChannelFactory object. */ ChannelFactoryConstPtr Connection::channelFactory() const { return mPriv->chanFactory; } /** * Return the contact factory used by this connection. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the account would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ContactFactory object. */ ContactFactoryConstPtr Connection::contactFactory() const { return mPriv->contactFactory; } /** * Return the connection manager name of this connection. * * \return The connection manager name. */ QString Connection::cmName() const { return mPriv->cmName; } /** * Return the protocol name of this connection. * * \return The protocol name. */ QString Connection::protocolName() const { return mPriv->protocolName; } /** * Return the status of this connection. * * Change notification is via the statusChanged() signal. * * This method requires Connection::FeatureCore to be ready. * * \return The status as #ConnectionStatus. * \sa statusChanged(), statusReason(), errorDetails() */ ConnectionStatus Connection::status() const { return (ConnectionStatus) mPriv->status; } /** * Return the reason for this connection status. * * The validity and change rules are the same as for status(). * * The status reason should be only used as a fallback in error handling when the application * doesn't understand an error name given as the invalidation reason, which may in some cases be * domain/UI-specific. * * This method requires Connection::FeatureCore to be ready. * * \return The status reason as #ConnectionStatusReason. * \sa invalidated(), invalidationReason() */ ConnectionStatusReason Connection::statusReason() const { return (ConnectionStatusReason) mPriv->statusReason; } struct TP_QT_NO_EXPORT Connection::ErrorDetails::Private : public QSharedData { Private(const QVariantMap &details) : details(details) {} QVariantMap details; }; /** * \class Connection::ErrorDetails * \ingroup clientconn * \headerfile TelepathyQt/connection.h * * \brief The Connection::ErrorDetails class represents the details of a connection error. * * It contains detailed information about the reason for the connection going invalidated(). * * Some services may provide additional error information in the ConnectionError D-Bus signal, when * a Connection is disconnected / has become unusable. If the service didn't provide any, or has not * been invalidated yet, the instance will be invalid, as returned by isValid(). * * The information provided by invalidationReason() and this class should always be used in error * handling in preference to statusReason(). The status reason can be used as a fallback, however, * if the client doesn't understand what a particular value returned by invalidationReason() means, * as it may be domain-specific with some services. * * Connection::errorDetails() can be used to return the instance containing the details for * invalidating that connection after invalidated() has been emitted. */ /** * Constructs a new invalid ErrorDetails instance. */ Connection::ErrorDetails::ErrorDetails() : mPriv(0) { } /** * Construct a error details instance with the given details. The instance will indicate that * it is valid. */ Connection::ErrorDetails::ErrorDetails(const QVariantMap &details) : mPriv(new Private(details)) { } /** * Copy constructor. */ Connection::ErrorDetails::ErrorDetails(const ErrorDetails &other) : mPriv(other.mPriv) { } /** * Class destructor. */ Connection::ErrorDetails::~ErrorDetails() { } /** * Assigns all information (validity, details) from other to this. */ Connection::ErrorDetails &Connection::ErrorDetails::operator=( const ErrorDetails &other) { if (this->mPriv.constData() != other.mPriv.constData()) this->mPriv = other.mPriv; return *this; } /** * \fn bool Connection::ErrorDetails::isValid() const * * Return whether or not the details are valid (have actually been received from the service). * * \return \c true if valid, \c false otherwise. */ /** * \fn bool Connection::ErrorDetails::hasDebugMessage() const * * Return whether or not the details specify a debug message. * * If present, the debug message will likely be the same string as the one returned by * invalidationMessage(). * * The debug message is purely informational, offered for display for bug reporting purposes, and * should not be attempted to be parsed. * * \return \c true if debug message is present, \c false otherwise. * \sa debugMessage() */ /** * \fn QString Connection::ErrorDetails::debugMessage() const * * Return the debug message specified by the details, if any. * * If present, the debug message will likely be the same string as the one returned by * invalidationMessage(). * * The debug message is purely informational, offered for display for bug reporting purposes, and * should not be attempted to be parsed. * * \return The debug message, or an empty string if there is none. * \sa hasDebugMessage() */ /** * Return a map containing all details given in the low-level ConnectionError signal. * * This is useful for accessing domain-specific additional details. * * \return The details of the connection error as QVariantMap. */ QVariantMap Connection::ErrorDetails::allDetails() const { return isValid() ? mPriv->details : QVariantMap(); } /** * Return detailed information about the reason for the connection going invalidated(). * * Some services may provide additional error information in the ConnectionError D-Bus signal, when * a Connection is disconnected / has become unusable. If the service didn't provide any, or has not * been invalidated yet, an invalid instance is returned. * * The information provided by invalidationReason() and this method should always be used in error * handling in preference to statusReason(). The status reason can be used as a fallback, however, * if the client doesn't understand what a particular value returned by invalidationReason() means, * as it may be domain-specific with some services. * * \return The error details as a Connection::ErrorDetails object. * \sa status(), statusReason(), invalidationReason() */ const Connection::ErrorDetails &Connection::errorDetails() const { if (isValid()) { warning() << "Connection::errorDetails() used on" << objectPath() << "which is valid"; } return mPriv->errorDetails; } /** * Return the handle representing the user on this connection. * * Note that if the connection is not yet in the ConnectionStatusConnected state, * the value of this property may be zero. * * Change notification is via the selfHandleChanged() signal. * * This method requires Connection::FeatureCore to be ready. * * \return The user handle. * \sa selfHandleChanged(), selfContact() */ uint Connection::selfHandle() const { return mPriv->selfHandle; } /** * Return a dictionary of presence statuses valid for use in this connection. * * The value may have changed arbitrarily during the time the * Connection spends in status ConnectionStatusConnecting, * again staying fixed for the entire time in ConnectionStatusConnected. * * This method requires Connection::FeatureSimplePresence to be ready. * * \return The allowed statuses as a map from string identifiers to SimpleStatusSpec objects. */ SimpleStatusSpecMap ConnectionLowlevel::allowedPresenceStatuses() const { if (!isValid()) { warning() << "ConnectionLowlevel::selfHandle() " "called for a connection which is already destroyed"; return SimpleStatusSpecMap(); } ConnectionPtr conn(connection()); if (!conn->isReady(Connection::FeatureSimplePresence)) { warning() << "Trying to retrieve allowed presence statuses from connection, but " "simple presence is not supported or was not requested. " "Enable FeatureSimplePresence in this connection"; } return conn->mPriv->simplePresenceStatuses; } /** * Return the maximum length for a presence status message. * * The value may have changed arbitrarily during the time the * Connection spends in status ConnectionStatusConnecting, * again staying fixed for the entire time in ConnectionStatusConnected. * * This method requires Connection::FeatureSimplePresence to be ready. * * \return The maximum length, or 0 if there is no limit. */ uint ConnectionLowlevel::maxPresenceStatusMessageLength() const { if (!isValid()) { warning() << "ConnectionLowlevel::maxPresenceStatusMessageLength() " "called for a connection which is already destroyed"; return 0; } ConnectionPtr conn(connection()); if (!conn->isReady(Connection::FeatureSimplePresence)) { warning() << "Trying to retrieve max presence status message length connection, but " "simple presence is not supported or was not requested. " "Enable FeatureSimplePresence in this connection"; } return conn->mPriv->maxPresenceStatusMessageLength; } /** * Set the self presence status. * * This should generally only be called by an Account Manager. In typical usage, * Account::setRequestedPresence() should be used instead. * * \a status must be one of the allowed statuses returned by * allowedPresenceStatuses(). * * Note that clients SHOULD set the status message for the local user to the * empty string, unless the user has actually provided a specific message (i.e. * one that conveys more information than the ConnectionStatus). * * \param status The desired status. * \param statusMessage The desired status message. * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa allowedPresenceStatuses() */ PendingOperation *ConnectionLowlevel::setSelfPresence(const QString &status, const QString &statusMessage) { if (!isValid()) { warning() << "ConnectionLowlevel::selfHandle() called for a connection which is already destroyed"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection already destroyed"), ConnectionPtr()); } ConnectionPtr conn(connection()); if (!conn->interfaces().contains(TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE)) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Connection does not support SimplePresence"), conn); } Client::ConnectionInterfaceSimplePresenceInterface *simplePresenceInterface = conn->interface(); return new PendingVoid( simplePresenceInterface->SetPresence(status, statusMessage), conn); } /** * Return the object representing the user on this connection. * * Note that if the connection is not yet in the ConnectionStatusConnected state, the value of this * property may be null. * * Change notification is via the selfContactChanged() signal. * * This method requires Connection::FeatureSelfContact to be ready. * * \return A pointer to the Contact object, or a null ContactPtr if unknown. * \sa selfContactChanged(), selfHandle() */ ContactPtr Connection::selfContact() const { if (!isReady(FeatureSelfContact)) { warning() << "Connection::selfContact() used, but becomeReady(FeatureSelfContact) " "hasn't been completed!"; } return mPriv->selfContact; } /** * Return the user's balance on the account corresponding to this connection. * * A negative amount may be possible on some services, and indicates that the user * owes money to the service provider. * * Change notification is via the accountBalanceChanged() signal. * * This method requires Connection::FeatureAccountBalance to be ready. * * \return The account balance as #CurrencyAmount. * \sa accountBalanceChanged() */ CurrencyAmount Connection::accountBalance() const { if (!isReady(FeatureAccountBalance)) { warning() << "Connection::accountBalance() used before connection " "FeatureAccountBalance is ready"; } return mPriv->accountBalance; } /** * Return the capabilities for this connection. * * User interfaces can use this information to show or hide UI components. * * This property cannot change after the connection has gone to state * ConnectionStatusConnected, so there is no change notification. * * This method requires Connection::FeatureCore to be ready. * * @return The capabilities of this connection. */ ConnectionCapabilities Connection::capabilities() const { if (!isReady(Connection::FeatureCore)) { warning() << "Connection::capabilities() used before connection " "FeatureCore is ready"; } return mPriv->caps; } void Connection::onStatusReady(uint status) { Q_ASSERT(status == mPriv->pendingStatus); if (mPriv->status == status) { return; } mPriv->status = status; mPriv->statusReason = mPriv->pendingStatusReason; if (isValid()) { emit statusChanged((ConnectionStatus) mPriv->status); } else { debug() << this << " not emitting statusChanged because it has been invalidated"; } } void Connection::onStatusChanged(uint status, uint reason) { debug() << "StatusChanged from" << mPriv->pendingStatus << "to" << status << "with reason" << reason; if (mPriv->pendingStatus == status) { warning() << "New status was the same as the old status! Ignoring" "redundant StatusChanged"; return; } uint oldStatus = mPriv->pendingStatus; mPriv->pendingStatus = status; mPriv->pendingStatusReason = reason; switch (status) { case ConnectionStatusConnected: debug() << "Performing introspection for the Connected status"; mPriv->setCurrentStatus(status); break; case ConnectionStatusConnecting: mPriv->setCurrentStatus(status); break; case ConnectionStatusDisconnected: { QString errorName = ConnectionHelper::statusReasonToErrorName( (ConnectionStatusReason) reason, (ConnectionStatus) oldStatus); // TODO should we signal statusChanged to Disconnected here or just // invalidate? // Also none of the pendingOperations will finish. The // user should just consider them to fail as the connection // is invalid onStatusReady(ConnectionStatusDisconnected); mPriv->invalidateResetCaps(errorName, QString(QLatin1String("ConnectionStatusReason = %1")).arg(uint(reason))); } break; default: warning() << "Unknown connection status" << status; break; } } void Connection::onConnectionError(const QString &error, const QVariantMap &details) { debug().nospace() << "Connection(" << objectPath() << ") got ConnectionError(" << error << ") with " << details.size() << " details"; mPriv->errorDetails = details; mPriv->invalidateResetCaps(error, details.value(QLatin1String("debug-message")).toString()); } void Connection::gotMainProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; QVariantMap props; if (!reply.isError()) { props = reply.value(); } else { warning().nospace() << "Properties::GetAll(Connection) failed with " << reply.error().name() << ": " << reply.error().message(); // let's try to fallback first before failing } uint status = static_cast(-1); if (props.contains(QLatin1String("Status")) && ((status = qdbus_cast(props[QLatin1String("Status")])) <= ConnectionStatusDisconnected)) { mPriv->forceCurrentStatus(status); } else { // only introspect status if we did not got it from StatusChanged if (mPriv->pendingStatus == (uint) -1) { mPriv->introspectMainQueue.enqueue( &Private::introspectMainFallbackStatus); } } if (props.contains(QLatin1String("Interfaces"))) { mPriv->setInterfaces(qdbus_cast( props[QLatin1String("Interfaces")])); } else { mPriv->introspectMainQueue.enqueue( &Private::introspectMainFallbackInterfaces); } if (props.contains(QLatin1String("SelfHandle"))) { mPriv->selfHandle = qdbus_cast( props[QLatin1String("SelfHandle")]); } else { mPriv->introspectMainQueue.enqueue( &Private::introspectMainFallbackSelfHandle); } if (props.contains(QLatin1String("HasImmortalHandles"))) { mPriv->immortalHandles = qdbus_cast(props[QLatin1String("HasImmortalHandles")]); } if (hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS)) { mPriv->introspectMainQueue.enqueue( &Private::introspectCapabilities); } if (hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS)) { mPriv->introspectMainQueue.enqueue( &Private::introspectContactAttributeInterfaces); } mPriv->continueMainIntrospection(); watcher->deleteLater(); } void Connection::gotStatus(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { mPriv->forceCurrentStatus(reply.value()); mPriv->continueMainIntrospection(); } else { warning().nospace() << "GetStatus() failed with " << reply.error().name() << ": " << reply.error().message(); mPriv->invalidateResetCaps(reply.error().name(), reply.error().message()); } watcher->deleteLater(); } void Connection::gotInterfaces(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { mPriv->setInterfaces(reply.value()); } else { warning().nospace() << "GetInterfaces() failed with " << reply.error().name() << ": " << reply.error().message() << " - assuming no new interfaces"; // let's not fail if GetInterfaces fail } mPriv->continueMainIntrospection(); watcher->deleteLater(); } void Connection::gotSelfHandle(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { mPriv->selfHandle = reply.value(); debug() << "Got self handle:" << mPriv->selfHandle; mPriv->continueMainIntrospection(); } else { warning().nospace() << "GetSelfHandle() failed with " << reply.error().name() << ": " << reply.error().message(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); } watcher->deleteLater(); } void Connection::gotCapabilities(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got capabilities"; mPriv->caps.updateRequestableChannelClasses( qdbus_cast(reply.value().variant())); } else { warning().nospace() << "Getting capabilities failed with " << reply.error().name() << ": " << reply.error().message(); // let's not fail if retrieving capabilities fail } mPriv->continueMainIntrospection(); watcher->deleteLater(); } void Connection::gotContactAttributeInterfaces(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got contact attribute interfaces"; mPriv->contactAttributeInterfaces = qdbus_cast(reply.value().variant()); } else { warning().nospace() << "Getting contact attribute interfaces failed with " << reply.error().name() << ": " << reply.error().message(); // let's not fail if retrieving contact attribute interfaces fail // TODO should we remove Contacts interface from interfaces? } mPriv->continueMainIntrospection(); watcher->deleteLater(); } void Connection::gotSimpleStatuses(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { QVariantMap props = reply.value(); mPriv->simplePresenceStatuses = qdbus_cast( props[QLatin1String("Statuses")]); mPriv->maxPresenceStatusMessageLength = qdbus_cast( props[QLatin1String("MaximumStatusMessageLength")]); debug() << "Got" << mPriv->simplePresenceStatuses.size() << "simple presence statuses - max status message length is" << mPriv->maxPresenceStatusMessageLength; mPriv->readinessHelper->setIntrospectCompleted(FeatureSimplePresence, true); } else { warning().nospace() << "Getting simple presence statuses failed with " << reply.error().name() << ":" << reply.error().message(); mPriv->readinessHelper->setIntrospectCompleted(FeatureSimplePresence, false, reply.error()); } watcher->deleteLater(); } void Connection::gotSelfContact(PendingOperation *op) { PendingContacts *pending = qobject_cast(op); if (pending->isValid()) { Q_ASSERT(pending->contacts().size() == 1); ContactPtr contact = pending->contacts()[0]; if (mPriv->selfContact != contact) { mPriv->selfContact = contact; if (!isReady(FeatureSelfContact)) { mPriv->readinessHelper->setIntrospectCompleted(FeatureSelfContact, true); } emit selfContactChanged(); } } else { warning().nospace() << "Getting self contact failed with " << pending->errorName() << ":" << pending->errorMessage(); // check if the feature is already there, and for some reason introspectSelfContact // failed when called the second time if (!isReady(FeatureSelfContact)) { mPriv->readinessHelper->setIntrospectCompleted(FeatureSelfContact, false, op->errorName(), op->errorMessage()); } if (mPriv->selfContact) { mPriv->selfContact.reset(); emit selfContactChanged(); } } mPriv->introspectingSelfContact = false; if (mPriv->reintrospectSelfContactRequired) { mPriv->introspectSelfContact(mPriv); } } void Connection::onIntrospectRosterFinished(PendingOperation *op) { if (op->isError()) { warning().nospace() << "Introspecting roster failed with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureRoster, false, op->errorName(), op->errorMessage()); return; } debug() << "Introspecting roster finished"; mPriv->readinessHelper->setIntrospectCompleted(FeatureRoster, true); } void Connection::onIntrospectRosterGroupsFinished(PendingOperation *op) { if (op->isError()) { warning().nospace() << "Introspecting roster groups failed with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureRosterGroups, false, op->errorName(), op->errorMessage()); return; } debug() << "Introspecting roster groups finished"; mPriv->readinessHelper->setIntrospectCompleted(FeatureRosterGroups, true); } void Connection::gotBalance(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got balance"; mPriv->accountBalance = qdbus_cast(reply.value()); mPriv->readinessHelper->setIntrospectCompleted(FeatureAccountBalance, true); } else { warning().nospace() << "Getting balance failed with " << reply.error().name() << ":" << reply.error().message(); mPriv->readinessHelper->setIntrospectCompleted(FeatureAccountBalance, false, reply.error().name(), reply.error().message()); } watcher->deleteLater(); } /** * Return the Client::ConnectionInterface interface proxy object for this connection. * This method is protected since the convenience methods provided by this * class should generally be used instead of calling D-Bus methods * directly. * * \return A pointer to the existing Client::ConnectionInterface object for this * Connection object. */ Client::ConnectionInterface *Connection::baseInterface() const { return mPriv->baseInterface; } /** * Same as \c createChannel(request, -1) */ PendingChannel *ConnectionLowlevel::createChannel(const QVariantMap &request) { return createChannel(request, -1); } /** * Asynchronously creates a channel satisfying the given request. * * In typical usage, only the Channel Dispatcher should call this. Ordinary * applications should use the Account::createChannel() family of methods * (which invoke the Channel Dispatcher's services). * * The request MUST contain the following keys: * org.freedesktop.Telepathy.Channel.ChannelType * org.freedesktop.Telepathy.Channel.TargetHandleType * * Upon completion, the reply to the request can be retrieved through the * returned PendingChannel object. The object also provides access to the * parameters with which the call was made and a signal to connect to get * notification of the request finishing processing. See the documentation * for that class for more info. * * \param request A dictionary containing the desirable properties. * \param timeout The D-Bus timeout in milliseconds used for the method call. * If timeout is -1, a default implementation-defined value that * is suitable for inter-process communications (generally, * 25 seconds) will be used. * \return A PendingChannel which will emit PendingChannel::finished * when the channel has been created, or an error occurred. * \sa PendingChannel, ensureChannel(), * Account::createChannel(), Account::createAndHandleChannel(), * Account::ensureChannel(), Account::ensureAndHandleChannel() */ PendingChannel *ConnectionLowlevel::createChannel(const QVariantMap &request, int timeout) { if (!isValid()) { return new PendingChannel(ConnectionPtr(), TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection has been destroyed")); } ConnectionPtr conn(connection()); if (conn->mPriv->pendingStatus != ConnectionStatusConnected) { warning() << "Calling createChannel with connection not yet connected"; return new PendingChannel(conn, TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection not yet connected")); } if (!conn->interfaces().contains(TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS)) { warning() << "Requests interface is not support by this connection"; return new PendingChannel(conn, TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Connection does not support Requests Interface")); } if (!request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"))) { return new PendingChannel(conn, TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid 'request' argument")); } debug() << "Creating a Channel"; PendingChannel *channel = new PendingChannel(conn, request, true, timeout); return channel; } /** * Same as \c ensureChannel(request, -1) */ PendingChannel *ConnectionLowlevel::ensureChannel(const QVariantMap &request) { return ensureChannel(request, -1); } /** * Asynchronously ensures a channel exists satisfying the given request. * * In typical usage, only the Channel Dispatcher should call this. Ordinary * applications should use the Account::ensureChannel() family of methods * (which invoke the Channel Dispatcher's services). * * The request MUST contain the following keys: * org.freedesktop.Telepathy.Channel.ChannelType * org.freedesktop.Telepathy.Channel.TargetHandleType * * Upon completion, the reply to the request can be retrieved through the * returned PendingChannel object. The object also provides access to the * parameters with which the call was made and a signal to connect to get * notification of the request finishing processing. See the documentation * for that class for more info. * * \param request A dictionary containing the desirable properties. * \param timeout The D-Bus timeout in milliseconds used for the method call. * If timeout is -1, a default implementation-defined value that * is suitable for inter-process communications (generally, * 25 seconds) will be used. * \return A PendingChannel which will emit PendingChannel::finished * when the channel is ensured to exist, or an error occurred. * \sa PendingChannel, createChannel(), * Account::createChannel(), Account::createAndHandleChannel(), * Account::ensureChannel(), Account::ensureAndHandleChannel() */ PendingChannel *ConnectionLowlevel::ensureChannel(const QVariantMap &request, int timeout) { if (!isValid()) { return new PendingChannel(ConnectionPtr(), TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection has been destroyed")); } ConnectionPtr conn(connection()); if (conn->mPriv->pendingStatus != ConnectionStatusConnected) { warning() << "Calling ensureChannel with connection not yet connected"; return new PendingChannel(conn, TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection not yet connected")); } if (!conn->interfaces().contains(TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS)) { warning() << "Requests interface is not support by this connection"; return new PendingChannel(conn, TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Connection does not support Requests Interface")); } if (!request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"))) { return new PendingChannel(conn, TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid 'request' argument")); } debug() << "Creating a Channel"; PendingChannel *channel = new PendingChannel(conn, request, false, timeout); return channel; } /** * Request handles of the given type for the given entities (contacts, * rooms, lists, etc.). * * Typically one doesn't need to request and use handles directly; instead, string identifiers * and/or Contact objects are used in most APIs. File a bug for APIs in which there is no * alternative to using handles. In particular however using low-level DBus interfaces for which * there is no corresponding high-level (or one is implementing that abstraction) functionality does * and will always require using bare handles. * * Upon completion, the reply to the request can be retrieved through the * returned PendingHandles object. The object also provides access to the * parameters with which the call was made and a signal to connect to to get * notification of the request finishing processing. See the documentation * for that class for more info. * * The returned PendingHandles object should be freed using * its QObject::deleteLater() method after it is no longer used. However, * all PendingHandles objects resulting from requests to a particular * Connection will be freed when the Connection itself is freed. Conversely, * this means that the PendingHandles object should not be used after the * Connection is destroyed. * * \param handleType Type for the handles to request, as specified in * #HandleType. * \param names Names of the entities to request handles for. * \return A PendingHandles which will emit PendingHandles::finished * when the handles have been requested, or an error occurred. * \sa PendingHandles */ PendingHandles *ConnectionLowlevel::requestHandles(HandleType handleType, const QStringList &names) { debug() << "Request for" << names.length() << "handles of type" << handleType; if (!isValid()) { return new PendingHandles(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection has been destroyed")); } ConnectionPtr conn(connection()); if (!hasImmortalHandles()) { Connection::Private::HandleContext *handleContext = conn->mPriv->handleContext; QMutexLocker locker(&handleContext->lock); handleContext->types[handleType].requestsInFlight++; } PendingHandles *pending = new PendingHandles(conn, handleType, names); return pending; } /** * Request a reference to the given handles. Handles not explicitly * requested (via requestHandles()) but eg. observed in a signal need to be * referenced to guarantee them staying valid. * * Typically one doesn't need to reference and use handles directly; instead, string identifiers * and/or Contact objects are used in most APIs. File a bug for APIs in which there is no * alternative to using handles. In particular however using low-level DBus interfaces for which * there is no corresponding high-level (or one is implementing that abstraction) functionality does * and will always require using bare handles. * * Upon completion, the reply to the operation can be retrieved through the * returned PendingHandles object. The object also provides access to the * parameters with which the call was made and a signal to connect to to get * notification of the request finishing processing. See the documentation * for that class for more info. * * The returned PendingHandles object should be freed using * its QObject::deleteLater() method after it is no longer used. However, * all PendingHandles objects resulting from requests to a particular * Connection will be freed when the Connection itself is freed. Conversely, * this means that the PendingHandles object should not be used after the * Connection is destroyed. * * \sa PendingHandles * * \param handleType Type of the handles given, as specified in #HandleType. * \param handles Handles to request a reference to. * \return A PendingHandles which will emit PendingHandles::finished * when the handles have been referenced, or an error occurred. */ PendingHandles *ConnectionLowlevel::referenceHandles(HandleType handleType, const UIntList &handles) { debug() << "Reference of" << handles.length() << "handles of type" << handleType; if (!isValid()) { return new PendingHandles(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection has been destroyed")); } ConnectionPtr conn(connection()); UIntList alreadyHeld; UIntList notYetHeld; if (!hasImmortalHandles()) { Connection::Private::HandleContext *handleContext = conn->mPriv->handleContext; QMutexLocker locker(&handleContext->lock); foreach (uint handle, handles) { if (handleContext->types[handleType].refcounts.contains(handle) || handleContext->types[handleType].toRelease.contains(handle)) { alreadyHeld.push_back(handle); } else { notYetHeld.push_back(handle); } } debug() << " Already holding" << alreadyHeld.size() << "of the handles -" << notYetHeld.size() << "to go"; } else { alreadyHeld = handles; } PendingHandles *pending = new PendingHandles(conn, handleType, handles, alreadyHeld, notYetHeld); return pending; } /** * Start an asynchronous request that the connection be connected. * * When using a full-fledged Telepathy setup with an Account Manager service, the Account methods * Account::setRequestedPresence() and Account::reconnect() must be used instead. * * The returned PendingOperation will finish successfully when the connection * has reached ConnectionStatusConnected and the requested \a features are all ready, or * finish with an error if a fatal error occurs during that process. * * \param requestedFeatures The features which should be enabled * \return A PendingReady which will emit PendingReady::finished * when the Connection has reached #ConnectionStatusConnected, and initial setup * for basic functionality, plus the given features, has succeeded or * failed. */ PendingReady *ConnectionLowlevel::requestConnect(const Features &requestedFeatures) { if (!isValid()) { Connection::PendingConnect *pending = new Connection::PendingConnect(ConnectionPtr(), requestedFeatures); pending->setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection has been destroyed")); return pending; } return new Connection::PendingConnect(connection(), requestedFeatures); } /** * Start an asynchronous request that the connection be disconnected. * The returned PendingOperation object will signal the success or failure * of this request; under normal circumstances, it can be expected to * succeed. * * When using a full-fledged Telepathy setup with an Account Manager service, * Account::setRequestedPresence() with Presence::offline() as an argument should generally be used * instead. * * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. */ PendingOperation *ConnectionLowlevel::requestDisconnect() { if (!isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection has been destroyed"), ConnectionPtr()); } ConnectionPtr conn(connection()); return new PendingVoid(conn->baseInterface()->Disconnect(), conn); } /** * Requests attributes for contacts. Optionally, the handles of the contacts * will be referenced automatically. Essentially, this method wraps * ConnectionInterfaceContactsInterface::GetContactAttributes(), integrating it * with the rest of the handle-referencing machinery. * * This is very low-level API the Contact/ContactManager API provides a higher level of abstraction * for the same functionality. * * Upon completion, the reply to the request can be retrieved through the * returned PendingContactAttributes object. The object also provides access to * the parameters with which the call was made and a signal to connect to to get * notification of the request finishing processing. See the documentation for * that class for more info. * * If the remote object doesn't support the Contacts interface (as signified by * the list returned by interfaces() not containing * #TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS), the returned * PendingContactAttributes instance will fail instantly with the error * #TP_QT_ERROR_NOT_IMPLEMENTED. * * Similarly, if the connection isn't both connected and ready * (status() == ConnectionStatusConnected && isReady(Connection::FeatureCore)), * the returned PendingContactAttributes instance will fail instantly with the * error #TP_QT_ERROR_NOT_AVAILABLE. * * This method requires Connection::FeatureCore to be ready. * * \sa PendingContactAttributes * * \param handles A list of handles of type HandleTypeContact * \param interfaces D-Bus interfaces for which the client requires information * \param reference Whether the handles should additionally be referenced. * \return A PendingContactAttributes which will emit PendingContactAttributes::fininshed * when the contact attributes have been retrieved, or an error occurred. */ PendingContactAttributes *ConnectionLowlevel::contactAttributes(const UIntList &handles, const QStringList &interfaces, bool reference) { debug() << "Request for attributes for" << handles.size() << "contacts"; if (!isValid()) { PendingContactAttributes *pending = new PendingContactAttributes(ConnectionPtr(), handles, interfaces, reference); pending->failImmediately(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection has been destroyed")); return pending; } ConnectionPtr conn(connection()); PendingContactAttributes *pending = new PendingContactAttributes(conn, handles, interfaces, reference); if (!conn->isReady(Connection::FeatureCore)) { warning() << "ConnectionLowlevel::contactAttributes() used when not ready"; pending->failImmediately(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection isn't ready")); return pending; } else if (conn->mPriv->pendingStatus != ConnectionStatusConnected) { warning() << "ConnectionLowlevel::contactAttributes() used with status" << conn->status() << "!= ConnectionStatusConnected"; pending->failImmediately(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection isn't Connected")); return pending; } else if (!conn->interfaces().contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS)) { warning() << "ConnectionLowlevel::contactAttributes() used without the remote object supporting" << "the Contacts interface"; pending->failImmediately(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The connection doesn't support the Contacts interface")); return pending; } if (!hasImmortalHandles()) { Connection::Private::HandleContext *handleContext = conn->mPriv->handleContext; QMutexLocker locker(&handleContext->lock); handleContext->types[HandleTypeContact].requestsInFlight++; } Client::ConnectionInterfaceContactsInterface *contactsInterface = conn->interface(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(contactsInterface->GetContactAttributes(handles, interfaces, reference)); pending->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onCallFinished(QDBusPendingCallWatcher*))); return pending; } QStringList ConnectionLowlevel::contactAttributeInterfaces() const { if (!isValid()) { warning() << "ConnectionLowlevel::contactAttributeInterfaces() called for a destroyed Connection"; return QStringList(); } ConnectionPtr conn(connection()); if (conn->mPriv->pendingStatus != ConnectionStatusConnected) { warning() << "ConnectionLowlevel::contactAttributeInterfaces() used with status" << conn->status() << "!= ConnectionStatusConnected"; } else if (!conn->interfaces().contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS)) { warning() << "ConnectionLowlevel::contactAttributeInterfaces() used without the remote object supporting" << "the Contacts interface"; } return conn->mPriv->contactAttributeInterfaces; } void ConnectionLowlevel::injectContactIds(const HandleIdentifierMap &contactIds) { if (!hasImmortalHandles()) { return; } for (HandleIdentifierMap::const_iterator i = contactIds.constBegin(); i != contactIds.constEnd(); ++i) { uint handle = i.key(); QString id = i.value(); if (!id.isEmpty()) { QString currentId = mPriv->contactsIds.value(handle); if (!currentId.isEmpty() && id != currentId) { warning() << "Trying to overwrite contact id from" << currentId << "to" << id << "for the same handle" << handle << ", ignoring"; } else { mPriv->contactsIds.insert(handle, id); } } } } void ConnectionLowlevel::injectContactId(uint handle, const QString &contactId) { HandleIdentifierMap contactIds; contactIds.insert(handle, contactId); injectContactIds(contactIds); } bool ConnectionLowlevel::hasContactId(uint handle) const { return mPriv->contactsIds.contains(handle); } QString ConnectionLowlevel::contactId(uint handle) const { return mPriv->contactsIds.value(handle); } /** * Return whether the handles last for the whole lifetime of the connection. * * \return \c true if handles are immortal, \c false otherwise. */ bool ConnectionLowlevel::hasImmortalHandles() const { return connection()->mPriv->immortalHandles; } /** * Return the ContactManager object for this connection. * * The contact manager is responsible for all contact handling in this * connection, including adding, removing, authorizing, etc. * * \return A pointer to the ContactManager object. */ ContactManagerPtr Connection::contactManager() const { return mPriv->contactManager; } ConnectionLowlevelPtr Connection::lowlevel() { return mPriv->lowlevel; } ConnectionLowlevelConstPtr Connection::lowlevel() const { return mPriv->lowlevel; } void Connection::refHandle(HandleType handleType, uint handle) { if (mPriv->immortalHandles) { return; } Private::HandleContext *handleContext = mPriv->handleContext; QMutexLocker locker(&handleContext->lock); if (handleContext->types[handleType].toRelease.contains(handle)) { handleContext->types[handleType].toRelease.remove(handle); } handleContext->types[handleType].refcounts[handle]++; } void Connection::unrefHandle(HandleType handleType, uint handle) { if (mPriv->immortalHandles) { return; } Private::HandleContext *handleContext = mPriv->handleContext; QMutexLocker locker(&handleContext->lock); Q_ASSERT(handleContext->types.contains(handleType)); Q_ASSERT(handleContext->types[handleType].refcounts.contains(handle)); if (!--handleContext->types[handleType].refcounts[handle]) { handleContext->types[handleType].refcounts.remove(handle); handleContext->types[handleType].toRelease.insert(handle); if (!handleContext->types[handleType].releaseScheduled) { if (!handleContext->types[handleType].requestsInFlight) { debug() << "Lost last reference to at least one handle of type" << handleType << "and no requests in flight for that type - scheduling a release sweep"; QMetaObject::invokeMethod(this, "doReleaseSweep", Qt::QueuedConnection, Q_ARG(uint, handleType)); handleContext->types[handleType].releaseScheduled = true; } } } } void Connection::doReleaseSweep(uint handleType) { if (mPriv->immortalHandles) { return; } Private::HandleContext *handleContext = mPriv->handleContext; QMutexLocker locker(&handleContext->lock); Q_ASSERT(handleContext->types.contains(handleType)); Q_ASSERT(handleContext->types[handleType].releaseScheduled); debug() << "Entering handle release sweep for type" << handleType; handleContext->types[handleType].releaseScheduled = false; if (handleContext->types[handleType].requestsInFlight > 0) { debug() << " There are requests in flight, deferring sweep to when they have been completed"; return; } if (handleContext->types[handleType].toRelease.isEmpty()) { debug() << " No handles to release - every one has been resurrected"; return; } debug() << " Releasing" << handleContext->types[handleType].toRelease.size() << "handles"; mPriv->baseInterface->ReleaseHandles(handleType, handleContext->types[handleType].toRelease.toList()); handleContext->types[handleType].toRelease.clear(); } void Connection::handleRequestLanded(HandleType handleType) { if (mPriv->immortalHandles) { return; } Private::HandleContext *handleContext = mPriv->handleContext; QMutexLocker locker(&handleContext->lock); Q_ASSERT(handleContext->types.contains(handleType)); Q_ASSERT(handleContext->types[handleType].requestsInFlight > 0); if (!--handleContext->types[handleType].requestsInFlight && !handleContext->types[handleType].toRelease.isEmpty() && !handleContext->types[handleType].releaseScheduled) { debug() << "All handle requests for type" << handleType << "landed and there are handles of that type to release - scheduling a release sweep"; QMetaObject::invokeMethod(this, "doReleaseSweep", Qt::QueuedConnection, Q_ARG(uint, handleType)); handleContext->types[handleType].releaseScheduled = true; } } void Connection::onSelfHandleChanged(uint handle) { if (mPriv->selfHandle == handle) { return; } if (mPriv->pendingStatus != ConnectionStatusConnected || !mPriv->selfHandle) { debug() << "Got a self handle change before we have the initial self handle, ignoring"; return; } debug() << "Connection self handle changed to" << handle; mPriv->selfHandle = handle; emit selfHandleChanged(handle); if (mPriv->introspectingSelfContact) { // We're currently introspecting the SelfContact feature, but have started building the // contact with the old handle, so we need to do it again with the new handle. debug() << "The self contact is being built, will rebuild with the new handle shortly"; mPriv->reintrospectSelfContactRequired = true; } else if (isReady(FeatureSelfContact)) { // We've already introspected the SelfContact feature, so we can reinvoke the introspection // logic directly to rebuild with the new handle. debug() << "Re-building self contact for handle" << handle; Private::introspectSelfContact(mPriv); } // If ReadinessHelper hasn't started introspecting SelfContact yet for the Connected state, we // don't need to do anything. When it does start the introspection, it will do so using the // correct handle. } void Connection::onBalanceChanged(const Tp::CurrencyAmount &value) { mPriv->accountBalance = value; emit accountBalanceChanged(value); } QString ConnectionHelper::statusReasonToErrorName(Tp::ConnectionStatusReason reason, Tp::ConnectionStatus oldStatus) { QString errorName; switch (reason) { case ConnectionStatusReasonNoneSpecified: errorName = TP_QT_ERROR_DISCONNECTED; break; case ConnectionStatusReasonRequested: errorName = TP_QT_ERROR_CANCELLED; break; case ConnectionStatusReasonNetworkError: errorName = TP_QT_ERROR_NETWORK_ERROR; break; case ConnectionStatusReasonAuthenticationFailed: errorName = TP_QT_ERROR_AUTHENTICATION_FAILED; break; case ConnectionStatusReasonEncryptionError: errorName = TP_QT_ERROR_ENCRYPTION_ERROR; break; case ConnectionStatusReasonNameInUse: if (oldStatus == ConnectionStatusConnected) { errorName = TP_QT_ERROR_CONNECTION_REPLACED; } else { errorName = TP_QT_ERROR_ALREADY_CONNECTED; } break; case ConnectionStatusReasonCertNotProvided: errorName = TP_QT_ERROR_CERT_NOT_PROVIDED; break; case ConnectionStatusReasonCertUntrusted: errorName = TP_QT_ERROR_CERT_UNTRUSTED; break; case ConnectionStatusReasonCertExpired: errorName = TP_QT_ERROR_CERT_EXPIRED; break; case ConnectionStatusReasonCertNotActivated: errorName = TP_QT_ERROR_CERT_NOT_ACTIVATED; break; case ConnectionStatusReasonCertHostnameMismatch: errorName = TP_QT_ERROR_CERT_HOSTNAME_MISMATCH; break; case ConnectionStatusReasonCertFingerprintMismatch: errorName = TP_QT_ERROR_CERT_FINGERPRINT_MISMATCH; break; case ConnectionStatusReasonCertSelfSigned: errorName = TP_QT_ERROR_CERT_SELF_SIGNED; break; case ConnectionStatusReasonCertOtherError: errorName = TP_QT_ERROR_CERT_INVALID; break; default: errorName = TP_QT_ERROR_DISCONNECTED; break; } return errorName; } /** * \fn void Connection::statusChanged(Tp::ConnectionStatus newStatus) * * Indicates that the connection's status has changed and that all previously requested features are * now ready to use for the new status. * * Legitimate uses for this signal, apart from waiting for a given connection status to be ready, * include updating an animation based on the connection being in ConnectionStatusConnecting, * ConnectionStatusConnected and ConnectionStatusDisconnected, and otherwise showing progress * indication to the user. It should, however, NEVER be used for error handling: * * This signal doesn't contain the status reason as an argument, because statusChanged() shouldn't * be used for error-handling. There are numerous cases in which a Connection may become unusable * without there being a status change to ConnectionStatusDisconnected. All of these cases, and * being disconnected itself, are signaled by invalidated() with appropriate error names. On the * other hand, the reason for the status going to ConnectionStatusConnecting or * ConnectionStatusConnected will always be ConnectionStatusReasonRequested, so signaling that would * be useless. * * The status reason, as returned by statusReason(), may however be used as a fallback for error * handling in slots connected to the invalidated() signal, if the client doesn't understand a * particular (likely domain-specific if so) error name given by invalidateReason(). * * \param newStatus The new status of the connection, as would be returned by status(). */ /** * \fn void Connection::selfHandleChanged(uint newHandle) * * Emitted when the value of selfHandle() changes. * * \param newHandle The new connection self handle. * \sa selfHandle() */ /** * \fn void Connection::selfContactChanged() * * Emitted when the value of selfContact() changes. * * \sa selfContact() */ /** * \fn void Connection::accountBalanceChanged(const Tp::CurrencyAmount &accountBalance) * * Emitted when the value of accountBalance() changes. * * \param accountBalance The new user's balance of this connection. * \sa accountBalance() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/connection.h0000664000175000017500000001775312470405660017541 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_connection_h_HEADER_GUARD_ #define _TelepathyQt_connection_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { class Channel; class ConnectionCapabilities; class ConnectionLowlevel; class Contact; class ContactManager; class PendingChannel; class PendingContactAttributes; class PendingHandles; class PendingOperation; class PendingReady; class TP_QT_EXPORT Connection : public StatefulDBusProxy, public OptionalInterfaceFactory { Q_OBJECT Q_DISABLE_COPY(Connection) public: static const Feature FeatureCore; static const Feature FeatureSelfContact; static const Feature FeatureSimplePresence; static const Feature FeatureRoster; static const Feature FeatureRosterGroups; static const Feature FeatureAccountBalance; // TODO unit tests for this static const Feature FeatureConnected; static ConnectionPtr create(const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory); static ConnectionPtr create(const QDBusConnection &bus, const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory); virtual ~Connection(); ChannelFactoryConstPtr channelFactory() const; ContactFactoryConstPtr contactFactory() const; QString cmName() const; QString protocolName() const; ConnectionStatus status() const; ConnectionStatusReason statusReason() const; class ErrorDetails { public: ErrorDetails(); ErrorDetails(const QVariantMap &details); ErrorDetails(const ErrorDetails &other); ~ErrorDetails(); ErrorDetails &operator=(const ErrorDetails &other); bool isValid() const { return mPriv.constData() != 0; } bool hasDebugMessage() const { return allDetails().contains(QLatin1String("debug-message")); } QString debugMessage() const { return qdbus_cast(allDetails().value(QLatin1String("debug-message"))); } bool hasServerMessage() const { return allDetails().contains(QLatin1String("server-message")); } QString serverMessage() const { return qdbus_cast(allDetails().value(QLatin1String("server-message"))); } bool hasUserRequested() const { return allDetails().contains(QLatin1String("user-requested")); } bool userRequested() const { return qdbus_cast(allDetails().value(QLatin1String("user-requested"))); } bool hasExpectedHostname() const { return allDetails().contains(QLatin1String("expected-hostname")); } QString expectedHostname() const { return qdbus_cast(allDetails().value(QLatin1String("expected-hostname"))); } bool hasCertificateHostname() const { return allDetails().contains(QLatin1String("certificate-hostname")); } QString certificateHostname() const { return qdbus_cast(allDetails().value(QLatin1String("certificate-hostname"))); } QVariantMap allDetails() const; private: friend class Connection; struct Private; friend struct Private; QSharedDataPointer mPriv; }; const ErrorDetails &errorDetails() const; uint selfHandle() const; ContactPtr selfContact() const; CurrencyAmount accountBalance() const; ConnectionCapabilities capabilities() const; ContactManagerPtr contactManager() const; #if defined(BUILDING_TP_QT) || defined(TP_QT_ENABLE_LOWLEVEL_API) ConnectionLowlevelPtr lowlevel(); ConnectionLowlevelConstPtr lowlevel() const; #endif Q_SIGNALS: void statusChanged(Tp::ConnectionStatus newStatus); void selfHandleChanged(uint newHandle); // FIXME: might not need this when Renaming is fixed and mapped to Contacts void selfContactChanged(); void accountBalanceChanged(const Tp::CurrencyAmount &accountBalance); protected: Connection(const QDBusConnection &bus, const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const Feature &coreFeature); Client::ConnectionInterface *baseInterface() const; private Q_SLOTS: TP_QT_NO_EXPORT void onStatusReady(uint status); TP_QT_NO_EXPORT void onStatusChanged(uint status, uint reason); TP_QT_NO_EXPORT void onConnectionError(const QString &error, const QVariantMap &details); TP_QT_NO_EXPORT void gotMainProperties(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotStatus(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotInterfaces(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotSelfHandle(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotCapabilities(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotContactAttributeInterfaces(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotSimpleStatuses(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotSelfContact(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onIntrospectRosterFinished(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onIntrospectRosterGroupsFinished(Tp::PendingOperation *op); TP_QT_NO_EXPORT void doReleaseSweep(uint handleType); TP_QT_NO_EXPORT void onSelfHandleChanged(uint); TP_QT_NO_EXPORT void gotBalance(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onBalanceChanged(const Tp::CurrencyAmount &); private: class PendingConnect; friend class ConnectionLowlevel; friend class PendingChannel; friend class PendingConnect; friend class PendingContactAttributes; friend class PendingContacts; friend class PendingHandles; friend class ReferencedHandles; TP_QT_NO_EXPORT void refHandle(HandleType handleType, uint handle); TP_QT_NO_EXPORT void unrefHandle(HandleType handleType, uint handle); TP_QT_NO_EXPORT void handleRequestLanded(HandleType handleType); struct Private; friend struct Private; Private *mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::Connection::ErrorDetails); #endif telepathy-qt-0.9.6~git1/TelepathyQt/pending-channel-request-internal.h0000664000175000017500000000416712470405660023727 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_channel_request_internal_h_HEADER_GUARD_ #define _TelepathyQt_pending_channel_request_internal_h_HEADER_GUARD_ #include #include #include namespace Tp { class TP_QT_NO_EXPORT PendingChannelRequestCancelOperation : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingChannelRequestCancelOperation) public: PendingChannelRequestCancelOperation() : PendingOperation(SharedPtr()) { } ~PendingChannelRequestCancelOperation() { } void go(const ChannelRequestPtr &channelRequest) { Q_ASSERT(mChannelRequest.isNull()); mChannelRequest = channelRequest; connect(mChannelRequest->cancel(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onCancelOperationFinished(Tp::PendingOperation*))); } private Q_SLOTS: void onCancelOperationFinished(Tp::PendingOperation *op) { if (op->isError()) { setFinishedWithError(op->errorName(), op->errorMessage()); return; } setFinished(); } private: ChannelRequestPtr mChannelRequest; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/account-set.cpp0000664000175000017500000002745012470405660020155 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/account-set-internal.h" #include "TelepathyQt/_gen/account-set.moc.hpp" #include "TelepathyQt/_gen/account-set-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include namespace Tp { AccountSet::Private::Private(AccountSet *parent, const AccountManagerPtr &accountManager, const AccountFilterConstPtr &filter) : parent(parent), accountManager(accountManager), filter(filter), ready(false) { init(); } AccountSet::Private::Private(AccountSet *parent, const AccountManagerPtr &accountManager, const QVariantMap &filterMap) : parent(parent), accountManager(accountManager), ready(false) { AccountPropertyFilterPtr propertyFilter = AccountPropertyFilter::create(); for (QVariantMap::const_iterator i = filterMap.constBegin(); i != filterMap.constEnd(); ++i) { propertyFilter->addProperty(i.key(), i.value()); } filter = AccountFilterPtr::dynamicCast(propertyFilter); init(); } void AccountSet::Private::init() { if (filter->isValid()) { connectSignals(); insertAccounts(); ready = true; } } void AccountSet::Private::connectSignals() { parent->connect(accountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)), SLOT(onNewAccount(Tp::AccountPtr))); } void AccountSet::Private::insertAccounts() { foreach (const Tp::AccountPtr &account, accountManager->allAccounts()) { insertAccount(account); } } void AccountSet::Private::insertAccount(const Tp::AccountPtr &account) { QString accountPath = account->objectPath(); Q_ASSERT(!wrappers.contains(accountPath)); wrapAccount(account); filterAccount(account); } void AccountSet::Private::removeAccount(const Tp::AccountPtr &account) { QString accountPath = account->objectPath(); Q_ASSERT(wrappers.contains(accountPath)); accounts.remove(accountPath); AccountWrapper *wrapper = wrappers.take(accountPath); Q_ASSERT(wrapper->disconnect(parent)); wrapper->deleteLater(); emit parent->accountRemoved(account); } void AccountSet::Private::wrapAccount(const AccountPtr &account) { AccountWrapper *wrapper = new AccountWrapper(account, parent); parent->connect(wrapper, SIGNAL(accountRemoved(Tp::AccountPtr)), SLOT(onAccountRemoved(Tp::AccountPtr))); parent->connect(wrapper, SIGNAL(accountPropertyChanged(Tp::AccountPtr,QString)), SLOT(onAccountChanged(Tp::AccountPtr))); parent->connect(wrapper, SIGNAL(accountCapabilitiesChanged(Tp::AccountPtr,Tp::ConnectionCapabilities)), SLOT(onAccountChanged(Tp::AccountPtr))); wrappers.insert(account->objectPath(), wrapper); } void AccountSet::Private::filterAccount(const AccountPtr &account) { QString accountPath = account->objectPath(); Q_ASSERT(wrappers.contains(accountPath)); AccountWrapper *wrapper = wrappers[accountPath]; /* account changed, let's check if it matches filter */ if (accountMatchFilter(wrapper)) { if (!accounts.contains(account->objectPath())) { accounts.insert(account->objectPath(), account); if (ready) { emit parent->accountAdded(account); } } } else { if (accounts.contains(account->objectPath())) { accounts.remove(account->objectPath()); if (ready) { emit parent->accountRemoved(account); } } } } bool AccountSet::Private::accountMatchFilter(AccountWrapper *wrapper) { if (!filter) { return true; } return filter->matches(wrapper->account()); } AccountSet::Private::AccountWrapper::AccountWrapper( const AccountPtr &account, QObject *parent) : QObject(parent), mAccount(account) { connect(account.data(), SIGNAL(removed()), SLOT(onAccountRemoved())); connect(account.data(), SIGNAL(propertyChanged(QString)), SLOT(onAccountPropertyChanged(QString))); connect(account.data(), SIGNAL(capabilitiesChanged(Tp::ConnectionCapabilities)), SLOT(onAccountCapalitiesChanged(Tp::ConnectionCapabilities))); } AccountSet::Private::AccountWrapper::~AccountWrapper() { } void AccountSet::Private::AccountWrapper::onAccountRemoved() { emit accountRemoved(mAccount); } void AccountSet::Private::AccountWrapper::onAccountPropertyChanged( const QString &propertyName) { emit accountPropertyChanged(mAccount, propertyName); } void AccountSet::Private::AccountWrapper::onAccountCapalitiesChanged( const ConnectionCapabilities &caps) { emit accountCapabilitiesChanged(mAccount, caps); } /** * \class AccountSet * \ingroup clientaccount * \headerfile TelepathyQt/account-set.h * * \brief The AccountSet class represents a set of Telepathy accounts * filtered by a given criteria. * * AccountSet is automatically updated whenever accounts that match the given * criteria are added, removed or updated. * * \section account_set_usage_sec Usage * * \subsection account_set_create_sec Creating an AccountSet object * * The easiest way to create AccountSet objects is through AccountManager. One * can just use the AccountManager convenience methods such as * AccountManager::validAccounts() to get a set of account objects * representing valid accounts. * * For example: * * \code * * class MyClass : public QObject * { * QOBJECT * * public: * MyClass(QObject *parent = 0); * ~MyClass() { } * * private Q_SLOTS: * void onAccountManagerReady(Tp::PendingOperation *); * void onValidAccountAdded(const Tp::AccountPtr &); * void onValidAccountRemoved(const Tp::AccountPtr &); * * private: * AccountManagerPtr am; * AccountSetPtr validAccountsSet; * }; * * MyClass::MyClass(QObject *parent) * : QObject(parent) * am(AccountManager::create()) * { * connect(am->becomeReady(), * SIGNAL(finished(Tp::PendingOperation*)), * SLOT(onAccountManagerReady(Tp::PendingOperation*))); * } * * void MyClass::onAccountManagerReady(Tp::PendingOperation *op) * { * if (op->isError()) { * qWarning() << "Account manager cannot become ready:" << * op->errorName() << "-" << op->errorMessage(); * return; * } * * validAccountsSet = am->validAccounts(); * connect(validAccountsSet.data(), * SIGNAL(accountAdded(const Tp::AccountPtr &)), * SLOT(onValidAccountAdded(const Tp::AccountPtr &))); * connect(validAccountsSet.data(), * SIGNAL(accountRemoved(const Tp::AccountPtr &)), * SLOT(onValidAccountRemoved(const Tp::AccountPtr &))); * * QList accounts = validAccountsSet->accounts(); * // do something with accounts * } * * void MyClass::onValidAccountAdded(const Tp::AccountPtr &account) * { * // do something with account * } * * void MyClass::onValidAccountRemoved(const Tp::AccountPtr &account) * { * // do something with account * } * * \endcode * * You can also define your own filter using AccountManager::filterAccounts: * * \code * * void MyClass::onAccountManagerReady(Tp::PendingOperation *op) * { * ... * * AccountPropertyFilterPtr filter = AccountPropertyFilter::create(); * filter->addProperty(QLatin1String("protocolName"), QLatin1String("jabber")); * filter->addProperty(QLatin1String("enabled"), true); * * AccountSetPtr filteredAccountSet = am->filterAccounts(filter); * // connect to AccountSet::accountAdded/accountRemoved signals * QList accounts = filteredAccountSet->accounts(); * // do something with accounts * * .... * } * * \endcode * * Note that for AccountSet to property work with AccountCapabilityFilter * objects, the feature Account::FeatureCapabilities need to be enabled in all * accounts return by the AccountManager passed as param in the constructor. * The easiest way to do this is to enable AccountManager feature * AccountManager::FeatureFilterByCapabilities. * * AccountSet can also be instantiated directly, but when doing it, * the AccountManager object passed as param in the constructor must be ready * for AccountSet properly work. */ /** * Construct a new AccountSet object. * * \param accountManager An account manager object used to filter accounts. * The account manager object must be ready. * \param filter The desired filter. */ AccountSet::AccountSet(const AccountManagerPtr &accountManager, const AccountFilterConstPtr &filter) : Object(), mPriv(new Private(this, accountManager, filter)) { } /** * Construct a new AccountSet object. * * The \a filter must contain Account property names and values as map items. * * \param accountManager An account manager object used to filter accounts. * The account manager object must be ready. * \param filter The desired filter. */ AccountSet::AccountSet(const AccountManagerPtr &accountManager, const QVariantMap &filter) : Object(), mPriv(new Private(this, accountManager, filter)) { } /** * Class destructor. */ AccountSet::~AccountSet() { delete mPriv; } /** * Return the account manager object used to filter accounts. * * \return A pointer to the AccountManager object. */ AccountManagerPtr AccountSet::accountManager() const { return mPriv->accountManager; } /** * Return the filter used to filter accounts. * * \return A read-only pointer the AccountFilter object. */ AccountFilterConstPtr AccountSet::filter() const { return mPriv->filter; } /** * Return a list of account objects that match filter. * * Change notification is via the accountAdded() and accountRemoved() signals. * * \return A list of pointers to Account objects. * \sa accountAdded(), accountRemoved() */ QList AccountSet::accounts() const { return mPriv->accounts.values(); } /** * \fn void AccountSet::accountAdded(const Tp::AccountPtr &account) * * Emitted whenever an account that matches filter is added to * this set. * * \param account The account that was added to this set. * \sa accounts() */ /** * \fn void AccountSet::accountRemoved(const Tp::AccountPtr &account) * * Emitted whenever an account that matches filter is removed * from this set. * * \param account The account that was removed from this set. * \sa accounts() */ void AccountSet::onNewAccount(const AccountPtr &account) { mPriv->insertAccount(account); } void AccountSet::onAccountRemoved(const AccountPtr &account) { mPriv->removeAccount(account); } void AccountSet::onAccountChanged(const AccountPtr &account) { mPriv->filterAccount(account); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/PendingFailure0000664000175000017500000000040312470405660020030 0ustar jrjr#ifndef _TelepathyQt_PendingFailure_HEADER_GUARD_ #define _TelepathyQt_PendingFailure_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/connection-lowlevel.h0000664000175000017500000000602512470405660021356 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_connection_lowlevel_h_HEADER_GUARD_ #define _TelepathyQt_connection_lowlevel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class Connection; class PendingChannel; class PendingContactAttributes; class PendingHandles; class PendingOperation; class PendingReady; class TP_QT_EXPORT ConnectionLowlevel : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(ConnectionLowlevel) public: ~ConnectionLowlevel(); bool isValid() const; ConnectionPtr connection() const; PendingReady *requestConnect(const Features &requestedFeatures = Features()); PendingOperation *requestDisconnect(); SimpleStatusSpecMap allowedPresenceStatuses() const; uint maxPresenceStatusMessageLength() const; PendingOperation *setSelfPresence(const QString &status, const QString &statusMessage); PendingChannel *createChannel(const QVariantMap &request); PendingChannel *createChannel(const QVariantMap &request, int timeout); PendingChannel *ensureChannel(const QVariantMap &request); PendingChannel *ensureChannel(const QVariantMap &request, int timeout); PendingHandles *requestHandles(HandleType handleType, const QStringList &names); PendingHandles *referenceHandles(HandleType handleType, const UIntList &handles); PendingContactAttributes *contactAttributes(const UIntList &handles, const QStringList &interfaces, bool reference = true); QStringList contactAttributeInterfaces() const; void injectContactIds(const HandleIdentifierMap &contactIds); void injectContactId(uint handle, const QString &contactId); private: friend class Connection; friend class ContactManager; friend class PendingContacts; TP_QT_NO_EXPORT ConnectionLowlevel(Connection *parent); TP_QT_NO_EXPORT bool hasImmortalHandles() const; TP_QT_NO_EXPORT bool hasContactId(uint handle) const; TP_QT_NO_EXPORT QString contactId(uint handle) const; struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/outgoing-dbus-tube-channel.h0000664000175000017500000000346412470405660022525 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_outgoing_dbus_tube_channel_h_HEADER_GUARD_ #define _TelepathyQt_outgoing_dbus_tube_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class PendingDBusTubeConnection; class TP_QT_EXPORT OutgoingDBusTubeChannel : public DBusTubeChannel { Q_OBJECT Q_DISABLE_COPY(OutgoingDBusTubeChannel) public: static OutgoingDBusTubeChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~OutgoingDBusTubeChannel(); PendingDBusTubeConnection *offerTube(const QVariantMap ¶meters, bool allowOtherUsers = false); protected: OutgoingDBusTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); private: struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/connection-manager.cpp0000664000175000017500000012401412470405660021471 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "TelepathyQt/connection-manager-internal.h" #include "TelepathyQt/_gen/cli-connection-manager-body.hpp" #include "TelepathyQt/_gen/cli-connection-manager.moc.hpp" #include "TelepathyQt/_gen/connection-manager.moc.hpp" #include "TelepathyQt/_gen/connection-manager-internal.moc.hpp" #include "TelepathyQt/_gen/connection-manager-lowlevel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/manager-file.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { ConnectionManager::Private::PendingNames::PendingNames(const QDBusConnection &bus) : PendingStringList(SharedPtr()), mBus(bus) { mMethodsQueue.enqueue(QLatin1String("ListNames")); mMethodsQueue.enqueue(QLatin1String("ListActivatableNames")); QTimer::singleShot(0, this, SLOT(continueProcessing())); } void ConnectionManager::Private::PendingNames::onCallFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { parseResult(reply.value()); continueProcessing(); } else { warning() << "Failure: error " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } void ConnectionManager::Private::PendingNames::continueProcessing() { if (!mMethodsQueue.isEmpty()) { QLatin1String method = mMethodsQueue.dequeue(); invokeMethod(method); } else { debug() << "Success: list" << mResult; setResult(mResult.toList()); setFinished(); } } void ConnectionManager::Private::PendingNames::invokeMethod(const QLatin1String &method) { QDBusPendingCall call = mBus.interface()->asyncCallWithArgumentList( method, QList()); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onCallFinished(QDBusPendingCallWatcher*))); } void ConnectionManager::Private::PendingNames::parseResult(const QStringList &names) { foreach (const QString name, names) { if (name.startsWith(TP_QT_IFACE_CONNECTION_MANAGER + QLatin1String("."))) { mResult << name.right(name.length() - 44); } } } const Feature ConnectionManager::Private::ProtocolWrapper::FeatureCore = Feature(QLatin1String(ConnectionManager::Private::ProtocolWrapper::staticMetaObject.className()), 0, true); ConnectionManager::Private::ProtocolWrapper::ProtocolWrapper( const ConnectionManagerPtr &cm, const QString &objectPath, const QString &name, const QVariantMap &props) : StatelessDBusProxy(cm->dbusConnection(), cm->busName(), objectPath, FeatureCore), OptionalInterfaceFactory(this), mReadinessHelper(readinessHelper()), mInfo(ProtocolInfo(cm, name)), mImmutableProps(props), mHasMainProps(false), mHasAvatarsProps(false), mHasPresenceProps(false), mHasAddressingProps(false) { fillRCCs(); ReadinessHelper::Introspectables introspectables; // As Protocol does not have predefined statuses let's simulate one (0) ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &ProtocolWrapper::introspectMain, this); introspectables[FeatureCore] = introspectableCore; mReadinessHelper->addIntrospectables(introspectables); } ConnectionManager::Private::ProtocolWrapper::~ProtocolWrapper() { } void ConnectionManager::Private::ProtocolWrapper::introspectMain( ConnectionManager::Private::ProtocolWrapper *self) { if (self->extractImmutableProperties()) { debug() << "Got everything we want from the immutable props for" << self->info().name(); self->continueIntrospection(); return; } if (!self->mHasMainProps) { self->introspectQueue.enqueue(&ProtocolWrapper::introspectMainProperties); } else { self->introspectInterfaces(); } self->continueIntrospection(); } void ConnectionManager::Private::ProtocolWrapper::introspectMainProperties() { Client::ProtocolInterface *protocol = baseInterface(); Q_ASSERT(protocol != 0); debug() << "Calling Properties::GetAll(Protocol) for" << info().name(); PendingVariantMap *pvm = protocol->requestAllProperties(); connect(pvm, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotMainProperties(Tp::PendingOperation*))); } void ConnectionManager::Private::ProtocolWrapper::introspectInterfaces() { if (!mHasAvatarsProps) { if (hasInterface(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS)) { introspectQueue.enqueue(&ProtocolWrapper::introspectAvatars); } else { debug() << "Full functionality requires CM support for the Protocol.Avatars interface"; } } if (!mHasPresenceProps) { if (hasInterface(TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE)) { introspectQueue.enqueue(&ProtocolWrapper::introspectPresence); } else { debug() << "Full functionality requires CM support for the Protocol.Presence interface"; } } if (!mHasAddressingProps) { if (hasInterface(TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING)) { introspectQueue.enqueue(&ProtocolWrapper::introspectAddressing); } else { debug() << "Full functionality requires CM support for the Protocol.Addressing interface"; } } } void ConnectionManager::Private::ProtocolWrapper::introspectAvatars() { Client::ProtocolInterfaceAvatarsInterface *avatars = avatarsInterface(); Q_ASSERT(avatars != 0); debug() << "Calling Properties::GetAll(Protocol.Avatars) for" << info().name(); PendingVariantMap *pvm = avatars->requestAllProperties(); connect(pvm, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotAvatarsProperties(Tp::PendingOperation*))); } void ConnectionManager::Private::ProtocolWrapper::introspectPresence() { Client::ProtocolInterfacePresenceInterface *presence = presenceInterface(); Q_ASSERT(presence != 0); debug() << "Calling Properties::GetAll(Protocol.Presence) for" << info().name(); PendingVariantMap *pvm = presence->requestAllProperties(); connect(pvm, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotPresenceProperties(Tp::PendingOperation*))); } void ConnectionManager::Private::ProtocolWrapper::introspectAddressing() { Client::ProtocolInterfaceAddressingInterface *addressing = addressingInterface(); Q_ASSERT(addressing != 0); debug() << "Calling Properties::GetAll(Protocol.Addressing) for" << info().name(); PendingVariantMap *pvm = addressing->requestAllProperties(); connect(pvm, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotAddressingProperties(Tp::PendingOperation*))); } void ConnectionManager::Private::ProtocolWrapper::continueIntrospection() { if (introspectQueue.isEmpty()) { mReadinessHelper->setIntrospectCompleted(FeatureCore, true); } else { (this->*(introspectQueue.dequeue()))(); } } void ConnectionManager::Private::ProtocolWrapper::gotMainProperties( Tp::PendingOperation *op) { if (!op->isError()) { debug() << "Got reply to Properties.GetAll(Protocol)"; PendingVariantMap *pvm = qobject_cast(op); QVariantMap unqualifiedProps = pvm->result(); extractMainProperties(qualifyProperties(TP_QT_IFACE_PROTOCOL, unqualifiedProps)); introspectInterfaces(); } else { warning().nospace() << "Properties.GetAll(Protocol) failed: " << op->errorName() << ": " << op->errorMessage(); warning() << " Full functionality requires CM support for the Protocol interface"; } continueIntrospection(); } void ConnectionManager::Private::ProtocolWrapper::gotAvatarsProperties( Tp::PendingOperation *op) { if (!op->isError()) { debug() << "Got reply to Properties.GetAll(Protocol.Avatars)"; PendingVariantMap *pvm = qobject_cast(op); QVariantMap unqualifiedProps = pvm->result(); extractAvatarsProperties(qualifyProperties(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS, unqualifiedProps)); } else { warning().nospace() << "Properties.GetAll(Protocol.Avatars) failed: " << op->errorName() << ": " << op->errorMessage(); warning() << " Full functionality requires CM support for the Protocol.Avatars interface"; } continueIntrospection(); } void ConnectionManager::Private::ProtocolWrapper::gotPresenceProperties( Tp::PendingOperation *op) { if (!op->isError()) { debug() << "Got reply to Properties.GetAll(Protocol.Presence)"; PendingVariantMap *pvm = qobject_cast(op); QVariantMap unqualifiedProps = pvm->result(); extractPresenceProperties(qualifyProperties(TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE, unqualifiedProps)); } else { warning().nospace() << "Properties.GetAll(Protocol.Presence) failed: " << op->errorName() << ": " << op->errorMessage(); warning() << " Full functionality requires CM support for the Protocol.Presence interface"; } continueIntrospection(); } void ConnectionManager::Private::ProtocolWrapper::gotAddressingProperties( Tp::PendingOperation *op) { QVariantMap unqualifiedProps; if (!op->isError()) { debug() << "Got reply to Properties.GetAll(Protocol.Addressing)"; PendingVariantMap *pvm = qobject_cast(op); QVariantMap unqualifiedProps = pvm->result(); extractAddressingProperties(qualifyProperties(TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING, unqualifiedProps)); } else { warning().nospace() << "Properties.GetAll(Protocol.Addressing) failed: " << op->errorName() << ": " << op->errorMessage(); warning() << " Full functionality requires CM support for the Protocol.Addressing interface"; } continueIntrospection(); } QVariantMap ConnectionManager::Private::ProtocolWrapper::qualifyProperties( const QString &ifaceName, const QVariantMap &unqualifiedProps) { QVariantMap qualifiedProps; foreach (const QString &unqualifiedProp, unqualifiedProps.keys()) { qualifiedProps.insert( QString(QLatin1String("%1.%2")). arg(ifaceName). arg(unqualifiedProp), unqualifiedProps.value(unqualifiedProp)); } return qualifiedProps; } void ConnectionManager::Private::ProtocolWrapper::fillRCCs() { RequestableChannelClassList classes; QVariantMap fixedProps; QStringList allowedProps; // Text chatrooms fixedProps.insert( TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); fixedProps.insert( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), static_cast(HandleTypeRoom)); RequestableChannelClass textChatroom = {fixedProps, allowedProps}; classes.append(textChatroom); // 1-1 text chats fixedProps[TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")] = static_cast(HandleTypeContact); RequestableChannelClass text = {fixedProps, allowedProps}; classes.append(text); // Media calls fixedProps[TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")] = TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA; RequestableChannelClass media = {fixedProps, allowedProps}; classes.append(media); // Initially audio-only calls allowedProps.push_back( TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio")); RequestableChannelClass initialAudio = {fixedProps, allowedProps}; classes.append(initialAudio); // Initially AV calls allowedProps.push_back( TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo")); RequestableChannelClass initialAV = {fixedProps, allowedProps}; classes.append(initialAV); // Initially video-only calls allowedProps.removeAll( TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio")); RequestableChannelClass initialVideo = {fixedProps, allowedProps}; classes.append(initialVideo); // That also settles upgrading calls, because the media classes don't have ImmutableStreams mInfo.setRequestableChannelClasses(classes); } bool ConnectionManager::Private::ProtocolWrapper::extractImmutableProperties() { extractMainProperties(mImmutableProps); extractAvatarsProperties(mImmutableProps); extractPresenceProperties(mImmutableProps); extractAddressingProperties(mImmutableProps); return mHasMainProps && mHasAvatarsProps && mHasPresenceProps && mHasAddressingProps; } void ConnectionManager::Private::ProtocolWrapper::extractMainProperties(const QVariantMap &props) { mHasMainProps = props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".Interfaces")) && props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".Parameters")) && props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".ConnectionInterfaces")) && props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".RequestableChannelClasses")) && props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".VCardField")) && props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".EnglishName")) && props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".Icon")); setInterfaces(qdbus_cast( props[TP_QT_IFACE_PROTOCOL + QLatin1String(".Interfaces")])); mReadinessHelper->setInterfaces(interfaces()); ParamSpecList parameters = qdbus_cast( props[TP_QT_IFACE_PROTOCOL + QLatin1String(".Parameters")]); foreach (const ParamSpec &spec, parameters) { mInfo.addParameter(spec); } mInfo.setVCardField(qdbus_cast( props[TP_QT_IFACE_PROTOCOL + QLatin1String(".VCardField")])); QString englishName = qdbus_cast( props[TP_QT_IFACE_PROTOCOL + QLatin1String(".EnglishName")]); if (englishName.isEmpty()) { QStringList words = mInfo.name().split(QLatin1Char('-')); for (int i = 0; i < words.size(); ++i) { words[i][0] = words[i].at(0).toUpper(); } englishName = words.join(QLatin1String(" ")); } mInfo.setEnglishName(englishName); QString iconName = qdbus_cast( props[TP_QT_IFACE_PROTOCOL + QLatin1String(".Icon")]); if (iconName.isEmpty()) { iconName = QString(QLatin1String("im-%1")).arg(mInfo.name()); } mInfo.setIconName(iconName); // Don't overwrite the everything-is-possible RCCs with an empty list if there is no RCCs key if (props.contains(TP_QT_IFACE_PROTOCOL + QLatin1String(".RequestableChannelClasses"))) { mInfo.setRequestableChannelClasses(qdbus_cast( props[TP_QT_IFACE_PROTOCOL + QLatin1String(".RequestableChannelClasses")])); } } void ConnectionManager::Private::ProtocolWrapper::extractAvatarsProperties(const QVariantMap &props) { mHasAvatarsProps = props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".SupportedAvatarMIMETypes")) && props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarHeight")) && props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarHeight")) && props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarHeight")) && props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarWidth")) && props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarWidth")) && props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarWidth")) && props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarBytes")); QStringList supportedMimeTypes = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".SupportedAvatarMIMETypes")]); uint minHeight = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarHeight")]); uint maxHeight = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarHeight")]); uint recommendedHeight = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarHeight")]); uint minWidth = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarWidth")]); uint maxWidth = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarWidth")]); uint recommendedWidth = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarWidth")]); uint maxBytes = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarBytes")]); mInfo.setAvatarRequirements(AvatarSpec(supportedMimeTypes, minHeight, maxHeight, recommendedHeight, minWidth, maxWidth, recommendedWidth, maxBytes)); } void ConnectionManager::Private::ProtocolWrapper::extractPresenceProperties(const QVariantMap &props) { mHasPresenceProps = props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE + QLatin1String(".Statuses")); mInfo.setAllowedPresenceStatuses(PresenceSpecList(qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE + QLatin1String(".Statuses")]))); } void ConnectionManager::Private::ProtocolWrapper::extractAddressingProperties(const QVariantMap &props) { mHasAddressingProps = props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING + QLatin1String(".AddressableVCardFields")) && props.contains(TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING + QLatin1String(".AddressableURISchemes")); QStringList vcardFields = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING + QLatin1String(".AddressableVCardFields")]); QStringList uriSchemes = qdbus_cast( props[TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING + QLatin1String(".AddressableURISchemes")]); mInfo.setAddressableVCardFields(vcardFields); mInfo.setAddressableUriSchemes(uriSchemes); } ConnectionManager::Private::Private(ConnectionManager *parent, const QString &name, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) : parent(parent), lowlevel(ConnectionManagerLowlevelPtr(new ConnectionManagerLowlevel(parent))), name(name), baseInterface(new Client::ConnectionManagerInterface(parent)), properties(parent->interface()), readinessHelper(parent->readinessHelper()), connFactory(connFactory), chanFactory(chanFactory), contactFactory(contactFactory) { debug() << "Creating new ConnectionManager:" << parent->busName(); if (connFactory->dbusConnection().name() != parent->dbusConnection().name()) { warning() << " The D-Bus connection in the connection factory is not the proxy connection"; } if (chanFactory->dbusConnection().name() != parent->dbusConnection().name()) { warning() << " The D-Bus connection in the channel factory is not the proxy connection"; } ReadinessHelper::Introspectables introspectables; // As ConnectionManager does not have predefined statuses let's simulate one (0) ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMain, this); introspectables[FeatureCore] = introspectableCore; readinessHelper->addIntrospectables(introspectables); } ConnectionManager::Private::~Private() { delete baseInterface; } bool ConnectionManager::Private::parseConfigFile() { ManagerFile f(name); if (!f.isValid()) { return false; } foreach (const QString &protocol, f.protocols()) { ProtocolInfo info(ConnectionManagerPtr(parent), protocol); foreach (const ParamSpec &spec, f.parameters(protocol)) { info.addParameter(spec); } info.setRequestableChannelClasses( f.requestableChannelClasses(protocol)); info.setVCardField(f.vcardField(protocol)); info.setEnglishName(f.englishName(protocol)); info.setIconName(f.iconName(protocol)); info.setAllowedPresenceStatuses(f.allowedPresenceStatuses(protocol)); info.setAvatarRequirements(f.avatarRequirements(protocol)); info.setAddressableVCardFields(f.addressableVCardFields(protocol)); info.setAddressableUriSchemes(f.addressableUriSchemes(protocol)); protocols.append(info); } return true; } void ConnectionManager::Private::introspectMain(ConnectionManager::Private *self) { if (self->parseConfigFile()) { self->readinessHelper->setIntrospectCompleted(FeatureCore, true); return; } warning() << "Error parsing config file for connection manager" << self->name << "- introspecting"; debug() << "Calling Properties::GetAll(ConnectionManager)"; PendingVariantMap *pvm = self->baseInterface->requestAllProperties(); self->parent->connect(pvm, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotMainProperties(Tp::PendingOperation*))); } void ConnectionManager::Private::introspectProtocolsLegacy() { debug() << "Calling ConnectionManager::ListProtocols"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( baseInterface->ListProtocols(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotProtocolsLegacy(QDBusPendingCallWatcher*))); } void ConnectionManager::Private::introspectParametersLegacy() { foreach (const QString &protocolName, parametersQueue) { debug() << "Calling ConnectionManager::GetParameters(" << protocolName << ")"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( baseInterface->GetParameters(protocolName), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotParametersLegacy(QDBusPendingCallWatcher*))); } } QString ConnectionManager::Private::makeBusName(const QString &name) { return QString(TP_QT_CONNECTION_MANAGER_BUS_NAME_BASE).append(name); } QString ConnectionManager::Private::makeObjectPath(const QString &name) { return QString(TP_QT_CONNECTION_MANAGER_OBJECT_PATH_BASE).append(name); } /** * \class ConnectionManagerLowlevel * \ingroup clientcm * \headerfile TelepathyQt/connection-manager-lowlevel.h * * \brief The ConnectionManagerLowlevel class extends ConnectionManager with * support to low-level features. */ ConnectionManagerLowlevel::ConnectionManagerLowlevel(ConnectionManager *cm) : mPriv(new Private(cm)) { } ConnectionManagerLowlevel::~ConnectionManagerLowlevel() { delete mPriv; } bool ConnectionManagerLowlevel::isValid() const { return !(connectionManager().isNull()); } ConnectionManagerPtr ConnectionManagerLowlevel::connectionManager() const { return ConnectionManagerPtr(mPriv->cm); } /** * \class ConnectionManager * \ingroup clientcm * \headerfile TelepathyQt/connection-manager.h * * \brief The ConnectionManager class represents a Telepathy connection manager. * * Connection managers allow connections to be made on one or more protocols. * * Most client applications should use this functionality via the * AccountManager, to allow connections to be shared between client * applications. */ /** * Feature representing the core that needs to become ready to make the * ConnectionManager object usable. * * Note that this feature must be enabled in order to use most ConnectionManager * methods. * See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature ConnectionManager::FeatureCore = Feature(QLatin1String(ConnectionManager::staticMetaObject.className()), 0, true); /** * Create a new ConnectionManager object. * * The instance will use a connection factory creating Tp::Connection objects with no features * ready, and a channel factory creating stock Telepathy-Qt channel subclasses, as appropriate, * with no features ready. * * \param bus QDBusConnection to use. * \param name Name of the connection manager. * \return A ConnectionManagerPtr object pointing to the newly created * ConnectionManager object. */ ConnectionManagerPtr ConnectionManager::create(const QDBusConnection &bus, const QString &name) { return ConnectionManagerPtr(new ConnectionManager(QDBusConnection::sessionBus(), name, ConnectionFactory::create(bus), ChannelFactory::create(bus), ContactFactory::create())); } /** * Create a new ConnectionManager using QDBusConnection::sessionBus() and the given factories. * * The channel factory is passed to any Connection objects created by this manager * object. In fact, they're not used directly by ConnectionManager at all. * * A warning is printed if the factories are for a bus different from QDBusConnection::sessionBus(). * * \param name Name of the connection manager. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return A ConnectionManagerPtr object pointing to the newly created * ConnectionManager object. */ ConnectionManagerPtr ConnectionManager::create(const QString &name, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return ConnectionManagerPtr(new ConnectionManager(QDBusConnection::sessionBus(), name, connectionFactory, channelFactory, contactFactory)); } /** * Create a new ConnectionManager using the given \a bus and the given factories. * * The channel factory is passed to any Connection objects created by this manager * object. In fact, they're not used directly by ConnectionManager at all. * * A warning is printed if the factories are for a bus different from QDBusConnection::sessionBus(). * * \param bus QDBusConnection to use. * \param name Name of the connection manager. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return A ConnectionManagerPtr object pointing to the newly created * ConnectionManager object. */ ConnectionManagerPtr ConnectionManager::create(const QDBusConnection &bus, const QString &name, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return ConnectionManagerPtr(new ConnectionManager(bus, name, connectionFactory, channelFactory, contactFactory)); } /** * Construct a new ConnectionManager object using the given \a bus. * * \param bus QDBusConnection to use. * \param name Name of the connection manager. */ ConnectionManager::ConnectionManager(const QDBusConnection &bus, const QString &name, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) : StatelessDBusProxy(bus, Private::makeBusName(name), Private::makeObjectPath(name), FeatureCore), OptionalInterfaceFactory(this), mPriv(new Private(this, name, connectionFactory, channelFactory, contactFactory)) { } /** * Class destructor. */ ConnectionManager::~ConnectionManager() { delete mPriv; } /** * Return the short name of the connection manager (e.g. "gabble"). * * \return The name of the connection manager. */ QString ConnectionManager::name() const { return mPriv->name; } /** * Return the connection factory used by this manager. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the manager would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ConnectionFactory object. */ ConnectionFactoryConstPtr ConnectionManager::connectionFactory() const { return mPriv->connFactory; } /** * Return the channel factory used by this manager. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the manager would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ChannelFactory object. */ ChannelFactoryConstPtr ConnectionManager::channelFactory() const { return mPriv->chanFactory; } /** * Return the contact factory used by this manager. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the manager would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ContactFactory object. */ ContactFactoryConstPtr ConnectionManager::contactFactory() const { return mPriv->contactFactory; } /** * Return a list of strings identifying the protocols supported by this * connection manager, as described in the \telepathy_spec (e.g. "jabber"). * * These identifiers are not intended to be displayed to users directly; user * interfaces are responsible for mapping them to localized strings. * * This method requires ConnectionManager::FeatureCore to be ready. * * \return A list of supported protocols. */ QStringList ConnectionManager::supportedProtocols() const { QStringList protocols; foreach (const ProtocolInfo &info, mPriv->protocols) { protocols.append(info.name()); } return protocols; } /** * Return a list of protocols info for this connection manager. * * Note that the returned ProtocolInfoList contents should not be freed. * * This method requires ConnectionManager::FeatureCore to be ready. * * \return A list of ṔrotocolInfo. */ const ProtocolInfoList &ConnectionManager::protocols() const { return mPriv->protocols; } /** * Return whether this connection manager implements the protocol specified by * \a protocolName. * * This method requires ConnectionManager::FeatureCore to be ready. * * \return \c true if the protocol is supported, \c false otherwise. * \sa protocol(), protocols() */ bool ConnectionManager::hasProtocol(const QString &protocolName) const { foreach (const ProtocolInfo &info, mPriv->protocols) { if (info.name() == protocolName) { return true; } } return false; } /** * Return the ProtocolInfo object for the protocol specified by * \a protocolName. * * This method requires ConnectionManager::FeatureCore to be ready. * * \param protocolName The name of the protocol. * \return A ProtocolInfo object which will return \c for ProtocolInfo::isValid() if the protocol * specified by \a protocolName is not supported. * \sa hasProtocol() */ ProtocolInfo ConnectionManager::protocol(const QString &protocolName) const { foreach (const ProtocolInfo &info, mPriv->protocols) { if (info.name() == protocolName) { return info; } } return ProtocolInfo(); } /** * Request a Connection object representing a given account on a given protocol * with the given parameters. * * Return a pending operation representing the Connection object which will * succeed when the connection has been created or fail if an error occurred. * * \param protocol Name of the protocol to create the account for. * \param parameters Account parameters. * \return A PendingOperation which will emit PendingConnection::finished when * the account has been created of failed its creation process. */ PendingConnection *ConnectionManagerLowlevel::requestConnection(const QString &protocol, const QVariantMap ¶meters) { if (!isValid()) { return new PendingConnection(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("The connection manager has been destroyed already")); } return new PendingConnection(connectionManager(), protocol, parameters); } /** * Return a pending operation from which a list of all installed connection * manager short names (such as "gabble" or "haze") can be retrieved if it * succeeds. * * \return A PendingStringList which will emit PendingStringList::finished * when this object has finished or failed getting the connection * manager names. */ PendingStringList *ConnectionManager::listNames(const QDBusConnection &bus) { return new ConnectionManager::Private::PendingNames(bus); } ConnectionManagerLowlevelPtr ConnectionManager::lowlevel() { return mPriv->lowlevel; } ConnectionManagerLowlevelConstPtr ConnectionManager::lowlevel() const { return mPriv->lowlevel; } /** * Return the Client::ConnectionManagerInterface for this ConnectionManager. * This method is protected since the convenience methods provided by this * class should generally be used instead of calling D-Bus methods * directly. * * \return A pointer to the existing Client::ConnectionManagerInterface for this * ConnectionManager object. */ Client::ConnectionManagerInterface *ConnectionManager::baseInterface() const { return mPriv->baseInterface; } /**** Private ****/ void ConnectionManager::gotMainProperties(Tp::PendingOperation *op) { QVariantMap props; if (!op->isError()) { debug() << "Got reply to Properties.GetAll(ConnectionManager)"; PendingVariantMap *pvm = qobject_cast(op); props = pvm->result(); // If Interfaces is not supported, the spec says to assume it's // empty, so keep the empty list mPriv was initialized with if (props.contains(QLatin1String("Interfaces"))) { setInterfaces(qdbus_cast(props[QLatin1String("Interfaces")])); mPriv->readinessHelper->setInterfaces(interfaces()); } } else { warning().nospace() << "Properties.GetAll(ConnectionManager) failed: " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, op->errorName(), op->errorMessage()); return; } ProtocolPropertiesMap protocolsMap = qdbus_cast(props[QLatin1String("Protocols")]); if (!protocolsMap.isEmpty()) { ProtocolPropertiesMap::const_iterator i = protocolsMap.constBegin(); ProtocolPropertiesMap::const_iterator end = protocolsMap.constEnd(); while (i != end) { QString protocolName = i.key(); if (!checkValidProtocolName(protocolName)) { warning() << "Protocol has an invalid name" << protocolName << "- ignoring"; continue; } QString escapedProtocolName = protocolName; escapedProtocolName.replace(QLatin1Char('-'), QLatin1Char('_')); QString protocolPath = QString( QLatin1String("%1/%2")).arg(objectPath()).arg(escapedProtocolName); SharedPtr wrapper = SharedPtr( new Private::ProtocolWrapper(ConnectionManagerPtr(this), protocolPath, protocolName, i.value())); connect(wrapper->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onProtocolReady(Tp::PendingOperation*))); mPriv->wrappers.insert(wrapper); ++i; } } else { mPriv->introspectProtocolsLegacy(); } } void ConnectionManager::gotProtocolsLegacy(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; QStringList protocolsNames; if (!reply.isError()) { debug() << "Got reply to ConnectionManager.ListProtocols"; protocolsNames = reply.value(); if (!protocolsNames.isEmpty()) { foreach (const QString &protocolName, protocolsNames) { mPriv->protocols.append(ProtocolInfo(ConnectionManagerPtr(this), protocolName)); mPriv->parametersQueue.enqueue(protocolName); } mPriv->introspectParametersLegacy(); } else { //no protocols - introspection finished mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); warning().nospace() << "ConnectionManager.ListProtocols failed: " << reply.error().name() << ": " << reply.error().message(); // FIXME shouldn't this invalidate the CM? } watcher->deleteLater(); } void ConnectionManager::gotParametersLegacy(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; QString protocolName = mPriv->parametersQueue.dequeue(); bool found = false; int pos = 0; foreach (const ProtocolInfo &info, mPriv->protocols) { if (info.name() == protocolName) { found = true; break; } ++pos; } Q_ASSERT(found); Q_UNUSED(found); if (!reply.isError()) { debug() << QString(QLatin1String("Got reply to ConnectionManager.GetParameters(%1)")).arg(protocolName); ParamSpecList parameters = reply.value(); ProtocolInfo &info = mPriv->protocols[pos]; foreach (const ParamSpec &spec, parameters) { debug() << "Parameter" << spec.name << "has flags" << spec.flags << "and signature" << spec.signature; info.addParameter(spec); } } else { // let's remove this protocol as we can't get the params mPriv->protocols.removeAt(pos); warning().nospace() << QString(QLatin1String("ConnectionManager.GetParameters(%1) failed: ")).arg(protocolName) << reply.error().name() << ": " << reply.error().message(); } if (mPriv->parametersQueue.isEmpty()) { if (!mPriv->protocols.isEmpty()) { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } else { // we could not retrieve the params for any protocol, fail core. mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); } } watcher->deleteLater(); } void ConnectionManager::onProtocolReady(Tp::PendingOperation *op) { PendingReady *pr = qobject_cast(op); SharedPtr wrapper = SharedPtr::qObjectCast(pr->proxy()); ProtocolInfo info = wrapper->info(); mPriv->wrappers.remove(wrapper); if (!op->isError()) { mPriv->protocols.append(info); } else { warning().nospace() << "Protocol(" << info.name() << ")::becomeReady " "failed: " << op->errorName() << ": " << op->errorMessage(); } if (mPriv->wrappers.isEmpty()) { if (!mPriv->protocols.isEmpty()) { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } else { // we could not make any Protocol objects ready, fail core. mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, op->errorName(), op->errorMessage()); } } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/pending-variant-map.h0000664000175000017500000000321512470405660021227 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_variant_map_h_HEADER_GUARD_ #define _TelepathyQt_pending_variant_map_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class TP_QT_EXPORT PendingVariantMap : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingVariantMap); public: PendingVariantMap(QDBusPendingCall call, const SharedPtr &object); ~PendingVariantMap(); QVariantMap result() const; private Q_SLOTS: TP_QT_NO_EXPORT void watcherFinished(QDBusPendingCallWatcher*); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/PendingAccount0000664000175000017500000000037112470405660020041 0ustar jrjr#ifndef _TelepathyQt_PendingAccount_HEADER_GUARD_ #define _TelepathyQt_PendingAccount_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ContactCapabilities0000664000175000017500000000041012470405660021037 0ustar jrjr#ifndef _TelepathyQt_ContactCapabilities_HEADER_GUARD_ #define _TelepathyQt_ContactCapabilities_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/connection-internal.h0000664000175000017500000000356112470405660021343 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_connection_internal_h_HEADER_GUARD_ #define _TelepathyQt_connection_internal_h_HEADER_GUARD_ #include #include #include namespace Tp { class TP_QT_NO_EXPORT Connection::PendingConnect : public PendingReady { Q_OBJECT public: PendingConnect(const ConnectionPtr &connection, const Features &requestedFeatures); private Q_SLOTS: TP_QT_NO_EXPORT void onConnectReply(QDBusPendingCallWatcher *); TP_QT_NO_EXPORT void onStatusChanged(Tp::ConnectionStatus newStatus); TP_QT_NO_EXPORT void onBecomeReadyReply(Tp::PendingOperation *); TP_QT_NO_EXPORT void onConnInvalidated(Tp::DBusProxy *proxy, const QString &error, const QString &message); private: friend class ConnectionLowlevel; }; class ConnectionHelper { public: static QString statusReasonToErrorName(Tp::ConnectionStatusReason reason, Tp::ConnectionStatus oldStatus); }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/requestable-channel-class-spec.h0000664000175000017500000001174712470405660023354 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_requestable_channel_class_spec_h_HEADER_GUARD_ #define _TelepathyQt_requestable_channel_class_spec_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT RequestableChannelClassSpec { public: RequestableChannelClassSpec(); RequestableChannelClassSpec(const RequestableChannelClass &rcc); RequestableChannelClassSpec(const RequestableChannelClassSpec &other); ~RequestableChannelClassSpec(); static RequestableChannelClassSpec textChat(); static RequestableChannelClassSpec textChatroom(); static RequestableChannelClassSpec audioCall(); static RequestableChannelClassSpec audioCallWithVideoAllowed(); static RequestableChannelClassSpec videoCall(); static RequestableChannelClassSpec videoCallWithAudioAllowed(); TP_QT_DEPRECATED static RequestableChannelClassSpec streamedMediaCall(); TP_QT_DEPRECATED static RequestableChannelClassSpec streamedMediaAudioCall(); TP_QT_DEPRECATED static RequestableChannelClassSpec streamedMediaVideoCall(); TP_QT_DEPRECATED static RequestableChannelClassSpec streamedMediaVideoCallWithAudio(); static RequestableChannelClassSpec fileTransfer(); static RequestableChannelClassSpec conferenceTextChat(); static RequestableChannelClassSpec conferenceTextChatWithInvitees(); static RequestableChannelClassSpec conferenceTextChatroom(); static RequestableChannelClassSpec conferenceTextChatroomWithInvitees(); TP_QT_DEPRECATED static RequestableChannelClassSpec conferenceStreamedMediaCall(); TP_QT_DEPRECATED static RequestableChannelClassSpec conferenceStreamedMediaCallWithInvitees(); static RequestableChannelClassSpec contactSearch(); static RequestableChannelClassSpec contactSearchWithSpecificServer(); static RequestableChannelClassSpec contactSearchWithLimit(); static RequestableChannelClassSpec contactSearchWithSpecificServerAndLimit(); static RequestableChannelClassSpec dbusTube(const QString &serviceName = QString()); static RequestableChannelClassSpec streamTube(const QString &service = QString()); bool isValid() const { return mPriv.constData() != 0; } RequestableChannelClassSpec &operator=(const RequestableChannelClassSpec &other); bool operator==(const RequestableChannelClassSpec &other) const; bool supports(const RequestableChannelClassSpec &spec) const; QString channelType() const; bool hasTargetHandleType() const; HandleType targetHandleType() const; bool hasFixedProperty(const QString &name) const; QVariant fixedProperty(const QString &name) const; QVariantMap fixedProperties() const; bool allowsProperty(const QString &name) const; QStringList allowedProperties() const; RequestableChannelClass bareClass() const; private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; class TP_QT_EXPORT RequestableChannelClassSpecList : public QList { public: RequestableChannelClassSpecList() { } RequestableChannelClassSpecList(const RequestableChannelClass &rcc) { append(RequestableChannelClassSpec(rcc)); } RequestableChannelClassSpecList(const RequestableChannelClassList &rccs) { Q_FOREACH (const RequestableChannelClass &rcc, rccs) { append(RequestableChannelClassSpec(rcc)); } } RequestableChannelClassSpecList(const RequestableChannelClassSpec &rccSpec) { append(rccSpec); } RequestableChannelClassSpecList(const QList &other) : QList(other) { } RequestableChannelClassList bareClasses() const { RequestableChannelClassList list; Q_FOREACH (const RequestableChannelClassSpec &rccSpec, *this) { list.append(rccSpec.bareClass()); } return list; } }; } // Tp Q_DECLARE_METATYPE(Tp::RequestableChannelClassSpec); Q_DECLARE_METATYPE(Tp::RequestableChannelClassSpecList); #endif telepathy-qt-0.9.6~git1/TelepathyQt/properties.cpp0000664000175000017500000000206412470405660020116 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/cli-properties-body.hpp" #include "TelepathyQt/_gen/cli-properties.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/pending-contacts-internal.h0000664000175000017500000000521412470405660022441 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_contacts_internal_h_HEADER_GUARD_ #define _TelepathyQt_pending_contacts_internal_h_HEADER_GUARD_ #include #include namespace Tp { class TP_QT_NO_EXPORT PendingAddressingGetContacts : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingAddressingGetContacts) public: PendingAddressingGetContacts(const ConnectionPtr &connection, const QString &vcardField, const QStringList &vcardAddresses, const QStringList &interfaces); PendingAddressingGetContacts(const ConnectionPtr &connection, const QStringList &uris, const QStringList &interfaces); ~PendingAddressingGetContacts(); UIntList validHandles() const { return mValidHandles; } bool isForVCardAddresses() const { return mRequestType == ForVCardAddresses; } QString vcardField() const { return mVCardField; } QStringList vcardAddresses() const { return mAddresses; } bool isForUris() const { return mRequestType == ForUris; } QStringList uris() const { return mAddresses; } QStringList validAddresses() const { return mValidAddresses; } QStringList invalidAddresses() const { return mInvalidAddresses; } ContactAttributesMap attributes() const { return mAttributes; } private Q_SLOTS: void onGetContactsFinished(QDBusPendingCallWatcher* watcher); private: enum RequestType { ForVCardAddresses, ForUris }; ConnectionPtr mConnection; RequestType mRequestType; UIntList mValidHandles; QString mVCardField; QStringList mAddresses; QStringList mValidAddresses; QStringList mInvalidAddresses; ContactAttributesMap mAttributes; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/future-channel.xml0000664000175000017500000000064512470405660020663 0ustar jrjr Channel extensions from the future telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceAliasingInterface0000664000175000017500000000044012470405660024346 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceAliasingInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceAliasingInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Profile0000664000175000017500000000034312470405660016537 0ustar jrjr#ifndef _TelepathyQt_Profile_HEADER_GUARD_ #define _TelepathyQt_Profile_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-handles.h0000664000175000017500000000541112470405660020426 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_handles_h_HEADER_GUARD_ #define _TelepathyQt_pending_handles_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include namespace Tp { class PendingHandles; class ReferencedHandles; class TP_QT_EXPORT PendingHandles : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingHandles) public: ~PendingHandles(); ConnectionPtr connection() const; HandleType handleType() const; bool isRequest() const; bool isReference() const; const QStringList &namesRequested() const; QStringList validNames() const; QHash > invalidNames() const; const UIntList &handlesToReference() const; ReferencedHandles handles() const; UIntList invalidHandles() const; private Q_SLOTS: TP_QT_NO_EXPORT void onRequestHandlesFinished(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onHoldHandlesFinished(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onRequestHandlesFallbackFinished(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onHoldHandlesFallbackFinished(QDBusPendingCallWatcher *watcher); private: friend class ConnectionLowlevel; TP_QT_NO_EXPORT PendingHandles(const ConnectionPtr &connection, HandleType handleType, const QStringList &names); TP_QT_NO_EXPORT PendingHandles(const ConnectionPtr &connection, HandleType handleType, const UIntList &handles, const UIntList &alreadyHeld, const UIntList ¬YetHeld); TP_QT_NO_EXPORT PendingHandles(const QString &errorName, const QString &errorMessage); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/media-session-handler.xml0000664000175000017500000000036112470405660022111 0ustar jrjr Media session handler telepathy-qt-0.9.6~git1/TelepathyQt/protocol-parameter.cpp0000664000175000017500000001357112470405660021546 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/debug-internal.h" #include namespace Tp { struct TP_QT_NO_EXPORT ProtocolParameter::Private : public QSharedData { Private(const ParamSpec &sp) : spec(sp), type(variantTypeFromDBusSignature(spec.signature)) { init(); } Private(const QString &name, const QString &dbusSignature, ConnMgrParamFlags flags, const QVariant &defaultValue) : type(variantTypeFromDBusSignature(dbusSignature)) { spec.name = name; spec.flags = flags; spec.signature = dbusSignature; spec.defaultValue = QDBusVariant(defaultValue); init(); } void init() { if (spec.flags & ConnMgrParamFlagHasDefault) { if (spec.defaultValue.variant() == QVariant::Invalid) { // flags contains HasDefault but no default value is passed, // lets warn and build a default value from signature warning() << "Building ProtocolParameter with flags containing ConnMgrParamFlagHasDefault" " and no default value, generating a dummy one from signature"; spec.defaultValue = QDBusVariant( parseValueWithDBusSignature(QString(), spec.signature)); } } else { if (spec.defaultValue.variant() != QVariant::Invalid) { // flags does not contain HasDefault but a default value is passed, // lets add HasDefault to flags debug() << "Building ProtocolParameter with flags not containing ConnMgrParamFlagHasDefault" " and a default value, updating flags to contain ConnMgrParamFlagHasDefault"; spec.flags |= ConnMgrParamFlagHasDefault; } } } ParamSpec spec; QVariant::Type type; }; /** * \class ProtocolParameter * \ingroup clientcm * \headerfile TelepathyQt/protocol-parameter.h * * \brief The ProtocolParameter class represents a Telepathy protocol parameter. */ ProtocolParameter::ProtocolParameter() { } ProtocolParameter::ProtocolParameter(const ParamSpec &spec) : mPriv(new Private(spec)) { } ProtocolParameter::ProtocolParameter(const QString &name, const QDBusSignature &dbusSignature, ConnMgrParamFlags flags, QVariant defaultValue) : mPriv(new Private(name, dbusSignature.signature(), flags, defaultValue)) { } ProtocolParameter::ProtocolParameter(const QString &name, const QString &dbusSignature, ConnMgrParamFlags flags, QVariant defaultValue) : mPriv(new Private(name, dbusSignature, flags, defaultValue)) { } ProtocolParameter::ProtocolParameter(const ProtocolParameter &other) : mPriv(other.mPriv) { } ProtocolParameter::~ProtocolParameter() { } ProtocolParameter &ProtocolParameter::operator=(const ProtocolParameter &other) { this->mPriv = other.mPriv; return *this; } bool ProtocolParameter::operator==(const ProtocolParameter &other) const { if (!isValid() || !other.isValid()) { if (!isValid() && !other.isValid()) { return true; } return false; } return (mPriv->spec.name == other.name()); } bool ProtocolParameter::operator==(const QString &name) const { if (!isValid()) { return false; } return (mPriv->spec.name == name); } bool ProtocolParameter::operator<(const Tp::ProtocolParameter& other) const { return mPriv->spec.name < other.name(); } QString ProtocolParameter::name() const { if (!isValid()) { return QString(); } return mPriv->spec.name; } QDBusSignature ProtocolParameter::dbusSignature() const { if (!isValid()) { return QDBusSignature(); } return QDBusSignature(mPriv->spec.signature); } QVariant::Type ProtocolParameter::type() const { if (!isValid()) { return QVariant::Invalid; } return mPriv->type; } QVariant ProtocolParameter::defaultValue() const { if (!isValid()) { return QVariant(); } return mPriv->spec.defaultValue.variant(); } bool ProtocolParameter::isRequired() const { if (!isValid()) { return false; } return mPriv->spec.flags & ConnMgrParamFlagRequired; } bool ProtocolParameter::isSecret() const { if (!isValid()) { return false; } return mPriv->spec.flags & ConnMgrParamFlagSecret; } bool ProtocolParameter::isRequiredForRegistration() const { if (!isValid()) { return false; } return mPriv->spec.flags & ConnMgrParamFlagRegister; } ParamSpec ProtocolParameter::bareParameter() const { if (!isValid()) { return ParamSpec(); } return mPriv->spec; } uint qHash(const ProtocolParameter& parameter) { return qHash(parameter.name()); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/MethodInvocationContext0000664000175000017500000000042512470405660021757 0ustar jrjr#ifndef _TelepathyQt_MethodInvocationContext_HEADER_GUARD_ #define _TelepathyQt_MethodInvocationContext_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/request-temporary-handler-internal.h0000664000175000017500000000617412470405660024332 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_request_temporary_handler_internal_h_HEADER_GUARD_ #define _TelepathyQt_request_temporary_handler_internal_h_HEADER_GUARD_ #include #include #include namespace Tp { class TP_QT_NO_EXPORT RequestTemporaryHandler : public QObject, public AbstractClientHandler { Q_OBJECT public: static SharedPtr create(const AccountPtr &account); ~RequestTemporaryHandler(); AccountPtr account() const { return mAccount; } ChannelPtr channel() const { return ChannelPtr(mChannel); } /** * Handlers we request ourselves never go through the approvers but this * handler shouldn't get any channels we didn't request - hence let's make * this always false to leave slightly less room for the CD to get confused and * give some channel we didn't request to us, without even asking an approver * first. Though if the CD isn't confused it shouldn't really matter - our filter * is empty anyway. */ bool bypassApproval() const { return false; } void handleChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const QList &requestsSatisfied, const QDateTime &userActionTime, const HandlerInfo &handlerInfo); void setQueueChannelReceived(bool queue); void setDBusHandlerInvoked(); void setDBusHandlerErrored(const QString &errorName, const QString &errorMessage); bool isDBusHandlerInvoked() const { return dbusHandlerInvoked; } Q_SIGNALS: void error(const QString &errorName, const QString &errorMessage); void channelReceived(const Tp::ChannelPtr &channel, const QDateTime &userActionTime, const Tp::ChannelRequestHints &requestHints); private: RequestTemporaryHandler(const AccountPtr &account); void processChannelReceivedQueue(); AccountPtr mAccount; WeakPtr mChannel; bool mQueueChannelReceived; QQueue > mChannelReceivedQueue; bool dbusHandlerInvoked; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/contact-messenger.cpp0000664000175000017500000002136012470405660021343 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/contact-messenger.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/future-internal.h" #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ContactMessenger::Private { Private(ContactMessenger *parent, const AccountPtr &account, const QString &contactIdentifier) : parent(parent), account(account), contactIdentifier(contactIdentifier), cdMessagesInterface(0) { } PendingSendMessage *sendMessage(const Message &message, MessageSendingFlags flags); ContactMessenger *parent; AccountPtr account; QString contactIdentifier; SimpleTextObserverPtr observer; Tp::Client::ChannelDispatcherInterfaceMessages1Interface *cdMessagesInterface; }; PendingSendMessage *ContactMessenger::Private::sendMessage(const Message &message, MessageSendingFlags flags) { if (!cdMessagesInterface) { cdMessagesInterface = new Tp::Client::ChannelDispatcherInterfaceMessages1Interface( account->dbusConnection(), TP_QT_CHANNEL_DISPATCHER_BUS_NAME, TP_QT_CHANNEL_DISPATCHER_OBJECT_PATH, parent); } PendingSendMessage *op = new PendingSendMessage(ContactMessengerPtr(parent), message); Tp::MessagePartList parts; foreach (const Tp::MessagePart &part, message.parts()) { parts << static_cast >(part); } connect(new QDBusPendingCallWatcher( cdMessagesInterface->SendMessage(QDBusObjectPath(account->objectPath()), contactIdentifier, parts, (uint) flags)), SIGNAL(finished(QDBusPendingCallWatcher*)), op, SLOT(onCDMessageSent(QDBusPendingCallWatcher*))); return op; } /** * \class ContactMessenger * \ingroup clientaccount * \headerfile TelepathyQt/contact-messenger.h * * \brief The ContactMessenger class provides an easy way to send text messages to a contact * and also track sent/receive text messages from the same contact. */ /** * Create a new ContactMessenger object. * * \param account The account this messenger is communicating with. * \param contact The contact this messenger is communicating with. * \return An ContactMessengerPtr object pointing to the newly created ContactMessenger object, * or a null ContactMessengerPtr if \a contact is null. */ ContactMessengerPtr ContactMessenger::create(const AccountPtr &account, const ContactPtr &contact) { if (!contact) { warning() << "Contact used to create a ContactMessenger object must be " "valid"; return ContactMessengerPtr(); } return ContactMessengerPtr(new ContactMessenger(account, contact->id())); } /** * Create a new ContactMessenger object. * * \param account The account this messenger is communicating with. * \param contactIdentifier The identifier of the contact this messenger is communicating with. * \return An ContactMessengerPtr object pointing to the newly created ContactMessenger object, * or a null ContactMessengerPtr if \a contact is null. */ ContactMessengerPtr ContactMessenger::create(const AccountPtr &account, const QString &contactIdentifier) { if (contactIdentifier.isEmpty()) { warning() << "Contact identifier used to create a ContactMessenger object must be " "non-empty"; return ContactMessengerPtr(); } return ContactMessengerPtr(new ContactMessenger(account, contactIdentifier)); } /** * Construct a new ContactMessenger object. * * \param account The account this messenger is communicating with. * \param contactIdentifier The identifier of the contact this messenger is communicating with. */ ContactMessenger::ContactMessenger(const AccountPtr &account, const QString &contactIdentifier) : mPriv(new Private(this, account, contactIdentifier)) { mPriv->observer = SimpleTextObserver::create(account, contactIdentifier); connect(mPriv->observer.data(), SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString,Tp::TextChannelPtr)), SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString,Tp::TextChannelPtr))); connect(mPriv->observer.data(), SIGNAL(messageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)), SIGNAL(messageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr))); } /** * Class destructor. */ ContactMessenger::~ContactMessenger() { delete mPriv; } /** * Return the account this messenger is communicating with. * * \return A pointer to the Account object. */ AccountPtr ContactMessenger::account() const { return mPriv->account; } /** * Return the identifier of the contact this messenger is communicating with. * * \return The identifier of the contact. */ QString ContactMessenger::contactIdentifier() const { return mPriv->contactIdentifier; } /** * Return the list of text chats currently being observed. * * \return A list of pointers to TextChannel objects. */ QList ContactMessenger::textChats() const { return mPriv->observer->textChats(); } /** * Send a message to the contact identified by contactIdentifier() using account(). * * Note that the return from this method isn't ordered in any sane way, meaning that * messageSent() can be signalled either before or after the returned PendingSendMessage object * finishes. * * \param text The message text. * \param type The message type. * \param flags The message flags. * \return A PendingSendMessage which will emit PendingSendMessage::finished * once the reply is received and that can be used to check whether sending the * message succeeded or not. */ PendingSendMessage *ContactMessenger::sendMessage(const QString &text, ChannelTextMessageType type, MessageSendingFlags flags) { Message message(type, text); return mPriv->sendMessage(message, flags); } /** * Send a message to the contact identified by contactIdentifier() using account(). * * Note that the return from this method isn't ordered in any sane way, meaning that * messageSent() can be signalled either before or after the returned PendingSendMessage object * finishes. * * \param parts The message parts. * \param flags The message flags. * \return A PendingSendMessage which will emit PendingSendMessage::finished * once the reply is received and that can be used to check whether sending the * message succeeded or not. */ PendingSendMessage *ContactMessenger::sendMessage(const MessageContentPartList &parts, MessageSendingFlags flags) { Message message(parts.bareParts()); return mPriv->sendMessage(message, flags); } /** * \fn void ContactMessenger::messageSent(const Tp::Message &message, * Tp::MessageSendingFlags flags, const QString &sentMessageToken, * const Tp::TextChannelPtr &channel); * * Emitted whenever a text message on account() is sent to the contact * identified by contactIdentifier(). * * \param message The message sent. * \param flags The flags of the message that was sent. * \param sentMessageToken The token of the message that was sent. * \param channel The channel from which the message was sent. */ /** * \fn void ContactMessenger::messageReceived(const Tp::ReceivedMessage &message, * const Tp::TextChannelPtr &channel); * * Emitted whenever a text message on account() is received from the contact * identified by contactIdentifier(). * * \param message The message received. * \param channel The channel from which the message was received. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/PendingChannel0000664000175000017500000000037112470405660020015 0ustar jrjr#ifndef _TelepathyQt_PendingChannel_HEADER_GUARD_ #define _TelepathyQt_PendingChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PendingVariant0000664000175000017500000000037112470405660020051 0ustar jrjr#ifndef _TelepathyQt_PendingVariant_HEADER_GUARD_ #define _TelepathyQt_PendingVariant_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/CallContentInterfaceMediaInterface0000664000175000017500000000043612470405660023752 0ustar jrjr#ifndef _TelepathyQt_CallContentInterfaceMediaInterface_HEADER_GUARD_ #define _TelepathyQt_CallContentInterfaceMediaInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-contact-attributes.h0000664000175000017500000000433212470405660022630 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_contact_attributes_h_HEADER_GUARD_ #define _TelepathyQt_pending_contact_attributes_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include namespace Tp { class ReferencedHandles; class TP_QT_EXPORT PendingContactAttributes : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingContactAttributes) public: ~PendingContactAttributes(); ConnectionPtr connection() const; const UIntList &contactsRequested() const; const QStringList &interfacesRequested() const; bool shouldReference() const; ReferencedHandles validHandles() const; UIntList invalidHandles() const; ContactAttributesMap attributes() const; private Q_SLOTS: TP_QT_NO_EXPORT void onCallFinished(QDBusPendingCallWatcher *watcher); private: friend class ConnectionLowlevel; TP_QT_NO_EXPORT PendingContactAttributes(const ConnectionPtr &connection, const UIntList &handles, const QStringList &interfaces, bool reference); TP_QT_NO_EXPORT void failImmediately(const QString &error, const QString &errorMessage); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/AccountSet0000664000175000017500000000035512470405660017212 0ustar jrjr#ifndef _TelepathyQt_AccountSet_HEADER_GUARD_ #define _TelepathyQt_AccountSet_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/IntrospectableInterface0000664000175000017500000000040012470405660021730 0ustar jrjr#ifndef _TelepathyQt_IntrospectableInterface_HEADER_GUARD_ #define _TelepathyQt_IntrospectableInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/base-call.cpp0000664000175000017500000003403712470405660017552 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2013 Matthias Gehre * @copyright Copyright 2013 Canonical Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "TelepathyQt/base-call-internal.h" #include "TelepathyQt/_gen/base-call.moc.hpp" #include "TelepathyQt/_gen/base-call-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include namespace Tp { /** * \class AbstractCallContentInterface * \ingroup servicecm * \headerfile TelepathyQt/base-call.h * * \brief Base class for all the CallContent object interface implementations. */ AbstractCallContentInterface::AbstractCallContentInterface(const QString &interfaceName) : AbstractDBusServiceInterface(interfaceName) { } AbstractCallContentInterface::~AbstractCallContentInterface() { } BaseCallContent::Adaptee::Adaptee(const QDBusConnection &dbusConnection, BaseCallContent *content) : QObject(content), mContent(content) { debug() << "Creating service::CallContentAdaptor for " << content->dbusObject(); mAdaptor = new Service::CallContentAdaptor(dbusConnection, this, content->dbusObject()); } QStringList BaseCallContent::Adaptee::interfaces() const { QStringList ret; foreach(const AbstractCallContentInterfacePtr & iface, mContent->interfaces()) { ret << iface->interfaceName(); } ret << TP_QT_IFACE_PROPERTIES; return ret; } BaseCallContent::Adaptee::~Adaptee() { } void BaseCallContent::Adaptee::remove(const Tp::Service::CallContentAdaptor::RemoveContextPtr &context) { context->setFinished(); } struct TP_QT_NO_EXPORT BaseCallContent::Private { Private(BaseCallContent *parent, const QDBusConnection &dbusConnection, BaseChannel* channel, const QString &name, const Tp::MediaStreamType &type, const Tp::MediaStreamDirection &direction) : parent(parent), channel(channel), name(name), type(type), disposition(Tp::CallContentDispositionNone), direction(direction), adaptee(new BaseCallContent::Adaptee(dbusConnection, parent)) { } BaseCallContent *parent; BaseChannel *channel; QString name; Tp::MediaStreamType type; Tp::CallContentDisposition disposition; Tp::ObjectPathList streams; Tp::MediaStreamDirection direction; QHash interfaces; BaseCallContent::Adaptee *adaptee; }; BaseCallContent::BaseCallContent(const QDBusConnection &dbusConnection, BaseChannel* channel, const QString &name, const Tp::MediaStreamType &type, const Tp::MediaStreamDirection &direction) : DBusService(dbusConnection), mPriv(new Private(this, dbusConnection, channel, name, type, direction)) { } BaseCallContent::~BaseCallContent() { delete mPriv; } QVariantMap BaseCallContent::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CALL_CONTENT + QLatin1String(".Interfaces"), QVariant::fromValue(mPriv->adaptee->interfaces())); map.insert(TP_QT_IFACE_CALL_CONTENT + QLatin1String(".Name"), QVariant::fromValue(mPriv->adaptee->name())); map.insert(TP_QT_IFACE_CALL_CONTENT + QLatin1String(".Type"), QVariant::fromValue((uint)mPriv->adaptee->type())); map.insert(TP_QT_IFACE_CALL_CONTENT + QLatin1String(".Disposition"), QVariant::fromValue((uint)mPriv->adaptee->disposition())); return map; } QString BaseCallContent::name() const { return mPriv->name; } Tp::MediaStreamType BaseCallContent::type() const { return mPriv->type; } Tp::CallContentDisposition BaseCallContent::disposition() const { return mPriv->disposition; } Tp::ObjectPathList BaseCallContent::streams() const { return mPriv->streams; } QString BaseCallContent::uniqueName() const { return QString(QLatin1String("_%1")).arg((quintptr) this, 0, 16); } bool BaseCallContent::registerObject(DBusError *error) { if (isRegistered()) { return true; } QString name = mPriv->name; QString busName = mPriv->channel->busName(); QString objectPath = QString(QLatin1String("%1/%2")) .arg(mPriv->channel->objectPath(), name); debug() << "Registering Content: busName: " << busName << " objectName: " << objectPath; DBusError _error; debug() << "CallContent: registering interfaces at " << dbusObject(); foreach(const AbstractCallContentInterfacePtr & iface, mPriv->interfaces) { if (!iface->registerInterface(dbusObject())) { // lets not fail if an optional interface fails registering, lets warn only warning() << "Unable to register interface" << iface->interfaceName(); } } bool ret = registerObject(busName, objectPath, &_error); if (!ret && error) { error->set(_error.name(), _error.message()); } return ret; } /** * Reimplemented from DBusService. */ bool BaseCallContent::registerObject(const QString &busName, const QString &objectPath, DBusError *error) { return DBusService::registerObject(busName, objectPath, error); } QList BaseCallContent::interfaces() const { return mPriv->interfaces.values(); } bool BaseCallContent::plugInterface(const AbstractCallContentInterfacePtr &interface) { if (isRegistered()) { warning() << "Unable to plug protocol interface " << interface->interfaceName() << "- protocol already registered"; return false; } if (interface->isRegistered()) { warning() << "Unable to plug protocol interface" << interface->interfaceName() << "- interface already registered"; return false; } if (mPriv->interfaces.contains(interface->interfaceName())) { warning() << "Unable to plug protocol interface" << interface->interfaceName() << "- another interface with same name already plugged"; return false; } debug() << "Interface" << interface->interfaceName() << "plugged"; mPriv->interfaces.insert(interface->interfaceName(), interface); return true; } // Call.I.Mute BaseCallMuteInterface::Adaptee::Adaptee(BaseCallMuteInterface *interface) : QObject(interface), mInterface(interface) { } BaseCallMuteInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseCallMuteInterface::Private { Private(BaseCallMuteInterface *parent, Tp::LocalMuteState state) : state(state), adaptee(new BaseCallMuteInterface::Adaptee(parent)) { } SetMuteStateCallback setMuteStateCB; Tp::LocalMuteState state; BaseCallMuteInterface::Adaptee *adaptee; }; void BaseCallMuteInterface::Adaptee::requestMuted(bool mute, const Tp::Service::CallInterfaceMuteAdaptor::RequestMutedContextPtr &context) { if (!mInterface->mPriv->setMuteStateCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } Tp::LocalMuteState state = Tp::LocalMuteStateUnmuted; if (mute) { state = Tp::LocalMuteStateMuted; } DBusError error; mInterface->mPriv->setMuteStateCB(state, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseCallMuteInterface * \ingroup servicecm * \headerfile TelepathyQt/base-call.h * * \brief Base class for implementations of Call.Interface.Mute * */ /** * Class constructor. */ BaseCallMuteInterface::BaseCallMuteInterface() : AbstractChannelInterface(TP_QT_IFACE_CALL_INTERFACE_MUTE), mPriv(new Private(this, Tp::LocalMuteStateUnmuted)) { } Tp::LocalMuteState BaseCallMuteInterface::localMuteState() const { return mPriv->state; } void BaseCallMuteInterface::setMuteState(const Tp::LocalMuteState &state) { if (mPriv->state != state) { mPriv->state = state; QMetaObject::invokeMethod(mPriv->adaptee, "muteStateChanged", Q_ARG(Tp::LocalMuteState, state)); } } void BaseCallMuteInterface::setSetMuteStateCallback(const SetMuteStateCallback &cb) { mPriv->setMuteStateCB = cb; } /** * Class destructor. */ BaseCallMuteInterface::~BaseCallMuteInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseCallMuteInterface::immutableProperties() const { QVariantMap map; return map; } void BaseCallMuteInterface::createAdaptor() { (void) new Service::CallInterfaceMuteAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } // Call.Content.Interface.DTMF BaseCallContentDTMFInterface::Adaptee::Adaptee(BaseCallContentDTMFInterface *interface) : QObject(interface), mInterface(interface) { } BaseCallContentDTMFInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseCallContentDTMFInterface::Private { Private(BaseCallContentDTMFInterface *parent) : currentlySendingTones(false), adaptee(new BaseCallContentDTMFInterface::Adaptee(parent)) { } StartToneCallback startToneCB; StopToneCallback stopToneCB; MultipleTonesCallback multipleTonesCB; bool currentlySendingTones; QString deferredTones; BaseCallContentDTMFInterface::Adaptee *adaptee; }; void BaseCallContentDTMFInterface::Adaptee::startTone(uchar event, const Tp::Service::CallContentInterfaceDTMFAdaptor::StartToneContextPtr &context) { if (!mInterface->mPriv->startToneCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->startToneCB(event, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseCallContentDTMFInterface::Adaptee::stopTone(const Tp::Service::CallContentInterfaceDTMFAdaptor::StopToneContextPtr &context) { if (!mInterface->mPriv->stopToneCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->stopToneCB(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseCallContentDTMFInterface::Adaptee::multipleTones(const QString& tones, const Tp::Service::CallContentInterfaceDTMFAdaptor::MultipleTonesContextPtr &context) { if (!mInterface->mPriv->multipleTonesCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->multipleTonesCB(tones, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseCallContentDTMFInterface * \ingroup servicecm * \headerfile TelepathyQt/base-call.h * * \brief Base class for implementations of Call.Content.Interface.DTMF * */ /** * Class constructor. */ BaseCallContentDTMFInterface::BaseCallContentDTMFInterface() : AbstractCallContentInterface(TP_QT_IFACE_CALL_CONTENT_INTERFACE_DTMF), mPriv(new Private(this)) { } bool BaseCallContentDTMFInterface::currentlySendingTones() const { return mPriv->currentlySendingTones; } void BaseCallContentDTMFInterface::setCurrentlySendingTones(bool sending) { mPriv->currentlySendingTones = sending; } QString BaseCallContentDTMFInterface::deferredTones() const { return mPriv->deferredTones; } void BaseCallContentDTMFInterface::setDeferredTones(const QString &tones) { mPriv->deferredTones = tones; } void BaseCallContentDTMFInterface::setStartToneCallback(const StartToneCallback &cb) { mPriv->startToneCB = cb; } void BaseCallContentDTMFInterface::setStopToneCallback(const StopToneCallback &cb) { mPriv->stopToneCB = cb; } void BaseCallContentDTMFInterface::setMultipleTonesCallback(const MultipleTonesCallback &cb) { mPriv->multipleTonesCB = cb; } /** * Class destructor. */ BaseCallContentDTMFInterface::~BaseCallContentDTMFInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseCallContentDTMFInterface::immutableProperties() const { QVariantMap map; return map; } void BaseCallContentDTMFInterface::createAdaptor() { (void) new Service::CallContentInterfaceDTMFAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } } telepathy-qt-0.9.6~git1/TelepathyQt/ChannelDispatchOperationInterface0000664000175000017500000000045212470405660023672 0ustar jrjr#ifndef _TelepathyQt_ChannelDispatchOperationInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelDispatchOperationInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/tls-certificate.cpp0000664000175000017500000000205212470405660021001 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #define IN_TP_QT_HEADER #include #include "TelepathyQt/_gen/cli-tls-certificate-body.hpp" #include "TelepathyQt/_gen/cli-tls-certificate.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/dbus-proxy-factory.cpp0000664000175000017500000002507412470405660021511 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/dbus-proxy-factory-internal.h" #include "TelepathyQt/_gen/dbus-proxy-factory.moc.hpp" #include "TelepathyQt/_gen/dbus-proxy-factory-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT DBusProxyFactory::Private { Private(const QDBusConnection &bus) : bus(bus), cache(new Cache) { } ~Private() { delete cache; } QDBusConnection bus; Cache *cache; }; /** * \class DBusProxyFactory * \ingroup utils * \headerfile TelepathyQt/dbus-proxy-factory.h * * \brief The DBusProxyFactory class is a base class for all D-Bus proxy factory * classes. Handles proxy caching and making them ready as appropriate. */ /** * Construct a new DBusProxyFactory object. * * The intention for storing the bus here is that it generally doesn't make sense to construct * proxies for multiple buses in the same context. Allowing that would lead to more complex keying * needs in the cache, as well. * * \param bus The D-Bus bus connection for the objects constructed using this factory. */ DBusProxyFactory::DBusProxyFactory(const QDBusConnection &bus) : mPriv(new Private(bus)) { } /** * Class destructor. */ DBusProxyFactory::~DBusProxyFactory() { delete mPriv; } /** * Return the D-Bus connection all of the proxies from this factory communicate with. * * \return A QDBusConnection object. */ const QDBusConnection &DBusProxyFactory::dbusConnection() const { return mPriv->bus; } /** * Return a cached proxy with the given \a busName and \a objectPath. * * If a proxy has not been previously put into the cache by nowHaveProxy for those identifying * attributes, or a previously cached proxy has since been invalidated and/or destroyed, a \c Null * shared pointer is returned instead. * * \param busName Bus name of the proxy to return. * \param objectPath Object path of the proxy to return. * \return A pointer to the DBusProxy object, if any. */ DBusProxyPtr DBusProxyFactory::cachedProxy(const QString &busName, const QString &objectPath) const { QString finalName = finalBusNameFrom(busName); return mPriv->cache->get(Cache::Key(finalName, objectPath)); } /** * Should be called by subclasses when they have a proxy, be it a newly-constructed one or one from * the cache. * * This function will then do the rest of the factory work, including caching the proxy if it's not * cached already, doing any initialPrepare()/readyPrepare() work if appropriate, and making the * features from featuresFor() ready if they aren't already. * * The returned PendingReady only finishes when the initialPrepare() and readyPrepare() operations * for the proxy has completed, and the requested features have all been made ready (or found unable * to be made ready). Note that this might have happened already before calling this function, if * the proxy was not a newly created one, but was looked up from the cache. DBusProxyFactory handles * the necessary subleties for this to work. * * Access to the proxy instance is allowed as soon as this method returns through * PendingReady::proxy(), if the proxy is needed in a context where it's not required to be ready. * * \param proxy The proxy which the factory should now make sure is prepared and made ready. * \return A PendingReady operation which will emit PendingReady::finished * when the proxy is usable. */ PendingReady *DBusProxyFactory::nowHaveProxy(const DBusProxyPtr &proxy) const { Q_ASSERT(!proxy.isNull()); mPriv->cache->put(proxy); return new PendingReady(SharedPtr((DBusProxyFactory*) this), proxy, featuresFor(proxy)); } /** * \fn QString DBusProxyFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const * * "Normalize" a bus name according to the rules for the proxy class to construct. * * Should be implemented by subclasses to transform the application-specified name \a * uniqueOrWellKnown to whatever the proxy constructed for that name would have in its * DBusProxy::busName() in the end. * * For StatelessDBusProxy sub-classes this should mostly be an identity transform, while for * StatefulDBusProxy sub-classes StatefulDBusProxy::uniqueNameFrom() or an equivalent thereof should * be used in most cases. * * If this is not implemented correctly, caching won't work properly. * * \param uniqueOrWellKnown Any valid D-Bus service name, either unique or well-known. * \return Whatever that name would turn to, when a proxy is constructed for it. */ /** * Allows subclasses to do arbitrary manipulation on the proxy before it is attempted to be made * ready. * * If a non-\c NULL operation is returned, the completion of that operation is waited for before * starting to make the object ready whenever nowHaveProxy() is called the first time around for a * given proxy. * * \todo FIXME actually implement this... :) Currently just a vtable placeholder. * \param proxy The just-constructed proxy to be prepared. * \return \c NULL ie. nothing to do. */ PendingOperation *DBusProxyFactory::initialPrepare(const DBusProxyPtr &proxy) const { // Nothing we could think about needs doing return NULL; } /** * Allows subclasses to do arbitrary manipulation on the proxy after it has been made ready. * * If a non-\c NULL operation is returned, the completion of that operation is waited for before * signaling that the object is ready for use after ReadyObject::becomeReady() for it has finished * whenever nowHaveProxy() is called the first time around for a given proxy. * * \todo FIXME actually implement this... :) Currently just a vtable placeholder. * \param proxy The just-readified proxy to be prepared. * \return \c NULL ie. nothing to do. */ PendingOperation *DBusProxyFactory::readyPrepare(const DBusProxyPtr &proxy) const { // Nothing we could think about needs doing return NULL; } /** * \fn Features DBusProxyFactory::featuresFor(const SharedPtr &proxy) const * * Return the features which should be made ready on a given proxy. * * This can be used to implement instance-specific features based on arbitrary criteria. * FixedFeatureFactory implements this as a fixed set of features independent of the instance, * however. * * It should be noted that if an empty set of features is returned, ReadyObject::becomeReady() is * not called at all. In other words, any "core feature" is not automatically added to the requested * features. This is to enable setting a factory to not make proxies ready at all, which is useful * eg. in the case of account editing UIs which aren't interested in the state of Connection objects * for the Account objects they're editing. * * \param proxy The proxy on which the returned features will be made ready. * \return A list of Feature objects. */ DBusProxyFactory::Cache::Cache() { } DBusProxyFactory::Cache::~Cache() { } DBusProxyPtr DBusProxyFactory::Cache::get(const Key &key) const { DBusProxyPtr proxy(proxies.value(key)); if (proxy.isNull() || !proxy->isValid()) { // Weak pointer invalidated or proxy invalidated during this mainloop iteration and we still // haven't got the invalidated() signal for it return DBusProxyPtr(); } return proxy; } void DBusProxyFactory::Cache::put(const DBusProxyPtr &proxy) { if (proxy->busName().isEmpty()) { debug() << "Not inserting proxy" << proxy.data() << "with no bus name to factory cache"; return; } else if (!proxy->isValid()) { debug() << "Not inserting to factory cache invalid proxy - proxy is for" << proxy->busName() << ',' << proxy->objectPath(); return; } Key key(proxy->busName(), proxy->objectPath()); DBusProxyPtr existingProxy(proxies.value(key)); if (!existingProxy || existingProxy != proxy) { // Disconnect the invalidated signal from the proxy we're replacing, so it won't uselessly // cause the new (hopefully valid) proxy to be dropped from the cache if it arrives late. // // The window in which this makes a difference is very slim but existent; namely, somebody // must request a proxy from the factory in the same mainloop iteration as an otherwise // matching proxy has invalidated itself. The invalidation signal would be delivered and // processed only during the next mainloop iteration. if (existingProxy) { Q_ASSERT(!existingProxy->isValid()); existingProxy->disconnect( SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), this, SLOT(onProxyInvalidated(Tp::DBusProxy*))); debug() << "Replacing invalidated proxy" << existingProxy.data() << "in cache for name" << existingProxy->busName() << ',' << existingProxy->objectPath(); } connect(proxy.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onProxyInvalidated(Tp::DBusProxy*))); debug() << "Inserting to factory cache proxy for" << key; proxies.insert(key, proxy); } } void DBusProxyFactory::Cache::onProxyInvalidated(Tp::DBusProxy *proxy) { Key key(proxy->busName(), proxy->objectPath()); // Not having it would indicate invalidated() signaled twice for the same proxy, or us having // connected to two proxies with the same key, neither of which should happen Q_ASSERT(proxies.contains(key)); debug() << "Removing from factory cache invalidated proxy for" << key; proxies.remove(key); } } telepathy-qt-0.9.6~git1/TelepathyQt/or-filter.dox0000664000175000017500000000234512470405660017637 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \class Tp::OrFilter * \ingroup utils * \headerfile TelepathyQt/or-filter.h * * \brief The OrFilter class provides a generic filter object to be used * in conjunction of other filters. * * The OrFilter will match if any of its given list of filters matches * their criteria. */ telepathy-qt-0.9.6~git1/TelepathyQt/dbus-object.cpp0000664000175000017500000000437712470405660020134 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/dbus-object.moc.hpp" #include namespace Tp { struct TP_QT_NO_EXPORT DBusObject::Private { Private(const QDBusConnection &dbusConnection) : dbusConnection(dbusConnection) { } QDBusConnection dbusConnection; QString objectPath; }; /** * \class DBusObject * \ingroup servicesideimpl * \headerfile TelepathyQt/dbus-object.h * * \brief A QObject on which low-level D-Bus adaptors are plugged to provide a D-Bus object. */ /** * Construct a DBusObject that operates on the given \a dbusConnection. * * \param dbusConnection The D-Bus connection to use. * \param parent The QObject parent of this instance. */ DBusObject::DBusObject(const QDBusConnection &dbusConnection, QObject *parent) : QObject(parent), mPriv(new Private(dbusConnection)) { } /** * Class destructor. */ DBusObject::~DBusObject() { delete mPriv; } void DBusObject::setObjectPath(const QString &path) { mPriv->objectPath = path; } QString DBusObject::objectPath() const { return mPriv->objectPath; } /** * Return the D-Bus connection associated with this object. * * \return The D-Bus connection associated with this object. */ QDBusConnection DBusObject::dbusConnection() const { return mPriv->dbusConnection; } } telepathy-qt-0.9.6~git1/TelepathyQt/stream-tube-client-internal.h0000664000175000017500000000417312470405660022710 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include namespace Tp { class TP_QT_NO_EXPORT StreamTubeClient::TubeWrapper : public QObject { Q_OBJECT Q_DISABLE_COPY(TubeWrapper) public: TubeWrapper(const AccountPtr &acc, const IncomingStreamTubeChannelPtr &tube, const QHostAddress &sourceAddress, quint16 sourcePort, StreamTubeClient *parent); TubeWrapper(const AccountPtr &acc, const IncomingStreamTubeChannelPtr &tube, bool requireCredentials, StreamTubeClient *parent); ~TubeWrapper() { } AccountPtr mAcc; IncomingStreamTubeChannelPtr mTube; QHostAddress mSourceAddress; quint16 mSourcePort; Q_SIGNALS: void acceptFinished(TubeWrapper *wrapper, Tp::PendingStreamTubeConnection *conn); void newConnection(TubeWrapper *wrapper, uint conn); void connectionClosed(TubeWrapper *wrapper, uint conn, const QString &error, const QString &message); private Q_SLOTS: void onTubeAccepted(Tp::PendingOperation *); void onNewConnection(uint); void onConnectionClosed(uint, const QString &, const QString &); }; } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfacePasswordInterface0000664000175000017500000000042712470405660023677 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfacePasswordInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfacePasswordInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-contacts.cpp0000664000175000017500000005740512470405660021173 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2011 Collabora Ltd. * @copyright Copyright (C) 2008-2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/pending-contacts-internal.h" #include "TelepathyQt/_gen/pending-contacts.moc.hpp" #include "TelepathyQt/_gen/pending-contacts-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include // FIXME: Refactor PendingContacts code to make it more readable/maintainable and reuse common code // when appropriate. namespace Tp { struct TP_QT_NO_EXPORT PendingContacts::Private { Private(PendingContacts *parent, const ContactManagerPtr &manager, const UIntList &handles, const Features &features, const Features &missingFeatures, const QMap &satisfyingContacts) : parent(parent), manager(manager), features(features), missingFeatures(missingFeatures), satisfyingContacts(satisfyingContacts), requestType(PendingContacts::ForHandles), handles(handles), nested(0) { } Private(PendingContacts *parent, const ContactManagerPtr &manager, const QStringList &list, PendingContacts::RequestType type, const Features &features) : parent(parent), manager(manager), features(features), missingFeatures(features), requestType(type), addresses(list), nested(0) { if (type != PendingContacts::ForIdentifiers && type != PendingContacts::ForUris) { Q_ASSERT(false); } } Private(PendingContacts *parent, const ContactManagerPtr &manager, const QString &vcardField, const QStringList &vcardAddresses, const Features &features) : parent(parent), manager(manager), features(features), missingFeatures(features), requestType(PendingContacts::ForVCardAddresses), addresses(vcardAddresses), vcardField(vcardField), nested(0) { } Private(PendingContacts *parent, const ContactManagerPtr &manager, const QList &contactsToUpgrade, const Features &features) : parent(parent), manager(manager), features(features), requestType(PendingContacts::Upgrade), contactsToUpgrade(contactsToUpgrade), nested(0) { } void setFinished(); bool checkRequestTypeAndState(const char *methodName, const char *debug, RequestType type); // Public object PendingContacts *parent; // Generic parameters ContactManagerPtr manager; Features features; Features missingFeatures; QMap satisfyingContacts; // Request type specific parameters RequestType requestType; UIntList handles; QStringList addresses; QString vcardField; QList contactsToUpgrade; PendingContacts *nested; // Results QList contacts; UIntList invalidHandles; QStringList validIds; QHash > invalidIds; QStringList validAddresses; QStringList invalidAddresses; ReferencedHandles handlesToInspect; }; void PendingContacts::Private::setFinished() { ConnectionLowlevelPtr connLowlevel = manager->connection()->lowlevel(); UIntList handles = invalidHandles; foreach (uint handle, handles) { if (connLowlevel->hasContactId(handle)) { satisfyingContacts.insert(handle, manager->ensureContact(handle, connLowlevel->contactId(handle), missingFeatures)); invalidHandles.removeOne(handle); } } parent->setFinished(); } bool PendingContacts::Private::checkRequestTypeAndState(const char *methodName, const char *debug, RequestType type) { if (!parent->isFinished()) { warning().nospace() << "PendingContacts::" << methodName << "() called before finished"; return false; } else if (parent->isError()) { warning().nospace() << "PendingContacts::" << methodName << "() called when errored"; return false; } else if (requestType != type) { warning().nospace() << "PendingContacts::" << methodName << "() called for" << this << "which is not for " << debug; return false; } return true; } /** * \class PendingContacts * \ingroup clientconn * \headerfile TelepathyQt/pending-contacts.h * * \brief The PendingContacts class is used by ContactManager when * creating/updating Contact objects. * * See \ref async_model */ PendingContacts::PendingContacts(const ContactManagerPtr &manager, const UIntList &handles, const Features &features, const Features &missingFeatures, const QStringList &interfaces, const QMap &satisfyingContacts, const QSet &otherContacts, const QString &errorName, const QString &errorMessage) : PendingOperation(manager->connection()), mPriv(new Private(this, manager, handles, features, missingFeatures, satisfyingContacts)) { if (!errorName.isEmpty()) { setFinishedWithError(errorName, errorMessage); return; } if (!otherContacts.isEmpty()) { ConnectionPtr conn = manager->connection(); if (conn->interfaces().contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS)) { PendingContactAttributes *attributes = conn->lowlevel()->contactAttributes(otherContacts.toList(), interfaces, true); connect(attributes, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAttributesFinished(Tp::PendingOperation*))); } else { // fallback to just create the contacts PendingHandles *handles = conn->lowlevel()->referenceHandles(HandleTypeContact, otherContacts.toList()); connect(handles, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onReferenceHandlesFinished(Tp::PendingOperation*))); } } else { allAttributesFetched(); } } PendingContacts::PendingContacts(const ContactManagerPtr &manager, const QStringList &list, RequestType type, const Features &features, const QStringList &interfaces, const QString &errorName, const QString &errorMessage) : PendingOperation(manager->connection()), mPriv(new Private(this, manager, list, type, features)) { if (!errorName.isEmpty()) { setFinishedWithError(errorName, errorMessage); return; } ConnectionPtr conn = manager->connection(); if (type == ForIdentifiers) { Q_ASSERT(interfaces.isEmpty()); PendingHandles *handles = conn->lowlevel()->requestHandles(HandleTypeContact, list); connect(handles, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onRequestHandlesFinished(Tp::PendingOperation*))); } else if (type == ForUris) { Client::ConnectionInterfaceAddressingInterface *connAddressingIface = conn->optionalInterface( OptionalInterfaceFactory::CheckInterfaceSupported); if (!connAddressingIface) { setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Connection does not support Addressing interface")); return; } PendingAddressingGetContacts *pa = new PendingAddressingGetContacts(conn, list, interfaces); connect(pa, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAddressingGetContactsFinished(Tp::PendingOperation*))); } } PendingContacts::PendingContacts(const ContactManagerPtr &manager, const QString &vcardField, const QStringList &vcardAddresses, const Features &features, const QStringList &interfaces, const QString &errorName, const QString &errorMessage) : PendingOperation(manager->connection()), mPriv(new Private(this, manager, vcardField, vcardAddresses, features)) { if (!errorName.isEmpty()) { setFinishedWithError(errorName, errorMessage); return; } ConnectionPtr conn = manager->connection(); Client::ConnectionInterfaceAddressingInterface *connAddressingIface = conn->optionalInterface( OptionalInterfaceFactory::CheckInterfaceSupported); if (!connAddressingIface) { setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Connection does not support Addressing interface")); return; } PendingAddressingGetContacts *pa = new PendingAddressingGetContacts(conn, vcardField, vcardAddresses, interfaces); connect(pa, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAddressingGetContactsFinished(Tp::PendingOperation*))); } PendingContacts::PendingContacts(const ContactManagerPtr &manager, const QList &contacts, const Features &features, const QString &errorName, const QString &errorMessage) : PendingOperation(manager->connection()), mPriv(new Private(this, manager, contacts, features)) { if (!errorName.isEmpty()) { setFinishedWithError(errorName, errorMessage); return; } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles.push_back(contact->handle()[0]); } mPriv->nested = manager->contactsForHandles(handles, features); connect(mPriv->nested, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onNestedFinished(Tp::PendingOperation*))); } /** * Class destructor. */ PendingContacts::~PendingContacts() { delete mPriv; } ContactManagerPtr PendingContacts::manager() const { return mPriv->manager; } Features PendingContacts::features() const { return mPriv->features; } bool PendingContacts::isForHandles() const { return mPriv->requestType == ForHandles; } UIntList PendingContacts::handles() const { if (!isForHandles()) { warning() << "Tried to get handles from" << this << "which is not for handles!"; } return mPriv->handles; } bool PendingContacts::isForIdentifiers() const { return mPriv->requestType == ForIdentifiers; } QStringList PendingContacts::identifiers() const { if (!isForIdentifiers()) { warning() << "Tried to get identifiers from" << this << "which is not for identifiers!"; return QStringList(); } return mPriv->addresses; } bool PendingContacts::isForVCardAddresses() const { return mPriv->requestType == ForVCardAddresses; } QString PendingContacts::vcardField() const { if (!isForVCardAddresses()) { warning() << "Tried to get vcard field from" << this << "which is not for vcard addresses!"; } return mPriv->vcardField; } QStringList PendingContacts::vcardAddresses() const { if (!isForVCardAddresses()) { warning() << "Tried to get vcard addresses from" << this << "which is not for vcard addresses!"; return QStringList(); } return mPriv->addresses; } bool PendingContacts::isForUris() const { return mPriv->requestType == ForUris; } QStringList PendingContacts::uris() const { if (!isForUris()) { warning() << "Tried to get uris from" << this << "which is not for uris!"; return QStringList(); } return mPriv->addresses; } bool PendingContacts::isUpgrade() const { return mPriv->requestType == Upgrade; } QList PendingContacts::contactsToUpgrade() const { if (!isUpgrade()) { warning() << "Tried to get contacts to upgrade from" << this << "which is not an upgrade!"; } return mPriv->contactsToUpgrade; } QList PendingContacts::contacts() const { if (!isFinished()) { warning() << "PendingContacts::contacts() called before finished"; } else if (isError()) { warning() << "PendingContacts::contacts() called when errored"; } return mPriv->contacts; } UIntList PendingContacts::invalidHandles() const { if (!mPriv->checkRequestTypeAndState("invalidHandles", "handles", ForHandles)) { return UIntList(); } return mPriv->invalidHandles; } QStringList PendingContacts::validIdentifiers() const { if (!mPriv->checkRequestTypeAndState("validIdentifiers", "IDs", ForIdentifiers)) { return QStringList(); } return mPriv->validIds; } QHash > PendingContacts::invalidIdentifiers() const { if (!mPriv->checkRequestTypeAndState("invalidIdentifiers", "IDs", ForIdentifiers)) { return QHash >(); } return mPriv->invalidIds; } QStringList PendingContacts::validVCardAddresses() const { if (!mPriv->checkRequestTypeAndState("validVCardAddresses", "vcard addresses", ForVCardAddresses)) { return QStringList(); } return mPriv->validAddresses; } QStringList PendingContacts::invalidVCardAddresses() const { if (!mPriv->checkRequestTypeAndState("invalidVCardAddresses", "vcard addresses", ForVCardAddresses)) { return QStringList(); } return mPriv->invalidAddresses; } QStringList PendingContacts::validUris() const { if (!mPriv->checkRequestTypeAndState("validUris", "URIS", ForUris)) { return QStringList(); } return mPriv->validAddresses; } QStringList PendingContacts::invalidUris() const { if (!mPriv->checkRequestTypeAndState("invalidUris", "URIS", ForUris)) { return QStringList(); } return mPriv->invalidAddresses; } void PendingContacts::onAttributesFinished(PendingOperation *operation) { PendingContactAttributes *pendingAttributes = qobject_cast(operation); if (pendingAttributes->isError()) { debug() << "PendingAttrs error" << pendingAttributes->errorName() << "message" << pendingAttributes->errorMessage(); setFinishedWithError(pendingAttributes->errorName(), pendingAttributes->errorMessage()); return; } ReferencedHandles validHandles = pendingAttributes->validHandles(); ContactAttributesMap attributes = pendingAttributes->attributes(); foreach (uint handle, mPriv->handles) { if (!mPriv->satisfyingContacts.contains(handle)) { int indexInValid = validHandles.indexOf(handle); if (indexInValid >= 0) { ReferencedHandles referencedHandle = validHandles.mid(indexInValid, 1); QVariantMap handleAttributes = attributes[handle]; mPriv->satisfyingContacts.insert(handle, manager()->ensureContact(referencedHandle, mPriv->missingFeatures, handleAttributes)); } else { mPriv->invalidHandles.push_back(handle); } } } allAttributesFetched(); } void PendingContacts::onRequestHandlesFinished(PendingOperation *operation) { PendingHandles *pendingHandles = qobject_cast(operation); mPriv->validIds = pendingHandles->validNames(); mPriv->invalidIds = pendingHandles->invalidNames(); if (pendingHandles->isError()) { debug() << "RequestHandles error" << operation->errorName() << "message" << operation->errorMessage(); setFinishedWithError(operation->errorName(), operation->errorMessage()); return; } mPriv->nested = manager()->contactsForHandles(pendingHandles->handles(), features()); connect(mPriv->nested, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onNestedFinished(Tp::PendingOperation*))); } void PendingContacts::onAddressingGetContactsFinished(PendingOperation *operation) { PendingAddressingGetContacts *pa = qobject_cast(operation); Q_ASSERT(pa->isForUris() || pa->isForVCardAddresses()); mPriv->validAddresses = pa->validAddresses(); mPriv->invalidAddresses = pa->invalidAddresses(); if (pa->isError()) { setFinishedWithError(operation->errorName(), operation->errorMessage()); return; } ConnectionPtr conn = mPriv->manager->connection(); ContactAttributesMap attributes = pa->attributes(); UIntList handles = attributes.keys(); ReferencedHandles referencedHandles(conn, HandleTypeContact, handles); foreach (uint handle, handles) { int indexInValid = referencedHandles.indexOf(handle); Q_ASSERT(indexInValid >= 0); ReferencedHandles referencedHandle = referencedHandles.mid(indexInValid, 1); QVariantMap handleAttributes = attributes[handle]; ContactPtr contact = mPriv->manager->ensureContact(referencedHandle, mPriv->missingFeatures, handleAttributes); mPriv->contacts.push_back(contact); } setFinished(); } void PendingContacts::onReferenceHandlesFinished(PendingOperation *operation) { PendingHandles *pendingHandles = qobject_cast(operation); if (pendingHandles->isError()) { debug() << "ReferenceHandles error" << operation->errorName() << "message" << operation->errorMessage(); setFinishedWithError(operation->errorName(), operation->errorMessage()); return; } ReferencedHandles validHandles = pendingHandles->handles(); UIntList invalidHandles = pendingHandles->invalidHandles(); ConnectionPtr conn = mPriv->manager->connection(); mPriv->handlesToInspect = ReferencedHandles(conn, HandleTypeContact, UIntList()); foreach (uint handle, mPriv->handles) { if (!mPriv->satisfyingContacts.contains(handle)) { int indexInValid = validHandles.indexOf(handle); if (indexInValid >= 0) { ReferencedHandles referencedHandle = validHandles.mid(indexInValid, 1); mPriv->handlesToInspect.append(referencedHandle); } else { mPriv->invalidHandles.push_back(handle); } } } QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( conn->baseInterface()->InspectHandles(HandleTypeContact, mPriv->handlesToInspect.toList()), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onInspectHandlesFinished(QDBusPendingCallWatcher*))); } void PendingContacts::onNestedFinished(PendingOperation *operation) { Q_ASSERT(operation == mPriv->nested); if (operation->isError()) { debug() << " error" << operation->errorName() << "message" << operation->errorMessage(); setFinishedWithError(operation->errorName(), operation->errorMessage()); return; } mPriv->contacts = mPriv->nested->contacts(); mPriv->nested = 0; mPriv->setFinished(); } void PendingContacts::onInspectHandlesFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { debug().nospace() << "InspectHandles: error " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); return; } QStringList names = reply.value(); int i = 0; ConnectionPtr conn = mPriv->manager->connection(); foreach (uint handle, mPriv->handlesToInspect) { QVariantMap handleAttributes; handleAttributes.insert(TP_QT_IFACE_CONNECTION + QLatin1String("/contact-id"), names[i++]); ReferencedHandles referencedHandle(conn, HandleTypeContact, UIntList() << handle); mPriv->satisfyingContacts.insert(handle, manager()->ensureContact(referencedHandle, mPriv->missingFeatures, handleAttributes)); } allAttributesFetched(); watcher->deleteLater(); } void PendingContacts::allAttributesFetched() { foreach (uint handle, mPriv->handles) { if (mPriv->satisfyingContacts.contains(handle)) { mPriv->contacts.push_back(mPriv->satisfyingContacts[handle]); } } mPriv->setFinished(); } PendingAddressingGetContacts::PendingAddressingGetContacts(const ConnectionPtr &connection, const QString &vcardField, const QStringList &vcardAddresses, const QStringList &interfaces) : PendingOperation(connection), mConnection(connection), mRequestType(ForVCardAddresses), mVCardField(vcardField), mAddresses(vcardAddresses) { // no check for the interface here again, we expect this interface to be used only when // Conn.I.Addressing is available Client::ConnectionInterfaceAddressingInterface *connAddressingIface = connection->optionalInterface( OptionalInterfaceFactory::BypassInterfaceCheck); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( connAddressingIface->GetContactsByVCardField(vcardField, vcardAddresses, interfaces)); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onGetContactsFinished(QDBusPendingCallWatcher*))); } PendingAddressingGetContacts::PendingAddressingGetContacts(const ConnectionPtr &connection, const QStringList &uris, const QStringList &interfaces) : PendingOperation(connection), mConnection(connection), mRequestType(ForUris), mAddresses(uris) { // no check for the interface here again, we expect this interface to be used only when // Conn.I.Addressing is available Client::ConnectionInterfaceAddressingInterface *connAddressingIface = connection->optionalInterface( OptionalInterfaceFactory::BypassInterfaceCheck); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( connAddressingIface->GetContactsByURI(uris, interfaces)); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onGetContactsFinished(QDBusPendingCallWatcher*))); } PendingAddressingGetContacts::~PendingAddressingGetContacts() { } void PendingAddressingGetContacts::onGetContactsFinished(QDBusPendingCallWatcher* watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { AddressingNormalizationMap requested = reply.argumentAt<0>(); mValidHandles = requested.values(); mValidAddresses = requested.keys(); mInvalidAddresses = mAddresses.toSet().subtract(mValidAddresses.toSet()).toList(); mAttributes = reply.argumentAt<1>(); setFinished(); } else { debug().nospace() << "GetContactsBy* failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceRoomConfigInterface0000664000175000017500000000043312470405660024134 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceRoomConfigInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceRoomConfigInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ProtocolParameter0000664000175000017500000000040212470405660020575 0ustar jrjr#ifndef _TelepathyQt_ProtocolParameter_HEADER_GUARD_ #define _TelepathyQt_ProtocolParameter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceGroupInterface0000664000175000017500000000042112470405660023163 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceGroupInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceGroupInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/base-connection.h0000664000175000017500000005124112470405660020437 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_base_connection_h_HEADER_GUARD_ #define _TelepathyQt_base_connection_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include class QString; namespace Tp { class TP_QT_EXPORT BaseConnection : public DBusService { Q_OBJECT Q_DISABLE_COPY(BaseConnection) public: static BaseConnectionPtr create(const QString &cmName, const QString &protocolName, const QVariantMap ¶meters) { return BaseConnectionPtr(new BaseConnection( QDBusConnection::sessionBus(), cmName, protocolName, parameters)); } template static SharedPtr create(const QString &cmName, const QString &protocolName, const QVariantMap ¶meters) { return SharedPtr(new BaseConnectionSubclass( QDBusConnection::sessionBus(), cmName, protocolName, parameters)); } static BaseConnectionPtr create(const QDBusConnection &dbusConnection, const QString &cmName, const QString &protocolName, const QVariantMap ¶meters) { return BaseConnectionPtr(new BaseConnection( dbusConnection, cmName, protocolName, parameters)); } template static SharedPtr create(const QDBusConnection &dbusConnection, const QString &cmName, const QString &protocolName, const QVariantMap ¶meters) { return SharedPtr(new BaseConnectionSubclass( dbusConnection, cmName, protocolName, parameters)); } virtual ~BaseConnection(); QString cmName() const; QString protocolName() const; QVariantMap parameters() const; uint status() const; QVariantMap immutableProperties() const; void setStatus(uint newStatus, uint reason); typedef Callback5 CreateChannelCallback; void setCreateChannelCallback(const CreateChannelCallback &cb); Tp::BaseChannelPtr createChannel(const QString &channelType, uint targetHandleType, uint targetHandle, uint initiatorHandle, bool suppressHandler, const QVariantMap &request, DBusError *error); typedef Callback3 RequestHandlesCallback; void setRequestHandlesCallback(const RequestHandlesCallback &cb); UIntList requestHandles(uint handleType, const QStringList &identifiers, DBusError* error); //typedef Callback3 SetPresenceCallback; //void setSetPresenceCallback(const SetPresenceCallback &cb); void setSelfHandle(uint selfHandle); uint selfHandle() const; typedef Callback1 ConnectCallback; void setConnectCallback(const ConnectCallback &cb); typedef Callback3 InspectHandlesCallback; void setInspectHandlesCallback(const InspectHandlesCallback &cb); Tp::ChannelInfoList channelsInfo(); Tp::ChannelDetailsList channelsDetails(); BaseChannelPtr ensureChannel(const QString &channelType, uint targetHandleType, uint targetHandle, bool &yours, uint initiatorHandle, bool suppressHandler, const QVariantMap &request, DBusError *error); void addChannel(BaseChannelPtr channel); QList interfaces() const; AbstractConnectionInterfacePtr interface(const QString &interfaceName) const; bool plugInterface(const AbstractConnectionInterfacePtr &interface); virtual QString uniqueName() const; bool registerObject(DBusError *error = NULL); Q_SIGNALS: void disconnected(); private Q_SLOTS: TP_QT_NO_EXPORT void removeChannel(); protected: BaseConnection(const QDBusConnection &dbusConnection, const QString &cmName, const QString &protocolName, const QVariantMap ¶meters); virtual bool registerObject(const QString &busName, const QString &objectPath, DBusError *error); private: class Adaptee; friend class Adaptee; class Private; friend class Private; Private *mPriv; }; class TP_QT_EXPORT AbstractConnectionInterface : public AbstractDBusServiceInterface { Q_OBJECT Q_DISABLE_COPY(AbstractConnectionInterface) public: AbstractConnectionInterface(const QString &interfaceName); virtual ~AbstractConnectionInterface(); private: friend class BaseConnection; class Private; friend class Private; Private *mPriv; }; class TP_QT_EXPORT BaseConnectionRequestsInterface : public AbstractConnectionInterface { Q_OBJECT Q_DISABLE_COPY(BaseConnectionRequestsInterface) public: static BaseConnectionRequestsInterfacePtr create(BaseConnection* connection) { return BaseConnectionRequestsInterfacePtr(new BaseConnectionRequestsInterface(connection)); } template static SharedPtr create(BaseConnection* connection) { return SharedPtr( new BaseConnectionRequestsInterfaceSubclass(connection)); } virtual ~BaseConnectionRequestsInterface(); QVariantMap immutableProperties() const; Tp::RequestableChannelClassList requestableChannelClasses; void ensureChannel(const QVariantMap &request, bool &yours, QDBusObjectPath &channel, QVariantMap &details, DBusError* error); void createChannel(const QVariantMap &request, QDBusObjectPath &channel, QVariantMap &details, DBusError* error); public Q_SLOTS: void newChannels(const Tp::ChannelDetailsList &channels); void channelClosed(const QDBusObjectPath &removed); protected: BaseConnectionRequestsInterface(BaseConnection* connection); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseConnectionContactsInterface : public AbstractConnectionInterface { Q_OBJECT Q_DISABLE_COPY(BaseConnectionContactsInterface) public: static BaseConnectionContactsInterfacePtr create() { return BaseConnectionContactsInterfacePtr(new BaseConnectionContactsInterface()); } template static SharedPtr create() { return SharedPtr( new BaseConnectionContactsInterfaceSubclass()); } virtual ~BaseConnectionContactsInterface(); QVariantMap immutableProperties() const; typedef Callback3 GetContactAttributesCallback; void setGetContactAttributesCallback(const GetContactAttributesCallback &cb); ContactAttributesMap getContactAttributes(const Tp::UIntList &handles, const QStringList &interfaces, DBusError *error); void setContactAttributeInterfaces(const QStringList &contactAttributeInterfaces); protected: BaseConnectionContactsInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseConnectionSimplePresenceInterface : public AbstractConnectionInterface { Q_OBJECT Q_DISABLE_COPY(BaseConnectionSimplePresenceInterface) public: static BaseConnectionSimplePresenceInterfacePtr create() { return BaseConnectionSimplePresenceInterfacePtr(new BaseConnectionSimplePresenceInterface()); } template static SharedPtr create() { return SharedPtr( new BaseConnectionSimplePresenceInterfaceSublclass()); } virtual ~BaseConnectionSimplePresenceInterface(); QVariantMap immutableProperties() const; Tp::SimpleStatusSpecMap statuses() const; void setStatuses(const Tp::SimpleStatusSpecMap &statuses); int maximumStatusMessageLength() const; void setMaxmimumStatusMessageLength(uint maxmimumStatusMessageLength); typedef Callback3 SetPresenceCallback; void setSetPresenceCallback(const SetPresenceCallback &cb); void setPresences(const Tp::SimpleContactPresences &presences); protected: BaseConnectionSimplePresenceInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseConnectionContactListInterface : public AbstractConnectionInterface { Q_OBJECT Q_DISABLE_COPY(BaseConnectionContactListInterface) public: static BaseConnectionContactListInterfacePtr create() { return BaseConnectionContactListInterfacePtr(new BaseConnectionContactListInterface()); } template static SharedPtr create() { return SharedPtr( new BaseConnectionContactListInterfaceSubclass()); } virtual ~BaseConnectionContactListInterface(); QVariantMap immutableProperties() const; uint contactListState() const; void setContactListState(uint contactListState); bool contactListPersists() const; void setContactListPersists(bool contactListPersists); bool canChangeContactList() const; void setCanChangeContactList(bool canChangeContactList); bool requestUsesMessage() const; void setRequestUsesMessage(bool requestUsesMessage); bool downloadAtConnection() const; void setDownloadAtConnection(bool downloadAtConnection); typedef Callback3 GetContactListAttributesCallback; void setGetContactListAttributesCallback(const GetContactListAttributesCallback &cb); Tp::ContactAttributesMap getContactListAttributes(const QStringList &interfaces, bool hold, DBusError *error); typedef Callback3 RequestSubscriptionCallback; void setRequestSubscriptionCallback(const RequestSubscriptionCallback &cb); void requestSubscription(const Tp::UIntList &contacts, const QString &message, DBusError *error); typedef Callback2 AuthorizePublicationCallback; void setAuthorizePublicationCallback(const AuthorizePublicationCallback &cb); void authorizePublication(const Tp::UIntList &contacts, DBusError *error); typedef Callback2 RemoveContactsCallback; void setRemoveContactsCallback(const RemoveContactsCallback &cb); void removeContacts(const Tp::UIntList &contacts, DBusError *error); typedef Callback2 UnsubscribeCallback; void setUnsubscribeCallback(const UnsubscribeCallback &cb); void unsubscribe(const Tp::UIntList &contacts, DBusError *error); typedef Callback2 UnpublishCallback; void setUnpublishCallback(const UnpublishCallback &cb); void unpublish(const Tp::UIntList &contacts, DBusError *error); typedef Callback1 DownloadCallback; void setDownloadCallback(const DownloadCallback &cb); void download(DBusError *error); void contactsChangedWithID(const Tp::ContactSubscriptionMap &changes, const Tp::HandleIdentifierMap &identifiers, const Tp::HandleIdentifierMap &removals); protected: BaseConnectionContactListInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseConnectionContactInfoInterface : public AbstractConnectionInterface { Q_OBJECT Q_DISABLE_COPY(BaseConnectionContactInfoInterface) public: static BaseConnectionContactInfoInterfacePtr create() { return BaseConnectionContactInfoInterfacePtr(new BaseConnectionContactInfoInterface()); } template static SharedPtr create() { return SharedPtr( new BaseConnectionContactInfoInterfaceSubclass()); } virtual ~BaseConnectionContactInfoInterface(); QVariantMap immutableProperties() const; Tp::ContactInfoFlags contactInfoFlags() const; void setContactInfoFlags(const Tp::ContactInfoFlags &contactInfoFlags); Tp::FieldSpecs supportedFields() const; void setSupportedFields(const Tp::FieldSpecs &supportedFields); typedef Callback2 GetContactInfoCallback; void setGetContactInfoCallback(const GetContactInfoCallback &cb); Tp::ContactInfoMap getContactInfo(const Tp::UIntList &contacts, DBusError *error); typedef Callback2 RefreshContactInfoCallback; void setRefreshContactInfoCallback(const RefreshContactInfoCallback &cb); void refreshContactInfo(const Tp::UIntList &contacts, DBusError *error); typedef Callback2 RequestContactInfoCallback; void setRequestContactInfoCallback(const RequestContactInfoCallback &cb); Tp::ContactInfoFieldList requestContactInfo(uint contact, DBusError *error); typedef Callback2 SetContactInfoCallback; void setSetContactInfoCallback(const SetContactInfoCallback &cb); void setContactInfo(const Tp::ContactInfoFieldList &contactInfo, DBusError *error); void contactInfoChanged(uint contact, const Tp::ContactInfoFieldList &contactInfo); protected: BaseConnectionContactInfoInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseConnectionAddressingInterface : public AbstractConnectionInterface { Q_OBJECT Q_DISABLE_COPY(BaseConnectionAddressingInterface) public: static BaseConnectionAddressingInterfacePtr create() { return BaseConnectionAddressingInterfacePtr(new BaseConnectionAddressingInterface()); } template static SharedPtr create() { return SharedPtr( new BaseConnectionAddressingInterfaceSubclass()); } virtual ~BaseConnectionAddressingInterface(); QVariantMap immutableProperties() const; typedef Callback6 < void, const QString&, const QStringList&, const QStringList&, Tp::AddressingNormalizationMap&, Tp::ContactAttributesMap&, DBusError* > GetContactsByVCardFieldCallback; void setGetContactsByVCardFieldCallback(const GetContactsByVCardFieldCallback &cb); typedef Callback5 < void, const QStringList&, const QStringList&, Tp::AddressingNormalizationMap&, Tp::ContactAttributesMap&, DBusError* > GetContactsByURICallback; void setGetContactsByURICallback(const GetContactsByURICallback &cb); protected: BaseConnectionAddressingInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseConnectionAliasingInterface : public AbstractConnectionInterface { Q_OBJECT Q_DISABLE_COPY(BaseConnectionAliasingInterface) public: static BaseConnectionAliasingInterfacePtr create() { return BaseConnectionAliasingInterfacePtr(new BaseConnectionAliasingInterface()); } template static SharedPtr create() { return SharedPtr( new BaseConnectionAliasingInterfaceSubclass()); } virtual ~BaseConnectionAliasingInterface(); QVariantMap immutableProperties() const; typedef Callback1 GetAliasFlagsCallback; void setGetAliasFlagsCallback(const GetAliasFlagsCallback &cb); Tp::ConnectionAliasFlags getAliasFlags(DBusError *error); typedef Callback2 RequestAliasesCallback; void setRequestAliasesCallback(const RequestAliasesCallback &cb); QStringList requestAliases(const Tp::UIntList &contacts, DBusError *error); typedef Callback2 GetAliasesCallback; void setGetAliasesCallback(const GetAliasesCallback &cb); Tp::AliasMap getAliases(const Tp::UIntList &contacts, DBusError *error); typedef Callback2 SetAliasesCallback; void setSetAliasesCallback(const SetAliasesCallback &cb); void setAliases(const Tp::AliasMap &aliases, DBusError *error); void aliasesChanged(const Tp::AliasPairList &aliases); protected: BaseConnectionAliasingInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseConnectionAvatarsInterface : public AbstractConnectionInterface { Q_OBJECT Q_DISABLE_COPY(BaseConnectionAvatarsInterface) public: static BaseConnectionAvatarsInterfacePtr create() { return BaseConnectionAvatarsInterfacePtr(new BaseConnectionAvatarsInterface()); } template static SharedPtr create() { return SharedPtr( new BaseConnectionAvatarsInterfaceSubclass()); } virtual ~BaseConnectionAvatarsInterface(); QVariantMap immutableProperties() const; AvatarSpec avatarDetails() const; void setAvatarDetails(const AvatarSpec &spec); typedef Callback2 GetKnownAvatarTokensCallback; void setGetKnownAvatarTokensCallback(const GetKnownAvatarTokensCallback &cb); Tp::AvatarTokenMap getKnownAvatarTokens(const Tp::UIntList &contacts, DBusError *error); typedef Callback2 RequestAvatarsCallback; void setRequestAvatarsCallback(const RequestAvatarsCallback &cb); void requestAvatars(const Tp::UIntList &contacts, DBusError *error); typedef Callback3 SetAvatarCallback; void setSetAvatarCallback(const SetAvatarCallback &cb); QString setAvatar(const QByteArray &avatar, const QString &mimeType, DBusError *error); typedef Callback1 ClearAvatarCallback; void setClearAvatarCallback(const ClearAvatarCallback &cb); void clearAvatar(DBusError *error); void avatarUpdated(uint contact, const QString &newAvatarToken); void avatarRetrieved(uint contact, const QString &token, const QByteArray &avatar, const QString &type); protected: BaseConnectionAvatarsInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/account-capability-filter.dox0000664000175000017500000000230012470405660022761 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \class Tp::AccountCapabilityFilter * \ingroup utils * \headerfile TelepathyQt/account-capability-filter.h * * \brief The AccountCapabilityFilter class provides a filter object to be used * to filter accounts by capabilities. */ telepathy-qt-0.9.6~git1/TelepathyQt/async-model.dox0000664000175000017500000000555512470405660020155 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \page async_model Asynchronous Object Model * * \section async_model_overview Overview * * Telepathy-Qt uses \dbus to communicate with applications implementing the \telepathy_spec. * * When dealing with D-Bus, method calls can take some time to return, * and in this case is not desirable to make synchronous calls, * which could turn into applications hanging waiting for method returns. * In order to avoid this issue, all Telepathy-Qt high-level methods requiring * D-Bus method calls will return a \link Tp::PendingOperation \endlink which will * emit the signal \link Tp::PendingOperation::finished() \endlink when the operation * has ended. See individual methods' documentation for more details. * * Additionally Telepathy-Qt introduces a concept in which object features need * to be enabled before usage. Information corresponding to enabled features can be inspected * synchronously with no need for asynchronous D-Bus method calls and the associated * programming complexity. * * To avoid the complexity of doing asynchronous calls when making object features ready * Telepathy-Qt also provides so called factories for the main objects. * These object features can be enabled by constructing a corresponding factory and enabling the * desired features, and passing these factories to the objects responsible for creating * the objects whose features are required. * Doing that, applications are guaranteed that the specified features are ready in objects * signaled to them by the library. * * However, if a particular feature is only ever used in a specific circumstance, such as an user * opening some settings dialog separate from the general view of the application, * features can be later enabled as needed by calling becomeReady(), or in the * \link Tp::Contact \endlink case by calling \link Tp::ContactManager::upgradeContacts() \endlink, * with the additional features on the object, and waiting for the resulting PendingOperation to * finish. */ telepathy-qt-0.9.6~git1/TelepathyQt/AccountManager0000664000175000017500000000037112470405660020027 0ustar jrjr#ifndef _TelepathyQt_AccountManager_HEADER_GUARD_ #define _TelepathyQt_AccountManager_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceSimplePresenceInterface0000664000175000017500000000045412470405660025542 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceSimplePresenceInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceSimplePresenceInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ProtocolInfoList0000664000175000017500000000037312470405660020413 0ustar jrjr#ifndef _TelepathyQt_ProtocolInfoList_HEADER_GUARD_ #define _TelepathyQt_ProtocolInfoList_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/outgoing-stream-tube-channel.h0000664000175000017500000000613712470405660023063 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_outgoing_stream_tube_channel_h_HEADER_GUARD_ #define _TelepathyQt_outgoing_stream_tube_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include class QHostAddress; class QTcpServer; class QLocalServer; namespace Tp { class TP_QT_EXPORT OutgoingStreamTubeChannel : public StreamTubeChannel { Q_OBJECT Q_DISABLE_COPY(OutgoingStreamTubeChannel) public: static const Feature FeatureCore; static OutgoingStreamTubeChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~OutgoingStreamTubeChannel(); PendingOperation *offerTcpSocket(const QHostAddress &address, quint16 port, const QVariantMap ¶meters = QVariantMap()); PendingOperation *offerTcpSocket(const QTcpServer *server, const QVariantMap ¶meters = QVariantMap()); PendingOperation *offerUnixSocket(const QString &socketAddress, const QVariantMap ¶meters = QVariantMap(), bool requireCredentials = false); PendingOperation *offerUnixSocket(const QLocalServer *server, const QVariantMap ¶meters = QVariantMap(), bool requireCredentials = false); QHash contactsForConnections() const; QHash, uint> connectionsForSourceAddresses() const; QHash connectionsForCredentials() const; protected: OutgoingStreamTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = OutgoingStreamTubeChannel::FeatureCore); private Q_SLOTS: TP_QT_NO_EXPORT void onNewRemoteConnection(uint contactId, const QDBusVariant ¶meter, uint connectionId); TP_QT_NO_EXPORT void onContactsRetrieved(const QUuid &uuid, const QList &contacts); TP_QT_NO_EXPORT void onConnectionClosed(uint connectionId, const QString &errorName, const QString &errorMessage); private: struct Private; friend struct PendingOpenTube; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/DBusService0000664000175000017500000000036012470405660017314 0ustar jrjr#ifndef _TelepathyQt_DBusService_HEADER_GUARD_ #define _TelepathyQt_DBusService_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/object.cpp0000664000175000017500000000320312470405660017164 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/object.moc.hpp" namespace Tp { /** * \class Object * \ingroup clientobject * \headerfile TelepathyQt/object.h * * \brief The Object class provides an object with property notification. */ /** * Construct a new Object object. */ Object::Object() : QObject() { } /** * Class destructor. */ Object::~Object() { } /** * Notify that a property named \a propertyName changed. * * This method will emit propertyChanged() for \a propertyName. * * \todo Use for more classes beyond Account. Most importantly Contact. */ void Object::notify(const char *propertyName) { emit propertyChanged(QLatin1String(propertyName)); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/connection.xml0000664000175000017500000000312612470405660020077 0ustar jrjr Connection interfaces telepathy-qt-0.9.6~git1/TelepathyQt/outgoing-stream-tube-channel-internal.h0000664000175000017500000000650512470405660024674 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_outgoing_stream_tube_channel_internal_h_HEADER_GUARD_ #define _TelepathyQt_outgoing_stream_tube_channel_internal_h_HEADER_GUARD_ #include #include namespace Tp { class PendingVoid; class TP_QT_NO_EXPORT PendingOpenTube : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingOpenTube) public: PendingOpenTube(PendingVoid *offerOperation, const QVariantMap ¶meters, const OutgoingStreamTubeChannelPtr &object); ~PendingOpenTube(); private Q_SLOTS: void onTubeStateChanged(Tp::TubeChannelState state); void onOfferFinished(Tp::PendingOperation *operation); private: struct Private; friend struct Private; Private *mPriv; }; class TP_QT_NO_EXPORT QueuedContactFactory : public QObject { Q_OBJECT Q_DISABLE_COPY(QueuedContactFactory) public: QueuedContactFactory(ContactManagerPtr contactManager, QObject* parent = 0); ~QueuedContactFactory(); QUuid appendNewRequest(const UIntList &handles); Q_SIGNALS: void contactsRetrieved(QUuid uuid, QList contacts); void queueCompleted(); private Q_SLOTS: void onPendingContactsFinished(Tp::PendingOperation *operation); void processNextRequest(); private: struct Entry { QUuid uuid; UIntList handles; }; bool m_isProcessing; ContactManagerPtr m_manager; QQueue m_queue; }; struct TP_QT_NO_EXPORT PendingOpenTube::Private { Private(const QVariantMap ¶meters, PendingOpenTube *parent); // Public object PendingOpenTube *parent; OutgoingStreamTubeChannelPtr tube; QVariantMap parameters; }; struct TP_QT_NO_EXPORT OutgoingStreamTubeChannel::Private { Private(OutgoingStreamTubeChannel *parent); OutgoingStreamTubeChannel *parent; QHash contactsForConnections; QHash, uint> connectionsForSourceAddresses; QHash connectionsForCredentials; QHash > pendingNewConnections; struct ClosedConnection { uint id; QString error, message; ClosedConnection() : id(~0U) {} ClosedConnection(uint id, const QString &error, const QString &message) : id(id), error(error), message(message) {} }; QHash pendingClosedConnections; QueuedContactFactory *queuedContactFactory; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/room-list-channel.h0000664000175000017500000000333012470405660020717 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_room_list_channel_h_HEADER_GUARD_ #define _TelepathyQt_room_list_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class TP_QT_EXPORT RoomListChannel : public Channel { Q_OBJECT Q_DISABLE_COPY(RoomListChannel) public: static RoomListChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~RoomListChannel(); protected: RoomListChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = Channel::FeatureCore); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/BaseProtocolPresenceInterface0000664000175000017500000000042512470405660023042 0ustar jrjr#ifndef _TelepathyQt_BaseProtocolPresenceInterface_HEADER_GUARD_ #define _TelepathyQt_BaseProtocolPresenceInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/captcha-authentication.h0000664000175000017500000000605612470405660022014 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_captcha_authentication_h_HEADER_GUARD_ #define _TelepathyQt_captcha_authentication_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include namespace Tp { class PendingCaptchaAnswer; class PendingCaptchaCancel; class PendingCaptchas; class TP_QT_EXPORT CaptchaAuthentication : public Tp::Object { Q_OBJECT Q_DISABLE_COPY(CaptchaAuthentication) public: enum ChallengeType { NoChallenge = 0, OCRChallenge = 1, AudioRecognitionChallenge = 2, PictureQuestionChallenge = 4, PictureRecognitionChallenge = 8, TextQuestionChallenge = 16, SpeechQuestionChallenge = 32, SpeechRecognitionChallenge = 64, VideoQuestionChallenge = 128, VideoRecognitionChallenge = 256, UnknownChallenge = 32768 }; Q_DECLARE_FLAGS(ChallengeTypes, ChallengeType) virtual ~CaptchaAuthentication(); ChannelPtr channel() const; bool canRetry() const; Tp::CaptchaStatus status() const; QString error() const; Connection::ErrorDetails errorDetails() const; Tp::PendingCaptchas *requestCaptchas(const QStringList &preferredMimeTypes = QStringList(), ChallengeTypes preferredTypes = ~ChallengeTypes(NoChallenge)); Tp::PendingOperation *answer(uint id, const QString &answer); Tp::PendingOperation *answer(const Tp::CaptchaAnswers &response); Q_SIGNALS: void statusChanged(Tp::CaptchaStatus status); public Q_SLOTS: Tp::PendingOperation *cancel(Tp::CaptchaCancelReason reason, const QString &message = QString()); private Q_SLOTS: TP_QT_NO_EXPORT void onPropertiesChanged(const QVariantMap &changedProperties, const QStringList &invalidatedProperties); private: TP_QT_NO_EXPORT CaptchaAuthentication(const ChannelPtr &parent); friend class ServerAuthenticationChannel; struct Private; friend struct Private; Private *mPriv; }; } // namespace Tp Q_DECLARE_OPERATORS_FOR_FLAGS(Tp::CaptchaAuthentication::ChallengeTypes) #endif telepathy-qt-0.9.6~git1/TelepathyQt/connection-capabilities.cpp0000664000175000017500000002251512470405660022513 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include namespace Tp { /** * \class ConnectionCapabilities * \ingroup clientconn * \headerfile TelepathyQt/connection-capabilities.h * * \brief The ConnectionCapabilities class represents the capabilities of a * Connection. */ /** * Construct a new ConnectionCapabilities object. */ ConnectionCapabilities::ConnectionCapabilities() : CapabilitiesBase() { } /** * Construct a new ConnectionCapabilities object using the give \a rccs. * * \param rccs RequestableChannelClassList representing the capabilities of a * Connection. */ ConnectionCapabilities::ConnectionCapabilities(const RequestableChannelClassList &rccs) : CapabilitiesBase(rccs, false) { } /** * Construct a new ConnectionCapabilities object using the give \a rccSpecs. * * \param rccSpecs RequestableChannelClassSpecList representing the capabilities of a * Connection. */ ConnectionCapabilities::ConnectionCapabilities(const RequestableChannelClassSpecList &rccSpecs) : CapabilitiesBase(rccSpecs, false) { } /** * Class destructor. */ ConnectionCapabilities::~ConnectionCapabilities() { } /** * Return true if named text chatrooms can be joined by providing a * chatroom identifier. * * If the protocol is such that chatrooms can be joined, but only via * a more elaborate D-Bus API than normal (because more information is needed), * then this method will return false. * * \return \c true if Account::ensureTextChatroom() can be expected to work. */ bool ConnectionCapabilities::textChatrooms() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::textChatroom())) { return true; } } return false; } /** * Return whether creating conference media calls is supported. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::conferenceStreamedMediaCalls() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::conferenceStreamedMediaCall())) { return true; } } return false; } /** * Return whether creating conference media calls is supported. * * This method will also check whether inviting new contacts when creating a conference media call * channel by providing additional members to initial invitees (as opposed to merging several * channels into one new conference channel) is supported. * * If providing additional members is supported, it is also possible to request conference media * calls with fewer than two (even zero) already established media calls. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::conferenceStreamedMediaCallsWithInvitees() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::conferenceStreamedMediaCallWithInvitees())) { return true; } } return false; } /** * Return whether creating conference text chats is supported. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::conferenceTextChats() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::conferenceTextChat())) { return true; } } return false; } /** * Return whether creating conference text chats is supported. * * This method will also check whether inviting new contacts when creating a conference text chat * channel by providing additional members to initial invitees (as opposed to merging several * channels into one new conference channel) is supported. * * If providing additional members is supported, it is also possible to request conference text * chats with fewer than two (even zero) already established text chats. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::conferenceTextChatsWithInvitees() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::conferenceTextChatWithInvitees())) { return true; } } return false; } /** * Return whether creating conference text chat rooms is supported. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::conferenceTextChatrooms() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::conferenceTextChatroom())) { return true; } } return false; } /** * Return whether creating conference text chat rooms is supported. * * This method will also check whether inviting new contacts when creating a conference text chat * room channel by providing additional members to initial invitees (as opposed to merging several * channels into one new conference channel) is supported. * * If providing additional members is supported, it is also possible to request conference text * chat rooms with fewer than two (even zero) already established text chat rooms. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::conferenceTextChatroomsWithInvitees() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::conferenceTextChatroomWithInvitees())) { return true; } } return false; } /** * Return whether creating a ContactSearch channel is supported. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::contactSearches() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::contactSearch())) { return true; } } return false; } /** * Return whether creating a ContactSearch channel specifying a server is supported. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::contactSearchesWithSpecificServer() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::contactSearchWithSpecificServer())) { return true; } } return false; } /** * Return whether creating a ContactSearch channel specifying a limit is supported. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::contactSearchesWithLimit() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::contactSearchWithLimit())) { return true; } } return false; } /** * Return whether creating a DBusTube channel by providing a contact identifier is supported. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::dbusTubes() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::dbusTube())) { return true; } } return false; } /** * Return whether creating a StreamTube channel by providing a contact identifier is supported. * * \return \c true if supported, \c false otherwise. */ bool ConnectionCapabilities::streamTubes() const { RequestableChannelClassSpecList rccSpecs = allClassSpecs(); foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) { if (rccSpec.supports(RequestableChannelClassSpec::streamTube())) { return true; } } return false; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/AbstractDBusServiceInterface0000664000175000017500000000042212470405660022620 0ustar jrjr#ifndef _TelepathyQt_AbstractDBusServiceInterface_HEADER_GUARD_ #define _TelepathyQt_AbstractDBusServiceInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-variant.cpp0000664000175000017500000000474612470405660021021 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-variant.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingVariant::Private { QVariant result; }; /** * \class PendingVariant * \ingroup utils * \headerfile TelepathyQt/pending-variant.h * * \brief The PendingVariant class is a generic subclass of PendingOperation * representing a pending D-Bus method call that returns a variant. * * See \ref async_model */ PendingVariant::PendingVariant(QDBusPendingCall call, const SharedPtr &object) : PendingOperation(object), mPriv(new Private) { connect(new QDBusPendingCallWatcher(call), SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(watcherFinished(QDBusPendingCallWatcher*))); } /** * Class destructor. */ PendingVariant::~PendingVariant() { delete mPriv; } QVariant PendingVariant::result() const { return mPriv->result; } void PendingVariant::watcherFinished(QDBusPendingCallWatcher* watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got reply to PendingVariant call"; mPriv->result = reply.value().variant(); setFinished(); } else { debug().nospace() << "PendingVariant call failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/StreamTubeServer0000664000175000017500000000040012470405660020373 0ustar jrjr#ifndef _TelepathyQt_StreamTubeServer_HEADER_GUARD_ #define _TelepathyQt_StreamTubeServer_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/svc-call.xml0000664000175000017500000000052512470405660017444 0ustar jrjr Call interfaces telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeTubeInterface0000664000175000017500000000042312470405660022011 0ustar jrjr#ifndef _TelepathyQt_Client_ChannelTypeTubeInterface_HEADER_GUARD_ #define _TelepathyQt_Client_ChannelTypeTubeInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/properties.xml0000664000175000017500000000037512470405660020137 0ustar jrjr The Telepathy properties interface telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfacePowerSavingInterface0000664000175000017500000000044612470405660025071 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfacePowerSavingInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfacePowerSavingInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/base-connection.cpp0000664000175000017500000022226412470405660020777 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/base-connection-internal.h" #include "TelepathyQt/_gen/base-connection.moc.hpp" #include "TelepathyQt/_gen/base-connection-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT BaseConnection::Private { Private(BaseConnection *parent, const QDBusConnection &dbusConnection, const QString &cmName, const QString &protocolName, const QVariantMap ¶meters) : parent(parent), cmName(cmName), protocolName(protocolName), parameters(parameters), status(Tp::ConnectionStatusDisconnected), selfHandle(0), adaptee(new BaseConnection::Adaptee(dbusConnection, parent)) { } BaseConnection *parent; QString cmName; QString protocolName; QVariantMap parameters; uint status; QHash interfaces; QSet channels; CreateChannelCallback createChannelCB; RequestHandlesCallback requestHandlesCB; ConnectCallback connectCB; InspectHandlesCallback inspectHandlesCB; uint selfHandle; BaseConnection::Adaptee *adaptee; }; BaseConnection::Adaptee::Adaptee(const QDBusConnection &dbusConnection, BaseConnection *connection) : QObject(connection), mConnection(connection) { mAdaptor = new Service::ConnectionAdaptor(dbusConnection, this, connection->dbusObject()); } BaseConnection::Adaptee::~Adaptee() { } void BaseConnection::Adaptee::disconnect(const Tp::Service::ConnectionAdaptor::DisconnectContextPtr &context) { debug() << "BaseConnection::Adaptee::disconnect"; /* This will remove the connection from the connection manager * and destroy this object. */ emit mConnection->disconnected(); context->setFinished(); } void BaseConnection::Adaptee::getSelfHandle(const Tp::Service::ConnectionAdaptor::GetSelfHandleContextPtr &context) { context->setFinished(mConnection->mPriv->selfHandle); } uint BaseConnection::Adaptee::selfHandle() const { return mConnection->mPriv->selfHandle; } void BaseConnection::Adaptee::getStatus(const Tp::Service::ConnectionAdaptor::GetStatusContextPtr &context) { context->setFinished(mConnection->status()); } void BaseConnection::Adaptee::connect(const Tp::Service::ConnectionAdaptor::ConnectContextPtr &context) { if (!mConnection->mPriv->connectCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mConnection->mPriv->connectCB(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseConnection::Adaptee::inspectHandles(uint handleType, const Tp::UIntList &handles, const Tp::Service::ConnectionAdaptor::InspectHandlesContextPtr &context) { if (!mConnection->mPriv->inspectHandlesCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; QStringList ret = mConnection->mPriv->inspectHandlesCB(handleType, handles, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(ret); } QStringList BaseConnection::Adaptee::interfaces() const { QStringList ret; foreach(const AbstractConnectionInterfacePtr & iface, mConnection->interfaces()) { ret << iface->interfaceName(); } return ret; } void BaseConnection::Adaptee::requestChannel(const QString &type, uint handleType, uint handle, bool suppressHandler, const Tp::Service::ConnectionAdaptor::RequestChannelContextPtr &context) { debug() << "BaseConnection::Adaptee::requestChannel (deprecated)"; DBusError error; bool yours; BaseChannelPtr channel = mConnection->ensureChannel(type, handleType, handle, yours, selfHandle(), suppressHandler, QVariantMap(), &error); if (error.isValid() || !channel) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(QDBusObjectPath(channel->objectPath())); } void BaseConnection::Adaptee::requestHandles(uint handleType, const QStringList &identifiers, const Tp::Service::ConnectionAdaptor::RequestHandlesContextPtr &context) { DBusError error; Tp::UIntList handles = mConnection->requestHandles(handleType, identifiers, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(handles); } /** * \class BaseConnection * \ingroup serviceconn * \headerfile TelepathyQt/base-connection.h * * \brief Base class for Connection implementations. */ /** * Construct a BaseConnection. * * \param dbusConnection The D-Bus connection that will be used by this object. * \param cmName The name of the connection manager associated with this connection. * \param protocolName The name of the protocol associated with this connection. * \param parameters The parameters of this connection. */ BaseConnection::BaseConnection(const QDBusConnection &dbusConnection, const QString &cmName, const QString &protocolName, const QVariantMap ¶meters) : DBusService(dbusConnection), mPriv(new Private(this, dbusConnection, cmName, protocolName, parameters)) { } /** * Class destructor. */ BaseConnection::~BaseConnection() { foreach (BaseChannelPtr channel, mPriv->channels) { channel->close(); } delete mPriv; } /** * Return the name of the connection manager associated with this connection. * * \return The name of the connection manager associated with this connection. */ QString BaseConnection::cmName() const { return mPriv->cmName; } /** * Return the name of the protocol associated with this connection. * * \return The name of the protocol associated with this connection. */ QString BaseConnection::protocolName() const { return mPriv->protocolName; } /** * Return the parameters of this connection. * * \return The parameters of this connection. */ QVariantMap BaseConnection::parameters() const { return mPriv->parameters; } /** * Return the immutable properties of this connection object. * * Immutable properties cannot change after the object has been registered * on the bus with registerObject(). * * \return The immutable properties of this connection object. */ QVariantMap BaseConnection::immutableProperties() const { // FIXME return QVariantMap(); } /** * Return a unique name for this connection. * * \return A unique name for this connection. */ QString BaseConnection::uniqueName() const { return QString(QLatin1String("connection_%1")).arg((quintptr) this, 0, 16); } uint BaseConnection::status() const { debug() << "BaseConnection::status = " << mPriv->status << " " << this; return mPriv->status; } void BaseConnection::setStatus(uint newStatus, uint reason) { debug() << "BaseConnection::setStatus " << newStatus << " " << reason << " " << this; bool changed = (newStatus != mPriv->status); mPriv->status = newStatus; if (changed) QMetaObject::invokeMethod(mPriv->adaptee, "statusChanged", Q_ARG(uint, newStatus), Q_ARG(uint, reason)); //Can simply use emit in Qt5 } void BaseConnection::setCreateChannelCallback(const CreateChannelCallback &cb) { mPriv->createChannelCB = cb; } Tp::BaseChannelPtr BaseConnection::createChannel(const QString &channelType, uint targetHandleType, uint targetHandle, uint initiatorHandle, bool suppressHandler, const QVariantMap &request, DBusError *error) { if (!mPriv->createChannelCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return BaseChannelPtr(); } if (!mPriv->inspectHandlesCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return BaseChannelPtr(); } BaseChannelPtr channel = mPriv->createChannelCB(channelType, targetHandleType, targetHandle, request, error); if (error->isValid()) return BaseChannelPtr(); QString targetID; if (targetHandle != 0) { QStringList list = mPriv->inspectHandlesCB(targetHandleType, UIntList() << targetHandle, error); if (error->isValid()) { debug() << "BaseConnection::createChannel: could not resolve handle " << targetHandle; return BaseChannelPtr(); } else { debug() << "BaseConnection::createChannel: found targetID " << *list.begin(); targetID = *list.begin(); } } QString initiatorID; if (initiatorHandle != 0) { QStringList list = mPriv->inspectHandlesCB(HandleTypeContact, UIntList() << initiatorHandle, error); if (error->isValid()) { debug() << "BaseConnection::createChannel: could not resolve handle " << initiatorHandle; return BaseChannelPtr(); } else { debug() << "BaseConnection::createChannel: found initiatorID " << *list.begin(); initiatorID = *list.begin(); } } channel->setInitiatorHandle(initiatorHandle); channel->setInitiatorID(initiatorID); channel->setTargetID(targetID); channel->setRequested(initiatorHandle == mPriv->selfHandle); channel->registerObject(error); if (error->isValid()) return BaseChannelPtr(); mPriv->channels.insert(channel); BaseConnectionRequestsInterfacePtr reqIface = BaseConnectionRequestsInterfacePtr::dynamicCast(interface(TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS)); if (!reqIface.isNull()) //emit after return QMetaObject::invokeMethod(reqIface.data(), "newChannels", Qt::QueuedConnection, Q_ARG(Tp::ChannelDetailsList, ChannelDetailsList() << channel->details())); //emit after return QMetaObject::invokeMethod(mPriv->adaptee, "newChannel", Qt::QueuedConnection, Q_ARG(QDBusObjectPath, QDBusObjectPath(channel->objectPath())), Q_ARG(QString, channel->channelType()), Q_ARG(uint, channel->targetHandleType()), Q_ARG(uint, channel->targetHandle()), Q_ARG(bool, suppressHandler)); QObject::connect(channel.data(), SIGNAL(closed()), SLOT(removeChannel())); return channel; } void BaseConnection::setRequestHandlesCallback(const RequestHandlesCallback &cb) { mPriv->requestHandlesCB = cb; } UIntList BaseConnection::requestHandles(uint handleType, const QStringList &identifiers, DBusError* error) { if (!mPriv->requestHandlesCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return UIntList(); } return mPriv->requestHandlesCB(handleType, identifiers, error); } Tp::ChannelInfoList BaseConnection::channelsInfo() { qDebug() << "BaseConnection::channelsInfo:"; Tp::ChannelInfoList list; foreach(const BaseChannelPtr & c, mPriv->channels) { Tp::ChannelInfo info; info.channel = QDBusObjectPath(c->objectPath()); info.channelType = c->channelType(); info.handle = c->targetHandle(); info.handleType = c->targetHandleType(); qDebug() << "BaseConnection::channelsInfo " << info.channel.path(); list << info; } return list; } Tp::ChannelDetailsList BaseConnection::channelsDetails() { Tp::ChannelDetailsList list; foreach(const BaseChannelPtr & c, mPriv->channels) list << c->details(); return list; } BaseChannelPtr BaseConnection::ensureChannel(const QString &channelType, uint targetHandleType, uint targetHandle, bool &yours, uint initiatorHandle, bool suppressHandler, const QVariantMap &request, DBusError* error) { foreach(BaseChannelPtr channel, mPriv->channels) { if (channel->channelType() == channelType && channel->targetHandleType() == targetHandleType && channel->targetHandle() == targetHandle) { yours = false; return channel; } } yours = true; return createChannel(channelType, targetHandleType, targetHandle, initiatorHandle, suppressHandler, request, error); } void BaseConnection::addChannel(BaseChannelPtr channel) { if (mPriv->channels.contains(channel)) { qDebug() << "BaseConnection::addChannel: Channel already added."; return; } mPriv->channels.insert(channel); BaseConnectionRequestsInterfacePtr reqIface = BaseConnectionRequestsInterfacePtr::dynamicCast(interface(TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS)); if (!reqIface.isNull()) { //emit after return QMetaObject::invokeMethod(reqIface.data(), "newChannels", Qt::QueuedConnection, Q_ARG(Tp::ChannelDetailsList, ChannelDetailsList() << channel->details())); } //emit after return QMetaObject::invokeMethod(mPriv->adaptee, "newChannel", Qt::QueuedConnection, Q_ARG(QDBusObjectPath, QDBusObjectPath(channel->objectPath())), Q_ARG(QString, channel->channelType()), Q_ARG(uint, channel->targetHandleType()), Q_ARG(uint, channel->targetHandle()), Q_ARG(bool, false)); QObject::connect(channel.data(), SIGNAL(closed()), SLOT(removeChannel())); } void BaseConnection::removeChannel() { BaseChannelPtr channel = BaseChannelPtr( qobject_cast(sender())); Q_ASSERT(channel); Q_ASSERT(mPriv->channels.contains(channel)); BaseConnectionRequestsInterfacePtr reqIface = BaseConnectionRequestsInterfacePtr::dynamicCast(interface(TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS)); if (!reqIface.isNull()) { reqIface->channelClosed(QDBusObjectPath(channel->objectPath())); } mPriv->channels.remove(channel); } /** * Return a list of interfaces that have been plugged into this Protocol * D-Bus object with plugInterface(). * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \return A list containing all the Protocol interface implementation objects. * \sa plugInterface(), interface() */ QList BaseConnection::interfaces() const { return mPriv->interfaces.values(); } /** * Return a pointer to the interface with the given name. * * \param interfaceName The D-Bus name of the interface, * ex. TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING. * \return A pointer to the AbstractConnectionInterface object that implements * the D-Bus interface with the given name, or a null pointer if such an interface * has not been plugged into this object. * \sa plugInterface(), interfaces() */ AbstractConnectionInterfacePtr BaseConnection::interface(const QString &interfaceName) const { return mPriv->interfaces.value(interfaceName); } /** * Plug a new interface into this Connection D-Bus object. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param interface An AbstractConnectionInterface instance that implements * the interface that is to be plugged. * \return \c true on success or \c false otherwise * \sa interfaces(), interface() */ bool BaseConnection::plugInterface(const AbstractConnectionInterfacePtr &interface) { if (isRegistered()) { warning() << "Unable to plug protocol interface " << interface->interfaceName() << "- protocol already registered"; return false; } if (interface->isRegistered()) { warning() << "Unable to plug protocol interface" << interface->interfaceName() << "- interface already registered"; return false; } if (mPriv->interfaces.contains(interface->interfaceName())) { warning() << "Unable to plug protocol interface" << interface->interfaceName() << "- another interface with same name already plugged"; return false; } debug() << "Interface" << interface->interfaceName() << "plugged"; mPriv->interfaces.insert(interface->interfaceName(), interface); return true; } /** * Register this connection object on the bus. * * If \a error is passed, any D-Bus error that may occur will * be stored there. * * \param error A pointer to an empty DBusError where any * possible D-Bus error will be stored. * \return \c true on success and \c false if there was an error * or this connection object is already registered. * \sa isRegistered() */ bool BaseConnection::registerObject(DBusError *error) { if (isRegistered()) { return true; } if (!checkValidProtocolName(mPriv->protocolName)) { if (error) { error->set(TP_QT_ERROR_INVALID_ARGUMENT, mPriv->protocolName + QLatin1String("is not a valid protocol name")); } debug() << "Unable to register connection - invalid protocol name"; return false; } QString escapedProtocolName = mPriv->protocolName; escapedProtocolName.replace(QLatin1Char('-'), QLatin1Char('_')); QString name = uniqueName(); debug() << "cmName: " << mPriv->cmName << " escapedProtocolName: " << escapedProtocolName << " name:" << name; QString busName = QString(QLatin1String("%1%2.%3.%4")) .arg(TP_QT_CONNECTION_BUS_NAME_BASE, mPriv->cmName, escapedProtocolName, name); QString objectPath = QString(QLatin1String("%1%2/%3/%4")) .arg(TP_QT_CONNECTION_OBJECT_PATH_BASE, mPriv->cmName, escapedProtocolName, name); debug() << "busName: " << busName << " objectName: " << objectPath; DBusError _error; debug() << "Connection: registering interfaces at " << dbusObject(); foreach(const AbstractConnectionInterfacePtr & iface, mPriv->interfaces) { if (!iface->registerInterface(dbusObject())) { // lets not fail if an optional interface fails registering, lets warn only warning() << "Unable to register interface" << iface->interfaceName(); } } bool ret = registerObject(busName, objectPath, &_error); if (!ret && error) { error->set(_error.name(), _error.message()); } return ret; } /** * Reimplemented from DBusService. */ bool BaseConnection::registerObject(const QString &busName, const QString &objectPath, DBusError *error) { return DBusService::registerObject(busName, objectPath, error); } void BaseConnection::setSelfHandle(uint selfHandle) { bool changed = (selfHandle != mPriv->selfHandle); mPriv->selfHandle = selfHandle; if (changed) QMetaObject::invokeMethod(mPriv->adaptee, "selfHandleChanged", Q_ARG(uint, selfHandle)); } uint BaseConnection::selfHandle() const { return mPriv->selfHandle; } void BaseConnection::setConnectCallback(const ConnectCallback &cb) { mPriv->connectCB = cb; } void BaseConnection::setInspectHandlesCallback(const InspectHandlesCallback &cb) { mPriv->inspectHandlesCB = cb; } /** * \fn void BaseConnection::disconnected() * * Emitted when this connection has been disconnected. */ /** * \class AbstractConnectionInterface * \ingroup servicecm * \headerfile TelepathyQt/base-connection.h * * \brief Base class for all the Connection object interface implementations. */ AbstractConnectionInterface::AbstractConnectionInterface(const QString &interfaceName) : AbstractDBusServiceInterface(interfaceName) { } AbstractConnectionInterface::~AbstractConnectionInterface() { } // Conn.I.Requests BaseConnectionRequestsInterface::Adaptee::Adaptee(BaseConnectionRequestsInterface *interface) : QObject(interface), mInterface(interface) { } BaseConnectionRequestsInterface::Adaptee::~Adaptee() { } void BaseConnectionRequestsInterface::Adaptee::ensureChannel(const QVariantMap &request, const Tp::Service::ConnectionInterfaceRequestsAdaptor::EnsureChannelContextPtr &context) { DBusError error; bool yours; QDBusObjectPath channel; QVariantMap details; mInterface->ensureChannel(request, yours, channel, details, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(yours, channel, details); } void BaseConnectionRequestsInterface::Adaptee::createChannel(const QVariantMap &request, const Tp::Service::ConnectionInterfaceRequestsAdaptor::CreateChannelContextPtr &context) { DBusError error; QDBusObjectPath channel; QVariantMap details; mInterface->createChannel(request, channel, details, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(channel, details); } struct TP_QT_NO_EXPORT BaseConnectionRequestsInterface::Private { Private(BaseConnectionRequestsInterface *parent, BaseConnection *connection_) : connection(connection_), adaptee(new BaseConnectionRequestsInterface::Adaptee(parent)) { } BaseConnection *connection; BaseConnectionRequestsInterface::Adaptee *adaptee; }; /** * \class BaseConnectionRequestsInterface * \ingroup servicecm * \headerfile TelepathyQt/base-connection.h * * \brief Base class for implementations of Connection.Interface.Requests */ /** * Class constructor. */ BaseConnectionRequestsInterface::BaseConnectionRequestsInterface(BaseConnection *connection) : AbstractConnectionInterface(TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS), mPriv(new Private(this, connection)) { } /** * Class destructor. */ BaseConnectionRequestsInterface::~BaseConnectionRequestsInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseConnectionRequestsInterface::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS + QLatin1String(".RequestableChannelClasses"), QVariant::fromValue(mPriv->adaptee->requestableChannelClasses())); return map; } void BaseConnectionRequestsInterface::createAdaptor() { (void) new Service::ConnectionInterfaceRequestsAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } Tp::ChannelDetailsList BaseConnectionRequestsInterface::Adaptee::channels() const { return mInterface->mPriv->connection->channelsDetails(); } void BaseConnectionRequestsInterface::newChannels(const Tp::ChannelDetailsList &channels) { QMetaObject::invokeMethod(mPriv->adaptee,"newChannels", Q_ARG(Tp::ChannelDetailsList,channels)); //Can replace by a direct call in Qt5 } void BaseConnectionRequestsInterface::channelClosed(const QDBusObjectPath &removed) { QMetaObject::invokeMethod(mPriv->adaptee,"channelClosed", Q_ARG(QDBusObjectPath, removed)); //Can replace by a direct call in Qt5 } void BaseConnectionRequestsInterface::ensureChannel(const QVariantMap &request, bool &yours, QDBusObjectPath &objectPath, QVariantMap &details, DBusError *error) { if (!request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")) || !request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")) || (!request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")) && !request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")))) { error->set(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Missing parameters")); return; } QString channelType = request[TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")].toString(); uint targetHandleType = request[TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")].toUInt(); uint targetHandle; if (request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"))) targetHandle = request[TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")].toUInt(); else { QString targetID = request[TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")].toString(); Tp::UIntList list = mPriv->connection->requestHandles(targetHandleType, QStringList() << targetID, error); if (error->isValid()) { warning() << "BBaseConnectionRequestsInterface::ensureChannel: could not resolve ID " << targetID; return; } targetHandle = *list.begin(); } bool suppressHandler = true; BaseChannelPtr channel = mPriv->connection->ensureChannel(channelType, targetHandleType, targetHandle, yours, mPriv->connection->selfHandle(), suppressHandler, request, error); if (error->isValid()) return; objectPath = QDBusObjectPath(channel->objectPath()); details = channel->details().properties; } void BaseConnectionRequestsInterface::createChannel(const QVariantMap &request, QDBusObjectPath &objectPath, QVariantMap &details, DBusError *error) { if (!request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")) || !request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")) || !request.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"))) { error->set(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Missing parameters")); return; } QString channelType = request[TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")].toString(); uint targetHandleType = request[TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")].toUInt(); uint targetHandle = request[TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")].toUInt(); bool suppressHandler = true; BaseChannelPtr channel = mPriv->connection->createChannel(channelType, targetHandleType, targetHandle, mPriv->connection->selfHandle(), suppressHandler, request, error); if (error->isValid()) return; objectPath = QDBusObjectPath(channel->objectPath()); details = channel->details().properties; } // Conn.I.Contacts BaseConnectionContactsInterface::Adaptee::Adaptee(BaseConnectionContactsInterface *interface) : QObject(interface), mInterface(interface) { } BaseConnectionContactsInterface::Adaptee::~Adaptee() { } void BaseConnectionContactsInterface::Adaptee::getContactAttributes(const Tp::UIntList &handles, const QStringList &interfaces, bool /*hold*/, const Tp::Service::ConnectionInterfaceContactsAdaptor::GetContactAttributesContextPtr &context) { DBusError error; ContactAttributesMap contactAttributes = mInterface->getContactAttributes(handles, interfaces, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(contactAttributes); } struct TP_QT_NO_EXPORT BaseConnectionContactsInterface::Private { Private(BaseConnectionContactsInterface *parent) : adaptee(new BaseConnectionContactsInterface::Adaptee(parent)) { } QStringList contactAttributeInterfaces; GetContactAttributesCallback getContactAttributesCallback; BaseConnectionContactsInterface::Adaptee *adaptee; }; QStringList BaseConnectionContactsInterface::Adaptee::contactAttributeInterfaces() const { return mInterface->mPriv->contactAttributeInterfaces; } /** * \class BaseConnectionContactsInterface * \ingroup servicecm * \headerfile TelepathyQt/base-connection.h * * \brief Base class for implementations of Connection.Interface.Contacts */ /** * Class constructor. */ BaseConnectionContactsInterface::BaseConnectionContactsInterface() : AbstractConnectionInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS), mPriv(new Private(this)) { } /** * Class destructor. */ BaseConnectionContactsInterface::~BaseConnectionContactsInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseConnectionContactsInterface::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS + QLatin1String(".ContactAttributeInterfaces"), QVariant::fromValue(mPriv->adaptee->contactAttributeInterfaces())); return map; } void BaseConnectionContactsInterface::createAdaptor() { (void) new Service::ConnectionInterfaceContactsAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseConnectionContactsInterface::setContactAttributeInterfaces(const QStringList &contactAttributeInterfaces) { mPriv->contactAttributeInterfaces = contactAttributeInterfaces; } void BaseConnectionContactsInterface::setGetContactAttributesCallback(const GetContactAttributesCallback &cb) { mPriv->getContactAttributesCallback = cb; } ContactAttributesMap BaseConnectionContactsInterface::getContactAttributes(const Tp::UIntList &handles, const QStringList &interfaces, DBusError *error) { if (!mPriv->getContactAttributesCallback.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return ContactAttributesMap(); } return mPriv->getContactAttributesCallback(handles, interfaces, error); } // Conn.I.SimplePresence BaseConnectionSimplePresenceInterface::Adaptee::Adaptee(BaseConnectionSimplePresenceInterface *interface) : QObject(interface), mInterface(interface) { } BaseConnectionSimplePresenceInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseConnectionSimplePresenceInterface::Private { Private(BaseConnectionSimplePresenceInterface *parent) : maxmimumStatusMessageLength(0), adaptee(new BaseConnectionSimplePresenceInterface::Adaptee(parent)) { } SetPresenceCallback setPresenceCB; SimpleStatusSpecMap statuses; uint maxmimumStatusMessageLength; /* The current presences */ SimpleContactPresences presences; BaseConnectionSimplePresenceInterface::Adaptee *adaptee; }; /** * \class BaseConnectionSimplePresenceInterface * \ingroup servicecm * \headerfile TelepathyQt/base-connection.h * * \brief Base class for implementations of Connection.Interface.SimplePresence */ /** * Class constructor. */ BaseConnectionSimplePresenceInterface::BaseConnectionSimplePresenceInterface() : AbstractConnectionInterface(TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE), mPriv(new Private(this)) { } /** * Class destructor. */ BaseConnectionSimplePresenceInterface::~BaseConnectionSimplePresenceInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseConnectionSimplePresenceInterface::immutableProperties() const { QVariantMap map; //FIXME return map; } void BaseConnectionSimplePresenceInterface::createAdaptor() { (void) new Service::ConnectionInterfaceSimplePresenceAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseConnectionSimplePresenceInterface::setPresences(const Tp::SimpleContactPresences &presences) { foreach(uint handle, presences.keys()) { mPriv->presences[handle] = presences[handle]; } QMetaObject::invokeMethod(mPriv->adaptee, "presencesChanged", Q_ARG(Tp::SimpleContactPresences, presences)); //Can simply use emit in Qt5 } void BaseConnectionSimplePresenceInterface::setSetPresenceCallback(const SetPresenceCallback &cb) { mPriv->setPresenceCB = cb; } Tp::SimpleStatusSpecMap BaseConnectionSimplePresenceInterface::statuses() const { return mPriv->statuses; } void BaseConnectionSimplePresenceInterface::setStatuses(const SimpleStatusSpecMap &statuses) { mPriv->statuses = statuses; } int BaseConnectionSimplePresenceInterface::maximumStatusMessageLength() const { return mPriv->maxmimumStatusMessageLength; } void BaseConnectionSimplePresenceInterface::setMaxmimumStatusMessageLength(uint maxmimumStatusMessageLength) { mPriv->maxmimumStatusMessageLength = maxmimumStatusMessageLength; } Tp::SimpleStatusSpecMap BaseConnectionSimplePresenceInterface::Adaptee::statuses() const { return mInterface->mPriv->statuses; } int BaseConnectionSimplePresenceInterface::Adaptee::maximumStatusMessageLength() const { return mInterface->mPriv->maxmimumStatusMessageLength; } void BaseConnectionSimplePresenceInterface::Adaptee::setPresence(const QString &status, const QString &statusMessage_, const Tp::Service::ConnectionInterfaceSimplePresenceAdaptor::SetPresenceContextPtr &context) { if (!mInterface->mPriv->setPresenceCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } SimpleStatusSpecMap::Iterator i = mInterface->mPriv->statuses.find(status); if (i == mInterface->mPriv->statuses.end()) { warning() << "BaseConnectionSimplePresenceInterface::Adaptee::setPresence: status is not in statuses"; context->setFinishedWithError(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("status not in statuses")); return; } QString statusMessage = statusMessage_; if ((uint)statusMessage.length() > mInterface->mPriv->maxmimumStatusMessageLength) { debug() << "BaseConnectionSimplePresenceInterface::Adaptee::setPresence: " << "truncating status to " << mInterface->mPriv->maxmimumStatusMessageLength; statusMessage = statusMessage.left(mInterface->mPriv->maxmimumStatusMessageLength); } DBusError error; uint selfHandle = mInterface->mPriv->setPresenceCB(status, statusMessage, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } Tp::SimplePresence presence; presence.type = i->type; presence.status = status; presence.statusMessage = statusMessage; mInterface->mPriv->presences[selfHandle] = presence; /* Emit PresencesChanged */ SimpleContactPresences presences; presences[selfHandle] = presence; //emit after return QMetaObject::invokeMethod(mInterface->mPriv->adaptee, "presencesChanged", Qt::QueuedConnection, Q_ARG(Tp::SimpleContactPresences, presences)); context->setFinished(); } void BaseConnectionSimplePresenceInterface::Adaptee::getPresences(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceSimplePresenceAdaptor::GetPresencesContextPtr &context) { Tp::SimpleContactPresences presences; foreach(uint handle, contacts) { SimpleContactPresences::iterator i = mInterface->mPriv->presences.find(handle); if (i == mInterface->mPriv->presences.end()) { Tp::SimplePresence presence; presence.type = ConnectionPresenceTypeUnknown; presence.status = QLatin1String("unknown"); presences[handle] = presence; } else presences[handle] = *i; } context->setFinished(presences); } // Conn.I.ContactList struct TP_QT_NO_EXPORT BaseConnectionContactListInterface::Private { Private(BaseConnectionContactListInterface *parent) : contactListState(ContactListStateNone), contactListPersists(false), canChangeContactList(true), requestUsesMessage(false), downloadAtConnection(false), adaptee(new BaseConnectionContactListInterface::Adaptee(parent)) { } uint contactListState; bool contactListPersists; bool canChangeContactList; bool requestUsesMessage; bool downloadAtConnection; GetContactListAttributesCallback getContactListAttributesCB; RequestSubscriptionCallback requestSubscriptionCB; AuthorizePublicationCallback authorizePublicationCB; RemoveContactsCallback removeContactsCB; UnsubscribeCallback unsubscribeCB; UnpublishCallback unpublishCB; DownloadCallback downloadCB; BaseConnectionContactListInterface::Adaptee *adaptee; }; BaseConnectionContactListInterface::Adaptee::Adaptee(BaseConnectionContactListInterface *interface) : QObject(interface), mInterface(interface) { } BaseConnectionContactListInterface::Adaptee::~Adaptee() { } uint BaseConnectionContactListInterface::Adaptee::contactListState() const { return mInterface->contactListState(); } bool BaseConnectionContactListInterface::Adaptee::contactListPersists() const { return mInterface->contactListPersists(); } bool BaseConnectionContactListInterface::Adaptee::canChangeContactList() const { return mInterface->canChangeContactList(); } bool BaseConnectionContactListInterface::Adaptee::requestUsesMessage() const { return mInterface->requestUsesMessage(); } bool BaseConnectionContactListInterface::Adaptee::downloadAtConnection() const { return mInterface->downloadAtConnection(); } void BaseConnectionContactListInterface::Adaptee::getContactListAttributes(const QStringList &interfaces, bool hold, const Tp::Service::ConnectionInterfaceContactListAdaptor::GetContactListAttributesContextPtr &context) { qDebug() << "BaseConnectionContactListInterface::Adaptee::getContactListAttributes"; DBusError error; Tp::ContactAttributesMap attributes = mInterface->getContactListAttributes(interfaces, hold, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(attributes); } void BaseConnectionContactListInterface::Adaptee::requestSubscription(const Tp::UIntList &contacts, const QString &message, const Tp::Service::ConnectionInterfaceContactListAdaptor::RequestSubscriptionContextPtr &context) { qDebug() << "BaseConnectionContactListInterface::Adaptee::requestSubscription"; DBusError error; mInterface->requestSubscription(contacts, message, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseConnectionContactListInterface::Adaptee::authorizePublication(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactListAdaptor::AuthorizePublicationContextPtr &context) { qDebug() << "BaseConnectionContactListInterface::Adaptee::authorizePublication"; DBusError error; mInterface->authorizePublication(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseConnectionContactListInterface::Adaptee::removeContacts(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactListAdaptor::RemoveContactsContextPtr &context) { qDebug() << "BaseConnectionContactListInterface::Adaptee::removeContacts"; DBusError error; mInterface->removeContacts(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseConnectionContactListInterface::Adaptee::unsubscribe(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactListAdaptor::UnsubscribeContextPtr &context) { qDebug() << "BaseConnectionContactListInterface::Adaptee::unsubscribe"; DBusError error; mInterface->unsubscribe(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseConnectionContactListInterface::Adaptee::unpublish(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactListAdaptor::UnpublishContextPtr &context) { qDebug() << "BaseConnectionContactListInterface::Adaptee::unpublish"; DBusError error; mInterface->unpublish(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseConnectionContactListInterface::Adaptee::download( const Tp::Service::ConnectionInterfaceContactListAdaptor::DownloadContextPtr &context) { qDebug() << "BaseConnectionContactListInterface::Adaptee::download"; DBusError error; mInterface->download(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseConnectionContactListInterface * \ingroup servicecm * \headerfile TelepathyQt/base-connection.h * * \brief Base class for implementations of Connection.Interface.ContactList */ /** * Class constructor. */ BaseConnectionContactListInterface::BaseConnectionContactListInterface() : AbstractConnectionInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST), mPriv(new Private(this)) { } /** * Class destructor. */ BaseConnectionContactListInterface::~BaseConnectionContactListInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseConnectionContactListInterface::immutableProperties() const { QVariantMap map; return map; } uint BaseConnectionContactListInterface::contactListState() const { return mPriv->contactListState; } void BaseConnectionContactListInterface::setContactListState(uint contactListState) { if (mPriv->contactListState == contactListState) { return; } mPriv->contactListState = contactListState; QMetaObject::invokeMethod(mPriv->adaptee, "contactListStateChanged", Q_ARG(uint, contactListState)); //Can simply use emit in Qt5 } bool BaseConnectionContactListInterface::contactListPersists() const { return mPriv->contactListPersists; } void BaseConnectionContactListInterface::setContactListPersists(bool contactListPersists) { mPriv->contactListPersists = contactListPersists; } bool BaseConnectionContactListInterface::canChangeContactList() const { return mPriv->canChangeContactList; } void BaseConnectionContactListInterface::setCanChangeContactList(bool canChangeContactList) { mPriv->canChangeContactList = canChangeContactList; } bool BaseConnectionContactListInterface::requestUsesMessage() const { return mPriv->requestUsesMessage; } void BaseConnectionContactListInterface::setRequestUsesMessage(bool requestUsesMessage) { mPriv->requestUsesMessage = requestUsesMessage; } bool BaseConnectionContactListInterface::downloadAtConnection() const { return mPriv->downloadAtConnection; } void BaseConnectionContactListInterface::setDownloadAtConnection(bool downloadAtConnection) { mPriv->downloadAtConnection = downloadAtConnection; } void BaseConnectionContactListInterface::createAdaptor() { (void) new Service::ConnectionInterfaceContactListAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseConnectionContactListInterface::setGetContactListAttributesCallback(const BaseConnectionContactListInterface::GetContactListAttributesCallback &cb) { mPriv->getContactListAttributesCB = cb; } Tp::ContactAttributesMap BaseConnectionContactListInterface::getContactListAttributes(const QStringList &interfaces, bool hold, DBusError *error) { if (!mPriv->getContactListAttributesCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return Tp::ContactAttributesMap(); } return mPriv->getContactListAttributesCB(interfaces, hold, error); } void BaseConnectionContactListInterface::setRequestSubscriptionCallback(const BaseConnectionContactListInterface::RequestSubscriptionCallback &cb) { mPriv->requestSubscriptionCB = cb; } void BaseConnectionContactListInterface::requestSubscription(const Tp::UIntList &contacts, const QString &message, DBusError *error) { if (!mPriv->requestSubscriptionCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->requestSubscriptionCB(contacts, message, error); } void BaseConnectionContactListInterface::setAuthorizePublicationCallback(const BaseConnectionContactListInterface::AuthorizePublicationCallback &cb) { mPriv->authorizePublicationCB = cb; } void BaseConnectionContactListInterface::authorizePublication(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->authorizePublicationCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->authorizePublicationCB(contacts, error); } void BaseConnectionContactListInterface::setRemoveContactsCallback(const BaseConnectionContactListInterface::RemoveContactsCallback &cb) { mPriv->removeContactsCB = cb; } void BaseConnectionContactListInterface::removeContacts(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->removeContactsCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->removeContactsCB(contacts, error); } void BaseConnectionContactListInterface::setUnsubscribeCallback(const BaseConnectionContactListInterface::UnsubscribeCallback &cb) { mPriv->unsubscribeCB = cb; } void BaseConnectionContactListInterface::unsubscribe(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->unsubscribeCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->unsubscribeCB(contacts, error); } void BaseConnectionContactListInterface::setUnpublishCallback(const BaseConnectionContactListInterface::UnpublishCallback &cb) { mPriv->unpublishCB = cb; } void BaseConnectionContactListInterface::unpublish(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->unpublishCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->unpublishCB(contacts, error); } void BaseConnectionContactListInterface::setDownloadCallback(const BaseConnectionContactListInterface::DownloadCallback &cb) { mPriv->downloadCB = cb; } void BaseConnectionContactListInterface::download(DBusError *error) { if (!mPriv->downloadCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->downloadCB(error); } void BaseConnectionContactListInterface::contactsChangedWithID(const Tp::ContactSubscriptionMap &changes, const Tp::HandleIdentifierMap &identifiers, const Tp::HandleIdentifierMap &removals) { QMetaObject::invokeMethod(mPriv->adaptee, "contactsChangedWithID", Q_ARG(Tp::ContactSubscriptionMap, changes), Q_ARG(Tp::HandleIdentifierMap, identifiers), Q_ARG(Tp::HandleIdentifierMap, removals)); //Can simply use emit in Qt5 } // Conn.I.ContactInfo struct TP_QT_NO_EXPORT BaseConnectionContactInfoInterface::Private { Private(BaseConnectionContactInfoInterface *parent) : adaptee(new BaseConnectionContactInfoInterface::Adaptee(parent)) { } Tp::ContactInfoFlags contactInfoFlags; Tp::FieldSpecs supportedFields; GetContactInfoCallback getContactInfoCB; RefreshContactInfoCallback refreshContactInfoCB; RequestContactInfoCallback requestContactInfoCB; SetContactInfoCallback setContactInfoCB; BaseConnectionContactInfoInterface::Adaptee *adaptee; }; BaseConnectionContactInfoInterface::Adaptee::Adaptee(BaseConnectionContactInfoInterface *interface) : QObject(interface), mInterface(interface) { } BaseConnectionContactInfoInterface::Adaptee::~Adaptee() { } uint BaseConnectionContactInfoInterface::Adaptee::contactInfoFlags() const { return mInterface->contactInfoFlags(); } Tp::FieldSpecs BaseConnectionContactInfoInterface::Adaptee::supportedFields() const { return mInterface->supportedFields(); } void BaseConnectionContactInfoInterface::Adaptee::getContactInfo(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactInfoAdaptor::GetContactInfoContextPtr &context) { qDebug() << "BaseConnectionContactInfoInterface::Adaptee::getContactInfo"; DBusError error; Tp::ContactInfoMap contactInfo = mInterface->getContactInfo(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(contactInfo); } void BaseConnectionContactInfoInterface::Adaptee::refreshContactInfo(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactInfoAdaptor::RefreshContactInfoContextPtr &context) { qDebug() << "BaseConnectionContactInfoInterface::Adaptee::refreshContactInfo"; DBusError error; mInterface->refreshContactInfo(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseConnectionContactInfoInterface::Adaptee::requestContactInfo(uint contact, const Tp::Service::ConnectionInterfaceContactInfoAdaptor::RequestContactInfoContextPtr &context) { qDebug() << "BaseConnectionContactInfoInterface::Adaptee::requestContactInfo"; DBusError error; Tp::ContactInfoFieldList contactInfo = mInterface->requestContactInfo(contact, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(contactInfo); } void BaseConnectionContactInfoInterface::Adaptee::setContactInfo(const Tp::ContactInfoFieldList &contactInfo, const Tp::Service::ConnectionInterfaceContactInfoAdaptor::SetContactInfoContextPtr &context) { qDebug() << "BaseConnectionContactInfoInterface::Adaptee::setContactInfo"; DBusError error; mInterface->setContactInfo(contactInfo, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseConnectionContactInfoInterface * \ingroup servicecm * \headerfile TelepathyQt/base-connection.h * * \brief Base class for implementations of Connection.Interface.Contact.Info */ /** * Class constructor. */ BaseConnectionContactInfoInterface::BaseConnectionContactInfoInterface() : AbstractConnectionInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_INFO), mPriv(new Private(this)) { } /** * Class destructor. */ BaseConnectionContactInfoInterface::~BaseConnectionContactInfoInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseConnectionContactInfoInterface::immutableProperties() const { QVariantMap map; return map; } Tp::ContactInfoFlags BaseConnectionContactInfoInterface::contactInfoFlags() const { return mPriv->contactInfoFlags; } void BaseConnectionContactInfoInterface::setContactInfoFlags(const Tp::ContactInfoFlags &contactInfoFlags) { mPriv->contactInfoFlags = contactInfoFlags; } Tp::FieldSpecs BaseConnectionContactInfoInterface::supportedFields() const { return mPriv->supportedFields; } void BaseConnectionContactInfoInterface::setSupportedFields(const Tp::FieldSpecs &supportedFields) { mPriv->supportedFields = supportedFields; } void BaseConnectionContactInfoInterface::createAdaptor() { (void) new Service::ConnectionInterfaceContactInfoAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseConnectionContactInfoInterface::setGetContactInfoCallback(const BaseConnectionContactInfoInterface::GetContactInfoCallback &cb) { mPriv->getContactInfoCB = cb; } Tp::ContactInfoMap BaseConnectionContactInfoInterface::getContactInfo(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->getContactInfoCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return Tp::ContactInfoMap(); } return mPriv->getContactInfoCB(contacts, error); } void BaseConnectionContactInfoInterface::setRefreshContactInfoCallback(const BaseConnectionContactInfoInterface::RefreshContactInfoCallback &cb) { mPriv->refreshContactInfoCB = cb; } void BaseConnectionContactInfoInterface::refreshContactInfo(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->refreshContactInfoCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->refreshContactInfoCB(contacts, error); } void BaseConnectionContactInfoInterface::setRequestContactInfoCallback(const BaseConnectionContactInfoInterface::RequestContactInfoCallback &cb) { mPriv->requestContactInfoCB = cb; } Tp::ContactInfoFieldList BaseConnectionContactInfoInterface::requestContactInfo(uint contact, DBusError *error) { if (!mPriv->requestContactInfoCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return Tp::ContactInfoFieldList(); } return mPriv->requestContactInfoCB(contact, error); } void BaseConnectionContactInfoInterface::setSetContactInfoCallback(const BaseConnectionContactInfoInterface::SetContactInfoCallback &cb) { mPriv->setContactInfoCB = cb; } void BaseConnectionContactInfoInterface::setContactInfo(const Tp::ContactInfoFieldList &contactInfo, DBusError *error) { if (!mPriv->setContactInfoCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->setContactInfoCB(contactInfo, error); } void BaseConnectionContactInfoInterface::contactInfoChanged(uint contact, const Tp::ContactInfoFieldList &contactInfo) { QMetaObject::invokeMethod(mPriv->adaptee, "contactInfoChanged", Q_ARG(uint, contact), Q_ARG(Tp::ContactInfoFieldList, contactInfo)); //Can simply use emit in Qt5 } // Conn.I.Addressing BaseConnectionAddressingInterface::Adaptee::Adaptee(BaseConnectionAddressingInterface *interface) : QObject(interface), mInterface(interface) { } BaseConnectionAddressingInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseConnectionAddressingInterface::Private { Private(BaseConnectionAddressingInterface *parent) : adaptee(new BaseConnectionAddressingInterface::Adaptee(parent)) { } GetContactsByVCardFieldCallback getContactsByVCardFieldCB; GetContactsByURICallback getContactsByURICB; BaseConnectionAddressingInterface::Adaptee *adaptee; }; /** * \class BaseConnectionAddressingInterface * \ingroup servicecm * \headerfile TelepathyQt/base-connection.h * * \brief Base class for implementations of Connection.Interface.Addressing */ /** * Class constructor. */ BaseConnectionAddressingInterface::BaseConnectionAddressingInterface() : AbstractConnectionInterface(TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING), mPriv(new Private(this)) { } /** * Class destructor. */ BaseConnectionAddressingInterface::~BaseConnectionAddressingInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseConnectionAddressingInterface::immutableProperties() const { QVariantMap map; return map; } void BaseConnectionAddressingInterface::createAdaptor() { (void) new Service::ConnectionInterfaceAddressingAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseConnectionAddressingInterface::setGetContactsByVCardFieldCallback(const GetContactsByVCardFieldCallback &cb) { mPriv->getContactsByVCardFieldCB = cb; } void BaseConnectionAddressingInterface::setGetContactsByURICallback(const GetContactsByURICallback &cb) { mPriv->getContactsByURICB = cb; } void BaseConnectionAddressingInterface::Adaptee::getContactsByVCardField(const QString &field, const QStringList &addresses, const QStringList &interfaces, const Tp::Service::ConnectionInterfaceAddressingAdaptor::GetContactsByVCardFieldContextPtr &context) { if (!mInterface->mPriv->getContactsByVCardFieldCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } Tp::AddressingNormalizationMap addressingNormalizationMap; Tp::ContactAttributesMap contactAttributesMap; DBusError error; mInterface->mPriv->getContactsByVCardFieldCB(field, addresses, interfaces, addressingNormalizationMap, contactAttributesMap, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(addressingNormalizationMap, contactAttributesMap); } void BaseConnectionAddressingInterface::Adaptee::getContactsByURI(const QStringList &URIs, const QStringList &interfaces, const Tp::Service::ConnectionInterfaceAddressingAdaptor::GetContactsByURIContextPtr &context) { if (!mInterface->mPriv->getContactsByURICB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } Tp::AddressingNormalizationMap addressingNormalizationMap; Tp::ContactAttributesMap contactAttributesMap; DBusError error; mInterface->mPriv->getContactsByURICB(URIs, interfaces, addressingNormalizationMap, contactAttributesMap, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(addressingNormalizationMap, contactAttributesMap); } // Conn.I.Aliasing struct TP_QT_NO_EXPORT BaseConnectionAliasingInterface::Private { Private(BaseConnectionAliasingInterface *parent) : adaptee(new BaseConnectionAliasingInterface::Adaptee(parent)) { } GetAliasFlagsCallback getAliasFlagsCB; RequestAliasesCallback requestAliasesCB; GetAliasesCallback getAliasesCB; SetAliasesCallback setAliasesCB; BaseConnectionAliasingInterface::Adaptee *adaptee; }; BaseConnectionAliasingInterface::Adaptee::Adaptee(BaseConnectionAliasingInterface *interface) : QObject(interface), mInterface(interface) { } BaseConnectionAliasingInterface::Adaptee::~Adaptee() { } void BaseConnectionAliasingInterface::Adaptee::getAliasFlags( const Tp::Service::ConnectionInterfaceAliasingAdaptor::GetAliasFlagsContextPtr &context) { qDebug() << "BaseConnectionAliasingInterface::Adaptee::getAliasFlags"; DBusError error; Tp::ConnectionAliasFlags aliasFlags = mInterface->getAliasFlags(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(aliasFlags); } void BaseConnectionAliasingInterface::Adaptee::requestAliases(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceAliasingAdaptor::RequestAliasesContextPtr &context) { qDebug() << "BaseConnectionAliasingInterface::Adaptee::requestAliases"; DBusError error; QStringList aliases = mInterface->requestAliases(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(aliases); } void BaseConnectionAliasingInterface::Adaptee::getAliases(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceAliasingAdaptor::GetAliasesContextPtr &context) { qDebug() << "BaseConnectionAliasingInterface::Adaptee::getAliases"; DBusError error; Tp::AliasMap aliases = mInterface->getAliases(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(aliases); } void BaseConnectionAliasingInterface::Adaptee::setAliases(const Tp::AliasMap &aliases, const Tp::Service::ConnectionInterfaceAliasingAdaptor::SetAliasesContextPtr &context) { qDebug() << "BaseConnectionAliasingInterface::Adaptee::setAliases"; DBusError error; mInterface->setAliases(aliases, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseConnectionAliasingInterface * \ingroup servicecm * \headerfile TelepathyQt/base-connection.h * * \brief Base class for implementations of Connection.Interface.Aliasing */ /** * Class constructor. */ BaseConnectionAliasingInterface::BaseConnectionAliasingInterface() : AbstractConnectionInterface(TP_QT_IFACE_CONNECTION_INTERFACE_ALIASING), mPriv(new Private(this)) { } /** * Class destructor. */ BaseConnectionAliasingInterface::~BaseConnectionAliasingInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseConnectionAliasingInterface::immutableProperties() const { QVariantMap map; return map; } void BaseConnectionAliasingInterface::createAdaptor() { (void) new Service::ConnectionInterfaceAliasingAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseConnectionAliasingInterface::setGetAliasFlagsCallback(const BaseConnectionAliasingInterface::GetAliasFlagsCallback &cb) { mPriv->getAliasFlagsCB = cb; } Tp::ConnectionAliasFlags BaseConnectionAliasingInterface::getAliasFlags(DBusError *error) { if (!mPriv->getAliasFlagsCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return Tp::ConnectionAliasFlags(); } return mPriv->getAliasFlagsCB(error); } void BaseConnectionAliasingInterface::setRequestAliasesCallback(const BaseConnectionAliasingInterface::RequestAliasesCallback &cb) { mPriv->requestAliasesCB = cb; } QStringList BaseConnectionAliasingInterface::requestAliases(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->requestAliasesCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return QStringList(); } return mPriv->requestAliasesCB(contacts, error); } void BaseConnectionAliasingInterface::setGetAliasesCallback(const BaseConnectionAliasingInterface::GetAliasesCallback &cb) { mPriv->getAliasesCB = cb; } Tp::AliasMap BaseConnectionAliasingInterface::getAliases(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->getAliasesCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return Tp::AliasMap(); } return mPriv->getAliasesCB(contacts, error); } void BaseConnectionAliasingInterface::setSetAliasesCallback(const BaseConnectionAliasingInterface::SetAliasesCallback &cb) { mPriv->setAliasesCB = cb; } void BaseConnectionAliasingInterface::setAliases(const Tp::AliasMap &aliases, DBusError *error) { if (!mPriv->setAliasesCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->setAliasesCB(aliases, error); } void BaseConnectionAliasingInterface::aliasesChanged(const Tp::AliasPairList &aliases) { QMetaObject::invokeMethod(mPriv->adaptee, "aliasesChanged", Q_ARG(Tp::AliasPairList, aliases)); //Can simply use emit in Qt5 } // Conn.I.Avatars struct TP_QT_NO_EXPORT BaseConnectionAvatarsInterface::Private { Private(BaseConnectionAvatarsInterface *parent) : adaptee(new BaseConnectionAvatarsInterface::Adaptee(parent)) { } AvatarSpec avatarDetails; GetKnownAvatarTokensCallback getKnownAvatarTokensCB; RequestAvatarsCallback requestAvatarsCB; SetAvatarCallback setAvatarCB; ClearAvatarCallback clearAvatarCB; BaseConnectionAvatarsInterface::Adaptee *adaptee; friend class BaseConnectionAvatarsInterface::Adaptee; }; BaseConnectionAvatarsInterface::Adaptee::Adaptee(BaseConnectionAvatarsInterface *interface) : QObject(interface), mInterface(interface) { } BaseConnectionAvatarsInterface::Adaptee::~Adaptee() { } QStringList BaseConnectionAvatarsInterface::Adaptee::supportedAvatarMimeTypes() const { return mInterface->mPriv->avatarDetails.supportedMimeTypes(); } uint BaseConnectionAvatarsInterface::Adaptee::minimumAvatarHeight() const { return mInterface->mPriv->avatarDetails.minimumHeight(); } uint BaseConnectionAvatarsInterface::Adaptee::minimumAvatarWidth() const { return mInterface->mPriv->avatarDetails.minimumWidth(); } uint BaseConnectionAvatarsInterface::Adaptee::recommendedAvatarHeight() const { return mInterface->mPriv->avatarDetails.recommendedHeight(); } uint BaseConnectionAvatarsInterface::Adaptee::recommendedAvatarWidth() const { return mInterface->mPriv->avatarDetails.recommendedWidth(); } uint BaseConnectionAvatarsInterface::Adaptee::maximumAvatarHeight() const { return mInterface->mPriv->avatarDetails.maximumHeight(); } uint BaseConnectionAvatarsInterface::Adaptee::maximumAvatarWidth() const { return mInterface->mPriv->avatarDetails.maximumWidth(); } uint BaseConnectionAvatarsInterface::Adaptee::maximumAvatarBytes() const { return mInterface->mPriv->avatarDetails.maximumBytes(); } void BaseConnectionAvatarsInterface::Adaptee::getKnownAvatarTokens(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceAvatarsAdaptor::GetKnownAvatarTokensContextPtr &context) { qDebug() << "BaseConnectionAvatarsInterface::Adaptee::getKnownAvatarTokens"; DBusError error; Tp::AvatarTokenMap tokens = mInterface->getKnownAvatarTokens(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(tokens); } void BaseConnectionAvatarsInterface::Adaptee::requestAvatars(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceAvatarsAdaptor::RequestAvatarsContextPtr &context) { qDebug() << "BaseConnectionAvatarsInterface::Adaptee::requestAvatars"; DBusError error; mInterface->requestAvatars(contacts, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseConnectionAvatarsInterface::Adaptee::setAvatar(const QByteArray &avatar, const QString &mimeType, const Tp::Service::ConnectionInterfaceAvatarsAdaptor::SetAvatarContextPtr &context) { qDebug() << "BaseConnectionAvatarsInterface::Adaptee::setAvatar"; DBusError error; QString token = mInterface->setAvatar(avatar, mimeType, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(token); } void BaseConnectionAvatarsInterface::Adaptee::clearAvatar( const Tp::Service::ConnectionInterfaceAvatarsAdaptor::ClearAvatarContextPtr &context) { qDebug() << "BaseConnectionAvatarsInterface::Adaptee::clearAvatar"; DBusError error; mInterface->clearAvatar(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseConnectionAvatarsInterface * \ingroup servicecm * \headerfile TelepathyQt/base-connection.h * * \brief Base class for implementations of Connection.Interface.Avatars */ /** * Class constructor. */ BaseConnectionAvatarsInterface::BaseConnectionAvatarsInterface() : AbstractConnectionInterface(TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS), mPriv(new Private(this)) { } /** * Class destructor. */ BaseConnectionAvatarsInterface::~BaseConnectionAvatarsInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseConnectionAvatarsInterface::immutableProperties() const { QVariantMap map; return map; } AvatarSpec BaseConnectionAvatarsInterface::avatarDetails() const { return mPriv->avatarDetails; } void BaseConnectionAvatarsInterface::setAvatarDetails(const AvatarSpec &spec) { mPriv->avatarDetails = spec; } void BaseConnectionAvatarsInterface::createAdaptor() { (void) new Service::ConnectionInterfaceAvatarsAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseConnectionAvatarsInterface::setGetKnownAvatarTokensCallback(const BaseConnectionAvatarsInterface::GetKnownAvatarTokensCallback &cb) { mPriv->getKnownAvatarTokensCB = cb; } Tp::AvatarTokenMap BaseConnectionAvatarsInterface::getKnownAvatarTokens(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->getKnownAvatarTokensCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return Tp::AvatarTokenMap(); } return mPriv->getKnownAvatarTokensCB(contacts, error); } void BaseConnectionAvatarsInterface::setRequestAvatarsCallback(const BaseConnectionAvatarsInterface::RequestAvatarsCallback &cb) { mPriv->requestAvatarsCB = cb; } void BaseConnectionAvatarsInterface::requestAvatars(const Tp::UIntList &contacts, DBusError *error) { if (!mPriv->requestAvatarsCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->requestAvatarsCB(contacts, error); } void BaseConnectionAvatarsInterface::setSetAvatarCallback(const BaseConnectionAvatarsInterface::SetAvatarCallback &cb) { mPriv->setAvatarCB = cb; } QString BaseConnectionAvatarsInterface::setAvatar(const QByteArray &avatar, const QString &mimeType, DBusError *error) { if (!mPriv->setAvatarCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return QString(); } return mPriv->setAvatarCB(avatar, mimeType, error); } void BaseConnectionAvatarsInterface::setClearAvatarCallback(const BaseConnectionAvatarsInterface::ClearAvatarCallback &cb) { mPriv->clearAvatarCB = cb; } void BaseConnectionAvatarsInterface::clearAvatar(DBusError *error) { if (!mPriv->clearAvatarCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->clearAvatarCB(error); } void BaseConnectionAvatarsInterface::avatarUpdated(uint contact, const QString &newAvatarToken) { QMetaObject::invokeMethod(mPriv->adaptee, "avatarUpdated", Q_ARG(uint, contact), Q_ARG(QString, newAvatarToken)); //Can simply use emit in Qt5 } void BaseConnectionAvatarsInterface::avatarRetrieved(uint contact, const QString &token, const QByteArray &avatar, const QString &type) { QMetaObject::invokeMethod(mPriv->adaptee, "avatarRetrieved", Q_ARG(uint, contact), Q_ARG(QString, token), Q_ARG(QByteArray, avatar), Q_ARG(QString, type)); //Can simply use emit in Qt5 } } telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceCaptchaAuthenticationInterface0000664000175000017500000000046112470405660026336 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceCaptchaAuthenticationInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceCaptchaAuthenticationInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel-factory.cpp0000664000175000017500000005763212470405660021012 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/channel-factory.moc.hpp" #include "TelepathyQt/_gen/future-constants.h" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ChannelFactory::Private { Private(); QList features; typedef QPair CtorPair; QList ctors; }; ChannelFactory::Private::Private() { } /** * \class ChannelFactory * \ingroup utils * \headerfile TelepathyQt/channel-factory.h * * \brief The ChannelFactory class is responsible for constructing Channel * objects according to application-defined settings. */ /** * Create a new ChannelFactory object. * * The returned factory will construct channel subclasses provided by TelepathyQt as appropriate * for the channel immutable properties, but not make any features ready. * * \param bus The QDBusConnection the proxies constructed using this factory should use. * \return An ChannelFactoryPtr pointing to the newly created factory. */ ChannelFactoryPtr ChannelFactory::create(const QDBusConnection &bus) { return ChannelFactoryPtr(new ChannelFactory(bus)); } /** * Construct a new ChannelFactory object. * * The constructed factory will construct channel subclasses provided by TelepathyQt as appropriate * for the channel immutable properties, but not make any features ready. * * \param bus The QDBusConnection the proxies constructed using this factory should use. */ ChannelFactory::ChannelFactory(const QDBusConnection &bus) : DBusProxyFactory(bus), mPriv(new Private) { setSubclassForTextChats(); setSubclassForTextChatrooms(); setSubclassForCalls(); setSubclassForStreamedMediaCalls(); setSubclassForRoomLists(); setSubclassForIncomingDBusTubes(); setSubclassForOutgoingDBusTubes(); setSubclassForIncomingRoomDBusTubes(); setSubclassForOutgoingRoomDBusTubes(); setSubclassForIncomingFileTransfers(); setSubclassForOutgoingFileTransfers(); setSubclassForIncomingStreamTubes(); setSubclassForOutgoingStreamTubes(); setSubclassForIncomingRoomStreamTubes(); setSubclassForOutgoingRoomStreamTubes(); setSubclassForContactSearches(); setSubclassForServerAuthentication(); setFallbackSubclass(); } /** * Class destructor. */ ChannelFactory::~ChannelFactory() { delete mPriv; } Features ChannelFactory::featuresForTextChats(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::textChat(additionalProps)); } void ChannelFactory::addFeaturesForTextChats(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::textChat(additionalProps), features); addFeaturesFor(ChannelClassSpec::unnamedTextChat(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForTextChats( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::textChat(additionalProps)); } void ChannelFactory::setConstructorForTextChats(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::textChat(additionalProps), ctor); setConstructorFor(ChannelClassSpec::unnamedTextChat(additionalProps), ctor); } Features ChannelFactory::featuresForTextChatrooms(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::textChatroom(additionalProps)); } void ChannelFactory::addFeaturesForTextChatrooms(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::textChatroom(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForTextChatrooms( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::textChatroom(additionalProps)); } void ChannelFactory::setConstructorForTextChatrooms(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::textChatroom(additionalProps), ctor); } Features ChannelFactory::featuresForCalls(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::audioCall(additionalProps)); } void ChannelFactory::addFeaturesForCalls(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::audioCall(additionalProps), features); addFeaturesFor(ChannelClassSpec::videoCall(additionalProps), features); } void ChannelFactory::setConstructorForCalls(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::audioCall(additionalProps), ctor); setConstructorFor(ChannelClassSpec::videoCall(additionalProps), ctor); } Features ChannelFactory::featuresForStreamedMediaCalls(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::streamedMediaCall(additionalProps)); } void ChannelFactory::addFeaturesForStreamedMediaCalls(const Features &features, const QVariantMap &additionalProps) { ChannelClassSpec smSpec = ChannelClassSpec::streamedMediaCall(additionalProps); ChannelClassSpec unnamedSMSpec = ChannelClassSpec::unnamedStreamedMediaCall(additionalProps); addFeaturesFor(smSpec, features); addFeaturesFor(unnamedSMSpec, features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForStreamedMediaCalls( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::streamedMediaCall(additionalProps)); } void ChannelFactory::setConstructorForStreamedMediaCalls(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { ChannelClassSpec smSpec = ChannelClassSpec::streamedMediaCall(additionalProps); ChannelClassSpec unnamedSMSpec = ChannelClassSpec::unnamedStreamedMediaCall(additionalProps); setConstructorFor(smSpec, ctor); setConstructorFor(unnamedSMSpec, ctor); } Features ChannelFactory::featuresForRoomLists(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::roomList(additionalProps)); } void ChannelFactory::addFeaturesForRoomLists(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::roomList(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForRoomLists( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::roomList(additionalProps)); } void ChannelFactory::setConstructorForRoomLists(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::roomList(additionalProps), ctor); } Features ChannelFactory::featuresForOutgoingFileTransfers(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::outgoingFileTransfer(additionalProps)); } void ChannelFactory::addFeaturesForOutgoingFileTransfers(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::outgoingFileTransfer(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForOutgoingFileTransfers( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::outgoingFileTransfer(additionalProps)); } void ChannelFactory::setConstructorForOutgoingFileTransfers(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::outgoingFileTransfer(additionalProps), ctor); } Features ChannelFactory::featuresForIncomingFileTransfers(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::incomingFileTransfer(additionalProps)); } void ChannelFactory::addFeaturesForIncomingFileTransfers(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::incomingFileTransfer(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForIncomingFileTransfers( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::incomingFileTransfer(additionalProps)); } void ChannelFactory::setConstructorForIncomingFileTransfers(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::incomingFileTransfer(additionalProps), ctor); } Features ChannelFactory::featuresForOutgoingStreamTubes(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::outgoingStreamTube(QString(), additionalProps)); } void ChannelFactory::addFeaturesForOutgoingStreamTubes(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::outgoingStreamTube(QString(), additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForOutgoingStreamTubes( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::outgoingStreamTube(QString(), additionalProps)); } void ChannelFactory::setConstructorForOutgoingStreamTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::outgoingStreamTube(QString(), additionalProps), ctor); } Features ChannelFactory::featuresForIncomingStreamTubes(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::incomingStreamTube(QString(), additionalProps)); } void ChannelFactory::addFeaturesForIncomingStreamTubes(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::incomingStreamTube(QString(), additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForIncomingStreamTubes( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::incomingStreamTube(QString(), additionalProps)); } void ChannelFactory::setConstructorForIncomingStreamTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::incomingStreamTube(QString(), additionalProps), ctor); } Features ChannelFactory::featuresForOutgoingRoomStreamTubes(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::outgoingRoomStreamTube(QString(), additionalProps)); } void ChannelFactory::addFeaturesForOutgoingRoomStreamTubes(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::outgoingRoomStreamTube(QString(), additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForOutgoingRoomStreamTubes( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::outgoingRoomStreamTube(QString(), additionalProps)); } void ChannelFactory::setConstructorForOutgoingRoomStreamTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::outgoingRoomStreamTube(QString(), additionalProps), ctor); } Features ChannelFactory::featuresForIncomingRoomStreamTubes(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::incomingRoomStreamTube(QString(), additionalProps)); } void ChannelFactory::addFeaturesForIncomingRoomStreamTubes(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::incomingRoomStreamTube(QString(), additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForIncomingRoomStreamTubes( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::incomingRoomStreamTube(QString(), additionalProps)); } void ChannelFactory::setConstructorForIncomingRoomStreamTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::incomingRoomStreamTube(QString(), additionalProps), ctor); } Features ChannelFactory::featuresForOutgoingDBusTubes(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::outgoingDBusTube(QString(), additionalProps)); } void ChannelFactory::addFeaturesForOutgoingDBusTubes(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::outgoingDBusTube(QString(), additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForOutgoingDBusTubes( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::outgoingDBusTube(QString(), additionalProps)); } void ChannelFactory::setConstructorForOutgoingDBusTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::outgoingDBusTube(QString(), additionalProps), ctor); } Features ChannelFactory::featuresForIncomingDBusTubes(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::incomingDBusTube(QString(), additionalProps)); } void ChannelFactory::addFeaturesForIncomingDBusTubes(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::incomingDBusTube(QString(), additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForIncomingDBusTubes( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::incomingDBusTube(QString(), additionalProps)); } void ChannelFactory::setConstructorForIncomingDBusTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::incomingDBusTube(QString(), additionalProps), ctor); } Features ChannelFactory::featuresForOutgoingRoomDBusTubes(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::outgoingRoomDBusTube(QString(), additionalProps)); } void ChannelFactory::addFeaturesForOutgoingRoomDBusTubes(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::outgoingRoomDBusTube(QString(), additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForOutgoingRoomDBusTubes( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::outgoingRoomDBusTube(QString(), additionalProps)); } void ChannelFactory::setConstructorForOutgoingRoomDBusTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::outgoingRoomDBusTube(QString(), additionalProps), ctor); } Features ChannelFactory::featuresForIncomingRoomDBusTubes(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::incomingRoomDBusTube(QString(), additionalProps)); } void ChannelFactory::addFeaturesForIncomingRoomDBusTubes(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::incomingRoomDBusTube(QString(), additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForIncomingRoomDBusTubes( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::incomingRoomDBusTube(QString(), additionalProps)); } void ChannelFactory::setConstructorForIncomingRoomDBusTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::incomingRoomDBusTube(QString(), additionalProps), ctor); } Features ChannelFactory::featuresForContactSearches(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::contactSearch(additionalProps)); } void ChannelFactory::addFeaturesForContactSearches(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::contactSearch(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForContactSearches( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::contactSearch(additionalProps)); } void ChannelFactory::setConstructorForContactSearches(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::contactSearch(additionalProps), ctor); } Features ChannelFactory::featuresForServerAuthentication(const QVariantMap &additionalProps) const { return featuresFor(ChannelClassSpec::serverAuthentication(additionalProps)); } void ChannelFactory::addFeaturesForServerAuthentication(const Features &features, const QVariantMap &additionalProps) { addFeaturesFor(ChannelClassSpec::serverAuthentication(additionalProps), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorForServerAuthentication( const QVariantMap &additionalProps) const { return constructorFor(ChannelClassSpec::serverAuthentication(additionalProps)); } void ChannelFactory::setConstructorForServerAuthentication(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps) { setConstructorFor(ChannelClassSpec::serverAuthentication(additionalProps), ctor); } Features ChannelFactory::commonFeatures() const { return featuresFor(ChannelClassSpec()); } void ChannelFactory::addCommonFeatures(const Features &features) { addFeaturesFor(ChannelClassSpec(), features); } ChannelFactory::ConstructorConstPtr ChannelFactory::fallbackConstructor() const { return constructorFor(ChannelClassSpec()); } void ChannelFactory::setFallbackConstructor(const ConstructorConstPtr &ctor) { setConstructorFor(ChannelClassSpec(), ctor); } Features ChannelFactory::featuresFor(const ChannelClassSpec &channelClass) const { Features features; foreach (const ChannelClassFeatures &pair, mPriv->features) { if (pair.first.isSubsetOf(channelClass)) { features.unite(pair.second); } } return features; } void ChannelFactory::addFeaturesFor(const ChannelClassSpec &channelClass, const Features &features) { QList::iterator i; for (i = mPriv->features.begin(); i != mPriv->features.end(); ++i) { if (channelClass.allProperties().size() > i->first.allProperties().size()) { break; } if (i->first == channelClass) { i->second.unite(features); return; } } // We ran out of feature specifications (for the given size/specificity of a channel class) // before finding a matching one, so let's create a new entry mPriv->features.insert(i, qMakePair(channelClass, features)); } ChannelFactory::ConstructorConstPtr ChannelFactory::constructorFor(const ChannelClassSpec &cc) const { QList::iterator i; for (i = mPriv->ctors.begin(); i != mPriv->ctors.end(); ++i) { if (i->first.isSubsetOf(cc)) { return i->second; } } // If this is reached, we didn't have a proper fallback constructor Q_ASSERT(false); return ConstructorConstPtr(); } void ChannelFactory::setConstructorFor(const ChannelClassSpec &channelClass, const ConstructorConstPtr &ctor) { if (ctor.isNull()) { warning().nospace() << "Tried to set a NULL ctor for ChannelClass(" << channelClass.channelType() << ", " << channelClass.targetHandleType() << ", " << channelClass.allProperties().size() << "props in total)"; return; } QList::iterator i; for (i = mPriv->ctors.begin(); i != mPriv->ctors.end(); ++i) { if (channelClass.allProperties().size() > i->first.allProperties().size()) { break; } if (i->first == channelClass) { i->second = ctor; return; } } // We ran out of constructors (for the given size/specificity of a channel class) // before finding a matching one, so let's create a new entry mPriv->ctors.insert(i, qMakePair(channelClass, ctor)); } /** * Constructs a Channel proxy and begins making it ready. * * If a valid proxy already exists in the factory cache for the given combination of \a busName and * \a objectPath, it is returned instead. All newly created proxies are automatically cached until * they're either DBusProxy::invalidated() or the last reference to them outside the factory has * been dropped. * * The proxy can be accessed immediately after this function returns using PendingReady::proxy(). * * \param connection Proxy for the owning connection of the channel. * \param channelPath The object path of the channel. * \param immutableProperties The immutable properties of the channel. * \return A PendingReady operation with the proxy in PendingReady::proxy(). */ PendingReady *ChannelFactory::proxy(const ConnectionPtr &connection, const QString &channelPath, const QVariantMap &immutableProperties) const { DBusProxyPtr proxy = cachedProxy(connection->busName(), channelPath); if (proxy.isNull()) { proxy = constructorFor(ChannelClassSpec(immutableProperties))->construct(connection, channelPath, immutableProperties); } return nowHaveProxy(proxy); } /** * Transforms well-known names to the corresponding unique names, as is appropriate for Channel * * \param uniqueOrWellKnown The name to transform. * \return The unique name corresponding to \a uniqueOrWellKnown (which may be it itself). */ QString ChannelFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const { return StatefulDBusProxy::uniqueNameFrom(dbusConnection(), uniqueOrWellKnown); } /** * Return features as configured for the channel class given by the Channel::immutableProperties() * of \a proxy. * * \param proxy The Channel proxy to determine the features for. * \return A list of Feature objects. */ Features ChannelFactory::featuresFor(const DBusProxyPtr &proxy) const { ChannelPtr chan = ChannelPtr::qObjectCast(proxy); Q_ASSERT(!chan.isNull()); return featuresFor(ChannelClassSpec(chan->immutableProperties())); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceFileTransferMetadataInterface0000664000175000017500000000045712470405660026125 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceFileTransferMetadataInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceFileTransferMetadataInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceCellularInterface0000664000175000017500000000044012470405660024362 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceCellularInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceCellularInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-send-message.cpp0000664000175000017500000001052612470405660021721 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-send-message.moc.hpp" #include #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingSendMessage::Private { Private(const Message &message) : message(message) { } QString token; Message message; }; /** * \class PendingSendMessage * \ingroup clientchannel * \headerfile TelepathyQt/pending-send-message.h * * \brief The PendingSendMessage class represents the parameters of and the * reply to an asynchronous message send request. * * See \ref async_model */ PendingSendMessage::PendingSendMessage(const TextChannelPtr &channel, const Message &message) : PendingOperation(channel), mPriv(new Private(message)) { } PendingSendMessage::PendingSendMessage(const ContactMessengerPtr &messenger, const Message &message) : PendingOperation(messenger), mPriv(new Private(message)) { } PendingSendMessage::~PendingSendMessage() { delete mPriv; } /** * Return the channel used to send the message if this instance was created using * TextChannel. If it was created using ContactMessenger, return a null TextChannelPtr. * * \return A pointer to the TextChannel object, or a null TextChannelPtr if created using * ContactMessenger. */ TextChannelPtr PendingSendMessage::channel() const { return TextChannelPtr(qobject_cast((TextChannel*) object().data())); } /** * Return the contact messenger used to send the message if this instance was created using * ContactMessenger. If it was created using TextChannel, return a null ContactMessengerPtr. * * \return A pointer to the ContactMessenger object, or a null ContactMessengerPtr if created using * TextChannel. */ ContactMessengerPtr PendingSendMessage::messenger() const { return ContactMessengerPtr(qobject_cast((ContactMessenger*) object().data())); } QString PendingSendMessage::sentMessageToken() const { return mPriv->token; } Message PendingSendMessage::message() const { return mPriv->message; } void PendingSendMessage::onTextSent(QDBusPendingCallWatcher *watcher) { QDBusPendingReply<> reply = *watcher; if (reply.isError()) { setFinishedWithError(reply.error()); } else { setFinished(); } watcher->deleteLater(); } void PendingSendMessage::onMessageSent(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { setFinishedWithError(reply.error()); } else { mPriv->token = reply.value(); setFinished(); } watcher->deleteLater(); } void PendingSendMessage::onCDMessageSent(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { QDBusError error = reply.error(); if (error.name() == TP_QT_DBUS_ERROR_UNKNOWN_METHOD || error.name() == TP_QT_DBUS_ERROR_UNKNOWN_INTERFACE) { setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Channel Dispatcher implementation (e.g. mission-control), " "does not support interface CD.I.Messages")); } else { setFinishedWithError(error); } } else { mPriv->token = reply.value(); setFinished(); } watcher->deleteLater(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ClientRegistrar0000664000175000017500000000037412470405660020244 0ustar jrjr#ifndef _TelepathyQt_ClientRegistrar_HEADER_GUARD_ #define _TelepathyQt_ClientRegistrar_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ReadyObject0000664000175000017500000000036012470405660017331 0ustar jrjr#ifndef _TelepathyQt_ReadyObject_HEADER_GUARD_ #define _TelepathyQt_ReadyObject_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/message-content-part.h0000664000175000017500000000515112470405660021427 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_message_content_part_h_HEADER_GUARD_ #define _TelepathyQt_message_content_part_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT MessageContentPart { public: MessageContentPart(); MessageContentPart(const MessagePart &mp); MessageContentPart(const MessageContentPart &other); ~MessageContentPart(); bool isValid() const { return mPriv.constData() != 0; } MessageContentPart &operator=(const MessageContentPart &other); bool operator==(const MessageContentPart &other) const; MessagePart barePart() const; private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; class TP_QT_EXPORT MessageContentPartList : public QList { public: MessageContentPartList() { } MessageContentPartList(const MessagePart &mp) { append(MessageContentPart(mp)); } MessageContentPartList(const MessagePartList &mps) { Q_FOREACH (const MessagePart &mp, mps) { append(MessageContentPart(mp)); } } MessageContentPartList(const MessageContentPart &mcp) { append(mcp); } MessageContentPartList(const QList &other) : QList(other) { } MessagePartList bareParts() const { MessagePartList list; Q_FOREACH (const MessageContentPart &mcp, *this) { list.append(mcp.barePart()); } return list; } }; } // Tp Q_DECLARE_METATYPE(Tp::MessageContentPart); Q_DECLARE_METATYPE(Tp::MessageContentPartList); #endif telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/0000775000175000017500000000000012470405660017140 5ustar jrjrtelepathy-qt-0.9.6~git1/TelepathyQt/Farstream/channel.cpp0000664000175000017500000001211012470405660021247 0ustar jrjr/** * This file is part of TelepathyQt * * Copyright © 2009-2012 Collabora Ltd. * Copyright © 2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/Farstream/_gen/channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include namespace Tp { namespace Farstream { struct TP_QT_FS_NO_EXPORT PendingChannel::Private { Private() : mTfChannel(0) { } static void onTfChannelNewFinish(GObject *sourceObject, GAsyncResult *res, gpointer userData); TfChannel *mTfChannel; }; PendingChannel::PendingChannel(const CallChannelPtr &channel) : Tp::PendingOperation(channel), mPriv(new PendingChannel::Private) { if (!channel->handlerStreamingRequired()) { warning() << "Handler streaming not required"; setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Handler streaming not required")); return; } TpDBusDaemon *dbus = tp_dbus_daemon_dup(0); if (!dbus) { warning() << "Unable to connect to D-Bus"; setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Unable to connect to D-Bus")); return; } Tp::ConnectionPtr connection = channel->connection(); if (connection.isNull()) { warning() << "Connection not available"; setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection not available")); g_object_unref(dbus); return; } TpSimpleClientFactory *factory = (TpSimpleClientFactory *) tp_automatic_client_factory_new (dbus); if (!factory) { warning() << "Unable to construct TpAutomaticClientFactory"; setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Unable to construct TpAutomaticClientFactory")); g_object_unref(dbus); return; } TpConnection *gconnection = tp_simple_client_factory_ensure_connection (factory, connection->objectPath().toLatin1(), NULL, 0); if (!gconnection) { warning() << "Unable to construct TpConnection"; setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Unable to construct TpConnection")); g_object_unref(factory); g_object_unref(dbus); return; } TpChannel *gchannel = (TpChannel*) g_object_new(TP_TYPE_CALL_CHANNEL, "bus-name", connection->busName().toLatin1().constData(), "connection", gconnection, "dbus-daemon", dbus, "object-path", channel->objectPath().toLatin1().constData(), NULL); g_object_unref(factory); factory = 0; g_object_unref(dbus); dbus = 0; g_object_unref(gconnection); gconnection = 0; if (!gchannel) { warning() << "Unable to construct TpChannel"; setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Unable to construct TpChannel")); return; } tf_channel_new_async(gchannel, PendingChannel::Private::onTfChannelNewFinish, this); g_object_unref(gchannel); } PendingChannel::~PendingChannel() { delete mPriv; } void PendingChannel::Private::onTfChannelNewFinish(GObject *sourceObject, GAsyncResult *res, gpointer userData) { PendingChannel *self = reinterpret_cast(userData); GError *error = NULL; TfChannel *ret = tf_channel_new_finish(sourceObject, res, &error); if (error) { warning() << "Fs::PendingChannel::Private::onTfChannelNewFinish: error " << error->message; self->setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String(error->message)); g_clear_error(&error); return; } self->mPriv->mTfChannel = ret; self->setFinished(); } TfChannel *PendingChannel::tfChannel() const { return mPriv->mTfChannel; } CallChannelPtr PendingChannel::callChannel() const { return CallChannelPtr::staticCast(object()); } PendingChannel *createChannel(const CallChannelPtr &channel) { PendingChannel *ptf = new PendingChannel(channel); return ptf; } } // Farstream } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/Global0000664000175000017500000000043412470405660020264 0ustar jrjr#ifndef _TelepathyQt_Farstream_Global_HEADER_GUARD_ #define _TelepathyQt_Farstream_Global_HEADER_GUARD_ #ifndef IN_TP_QT_FARSTREAM_HEADER #define IN_TP_QT_FARSTREAM_HEADER #endif #include #undef IN_TP_QT_FARSTREAM_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/Channel0000664000175000017500000000043712470405660020437 0ustar jrjr#ifndef _TelepathyQt_Farstream_Channel_HEADER_GUARD_ #define _TelepathyQt_Farstream_Channel_HEADER_GUARD_ #ifndef IN_TP_QT_FARSTREAM_HEADER #define IN_TP_QT_FARSTREAM_HEADER #endif #include #undef IN_TP_QT_FARSTREAM_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/TelepathyQtFarstreamConfig.cmake.in0000664000175000017500000000266612470405660026020 0ustar jrjr# TelepathyQt@QT_VERSION_MAJOR@FarstreamConfig.cmake is generated by CMake from TelepathyQt/TelepathyQtFarstreamConfig.cmake.in. # Any changed value in this file will be overwritten by CMake. if(NOT TelepathyQt@QT_VERSION_MAJOR@Farstream_FOUND) # set the version number set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_VERSION_MAJOR @TP_QT_MAJOR_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_VERSION_MINOR @TP_QT_MINOR_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_VERSION_MICRO @TP_QT_MICRO_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_VERSION_NANO @TP_QT_NANO_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_VERSION @PACKAGE_VERSION@) # set the directories if(NOT TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_INSTALL_DIR) set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_INSTALL_DIR "@CMAKE_INSTALL_PREFIX@") endif(NOT TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_INSTALL_DIR) set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_INCLUDE_DIR "@TELEPATHY_QT_INCLUDE_DIR@") set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_LIB_DIR "@TELEPATHY_QT_LIB_DIR@") set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_SHARE_DIR "@TELEPATHY_QT_DATA_DIR@") find_package(TelepathyQt@QT_VERSION_MAJOR@ REQUIRED) set(TELEPATHY_QT@QT_VERSION_MAJOR@_FARSTREAM_LIBRARIES telepathy-qt@QT_VERSION_MAJOR@-farstream) endif(NOT TelepathyQt@QT_VERSION_MAJOR@Farstream_FOUND) telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/TelepathyQtFarstream.pc.in0000664000175000017500000000154612470405660024210 0ustar jrjrprefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${CMAKE_INSTALL_PREFIX} libdir=${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR} includedir=${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR} Name: TelepathyQt${QT_VERSION_MAJOR}Farstream Description: Qt Telepathy Farstream utility library for the Telepathy framework Version: ${PACKAGE_VERSION} Requires.private: Qt${QT_VERSION_PC}Core >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Core < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}DBus >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}DBus < ${QT_MAX_VERSION}, telepathy-glib >= ${TELEPATHY_GLIB_MIN_VERSION}, telepathy-farstream >= ${TELEPATHY_FARSTREAM_MIN_VERSION}, TelepathyQt${QT_VERSION_MAJOR} = ${PACKAGE_VERSION} Libs: -L${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR} -ltelepathy-qt${QT_VERSION_MAJOR}-farstream Cflags: -I${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR}/telepathy-qt${QT_VERSION_MAJOR} telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/PendingChannel0000664000175000017500000000045512470405660021744 0ustar jrjr#ifndef _TelepathyQt_Farstream_PendingChannel_HEADER_GUARD_ #define _TelepathyQt_Farstream_PendingChannel_HEADER_GUARD_ #ifndef IN_TP_QT_FARSTREAM_HEADER #define IN_TP_QT_FARSTREAM_HEADER #endif #include #undef IN_TP_QT_FARSTREAM_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/global.h0000664000175000017500000000263412470405660020556 0ustar jrjr/** * This file is part of TelepathyQt * * Copyright (C) 2009-2012 Collabora Ltd. * Copyright (C) 2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_Farstream_global_h_HEADER_GUARD_ #define _TelepathyQt_Farstream_global_h_HEADER_GUARD_ #ifndef IN_TP_QT_FARSTREAM_HEADER #error IN_TP_QT_FARSTREAM_HEADER #endif #include #ifdef BUILDING_TP_QT_FARSTREAM # define TP_QT_FS_EXPORT Q_DECL_EXPORT #else # define TP_QT_FS_EXPORT Q_DECL_IMPORT #endif #if !defined(Q_OS_WIN) && defined(QT_VISIBILITY_AVAILABLE) # define TP_QT_FS_NO_EXPORT __attribute__((visibility("hidden"))) #endif #ifndef TP_QT_FS_NO_EXPORT # define TP_QT_FS_NO_EXPORT #endif #endif telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/CMakeLists.txt0000664000175000017500000001142012470405660021676 0ustar jrjrif(FARSTREAM_COMPONENTS_FOUND) include_directories(${TELEPATHY_FARSTREAM_INCLUDE_DIR} ${TELEPATHY_GLIB_INCLUDE_DIR} ${FARSTREAM_INCLUDE_DIR} ${GSTREAMER_INCLUDE_DIR} ${GLIB2_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} ${DBUS_INCLUDE_DIR}) # It gets inherited from the previous directory, hence it has to be removed explicitely remove_definitions(-DBUILDING_TP_QT) # We are building Telepathy-Qt-Farstream add_definitions(-DBUILDING_TP_QT_FARSTREAM -DQT_NO_KEYWORDS) set(telepathy_qt_farstream_SRCS channel.cpp) set(telepathy_qt_farstream_HEADERS Channel channel.h Global global.h PendingChannel) set(telepathy_qt_farstream_MOC_SRCS channel.h) # generate client moc files tpqt_generate_mocs(${telepathy_qt_farstream_MOC_SRCS}) # Create the library if (ENABLE_COMPILER_COVERAGE) add_library(telepathy-qt${QT_VERSION_MAJOR}-farstream STATIC ${telepathy_qt_farstream_SRCS} ${telepathy_qt_farstream_MOC_SRCS}) else (ENABLE_COMPILER_COVERAGE) add_library(telepathy-qt${QT_VERSION_MAJOR}-farstream SHARED ${telepathy_qt_farstream_SRCS} ${telepathy_qt_farstream_MOC_SRCS}) endif (ENABLE_COMPILER_COVERAGE) # Link target_link_libraries(telepathy-qt${QT_VERSION_MAJOR}-farstream ${QT_QTDBUS_LIBRARY} ${QT_QTCORE_LIBRARY} ${GOBJECT_LIBRARIES} ${TELEPATHY_FARSTREAM_LIBRARIES} ${TELEPATHY_GLIB_LIBRARIES} telepathy-qt${QT_VERSION_MAJOR} ${TP_QT_LIBRARY_LINKER_FLAGS}) if (ENABLE_COMPILER_COVERAGE) target_link_libraries(telepathy-qt${QT_VERSION_MAJOR}-farstream gcov) endif (ENABLE_COMPILER_COVERAGE) # Set the correct version number set_target_properties(telepathy-qt${QT_VERSION_MAJOR}-farstream PROPERTIES SOVERSION ${TP_QT_ABI_VERSION} VERSION ${TP_QT_LIBRARY_VERSION}) # Install the library - watch out for the correct components if (WIN32) install(TARGETS telepathy-qt${QT_VERSION_MAJOR}-farstream EXPORT TelepathyQt${QT_VERSION_MAJOR}Targets RUNTIME DESTINATION ${LIB_INSTALL_DIR} COMPONENT farstream ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT farstream_libs) else (WIN32) install(TARGETS telepathy-qt${QT_VERSION_MAJOR}-farstream EXPORT TelepathyQt${QT_VERSION_MAJOR}Targets LIBRARY DESTINATION ${LIB_INSTALL_DIR} COMPONENT farstream ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT farstream_libs) endif (WIN32) # Install headers install(FILES ${telepathy_qt_farstream_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/telepathy-qt${QT_VERSION_MAJOR}/TelepathyQt/Farstream COMPONENT farstream_headers) # pkg-config files, only if not on windows if (NOT WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TelepathyQtFarstream.pc.in ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}Farstream.pc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TelepathyQtFarstream-uninstalled.pc.in ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}Farstream-uninstalled.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}Farstream.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig COMPONENT pkgconfig) endif (NOT WIN32) # Configure the actual Config file configure_file(TelepathyQtFarstreamConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}FarstreamConfig.cmake" @ONLY) # this file is used by to check if the installed version can be used. macro_write_basic_cmake_version_file(${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}FarstreamConfigVersion.cmake ${PACKAGE_VERSION}) if(USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) set(_TelepathyQtFarstreamConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/TelepathyQt${QT_VERSION_MAJOR}Farstream) else(USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) set(_TelepathyQtFarstreamConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/TelepathyQt${QT_VERSION_MAJOR}Farstream/cmake) endif(USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}FarstreamConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}FarstreamConfig.cmake DESTINATION ${_TelepathyQtFarstreamConfig_INSTALL_DIR} COMPONENT headers) endif(FARSTREAM_COMPONENTS_FOUND) telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/channel.h0000664000175000017500000000351312470405660020723 0ustar jrjr/** * This file is part of TelepathyQt * * Copyright (C) 2009-2012 Collabora Ltd. * Copyright (C) 2009 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_Farstream_channel_h_HEADER_GUARD_ #define _TelepathyQt_Farstream_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_FARSTREAM_HEADER #error IN_TP_QT_FARSTREAM_HEADER #endif #include #include #include #include typedef struct _TfChannel TfChannel; namespace Tp { namespace Farstream { class TP_QT_FS_EXPORT PendingChannel : public Tp::PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingChannel) public: ~PendingChannel(); TfChannel *tfChannel() const; CallChannelPtr callChannel() const; private: TP_QT_FS_NO_EXPORT PendingChannel(const CallChannelPtr &channel); friend PendingChannel *createChannel(const CallChannelPtr &channel); struct Private; friend struct Private; Private *mPriv; }; TP_QT_FS_EXPORT PendingChannel *createChannel(const CallChannelPtr &channel); } // Farstream } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/Farstream/TelepathyQtFarstream-uninstalled.pc.in0000664000175000017500000000145612470405660026530 0ustar jrjrprefix=/nonexistent exec_prefix=/nonexistent abs_top_builddir=${CMAKE_BINARY_DIR} abs_top_srcdir=${CMAKE_SOURCE_DIR} Name: TelepathyQt${QT_VERSION_MAJOR}Farstream (uninstalled copy) Description: Qt Telepathy Farstream utility library for the Telepathy framework Version: ${PACKAGE_VERSION} Requires.private: Qt${QT_VERSION_PC}Core >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Core < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}DBus >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}DBus < ${QT_MAX_VERSION}, telepathy-glib >= ${TELEPATHY_GLIB_MIN_VERSION}, telepathy-farstream >= ${TELEPATHY_FARSTREAM_MIN_VERSION}, TelepathyQt${QT_VERSION_MAJOR} = ${PACKAGE_VERSION} Libs: ${CMAKE_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}/Farstream/libtelepathy-qt${QT_VERSION_MAJOR}-farstream.so Cflags: -I${CMAKE_SOURCE_DIR} -I${CMAKE_BINARY_DIR} telepathy-qt-0.9.6~git1/TelepathyQt/streamed-media-channel.cpp0000664000175000017500000014464412470405660022224 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/streamed-media-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include namespace Tp { /* ====== PendingStreamedMediaStreams ====== */ struct TP_QT_NO_EXPORT PendingStreamedMediaStreams::Private { StreamedMediaStreams streams; uint numStreams; uint streamsReady; }; /** * \class PendingStreamedMediaStreams * \ingroup clientchannel * \headerfile TelepathyQt/streamed-media-channel.h * * \brief Class containing the result of an asynchronous streamed media stream creation * request. * * Instances of this class cannot be constructed directly; the only way to get * one is via StreamedMediaChannel. * * See \ref async_model */ /** * Construct a new PendingStreamedMediaStreams object. * * \param channel StreamedMediaChannel to use. * \param contact The contact who the media stream is with. * \param types A list of stream types to request. */ PendingStreamedMediaStreams::PendingStreamedMediaStreams(const StreamedMediaChannelPtr &channel, const ContactPtr &contact, const QList &types) : PendingOperation(channel), mPriv(new Private) { mPriv->numStreams = types.size(); mPriv->streamsReady = 0; UIntList l; foreach (MediaStreamType type, types) { l << type; } Client::ChannelTypeStreamedMediaInterface *streamedMediaInterface = channel->interface(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( streamedMediaInterface->RequestStreams( contact->handle()[0], l), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotStreams(QDBusPendingCallWatcher*))); } /** * Class destructor. */ PendingStreamedMediaStreams::~PendingStreamedMediaStreams() { delete mPriv; } /** * Return the channel through which the request was made. * * \return A pointer to the StreamedMediaChannel object. */ StreamedMediaChannelPtr PendingStreamedMediaStreams::channel() const { return StreamedMediaChannelPtr(qobject_cast( (StreamedMediaChannel*) object().data())); } /** * Return a list of the newly created StreamedMediaStreamPtr objects. * * \return A list of pointers to StreamedMediaStream objects, or an empty list if an error occurred. */ StreamedMediaStreams PendingStreamedMediaStreams::streams() const { if (!isFinished()) { warning() << "PendingStreamedMediaStreams::streams called before finished, " "returning empty list"; return StreamedMediaStreams(); } else if (!isValid()) { warning() << "PendingStreamedMediaStreams::streams called when not valid, " "returning empty list"; return StreamedMediaStreams(); } return mPriv->streams; } void PendingStreamedMediaStreams::gotStreams(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "StreamedMedia::RequestStreams()" " failed with " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); watcher->deleteLater(); return; } debug() << "Got reply to StreamedMedia::RequestStreams()"; MediaStreamInfoList list = reply.value(); foreach (const MediaStreamInfo &streamInfo, list) { StreamedMediaStreamPtr stream = channel()->lookupStreamById( streamInfo.identifier); if (!stream) { stream = channel()->addStream(streamInfo); } else { channel()->onStreamDirectionChanged(streamInfo.identifier, streamInfo.direction, streamInfo.pendingSendFlags); channel()->onStreamStateChanged(streamInfo.identifier, streamInfo.state); } mPriv->streams.append(stream); connect(channel().data(), SIGNAL(streamRemoved(Tp::StreamedMediaStreamPtr)), SLOT(onStreamRemoved(Tp::StreamedMediaStreamPtr))); connect(stream->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onStreamReady(Tp::PendingOperation*))); } watcher->deleteLater(); } void PendingStreamedMediaStreams::onStreamRemoved(const StreamedMediaStreamPtr &stream) { if (isFinished()) { return; } if (mPriv->streams.contains(stream)) { // the stream was removed before becoming ready setFinishedWithError(TP_QT_ERROR_CANCELLED, QLatin1String("Stream removed before ready")); } } void PendingStreamedMediaStreams::onStreamReady(PendingOperation *op) { if (isFinished()) { return; } if (op->isError()) { setFinishedWithError(op->errorName(), op->errorMessage()); return; } mPriv->streamsReady++; debug() << "PendingStreamedMediaStreams:"; debug() << " Streams count:" << mPriv->numStreams; debug() << " Streams ready:" << mPriv->streamsReady; if (mPriv->streamsReady == mPriv->numStreams) { debug() << "All streams are ready"; setFinished(); } } /* ====== StreamedMediaStream ====== */ struct TP_QT_NO_EXPORT StreamedMediaStream::Private { Private(StreamedMediaStream *parent, const StreamedMediaChannelPtr &channel, const MediaStreamInfo &info); static void introspectContact(Private *self); PendingOperation *updateDirection(bool send, bool receive); SendingState localSendingStateFromDirection(); SendingState remoteSendingStateFromDirection(); StreamedMediaStream *parent; WeakPtr channel; ReadinessHelper *readinessHelper; uint id; uint type; uint contactHandle; ContactPtr contact; uint direction; uint pendingSend; uint state; }; StreamedMediaStream::Private::Private(StreamedMediaStream *parent, const StreamedMediaChannelPtr &channel, const MediaStreamInfo &streamInfo) : parent(parent), channel(channel), readinessHelper(parent->readinessHelper()), id(streamInfo.identifier), type(streamInfo.type), contactHandle(streamInfo.contact), direction(MediaStreamDirectionNone), pendingSend(0), state(MediaStreamStateDisconnected) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectContact, this); introspectables[FeatureCore] = introspectableCore; readinessHelper->addIntrospectables(introspectables); } void StreamedMediaStream::Private::introspectContact(StreamedMediaStream::Private *self) { debug() << "Introspecting stream"; if (self->contactHandle == 0) { debug() << "Stream ready"; self->readinessHelper->setIntrospectCompleted(FeatureCore, true); return; } debug() << "Introspecting stream contact"; ContactManagerPtr contactManager = self->parent->channel()->connection()->contactManager(); debug() << "contact manager" << contactManager; // TODO: pass id hints to ContactManager if we ever gain support to retrieve contact ids // from MediaStreamInfo or something similar. self->parent->connect(contactManager->contactsForHandles( UIntList() << self->contactHandle), SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotContact(Tp::PendingOperation*))); } PendingOperation *StreamedMediaStream::Private::updateDirection( bool send, bool receive) { uint newDirection = 0; if (send) { newDirection |= MediaStreamDirectionSend; } if (receive) { newDirection |= MediaStreamDirectionReceive; } Client::ChannelTypeStreamedMediaInterface *streamedMediaInterface = parent->channel()->interface(); return new PendingVoid( streamedMediaInterface->RequestStreamDirection( id, newDirection), StreamedMediaStreamPtr(parent)); } StreamedMediaStream::SendingState StreamedMediaStream::Private::localSendingStateFromDirection() { if (pendingSend & MediaStreamPendingLocalSend) { return SendingStatePendingSend; } if (direction & MediaStreamDirectionSend) { return SendingStateSending; } return SendingStateNone; } StreamedMediaStream::SendingState StreamedMediaStream::Private::remoteSendingStateFromDirection() { if (pendingSend & MediaStreamPendingRemoteSend) { return SendingStatePendingSend; } if (direction & MediaStreamDirectionReceive) { return SendingStateSending; } return SendingStateNone; } /** * \class StreamedMediaStream * \ingroup clientchannel * \headerfile TelepathyQt/streamed-media-channel.h * * \brief The StreamedMediaStream class represents a Telepathy streamed media * stream. * * Instances of this class cannot be constructed directly; the only way to get * one is via StreamedMediaChannel. */ /** * Feature representing the core that needs to become ready to make the * StreamedMediaStream object usable. * * Note that this feature must be enabled in order to use most StreamedMediaStream * methods. See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature StreamedMediaStream::FeatureCore = Feature(QLatin1String(StreamedMediaStream::staticMetaObject.className()), 0); /** * Construct a new StreamedMediaStream object. * * \param channel The channel ownding this media stream. * \param streamInfo The stream info of this media stream. */ StreamedMediaStream::StreamedMediaStream(const StreamedMediaChannelPtr &channel, const MediaStreamInfo &streamInfo) : Object(), ReadyObject(this, FeatureCore), mPriv(new Private(this, channel, streamInfo)) { gotDirection(streamInfo.direction, streamInfo.pendingSendFlags); gotStreamState(streamInfo.state); } /** * Class destructor. */ StreamedMediaStream::~StreamedMediaStream() { delete mPriv; } /** * Return the channel owning this media stream. * * \return A pointer to the StreamedMediaChannel object. */ StreamedMediaChannelPtr StreamedMediaStream::channel() const { return StreamedMediaChannelPtr(mPriv->channel); } /** * Return the id of this media stream. * * \return An integer representing the media stream id. */ uint StreamedMediaStream::id() const { return mPriv->id; } /** * Return the contact who this media stream is with. * * \return A pointer to the Contact object. */ ContactPtr StreamedMediaStream::contact() const { return mPriv->contact; } /** * Return the state of this media stream. * * \return The state as #MediaStreamState. */ MediaStreamState StreamedMediaStream::state() const { return (MediaStreamState) mPriv->state; } /** * Return the type of this media stream. * * \return The type as #MediaStreamType. */ MediaStreamType StreamedMediaStream::type() const { return (MediaStreamType) mPriv->type; } /** * Return whether media is being sent on this media stream. * * \return \c true if media is being sent, \c false otherwise. * \sa localSendingStateChanged() */ bool StreamedMediaStream::sending() const { return mPriv->direction & MediaStreamDirectionSend; } /** * Return whether media is being received on this media stream. * * \return \c true if media is being received, \c false otherwise. * \sa remoteSendingStateChanged() */ bool StreamedMediaStream::receiving() const { return mPriv->direction & MediaStreamDirectionReceive; } /** * Return whether the local user has been asked to send media by the * remote user on this media stream. * * \return \c true if the local user has been asked to send media by the * remote user, \c false otherwise. * \sa localSendingStateChanged() */ bool StreamedMediaStream::localSendingRequested() const { return mPriv->pendingSend & MediaStreamPendingLocalSend; } /** * Return whether the remote user has been asked to send media by the local * user on this media stream. * * \return \c true if the remote user has been asked to send media by the * local user, \c false otherwise. * \sa remoteSendingStateChanged() */ bool StreamedMediaStream::remoteSendingRequested() const { return mPriv->pendingSend & MediaStreamPendingRemoteSend; } /** * Return the direction of this media stream. * * \return The direction as #MediaStreamDirection. * \sa localSendingState(), remoteSendingState(), * localSendingStateChanged(), remoteSendingStateChanged(), * sending(), receiving() */ MediaStreamDirection StreamedMediaStream::direction() const { return (MediaStreamDirection) mPriv->direction; } /** * Return the pending send flags of this media stream. * * \return The pending send flags as #MediaStreamPendingSend. * \sa localSendingStateChanged() */ MediaStreamPendingSend StreamedMediaStream::pendingSend() const { return (MediaStreamPendingSend) mPriv->pendingSend; } /** * Request a change in the direction of this media stream. In particular, this * might be useful to stop sending media of a particular type, or inform the * peer that you are no longer using media that is being sent to you. * * \param direction The new direction. * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa localSendingStateChanged(), remoteSendingStateChanged() */ PendingOperation *StreamedMediaStream::requestDirection( MediaStreamDirection direction) { StreamedMediaChannelPtr chan(channel()); Client::ChannelTypeStreamedMediaInterface *streamedMediaInterface = chan->interface(); return new PendingVoid( streamedMediaInterface->RequestStreamDirection( mPriv->id, direction), StreamedMediaStreamPtr(this)); } /** * Start sending a DTMF tone on this media stream. * * Where possible, the tone will continue until stopDTMFTone() is called. * On certain protocols, it may only be possible to send events with a predetermined * length. In this case, the implementation may emit a fixed-length tone, * and the stopDTMFTone() method call should return #TP_QT_ERROR_NOT_AVAILABLE. * * If the channel() does not support the #TP_QT_IFACE_CHANNEL_INTERFACE_DTMF * interface, the resulting PendingOperation will fail with error code * #TP_QT_ERROR_NOT_IMPLEMENTED. * \param event A numeric event code from the #DTMFEvent enum. * \return A PendingOperation which will emit PendingOperation::finished * when the request finishes. * \sa stopDTMFTone() */ PendingOperation *StreamedMediaStream::startDTMFTone(DTMFEvent event) { StreamedMediaChannelPtr chan(channel()); if (!chan->interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_DTMF)) { warning() << "StreamedMediaStream::startDTMFTone() used with no dtmf interface"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("StreamedMediaChannel does not support dtmf interface"), StreamedMediaStreamPtr(this)); } Client::ChannelInterfaceDTMFInterface *dtmfInterface = chan->interface(); return new PendingVoid( dtmfInterface->StartTone(mPriv->id, event), StreamedMediaStreamPtr(this)); } /** * Stop sending any DTMF tone which has been started using the startDTMFTone() * method. * * If there is no current tone, the resulting PendingOperation will * finish successfully. * * If continuous tones are not supported by this media stream, the resulting * PendingOperation will fail with error code #TP_QT_ERROR_NOT_AVAILABLE. * * If the channel() does not support the #TP_QT_IFACE_CHANNEL_INTERFACE_DTMF * interface, the resulting PendingOperation will fail with error code * #TP_QT_ERROR_NOT_IMPLEMENTED. * * \return A PendingOperation which will emit PendingOperation::finished * when the request finishes. * \sa startDTMFTone() */ PendingOperation *StreamedMediaStream::stopDTMFTone() { StreamedMediaChannelPtr chan(channel()); if (!chan->interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_DTMF)) { warning() << "StreamedMediaStream::stopDTMFTone() used with no dtmf interface"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("StreamedMediaChannel does not support dtmf interface"), StreamedMediaStreamPtr(this)); } Client::ChannelInterfaceDTMFInterface *dtmfInterface = chan->interface(); return new PendingVoid( dtmfInterface->StopTone(mPriv->id), StreamedMediaStreamPtr(this)); } /** * Request a change in the direction of this media stream. * * In particular, this might be useful to stop sending media of a particular type, * or inform the peer that you are no longer using media that is being sent to you. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa requestDirection(Tp::MediaStreamDirection direction), * localSendingStateChanged(), remoteSendingStateChanged() */ PendingOperation *StreamedMediaStream::requestDirection(bool send, bool receive) { uint dir = MediaStreamDirectionNone; if (send) { dir |= MediaStreamDirectionSend; } if (receive) { dir |= MediaStreamDirectionReceive; } return requestDirection((MediaStreamDirection) dir); } /** * Return the media stream local sending state. * * \return The local sending state as StreamedMediaStream::SendingState. * \sa localSendingStateChanged() */ StreamedMediaStream::SendingState StreamedMediaStream::localSendingState() const { return mPriv->localSendingStateFromDirection(); } /** * Return the media stream remote sending state. * * \return The remote sending state as StreamedMediaStream::SendingState. * \sa remoteSendingStateChanged() */ StreamedMediaStream::SendingState StreamedMediaStream::remoteSendingState() const { return mPriv->remoteSendingStateFromDirection(); } /** * Request that media starts or stops being sent on this media stream. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa localSendingStateChanged(), requestDirection() */ PendingOperation *StreamedMediaStream::requestSending(bool send) { return mPriv->updateDirection( send, mPriv->direction & MediaStreamDirectionReceive); } /** * Request that the remote contact stops or starts sending on this media stream. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa remoteSendingStateChanged(), requestDirection() */ PendingOperation *StreamedMediaStream::requestReceiving(bool receive) { return mPriv->updateDirection( mPriv->direction & MediaStreamDirectionSend, receive); } /** * \fn void StreamedMediaStream::localSendingStateChanged( * Tp::StreamedMediaStream::SendingState localSendingState) * * Emitted when the local sending state of this media stream changes. * * \param localSendingState The new local sending state of this media stream. * \sa localSendingState() */ /** * \fn void MediaStream::remoteSendingStateChanged( * Tp::MediaStream::SendingState &remoteSendingState) * * Emitted when the remote sending state of this media stream changes. * * \param remoteSendingState The new remote sending state of this media stream. * \sa remoteSendingState() */ void StreamedMediaStream::gotContact(PendingOperation *op) { PendingContacts *pc = qobject_cast(op); Q_ASSERT(pc->isForHandles()); if (op->isError()) { warning().nospace() << "Gathering media stream contact failed: " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, op->errorName(), op->errorMessage()); return; } QList contacts = pc->contacts(); UIntList invalidHandles = pc->invalidHandles(); if (contacts.size()) { Q_ASSERT(contacts.size() == 1); Q_ASSERT(invalidHandles.size() == 0); mPriv->contact = contacts.first(); debug() << "Got stream contact"; debug() << "Stream ready"; mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } else { Q_ASSERT(invalidHandles.size() == 1); warning().nospace() << "Error retrieving media stream contact (invalid handle)"; mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid contact handle")); } } void StreamedMediaStream::gotDirection(uint direction, uint pendingSend) { if (direction == mPriv->direction && pendingSend == mPriv->pendingSend) { return; } SendingState oldLocalState = mPriv->localSendingStateFromDirection(); SendingState oldRemoteState = mPriv->remoteSendingStateFromDirection(); mPriv->direction = direction; mPriv->pendingSend = pendingSend; if (!isReady()) { return; } SendingState localSendingState = mPriv->localSendingStateFromDirection(); if (localSendingState != oldLocalState) { emit localSendingStateChanged(localSendingState); } SendingState remoteSendingState = mPriv->remoteSendingStateFromDirection(); if (remoteSendingState != oldRemoteState) { emit remoteSendingStateChanged(remoteSendingState); } } void StreamedMediaStream::gotStreamState(uint state) { if (state == mPriv->state) { return; } mPriv->state = state; } /* ====== StreamedMediaChannel ====== */ struct TP_QT_NO_EXPORT StreamedMediaChannel::Private { Private(StreamedMediaChannel *parent); ~Private(); static void introspectStreams(Private *self); static void introspectLocalHoldState(Private *self); // Public object StreamedMediaChannel *parent; // Mandatory properties interface proxy Client::DBus::PropertiesInterface *properties; ReadinessHelper *readinessHelper; // Introspection StreamedMediaStreams incompleteStreams; StreamedMediaStreams streams; LocalHoldState localHoldState; LocalHoldStateReason localHoldStateReason; }; StreamedMediaChannel::Private::Private(StreamedMediaChannel *parent) : parent(parent), properties(parent->interface()), readinessHelper(parent->readinessHelper()), localHoldState(LocalHoldStateUnheld), localHoldStateReason(LocalHoldStateReasonNone) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableStreams( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectStreams, this); introspectables[FeatureStreams] = introspectableStreams; ReadinessHelper::Introspectable introspectableLocalHoldState( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList() << TP_QT_IFACE_CHANNEL_INTERFACE_HOLD, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectLocalHoldState, this); introspectables[FeatureLocalHoldState] = introspectableLocalHoldState; readinessHelper->addIntrospectables(introspectables); } StreamedMediaChannel::Private::~Private() { } void StreamedMediaChannel::Private::introspectStreams(StreamedMediaChannel::Private *self) { StreamedMediaChannel *parent = self->parent; Client::ChannelTypeStreamedMediaInterface *streamedMediaInterface = parent->interface(); parent->connect(streamedMediaInterface, SIGNAL(StreamAdded(uint,uint,uint)), SLOT(onStreamAdded(uint,uint,uint))); parent->connect(streamedMediaInterface, SIGNAL(StreamRemoved(uint)), SLOT(onStreamRemoved(uint))); parent->connect(streamedMediaInterface, SIGNAL(StreamDirectionChanged(uint,uint,uint)), SLOT(onStreamDirectionChanged(uint,uint,uint))); parent->connect(streamedMediaInterface, SIGNAL(StreamStateChanged(uint,uint)), SLOT(onStreamStateChanged(uint,uint))); parent->connect(streamedMediaInterface, SIGNAL(StreamError(uint,uint,QString)), SLOT(onStreamError(uint,uint,QString))); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( streamedMediaInterface->ListStreams(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), SLOT(gotStreams(QDBusPendingCallWatcher *))); } void StreamedMediaChannel::Private::introspectLocalHoldState(StreamedMediaChannel::Private *self) { StreamedMediaChannel *parent = self->parent; Client::ChannelInterfaceHoldInterface *holdInterface = parent->interface(); parent->connect(holdInterface, SIGNAL(HoldStateChanged(uint,uint)), SLOT(onLocalHoldStateChanged(uint,uint))); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( holdInterface->GetHoldState(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotLocalHoldState(QDBusPendingCallWatcher*))); } /** * \class StreamedMediaChannel * \ingroup clientchannel * \headerfile TelepathyQt/streamed-media-channel.h * * \brief The StreamedMediaChannel class represents a Telepathy channel of type StreamedMedia. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * StreamedMediaChannel object usable. * * This is currently the same as Channel::FeatureCore, but may change to include more. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. * \sa awaitingLocalAnswer(), awaitingRemoteAnswer(), acceptCall(), hangupCall(), handlerStreamingRequired() */ const Feature StreamedMediaChannel::FeatureCore = Feature(QLatin1String(Channel::staticMetaObject.className()), 0, true); /** * Feature used in order to access media stream specific methods. * * See media stream specific methods' documentation for more details. * \sa streams(), streamsForType(), * requestStream(), requestStreams(), streamAdded() * removeStream(), removeStreams(), streamRemoved(), * streamDirectionChanged(), streamStateChanged(), streamError() */ const Feature StreamedMediaChannel::FeatureStreams = Feature(QLatin1String(StreamedMediaChannel::staticMetaObject.className()), 0); /** * Feature used in order to access local hold state info. * * See local hold state specific methods' documentation for more details. * \sa localHoldState(), localHoldStateReason(), requestHold(), localHoldStateChanged() */ const Feature StreamedMediaChannel::FeatureLocalHoldState = Feature(QLatin1String(StreamedMediaChannel::staticMetaObject.className()), 1); /** * Create a new StreamedMediaChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A StreamedMediaChannelPtr object pointing to the newly created * StreamedMediaChannel object. */ StreamedMediaChannelPtr StreamedMediaChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return StreamedMediaChannelPtr(new StreamedMediaChannel(connection, objectPath, immutableProperties, StreamedMediaChannel::FeatureCore)); } /** * Construct a new StreamedMediaChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on StreamedMediaChannel::FeatureCore. */ StreamedMediaChannel::StreamedMediaChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : Channel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ StreamedMediaChannel::~StreamedMediaChannel() { delete mPriv; } /** * Return a list of media streams in this channel. * * This methods requires StreamedMediaChannel::FeatureStreams to be ready. * * \return A list of pointers to StreamedMediaStream objects. * \sa streamAdded(), streamRemoved(), streamsForType(), requestStreams() */ StreamedMediaStreams StreamedMediaChannel::streams() const { return mPriv->streams; } /** * Return a list of media streams in this channel for the given type \a type. * * This methods requires StreamedMediaChannel::FeatureStreams to be ready. * * \param type The interested type. * \return A list of pointers to StreamedMediaStream objects. * \sa streamAdded(), streamRemoved(), streams(), requestStreams() */ StreamedMediaStreams StreamedMediaChannel::streamsForType(MediaStreamType type) const { StreamedMediaStreams ret; foreach (const StreamedMediaStreamPtr &stream, mPriv->streams) { if (stream->type() == type) { ret << stream; } } return ret; } /** * Return whether this channel is awaiting local answer. * * This method requires StreamedMediaChannel::FeatureCore to be ready. * * \return \c true if awaiting local answer, \c false otherwise. * \sa awaitingRemoteAnswer(), acceptCall() */ bool StreamedMediaChannel::awaitingLocalAnswer() const { return groupSelfHandleIsLocalPending(); } /** * Return whether this channel is awaiting remote answer. * * This method requires StreamedMediaChannel::FeatureCore to be ready. * * \return \c true if awaiting remote answer, \c false otherwise. * \sa awaitingLocalAnswer() */ bool StreamedMediaChannel::awaitingRemoteAnswer() const { return !groupRemotePendingContacts().isEmpty(); } /** * Accept an incoming call. * * This method requires StreamedMediaChannel::FeatureCore to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa awaitingLocalAnswer(), hangupCall() */ PendingOperation *StreamedMediaChannel::acceptCall() { return groupAddSelfHandle(); } /** * Remove the specified media stream from this channel. * * This methods requires StreamedMediaChannel::FeatureStreams to be ready. * * \param stream Media stream to remove. * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa streamRemoved(), streams(), streamsForType() */ PendingOperation *StreamedMediaChannel::removeStream(const StreamedMediaStreamPtr &stream) { if (!stream) { return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Unable to remove a null stream"), StreamedMediaChannelPtr(this)); } // StreamedMedia.RemoveStreams will trigger StreamedMedia.StreamRemoved // that will proper remove the stream Client::ChannelTypeStreamedMediaInterface *streamedMediaInterface = interface(); return new PendingVoid( streamedMediaInterface->RemoveStreams( UIntList() << stream->id()), StreamedMediaChannelPtr(this)); } /** * Remove the specified media streams from this channel. * * This methods requires StreamedMediaChannel::FeatureStreams to be ready. * * \param streams List of media streams to remove. * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa streamRemoved(), streams(), streamsForType() */ PendingOperation *StreamedMediaChannel::removeStreams(const StreamedMediaStreams &streams) { UIntList ids; foreach (const StreamedMediaStreamPtr &stream, streams) { if (!stream) { continue; } ids << stream->id(); } if (ids.isEmpty()) { return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Unable to remove invalid streams"), StreamedMediaChannelPtr(this)); } Client::ChannelTypeStreamedMediaInterface *streamedMediaInterface = interface(); return new PendingVoid( streamedMediaInterface->RemoveStreams(ids), StreamedMediaChannelPtr(this)); } /** * Request that media streams be established to exchange the given type \a type * of media with the given contact \a contact. * * This methods requires StreamedMediaChannel::FeatureStreams to be ready. * * \return A PendingStreamedMediaStreams which will emit PendingStreamedMediaStreams::finished * when the call has finished. * \sa streamAdded(), streams(), streamsForType() */ PendingStreamedMediaStreams *StreamedMediaChannel::requestStream( const ContactPtr &contact, MediaStreamType type) { return new PendingStreamedMediaStreams(StreamedMediaChannelPtr(this), contact, QList() << type); } /** * Request that media streams be established to exchange the given types \a * types of media with the given contact \a contact. * * This methods requires StreamedMediaChannel::FeatureStreams to be ready. * * \return A PendingStreamedMediaStreams which will emit PendingStreamedMediaStreams::finished * when the call has finished. * \sa streamAdded(), streams(), streamsForType() */ PendingStreamedMediaStreams *StreamedMediaChannel::requestStreams( const ContactPtr &contact, QList types) { return new PendingStreamedMediaStreams(StreamedMediaChannelPtr(this), contact, types); } /** * Request that the call is ended. * * This method requires StreamedMediaChannel::FeatureCore to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *StreamedMediaChannel::hangupCall() { return requestLeave(); } /** * Check whether media streaming by the handler is required for this channel. * * For channels with the #TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING interface, * the main handler of the channel is responsible for doing the actual streaming, for instance by * calling createFarsightChannel(channel) from TelepathyQt-Farsight library * and using the telepathy-farsight API on the resulting TfChannel. * * This method requires StreamedMediaChannel::FeatureCore to be ready. * * \return \c true if required, \c false otherwise. */ bool StreamedMediaChannel::handlerStreamingRequired() const { return interfaces().contains( TP_QT_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING); } /** * Return the local hold state for this channel. * * Whether the local user has placed this channel on hold. * * This method requires StreamedMediaChannel::FeatureHoldState to be ready. * * \return The local hold state as #LocalHoldState. * \sa requestHold(), localHoldStateChanged() */ LocalHoldState StreamedMediaChannel::localHoldState() const { if (!isReady(FeatureLocalHoldState)) { warning() << "StreamedMediaChannel::localHoldState() used with FeatureLocalHoldState not ready"; } else if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD)) { warning() << "StreamedMediaChannel::localHoldStateReason() used with no hold interface"; } return mPriv->localHoldState; } /** * Return the reason why localHoldState() changed to its current value. * * This method requires StreamedMediaChannel::FeatureLocalHoldState to be ready. * * \return The local hold state reason as #LocalHoldStateReason. * \sa requestHold(), localHoldStateChanged() */ LocalHoldStateReason StreamedMediaChannel::localHoldStateReason() const { if (!isReady(FeatureLocalHoldState)) { warning() << "StreamedMediaChannel::localHoldStateReason() used with FeatureLocalHoldState not ready"; } else if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD)) { warning() << "StreamedMediaChannel::localHoldStateReason() used with no hold interface"; } return mPriv->localHoldStateReason; } /** * Request that the channel be put on hold (be instructed not to send any media * streams to you) or be taken off hold. * * If the CM can immediately tell that the requested state * change could not possibly succeed, the resulting PendingOperation will fail * with error code #TP_QT_ERROR_NOT_AVAILABLE. * If the requested state is the same as the current state, the resulting * PendingOperation will finish successfully. * * Otherwise, the channel's local hold state will change to * #LocalHoldStatePendingHold or #LocalHoldStatePendingUnhold (as * appropriate), then the resulting PendingOperation will finish successfully. * * The eventual success or failure of the request is indicated by a subsequent * localHoldStateChanged() signal, changing the local hold state to * #LocalHoldStateHeld or #LocalHoldStateUnheld. * * If the channel has multiple streams, and the connection manager succeeds in * changing the hold state of one stream but fails to change the hold state of * another, it will attempt to revert all streams to their previous hold * states. * * If the channel does not support the #TP_QT_IFACE_CHANNEL_INTERFACE_HOLD * interface, the PendingOperation will fail with error code * #TP_QT_ERROR_NOT_IMPLEMENTED. * * \param hold A boolean indicating whether or not the channel should be on hold * \return A PendingOperation which will emit PendingOperation::finished * when the request finishes. * \sa localHoldState(), localHoldStateReason(), localHoldStateChanged() */ PendingOperation *StreamedMediaChannel::requestHold(bool hold) { if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD)) { warning() << "StreamedMediaChannel::requestHold() used with no hold interface"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("StreamedMediaChannel does not support hold interface"), StreamedMediaChannelPtr(this)); } Client::ChannelInterfaceHoldInterface *holdInterface = interface(); return new PendingVoid(holdInterface->RequestHold(hold), StreamedMediaChannelPtr(this)); } /** * \fn void StreamedMediaChannel::streamAdded(const Tp::StreamedMediaStreamPtr &stream) * * Emitted when a media stream is added to this channel. * * \param stream The media stream that was added. * \sa streams(), streamsForType(), streamRemoved() */ /** * \fn void StreamedMediaChannel::streamRemoved(const Tp::StreamedMediaStreamPtr &stream) * * Emitted when a media stream is removed from this channel. * * \param stream The media stream that was removed. * \sa streams(), streamsForType(), streamAdded() */ /** * \fn void StreamedMediaChannel::streamDirectionChanged( * const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamDirection direction, * Tp::MediaStreamPendingSend pendingSend) * * Emitted when a media stream direction changes. * * \param stream The media stream which the direction changed. * \param direction The new direction of the stream that changed. * \param pendingSend The new pending send flags of the stream that changed. * \sa StreamedMediaStream::direction() */ /** * \fn void StreamedMediaChannel::streamStateChanged( * const Tp::StreamedMediaStreamPtr &stream, Tp::MediaStreamState state) * * Emitted when a media stream state changes. * * \param stream The media stream which the state changed. * \param state The new state of the stream that changed. * \sa StreamedMediaStream::state() */ /** * \fn void StreamedMediaChannel::streamError( * const Tp::StreamedMediaStreamPtr &stream, * Tp::StreamedMediaStreamError errorCode, const QString &errorMessage) * * Emitted when an error occurs on a media stream. * * \param stream The media stream which the error occurred. * \param errorCode The error code. * \param errorMessage The error message. */ /** * \fn void StreamedMediaChannel::localHoldStateChanged(Tp::LocalHoldState state, Tp::LocalHoldStateReason reason); * * Emitted when the local hold state of this channel changes. * * \param state The new local hold state of this channel. * \param reason The reason why the change occurred. * \sa localHoldState(), localHoldStateReason() */ void StreamedMediaChannel::onStreamReady(PendingOperation *op) { PendingReady *pr = qobject_cast(op); StreamedMediaStreamPtr stream = StreamedMediaStreamPtr::qObjectCast(pr->proxy()); if (op->isError()) { mPriv->incompleteStreams.removeOne(stream); if (!isReady(FeatureStreams) && mPriv->incompleteStreams.size() == 0) { // let's not fail because a stream could not become ready mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true); } return; } // the stream was removed before become ready if (!mPriv->incompleteStreams.contains(stream)) { if (!isReady(FeatureStreams) && mPriv->incompleteStreams.size() == 0) { mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true); } return; } mPriv->incompleteStreams.removeOne(stream); mPriv->streams.append(stream); if (isReady(FeatureStreams)) { emit streamAdded(stream); } if (!isReady(FeatureStreams) && mPriv->incompleteStreams.size() == 0) { mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true); } } void StreamedMediaChannel::gotStreams(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "StreamedMedia.ListStreams failed with" << reply.error().name() << ": " << reply.error().message(); mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, false, reply.error()); watcher->deleteLater(); return; } debug() << "Got reply to StreamedMedia::ListStreams()"; MediaStreamInfoList streamInfoList = reply.value(); if (streamInfoList.size() > 0) { foreach (const MediaStreamInfo &streamInfo, streamInfoList) { StreamedMediaStreamPtr stream = lookupStreamById( streamInfo.identifier); if (!stream) { addStream(streamInfo); } else { onStreamDirectionChanged(streamInfo.identifier, streamInfo.direction, streamInfo.pendingSendFlags); onStreamStateChanged(streamInfo.identifier, streamInfo.state); } } } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true); } watcher->deleteLater(); } void StreamedMediaChannel::onStreamAdded(uint streamId, uint contactHandle, uint streamType) { if (lookupStreamById(streamId)) { debug() << "Received StreamedMedia.StreamAdded for an existing " "stream, ignoring"; return; } MediaStreamInfo streamInfo = { streamId, contactHandle, streamType, MediaStreamStateDisconnected, MediaStreamDirectionReceive, MediaStreamPendingLocalSend }; addStream(streamInfo); } void StreamedMediaChannel::onStreamRemoved(uint streamId) { debug() << "Received StreamedMedia.StreamRemoved for stream" << streamId; StreamedMediaStreamPtr stream = lookupStreamById(streamId); if (!stream) { return; } bool incomplete = mPriv->incompleteStreams.contains(stream); if (incomplete) { mPriv->incompleteStreams.removeOne(stream); } else { mPriv->streams.removeOne(stream); } if (isReady(FeatureStreams) && !incomplete) { emit streamRemoved(stream); } // the stream was added/removed before become ready if (!isReady(FeatureStreams) && mPriv->streams.size() == 0 && mPriv->incompleteStreams.size() == 0) { mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true); } } void StreamedMediaChannel::onStreamDirectionChanged(uint streamId, uint streamDirection, uint streamPendingFlags) { debug() << "Received StreamedMedia.StreamDirectionChanged for stream" << streamId << "with direction changed to" << streamDirection; StreamedMediaStreamPtr stream = lookupStreamById(streamId); if (!stream) { return; } uint oldDirection = stream->direction(); uint oldPendingFlags = stream->pendingSend(); stream->gotDirection(streamDirection, streamPendingFlags); if (oldDirection != streamDirection || oldPendingFlags != streamPendingFlags) { emit streamDirectionChanged(stream, (MediaStreamDirection) streamDirection, (MediaStreamPendingSend) streamPendingFlags); } } void StreamedMediaChannel::onStreamStateChanged(uint streamId, uint streamState) { debug() << "Received StreamedMedia.StreamStateChanged for stream" << streamId << "with state changed to" << streamState; StreamedMediaStreamPtr stream = lookupStreamById(streamId); if (!stream) { return; } uint oldState = stream->state(); stream->gotStreamState(streamState); if (oldState != streamState) { emit streamStateChanged(stream, (MediaStreamState) streamState); } } void StreamedMediaChannel::onStreamError(uint streamId, uint errorCode, const QString &errorMessage) { debug() << "Received StreamedMedia.StreamError for stream" << streamId << "with error code" << errorCode << "and message:" << errorMessage; StreamedMediaStreamPtr stream = lookupStreamById(streamId); if (!stream) { return; } emit streamError(stream, (MediaStreamError) errorCode, errorMessage); } void StreamedMediaChannel::gotLocalHoldState(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "StreamedMedia::Hold::GetHoldState()" " failed with " << reply.error().name() << ": " << reply.error().message(); debug() << "Ignoring error getting hold state and assuming we're not " "on hold"; onLocalHoldStateChanged(mPriv->localHoldState, mPriv->localHoldStateReason); watcher->deleteLater(); return; } debug() << "Got reply to StreamedMedia::Hold::GetHoldState()"; onLocalHoldStateChanged(reply.argumentAt<0>(), reply.argumentAt<1>()); watcher->deleteLater(); } void StreamedMediaChannel::onLocalHoldStateChanged(uint localHoldState, uint localHoldStateReason) { bool changed = false; if (mPriv->localHoldState != static_cast(localHoldState) || mPriv->localHoldStateReason != static_cast(localHoldStateReason)) { changed = true; } mPriv->localHoldState = static_cast(localHoldState); mPriv->localHoldStateReason = static_cast(localHoldStateReason); if (!isReady(FeatureLocalHoldState)) { mPriv->readinessHelper->setIntrospectCompleted(FeatureLocalHoldState, true); } else { if (changed) { emit localHoldStateChanged(mPriv->localHoldState, mPriv->localHoldStateReason); } } } StreamedMediaStreamPtr StreamedMediaChannel::addStream(const MediaStreamInfo &streamInfo) { StreamedMediaStreamPtr stream = StreamedMediaStreamPtr( new StreamedMediaStream(StreamedMediaChannelPtr(this), streamInfo)); mPriv->incompleteStreams.append(stream); connect(stream->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onStreamReady(Tp::PendingOperation*))); return stream; } StreamedMediaStreamPtr StreamedMediaChannel::lookupStreamById(uint streamId) { foreach (const StreamedMediaStreamPtr &stream, mPriv->streams) { if (stream->id() == streamId) { return stream; } } foreach (const StreamedMediaStreamPtr &stream, mPriv->incompleteStreams) { if (stream->id() == streamId) { return stream; } } return StreamedMediaStreamPtr(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/account-set.h0000664000175000017500000000446512470405660017623 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_account_set_h_HEADER_GUARD_ #define _TelepathyQt_account_set_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include namespace Tp { class TP_QT_EXPORT AccountSet : public Object { Q_OBJECT Q_DISABLE_COPY(AccountSet) Q_PROPERTY(AccountManagerPtr accountManager READ accountManager) Q_PROPERTY(AccountFilterConstPtr filter READ filter) Q_PROPERTY(QList accounts READ accounts) public: AccountSet(const AccountManagerPtr &accountManager, const AccountFilterConstPtr &filter); AccountSet(const AccountManagerPtr &accountManager, const QVariantMap &filter); virtual ~AccountSet(); AccountManagerPtr accountManager() const; AccountFilterConstPtr filter() const; QList accounts() const; Q_SIGNALS: void accountAdded(const Tp::AccountPtr &account); void accountRemoved(const Tp::AccountPtr &account); private Q_SLOTS: TP_QT_NO_EXPORT void onNewAccount(const Tp::AccountPtr &account); TP_QT_NO_EXPORT void onAccountRemoved(const Tp::AccountPtr &account); TP_QT_NO_EXPORT void onAccountChanged(const Tp::AccountPtr &account); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/presence.h0000664000175000017500000001326512470405660017200 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_presence_h_HEADER_GUARD_ #define _TelepathyQt_presence_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT Presence { public: Presence(); Presence(const SimplePresence &sp); Presence(ConnectionPresenceType type, const QString &status, const QString &statusMessage); Presence(const Presence &other); ~Presence(); static Presence available(const QString &statusMessage = QString()); static Presence chat(const QString &statusMessage = QString()); static Presence away(const QString &statusMessage = QString()); static Presence brb(const QString &statusMessage = QString()); static Presence busy(const QString &statusMessage = QString()); static Presence dnd(const QString &statusMessage = QString()); static Presence xa(const QString &statusMessage = QString()); static Presence hidden(const QString &statusMessage = QString()); static Presence offline(const QString &statusMessage = QString()); bool isValid() const { return mPriv.constData() != 0; } Presence &operator=(const Presence &other); bool operator==(const Presence &other) const; bool operator!=(const Presence &other) const; ConnectionPresenceType type() const; QString status() const; QString statusMessage() const; void setStatus(const SimplePresence &value); void setStatus(ConnectionPresenceType type, const QString &status, const QString &statusMessage); void setStatusMessage(const QString &statusMessage); SimplePresence barePresence() const; private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; class TP_QT_EXPORT PresenceSpec { public: enum SimpleStatusFlag { NoFlags = 0, MaySetOnSelf = 0x1, CanHaveStatusMessage = 0x2, AllFlags = MaySetOnSelf | CanHaveStatusMessage }; Q_DECLARE_FLAGS(SimpleStatusFlags, SimpleStatusFlag); PresenceSpec(); PresenceSpec(const QString &status, const SimpleStatusSpec &spec); PresenceSpec(const PresenceSpec &other); ~PresenceSpec(); static PresenceSpec available(SimpleStatusFlags flags = AllFlags); static PresenceSpec chat(SimpleStatusFlags flags = AllFlags); static PresenceSpec pstn(SimpleStatusFlags flags = CanHaveStatusMessage); static PresenceSpec away(SimpleStatusFlags flags = AllFlags); static PresenceSpec brb(SimpleStatusFlags flags = AllFlags); static PresenceSpec dnd(SimpleStatusFlags flags = AllFlags); static PresenceSpec busy(SimpleStatusFlags flags = AllFlags); static PresenceSpec xa(SimpleStatusFlags flags = AllFlags); static PresenceSpec hidden(SimpleStatusFlags flags = AllFlags); static PresenceSpec offline(SimpleStatusFlags flags = CanHaveStatusMessage); static PresenceSpec unknown(SimpleStatusFlags flags = CanHaveStatusMessage); static PresenceSpec error(SimpleStatusFlags flags = CanHaveStatusMessage); bool isValid() const { return mPriv.constData() != 0; } PresenceSpec &operator=(const PresenceSpec &other); bool operator==(const PresenceSpec &other) const; bool operator!=(const PresenceSpec &other) const; bool operator<(const PresenceSpec &other) const; Presence presence(const QString &statusMessage = QString()) const; bool maySetOnSelf() const; bool canHaveStatusMessage() const; SimpleStatusSpec bareSpec() const; private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; class TP_QT_EXPORT PresenceSpecList : public QList { public: PresenceSpecList() { } PresenceSpecList(const SimpleStatusSpecMap &specMap) { SimpleStatusSpecMap::const_iterator i = specMap.constBegin(); SimpleStatusSpecMap::const_iterator end = specMap.end(); for (; i != end; ++i) { QString status = i.key(); SimpleStatusSpec spec = i.value(); append(PresenceSpec(status, spec)); } } PresenceSpecList(const QList &other) : QList(other) { } QMap toMap() const { QMap ret; Q_FOREACH (const PresenceSpec &spec, *this) { ret.insert(spec.presence().status(), spec); } return ret; } SimpleStatusSpecMap bareSpecs() const { SimpleStatusSpecMap ret; Q_FOREACH (const PresenceSpec &spec, *this) { ret.insert(spec.presence().status(), spec.bareSpec()); } return ret; } }; Q_DECLARE_OPERATORS_FOR_FLAGS(PresenceSpec::SimpleStatusFlags) } // Tp Q_DECLARE_METATYPE(Tp::Presence); Q_DECLARE_METATYPE(Tp::PresenceSpec); Q_DECLARE_METATYPE(Tp::PresenceSpecList); #endif telepathy-qt-0.9.6~git1/TelepathyQt/call-content-media-description.cpp0000664000175000017500000000215512470405660023704 0ustar jrjr/* * This file is part of TelepathyQt4 * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/cli-call-content-media-description-body.hpp" #include "TelepathyQt/_gen/cli-call-content-media-description.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/OrFilter0000664000175000017500000000034712470405660016671 0ustar jrjr#ifndef _TelepathyQt_OrFilter_HEADER_GUARD_ #define _TelepathyQt_OrFilter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/svc-connection-manager.xml0000664000175000017500000000073012470405660022276 0ustar jrjr Connection Manager interfaces telepathy-qt-0.9.6~git1/TelepathyQt/contact-manager.cpp0000664000175000017500000016534312470405660020777 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/contact-manager-internal.h" #include "TelepathyQt/_gen/contact-manager.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/future-internal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ContactManager::Private { Private(ContactManager *parent, Connection *connection); ~Private(); // avatar specific methods bool buildAvatarFileName(QString token, bool createDir, QString &avatarFileName, QString &mimeTypeFileName); Features realFeatures(const Features &features); QSet interfacesForFeatures(const Features &features); ContactManager *parent; WeakPtr connection; ContactManager::Roster *roster; QHash > contacts; QHash tracking; Features supportedFeatures; // avatar QSet requestAvatarsQueue; bool requestAvatarsIdle; // contact info PendingRefreshContactInfo *refreshInfoOp; }; ContactManager::Private::Private(ContactManager *parent, Connection *connection) : parent(parent), connection(connection), roster(new ContactManager::Roster(parent)), requestAvatarsIdle(false), refreshInfoOp(0) { } ContactManager::Private::~Private() { delete refreshInfoOp; delete roster; } bool ContactManager::Private::buildAvatarFileName(QString token, bool createDir, QString &avatarFileName, QString &mimeTypeFileName) { QString cacheDir = QString(QLatin1String(qgetenv("XDG_CACHE_HOME"))); if (cacheDir.isEmpty()) { cacheDir = QString(QLatin1String("%1/.cache")).arg(QLatin1String(qgetenv("HOME"))); } ConnectionPtr conn(parent->connection()); QString path = QString(QLatin1String("%1/telepathy/avatars/%2/%3")). arg(cacheDir).arg(conn->cmName()).arg(conn->protocolName()); if (createDir && !QDir().mkpath(path)) { return false; } avatarFileName = QString(QLatin1String("%1/%2")).arg(path).arg(escapeAsIdentifier(token)); mimeTypeFileName = QString(QLatin1String("%1.mime")).arg(avatarFileName); return true; } Features ContactManager::Private::realFeatures(const Features &features) { Features ret(features); ret.unite(parent->connection()->contactFactory()->features()); // FeatureAvatarData depends on FeatureAvatarToken if (ret.contains(Contact::FeatureAvatarData) && !ret.contains(Contact::FeatureAvatarToken)) { ret.insert(Contact::FeatureAvatarToken); } return ret; } QSet ContactManager::Private::interfacesForFeatures(const Features &features) { Features supported = parent->supportedFeatures(); QSet ret; foreach (const Feature &feature, features) { parent->ensureTracking(feature); if (supported.contains(feature)) { // Only query interfaces which are reported as supported to not get an error ret.insert(parent->featureToInterface(feature)); } } return ret; } ContactManager::PendingRefreshContactInfo::PendingRefreshContactInfo(const ConnectionPtr &conn) : PendingOperation(conn), mConn(conn) { } ContactManager::PendingRefreshContactInfo::~PendingRefreshContactInfo() { } void ContactManager::PendingRefreshContactInfo::addContact(Contact *contact) { mToRequest.insert(contact->handle()[0]); } void ContactManager::PendingRefreshContactInfo::refreshInfo() { Q_ASSERT(!mToRequest.isEmpty()); if (!mConn->isValid()) { setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid")); return; } if (!mConn->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_INFO)) { setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Connection does not support ContactInfo interface")); return; } debug() << "Calling ContactInfo.RefreshContactInfo for" << mToRequest.size() << "handles"; Client::ConnectionInterfaceContactInfoInterface *contactInfoInterface = mConn->interface(); Q_ASSERT(contactInfoInterface); PendingVoid *nested = new PendingVoid( contactInfoInterface->RefreshContactInfo(mToRequest.toList()), mConn); connect(nested, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onRefreshInfoFinished(Tp::PendingOperation*))); } void ContactManager::PendingRefreshContactInfo::onRefreshInfoFinished(PendingOperation *op) { if (op->isError()) { warning() << "ContactInfo.RefreshContactInfo failed with" << op->errorName() << "-" << op->errorMessage(); setFinishedWithError(op->errorName(), op->errorMessage()); } else { debug() << "Got reply to ContactInfo.RefreshContactInfo"; setFinished(); } } /** * \class ContactManager * \ingroup clientconn * \headerfile TelepathyQt/contact-manager.h * * \brief The ContactManager class is responsible for managing contacts. * * See \ref async_model, \ref shared_ptr */ /** * Construct a new ContactManager object. * * \param connection The connection owning this ContactManager. */ ContactManager::ContactManager(Connection *connection) : Object(), mPriv(new Private(this, connection)) { } /** * Class destructor. */ ContactManager::~ContactManager() { delete mPriv; } /** * Return the connection owning this ContactManager. * * \return A pointer to the Connection object. */ ConnectionPtr ContactManager::connection() const { return ConnectionPtr(mPriv->connection); } /** * Return the features that are expected to work on contacts on this ContactManager connection. * * This method requires Connection::FeatureCore to be ready. * * \return The supported features as a set of Feature objects. */ Features ContactManager::supportedFeatures() const { if (mPriv->supportedFeatures.isEmpty() && connection()->interfaces().contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACTS)) { Features allFeatures = Features() << Contact::FeatureAlias << Contact::FeatureAvatarToken << Contact::FeatureAvatarData << Contact::FeatureSimplePresence << Contact::FeatureCapabilities << Contact::FeatureLocation << Contact::FeatureInfo << Contact::FeatureRosterGroups << Contact::FeatureAddresses << Contact::FeatureClientTypes; QStringList interfaces = connection()->lowlevel()->contactAttributeInterfaces(); foreach (const Feature &feature, allFeatures) { if (interfaces.contains(featureToInterface(feature))) { mPriv->supportedFeatures.insert(feature); } } debug() << mPriv->supportedFeatures.size() << "contact features supported using" << this; } return mPriv->supportedFeatures; } /** * Return the progress made in retrieving the contact list. * * Change notification is via the stateChanged() signal. * * This method requires Connection::FeatureRoster to be ready. * * \return The contact list state as #ContactListState. * \sa stateChanged() */ ContactListState ContactManager::state() const { return mPriv->roster->state(); } /** * Return a list of relevant contacts (a reasonable guess as to what should * be displayed as "the contact list"). * * This may include any or all of: contacts whose presence the user receives, * contacts who are allowed to see the user's presence, contacts stored in * some persistent contact list on the server, contacts who the user * has blocked from communicating with them, or contacts who are relevant * in some other way. * * User interfaces displaying a contact list will probably want to filter this * list and display some suitable subset of it. * * On protocols where there is no concept of presence or a centrally-stored * contact list (like IRC), this method may return an empty list. * * Change notification is via the allKnownContactsChanged() signal. * * This method requires Connection::FeatureRoster to be ready. * * \return A set of pointers to the Contact objects. * \sa allKnownContactsChanged() */ Contacts ContactManager::allKnownContacts() const { if (!connection()->isReady(Connection::FeatureRoster)) { warning() << "Calling allKnownContacts() before FeatureRoster is ready"; return Contacts(); } return mPriv->roster->allKnownContacts(); } /** * Return a list of user-defined contact list groups' names. * * Change notification is via the groupAdded(), groupRemoved() and groupRenamed() signals. * * This method requires Connection::FeatureRosterGroups to be ready. * * \return The list of user-defined contact list groups names. * \sa groupMembersChanged(), groupAdded(), groupRemoved(), groupRenamed() */ QStringList ContactManager::allKnownGroups() const { if (!connection()->isReady(Connection::FeatureRosterGroups)) { return QStringList(); } return mPriv->roster->allKnownGroups(); } /** * Attempt to add an user-defined contact list group named \a group. * * On some protocols (e.g. XMPP) empty groups are not represented on the server, * so disconnecting from the server and reconnecting might cause empty groups to * vanish. * * The returned pending operation will finish successfully if the group already * exists. * * Change notification is via the groupAdded() signal. * * This method requires Connection::FeatureRosterGroups to be ready. * * \param group The group name. * \return A PendingOperation which will emit PendingOperation::finished * when an attempt has been made to add an user-defined contact list group. * \sa allKnownGroups(), groupAdded(), addContactsToGroup() */ PendingOperation *ContactManager::addGroup(const QString &group) { if (!connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), connection()); } else if (!connection()->isReady(Connection::FeatureRosterGroups)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRosterGroups is not ready"), connection()); } return mPriv->roster->addGroup(group); } /** * Attempt to remove an user-defined contact list group named \a group. * * Change notification is via the groupRemoved() signal. * * This method requires Connection::FeatureRosterGroups to be ready. * * \param group The group name. * \return A PendingOperation which will emit PendingOperation::finished() * when an attempt has been made to remove an user-defined contact list group. * \sa allKnownGroups(), groupRemoved(), removeContactsFromGroup() */ PendingOperation *ContactManager::removeGroup(const QString &group) { if (!connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), connection()); } else if (!connection()->isReady(Connection::FeatureRosterGroups)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRosterGroups is not ready"), connection()); } return mPriv->roster->removeGroup(group); } /** * Return the contacts in the given user-defined contact list group * named \a group. * * Change notification is via the groupMembersChanged() signal. * * This method requires Connection::FeatureRosterGroups to be ready. * * \param group The group name. * \return A set of pointers to the Contact objects, or an empty set if the group does not exist. * \sa allKnownGroups(), groupMembersChanged() */ Contacts ContactManager::groupContacts(const QString &group) const { if (!connection()->isReady(Connection::FeatureRosterGroups)) { return Contacts(); } return mPriv->roster->groupContacts(group); } /** * Attempt to add the given \a contacts to the user-defined contact list * group named \a group. * * Change notification is via the groupMembersChanged() signal. * * This method requires Connection::FeatureRosterGroups to be ready. * * \param group The group name. * \param contacts Contacts to add. * \return A PendingOperation which will emit PendingOperation::finished() * when an attempt has been made to add the contacts to the user-defined * contact list group. * \sa groupMembersChanged(), groupContacts() */ PendingOperation *ContactManager::addContactsToGroup(const QString &group, const QList &contacts) { if (!connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), connection()); } else if (!connection()->isReady(Connection::FeatureRosterGroups)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRosterGroups is not ready"), connection()); } return mPriv->roster->addContactsToGroup(group, contacts); } /** * Attempt to remove the given \a contacts from the user-defined contact list * group named \a group. * * Change notification is via the groupMembersChanged() signal. * * This method requires Connection::FeatureRosterGroups to be ready. * * \param group The group name. * \param contacts Contacts to remove. * \return A PendingOperation which will PendingOperation::finished * when an attempt has been made to remove the contacts from the user-defined * contact list group. * \sa groupMembersChanged(), groupContacts() */ PendingOperation *ContactManager::removeContactsFromGroup(const QString &group, const QList &contacts) { if (!connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), connection()); } else if (!connection()->isReady(Connection::FeatureRosterGroups)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRosterGroups is not ready"), connection()); } return mPriv->roster->removeContactsFromGroup(group, contacts); } /** * Return whether subscribing to additional contacts' presence is supported. * * In some protocols, the list of contacts whose presence can be seen is * fixed, so we can't subscribe to the presence of additional contacts. * * Notably, in link-local XMPP, you can see the presence of everyone on the * local network, and trying to add more subscriptions would be meaningless. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if Contact::requestPresenceSubscription() and * requestPresenceSubscription() are likely to succeed, \c false otherwise. * \sa requestPresenceSubscription(), subscriptionRequestHasMessage() */ bool ContactManager::canRequestPresenceSubscription() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->canRequestPresenceSubscription(); } /** * Return whether a message can be sent when subscribing to contacts' * presence. * * If no message will actually be sent, user interfaces should avoid prompting * the user for a message, and use an empty string for the message argument. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if the message argument to Contact::requestPresenceSubscription() and * requestPresenceSubscription() is actually used, \c false otherwise. * \sa canRemovePresenceSubscription(), requestPresenceSubscription() */ bool ContactManager::subscriptionRequestHasMessage() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->subscriptionRequestHasMessage(); } /** * Attempt to subscribe to the presence of the given contacts. * * This operation is sometimes called "adding contacts to the buddy * list" or "requesting authorization". * * On most protocols, the contacts will need to give permission * before the user will be able to receive their presence: if so, they will * be in presence state Contact::PresenceStateAsk until they authorize * or deny the request. * * The returned PendingOperation will return successfully when a request to * subscribe to the contacts' presence has been submitted, or fail if this * cannot happen. In particular, it does not wait for the contacts to give * permission for the presence subscription. * * This method requires Connection::FeatureRoster to be ready. * * \param contacts Contacts whose presence is desired * \param message A message from the user which is either transmitted to the * contacts, or ignored, depending on the protocol * \return A PendingOperation which will PendingOperation::finished() * when an attempt has been made to subscribe to the contacts' presence. * \sa canRequestPresenceSubscription(), subscriptionRequestHasMessage() */ PendingOperation *ContactManager::requestPresenceSubscription( const QList &contacts, const QString &message) { if (!connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), connection()); } else if (!connection()->isReady(Connection::FeatureRoster)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRoster is not ready"), connection()); } return mPriv->roster->requestPresenceSubscription(contacts, message); } /** * Return whether the user can stop receiving the presence of a contact * whose presence they have subscribed to. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if Contact::removePresenceSubscription() and * removePresenceSubscription() are likely to succeed * for contacts with subscription state Contact::PresenceStateYes, * \c false otherwise. * \sa removePresenceSubscription(), subscriptionRemovalHasMessage() */ bool ContactManager::canRemovePresenceSubscription() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->canRemovePresenceSubscription(); } /** * Return whether a message can be sent when removing an existing subscription * to the presence of a contact. * * If no message will actually be sent, user interfaces should avoid prompting * the user for a message, and use an empty string for the message argument. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if the message argument to Contact::removePresenceSubscription() and * removePresenceSubscription() is actually used, * for contacts with subscription state Contact::PresenceStateYes, * \c false otherwise. * \sa canRemovePresencePublication(), removePresenceSubscription() */ bool ContactManager::subscriptionRemovalHasMessage() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->subscriptionRemovalHasMessage(); } /** * Return whether the user can cancel a request to subscribe to a contact's * presence before that contact has responded. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if Contact::removePresenceSubscription() and * removePresenceSubscription() are likely to succeed * for contacts with subscription state Contact::PresenceStateAsk, * \c false otherwise. * \sa removePresenceSubscription(), subscriptionRescindingHasMessage() */ bool ContactManager::canRescindPresenceSubscriptionRequest() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->canRescindPresenceSubscriptionRequest(); } /** * Return whether a message can be sent when cancelling a request to * subscribe to the presence of a contact. * * If no message will actually be sent, user interfaces should avoid prompting * the user for a message, and use an empty string for the message argument. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if the message argument to Contact::removePresenceSubscription() and * removePresenceSubscription() is actually used, * for contacts with subscription state Contact::PresenceStateAsk, * \c false otherwise. * \sa canRescindPresenceSubscriptionRequest(), removePresenceSubscription() */ bool ContactManager::subscriptionRescindingHasMessage() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->subscriptionRescindingHasMessage(); } /** * Attempt to stop receiving the presence of the given contacts, or cancel * a request to subscribe to their presence that was previously sent. * * This method requires Connection::FeatureRoster to be ready. * * \param contacts Contacts whose presence is no longer required * \message A message from the user which is either transmitted to the * contacts, or ignored, depending on the protocol * \return A PendingOperation which will PendingOperation::finished() * when an attempt has been made to remove any subscription to the contacts' presence. * \sa canRemovePresenceSubscription(), canRescindPresenceSubscriptionRequest(), * subscriptionRemovalHasMessage(), subscriptionRescindingHasMessage() */ PendingOperation *ContactManager::removePresenceSubscription( const QList &contacts, const QString &message) { if (!connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), connection()); } else if (!connection()->isReady(Connection::FeatureRoster)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRoster is not ready"), connection()); } return mPriv->roster->removePresenceSubscription(contacts, message); } /** * Return true if the publication of the user's presence to contacts can be * authorized. * * This is always true, unless the protocol has no concept of authorizing * publication (in which case contacts' publication status can never be * Contact::PresenceStateAsk). * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if Contact::authorizePresencePublication() and * authorizePresencePublication() are likely to succeed * for contacts with subscription state Contact::PresenceStateAsk, * \c false otherwise. * \sa publicationAuthorizationHasMessage(), authorizePresencePublication() */ bool ContactManager::canAuthorizePresencePublication() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->canAuthorizePresencePublication(); } /** * Return whether a message can be sent when authorizing a request from a * contact that the user's presence is published to them. * * If no message will actually be sent, user interfaces should avoid prompting * the user for a message, and use an empty string for the message argument. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if the message argument to Contact::authorizePresencePublication() and * authorizePresencePublication() is actually used, * for contacts with subscription state Contact::PresenceStateAsk, * \c false otherwise. * \sa canAuthorizePresencePublication(), authorizePresencePublication() */ bool ContactManager::publicationAuthorizationHasMessage() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->publicationAuthorizationHasMessage(); } /** * If the given contacts have asked the user to publish presence to them, * grant permission for this publication to take place. * * This method requires Connection::FeatureRoster to be ready. * * \param contacts Contacts who should be allowed to receive the user's * presence * \message A message from the user which is either transmitted to the * contacts, or ignored, depending on the protocol * \return A PendingOperation which will emit PendingOperation::fininshed * when an attempt has been made to authorize publication of the user's presence * to the contacts. * \sa canAuthorizePresencePublication(), publicationAuthorizationHasMessage() */ PendingOperation *ContactManager::authorizePresencePublication( const QList &contacts, const QString &message) { if (!connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), connection()); } else if (!connection()->isReady(Connection::FeatureRoster)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRoster is not ready"), connection()); } return mPriv->roster->authorizePresencePublication(contacts, message); } /** * Return whether a message can be sent when rejecting a request from a * contact that the user's presence is published to them. * * If no message will actually be sent, user interfaces should avoid prompting * the user for a message, and use an empty string for the message argument. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if the message argument to Contact::removePresencePublication() and * removePresencePublication() is actually used, * for contacts with subscription state Contact::PresenceStateAsk, * \c false otherwise. * \sa canRemovePresencePublication(), removePresencePublication() */ bool ContactManager::publicationRejectionHasMessage() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->publicationRejectionHasMessage(); } /** * Return true if the publication of the user's presence to contacts can be * removed, even after permission has been given. * * (Rejecting requests for presence to be published is always allowed.) * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if Contact::removePresencePublication() and * removePresencePublication() are likely to succeed * for contacts with subscription state Contact::PresenceStateYes, * \c false otherwise. * \sa publicationRemovalHasMessage(), removePresencePublication() */ bool ContactManager::canRemovePresencePublication() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->canRemovePresencePublication(); } /** * Return whether a message can be sent when revoking earlier permission * that the user's presence is published to a contact. * * If no message will actually be sent, user interfaces should avoid prompting * the user for a message, and use an empty string for the message argument. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if the message argument to Contact::removePresencePublication and * removePresencePublication() is actually used, * for contacts with subscription state Contact::PresenceStateYes, * \c false otherwise. * \sa canRemovePresencePublication(), removePresencePublication() */ bool ContactManager::publicationRemovalHasMessage() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->publicationRemovalHasMessage(); } /** * If the given contacts have asked the user to publish presence to them, * deny this request (this should always succeed, unless a network error * occurs). * * If the given contacts already have permission to receive * the user's presence, attempt to revoke that permission (this might not * be supported by the protocol - canRemovePresencePublication * indicates whether it is likely to succeed). * * This method requires Connection::FeatureRoster to be ready. * * \param contacts Contacts who should no longer be allowed to receive the * user's presence * \message A message from the user which is either transmitted to the * contacts, or ignored, depending on the protocol * \return A PendingOperation which will emit PendingOperation::finished() * when an attempt has been made to remove any publication of the user's presence to the * contacts. * \sa canRemovePresencePublication(), publicationRejectionHasMessage(), * publicationRemovalHasMessage() */ PendingOperation *ContactManager::removePresencePublication( const QList &contacts, const QString &message) { if (!connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), connection()); } else if (!connection()->isReady(Connection::FeatureRoster)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRoster is not ready"), connection()); } return mPriv->roster->removePresencePublication(contacts, message); } /** * Remove completely contacts from the server. It has the same effect than * calling removePresencePublication() and removePresenceSubscription(), * but also remove from 'stored' list if it exists. * * This method requires Connection::FeatureRoster to be ready. * * \param contacts Contacts who should be removed * \message A message from the user which is either transmitted to the * contacts, or ignored, depending on the protocol * \return A PendingOperation which will emit PendingOperation::finished * when an attempt has been made to remove any publication of the user's presence to * the contacts. */ PendingOperation *ContactManager::removeContacts( const QList &contacts, const QString &message) { if (!connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), connection()); } else if (!connection()->isReady(Connection::FeatureRoster)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRoster is not ready"), connection()); } return mPriv->roster->removeContacts(contacts, message); } /** * Return whether this protocol has a list of blocked contacts. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if blockContacts() is likely to succeed, \c false otherwise. */ bool ContactManager::canBlockContacts() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->canBlockContacts(); } /** * Return whether this protocol can report abusive contacts. * * This method requires Connection::FeatureRoster to be ready. * * \return \c true if reporting abuse when blocking contacts is supported, \c false otherwise. */ bool ContactManager::canReportAbuse() const { if (!connection()->isReady(Connection::FeatureRoster)) { return false; } return mPriv->roster->canReportAbuse(); } /** * Block the given contacts. Blocked contacts cannot send messages * to the user; depending on the protocol, blocking a contact may * have other effects. * * This method requires Connection::FeatureRoster to be ready. * * \param contacts Contacts that should be blocked. * \return A PendingOperation which will emit PendingOperation::finished() * when an attempt has been made to take the requested action. * \sa canBlockContacts(), unblockContacts(), blockContactsAndReportAbuse() */ PendingOperation *ContactManager::blockContacts(const QList &contacts) { return mPriv->roster->blockContacts(contacts, true, false); } /** * Block the given contacts and additionally report abusive behaviour * to the server. * * If reporting abusive behaviour is not supported by the protocol, * this method has the same effect as blockContacts(). * * This method requires Connection::FeatureRoster to be ready. * * \param contacts Contacts who should be added to the list of blocked contacts. * \return A PendingOperation which will emit PendingOperation::finished() * when an attempt has been made to take the requested action. * \sa canBlockContacts(), canReportAbuse(), blockContacts() */ PendingOperation *ContactManager::blockContactsAndReportAbuse( const QList &contacts) { return mPriv->roster->blockContacts(contacts, true, true); } /** * Unblock the given contacts. * * This method requires Connection::FeatureRoster to be ready. * * \param contacts Contacts that should be unblocked. * \return A PendingOperation which will emit PendingOperation::finished() * when an attempt has been made to take the requested action. * \sa canBlockContacts(), blockContacts(), blockContactsAndReportAbuse() */ PendingOperation *ContactManager::unblockContacts(const QList &contacts) { return mPriv->roster->blockContacts(contacts, false, false); } PendingContacts *ContactManager::contactsForHandles(const UIntList &handles, const Features &features) { QMap satisfyingContacts; QSet otherContacts; Features missingFeatures; if (!connection()->isValid()) { return new PendingContacts(ContactManagerPtr(this), handles, features, Features(), QStringList(), satisfyingContacts, otherContacts, TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid")); } else if (!connection()->isReady(Connection::FeatureCore)) { return new PendingContacts(ContactManagerPtr(this), handles, features, Features(), QStringList(), satisfyingContacts, otherContacts, TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureCore is not ready")); } Features realFeatures = mPriv->realFeatures(features); ConnectionLowlevelPtr connLowlevel = connection()->lowlevel(); if (connLowlevel->hasImmortalHandles() && realFeatures.isEmpty()) { // try to avoid a roundtrip if all handles have an id set and no feature was requested foreach (uint handle, handles) { if (connLowlevel->hasContactId(handle)) { ContactPtr contact = ensureContact(handle, connLowlevel->contactId(handle), realFeatures); satisfyingContacts.insert(handle, contact); } } } foreach (uint handle, handles) { ContactPtr contact = lookupContactByHandle(handle); if (contact) { if ((realFeatures - contact->requestedFeatures()).isEmpty()) { // Contact exists and has all the requested features satisfyingContacts.insert(handle, contact); } else { // Contact exists but is missing features otherContacts.insert(handle); missingFeatures.unite(realFeatures - contact->requestedFeatures()); } } else { // Contact doesn't exist - we need to get all of the features (same as unite(features)) missingFeatures = realFeatures; otherContacts.insert(handle); } } QSet interfaces = mPriv->interfacesForFeatures(missingFeatures); PendingContacts *contacts = new PendingContacts(ContactManagerPtr(this), handles, features, missingFeatures, interfaces.toList(), satisfyingContacts, otherContacts); return contacts; } PendingContacts *ContactManager::contactsForHandles(const ReferencedHandles &handles, const Features &features) { return contactsForHandles(handles.toList(), features); } PendingContacts *ContactManager::contactsForHandles(const HandleIdentifierMap &handles, const Features &features) { connection()->lowlevel()->injectContactIds(handles); return contactsForHandles(handles.keys(), features); } PendingContacts *ContactManager::contactsForIdentifiers(const QStringList &identifiers, const Features &features) { if (!connection()->isValid()) { return new PendingContacts(ContactManagerPtr(this), identifiers, PendingContacts::ForIdentifiers, features, QStringList(), TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid")); } else if (!connection()->isReady(Connection::FeatureCore)) { return new PendingContacts(ContactManagerPtr(this), identifiers, PendingContacts::ForIdentifiers, features, QStringList(), TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureCore is not ready")); } Features realFeatures = mPriv->realFeatures(features); PendingContacts *contacts = new PendingContacts(ContactManagerPtr(this), identifiers, PendingContacts::ForIdentifiers, realFeatures, QStringList()); return contacts; } /** * Request contacts and enable their \a features using a given field in their vcards. * * This method requires Connection::FeatureCore to be ready. * * \param vcardField The vcard field of the addresses we are requesting. * Supported fields can be found in ProtocolInfo::addressableVCardFields(). * \param vcardAddresses The addresses to get contacts for. The address types must match * the given vcard field. * \param features The Contact features to enable. * \return A PendingContacts, which will emit PendingContacts::finished * when the contacts are retrieved or an error occurred. * \sa contactsForHandles(), contactsForIdentifiers(), contactsForUris(), * ProtocolInfo::normalizeVCardAddress() */ PendingContacts *ContactManager::contactsForVCardAddresses(const QString &vcardField, const QStringList &vcardAddresses, const Features &features) { if (!connection()->isValid()) { return new PendingContacts(ContactManagerPtr(this), vcardField, vcardAddresses, features, QStringList(), TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid")); } else if (!connection()->isReady(Connection::FeatureCore)) { return new PendingContacts(ContactManagerPtr(this), vcardField, vcardAddresses, features, QStringList(), TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureCore is not ready")); } Features realFeatures = mPriv->realFeatures(features); QSet interfaces = mPriv->interfacesForFeatures(realFeatures); PendingContacts *contacts = new PendingContacts(ContactManagerPtr(this), vcardField, vcardAddresses, realFeatures, interfaces.toList()); return contacts; } /** * Request contacts and enable their \a features using the given URI addresses. * * This method requires Connection::FeatureCore to be ready. * * \param uris The URI addresses to get contacts for. * Supported schemes can be found in ProtocolInfo::addressableUriSchemes(). * \param features The Contact features to enable. * \return A PendingContacts, which will emit PendingContacts::finished * when the contacts are retrieved or an error occurred. * \sa contactsForHandles(), contactsForIdentifiers(), contactsForVCardAddresses(), * ProtocolInfo::normalizeContactUri() */ PendingContacts *ContactManager::contactsForUris(const QStringList &uris, const Features &features) { if (!connection()->isValid()) { return new PendingContacts(ContactManagerPtr(this), uris, PendingContacts::ForUris, features, QStringList(), TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid")); } else if (!connection()->isReady(Connection::FeatureCore)) { return new PendingContacts(ContactManagerPtr(this), uris, PendingContacts::ForUris, features, QStringList(), TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureCore is not ready")); } Features realFeatures = mPriv->realFeatures(features); QSet interfaces = mPriv->interfacesForFeatures(realFeatures); PendingContacts *contacts = new PendingContacts(ContactManagerPtr(this), uris, PendingContacts::ForUris, realFeatures, interfaces.toList()); return contacts; } PendingContacts *ContactManager::upgradeContacts(const QList &contacts, const Features &features) { if (!connection()->isValid()) { return new PendingContacts(ContactManagerPtr(this), contacts, features, TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid")); } else if (!connection()->isReady(Connection::FeatureCore)) { return new PendingContacts(ContactManagerPtr(this), contacts, features, TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureCore is not ready")); } return new PendingContacts(ContactManagerPtr(this), contacts, features); } ContactPtr ContactManager::lookupContactByHandle(uint handle) { ContactPtr contact; if (mPriv->contacts.contains(handle)) { contact = ContactPtr(mPriv->contacts.value(handle)); if (!contact) { // Dangling weak pointer, remove it mPriv->contacts.remove(handle); } } return contact; } /** * Start a request to retrieve the avatar for the given \a contacts. * * Force the request of the avatar data. This method returns directly, emitting * Contact::avatarTokenChanged() and Contact::avatarDataChanged() signals once the token * and data are fetched from the server. * * This is only useful if the avatar token is unknown; see Contact::isAvatarTokenKnown(). * It happens in the case of offline XMPP contacts, because the server does not * send the token for them and an explicit request of the avatar data is needed. * * This method requires Contact::FeatureAvatarData to be ready. * * \sa Contact::avatarData(), Contact::avatarDataChanged(), * Contact::avatarToken(), Contact::avatarTokenChanged() */ void ContactManager::requestContactAvatars(const QList &contacts) { if (contacts.isEmpty()) { return; } if (!mPriv->requestAvatarsIdle) { mPriv->requestAvatarsIdle = true; QTimer::singleShot(0, this, SLOT(doRequestAvatars())); } mPriv->requestAvatarsQueue.unite(contacts.toSet()); } /** * Refresh information for the given contact. * * Once the information is retrieved infoFieldsChanged() will be emitted. * * This method requires Contact::FeatureInfo to be ready. * * \return A PendingOperation, which will emit PendingOperation::finished * when the call has finished. * \sa infoFieldsChanged() */ PendingOperation *ContactManager::refreshContactInfo(const QList &contacts) { if (!mPriv->refreshInfoOp) { mPriv->refreshInfoOp = new PendingRefreshContactInfo(connection()); QTimer::singleShot(0, this, SLOT(doRefreshInfo())); } foreach (const ContactPtr &contact, contacts) { mPriv->refreshInfoOp->addContact(contact.data()); } return mPriv->refreshInfoOp; } void ContactManager::onAliasesChanged(const AliasPairList &aliases) { debug() << "Got AliasesChanged for" << aliases.size() << "contacts"; foreach (AliasPair pair, aliases) { ContactPtr contact = lookupContactByHandle(pair.handle); if (contact) { contact->receiveAlias(pair.alias); } } } void ContactManager::doRequestAvatars() { Q_ASSERT(mPriv->requestAvatarsIdle); QSet contacts = mPriv->requestAvatarsQueue; Q_ASSERT(contacts.size() > 0); mPriv->requestAvatarsQueue.clear(); mPriv->requestAvatarsIdle = false; int found = 0; UIntList notFound; foreach (const ContactPtr &contact, contacts) { if (!contact) { continue; } QString avatarFileName; QString mimeTypeFileName; bool success = (contact->isAvatarTokenKnown() && mPriv->buildAvatarFileName(contact->avatarToken(), false, avatarFileName, mimeTypeFileName)); /* Check if the avatar is already in the cache */ if (success && QFile::exists(avatarFileName)) { QFile mimeTypeFile(mimeTypeFileName); mimeTypeFile.open(QIODevice::ReadOnly); QString mimeType = QString(QLatin1String(mimeTypeFile.readAll())); mimeTypeFile.close(); found++; contact->receiveAvatarData(AvatarData(avatarFileName, mimeType)); continue; } notFound << contact->handle()[0]; } if (found > 0) { debug() << "Avatar(s) found in cache for" << found << "contact(s)"; } if (found == contacts.size()) { return; } debug() << "Requesting avatar(s) for" << contacts.size() - found << "contact(s)"; Client::ConnectionInterfaceAvatarsInterface *avatarsInterface = connection()->interface(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( avatarsInterface->RequestAvatars(notFound), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), watcher, SLOT(deleteLater())); } void ContactManager::onAvatarUpdated(uint handle, const QString &token) { debug() << "Got AvatarUpdate for contact with handle" << handle; ContactPtr contact = lookupContactByHandle(handle); if (contact) { contact->receiveAvatarToken(token); } } void ContactManager::onAvatarRetrieved(uint handle, const QString &token, const QByteArray &data, const QString &mimeType) { QString avatarFileName; QString mimeTypeFileName; debug() << "Got AvatarRetrieved for contact with handle" << handle; bool success = mPriv->buildAvatarFileName(token, true, avatarFileName, mimeTypeFileName); if (success) { debug() << "Write avatar in cache for handle" << handle; debug() << "Filename:" << avatarFileName; debug() << "MimeType:" << mimeType; if (!QFile::exists(mimeTypeFileName)) { QTemporaryFile mimeTypeFile(mimeTypeFileName); if (mimeTypeFile.open()) { mimeTypeFile.write(mimeType.toLatin1()); mimeTypeFile.setAutoRemove(false); if (!mimeTypeFile.rename(mimeTypeFileName)) { mimeTypeFile.remove(); } } } if (!QFile::exists(avatarFileName)) { QTemporaryFile avatarFile(avatarFileName); if (avatarFile.open()) { avatarFile.write(data); avatarFile.setAutoRemove(false); if (!avatarFile.rename(avatarFileName)) { avatarFile.remove(); } } } } ContactPtr contact = lookupContactByHandle(handle); if (contact) { contact->setAvatarToken(token); contact->receiveAvatarData(AvatarData(avatarFileName, mimeType)); } } void ContactManager::onPresencesChanged(const SimpleContactPresences &presences) { debug() << "Got PresencesChanged for" << presences.size() << "contacts"; foreach (uint handle, presences.keys()) { ContactPtr contact = lookupContactByHandle(handle); if (contact) { contact->receiveSimplePresence(presences[handle]); } } } void ContactManager::onCapabilitiesChanged(const ContactCapabilitiesMap &caps) { debug() << "Got ContactCapabilitiesChanged for" << caps.size() << "contacts"; foreach (uint handle, caps.keys()) { ContactPtr contact = lookupContactByHandle(handle); if (contact) { contact->receiveCapabilities(caps[handle]); } } } void ContactManager::onLocationUpdated(uint handle, const QVariantMap &location) { debug() << "Got LocationUpdated for contact with handle" << handle; ContactPtr contact = lookupContactByHandle(handle); if (contact) { contact->receiveLocation(location); } } void ContactManager::onContactInfoChanged(uint handle, const Tp::ContactInfoFieldList &info) { debug() << "Got ContactInfoChanged for contact with handle" << handle; ContactPtr contact = lookupContactByHandle(handle); if (contact) { contact->receiveInfo(info); } } void ContactManager::onClientTypesUpdated(uint handle, const QStringList &clientTypes) { debug() << "Got ClientTypesUpdated for contact with handle" << handle; ContactPtr contact = lookupContactByHandle(handle); if (contact) { contact->receiveClientTypes(clientTypes); } } void ContactManager::doRefreshInfo() { PendingRefreshContactInfo *op = mPriv->refreshInfoOp; Q_ASSERT(op); mPriv->refreshInfoOp = 0; op->refreshInfo(); } ContactPtr ContactManager::ensureContact(const ReferencedHandles &handle, const Features &features, const QVariantMap &attributes) { uint bareHandle = handle[0]; ContactPtr contact = lookupContactByHandle(bareHandle); if (!contact) { contact = connection()->contactFactory()->construct(this, handle, features, attributes); mPriv->contacts.insert(bareHandle, contact); } contact->augment(features, attributes); return contact; } ContactPtr ContactManager::ensureContact(uint bareHandle, const QString &id, const Features &features) { ContactPtr contact = lookupContactByHandle(bareHandle); if (!contact) { QVariantMap attributes; attributes.insert(TP_QT_IFACE_CONNECTION + QLatin1String("/contact-id"), id); contact = connection()->contactFactory()->construct(this, ReferencedHandles(connection(), HandleTypeContact, UIntList() << bareHandle), features, attributes); mPriv->contacts.insert(bareHandle, contact); // do not call augment here as this is a fake contact } return contact; } QString ContactManager::featureToInterface(const Feature &feature) { if (feature == Contact::FeatureAlias) { return TP_QT_IFACE_CONNECTION_INTERFACE_ALIASING; } else if (feature == Contact::FeatureAvatarToken) { return TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS; } else if (feature == Contact::FeatureAvatarData) { return TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS; } else if (feature == Contact::FeatureSimplePresence) { return TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE; } else if (feature == Contact::FeatureCapabilities) { return TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES; } else if (feature == Contact::FeatureLocation) { return TP_QT_IFACE_CONNECTION_INTERFACE_LOCATION; } else if (feature == Contact::FeatureInfo) { return TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_INFO; } else if (feature == Contact::FeatureRosterGroups) { return TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS; } else if (feature == Contact::FeatureAddresses) { return TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING; } else if (feature == Contact::FeatureClientTypes) { return TP_QT_IFACE_CONNECTION_INTERFACE_CLIENT_TYPES; } else { warning() << "ContactManager doesn't know which interface corresponds to feature" << feature; return QString(); } } void ContactManager::ensureTracking(const Feature &feature) { if (mPriv->tracking[feature]) { return; } ConnectionPtr conn(connection()); if (feature == Contact::FeatureAlias) { Client::ConnectionInterfaceAliasingInterface *aliasingInterface = conn->interface(); connect(aliasingInterface, SIGNAL(AliasesChanged(Tp::AliasPairList)), SLOT(onAliasesChanged(Tp::AliasPairList))); } else if (feature == Contact::FeatureAvatarData) { Client::ConnectionInterfaceAvatarsInterface *avatarsInterface = conn->interface(); connect(avatarsInterface, SIGNAL(AvatarRetrieved(uint,QString,QByteArray,QString)), SLOT(onAvatarRetrieved(uint,QString,QByteArray,QString))); } else if (feature == Contact::FeatureAvatarToken) { Client::ConnectionInterfaceAvatarsInterface *avatarsInterface = conn->interface(); connect(avatarsInterface, SIGNAL(AvatarUpdated(uint,QString)), SLOT(onAvatarUpdated(uint,QString))); } else if (feature == Contact::FeatureCapabilities) { Client::ConnectionInterfaceContactCapabilitiesInterface *contactCapabilitiesInterface = conn->interface(); connect(contactCapabilitiesInterface, SIGNAL(ContactCapabilitiesChanged(Tp::ContactCapabilitiesMap)), SLOT(onCapabilitiesChanged(Tp::ContactCapabilitiesMap))); } else if (feature == Contact::FeatureInfo) { Client::ConnectionInterfaceContactInfoInterface *contactInfoInterface = conn->interface(); connect(contactInfoInterface, SIGNAL(ContactInfoChanged(uint,Tp::ContactInfoFieldList)), SLOT(onContactInfoChanged(uint,Tp::ContactInfoFieldList))); } else if (feature == Contact::FeatureLocation) { Client::ConnectionInterfaceLocationInterface *locationInterface = conn->interface(); connect(locationInterface, SIGNAL(LocationUpdated(uint,QVariantMap)), SLOT(onLocationUpdated(uint,QVariantMap))); } else if (feature == Contact::FeatureSimplePresence) { Client::ConnectionInterfaceSimplePresenceInterface *simplePresenceInterface = conn->interface(); connect(simplePresenceInterface, SIGNAL(PresencesChanged(Tp::SimpleContactPresences)), SLOT(onPresencesChanged(Tp::SimpleContactPresences))); } else if (feature == Contact::FeatureClientTypes) { Client::ConnectionInterfaceClientTypesInterface *clientTypesInterface = conn->interface(); connect(clientTypesInterface, SIGNAL(ClientTypesUpdated(uint,QStringList)), SLOT(onClientTypesUpdated(uint,QStringList))); } else if (feature == Contact::FeatureRosterGroups || feature == Contact::FeatureAddresses) { // nothing to do here, but we don't want to warn ; } else { warning() << " Unknown feature" << feature << "when trying to figure out how to connect change notification!"; } mPriv->tracking[feature] = true; } PendingOperation *ContactManager::introspectRoster() { return mPriv->roster->introspect(); } PendingOperation *ContactManager::introspectRosterGroups() { return mPriv->roster->introspectGroups(); } void ContactManager::resetRoster() { mPriv->roster->reset(); } /** * \fn void ContactManager::presencePublicationRequested(const Tp::Contacts &contacts) * * Emitted whenever some contacts request for presence publication. * * \param contacts A set of contacts which requested presence publication. */ /** * \fn void ContactManager::groupAdded(const QString &group) * * Emitted when a new contact list group is created. * * \param group The group name. * \sa allKnownGroups() */ /** * \fn void ContactManager::groupRenamed(const QString &oldGroup, const QString &newGroup) * * Emitted when a new contact list group is renamed. * * \param oldGroup The old group name. * \param newGroup The new group name. * \sa allKnownGroups() */ /** * \fn void ContactManager::groupRemoved(const QString &group) * * Emitted when a contact list group is removed. * * \param group The group name. * \sa allKnownGroups() */ /** * \fn void ContactManager::groupMembersChanged(const QString &group, * const Tp::Contacts &groupMembersAdded, * const Tp::Contacts &groupMembersRemoved, * const Tp::Channel::GroupMemberChangeDetails &details) * * Emitted whenever some contacts got removed or added from * a group. * * \param group The name of the group that changed. * \param groupMembersAdded A set of contacts which were added to the group \a group. * \param groupMembersRemoved A set of contacts which were removed from the group \a group. * \param details The change details. * \sa groupContacts() */ /** * \fn void ContactManager::allKnownContactsChanged(const Tp::Contacts &contactsAdded, * const Tp::Contacts &contactsRemoved, * const Tp::Channel::GroupMemberChangeDetails &details) * * Emitted whenever some contacts got removed or added from * ContactManager's known contact list. It is useful for monitoring which contacts * are currently known by ContactManager. * * Note that, in some protocols, this signal could stream newly added contacts * with both presence subscription and publication state set to No. Be sure to watch * over publication and/or subscription state changes if that is the case. * * \param contactsAdded A set of contacts which were added to the known contact list. * \param contactsRemoved A set of contacts which were removed from the known contact list. * \param details The change details. * \sa allKnownContacts() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/Utils0000664000175000017500000000033512470405660016240 0ustar jrjr#ifndef _TelepathyQt_Utils_HEADER_GUARD_ #define _TelepathyQt_Utils_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/account.cpp0000664000175000017500000061756512470405660017400 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2012 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/account.moc.hpp" #include "TelepathyQt/_gen/cli-account.moc.hpp" #include "TelepathyQt/_gen/cli-account-body.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/connection-internal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { namespace { struct PresenceStatusInfo { QString name; Tp::SimpleStatusSpec spec; }; Tp::ConnectionPresenceType presenceTypeForStatus(const QString &status, bool &maySetOnSelf) { static PresenceStatusInfo statuses[] = { { QLatin1String("available"), { Tp::ConnectionPresenceTypeAvailable, true, true } }, { QLatin1String("chat"), { Tp::ConnectionPresenceTypeAvailable, true, true } }, { QLatin1String("chatty"), { Tp::ConnectionPresenceTypeAvailable, true, true } }, { QLatin1String("away"), { Tp::ConnectionPresenceTypeAway, true, true } }, { QLatin1String("brb"), { Tp::ConnectionPresenceTypeAway, true, true } }, { QLatin1String("out-to-lunch"), { Tp::ConnectionPresenceTypeAway, true, true } }, { QLatin1String("xa"), { Tp::ConnectionPresenceTypeExtendedAway, true, true } }, { QLatin1String("hidden"), { Tp::ConnectionPresenceTypeHidden, true, true } }, { QLatin1String("invisible"), { Tp::ConnectionPresenceTypeHidden, true, true } }, { QLatin1String("offline"), { Tp::ConnectionPresenceTypeOffline, true, false } }, { QLatin1String("unknown"), { Tp::ConnectionPresenceTypeUnknown, false, false } }, { QLatin1String("error"), { Tp::ConnectionPresenceTypeError, false, false } } }; for (uint i = 0; i < sizeof(statuses) / sizeof(PresenceStatusInfo); ++i) { if (status == statuses[i].name) { maySetOnSelf = statuses[i].spec.maySetOnSelf; return (Tp::ConnectionPresenceType) statuses[i].spec.type; } } // fallback to type away if we don't know status maySetOnSelf = true; return Tp::ConnectionPresenceTypeAway; } Tp::PresenceSpec presenceSpecForStatus(const QString &status, bool canHaveStatusMessage) { Tp::SimpleStatusSpec spec; spec.type = presenceTypeForStatus(status, spec.maySetOnSelf); spec.canHaveMessage = canHaveStatusMessage; return Tp::PresenceSpec(status, spec); } QVariantMap textChatCommonRequest() { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); return request; } QVariantMap textChatRequest(const QString &contactIdentifier) { QVariantMap request = textChatCommonRequest(); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), contactIdentifier); return request; } QVariantMap textChatRequest(const Tp::ContactPtr &contact) { QVariantMap request = textChatCommonRequest(); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), contact ? contact->handle().at(0) : (uint) 0); return request; } QVariantMap textChatroomRequest(const QString &roomName) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeRoom); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), roomName); return request; } QVariantMap callCommonRequest(bool withAudio, const QString &audioName, bool withVideo, const QString &videoName) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); if (withAudio) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"), true); if (!audioName.isEmpty()) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudioName"), audioName); } } if (withVideo) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo"), true); if (!videoName.isEmpty()) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideoName"), videoName); } } return request; } QVariantMap audioCallRequest(const QString &contactIdentifier, const QString &contentName) { QVariantMap request = callCommonRequest(true, contentName, false, QString()); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), contactIdentifier); return request; } QVariantMap audioCallRequest(const Tp::ContactPtr &contact, const QString &contentName) { QVariantMap request = callCommonRequest(true, contentName, false, QString()); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), contact ? contact->handle().at(0) : (uint) 0); return request; } QVariantMap videoCallRequest(const QString &contactIdentifier, const QString &contentName) { QVariantMap request = callCommonRequest(false, QString(), true, contentName); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), contactIdentifier); return request; } QVariantMap videoCallRequest(const Tp::ContactPtr &contact, const QString &contentName) { QVariantMap request = callCommonRequest(false, QString(), true, contentName); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), contact ? contact->handle().at(0) : (uint) 0); return request; } QVariantMap audioVideoCallRequest(const QString &contactIdentifier, const QString &audioName, const QString &videoName) { QVariantMap request = callCommonRequest(true, audioName, true, videoName); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), contactIdentifier); return request; } QVariantMap audioVideoCallRequest(const Tp::ContactPtr &contact, const QString &audioName, const QString &videoName) { QVariantMap request = callCommonRequest(true, audioName, true, videoName); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), contact ? contact->handle().at(0) : (uint) 0); return request; } QVariantMap streamedMediaCallCommonRequest() { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); return request; } QVariantMap streamedMediaCallRequest(const QString &contactIdentifier) { QVariantMap request = streamedMediaCallCommonRequest(); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), contactIdentifier); return request; } QVariantMap streamedMediaCallRequest(const Tp::ContactPtr &contact) { QVariantMap request = streamedMediaCallCommonRequest(); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), contact ? contact->handle().at(0) : (uint) 0); return request; } QVariantMap streamedMediaAudioCallRequest(const QString &contactIdentifier) { QVariantMap request = streamedMediaCallRequest(contactIdentifier); request.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio"), true); return request; } QVariantMap streamedMediaAudioCallRequest(const Tp::ContactPtr &contact) { QVariantMap request = streamedMediaCallRequest(contact); request.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio"), true); return request; } QVariantMap streamedMediaVideoCallRequest(const QString &contactIdentifier, bool withAudio) { QVariantMap request = streamedMediaCallRequest(contactIdentifier); request.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo"), true); if (withAudio) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio"), true); } return request; } QVariantMap streamedMediaVideoCallRequest(const Tp::ContactPtr &contact, bool withAudio) { QVariantMap request = streamedMediaCallRequest(contact); request.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo"), true); if (withAudio) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio"), true); } return request; } QVariantMap fileTransferCommonRequest(const Tp::FileTransferChannelCreationProperties &properties) { if (!properties.isValid()) { warning() << "Invalid file transfer creation properties"; return QVariantMap(); } QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER + QLatin1String(".Filename"), properties.suggestedFileName()); request.insert(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER + QLatin1String(".ContentType"), properties.contentType()); request.insert(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER + QLatin1String(".Size"), properties.size()); if (properties.hasContentHash()) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER + QLatin1String(".ContentHashType"), (uint) properties.contentHashType()); request.insert(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER + QLatin1String(".ContentHash"), properties.contentHash()); } if (properties.hasDescription()) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER + QLatin1String(".Description"), properties.description()); } if (properties.hasLastModificationTime()) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER + QLatin1String(".Date"), (qulonglong) properties.lastModificationTime().toTime_t()); } if (properties.hasUri()) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER + QLatin1String(".URI"), properties.uri()); } return request; } QVariantMap fileTransferRequest(const QString &contactIdentifier, const Tp::FileTransferChannelCreationProperties &properties) { QVariantMap request = fileTransferCommonRequest(properties); if (!request.isEmpty()) { request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), contactIdentifier); } return request; } QVariantMap fileTransferRequest(const Tp::ContactPtr &contact, const Tp::FileTransferChannelCreationProperties &properties) { QVariantMap request = fileTransferCommonRequest(properties); if (!request.isEmpty()) { request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), contact ? contact->handle().at(0) : (uint) 0); } return request; } QVariantMap streamTubeCommonRequest(const QString &service) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QLatin1String(".Service"), service); return request; } QVariantMap streamTubeRequest(const QString &contactIdentifier, const QString &service) { QVariantMap request = streamTubeCommonRequest(service); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), contactIdentifier); return request; } QVariantMap streamTubeRequest(const Tp::ContactPtr &contact, const QString &service) { QVariantMap request = streamTubeCommonRequest(service); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), contact ? contact->handle().at(0) : (uint) 0); return request; } QVariantMap dbusTubeCommonRequest(const QString &serviceName) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeContact); request.insert(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName"), serviceName); return request; } QVariantMap dbusTubeRequest(const QString &contactIdentifier, const QString &serviceName) { QVariantMap request = dbusTubeCommonRequest(serviceName); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), contactIdentifier); return request; } QVariantMap dbusTubeRequest(const Tp::ContactPtr &contact, const QString &serviceName) { QVariantMap request = dbusTubeCommonRequest(serviceName); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), contact ? contact->handle().at(0) : (uint) 0); return request; } QVariantMap dbusTubeRoomRequest(const QString &roomName, const QString &serviceName) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeRoom); request.insert(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName"), serviceName); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), roomName); return request; } QVariantMap conferenceCommonRequest(const QString &channelType, Tp::HandleType targetHandleType, const QList &channels) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), channelType); if (targetHandleType != Tp::HandleTypeNone) { request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) targetHandleType); } Tp::ObjectPathList objectPaths; foreach (const Tp::ChannelPtr &channel, channels) { objectPaths << QDBusObjectPath(channel->objectPath()); } request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels"), qVariantFromValue(objectPaths)); return request; } QVariantMap conferenceRequest(const QString &channelType, Tp::HandleType targetHandleType, const QList &channels, const QStringList &initialInviteeContactsIdentifiers) { QVariantMap request = conferenceCommonRequest(channelType, targetHandleType, channels); if (!initialInviteeContactsIdentifiers.isEmpty()) { request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs"), initialInviteeContactsIdentifiers); } return request; } QVariantMap conferenceRequest(const QString &channelType, Tp::HandleType targetHandleType, const QList &channels, const QList &initialInviteeContacts) { QVariantMap request = conferenceCommonRequest(channelType, targetHandleType, channels); if (!initialInviteeContacts.isEmpty()) { Tp::UIntList handles; foreach (const Tp::ContactPtr &contact, initialInviteeContacts) { if (!contact) { continue; } handles << contact->handle()[0]; } if (!handles.isEmpty()) { request.insert(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles"), qVariantFromValue(handles)); } } return request; } QVariantMap conferenceTextChatRequest(const QList &channels, const QStringList &initialInviteeContactsIdentifiers) { QVariantMap request = conferenceRequest(TP_QT_IFACE_CHANNEL_TYPE_TEXT, Tp::HandleTypeNone, channels, initialInviteeContactsIdentifiers); return request; } QVariantMap conferenceTextChatRequest(const QList &channels, const QList &initialInviteeContacts) { QVariantMap request = conferenceRequest(TP_QT_IFACE_CHANNEL_TYPE_TEXT, Tp::HandleTypeNone, channels, initialInviteeContacts); return request; } QVariantMap conferenceTextChatroomRequest(const QString &roomName, const QList &channels, const QStringList &initialInviteeContactsIdentifiers) { QVariantMap request = conferenceRequest(TP_QT_IFACE_CHANNEL_TYPE_TEXT, Tp::HandleTypeRoom, channels, initialInviteeContactsIdentifiers); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), roomName); return request; } QVariantMap conferenceTextChatroomRequest(const QString &roomName, const QList &channels, const QList &initialInviteeContacts) { QVariantMap request = conferenceRequest(TP_QT_IFACE_CHANNEL_TYPE_TEXT, Tp::HandleTypeRoom, channels, initialInviteeContacts); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), roomName); return request; } QVariantMap conferenceStreamedMediaCallRequest(const QList &channels, const QStringList &initialInviteeContactsIdentifiers) { QVariantMap request = conferenceRequest(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, Tp::HandleTypeNone, channels, initialInviteeContactsIdentifiers); return request; } QVariantMap conferenceStreamedMediaCallRequest(const QList &channels, const QList &initialInviteeContacts) { QVariantMap request = conferenceRequest(TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, Tp::HandleTypeNone, channels, initialInviteeContacts); return request; } QVariantMap conferenceCallRequest(const QList &channels, const QStringList &initialInviteeContactsIdentifiers) { QVariantMap request = conferenceRequest(TP_QT_IFACE_CHANNEL_TYPE_CALL, Tp::HandleTypeNone, channels, initialInviteeContactsIdentifiers); return request; } QVariantMap conferenceCallRequest(const QList &channels, const QList &initialInviteeContacts) { QVariantMap request = conferenceRequest(TP_QT_IFACE_CHANNEL_TYPE_CALL, Tp::HandleTypeNone, channels, initialInviteeContacts); return request; } QVariantMap contactSearchRequest(const ConnectionCapabilities &capabilities, const QString &server, uint limit) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); if (capabilities.contactSearchesWithSpecificServer()) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Server"), server); } else if (!server.isEmpty()) { warning() << "Ignoring Server parameter for contact search, since the protocol does not support it."; } if (capabilities.contactSearchesWithLimit()) { request.insert(TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Limit"), limit); } else if (limit > 0) { warning() << "Ignoring Limit parameter for contact search, since the protocol does not support it."; } return request; } } // anonymous namespace struct TP_QT_NO_EXPORT Account::Private { Private(Account *parent, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory); ~Private(); void init(); static void introspectMain(Private *self); static void introspectAvatar(Private *self); static void introspectProtocolInfo(Private *self); static void introspectCapabilities(Private *self); void updateProperties(const QVariantMap &props); void retrieveAvatar(); bool processConnQueue(); bool checkCapabilitiesChanged(bool profileChanged); QString connectionObjectPath() const; // Public object Account *parent; // Factories ConnectionFactoryConstPtr connFactory; ChannelFactoryConstPtr chanFactory; ContactFactoryConstPtr contactFactory; // Instance of generated interface class Client::AccountInterface *baseInterface; // Mandatory properties interface proxy Client::DBus::PropertiesInterface *properties; ReadinessHelper *readinessHelper; // Introspection QVariantMap parameters; bool valid; bool enabled; bool connectsAutomatically; bool hasBeenOnline; bool changingPresence; QString cmName; QString protocolName; QString serviceName; ProfilePtr profile; QString displayName; QString nickname; QString iconName; QQueue connObjPathQueue; ConnectionPtr connection; bool mayFinishCore, coreFinished; QString normalizedName; Avatar avatar; ConnectionManagerPtr cm; ConnectionStatus connectionStatus; ConnectionStatusReason connectionStatusReason; QString connectionError; Connection::ErrorDetails connectionErrorDetails; Presence automaticPresence; Presence currentPresence; Presence requestedPresence; bool usingConnectionCaps; ConnectionCapabilities customCaps; // The contexts should never be removed from the map, to guarantee O(1) CD introspections per bus struct DispatcherContext; static QHash > dispatcherContexts; QSharedPointer dispatcherContext; }; struct Account::Private::DispatcherContext { DispatcherContext(const QDBusConnection &bus) : iface(new Client::ChannelDispatcherInterface(bus, TP_QT_CHANNEL_DISPATCHER_BUS_NAME, TP_QT_CHANNEL_DISPATCHER_OBJECT_PATH)), introspected(false), supportsHints(false) { } ~DispatcherContext() { delete iface; } Client::ChannelDispatcherInterface *iface; bool introspected, supportsHints; QPointer introspectOp; private: DispatcherContext(const DispatcherContext &); void operator=(const DispatcherContext &); }; Account::Private::Private(Account *parent, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) : parent(parent), connFactory(connFactory), chanFactory(chanFactory), contactFactory(contactFactory), baseInterface(new Client::AccountInterface(parent)), properties(parent->interface()), readinessHelper(parent->readinessHelper()), valid(false), enabled(false), connectsAutomatically(false), hasBeenOnline(false), changingPresence(false), mayFinishCore(false), coreFinished(false), connectionStatus(ConnectionStatusDisconnected), connectionStatusReason(ConnectionStatusReasonNoneSpecified), usingConnectionCaps(false), dispatcherContext(dispatcherContexts.value(parent->dbusConnection().name())) { // FIXME: QRegExp probably isn't the most efficient possible way to parse // this :-) QRegExp rx(QLatin1String("^") + TP_QT_ACCOUNT_OBJECT_PATH_BASE + QLatin1String("/([_A-Za-z][_A-Za-z0-9]*)" // cap(1) is the CM "/([_A-Za-z][_A-Za-z0-9]*)" // cap(2) is the protocol "/([_A-Za-z][_A-Za-z0-9]*)" // account-specific part )); if (rx.exactMatch(parent->objectPath())) { cmName = rx.cap(1); protocolName = rx.cap(2).replace(QLatin1Char('_'), QLatin1Char('-')); } else { warning() << "Account object path is not spec-compliant, " "trying again with a different account-specific part check"; rx = QRegExp(QLatin1String("^") + TP_QT_ACCOUNT_OBJECT_PATH_BASE + QLatin1String("/([_A-Za-z][_A-Za-z0-9]*)" // cap(1) is the CM "/([_A-Za-z][_A-Za-z0-9]*)" // cap(2) is the protocol "/([_A-Za-z0-9]*)" // account-specific part )); if (rx.exactMatch(parent->objectPath())) { cmName = rx.cap(1); protocolName = rx.cap(2).replace(QLatin1Char('_'), QLatin1Char('-')); } else { warning() << "Not a valid Account object path:" << parent->objectPath(); } } ReadinessHelper::Introspectables introspectables; // As Account does not have predefined statuses let's simulate one (0) ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMain, this); introspectables[FeatureCore] = introspectableCore; ReadinessHelper::Introspectable introspectableAvatar( QSet() << 0, // makesSenseForStatuses Features() << FeatureCore, // dependsOnFeatures (core) QStringList() << TP_QT_IFACE_ACCOUNT_INTERFACE_AVATAR, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectAvatar, this); introspectables[FeatureAvatar] = introspectableAvatar; ReadinessHelper::Introspectable introspectableProtocolInfo( QSet() << 0, // makesSenseForStatuses Features() << FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectProtocolInfo, this); introspectables[FeatureProtocolInfo] = introspectableProtocolInfo; ReadinessHelper::Introspectable introspectableCapabilities( QSet() << 0, // makesSenseForStatuses Features() << FeatureCore << FeatureProtocolInfo << FeatureProfile, // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectCapabilities, this); introspectables[FeatureCapabilities] = introspectableCapabilities; readinessHelper->addIntrospectables(introspectables); if (connFactory->dbusConnection().name() != parent->dbusConnection().name()) { warning() << " The D-Bus connection in the conn factory is not the proxy connection for" << parent->objectPath(); } if (chanFactory->dbusConnection().name() != parent->dbusConnection().name()) { warning() << " The D-Bus connection in the channel factory is not the proxy connection for" << parent->objectPath(); } if (!dispatcherContext) { dispatcherContext = QSharedPointer(new DispatcherContext(parent->dbusConnection())); dispatcherContexts.insert(parent->dbusConnection().name(), dispatcherContext); } init(); } Account::Private::~Private() { } bool Account::Private::checkCapabilitiesChanged(bool profileChanged) { /* when the capabilities changed: * * - We were using the connection caps and now we don't have connection or * the connection we have is not connected (changed to CM caps) * - We were using the CM caps and now we have a connected connection * (changed to new connection caps) */ bool changed = false; if (usingConnectionCaps && (parent->connection().isNull() || connection->status() != ConnectionStatusConnected)) { usingConnectionCaps = false; changed = true; } else if (!usingConnectionCaps && !parent->connection().isNull() && connection->status() == ConnectionStatusConnected) { usingConnectionCaps = true; changed = true; } else if (!usingConnectionCaps && profileChanged) { changed = true; } if (changed && parent->isReady(FeatureCapabilities)) { emit parent->capabilitiesChanged(parent->capabilities()); } return changed; } QString Account::Private::connectionObjectPath() const { return !connection.isNull() ? connection->objectPath() : QString(); } QHash > Account::Private::dispatcherContexts; /** * \class Account * \ingroup clientaccount * \headerfile TelepathyQt/account.h * * \brief The Account class represents a Telepathy account. * * The remote object accessor functions on this object (isValidAccount(), * isEnabled(), and so on) don't make any D-Bus calls; instead, they return/use * values cached from a previous introspection run. The introspection process * populates their values in the most efficient way possible based on what the * service implements. * * To avoid unnecessary D-Bus traffic, some accessors only return valid * information after specific features have been enabled. * For instance, to retrieve the account protocol information, it is necessary to * enable the feature Account::FeatureProtocolInfo. * See the individual methods descriptions for more details. * * Account features can be enabled by constructing an AccountFactory and enabling * the desired features, and passing it to AccountManager or ClientRegistrar * when creating them as appropriate. However, if a particular * feature is only ever used in a specific circumstance, such as an user opening * some settings dialog separate from the general view of the application, * features can be later enabled as needed by calling becomeReady() with the additional * features, and waiting for the resulting PendingOperation to finish. * * As an addition to accessors, signals are emitted to indicate that properties have * changed, for example displayNameChanged(), iconNameChanged(), etc. * * Convenience methods to create channels using the channel dispatcher such as * ensureTextChat(), createFileTransfer() are also provided. * * If the account is deleted from the AccountManager, this object * will not be deleted automatically; however, it will emit invalidated() * with error code #TP_QT_ERROR_OBJECT_REMOVED and will cease to * be useful. * * \section account_usage_sec Usage * * \subsection account_create_sec Creating an account object * * The easiest way to create account objects is through AccountManager. One can * just use the AccountManager convenience methods such as * AccountManager::validAccounts() to get a list of account objects representing * valid accounts. * * If you already know the object path, you can just call create(). * For example: * * \code AccountPtr acc = Account::create(busName, objectPath); \endcode * * An AccountPtr object is returned, which will automatically keep * track of object lifetime. * * You can also provide a D-Bus connection as a QDBusConnection: * * \code * * AccountPtr acc = Account::create(QDBusConnection::sessionBus(), * busName, objectPath); * * \endcode * * \subsection account_ready_sec Making account ready to use * * An Account object needs to become ready before usage, meaning that the * introspection process finished and the object accessors can be used. * * To make the object ready, use becomeReady() and wait for the * PendingOperation::finished() signal to be emitted. * * \code * * class MyClass : public QObject * { * QOBJECT * * public: * MyClass(QObject *parent = 0); * ~MyClass() { } * * private Q_SLOTS: * void onAccountReady(Tp::PendingOperation*); * * private: * AccountPtr acc; * }; * * MyClass::MyClass(const QString &busName, const QString &objectPath, * QObject *parent) * : QObject(parent) * acc(Account::create(busName, objectPath)) * { * connect(acc->becomeReady(), * SIGNAL(finished(Tp::PendingOperation*)), * SLOT(onAccountReady(Tp::PendingOperation*))); * } * * void MyClass::onAccountReady(Tp::PendingOperation *op) * { * if (op->isError()) { * qWarning() << "Account cannot become ready:" << * op->errorName() << "-" << op->errorMessage(); * return; * } * * // Account is now ready * qDebug() << "Display name:" << acc->displayName(); * } * * \endcode * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the Account * object usable. * * Note that this feature must be enabled in order to use most Account methods. * See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature Account::FeatureCore = Feature(QLatin1String(Account::staticMetaObject.className()), 0, true); /** * Feature used in order to access account avatar info. * * See avatar specific methods' documentation for more details. * * \sa avatar(), avatarChanged() */ const Feature Account::FeatureAvatar = Feature(QLatin1String(Account::staticMetaObject.className()), 1); /** * Feature used in order to access account protocol info. * * See protocol info specific methods' documentation for more details. * * \sa protocolInfo() */ const Feature Account::FeatureProtocolInfo = Feature(QLatin1String(Account::staticMetaObject.className()), 2); /** * Feature used in order to access account capabilities. * * Enabling this feature will also enable FeatureProtocolInfo and FeatureProfile. * * See capabilities specific methods' documentation for more details. * * \sa capabilities(), capabilitiesChanged() */ const Feature Account::FeatureCapabilities = Feature(QLatin1String(Account::staticMetaObject.className()), 3); /** * Feature used in order to access account profile info. * * See profile specific methods' documentation for more details. * * \sa profile(), profileChanged() */ const Feature Account::FeatureProfile = FeatureProtocolInfo; // FeatureProfile is the same as FeatureProtocolInfo for now, as it only needs // the protocol info, cm name and protocol name to build a fake profile. Make it // a full-featured feature if needed later. /** * Create a new Account object using QDBusConnection::sessionBus() and the given factories. * * A warning is printed if the factories are not for QDBusConnection::sessionBus(). * * \param busName The account well-known bus name (sometimes called a "service * name"). This is usually the same as the account manager * bus name #TP_QT_ACCOUNT_MANAGER_BUS_NAME. * \param objectPath The account object path. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return An AccountPtr object pointing to the newly created Account object. */ AccountPtr Account::create(const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return AccountPtr(new Account(QDBusConnection::sessionBus(), busName, objectPath, connectionFactory, channelFactory, contactFactory, Account::FeatureCore)); } /** * Create a new Account object using the given \a bus and the given factories. * * A warning is printed if the factories are not for \a bus. * * \param bus QDBusConnection to use. * \param busName The account well-known bus name (sometimes called a "service * name"). This is usually the same as the account manager * bus name #TP_QT_ACCOUNT_MANAGER_BUS_NAME. * \param objectPath The account object path. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return An AccountPtr object pointing to the newly created Account object. */ AccountPtr Account::create(const QDBusConnection &bus, const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return AccountPtr(new Account(bus, busName, objectPath, connectionFactory, channelFactory, contactFactory, Account::FeatureCore)); } /** * Construct a new Account object using the given \a bus and the given factories. * * A warning is printed if the factories are not for \a bus. * * \param bus QDBusConnection to use. * \param busName The account well-known bus name (sometimes called a "service * name"). This is usually the same as the account manager * bus name #TP_QT_ACCOUNT_MANAGER_BUS_NAME. * \param objectPath The account object path. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \param coreFeature The core feature of the Account subclass. The corresponding introspectable * should depend on Account::FeatureCore. */ Account::Account(const QDBusConnection &bus, const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const Feature &coreFeature) : StatelessDBusProxy(bus, busName, objectPath, coreFeature), OptionalInterfaceFactory(this), mPriv(new Private(this, connectionFactory, channelFactory, contactFactory)) { } /** * Class destructor. */ Account::~Account() { delete mPriv; } /** * Return the connection factory used by this account. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the account would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ConnectionFactory object. */ ConnectionFactoryConstPtr Account::connectionFactory() const { return mPriv->connFactory; } /** * Return the channel factory used by this account. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the account would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ChannelFactory object. */ ChannelFactoryConstPtr Account::channelFactory() const { return mPriv->chanFactory; } /** * Return the contact factory used by this account. * * Only read access is provided. This allows constructing object instances and examining the object * construction settings, but not changing settings. Allowing changes would lead to tricky * situations where objects constructed at different times by the account would have unpredictably * different construction settings (eg. subclass). * * \return A read-only pointer to the ContactFactory object. */ ContactFactoryConstPtr Account::contactFactory() const { return mPriv->contactFactory; } /** * Return whether this account is valid. * * If \c true, this account is considered by the account manager to be complete * and usable. If \c false, user action is required to make it usable, and it will * never attempt to connect. For instance, this might be caused by the absence * or misconfiguration of a required parameter, in which case updateParameters() * may be used to properly set the parameters values. * * Change notification is via the validityChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return \c true if valid, \c false otherwise. * \sa validityChanged(), updateParameters() */ bool Account::isValidAccount() const { return mPriv->valid; } /** * Return whether this account is enabled. * * Change notification is via the stateChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return \c true if enabled, \c false otherwise. * \sa stateChanged(), setEnabled() */ bool Account::isEnabled() const { return mPriv->enabled; } /** * Set whether this account should be enabled or disabled. * * This gives users the possibility to prevent an account from * being used. * * Note that changing this property won't change the validity of the account. * * \param value Whether this account should be enabled or disabled. * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa stateChanged(), isEnabled() */ PendingOperation *Account::setEnabled(bool value) { return new PendingVoid( mPriv->properties->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("Enabled"), QDBusVariant(value)), AccountPtr(this)); } /** * Return the connection manager name of this account. * * \return The connection manager name. */ QString Account::cmName() const { return mPriv->cmName; } /** * Return the protocol name of this account. * * \return The protocol name. */ QString Account::protocolName() const { return mPriv->protocolName; } /** * Return the service name of this account. * * Note that this method will fallback to protocolName() if service name * is not known. * * Change notification is via the serviceNameChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return The service name. * \sa serviceNameChanged(), setServiceName(), protocolName() */ QString Account::serviceName() const { if (mPriv->serviceName.isEmpty()) { return mPriv->protocolName; } return mPriv->serviceName; } /** * Set the service name of this account. * * Some protocols, like XMPP and SIP, are used by various different user-recognised brands, * such as Google Talk. On accounts for such services, this method can be used * to set the name describing the service, which must consist only of ASCII letters, numbers and * hyphen/minus signs, and start with a letter. * For the jabber protocol, one of the following service names should be used if possible: * * google-talk (for Google's IM service) * facebook (for Facebook's IM service) * lj-talk (for LiveJournal's IM service) * * The service name may also be set, if appropriate, when creating the account. See * AccountManager::createAccount() for more details. * * Note that changing this property may also change the profile() used by this account, * in which case profileChanged() will be emitted in addition to serviceNameChanged(), if * Account::FeatureProfile is enabled. * * \param value The service name of this account. * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa serviceNameChanged(), serviceName() */ PendingOperation *Account::setServiceName(const QString &value) { return new PendingVoid( mPriv->properties->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("Service"), QDBusVariant(value)), AccountPtr(this)); } /** * Return the profile used by this account. * * Profiles are intended to describe variants of the basic protocols supported by Telepathy * connection managers. * An example of this would be Google Talk vs Facebook chat vs Jabber/XMPP. Google Talk is a * specific case of XMPP with well-known capabilities, quirks and settings, and Facebook chat is * a subset of the standard XMPP offering. * * This method will return the profile for this account based on the service used by it. * * Note that if a profile for serviceName() is not available, a fake profile * (Profile::isFake() is \c true) will be returned in case protocolInfo() is valid. * * The fake profile will contain the following info: * - Profile::type() will return "IM" * - Profile::provider() will return an empty string * - Profile::serviceName() will return "cmName()-serviceName()" * - Profile::name() and Profile::protocolName() will return protocolName() * - Profile::iconName() will return "im-protocolName()" * - Profile::cmName() will return cmName() * - Profile::parameters() will return a list matching CM default parameters for protocol with name * protocolName() * - Profile::presences() will return an empty list and * Profile::allowOtherPresences() will return \c true, meaning that CM * presences should be used * - Profile::unsupportedChannelClassSpecs() will return an empty list * * Change notification is via the profileChanged() signal. * * This method requires Account::FeatureProfile to be ready. * * \return A pointer to the Profile object. * \sa profileChanged(), serviceName() */ ProfilePtr Account::profile() const { if (!isReady(FeatureProfile)) { warning() << "Account::profile() requires Account::FeatureProfile to be ready"; return ProfilePtr(); } if (!mPriv->profile) { mPriv->profile = Profile::createForServiceName(serviceName()); if (!mPriv->profile->isValid()) { if (protocolInfo().isValid()) { mPriv->profile = ProfilePtr(new Profile( QString(QLatin1String("%1-%2")).arg(mPriv->cmName).arg(serviceName()), mPriv->cmName, mPriv->protocolName, protocolInfo())); } else { warning() << "Cannot create profile as neither a .profile is installed for service" << serviceName() << "nor protocol info can be retrieved"; } } } return mPriv->profile; } /** * Return the display name of this account. * * Change notification is via the displayNameChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return The display name. * \sa displayNameChanged(), setDisplayName() */ QString Account::displayName() const { return mPriv->displayName; } /** * Set the display name of this account. * * The display name is the user-visible name of this account. * This is usually chosen by the user at account creation time. * See AccountManager::createAccount() for more details. * * \param value The display name of this account. * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa displayNameChanged(), displayName() */ PendingOperation *Account::setDisplayName(const QString &value) { return new PendingVoid( mPriv->properties->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("DisplayName"), QDBusVariant(value)), AccountPtr(this)); } /** * Return the icon name of this account. * * If the account has no icon, and Account::FeatureProfile is enabled, the icon from the result of * profile() will be used. * * If neither the account nor the profile has an icon, and Account::FeatureProtocolInfo is * enabled, the icon from protocolInfo() will be used if set. * * As a last resort, "im-" + protocolName() will be returned. * * This matches the fallbacks recommended by the \telepathy_spec. * * Change notification is via the iconNameChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return The icon name. * \sa iconNameChanged(), setIconName() */ QString Account::iconName() const { if (mPriv->iconName.isEmpty()) { if (isReady(FeatureProfile)) { ProfilePtr pr = profile(); if (pr && pr->isValid()) { QString iconName = pr->iconName(); if (!iconName.isEmpty()) { return iconName; } } } if (isReady(FeatureProtocolInfo) && protocolInfo().isValid()) { return protocolInfo().iconName(); } return QString(QLatin1String("im-%1")).arg(protocolName()); } return mPriv->iconName; } /** * Set the icon name of this account. * * \param value The icon name of this account. * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa iconNameChanged(), iconName() */ PendingOperation *Account::setIconName(const QString &value) { return new PendingVoid( mPriv->properties->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("Icon"), QDBusVariant(value)), AccountPtr(this)); } /** * Return the nickname of this account. * * Change notification is via the nicknameChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return The nickname. * \sa nicknameChanged(), setNickname() */ QString Account::nickname() const { return mPriv->nickname; } /** * Set the nickname of this account as seen to other contacts. * * \param value The nickname of this account. * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa nicknameChanged(), nickname() */ PendingOperation *Account::setNickname(const QString &value) { return new PendingVoid( mPriv->properties->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("Nickname"), QDBusVariant(value)), AccountPtr(this)); } /** * Return the avatar requirements (size limits, supported MIME types, etc) * for avatars passed to setAvatar() on this account. * * For now this method will only return the avatar requirements found in protocolInfo() if * Account::FeatureProtocolInfo is ready, otherwise an invalid AvatarSpec instance is returned. * * \return The requirements as an AvatarSpec object. * \sa avatar(), setAvatar() */ AvatarSpec Account::avatarRequirements() const { // TODO Once connection has support for avatar requirements use it if the connection is usable ProtocolInfo pi = protocolInfo(); if (pi.isValid()) { return pi.avatarRequirements(); } return AvatarSpec(); } /** * Return the avatar of this account. * * Change notification is via the avatarChanged() signal. * * This method requires Account::FeatureAvatar to be ready. * * \return The avatar as an Avatar object. * \sa avatarChanged(), setAvatar() */ const Avatar &Account::avatar() const { if (!isReady(Features() << FeatureAvatar)) { warning() << "Trying to retrieve avatar from account, but " "avatar is not supported or was not requested. " "Use becomeReady(FeatureAvatar)"; } return mPriv->avatar; } /** * Set avatar of this account as seen to other contacts. * * Note that \a avatar must match the requirements as returned by avatarRequirements(). * * \param avatar The avatar of this account. * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa avatarChanged(), avatar(), avatarRequirements() */ PendingOperation *Account::setAvatar(const Avatar &avatar) { if (!interfaces().contains(TP_QT_IFACE_ACCOUNT_INTERFACE_AVATAR)) { return new PendingFailure( TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Account does not support Avatar"), AccountPtr(this)); } return new PendingVoid( mPriv->properties->Set( TP_QT_IFACE_ACCOUNT_INTERFACE_AVATAR, QLatin1String("Avatar"), QDBusVariant(QVariant::fromValue(avatar))), AccountPtr(this)); } /** * Return the parameters of this account. * * The account parameters are represented as a map from connection manager parameter names * to their values. * * Change notification is via the parametersChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return The parameters as QVariantMap. * \sa parametersChanged(), updateParameters() */ QVariantMap Account::parameters() const { return mPriv->parameters; } /** * Update this account parameters. * * On success, the PendingOperation returned by this method will produce a * list of strings, which are the names of parameters whose changes will not * take effect until the account is disconnected and reconnected (for instance * by calling reconnect()). * * \param set Parameters to set. * \param unset Parameters to unset. * \return A PendingStringList which will emit PendingStringList::finished * when the request has been made * \sa parametersChanged(), parameters(), reconnect() */ PendingStringList *Account::updateParameters(const QVariantMap &set, const QStringList &unset) { return new PendingStringList( baseInterface()->UpdateParameters(set, unset), AccountPtr(this)); } /** * Return the protocol info of this account protocol. * * This method requires Account::FeatureProtocolInfo to be ready. * * \return The protocol info as a ProtocolInfo object. */ ProtocolInfo Account::protocolInfo() const { if (!isReady(Features() << FeatureProtocolInfo)) { warning() << "Trying to retrieve protocol info from account, but " "protocol info is not supported or was not requested. " "Use becomeReady(FeatureProtocolInfo)"; return ProtocolInfo(); } return mPriv->cm->protocol(mPriv->protocolName); } /** * Return the capabilities for this account. * * Note that this method will return the connection() capabilities if the * account is online and ready. If the account is disconnected, it will fallback * to return the subtraction of the protocolInfo() capabilities and the profile() unsupported * capabilities. * * Change notification is via the capabilitiesChanged() signal. * * This method requires Account::FeatureCapabilities to be ready. * * \return The capabilities as a ConnectionCapabilities object. * \sa capabilitiesChanged(), protocolInfo(), profile() */ ConnectionCapabilities Account::capabilities() const { if (!isReady(FeatureCapabilities)) { warning() << "Trying to retrieve capabilities from account, but " "FeatureCapabilities was not requested. " "Use becomeReady(FeatureCapabilities)"; return ConnectionCapabilities(); } // if the connection is online and ready use its caps if (mPriv->connection && mPriv->connection->status() == ConnectionStatusConnected) { return mPriv->connection->capabilities(); } // if we are here it means FeatureProtocolInfo and FeatureProfile are ready, as // FeatureCapabilities depend on them, so let's use the subtraction of protocol info caps rccs // and profile unsupported rccs. // // However, if we failed to introspect the CM (eg. this is a test), then let's not try to use // the protocolInfo because it'll be NULL! Profile may also be NULL in case a .profile for // serviceName() is not present and protocolInfo is NULL. ProtocolInfo pi = protocolInfo(); if (!pi.isValid()) { return ConnectionCapabilities(); } ProfilePtr pr; if (isReady(FeatureProfile)) { pr = profile(); } if (!pr || !pr->isValid()) { return pi.capabilities(); } RequestableChannelClassSpecList piClassSpecs = pi.capabilities().allClassSpecs(); RequestableChannelClassSpecList prUnsupportedClassSpecs = pr->unsupportedChannelClassSpecs(); RequestableChannelClassSpecList classSpecs; bool unsupported; foreach (const RequestableChannelClassSpec &piClassSpec, piClassSpecs) { unsupported = false; foreach (const RequestableChannelClassSpec &prUnsuportedClassSpec, prUnsupportedClassSpecs) { // Here we check the following: // - If the unsupported spec has no allowed property it means it does not support any // class whose fixed properties match. // E.g: Doesn't support any media calls, be it audio or video. // - If the unsupported spec has allowed properties it means it does not support a // specific class whose fixed properties and allowed properties should match. // E.g: Doesn't support video calls but does support audio calls. if (prUnsuportedClassSpec.allowedProperties().isEmpty()) { if (piClassSpec.fixedProperties() == prUnsuportedClassSpec.fixedProperties()) { unsupported = true; break; } } else { if (piClassSpec == prUnsuportedClassSpec) { unsupported = true; break; } } } if (!unsupported) { classSpecs.append(piClassSpec); } } mPriv->customCaps = ConnectionCapabilities(classSpecs); return mPriv->customCaps; } /** * Return whether this account should be put online automatically whenever * possible. * * Change notification is via the connectsAutomaticallyPropertyChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return \c true if it should try to connect automatically, \c false * otherwise. * \sa connectsAutomaticallyPropertyChanged(), setConnectsAutomatically() */ bool Account::connectsAutomatically() const { return mPriv->connectsAutomatically; } /** * Set whether this account should be put online automatically whenever * possible. * * \param value Value indicating if this account should be put online whenever * possible. * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa connectsAutomaticallyPropertyChanged(), connectsAutomatically() */ PendingOperation *Account::setConnectsAutomatically(bool value) { return new PendingVoid( mPriv->properties->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("ConnectAutomatically"), QDBusVariant(value)), AccountPtr(this)); } /** * Return whether this account has ever been put online successfully. * * This property cannot change from \c true to \c false, only from \c false to \c true. * When the account successfully goes online for the first time, or when it * is detected that this has already happened, the firstOnline() signal is * emitted. * * This method requires Account::FeatureCore to be ready. * * \return \c true if ever been online, \c false otherwise. */ bool Account::hasBeenOnline() const { return mPriv->hasBeenOnline; } /** * Return the status of this account connection. * * Note that this method may return a different value from the one returned by Connection::status() * on this account connection. This happens because this value will change whenever the connection * status of this account connection changes and won't consider the Connection introspection * process. The same rationale also applies to connectionStatusReason() and * connectionErrorDetails(). * * A valid use case for this is for account creation UIs that wish to display the accounts * connection status and nothing else on the connections (e.g. retrieve the contact list). * * Change notification is via the connectionStatusChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return The connection status as #ConnectionStatus. * \sa connectionStatusChanged(), connectionStatusReason(), connectionError(), * connectionErrorDetails() */ ConnectionStatus Account::connectionStatus() const { return mPriv->connectionStatus; } /** * Return the reason for this account connection status. * * This represents the reason for the last change to connectionStatus(). * * Note that this method may return a different value from the one returned by * Connection::statusReason() on this account connection. * See connectionStatus() for more details. * * This method requires Account::FeatureCore to be ready. * * \return The connection status reason as #ConnectionStatusReason. * \sa connectionStatusChanged(), connectionStatus(), connectionError(), connectionErrorDetails() */ ConnectionStatusReason Account::connectionStatusReason() const { return mPriv->connectionStatusReason; } /** * Return the D-Bus error name for the last disconnection or connection failure, * (in particular, #TP_QT_ERROR_CANCELLED if it was disconnected by user * request), or an empty string if the account is connected. * * This method requires Account::FeatureCore to be ready. * * \return The D-Bus error name for the last disconnection or connection failure. * \sa connectionErrorDetails(), connectionStatus(), connectionStatusReason(), * connectionStatusChanged() */ QString Account::connectionError() const { return mPriv->connectionError; } /** * Return detailed information related to connectionError(). * * Note that this method may return a different value from the one returned by * Connection::errorDetails() on this account connection. * See connectionStatus() for more details. * * This method requires Account::FeatureCore to be ready. * * \return The connection error details as a Connection::ErrorDetails object. * \sa connectionError(), connectionStatus(), connectionStatusReason(), connectionStatusChanged(), * Connection::ErrorDetails. */ Connection::ErrorDetails Account::connectionErrorDetails() const { return mPriv->connectionErrorDetails; } /** * Return the object representing the connection of this account. * * Note that the Connection object returned by this method will have the * features set in the connectionFactory() used by this account ready. * * Change notification is via the connectionChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return A pointer to the Connection object, or a null ConnectionPtr if * there is no connection currently or if an error occurred. * \sa connectionChanged() */ ConnectionPtr Account::connection() const { return mPriv->connection; } /** * Return whether this account connection is changing presence. * * Change notification is via the changingPresence() signal. * * This method requires Account::FeatureCore to be ready. * * \return \c true if changing presence, \c false otherwise. * \sa changingPresence(), currentPresenceChanged(), setRequestedPresence() */ bool Account::isChangingPresence() const { return mPriv->changingPresence; } /** * Return a list of presences allowed by a connection to this account. * * In particular, for the statuses reported here it can be assumed that setting them as the * requested presence via setRequestedPresence() will eventually result in currentPresence() * changing to exactly said presence. Other statuses are only guaranteed to be matched as closely as * possible. * * The statuses can be also used for the automatic presence, as set by setAutomaticPresence(), with * the exception of any status specifications for which Presence::type() is * Tp::ConnectionPresenceTypeOffline for the Presence returned by PresenceSpec::presence(). * * However, the optional parameter can be used to allow reporting also other possible presence * statuses on this protocol besides the others that can be set on yourself. These are purely * informatory, for e.g. adjusting an UI to allow all possible remote contact statuses to be * displayed. * * An offline presence status is always included, because it's always valid to make an account * offline by setting the requested presence to an offline status. * * Full functionality requires Account::FeatureProtocolInfo and Account::FeatureProfile to be ready * as well as connection with Connection::FeatureSimplePresence enabled. If the connection is online * and Connection::FeatureSimplePresence is enabled, it will return the connection allowed statuses, * otherwise it will return a list os statuses based on profile() and protocolInfo() information * if the corresponding features are enabled. * * If there's a mismatch between the presence status info provided in the .profile file and/or the * .manager file and what an online Connection actually reports (for example, the said data files * are missing or too old to include presence information), the returned value can change, in * particular when connectionChanged() is emitted with a connection for which Connection::status() * is Tp::ConnectionStatusConnected. * * This method requires Account::FeatureCore to be ready. * * \param includeAllStatuses Whether the returned list will include all statuses or just the ones * that can be settable using setRequestedPresence(). * \return The allowed statuses as a list of PresenceSpec objects. */ PresenceSpecList Account::allowedPresenceStatuses(bool includeAllStatuses) const { QHash specMap; // if the connection is online and ready use it if (mPriv->connection && mPriv->connection->status() == ConnectionStatusConnected && mPriv->connection->actualFeatures().contains(Connection::FeatureSimplePresence)) { SimpleStatusSpecMap connectionAllowedPresences = mPriv->connection->lowlevel()->allowedPresenceStatuses(); SimpleStatusSpecMap::const_iterator i = connectionAllowedPresences.constBegin(); SimpleStatusSpecMap::const_iterator end = connectionAllowedPresences.constEnd(); for (; i != end; ++i) { PresenceSpec presence = PresenceSpec(i.key(), i.value()); specMap.insert(i.key(), presence); } } else { ProtocolInfo pi = protocolInfo(); if (pi.isValid()) { // add all ProtocolInfo presences to the returned map foreach (const PresenceSpec &piPresence, pi.allowedPresenceStatuses()) { QString piStatus = piPresence.presence().status(); specMap.insert(piStatus, piPresence); } } ProfilePtr pr; if (isReady(FeatureProfile)) { pr = profile(); } if (pr && pr->isValid()) { // add all Profile presences to the returned map foreach (const Profile::Presence &prPresence, pr->presences()) { QString prStatus = prPresence.id(); if (specMap.contains(prStatus)) { // we already got the presence from ProtocolInfo, just update // canHaveStatusMessage if needed PresenceSpec presence = specMap.value(prStatus); if (presence.canHaveStatusMessage() != prPresence.canHaveStatusMessage()) { SimpleStatusSpec spec; spec.type = presence.presence().type(); spec.maySetOnSelf = presence.maySetOnSelf(); spec.canHaveMessage = prPresence.canHaveStatusMessage(); specMap.insert(prStatus, PresenceSpec(prStatus, spec)); } } else { // presence not found in ProtocolInfo, adding it specMap.insert(prStatus, presenceSpecForStatus(prStatus, prPresence.canHaveStatusMessage())); } } // now remove all presences that are not in the Profile, if it does // not allow other presences, and the ones that are disabled QHash::iterator i = specMap.begin(); QHash::iterator end = specMap.end(); while (i != end) { PresenceSpec presence = i.value(); QString status = presence.presence().status(); bool hasPresence = pr->hasPresence(status); Profile::Presence prPresence = pr->presence(status); if ((!hasPresence && !pr->allowOtherPresences()) || (hasPresence && prPresence.isDisabled())) { i = specMap.erase(i); } else { ++i; } } } } // filter out presences that may not be set on self if includeAllStatuses is false if (!includeAllStatuses) { QHash::iterator i = specMap.begin(); QHash::iterator end = specMap.end(); while (i != end) { PresenceSpec presence = i.value(); if (!presence.maySetOnSelf()) { i = specMap.erase(i); } else { ++i; } } } if (!specMap.size()) { // If we didn't discover any statuses, either the protocol doesn't really support presence, // or we lack information (e.g. features not enabled or info not provided in the .manager or // .profile files). "available" - just the fact that you're online in the first place, is at // least a valid option for any protocol, so we'll include it as a fallback. specMap.insert(QLatin1String("available"), presenceSpecForStatus(QLatin1String("available"), false)); } // We'll always include "offline". It is always valid to make an account offline via // setRequestedPresence(). if (!specMap.contains(QLatin1String("offline"))) { specMap.insert(QLatin1String("offline"), presenceSpecForStatus(QLatin1String("offline"), false)); } return specMap.values(); } /** * Return the maximum length for a presence status message. * * If a status message set using setRequestedPresence() (or setAutomaticPresence()) is longer than * the maximum length allowed, the message will be truncated and * currentPresenceChanged() will be emitted (if setting the presence worked) * with the truncated message. * * Full functionality requires Connection with Connection::FeatureSimplePresence * enabled. If the connection is online and Connection::FeatureSimplePresence is * enabled, it will return the connection maximum status message length, * otherwise it will return 0. * * This method requires Account::FeatureCore to be ready. * * \return The maximum length, or 0 if there is no limit. */ uint Account::maxPresenceStatusMessageLength() const { // if the connection is online and ready use it if (mPriv->connection && mPriv->connection->status() == ConnectionStatusConnected && mPriv->connection->actualFeatures().contains(Connection::FeatureSimplePresence)) { return mPriv->connection->lowlevel()->maxPresenceStatusMessageLength(); } return 0; } /** * Return the presence status that this account will have set on it by the * account manager if it brings it online automatically. * * Change notification is via the automaticPresenceChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return The automatic presence as a Presence object. * \sa automaticPresenceChanged(), setAutomaticPresence() */ Presence Account::automaticPresence() const { return mPriv->automaticPresence; } /** * Set the presence status that this account should have if it is brought * online automatically by the account manager. * * Note that changing this property won't actually change the account's status * until the next time it is (re)connected for some reason. * * The value of this property must be one that would be acceptable for setRequestedPresence(), * as returned by allowedPresenceStatuses(), with the additional restriction that the offline * presence cannot be used. * * \param presence The presence to set when this account is brought * online automatically by the account manager. * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa automaticPresenceChanged(), automaticPresence(), setRequestedPresence() */ PendingOperation *Account::setAutomaticPresence(const Presence &presence) { return new PendingVoid( mPriv->properties->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("AutomaticPresence"), QDBusVariant(QVariant::fromValue(presence.barePresence()))), AccountPtr(this)); } /** * Return the actual presence of this account. * * Change notification is via the currentPresenceChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return The current presence as a Presence object. * \sa currentPresenceChanged(), setRequestedPresence(), requestedPresence(), automaticPresence() */ Presence Account::currentPresence() const { return mPriv->currentPresence; } /** * Return the requested presence of this account. * * Change notification is via the requestedPresenceChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return The requested presence as a Presence object. * \sa requestedPresenceChanged(), setRequestedPresence(), currentPresence(), automaticPresence() */ Presence Account::requestedPresence() const { return mPriv->requestedPresence; } /** * Set the requested presence of this account. * * When the requested presence is changed, the account manager will attempt to * manipulate the connection to make currentPresence() match requestedPresence() * as closely as possible. * * \param presence The requested presence. * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa requestedPresenceChanged(), currentPresence(), automaticPresence(), setAutomaticPresence() */ PendingOperation *Account::setRequestedPresence(const Presence &presence) { return new PendingVoid( mPriv->properties->Set( TP_QT_IFACE_ACCOUNT, QLatin1String("RequestedPresence"), QDBusVariant(QVariant::fromValue(presence.barePresence()))), AccountPtr(this)); } /** * Return whether this account is online. * * Change notification is via the onlinenessChanged() signal. * * This method requires Account::FeatureCore to be ready. * * \return \c true if online, otherwise \c false. * \sa onlinenessChanged() */ bool Account::isOnline() const { return mPriv->currentPresence.type() != ConnectionPresenceTypeOffline; } /** * Return the unique identifier of this account. * * \return The unique identifier. */ QString Account::uniqueIdentifier() const { QString path = objectPath(); return path.right(path.length() - strlen("/org/freedesktop/Telepathy/Account/")); } /** * Return the normalized user ID of the local user of this account. * * It is unspecified whether this user ID is globally unique. * * As currently implemented, IRC user IDs are only unique within the same * IRCnet. On some saner protocols, the user ID includes a DNS name which * provides global uniqueness. * * If this value is not known yet (which will always be the case for accounts * that have never been online), it will be an empty string. * * It is possible that this value will change if the connection manager's * normalization algorithm changes. * * This method requires Account::FeatureCore to be ready. * * \return The normalized user ID of the local user. * \sa normalizedNameChanged() */ QString Account::normalizedName() const { return mPriv->normalizedName; } /** * If this account is currently connected, disconnect and reconnect it. If it * is currently trying to connect, cancel the attempt to connect and start * another. If it is currently disconnected, do nothing. * * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. */ PendingOperation *Account::reconnect() { return new PendingVoid(baseInterface()->Reconnect(), AccountPtr(this)); } /** * Delete this account. * * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa removed() */ PendingOperation *Account::remove() { return new PendingVoid(baseInterface()->Remove(), AccountPtr(this)); } /** * Return whether passing hints on channel requests on this account is known to be supported. * * This method requires Account::FeatureCore to be ready. * * \return \c true if supported, \c false otherwise. */ bool Account::supportsRequestHints() const { return mPriv->dispatcherContext->supportsHints; } /** * Return whether the ChannelRequest::succeeded(const Tp::ChannelPtr &channel) signal is expected to * be emitted with a non-NULL channel parameter for requests made using this account. * * This can be used as a run-time check for the Channel Dispatcher implementation being new enough. * In particular, similarly old Channel Dispatchers don't support request hints either, so the * return value for this function and Account::supportsRequestHints() will bet he same. * * This method requires Account::FeatureCore to be ready. * * \return \c true if supported, \c false otherwise. */ bool Account::requestsSucceedWithChannel() const { return supportsRequestHints(); } /** * Start a request to ensure that a text channel with the given * contact \a contactIdentifier exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contactIdentifier The identifier of the contact to chat with. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureTextChat( const QString &contactIdentifier, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = textChatRequest(contactIdentifier); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that a text channel with the given * contact \a contact exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contact The contact to chat with. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureTextChat( const ContactPtr &contact, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = textChatRequest(contact); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that a text chat room with the given * room name \a roomName exists, creating it if necessary. * * See ensureChannel() for more details. * * \param roomName The name of the chat room. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureTextChatroom( const QString &roomName, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = textChatroomRequest(roomName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that an audio call channel with the given * contact \a contactIdentifier exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contactIdentifier The identifier of the contact to call. * \param initialAudioContentName The name of the initial CallContent that will * be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureAudioCall( const QString &contactIdentifier, const QString &initialAudioContentName, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = audioCallRequest(contactIdentifier, initialAudioContentName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that an audio call channel with the given * contact \a contact exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contact The contact to call. * \param initialAudioContentName The name of the initial audio CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest* Account::ensureAudioCall( const ContactPtr &contact, const QString &initialAudioContentName, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = audioCallRequest(contact, initialAudioContentName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that a video call channel with the given * contact \a contactIdentifier exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contactIdentifier The identifier of the contact to call. * \param initialVideoContentName The name of the initial video CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureVideoCall( const QString &contactIdentifier, const QString &initialVideoContentName, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = videoCallRequest(contactIdentifier, initialVideoContentName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that a video call channel with the given * contact \a contact exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contact The contact to call. * \param initialVideoContentName The name of the initial video CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureVideoCall( const ContactPtr &contact, const QString &initialVideoContentName, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = videoCallRequest(contact, initialVideoContentName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that an audio/video call channel with the given * contact \a contactIdentifier exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contactIdentifier The identifier of the contact to call. * \param initialAudioContentName The name of the initial audio CallContent that * will be automatically added on the channel. * \param initialVideoContentName The name of the initial video CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureAudioVideoCall( const QString &contactIdentifier, const QString &initialAudioContentName, const QString &initialVideoContentName, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = audioVideoCallRequest(contactIdentifier, initialAudioContentName, initialVideoContentName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that an audio/video call channel with the given * contact \a contact exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contact The contact to call. * \param initialAudioContentName The name of the initial audio CallContent that * will be automatically added on the channel. * \param initialVideoContentName The name of the initial video CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureAudioVideoCall( const ContactPtr &contact, const QString &initialAudioContentName, const QString &initialVideoContentName, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = audioVideoCallRequest(contact, initialAudioContentName, initialVideoContentName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that a media channel with the given * contact \a contactIdentifier exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contactIdentifier The identifier of the contact to call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureStreamedMediaCall( const QString &contactIdentifier, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = streamedMediaCallRequest(contactIdentifier); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that a media channel with the given * contact \a contact exists, creating it if necessary. * * See ensureChannel() for more details. * * \param contact The contact to call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureStreamedMediaCall( const ContactPtr &contact, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = streamedMediaCallRequest(contact); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that an audio call with the given * contact \a contactIdentifier exists, creating it if necessary. * * See ensureChannel() for more details. * * This will only work on relatively modern connection managers, * like telepathy-gabble 0.9.0 or later. * * \param contactIdentifier The identifier of the contact to call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureStreamedMediaAudioCall( const QString &contactIdentifier, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = streamedMediaAudioCallRequest(contactIdentifier); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that an audio call with the given * contact \a contact exists, creating it if necessary. * * See ensureChannel() for more details. * * This will only work on relatively modern connection managers, * like telepathy-gabble 0.9.0 or later. * * \param contact The contact to call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureStreamedMediaAudioCall( const ContactPtr &contact, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = streamedMediaAudioCallRequest(contact); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that a video call with the given * contact \a contactIdentifier exists, creating it if necessary. * * See ensureChannel() for more details. * * This will only work on relatively modern connection managers, * like telepathy-gabble 0.9.0 or later. * * \param contactIdentifier The identifier of the contact to call. * \param withAudio true if both audio and video are required, false for a * video-only call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureStreamedMediaVideoCall( const QString &contactIdentifier, bool withAudio, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = streamedMediaVideoCallRequest(contactIdentifier, withAudio); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to ensure that a video call with the given * contact \a contact exists, creating it if necessary. * * See ensureChannel() for more details. * * This will only work on relatively modern connection managers, * like telepathy-gabble 0.9.0 or later. * * \param contact The contact to call. * \param withAudio true if both audio and video are required, false for a * video-only call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::ensureStreamedMediaVideoCall( const ContactPtr &contact, bool withAudio, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = streamedMediaVideoCallRequest(contact, withAudio); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to create a file transfer channel with the given * contact \a contact. * * \param contactIdentifier The identifier of the contact to send a file. * \param properties The desired properties. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createFileTransfer( const QString &contactIdentifier, const FileTransferChannelCreationProperties &properties, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = fileTransferRequest(contactIdentifier, properties); if (request.isEmpty()) { return new PendingChannelRequest(AccountPtr(this), TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Cannot create a file transfer with invalid parameters")); } return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a file transfer channel with the given * contact \a contact. * * \param contact The contact to send a file. * \param properties The desired properties. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createFileTransfer( const ContactPtr &contact, const FileTransferChannelCreationProperties &properties, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = fileTransferRequest(contact, properties); if (request.isEmpty()) { return new PendingChannelRequest(AccountPtr(this), TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Cannot create a file transfer with invalid parameters")); } return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a stream tube channel with the given * contact identifier \a contactIdentifier. * * \param contactIdentifier The identifier of the contact to open a stream tube with. * \param service The stream tube service. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createStreamTube( const QString &contactIdentifier, const QString &service, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = streamTubeRequest(contactIdentifier, service); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a stream tube channel with the given * contact \a contact. * * \param contact The contact to open a stream tube with. * \param service The stream tube service. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createStreamTube( const ContactPtr &contact, const QString &service, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = streamTubeRequest(contact, service); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a DBus tube channel with the given * contact \a contactIdentifier. * * \param contactIdentifier The contact identifier of the contact to open a DBus tube with. * \param serviceName the service name that will be used over the * tube. It should be a well-known D-Bus service name, of the form * \c com.example.ServiceName * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the call has finished. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createDBusTube( const QString &contactIdentifier, const QString &serviceName, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = dbusTubeRequest(contactIdentifier, serviceName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a DBus tube channel with the given * contact \a contact. * * \param contact The contact to open a DBus tube with. * \param serviceName the service name that will be used over the * tube. It should be a well-known D-Bus service name, of the form * \c com.example.ServiceName * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the call has finished. * \sa ensureChannel(), createChannel() */ PendingChannelRequest* Account::createDBusTube( const Tp::ContactPtr& contact, const QString& serviceName, const QDateTime& userActionTime, const QString& preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = dbusTubeRequest(contact, serviceName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } PendingChannelRequest* Account::createDBusTubeRoom( const QString &room, const QString &serviceName, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = dbusTubeRoomRequest(room, serviceName); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a conference media call with the given * channels \a channels. * * \param channels The conference channels. * \param initialInviteeContactsIdentifiers A list of additional contacts * identifiers to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createConferenceStreamedMediaCall( const QList &channels, const QStringList &initialInviteeContactsIdentifiers, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = conferenceStreamedMediaCallRequest(channels, initialInviteeContactsIdentifiers); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a conference media call with the given * channels \a channels. * * \param channels The conference channels. * \param initialInviteeContacts A list of additional contacts * to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createConferenceStreamedMediaCall( const QList &channels, const QList &initialInviteeContacts, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = conferenceStreamedMediaCallRequest(channels, initialInviteeContacts); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a conference call with the given * channels \a channels. * * \param channels The conference channels. * \param initialInviteeContactsIdentifiers A list of additional contacts * identifiers to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createConferenceCall( const QList &channels, const QStringList &initialInviteeContactsIdentifiers, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = conferenceCallRequest(channels, initialInviteeContactsIdentifiers); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a conference call with the given * channels \a channels. * * \param channels The conference channels. * \param initialInviteeContacts A list of additional contacts * to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createConferenceCall( const QList &channels, const QList &initialInviteeContacts, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = conferenceCallRequest(channels, initialInviteeContacts); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a conference text chat with the given * channels \a channels. * * \param channels The conference channels. * \param initialInviteeContactsIdentifiers A list of additional contacts * identifiers to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createConferenceTextChat( const QList &channels, const QStringList &initialInviteeContactsIdentifiers, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = conferenceTextChatRequest(channels, initialInviteeContactsIdentifiers); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a conference text chat with the given * channels \a channels. * * \param channels The conference channels. * \param initialInviteeContacts A list of additional contacts * to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createConferenceTextChat( const QList &channels, const QList &initialInviteeContacts, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = conferenceTextChatRequest(channels, initialInviteeContacts); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a conference text chat room with the given * channels \a channels and room name \a roomName. * * \param roomName The room name. * \param channels The conference channels. * \param initialInviteeContactsIdentifiers A list of additional contacts * identifiers to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createConferenceTextChatroom( const QString &roomName, const QList &channels, const QStringList &initialInviteeContactsIdentifiers, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = conferenceTextChatroomRequest(roomName, channels, initialInviteeContactsIdentifiers); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a conference text chat room with the given * channels \a channels and room name \a roomName. * * \param roomName The room name. * \param channels The conference channels. * \param initialInviteeContacts A list of additional contacts * to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa ensureChannel(), createChannel() */ PendingChannelRequest *Account::createConferenceTextChatroom( const QString &roomName, const QList &channels, const QList &initialInviteeContacts, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = conferenceTextChatroomRequest(roomName, channels, initialInviteeContacts); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to create a conference call with the given * channels \a channels. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param channels The conference channels. * \param initialInviteeContactsIdentifiers A list of additional contacts * identifiers to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleConferenceCall( const QList &channels, const QStringList &initialInviteeContactsIdentifiers, const QDateTime &userActionTime) { QVariantMap request = conferenceCallRequest(channels, initialInviteeContactsIdentifiers); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a conference call with the given * channels \a channels. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param channels The conference channels. * \param initialInviteeContacts A list of additional contacts * to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleConferenceCall( const QList &channels, const QList &initialInviteeContacts, const QDateTime &userActionTime) { QVariantMap request = conferenceCallRequest(channels, initialInviteeContacts); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a contact search channel with the given * server \a server and limit \a limit. * * \param server For protocols which support searching for contacts on multiple servers with * different DNS names (like XMPP), the DNS name of the server to be searched, * e.g. "characters.shakespeare.lit". Otherwise, an empty string. * \param limit The desired maximum number of results that should be returned by a doing a search. * If the protocol does not support specifying a limit for the number of results * returned at a time, this will be ignored. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa createChannel() */ PendingChannelRequest *Account::createContactSearch( const QString &server, uint limit, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { QVariantMap request = contactSearchRequest(capabilities(), server, limit); return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to ensure that a text channel with the given * contact \a contactIdentifier exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contactIdentifier The identifier of the contact to chat with. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleTextChat( const QString &contactIdentifier, const QDateTime &userActionTime) { QVariantMap request = textChatRequest(contactIdentifier); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that a text channel with the given * contact \a contact exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contact The contact to chat with. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleTextChat( const ContactPtr &contact, const QDateTime &userActionTime) { QVariantMap request = textChatRequest(contact); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that a text chat room with the given * room name \a roomName exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param roomName The name of the chat room. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleTextChatroom( const QString &roomName, const QDateTime &userActionTime) { QVariantMap request = textChatroomRequest(roomName); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that an audio call channel with the given * contact \a contactIdentifier exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contactIdentifier The identifier of the contact to call. * \param initialAudioContentName The name of the initial audio CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleAudioCall( const QString &contactIdentifier, const QString &initialAudioContentName, const QDateTime &userActionTime) { QVariantMap request = audioCallRequest(contactIdentifier, initialAudioContentName); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that an audio call channel with the given * contact \a contact exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contact The contact to call. * \param initialAudioContentName The name of the initial audio CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleAudioCall( const ContactPtr &contact, const QString &initialAudioContentName, const QDateTime &userActionTime) { QVariantMap request = audioCallRequest(contact, initialAudioContentName); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that a video call channel with the given * contact \a contactIdentifier exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contactIdentifier The identifier of the contact to call. * \param initialVideoContentName The name of the initial video CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleVideoCall( const QString &contactIdentifier, const QString &initialVideoContentName, const QDateTime &userActionTime) { QVariantMap request = videoCallRequest(contactIdentifier, initialVideoContentName); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that a video call channel with the given * contact \a contact exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contact The contact to call. * \param initialVideoContentName The name of the initial video CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleVideoCall( const ContactPtr &contact, const QString &initialVideoContentName, const QDateTime &userActionTime) { QVariantMap request = videoCallRequest(contact, initialVideoContentName); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that an audio/video call channel with the given * contact \a contactIdentifier exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contactIdentifier The identifier of the contact to call. * \param initialAudioContentName The name of the initial audio CallContent that * will be automatically added on the channel. * \param initialVideoContentName The name of the initial video CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleAudioVideoCall( const QString &contactIdentifier, const QString &initialAudioContentName, const QString &initialVideoContentName, const QDateTime &userActionTime) { QVariantMap request = audioVideoCallRequest(contactIdentifier, initialAudioContentName, initialVideoContentName); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that an audio/video call channel with the given * contact \a contact exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contact The contact to call. * \param initialAudioContentName The name of the initial audio CallContent that * will be automatically added on the channel. * \param initialVideoContentName The name of the initial video CallContent that * will be automatically added on the channel. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleAudioVideoCall( const ContactPtr &contact, const QString &initialAudioContentName, const QString &initialVideoContentName, const QDateTime &userActionTime) { QVariantMap request = audioVideoCallRequest(contact, initialAudioContentName, initialVideoContentName); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that a media channel with the given * contact \a contactIdentifier exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contactIdentifier The identifier of the contact to call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleStreamedMediaCall( const QString &contactIdentifier, const QDateTime &userActionTime) { QVariantMap request = streamedMediaCallRequest(contactIdentifier); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that a media channel with the given * contact \a contact exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contact The contact to call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleStreamedMediaCall( const ContactPtr &contact, const QDateTime &userActionTime) { QVariantMap request = streamedMediaCallRequest(contact); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that an audio call with the given * contact \a contactIdentifier exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * This will only work on relatively modern connection managers, * like telepathy-gabble 0.9.0 or later. * * \param contactIdentifier The identifier of the contact to call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleStreamedMediaAudioCall( const QString &contactIdentifier, const QDateTime &userActionTime) { QVariantMap request = streamedMediaAudioCallRequest(contactIdentifier); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that an audio call with the given * contact \a contact exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * This will only work on relatively modern connection managers, * like telepathy-gabble 0.9.0 or later. * * \param contact The contact to call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleStreamedMediaAudioCall( const ContactPtr &contact, const QDateTime &userActionTime) { QVariantMap request = streamedMediaAudioCallRequest(contact); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that a video call with the given * contact \a contactIdentifier exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * This will only work on relatively modern connection managers, * like telepathy-gabble 0.9.0 or later. * * \param contactIdentifier The identifier of the contact to call. * \param withAudio true if both audio and video are required, false for a * video-only call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleStreamedMediaVideoCall( const QString &contactIdentifier, bool withAudio, const QDateTime &userActionTime) { QVariantMap request = streamedMediaVideoCallRequest(contactIdentifier, withAudio); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to ensure that a video call with the given * contact \a contact exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * This will only work on relatively modern connection managers, * like telepathy-gabble 0.9.0 or later. * * \param contact The contact to call. * \param withAudio true if both audio and video are required, false for a * video-only call. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleStreamedMediaVideoCall( const ContactPtr &contact, bool withAudio, const QDateTime &userActionTime) { QVariantMap request = streamedMediaVideoCallRequest(contact, withAudio); return ensureAndHandleChannel(request, userActionTime); } /** * Start a request to create a file transfer channel with the given * contact \a contactIdentifier. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contactIdentifier The identifier of the contact to send a file. * \param properties The desired properties. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleFileTransfer( const QString &contactIdentifier, const FileTransferChannelCreationProperties &properties, const QDateTime &userActionTime) { QVariantMap request = fileTransferRequest(contactIdentifier, properties); if (request.isEmpty()) { return new PendingChannel(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Cannot create a file transfer with invalid parameters")); } return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a file transfer channel with the given * contact \a contact. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contact The contact to send a file. * \param properties The desired properties. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleFileTransfer( const ContactPtr &contact, const FileTransferChannelCreationProperties &properties, const QDateTime &userActionTime) { QVariantMap request = fileTransferRequest(contact, properties); if (request.isEmpty()) { return new PendingChannel(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Cannot create a file transfer with invalid parameters")); } return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a stream tube channel with the given * contact identifier \a contactIdentifier. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contactIdentifier The identifier of the contact to open a stream tube with. * \param service The stream tube service. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleStreamTube( const QString &contactIdentifier, const QString &service, const QDateTime &userActionTime) { QVariantMap request = streamTubeRequest(contactIdentifier, service); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a stream tube channel with the given * contact \a contact. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contact The contact to open a stream tube with. * \param service The stream tube service. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleStreamTube( const ContactPtr &contact, const QString &service, const QDateTime &userActionTime) { QVariantMap request = streamTubeRequest(contact, service); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a DBus tube channel with the given * contact identifier \a contactIdentifier. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contactIdentifier The identifier of the contact to open a DBus tube with. * \param serviceName The DBus tube service name. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleDBusTube( const QString &contactIdentifier, const QString &serviceName, const QDateTime &userActionTime) { QVariantMap request = dbusTubeRequest(contactIdentifier, serviceName); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a DBus tube channel with the given * contact \a contact. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param contact The contact to open a DBus tube with. * \param service The DBus tube service name. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleDBusTube( const ContactPtr &contact, const QString &serviceName, const QDateTime &userActionTime) { QVariantMap request = dbusTubeRequest(contact, serviceName); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a conference text chat with the given * channels \a channels. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param channels The conference channels. * \param initialInviteeContactsIdentifiers A list of additional contacts * identifiers to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleConferenceTextChat( const QList &channels, const QStringList &initialInviteeContactsIdentifiers, const QDateTime &userActionTime) { QVariantMap request = conferenceTextChatRequest(channels, initialInviteeContactsIdentifiers); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a conference text chat with the given * channels \a channels. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param channels The conference channels. * \param initialInviteeContacts A list of additional contacts * to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleConferenceTextChat( const QList &channels, const QList &initialInviteeContacts, const QDateTime &userActionTime) { QVariantMap request = conferenceTextChatRequest(channels, initialInviteeContacts); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a conference text chat room with the given * channels \a channels and room name \a roomName. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param roomName The room name. * \param channels The conference channels. * \param initialInviteeContactsIdentifiers A list of additional contacts * identifiers to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleConferenceTextChatroom( const QString &roomName, const QList &channels, const QStringList &initialInviteeContactsIdentifiers, const QDateTime &userActionTime) { QVariantMap request = conferenceTextChatroomRequest(roomName, channels, initialInviteeContactsIdentifiers); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a conference text chat room with the given * channels \a channels and room name \a roomName. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param roomName The room name. * \param channels The conference channels. * \param initialInviteeContacts A list of additional contacts * to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleConferenceTextChatroom( const QString &roomName, const QList &channels, const QList &initialInviteeContacts, const QDateTime &userActionTime) { QVariantMap request = conferenceTextChatroomRequest(roomName, channels, initialInviteeContacts); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a conference media call with the given * channels \a channels. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param channels The conference channels. * \param initialInviteeContactsIdentifiers A list of additional contacts * identifiers to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleConferenceStreamedMediaCall( const QList &channels, const QStringList &initialInviteeContactsIdentifiers, const QDateTime &userActionTime) { QVariantMap request = conferenceStreamedMediaCallRequest(channels, initialInviteeContactsIdentifiers); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a conference media call with the given * channels \a channels. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param channels The conference channels. * \param initialInviteeContacts A list of additional contacts * to be invited to this * conference when it is created. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleConferenceStreamedMediaCall( const QList &channels, const QList &initialInviteeContacts, const QDateTime &userActionTime) { QVariantMap request = conferenceStreamedMediaCallRequest(channels, initialInviteeContacts); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a contact search channel with the given * server \a server and limit \a limit. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * \param server For protocols which support searching for contacts on multiple servers with * different DNS names (like XMPP), the DNS name of the server to be searched, * e.g. "characters.shakespeare.lit". Otherwise, an empty string. * If the protocol does not support specifying a search server, this will be ignored. * \param limit The desired maximum number of results that should be returned by a doing a search. * If the protocol does not support specifying a limit for the number of results * returned at a time, this will be ignored. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel(), createAndHandleChannel() */ PendingChannel *Account::createAndHandleContactSearch( const QString &server, uint limit, const QDateTime &userActionTime) { QVariantMap request = contactSearchRequest(capabilities(), server, limit); return createAndHandleChannel(request, userActionTime); } /** * Start a request to create a channel. * This initially just creates a PendingChannelRequest object, * which can be used to track the success or failure of the request, * or to cancel it. * * Helper methods for text chat, text chat room, media call and conference are * provided and should be used if appropriate. * * \param request A dictionary containing desirable properties. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa createChannel() */ PendingChannelRequest *Account::createChannel( const QVariantMap &request, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, true, hints); } /** * Start a request to ensure that a channel exists, creating it if necessary. * This initially just creates a PendingChannelRequest object, * which can be used to track the success or failure of the request, * or to cancel it. * * Helper methods for text chat, text chat room, media call and conference are * provided and should be used if appropriate. * * \param request A dictionary containing desirable properties. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param hints Arbitrary metadata which will be relayed to the handler if supported, * as indicated by supportsRequestHints(). * \return A PendingChannelRequest which will emit PendingChannelRequest::finished * when the request has been made. * \sa createChannel() */ PendingChannelRequest *Account::ensureChannel( const QVariantMap &request, const QDateTime &userActionTime, const QString &preferredHandler, const ChannelRequestHints &hints) { return new PendingChannelRequest(AccountPtr(this), request, userActionTime, preferredHandler, false, hints); } /** * Start a request to create channel. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * Helper methods for text chat, text chat room, media call and conference are * provided and should be used if appropriate. * * The caller is responsible for closing the channel with * Channel::requestClose() or Channel::requestLeave() when it has finished handling it. * * A possible error returned by this method is #TP_QT_ERROR_NOT_AVAILABLE, in case a conflicting * channel that matches \a request already exists. * * \param request A dictionary containing desirable properties. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa ensureAndHandleChannel() */ PendingChannel *Account::createAndHandleChannel( const QVariantMap &request, const QDateTime &userActionTime) { return new PendingChannel(AccountPtr(this), request, userActionTime, true); } /** * Start a request to ensure that a channel exists, creating it if necessary. * This initially just creates a PendingChannel object, * which can be used to track the success or failure of the request. * * Helper methods for text chat, text chat room, media call and conference are * provided and should be used if appropriate. * * The caller is responsible for closing the channel with * Channel::requestClose() or Channel::requestLeave() when it has finished handling it. * * A possible error returned by this method is #TP_QT_ERROR_NOT_YOURS, in case somebody else is * already handling a channel that matches \a request. * * \param request A dictionary containing desirable properties. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \return A PendingChannel which will emit PendingChannel::finished * successfully, when the Channel is available for handling using * PendingChannel::channel(), or with an error if one has been encountered. * \sa createAndHandleChannel() */ PendingChannel *Account::ensureAndHandleChannel( const QVariantMap &request, const QDateTime &userActionTime) { return new PendingChannel(AccountPtr(this), request, userActionTime, false); } /** * Return the Client::AccountInterface interface proxy object for this account. * This method is protected since the convenience methods provided by this * class should generally be used instead of calling D-Bus methods * directly. * * \return A pointer to the existing Client::AccountInterface object for this * Account object. */ Client::AccountInterface *Account::baseInterface() const { return mPriv->baseInterface; } /** * Return the Client::ChannelDispatcherInterface interface proxy object to use for requesting * channels on this account. * * This method is protected since the convenience methods provided by this * class should generally be used instead of calling D-Bus methods * directly. * * \return A pointer to the existing Client::ChannelDispatcherInterface object for this * Account object. */ Client::ChannelDispatcherInterface *Account::dispatcherInterface() const { return mPriv->dispatcherContext->iface; } /**** Private ****/ void Account::Private::init() { if (!parent->isValid()) { return; } parent->connect(baseInterface, SIGNAL(Removed()), SLOT(onRemoved())); parent->connect(baseInterface, SIGNAL(AccountPropertyChanged(QVariantMap)), SLOT(onPropertyChanged(QVariantMap))); } void Account::Private::introspectMain(Account::Private *self) { if (self->dispatcherContext->introspected) { self->parent->onDispatcherIntrospected(0); return; } if (!self->dispatcherContext->introspectOp) { debug() << "Discovering if the Channel Dispatcher supports request hints"; self->dispatcherContext->introspectOp = self->dispatcherContext->iface->requestPropertySupportsRequestHints(); } connect(self->dispatcherContext->introspectOp.data(), SIGNAL(finished(Tp::PendingOperation*)), self->parent, SLOT(onDispatcherIntrospected(Tp::PendingOperation*))); } void Account::Private::introspectAvatar(Account::Private *self) { debug() << "Calling GetAvatar(Account)"; // we already checked if avatar interface exists, so bypass avatar interface // checking Client::AccountInterfaceAvatarInterface *iface = self->parent->interface(); // If we are here it means the user cares about avatar, so // connect to avatar changed signal, so we update the avatar // when it changes. self->parent->connect(iface, SIGNAL(AvatarChanged()), SLOT(onAvatarChanged())); self->retrieveAvatar(); } void Account::Private::introspectProtocolInfo(Account::Private *self) { Q_ASSERT(!self->cm); self->cm = ConnectionManager::create( self->parent->dbusConnection(), self->cmName, self->connFactory, self->chanFactory, self->contactFactory); self->parent->connect(self->cm->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onConnectionManagerReady(Tp::PendingOperation*))); } void Account::Private::introspectCapabilities(Account::Private *self) { if (!self->connection) { // there is no connection, just make capabilities ready self->readinessHelper->setIntrospectCompleted(FeatureCapabilities, true); return; } self->parent->connect(self->connection->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onConnectionReady(Tp::PendingOperation*))); } void Account::Private::updateProperties(const QVariantMap &props) { debug() << "Account::updateProperties: changed:"; if (props.contains(QLatin1String("Interfaces"))) { parent->setInterfaces(qdbus_cast(props[QLatin1String("Interfaces")])); debug() << " Interfaces:" << parent->interfaces(); } QString oldIconName = parent->iconName(); bool serviceNameChanged = false; bool profileChanged = false; if (props.contains(QLatin1String("Service")) && serviceName != qdbus_cast(props[QLatin1String("Service")])) { serviceNameChanged = true; serviceName = qdbus_cast(props[QLatin1String("Service")]); debug() << " Service Name:" << parent->serviceName(); /* use parent->serviceName() here as if the service name is empty we are going to use the * protocol name */ emit parent->serviceNameChanged(parent->serviceName()); parent->notify("serviceName"); /* if we had a profile and the service changed, it means the profile also changed */ if (parent->isReady(Account::FeatureProfile)) { /* service name changed, let's recreate profile */ profileChanged = true; profile.reset(); emit parent->profileChanged(parent->profile()); parent->notify("profile"); } } if (props.contains(QLatin1String("DisplayName")) && displayName != qdbus_cast(props[QLatin1String("DisplayName")])) { displayName = qdbus_cast(props[QLatin1String("DisplayName")]); debug() << " Display Name:" << displayName; emit parent->displayNameChanged(displayName); parent->notify("displayName"); } if ((props.contains(QLatin1String("Icon")) && oldIconName != qdbus_cast(props[QLatin1String("Icon")])) || serviceNameChanged) { if (props.contains(QLatin1String("Icon"))) { iconName = qdbus_cast(props[QLatin1String("Icon")]); } QString newIconName = parent->iconName(); if (oldIconName != newIconName) { debug() << " Icon:" << newIconName; emit parent->iconNameChanged(newIconName); parent->notify("iconName"); } } if (props.contains(QLatin1String("Nickname")) && nickname != qdbus_cast(props[QLatin1String("Nickname")])) { nickname = qdbus_cast(props[QLatin1String("Nickname")]); debug() << " Nickname:" << nickname; emit parent->nicknameChanged(nickname); parent->notify("nickname"); } if (props.contains(QLatin1String("NormalizedName")) && normalizedName != qdbus_cast(props[QLatin1String("NormalizedName")])) { normalizedName = qdbus_cast(props[QLatin1String("NormalizedName")]); debug() << " Normalized Name:" << normalizedName; emit parent->normalizedNameChanged(normalizedName); parent->notify("normalizedName"); } if (props.contains(QLatin1String("Valid")) && valid != qdbus_cast(props[QLatin1String("Valid")])) { valid = qdbus_cast(props[QLatin1String("Valid")]); debug() << " Valid:" << (valid ? "true" : "false"); emit parent->validityChanged(valid); parent->notify("valid"); } if (props.contains(QLatin1String("Enabled")) && enabled != qdbus_cast(props[QLatin1String("Enabled")])) { enabled = qdbus_cast(props[QLatin1String("Enabled")]); debug() << " Enabled:" << (enabled ? "true" : "false"); emit parent->stateChanged(enabled); parent->notify("enabled"); } if (props.contains(QLatin1String("ConnectAutomatically")) && connectsAutomatically != qdbus_cast(props[QLatin1String("ConnectAutomatically")])) { connectsAutomatically = qdbus_cast(props[QLatin1String("ConnectAutomatically")]); debug() << " Connects Automatically:" << (connectsAutomatically ? "true" : "false"); emit parent->connectsAutomaticallyPropertyChanged(connectsAutomatically); parent->notify("connectsAutomatically"); } if (props.contains(QLatin1String("HasBeenOnline")) && !hasBeenOnline && qdbus_cast(props[QLatin1String("HasBeenOnline")])) { hasBeenOnline = true; debug() << " HasBeenOnline changed to true"; // don't emit firstOnline unless we're already ready, that would be // misleading - we'd emit it just before any already-used account // became ready if (parent->isReady(Account::FeatureCore)) { emit parent->firstOnline(); } parent->notify("hasBeenOnline"); } if (props.contains(QLatin1String("Parameters")) && parameters != qdbus_cast(props[QLatin1String("Parameters")])) { parameters = qdbus_cast(props[QLatin1String("Parameters")]); emit parent->parametersChanged(parameters); parent->notify("parameters"); } if (props.contains(QLatin1String("AutomaticPresence")) && automaticPresence.barePresence() != qdbus_cast( props[QLatin1String("AutomaticPresence")])) { automaticPresence = Presence(qdbus_cast( props[QLatin1String("AutomaticPresence")])); debug() << " Automatic Presence:" << automaticPresence.type() << "-" << automaticPresence.status(); emit parent->automaticPresenceChanged(automaticPresence); parent->notify("automaticPresence"); } if (props.contains(QLatin1String("CurrentPresence")) && currentPresence.barePresence() != qdbus_cast( props[QLatin1String("CurrentPresence")])) { currentPresence = Presence(qdbus_cast( props[QLatin1String("CurrentPresence")])); debug() << " Current Presence:" << currentPresence.type() << "-" << currentPresence.status(); emit parent->currentPresenceChanged(currentPresence); parent->notify("currentPresence"); emit parent->onlinenessChanged(parent->isOnline()); parent->notify("online"); } if (props.contains(QLatin1String("RequestedPresence")) && requestedPresence.barePresence() != qdbus_cast( props[QLatin1String("RequestedPresence")])) { requestedPresence = Presence(qdbus_cast( props[QLatin1String("RequestedPresence")])); debug() << " Requested Presence:" << requestedPresence.type() << "-" << requestedPresence.status(); emit parent->requestedPresenceChanged(requestedPresence); parent->notify("requestedPresence"); } if (props.contains(QLatin1String("ChangingPresence")) && changingPresence != qdbus_cast( props[QLatin1String("ChangingPresence")])) { changingPresence = qdbus_cast( props[QLatin1String("ChangingPresence")]); debug() << " Changing Presence:" << changingPresence; emit parent->changingPresence(changingPresence); parent->notify("changingPresence"); } if (props.contains(QLatin1String("Connection"))) { QString path = qdbus_cast(props[QLatin1String("Connection")]).path(); if (path.isEmpty()) { debug() << " The map contains \"Connection\" but it's empty as a QDBusObjectPath!"; debug() << " Trying QString (known bug in some MC/dbus-glib versions)"; path = qdbus_cast(props[QLatin1String("Connection")]); } debug() << " Connection Object Path:" << path; if (path == QLatin1String("/")) { path = QString(); } connObjPathQueue.enqueue(path); if (connObjPathQueue.size() == 1) { processConnQueue(); } // onConnectionBuilt for a previous path will make sure the path we enqueued is processed if // the queue wasn't empty (so is now size() > 1) } bool connectionStatusChanged = false; if (props.contains(QLatin1String("ConnectionStatus")) || props.contains(QLatin1String("ConnectionStatusReason")) || props.contains(QLatin1String("ConnectionError")) || props.contains(QLatin1String("ConnectionErrorDetails"))) { ConnectionStatus oldConnectionStatus = connectionStatus; if (props.contains(QLatin1String("ConnectionStatus")) && connectionStatus != ConnectionStatus( qdbus_cast(props[QLatin1String("ConnectionStatus")]))) { connectionStatus = ConnectionStatus( qdbus_cast(props[QLatin1String("ConnectionStatus")])); debug() << " Connection Status:" << connectionStatus; connectionStatusChanged = true; } if (props.contains(QLatin1String("ConnectionStatusReason")) && connectionStatusReason != ConnectionStatusReason( qdbus_cast(props[QLatin1String("ConnectionStatusReason")]))) { connectionStatusReason = ConnectionStatusReason( qdbus_cast(props[QLatin1String("ConnectionStatusReason")])); debug() << " Connection StatusReason:" << connectionStatusReason; connectionStatusChanged = true; } if (connectionStatusChanged) { parent->notify("connectionStatus"); parent->notify("connectionStatusReason"); } if (props.contains(QLatin1String("ConnectionError")) && connectionError != qdbus_cast( props[QLatin1String("ConnectionError")])) { connectionError = qdbus_cast( props[QLatin1String("ConnectionError")]); debug() << " Connection Error:" << connectionError; connectionStatusChanged = true; } if (props.contains(QLatin1String("ConnectionErrorDetails")) && connectionErrorDetails.allDetails() != qdbus_cast( props[QLatin1String("ConnectionErrorDetails")])) { connectionErrorDetails = Connection::ErrorDetails(qdbus_cast( props[QLatin1String("ConnectionErrorDetails")])); debug() << " Connection Error Details:" << connectionErrorDetails.allDetails(); connectionStatusChanged = true; } if (connectionStatusChanged) { /* Something other than status changed, let's not emit connectionStatusChanged * and keep the error/errorDetails, for the next interaction. * It may happen if ConnectionError changes and in another property * change the status changes to Disconnected, so we use the error * previously signalled. If the status changes to something other * than Disconnected later, the error is cleared. */ if (oldConnectionStatus != connectionStatus) { /* We don't signal error for status other than Disconnected */ if (connectionStatus != ConnectionStatusDisconnected) { connectionError = QString(); connectionErrorDetails = Connection::ErrorDetails(); } else if (connectionError.isEmpty()) { connectionError = ConnectionHelper::statusReasonToErrorName( connectionStatusReason, oldConnectionStatus); } checkCapabilitiesChanged(profileChanged); emit parent->connectionStatusChanged(connectionStatus); parent->notify("connectionError"); parent->notify("connectionErrorDetails"); } else { connectionStatusChanged = false; } } } if (!connectionStatusChanged && profileChanged) { checkCapabilitiesChanged(profileChanged); } } void Account::Private::retrieveAvatar() { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( parent->mPriv->properties->Get( TP_QT_IFACE_ACCOUNT_INTERFACE_AVATAR, QLatin1String("Avatar")), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotAvatar(QDBusPendingCallWatcher*))); } bool Account::Private::processConnQueue() { while (!connObjPathQueue.isEmpty()) { QString path = connObjPathQueue.head(); if (path.isEmpty()) { if (!connection.isNull()) { debug() << "Dropping connection for account" << parent->objectPath(); connection.reset(); emit parent->connectionChanged(connection); parent->notify("connection"); parent->notify("connectionObjectPath"); } connObjPathQueue.dequeue(); } else { debug() << "Building connection" << path << "for account" << parent->objectPath(); if (connection && connection->objectPath() == path) { debug() << " Connection already built"; connObjPathQueue.dequeue(); continue; } QString busName = path.mid(1).replace(QLatin1String("/"), QLatin1String(".")); parent->connect(connFactory->proxy(busName, path, chanFactory, contactFactory), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onConnectionBuilt(Tp::PendingOperation*))); // No dequeue here, but only in onConnectionBuilt, so we will queue future changes return false; // Only move on to the next paths when that build finishes } } return true; } void Account::onDispatcherIntrospected(Tp::PendingOperation *op) { if (!mPriv->dispatcherContext->introspected) { Tp::PendingVariant *pv = static_cast(op); Q_ASSERT(pv != NULL); // Only the first Account for a given dispatcher will enter this branch, and will // immediately make further created accounts skip the whole waiting for CD to get // introspected part entirely mPriv->dispatcherContext->introspected = true; if (pv->isValid()) { mPriv->dispatcherContext->supportsHints = qdbus_cast(pv->result()); debug() << "Discovered channel dispatcher support for request hints: " << mPriv->dispatcherContext->supportsHints; } else { if (pv->errorName() == TP_QT_ERROR_NOT_IMPLEMENTED) { debug() << "Channel Dispatcher does not implement support for request hints"; } else { warning() << "(Too old?) Channel Dispatcher failed to tell us whether" << "it supports request hints, assuming it doesn't:" << pv->errorName() << ':' << pv->errorMessage(); } mPriv->dispatcherContext->supportsHints = false; } } debug() << "Calling Properties::GetAll(Account) on " << objectPath(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( mPriv->properties->GetAll( TP_QT_IFACE_ACCOUNT), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotMainProperties(QDBusPendingCallWatcher*))); } void Account::gotMainProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got reply to Properties.GetAll(Account) for" << objectPath(); mPriv->updateProperties(reply.value()); mPriv->readinessHelper->setInterfaces(interfaces()); mPriv->mayFinishCore = true; if (mPriv->connObjPathQueue.isEmpty()) { debug() << "Account basic functionality is ready"; mPriv->coreFinished = true; mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } else { debug() << "Deferring finishing Account::FeatureCore until the connection is built"; } } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); warning().nospace() << "GetAll(Account) failed: " << reply.error().name() << ": " << reply.error().message(); } watcher->deleteLater(); } void Account::gotAvatar(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got reply to GetAvatar(Account)"; mPriv->avatar = qdbus_cast(reply); // It could be in either of actual or missing from the first time in corner cases like the // object going away, so let's be prepared for both (only checking for actualFeatures here // actually used to trigger a rare bug) // // Anyway, the idea is to not do setIntrospectCompleted twice if (!mPriv->readinessHelper->actualFeatures().contains(FeatureAvatar) && !mPriv->readinessHelper->missingFeatures().contains(FeatureAvatar)) { mPriv->readinessHelper->setIntrospectCompleted(FeatureAvatar, true); } emit avatarChanged(mPriv->avatar); notify("avatar"); } else { // check if the feature is already there, and for some reason retrieveAvatar // failed when called the second time if (!mPriv->readinessHelper->actualFeatures().contains(FeatureAvatar) && !mPriv->readinessHelper->missingFeatures().contains(FeatureAvatar)) { mPriv->readinessHelper->setIntrospectCompleted(FeatureAvatar, false, reply.error()); } warning().nospace() << "GetAvatar(Account) failed: " << reply.error().name() << ": " << reply.error().message(); } watcher->deleteLater(); } void Account::onAvatarChanged() { debug() << "Avatar changed, retrieving it"; mPriv->retrieveAvatar(); } void Account::onConnectionManagerReady(PendingOperation *operation) { bool error = operation->isError(); if (!error) { error = !mPriv->cm->hasProtocol(mPriv->protocolName); } if (!error) { mPriv->readinessHelper->setIntrospectCompleted(FeatureProtocolInfo, true); } else { warning() << "Failed to find the protocol in the CM protocols for account" << objectPath(); mPriv->readinessHelper->setIntrospectCompleted(FeatureProtocolInfo, false, operation->errorName(), operation->errorMessage()); } } void Account::onConnectionReady(PendingOperation *op) { mPriv->checkCapabilitiesChanged(false); /* let's not fail if connection can't become ready, the caps will still * work, but return the CM caps instead. Also no need to call * setIntrospectCompleted if the feature was already set to complete once, * since this method will be called whenever the account connection * changes */ if (!isReady(FeatureCapabilities)) { mPriv->readinessHelper->setIntrospectCompleted(FeatureCapabilities, true); } } void Account::onPropertyChanged(const QVariantMap &delta) { mPriv->updateProperties(delta); } void Account::onRemoved() { mPriv->valid = false; mPriv->enabled = false; invalidate(TP_QT_ERROR_OBJECT_REMOVED, QLatin1String("Account removed from AccountManager")); emit removed(); } void Account::onConnectionBuilt(PendingOperation *op) { PendingReady *readyOp = qobject_cast(op); Q_ASSERT(readyOp != NULL); if (op->isError()) { warning() << "Building connection" << mPriv->connObjPathQueue.head() << "failed with" << op->errorName() << "-" << op->errorMessage(); if (!mPriv->connection.isNull()) { mPriv->connection.reset(); emit connectionChanged(mPriv->connection); notify("connection"); notify("connectionObjectPath"); } } else { ConnectionPtr prevConn = mPriv->connection; QString prevConnPath = mPriv->connectionObjectPath(); mPriv->connection = ConnectionPtr::qObjectCast(readyOp->proxy()); Q_ASSERT(mPriv->connection); debug() << "Connection" << mPriv->connectionObjectPath() << "built for" << objectPath(); if (prevConn != mPriv->connection) { notify("connection"); emit connectionChanged(mPriv->connection); } if (prevConnPath != mPriv->connectionObjectPath()) { notify("connectionObjectPath"); } } mPriv->connObjPathQueue.dequeue(); if (mPriv->processConnQueue() && !mPriv->coreFinished && mPriv->mayFinishCore) { debug() << "Account" << objectPath() << "basic functionality is ready (connections built)"; mPriv->coreFinished = true; mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } } /** * \fn void Account::removed() * * Emitted when this account is removed from the account manager it belonged. * * \sa remove(). */ /** * \fn void Account::validityChanged(bool validity) * * Emitted when the value of isValidAccount() changes. * * \param validity The new validity of this account. * \sa isValidAccount() */ /** * \fn void Account::stateChanged(bool state) * * Emitted when the value of isEnabled() changes. * * \param state The new state of this account. * \sa isEnabled() */ /** * \fn void Account::serviceNameChanged(const QString &serviceName) * * Emitted when the value of serviceName() changes. * * \param serviceName The new service name of this account. * \sa serviceName(), setServiceName() */ /** * \fn void Account::profileChanged(const Tp::ProfilePtr &profile) * * Emitted when the value of profile() changes. * * \param profile The new profile of this account. * \sa profile() */ /** * \fn void Account::displayNameChanged(const QString &displayName) * * Emitted when the value of displayName() changes. * * \param displayName The new display name of this account. * \sa displayName(), setDisplayName() */ /** * \fn void Account::iconNameChanged(const QString &iconName) * * Emitted when the value of iconName() changes. * * \param iconName The new icon name of this account. * \sa iconName(), setIconName() */ /** * \fn void Account::nicknameChanged(const QString &nickname) * * Emitted when the value of nickname() changes. * * \param nickname The new nickname of this account. * \sa nickname(), setNickname() */ /** * \fn void Account::normalizedNameChanged(const QString &normalizedName) * * Emitted when the value of normalizedName() changes. * * \param normalizedName The new normalized name of this account. * \sa normalizedName() */ /** * \fn void Account::capabilitiesChanged(const Tp::ConnectionCapabilities &capabilities) * * Emitted when the value of capabilities() changes. * * \param capabilities The new capabilities of this account. * \sa capabilities() */ /** * \fn void Account::connectsAutomaticallyPropertyChanged(bool connectsAutomatically) * * Emitted when the value of connectsAutomatically() changes. * * \param connectsAutomatically The new value of connects automatically property * of this account. * \sa isEnabled() */ /** * \fn void Account::firstOnline() * * Emitted when this account is first put online. * * \sa hasBeenOnline() */ /** * \fn void Account::parametersChanged(const QVariantMap ¶meters) * * Emitted when the value of parameters() changes. * * \param parameters The new parameters of this account. * \sa parameters() */ /** * \fn void Account::changingPresence(bool value) * * Emitted when the value of isChangingPresence() changes. * * \param value Whether this account's connection is changing presence. * \sa isChangingPresence() */ /** * \fn void Account::automaticPresenceChanged(const Tp::Presence &automaticPresence) * * Emitted when the value of automaticPresence() changes. * * \param automaticPresence The new value of automatic presence property of this * account. * \sa automaticPresence(), currentPresenceChanged() */ /** * \fn void Account::currentPresenceChanged(const Tp::Presence ¤tPresence) * * Emitted when the value of currentPresence() changes. * * \param currentPresence The new value of the current presence property of this * account. * \sa currentPresence() */ /** * \fn void Account::requestedPresenceChanged(const Tp::Presence &requestedPresence) * * Emitted when the value of requestedPresence() changes. * * \param requestedPresence The new value of the requested presence property of this * account. * \sa requestedPresence(), currentPresenceChanged() */ /** * \fn void Account::onlinenessChanged(bool online) * * Emitted when the value of isOnline() changes. * * \param online Whether this account is online. * \sa isOnline(), currentPresence() */ /** * \fn void Account::avatarChanged(const Tp::Avatar &avatar) * * Emitted when the value of avatar() changes. * * \param avatar The new avatar of this account. * \sa avatar() */ /** * \fn void Account::connectionStatusChanged(Tp::ConnectionStatus status) * * Emitted when the connection status changes. * * \param status The new status of this account connection. * \sa connectionStatus(), connectionStatusReason(), connectionError(), connectionErrorDetails(), * Connection::ErrorDetails */ /** * \fn void Account::connectionChanged(const Tp::ConnectionPtr &connection) * * Emitted when the value of connection() changes. * * The \a connection will have the features set in the ConnectionFactory used by this account ready * and the same channel and contact factories used by this account. * * \param connection A ConnectionPtr pointing to the new Connection object or a null ConnectionPtr * if there is no connection. * \sa connection() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/call-content-media-description.h0000664000175000017500000000226312470405660023351 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_call_content_media_description_h_HEADER_GUARD_ #define _TelepathyQt_call_content_media_description_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/service-types.h0000664000175000017500000001247712470405660020202 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_service_types_h_HEADER_GUARD_ #define _TelepathyQt_service_types_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class AbstractProtocolInterface; class AbstractCallContentInterface; class AbstractConnectionInterface; class AbstractChannelInterface; class BaseCallContent; class BaseCallMuteInterface; class BaseCallContentDTMFInterface; class BaseConnection; class BaseConnectionRequestsInterface; class BaseConnectionContactsInterface; class BaseConnectionSimplePresenceInterface; class BaseConnectionContactListInterface; class BaseConnectionContactInfoInterface; class BaseConnectionAddressingInterface; class BaseConnectionAliasingInterface; class BaseConnectionAvatarsInterface; class BaseConnectionManager; class BaseProtocol; class BaseProtocolAddressingInterface; class BaseProtocolAvatarsInterface; class BaseProtocolPresenceInterface; class BaseChannel; class BaseChannelTextType; class BaseChannelCallType; class BaseChannelMessagesInterface; class BaseChannelServerAuthenticationType; class BaseChannelSASLAuthenticationInterface; class BaseChannelCaptchaAuthenticationInterface; class BaseChannelSecurableInterface; class BaseChannelChatStateInterface; class BaseChannelGroupInterface; class BaseChannelHoldInterface; class BaseChannelMergeableConferenceInterface; class BaseChannelSplittableInterface; class BaseChannelSMSInterface; class BaseChannelConferenceInterface; class DBusService; #ifndef DOXYGEN_SHOULD_SKIP_THIS typedef SharedPtr AbstractProtocolInterfacePtr; typedef SharedPtr AbstractCallContentInterfacePtr; typedef SharedPtr AbstractConnectionInterfacePtr; typedef SharedPtr AbstractChannelInterfacePtr; typedef SharedPtr BaseCallContentPtr; typedef SharedPtr BaseCallContentDTMFInterfacePtr; typedef SharedPtr BaseCallMuteInterfacePtr; typedef SharedPtr BaseConnectionPtr; typedef SharedPtr BaseConnectionRequestsInterfacePtr; typedef SharedPtr BaseConnectionContactsInterfacePtr; typedef SharedPtr BaseConnectionSimplePresenceInterfacePtr; typedef SharedPtr BaseConnectionContactListInterfacePtr; typedef SharedPtr BaseConnectionContactInfoInterfacePtr; typedef SharedPtr BaseConnectionAddressingInterfacePtr; typedef SharedPtr BaseConnectionAliasingInterfacePtr; typedef SharedPtr BaseConnectionAvatarsInterfacePtr; typedef SharedPtr BaseConnectionManagerPtr; typedef SharedPtr BaseProtocolPtr; typedef SharedPtr BaseProtocolAddressingInterfacePtr; typedef SharedPtr BaseProtocolAvatarsInterfacePtr; typedef SharedPtr BaseProtocolPresenceInterfacePtr; typedef SharedPtr BaseChannelPtr; typedef SharedPtr BaseChannelCallTypePtr; typedef SharedPtr BaseChannelTextTypePtr; typedef SharedPtr BaseChannelMessagesInterfacePtr; typedef SharedPtr BaseChannelServerAuthenticationTypePtr; typedef SharedPtr BaseChannelSASLAuthenticationInterfacePtr; typedef SharedPtr BaseChannelCaptchaAuthenticationInterfacePtr; typedef SharedPtr BaseChannelSecurableInterfacePtr; typedef SharedPtr BaseChannelChatStateInterfacePtr; typedef SharedPtr BaseChannelGroupInterfacePtr; typedef SharedPtr BaseChannelHoldInterfacePtr; typedef SharedPtr BaseChannelMergeableConferenceInterfacePtr; typedef SharedPtr BaseChannelSplittableInterfacePtr; typedef SharedPtr BaseChannelSMSInterfacePtr; typedef SharedPtr BaseChannelConferenceInterfacePtr; typedef SharedPtr DBusServicePtr; #endif /* DOXYGEN_SHOULD_SKIP_THIS */ } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/stream-tube-server.cpp0000664000175000017500000012460612470405660021465 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/stream-tube-server-internal.h" #include "TelepathyQt/_gen/stream-tube-server.moc.hpp" #include "TelepathyQt/_gen/stream-tube-server-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/simple-stream-tube-handler.h" #include #include #include #include #include #include #include namespace Tp { /** * \class StreamTubeServer::ParametersGenerator * \ingroup serverclient * \headerfile TelepathyQt/stream-tube-server.h * * \brief The StreamTubeServer::ParametersGenerator abstract interface allows sending a different * set of parameters with each tube offer. * * %Tube parameters are arbitrary data sent with the tube offer, which can be retrieved in the * receiving end with IncomingStreamTubeChannel::parameters(). They can be used to transfer * e.g. session identification information, authentication credentials or alike, for bootstrapping * the protocol used for communicating over the tube. * * For usecases where the parameters don't need to change between each tube, just passing a fixed * set of parameters to a suitable StreamTubeServer::exportTcpSocket() overload is usually more * convenient than implementing a ParametersGenerator. Note that StreamTubeServer::exportTcpSocket() * can be called multiple times to change the parameters for future tubes when e.g. configuration * settings have been changed, so a ParametersGenerator only needs to be implemented if each and * every tube must have a different set of parameters. */ /** * \fn QVariantMap StreamTubeServer::ParametersGenerator::nextParameters(const AccountPtr &, const * OutgoingStreamTubeChannelPtr &, const ChannelRequestHints &) * * Return the parameters to send when offering the given \a tube. * * \param account The account from which the tube originates. * \param tube The tube channel which is going to be offered by the StreamTubeServer. * \param hints The hints associated with the request that led to the creation of this tube, if any. * * \return Parameters to send with the offer, or an empty QVariantMap if none are needed for this * tube. */ /** * \fn StreamTubeServer::ParametersGenerator::~ParametersGenerator * * Class destructor. Protected, because StreamTubeServer never deletes a ParametersGenerator passed * to it. */ class TP_QT_NO_EXPORT FixedParametersGenerator : public StreamTubeServer::ParametersGenerator { public: FixedParametersGenerator(const QVariantMap ¶ms) : mParams(params) {} QVariantMap nextParameters(const AccountPtr &, const OutgoingStreamTubeChannelPtr &, const ChannelRequestHints &) { return mParams; } private: QVariantMap mParams; }; struct TP_QT_NO_EXPORT StreamTubeServer::RemoteContact::Private : public QSharedData { // empty placeholder for now }; /** * \class StreamTubeServer::RemoteContact * \ingroup serverclient * \headerfile TelepathyQt/stream-tube-server.h * * \brief The StreamTubeServer::RemoteContact class represents a contact from which a socket * connection to our exported socket originates. */ /** * Constructs a new invalid RemoteContact instance. */ StreamTubeServer::RemoteContact::RemoteContact() { // invalid instance } /** * Constructs a new RemoteContact for the given \a contact object from the given \a account. * * \param account A pointer to the account which this contact can be reached through. * \param contact A pointer to the contact object. */ StreamTubeServer::RemoteContact::RemoteContact( const AccountPtr &account, const ContactPtr &contact) : QPair(account, contact), mPriv(new Private) { } /** * Copy constructor. */ StreamTubeServer::RemoteContact::RemoteContact( const RemoteContact &other) : QPair(other.account(), other.contact()), mPriv(other.mPriv) { } /** * Class destructor. */ StreamTubeServer::RemoteContact::~RemoteContact() { // mPriv deleted automatically } /** * Assignment operator. */ StreamTubeServer::RemoteContact &StreamTubeServer::RemoteContact::operator=( const RemoteContact &other) { if (&other == this) { return *this; } first = other.account(); second = other.contact(); mPriv = other.mPriv; return *this; } /** * \fn bool StreamTubeServer::RemoteContact::isValid() const * * Return whether or not the contact is valid or is just the null object created using the default * constructor. * * \return \c true if valid, \c false otherwise. */ /** * \fn AccountPtr StreamTubeServer::RemoteContact::account() const * * Return the account through which the contact can be reached. * * \return A pointer to the account object. */ /** * \fn ContactPtr StreamTubeServer::RemoteContact::contact() const * * Return the actual contact object. * * \return A pointer to the object. */ struct TP_QT_NO_EXPORT StreamTubeServer::Tube::Private : public QSharedData { // empty placeholder for now }; /** * \class StreamTubeServer::Tube * \ingroup serverclient * \headerfile TelepathyQt/stream-tube-server.h * * \brief The StreamTubeServer::Tube class represents a tube being handled by the server. */ /** * Constructs a new invalid Tube instance. */ StreamTubeServer::Tube::Tube() { // invalid instance } /** * Constructs a Tube instance for the given tube \a channel originating from the given \a account. * * \param account A pointer to the account object. * \param channel A pointer to the tube channel object. */ StreamTubeServer::Tube::Tube( const AccountPtr &account, const OutgoingStreamTubeChannelPtr &channel) : QPair(account, channel), mPriv(new Private) { } /** * Copy constructor. */ StreamTubeServer::Tube::Tube( const Tube &other) : QPair(other.account(), other.channel()), mPriv(other.mPriv) { } /** * Class destructor. */ StreamTubeServer::Tube::~Tube() { // mPriv deleted automatically } /** * Assignment operator. */ StreamTubeServer::Tube &StreamTubeServer::Tube::operator=( const Tube &other) { if (&other == this) { return *this; } first = other.account(); second = other.channel(); mPriv = other.mPriv; return *this; } /** * \fn bool StreamTubeServer::Tube::isValid() const * * Return whether or not the tube is valid or is just the null object created using the default * constructor. * * \return \c true if valid, \c false otherwise. */ /** * \fn AccountPtr StreamTubeServer::Tube::account() const * * Return the account from which the tube originates. * * \return A pointer to the account object. */ /** * \fn OutgoingStreamTubeChannelPtr StreamTubeServer::Tube::channel() const * * Return the actual tube channel. * * \return A pointer to the channel. */ struct StreamTubeServer::Private { Private(const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices, const QString &maybeClientName, bool monitorConnections) : registrar(registrar), handler(SimpleStreamTubeHandler::create(p2pServices, roomServices, true, monitorConnections)), clientName(maybeClientName), isRegistered(false), exportedPort(0), generator(0) { if (clientName.isEmpty()) { clientName = QString::fromLatin1("TpQtSTubeServer_%1_%2") .arg(registrar->dbusConnection().baseService() .replace(QLatin1Char(':'), QLatin1Char('_')) .replace(QLatin1Char('.'), QLatin1Char('_'))) .arg((quintptr) this, 0, 16); } } void ensureRegistered() { if (isRegistered) { return; } debug() << "Register StreamTubeServer with name " << clientName; if (registrar->registerClient(handler, clientName)) { isRegistered = true; } else { warning() << "StreamTubeServer" << clientName << "registration failed"; } } ClientRegistrarPtr registrar; SharedPtr handler; QString clientName; bool isRegistered; QHostAddress exportedAddr; quint16 exportedPort; ParametersGenerator *generator; QScopedPointer fixedGenerator; QHash tubes; }; StreamTubeServer::TubeWrapper::TubeWrapper(const AccountPtr &acc, const OutgoingStreamTubeChannelPtr &tube, const QHostAddress &exportedAddr, quint16 exportedPort, const QVariantMap ¶ms, StreamTubeServer *parent) : QObject(parent), mAcc(acc), mTube(tube) { connect(tube->offerTcpSocket(exportedAddr, exportedPort, params), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onTubeOffered(Tp::PendingOperation*))); connect(tube.data(), SIGNAL(newConnection(uint)), SLOT(onNewConnection(uint))); connect(tube.data(), SIGNAL(connectionClosed(uint,QString,QString)), SLOT(onConnectionClosed(uint,QString,QString))); } void StreamTubeServer::TubeWrapper::onTubeOffered(Tp::PendingOperation *op) { emit offerFinished(this, op); } void StreamTubeServer::TubeWrapper::onNewConnection(uint conn) { emit newConnection(this, conn); } void StreamTubeServer::TubeWrapper::onConnectionClosed(uint conn, const QString &error, const QString &message) { emit connectionClosed(this, conn, error, message); } /** * \class StreamTubeServer * \ingroup serverclient * \headerfile TelepathyQt/stream-tube-server.h * * \brief The StreamTubeServer class is a Handler implementation for outgoing %Stream %Tube channels, * allowing an application to easily export a TCP network server over Telepathy Tubes without * worrying about the channel dispatching details. * * Telepathy Tubes is a technology for connecting arbitrary applications together through the IM * network (and sometimes with direct peer-to-peer connections), such that issues like firewall/NAT * traversal are automatically handled. Stream Tubes in particular offer properties similar to * SOCK_STREAM sockets. The StreamTubeServer class exports such a bytestream socket \b server over * the tubes it \em handles as a Telepathy Handler %Client; the StreamTubeClient class is the * counterpart, enabling TCP/UNIX socket clients to connect to services from such exported servers * offered to them via tubes. * * Both peer-to-peer (\c TargetHandleType == \ref HandleTypeContact) and group (\c TargetHandleType * == \ref HandleTypeRoom) channels are supported, and it's possible to specify the tube services to * handle for each separately. It is also possible to not advertise handling capability for ANY tube * service; instead just using the StreamTubeServer to handle tubes on an one-off basis by passing * its corresponding %Client service name as the \a preferredHandler when requesting tubes via the * Account::createStreamTube() methods (or equivalent). * * %Connection monitoring allows associating incoming connections on the exported server socket with * the corresponding remote contacts. This allows an application to show the details of and/or * initiate further communication with the remote contacts, without considering the actual tube * channels the connections are being made through at all (in particular, their * Channel::targetContact() accessor for peer-to-peer and the * OutgoingStreamTubeChannel::connectionsForSourceAddresses() accessor for group tubes). * * Enabling connection monitoring adds a small overhead and latency to handling each incoming tube * and signaling each new incoming connection over them, though, so use it only when needed. * Additionally, some protocol backends or environments they're running in might not support the * ::SocketAccessControlPort mechanism, in which case the source address won't be reported for * connections through them. Even in this case, the remote contacts can be associated by accepting * one incoming socket connection at a time, and waiting for the corresponding contact to be * signaled (although its source address will be invalid, it's the only possibility given its the * only accepted connection). However, it's not necessary to do this e.g. with the Gabble XMPP * backend, because it fully supports the required mechanism. * * A service activated Handler can be implemented using StreamTubeServer by passing a predefined \a * clientName manually to the chosen create() method, and installing Telepathy \c .client and D-Bus * \c .service files declaring the implemented tube services as channel classes and a path to the * executable. If this is not needed, the \a clientName can be omitted, in which case a random * unique client name is generated and used instead. * * StreamTubeServer shares Account, Connection and Channel proxies and Contact objects with the * rest of the application as long as a reference to the AccountManager, ClientRegistrar, or the * factories used elsewhere is passed to the create() method. A stand-alone tube service Handler can * get away without passing these however, or just passing select factories to make the desired * features prepared and subclasses employed for these objects for their own convenience. * * Whichever method is used, the ChannelFactory (perhaps indirectly) given must construct * OutgoingStreamTubeChannel instances or subclasses thereof for all channel classes corresponding * to the tube services to handle. This is the default; overriding it without obeying these * constraints using ChannelFactory::setSubclassForOutgoingStreamTubes() or the related methods * for room tubes prevents StreamTubeServer from operating correctly. * * \todo Coin up a small Python script or alike to easily generate the .client and .service files. * (fd.o #41614) * \todo Support exporting Unix sockets as well. (fd.o #41615) */ /** * Create a new StreamTubeServer, which will register itself on the session bus using an internal * ClientRegistrar and use the given factories. * * \param p2pServices Names of the tube services to handle on peer-to-peer tube channels. * \param roomServices Names of the tube services to handle on room/group tube channels. * \param clientName The client name (without the \c org.freedesktop.Telepathy.Client. prefix). * \param monitorConnections Whether to enable connection monitoring or not. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. */ StreamTubeServerPtr StreamTubeServer::create( const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return create( QDBusConnection::sessionBus(), accountFactory, connectionFactory, channelFactory, contactFactory, p2pServices, roomServices, clientName, monitorConnections); } /** * Create a new StreamTubeServer, which will register itself on the given \a bus using an internal * ClientRegistrar and use the given factories. * * The factories must all be created for the given \a bus. * * \param bus Connection to the bus to register on. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \param p2pServices Names of the tube services to handle on peer-to-peer tube channels. * \param roomServices Names of the tube services to handle on room/group tube channels. * \param clientName The client name (without the \c org.freedesktop.Telepathy.Client. prefix). * \param monitorConnections Whether to enable connection monitoring or not. */ StreamTubeServerPtr StreamTubeServer::create( const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections) { return create( ClientRegistrar::create( bus, accountFactory, connectionFactory, channelFactory, contactFactory), p2pServices, roomServices, clientName, monitorConnections); } /** * Create a new StreamTubeServer, which will register itself on the bus of and share objects with * the given \a accountManager, creating an internal ClientRegistrar. * * \param accountManager A pointer to the account manager to link up with. * \param p2pServices Names of the tube services to handle on peer-to-peer tube channels. * \param roomServices Names of the tube services to handle on room/group tube channels. * \param clientName The client name (without the \c org.freedesktop.Telepathy.Client. prefix). * \param monitorConnections Whether to enable connection monitoring or not. */ StreamTubeServerPtr StreamTubeServer::create( const AccountManagerPtr &accountManager, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections) { return create( accountManager->dbusConnection(), accountManager->accountFactory(), accountManager->connectionFactory(), accountManager->channelFactory(), accountManager->contactFactory(), p2pServices, roomServices, clientName, monitorConnections); } /** * Create a new StreamTubeServer, which will register itself on the bus of and using the given * client \a registrar, and share objects with it. * * \param registrar The client registrar to use. * \param p2pServices Names of the tube services to handle on peer-to-peer tube channels. * \param roomServices Names of the tube services to handle on room/group tube channels. * \param clientName The client name (without the \c org.freedesktop.Telepathy.Client. prefix). * \param monitorConnections Whether to enable connection monitoring or not. */ StreamTubeServerPtr StreamTubeServer::create( const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections) { return StreamTubeServerPtr( new StreamTubeServer(registrar, p2pServices, roomServices, clientName, monitorConnections)); } StreamTubeServer::StreamTubeServer( const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections) : mPriv(new Private(registrar, p2pServices, roomServices, clientName, monitorConnections)) { connect(mPriv->handler.data(), SIGNAL(invokedForTube( Tp::AccountPtr, Tp::StreamTubeChannelPtr, QDateTime, Tp::ChannelRequestHints)), SLOT(onInvokedForTube( Tp::AccountPtr, Tp::StreamTubeChannelPtr, QDateTime, Tp::ChannelRequestHints))); } /** * Class destructor. */ StreamTubeServer::~StreamTubeServer() { if (isRegistered()) { mPriv->registrar->unregisterClient(mPriv->handler); } delete mPriv; } /** * Return the client registrar used by the server to register itself as a Handler client. * * This is the registrar originally passed to * create(const ClientRegistrarPtr &, const QStringList &, const QStringList &, const QString &, bool) * if that was used, and an internally constructed one otherwise. In any case, it can be used to * e.g. register further clients like any other ClientRegistrar. * * \return A pointer to the registrar. */ ClientRegistrarPtr StreamTubeServer::registrar() const { return mPriv->registrar; } /** * Return the Telepathy %Client name of the server. * * \return The name, without the \c org.freedesktop.Telepathy.Client. prefix of the full D-Bus service name. */ QString StreamTubeServer::clientName() const { return mPriv->clientName; } /** * Return whether the server has been successfully registered or not. * * Registration is attempted, at the latest, when a socket is first exported using exportTcpSocket(). * It can fail e.g. because the connection to the bus has failed, or a predefined \a clientName has * been passed to create(), and a %Client with the same name is already registered. Typically, failure * registering would be a fatal error for a stand-alone tube handler, but only a warning event for * an application serving other purposes. In any case, a high-quality user of the API will check the * return value of this accessor after exporting their socket. * * \return \c true if the server has been successfully registered, \c false if not. */ bool StreamTubeServer::isRegistered() const { return mPriv->isRegistered; } /** * Return whether connection monitoring is enabled on this server. * * For technical reasons, connection monitoring can't be enabled when the server is already running, * so there is no corresponding setter method. It has to be enabled by passing \c true as the \a * monitorConnections parameter to the create() method. * * If connection monitoring isn't enabled, newTcpConnection() and tcpConnectionClosed() won't be * emitted and tcpConnections() won't be populated. * * \return \c true if monitoring is enabled, \c false if not. */ bool StreamTubeServer::monitorsConnections() const { return mPriv->handler->monitorsConnections(); } /** * Return the host address and port of the currently exported TCP socket, if any. * * QHostAddress::Null is reported as the address and 0 as the port if no TCP socket has yet been * successfully exported. * * \return The host address and port values in a pair structure. */ QPair StreamTubeServer::exportedTcpSocketAddress() const { return qMakePair(mPriv->exportedAddr, mPriv->exportedPort); } /** * Return the fixed parameters, if any, which are sent along when offering the exported socket on * all handled tubes. * * To prevent accidentally leaving the current parameters to be sent when offering a different * socket, or vice versa, the parameters can only be set together with the socket using * exportTcpSocket(). Parameters often contain sensitive information such as session identifiers or * authentication credentials, which could then be used to maliciously access the service listening * on the other socket. * * If a custom dynamic ParametersGenerator was passed to exportTcpSocket() instead of a set of fixed * parameters, an empty set of parameters is returned. * * \return The parameters in a string-variant map. */ QVariantMap StreamTubeServer::exportedParameters() const { if (!mPriv->generator) { return QVariantMap(); } FixedParametersGenerator *generator = dynamic_cast(mPriv->generator); if (generator) { return generator->nextParameters(AccountPtr(), OutgoingStreamTubeChannelPtr(), ChannelRequestHints()); } else { return QVariantMap(); } } /** * Set the server to offer the socket listening at the given (\a address, \a port) combination as the * local endpoint of tubes handled in the future. * * A fixed set of protocol bootstrapping \a parameters can optionally be set to be sent along with all * tube offers until the next call to exportTcpSocket(). See the ParametersGenerator documentation * for an in-depth description of the parameter transfer mechanism, and a more flexible way to vary * the parameters between each handled tube. * * The handler is registered on the bus at the latest when this method or another exportTcpSocket() * overload is called for the first time, so one should check the return value of isRegistered() at * that point to verify that was successful. * * \param address The listen address of the socket. * \param port The port of the socket. * \param parameters The bootstrapping parameters in a string-value map. */ void StreamTubeServer::exportTcpSocket( const QHostAddress &address, quint16 port, const QVariantMap ¶meters) { if (address.isNull() || port == 0) { warning() << "Attempted to export null TCP socket address or zero port, ignoring"; return; } mPriv->exportedAddr = address; mPriv->exportedPort = port; mPriv->generator = 0; if (!parameters.isEmpty()) { mPriv->fixedGenerator.reset(new FixedParametersGenerator(parameters)); mPriv->generator = mPriv->fixedGenerator.data(); } mPriv->ensureRegistered(); } /** * Set the StreamTubeServer to offer the already listening TCP \a server as the local endpoint of tubes * handled in the future. * * This is just a convenience wrapper around * exportTcpSocket(const QHostAddress &, quint16, const QVariantMap &) to be used when the TCP * server code is implemented using the QtNetwork facilities. * * A fixed set of protocol bootstrapping \a parameters can optionally be set to be sent along with all * tube offers until the next call to exportTcpSocket(). See the ParametersGenerator documentation * for an in-depth description of the parameter transfer mechanism, and a more flexible way to vary * the parameters between each handled tube. * * \param server A pointer to the TCP server. * \param parameters The bootstrapping parameters in a string-value map. */ void StreamTubeServer::exportTcpSocket( const QTcpServer *server, const QVariantMap ¶meters) { if (!server->isListening()) { warning() << "Attempted to export non-listening QTcpServer, ignoring"; return; } if (server->serverAddress() == QHostAddress::Any #if QT_VERSION >= 0x050000 || server->serverAddress() == QHostAddress::AnyIPv4 #endif ) { return exportTcpSocket(QHostAddress::LocalHost, server->serverPort(), parameters); } else if (server->serverAddress() == QHostAddress::AnyIPv6) { return exportTcpSocket(QHostAddress::LocalHostIPv6, server->serverPort(), parameters); } else { return exportTcpSocket(server->serverAddress(), server->serverPort(), parameters); } } /** * Set the server to offer the socket listening at the given \a address - \a port combination as the * local endpoint of tubes handled in the future, sending the parameters from the given \a generator * along with the offers. * * The handler is registered on the bus at the latest when this method or another exportTcpSocket() * overload is called for the first time, so one should check the return value of isRegistered() at * that point to verify that was successful. * * \param address The listen address of the socket. * \param port The port of the socket. * \param generator A pointer to the bootstrapping parameters generator. */ void StreamTubeServer::exportTcpSocket( const QHostAddress &address, quint16 port, ParametersGenerator *generator) { if (address.isNull() || port == 0) { warning() << "Attempted to export null TCP socket address or zero port, ignoring"; return; } mPriv->exportedAddr = address; mPriv->exportedPort = port; mPriv->generator = generator; mPriv->ensureRegistered(); } /** * Set the server to offer the already listening TCP \a server as the local endpoint of tubes * handled in the future, sending the parameters from the given \a generator along with the offers. * * This is just a convenience wrapper around * exportTcpSocket(const QHostAddress &, quint16, ParametersGenerator *) to be used when the TCP * server code is implemented using the QtNetwork facilities. * * \param server A pointer to the TCP server. * \param generator A pointer to the bootstrapping parameters generator. */ void StreamTubeServer::exportTcpSocket( const QTcpServer *server, ParametersGenerator *generator) { if (!server->isListening()) { warning() << "Attempted to export non-listening QTcpServer, ignoring"; return; } if (server->serverAddress() == QHostAddress::Any #if QT_VERSION >= 0x050000 || server->serverAddress() == QHostAddress::AnyIPv4 #endif ) { return exportTcpSocket(QHostAddress::LocalHost, server->serverPort(), generator); } else if (server->serverAddress() == QHostAddress::AnyIPv6) { return exportTcpSocket(QHostAddress::LocalHostIPv6, server->serverPort(), generator); } else { return exportTcpSocket(server->serverAddress(), server->serverPort(), generator); } } /** * Return the tubes currently handled by the server. * * \return A list of Tube structures containing pointers to the account and tube channel for each * tube. */ QList StreamTubeServer::tubes() const { QList tubes; foreach (TubeWrapper *wrapper, mPriv->tubes.values()) { tubes.push_back(Tube(wrapper->mAcc, wrapper->mTube)); } return tubes; } /** * Return the ongoing TCP connections over tubes handled by this server. * * The returned mapping has the connection source addresses as keys and the contacts along with the * accounts which can be used to reach them as values. Connections through protocol backends which * don't support SocketAccessControlPort will be included as the potentially many values for the * null source address key, the pair (\c QHostAddress::Null, 0). * * This is effectively a state recovery accessor corresponding to the change notification signals * newTcpConnection() and tcpConnectionClosed(). * * The mapping is only populated if connection monitoring was requested when creating the server (so * monitorsConnections() returns \c true). * * \return The connections in a mapping with pairs of their source host addresses and ports as keys * and structures containing pointers to the account and remote contacts they're from as values. */ QHash, StreamTubeServer::RemoteContact> StreamTubeServer::tcpConnections() const { QHash, RemoteContact> conns; if (!monitorsConnections()) { warning() << "StreamTubeServer::tcpConnections() used, but connection monitoring is disabled"; return conns; } foreach (const Tube &tube, tubes()) { // Ignore invalid and non-Open tubes to prevent a few useless warnings in corner cases where // a tube is still being opened, or has been invalidated but we haven't processed that event // yet. if (!tube.channel()->isValid() || tube.channel()->state() != TubeChannelStateOpen) { continue; } if (tube.channel()->addressType() != SocketAddressTypeIPv4 && tube.channel()->addressType() != SocketAddressTypeIPv6) { continue; } QHash, uint> srcAddrConns = tube.channel()->connectionsForSourceAddresses(); QHash connContacts = tube.channel()->contactsForConnections(); QPair srcAddr; foreach (srcAddr, srcAddrConns.keys()) { ContactPtr contact = connContacts.take(srcAddrConns.value(srcAddr)); conns.insert(srcAddr, RemoteContact(tube.account(), contact)); } // The remaining values in our copy of connContacts are those which didn't have a // corresponding source address, probably because the service doesn't properly implement // Port AC foreach (const ContactPtr &contact, connContacts.values()) { // Insert them with an invalid source address as the key conns.insertMulti(qMakePair(QHostAddress(QHostAddress::Null), quint16(0)), RemoteContact(tube.account(), contact)); } } return conns; } void StreamTubeServer::onInvokedForTube( const AccountPtr &acc, const StreamTubeChannelPtr &tube, const QDateTime &time, const ChannelRequestHints &hints) { Q_ASSERT(isRegistered()); // our SSTH shouldn't be receiving any channels unless it's registered Q_ASSERT(tube->isRequested()); Q_ASSERT(tube->isValid()); // SSTH won't emit invalid tubes OutgoingStreamTubeChannelPtr outgoing = OutgoingStreamTubeChannelPtr::qObjectCast(tube); if (outgoing) { emit tubeRequested(acc, outgoing, time, hints); } else { warning() << "The ChannelFactory used by StreamTubeServer must construct" << "OutgoingStreamTubeChannel subclasses for Requested=true StreamTubes"; tube->requestClose(); return; } if (!mPriv->tubes.contains(tube)) { debug().nospace() << "Offering socket " << mPriv->exportedAddr << ":" << mPriv->exportedPort << " on tube " << tube->objectPath(); QVariantMap params; if (mPriv->generator) { params = mPriv->generator->nextParameters(acc, outgoing, hints); } Q_ASSERT(!mPriv->exportedAddr.isNull() && mPriv->exportedPort != 0); TubeWrapper *wrapper = new TubeWrapper(acc, outgoing, mPriv->exportedAddr, mPriv->exportedPort, params, this); connect(wrapper, SIGNAL(offerFinished(TubeWrapper*,Tp::PendingOperation*)), SLOT(onOfferFinished(TubeWrapper*,Tp::PendingOperation*))); connect(tube.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onTubeInvalidated(Tp::DBusProxy*,QString,QString))); if (monitorsConnections()) { connect(wrapper, SIGNAL(newConnection(TubeWrapper*,uint)), SLOT(onNewConnection(TubeWrapper*,uint))); connect(wrapper, SIGNAL(connectionClosed(TubeWrapper*,uint,QString,QString)), SLOT(onConnectionClosed(TubeWrapper*,uint,QString,QString))); } mPriv->tubes.insert(outgoing, wrapper); } } void StreamTubeServer::onOfferFinished( TubeWrapper *wrapper, Tp::PendingOperation *op) { OutgoingStreamTubeChannelPtr tube = wrapper->mTube; if (op->isError()) { warning() << "Offer() failed, closing tube" << tube->objectPath() << '-' << op->errorName() << ':' << op->errorMessage(); if (wrapper->mTube->isValid()) { wrapper->mTube->requestClose(); } wrapper->mTube->disconnect(this); emit tubeClosed(wrapper->mAcc, wrapper->mTube, op->errorName(), op->errorMessage()); mPriv->tubes.remove(wrapper->mTube); wrapper->deleteLater(); } else { debug() << "Tube" << tube->objectPath() << "offered successfully"; } } void StreamTubeServer::onTubeInvalidated( Tp::DBusProxy *proxy, const QString &error, const QString &message) { OutgoingStreamTubeChannelPtr tube(qobject_cast(proxy)); Q_ASSERT(!tube.isNull()); TubeWrapper *wrapper = mPriv->tubes.value(tube); if (!wrapper) { // Offer finish with error already removed it return; } debug() << "Tube" << tube->objectPath() << "invalidated with" << error << ':' << message; emit tubeClosed(wrapper->mAcc, wrapper->mTube, error, message); mPriv->tubes.remove(tube); delete wrapper; } void StreamTubeServer::onNewConnection( TubeWrapper *wrapper, uint conn) { Q_ASSERT(monitorsConnections()); if (wrapper->mTube->addressType() == SocketAddressTypeIPv4 || wrapper->mTube->addressType() == SocketAddressTypeIPv6) { QHash, uint> srcAddrConns = wrapper->mTube->connectionsForSourceAddresses(); QHash connContacts = wrapper->mTube->contactsForConnections(); QPair srcAddr = srcAddrConns.key(conn); emit newTcpConnection(srcAddr.first, srcAddr.second, wrapper->mAcc, connContacts.value(conn), wrapper->mTube); } else { // No UNIX socket should ever have been offered yet Q_ASSERT(false); } } void StreamTubeServer::onConnectionClosed( TubeWrapper *wrapper, uint conn, const QString &error, const QString &message) { Q_ASSERT(monitorsConnections()); if (wrapper->mTube->addressType() == SocketAddressTypeIPv4 || wrapper->mTube->addressType() == SocketAddressTypeIPv6) { QHash, uint> srcAddrConns = wrapper->mTube->connectionsForSourceAddresses(); QHash connContacts = wrapper->mTube->contactsForConnections(); QPair srcAddr = srcAddrConns.key(conn); emit tcpConnectionClosed(srcAddr.first, srcAddr.second, wrapper->mAcc, connContacts.value(conn), error, message, wrapper->mTube); } else { // No UNIX socket should ever have been offered yet Q_ASSERT(false); } } /** * \fn void StreamTubeServer::tubeRequested(const AccountPtr &account, const * OutgoingStreamTubeChannelPtr &tube, const QDateTime &userActionTime, const ChannelRequestHints * &hints) * * Emitted when a tube has been requested for one of our services, and we've began handling it. * * This is emitted before invoking the ParametersGenerator, if any, for the tube. * * \param account A pointer to the account from which the tube was requested from. * \param tube A pointer to the actual tube channel. * \param userActionTime The time the request occurred at, if it was an user action. Should be used * for focus stealing prevention. * \param hints The hints passed to the request, if any. */ /** * \fn void StreamTubeServer::tubeClosed(const AccountPtr &account, const * OutgoingStreamTubeChannelPtr &tube, const QString &error, const QString &message) * * Emitted when a tube we've been handling (previously announced with tubeRequested()) has * encountered an error or has otherwise been closed from further communication. * * \param account A pointer to the account from which the tube was requested from. * \param tube A pointer to the actual tube channel. * \param error The D-Bus error name corresponding to the reason for the closure. * \param message A freeform debug message associated with the error. */ /** * \fn void StreamTubeServer::newTcpConnection(const QHostAddress &sourceAddress, quint16 * sourcePort, const AccountPtr &account, const ContactPtr &contact, const * OutgoingStreamTubeChannelPtr &tube) * * Emitted when we have picked up a new TCP connection to the (current or previous) exported server * socket. This can be used to associate connections the protocol backend relays to the exported * socket with the remote contact who originally initiated them in the other end of the tube. * * This is only emitted if connection monitoring was enabled when creating the StreamTubeServer. * Additionally, if the protocol backend the connection is from doesn't support the * ::SocketAccessControlPort mechanism, the source address and port will always be invalid. * * \param sourceAddress The source address of the connection, or QHostAddress::Null if it can't be * resolved. * \param sourcePort The source port of the connection, or 0 if it can't be resolved. * \param account A pointer to the account through which the remote contact can be reached. * \param contact A pointer to the remote contact object. * \param tube A pointer to the tube channel through which the connection has been made. */ /** * \fn void StreamTubeServer::tcpConnectionClosed(const QHostAddress &sourceAddress, quint16 * sourcePort, const AccountPtr &account, const ContactPtr &contact, conts QString &error, const * QString &message, const OutgoingStreamTubeChannelPtr &tube) * * Emitted when a TCP connection (previously announced with newTcpConnection()) through one of our * handled tubes has been closed due to an error or by a graceful disconnect (in which case the * error is ::TP_QT_ERROR_DISCONNECTED). * * This is only emitted if connection monitoring was enabled when creating the StreamTubeServer. * Additionally, if the protocol backend the connection is from doesn't support the * ::SocketAccessControlPort mechanism, the source address and port will always be invalid. * * \param sourceAddress The source address of the connection, or QHostAddress::Null if it couldn't * be resolved. * \param sourcePort The source port of the connection, or 0 if it couldn't be resolved. * \param account A pointer to the account through which the remote contact can be reached. * \param contact A pointer to the remote contact object. * \param error The D-Bus error name corresponding to the reason for the closure. * \param message A freeform debug message associated with the error. * \param tube A pointer to the tube channel through which the connection has been made. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/CaptchaAuthentication0000664000175000017500000000041612470405660021403 0ustar jrjr#ifndef _TelepathyQt_CaptchaAuthentication_HEADER_GUARD_ #define _TelepathyQt_CaptchaAuthentication_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/dbus-service.cpp0000664000175000017500000002320612470405660020316 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/dbus-service.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT DBusService::Private { Private(DBusService *parent, const QDBusConnection &dbusConnection) : parent(parent), dbusObject(new DBusObject(dbusConnection, parent)), registered(false) { } DBusService *parent; QString busName; DBusObject *dbusObject; bool registered; }; /** * \class DBusService * \ingroup servicesideimpl * \headerfile TelepathyQt/dbus-service.h * * \brief Base class for D-Bus services. * * This class serves as a base for all the classes that are used to implement * D-Bus services. */ /** * Construct a DBusService that uses the given \a dbusConnection. * * \param dbusConnection The D-Bus connection that will be used by this service. */ DBusService::DBusService(const QDBusConnection &dbusConnection) : mPriv(new Private(this, dbusConnection)) { } /** * Class destructor. */ DBusService::~DBusService() { delete mPriv; } /** * Return the D-Bus connection associated with this service. * * \return the D-Bus connection associated with this service. */ QDBusConnection DBusService::dbusConnection() const { return mPriv->dbusObject->dbusConnection(); } /** * Return the D-Bus service name of this service. * * This is only valid after this service has been registered * on the bus using registerObject(). * * \return the D-Bus service name of this service. */ QString DBusService::busName() const { return mPriv->busName; } /** * Return the D-Bus object path of this service. * * This is only valid after this service has been registered * on the bus using registerObject(). * * \return the D-Bus object path of this service. */ QString DBusService::objectPath() const { return mPriv->dbusObject->objectPath(); } /** * Return the DBusObject that is used for registering this service on the bus. * * The DBusObject is the object on which all the interface adaptors * for this service are plugged. * * \return a pointer to the DBusObject that is used for registering * this service on the bus. */ DBusObject *DBusService::dbusObject() const { return mPriv->dbusObject; } /** * Return whether this D-Bus service has been registered on the bus or not. * * \return \c true if the service has been registered, or \c false otherwise. */ bool DBusService::isRegistered() const { return mPriv->registered; } /** * Register this service object on the bus with the given \a busName and \a objectPath. * * \a error needs to be a valid pointer to a DBusError instance, where any * possible D-Bus error will be stored. * * A service may only be registered once in its lifetime. * Use isRegistered() to find out if it has already been registered or not. * * You normally don't need to use this method directly. * Subclasses should provide a simplified version of it. * * \param busName The D-Bus service name of this object. * \param objectPath The D-Bus object path of this object. * \param error A pointer to a valid DBusError instance, where any * possible D-Bus error will be stored. * \return \c true on success or \c false otherwise. */ bool DBusService::registerObject(const QString &busName, const QString &objectPath, DBusError *error) { if (mPriv->registered) { return true; } if (!mPriv->dbusObject->dbusConnection().registerService(busName)) { error->set(TP_QT_ERROR_INVALID_ARGUMENT, QString(QLatin1String("Name %1 already in use by another process")) .arg(busName)); warning() << "Unable to register service" << busName << "- name already registered by another process"; return false; } if (!mPriv->dbusObject->dbusConnection().registerObject(objectPath, mPriv->dbusObject)) { error->set(TP_QT_ERROR_INVALID_ARGUMENT, QString(QLatin1String("Object at path %1 already registered")) .arg(objectPath)); warning() << "Unable to register object" << objectPath << "- path already registered"; return false; } debug() << "Registered object" << objectPath << "at bus name" << busName; mPriv->busName = busName; mPriv->dbusObject->setObjectPath(objectPath); mPriv->registered = true; return true; } /** * \fn QVariantMap DBusService::immutableProperties() const * * Return the immutable properties of this D-Bus service object. * * Immutable properties cannot change after the object has been registered * on the bus with registerObject(). * * \return The immutable properties of this D-Bus service object. */ struct AbstractDBusServiceInterface::Private { Private(const QString &interfaceName) : interfaceName(interfaceName), dbusObject(0), registered(false) { } QString interfaceName; DBusObject *dbusObject; bool registered; }; /** * \class AbstractDBusServiceInterface * \ingroup servicesideimpl * \headerfile TelepathyQt/dbus-service.h * * \brief Base class for D-Bus service interfaces. * * This class serves as a base for all the classes that are used to implement * interfaces that sit on top of D-Bus services. */ /** * Construct an AbstractDBusServiceInterface that implements * the interface with the given \a interfaceName. * * \param interfaceName The name of the interface that this class implements. */ AbstractDBusServiceInterface::AbstractDBusServiceInterface(const QString &interfaceName) : mPriv(new Private(interfaceName)) { } /** * Class destructor. */ AbstractDBusServiceInterface::~AbstractDBusServiceInterface() { delete mPriv; } /** * Return the name of the interface that this class implements, * as given on the constructor. * * \return The name of the interface that this class implements. */ QString AbstractDBusServiceInterface::interfaceName() const { return mPriv->interfaceName; } /** * Return the DBusObject on which the adaptor of this interface is plugged. * * This is only accessible after the interface has been registered * with registerInterface(). * * \return a pointer to the DBusObject on which the adaptor * of this interface is plugged. * \sa DBusService::dbusObject() */ DBusObject *AbstractDBusServiceInterface::dbusObject() const { return mPriv->dbusObject; } /** * Return whether this interface has been registered. * * \return \c true if the service has been registered, or \c false otherwise. * \sa registerInterface() */ bool AbstractDBusServiceInterface::isRegistered() const { return mPriv->registered; } /** * Emit PropertiesChanged signal on object org.freedesktop.DBus.Properties interface * with the property \a propertyName. * * \param propertyName The name of the changed property. * \param propertyValue The actual value of the changed property. * \return \c false if the signal can not be emmited or \a true otherwise. */ bool AbstractDBusServiceInterface::notifyPropertyChanged(const QString &propertyName, const QVariant &propertyValue) { if (!isRegistered()) { return false; } QDBusMessage signal = QDBusMessage::createSignal(dbusObject()->objectPath(), TP_QT_IFACE_PROPERTIES, QLatin1String("PropertiesChanged")); QVariantMap changedProperties; changedProperties.insert(propertyName, propertyValue); signal << interfaceName(); signal << changedProperties; signal << QStringList(); return dbusObject()->dbusConnection().send(signal); } /** * Registers this interface by plugging its adaptor * on the given \a dbusObject. * * \param dbusObject The object on which to plug the adaptor. * \return \c false if the interface has already been registered, * or \a true otherwise. * \sa isRegistered() */ bool AbstractDBusServiceInterface::registerInterface(DBusObject *dbusObject) { if (mPriv->registered) { return true; } mPriv->dbusObject = dbusObject; createAdaptor(); mPriv->registered = true; return true; } /** * \fn QVariantMap AbstractDBusServiceInterface::immutableProperties() const * * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ /** * \fn void AbstractDBusServiceInterface::createAdaptor() * * Create the adaptor for this interface. * * Subclasses should reimplement this appropriately. */ } telepathy-qt-0.9.6~git1/TelepathyQt/media-session-handler.cpp0000664000175000017500000000212312470405660022071 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/cli-media-session-handler-body.hpp" #include "TelepathyQt/_gen/cli-media-session-handler.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/dbus-introspectable.xml0000664000175000017500000000056612470405660021716 0ustar jrjr D-Bus introspectable object telepathy-qt-0.9.6~git1/TelepathyQt/simple-text-observer.cpp0000664000175000017500000002476112470405660022032 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/simple-text-observer-internal.h" #include "TelepathyQt/_gen/simple-text-observer.moc.hpp" #include "TelepathyQt/_gen/simple-text-observer-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include #include namespace Tp { SimpleTextObserver::Private::Private(SimpleTextObserver *parent, const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization) : parent(parent), account(account), contactIdentifier(contactIdentifier) { debug() << "Creating a new SimpleTextObserver"; ChannelClassSpec channelFilter = ChannelClassSpec::textChat(); observer = SimpleObserver::create(account, ChannelClassSpecList() << channelFilter, contactIdentifier, requiresNormalization, QList() << ChannelClassFeatures(channelFilter, TextChannel::FeatureMessageQueue | TextChannel::FeatureMessageSentSignal)); parent->connect(observer.data(), SIGNAL(newChannels(QList)), SLOT(onNewChannels(QList))); parent->connect(observer.data(), SIGNAL(channelInvalidated(Tp::ChannelPtr,QString,QString)), SLOT(onChannelInvalidated(Tp::ChannelPtr))); } SimpleTextObserver::Private::~Private() { foreach (TextChannelWrapper *wrapper, channels) { delete wrapper; } } SimpleTextObserver::Private::TextChannelWrapper::TextChannelWrapper(const TextChannelPtr &channel) : mChannel(channel) { connect(mChannel.data(), SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)), SLOT(onChannelMessageSent(Tp::Message,Tp::MessageSendingFlags,QString))); connect(mChannel.data(), SIGNAL(messageReceived(Tp::ReceivedMessage)), SLOT(onChannelMessageReceived(Tp::ReceivedMessage))); } void SimpleTextObserver::Private::TextChannelWrapper::onChannelMessageSent( const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken) { emit channelMessageSent(message, flags, sentMessageToken, mChannel); } void SimpleTextObserver::Private::TextChannelWrapper::onChannelMessageReceived( const Tp::ReceivedMessage &message) { emit channelMessageReceived(message, mChannel); } /** * \class SimpleTextObserver * \ingroup utils * \headerfile TelepathyQt/simple-text-observer.h * * \brief The SimpleTextObserver class provides an easy way to track sent/received text messages * in an account and can be optionally filtered by a contact. */ /** * Create a new SimpleTextObserver object. * * Events will be signalled for all messages sent/received by all contacts in \a account. * * \param account The account used to listen to events. * \return An SimpleTextObserverPtr object pointing to the newly created SimpleTextObserver object. */ SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account) { return create(account, QString(), false); } /** * Create a new SimpleTextObserver object. * * If \a contact is not null, events will be signalled for all messages sent/received by \a * contact, otherwise this method works the same as create(const Tp::AccountPtr &). * * \param account The account used to listen to events. * \param contact The contact used to filter events. * \return An SimpleTextObserverPtr object pointing to the newly created SimpleTextObserver object. */ SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account, const ContactPtr &contact) { if (contact) { return create(account, contact->id(), false); } return create(account, QString(), false); } /** * Create a new SimpleTextObserver object. * * If \a contactIdentifier is non-empty, events will be signalled for all messages sent/received * by a contact identified by \a contactIdentifier, otherwise this method works the same as * create(const Tp::AccountPtr &). * * \param account The account used to listen to events. * \param contactIdentifier The identifier of the contact used to filter events. * \return An SimpleTextObserverPtr object pointing to the newly created SimpleTextObserver object. */ SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account, const QString &contactIdentifier) { return create(account, contactIdentifier, true); } SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization) { return SimpleTextObserverPtr( new SimpleTextObserver(account, contactIdentifier, requiresNormalization)); } /** * Construct a new SimpleTextObserver object. * * \param account The account used to listen to events. * \param contactIdentifier The identifier of the contact used to filter events. * \param requiresNormalization Whether \a contactIdentifier needs to be normalized. * \return An SimpleTextObserverPtr object pointing to the newly created SimpleTextObserver object. */ SimpleTextObserver::SimpleTextObserver(const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization) : mPriv(new Private(this, account, contactIdentifier, requiresNormalization)) { if (!mPriv->observer->channels().isEmpty()) { onNewChannels(mPriv->observer->channels()); } } /** * Class destructor. */ SimpleTextObserver::~SimpleTextObserver() { delete mPriv; } /** * Return the account used to listen to events. * * \return A pointer to the Account object. */ AccountPtr SimpleTextObserver::account() const { return mPriv->account; } /** * Return the identifier of the contact used to filter events, or an empty string if none was * provided at construction. * * \return The identifier of the contact. */ QString SimpleTextObserver::contactIdentifier() const { return mPriv->contactIdentifier; } /** * Return the list of text chats currently being observed. * * \return A list of pointers to TextChannel objects. */ QList SimpleTextObserver::textChats() const { QList ret; foreach (const ChannelPtr &channel, mPriv->observer->channels()) { TextChannelPtr textChannel = TextChannelPtr::qObjectCast(channel); if (textChannel) { ret << textChannel; } } return ret; } void SimpleTextObserver::onNewChannels(const QList &channels) { foreach (const ChannelPtr &channel, channels) { TextChannelPtr textChannel = TextChannelPtr::qObjectCast(channel); if (!textChannel) { if (channel->channelType() != TP_QT_IFACE_CHANNEL_TYPE_TEXT) { warning() << "Channel received to observe is not of type Text, service confused. " "Ignoring channel"; } else { warning() << "Channel received to observe is not a subclass of TextChannel. " "ChannelFactory set on this observer's account must construct TextChannel " "subclasses for channels of type Text. Ignoring channel"; } continue; } if (mPriv->channels.contains(channel)) { // we are already observing this channel continue; } Private::TextChannelWrapper *wrapper = new Private::TextChannelWrapper(textChannel); mPriv->channels.insert(channel, wrapper); connect(wrapper, SIGNAL(channelMessageSent(Tp::Message,Tp::MessageSendingFlags,QString,Tp::TextChannelPtr)), SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString,Tp::TextChannelPtr))); connect(wrapper, SIGNAL(channelMessageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)), SIGNAL(messageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr))); foreach (const ReceivedMessage &message, textChannel->messageQueue()) { emit messageReceived(message, textChannel); } } } void SimpleTextObserver::onChannelInvalidated(const ChannelPtr &channel) { // it may happen that the channel received in onNewChannels is not a text channel somehow, thus // the channel won't be added to mPriv->channels if (mPriv->channels.contains(channel)) { delete mPriv->channels.take(channel); } } /** * \fn void SimpleTextObserver::messageSent(const Tp::Message &message, * Tp::MessageSendingFlags flags, const QString &sentMessageToken, * const Tp::TextChannelPtr &channel); * * Emitted whenever a text message on account() is sent. * If contactIdentifier() is non-empty, only messages sent to the contact identified by it will * be signalled. * * \param message The message sent. * \param flags The message flags, * \param sentMessageToken The message token. * \param channel The channel which received the message. */ /** * \fn void SimpleTextObserver::messageReceived(const Tp::ReceivedMessage &message, * const Tp::TextChannelPtr &channel); * * Emitted whenever a text message on account() is received. * If contactIdentifier() is non-empty, only messages received by the contact identified by it will * be signalled. * * \param message The message received. * \param channel The channel which received the message. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/simple-observer.h0000664000175000017500000000746412470405660020516 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_simple_observer_h_HEADER_GUARD_ #define _TelepathyQt_simple_observer_h_HEADER_GUARD_ #include #include #include #include namespace Tp { class PendingOperation; class TP_QT_EXPORT SimpleObserver : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(SimpleObserver) public: static SimpleObserverPtr create(const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QList &extraChannelFeatures = QList()); static SimpleObserverPtr create(const AccountPtr &account, const ChannelClassSpecList &channelFilter, const ContactPtr &contact, const QList &extraChannelFeatures = QList()); static SimpleObserverPtr create(const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QString &contactIdentifier, const QList &extraChannelFeatures = QList()); virtual ~SimpleObserver(); AccountPtr account() const; ChannelClassSpecList channelFilter() const; QString contactIdentifier() const; QList extraChannelFeatures() const; QList channels() const; Q_SIGNALS: void newChannels(const QList &channels); void channelInvalidated(const Tp::ChannelPtr &channel, const QString &errorName, const QString &errorMessage); private Q_SLOTS: TP_QT_NO_EXPORT void onAccountConnectionChanged(const Tp::ConnectionPtr &connection); TP_QT_NO_EXPORT void onAccountConnectionConnected(); TP_QT_NO_EXPORT void onContactConstructed(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onNewChannels(const Tp::AccountPtr &channelsAccount, const QList &channels); TP_QT_NO_EXPORT void onChannelInvalidated(const Tp::AccountPtr &channelAccount, const Tp::ChannelPtr &channel, const QString &errorName, const QString &errorMessage); private: friend class SimpleCallObserver; friend class SimpleTextObserver; TP_QT_NO_EXPORT static SimpleObserverPtr create(const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QString &contactIdentifier, bool requiresNormalization, const QList &extraChannelFeatures); TP_QT_NO_EXPORT SimpleObserver(const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QString &contactIdentifier, bool requiresNormalization, const QList &extraChannelFeatures); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/AbstractClient0000664000175000017500000000037112470405660020042 0ustar jrjr#ifndef _TelepathyQt_AbstractClient_HEADER_GUARD_ #define _TelepathyQt_AbstractClient_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/OutgoingDBusTubeChannel0000664000175000017500000000042612470405660021623 0ustar jrjr#ifndef _TelepathyQt_OutgoingDBusTubeChannel_HEADER_GUARD_ #define _TelepathyQt_OutgoingDBusTubeChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PendingSendMessage0000664000175000017500000000040612470405660020642 0ustar jrjr#ifndef _TelepathyQt_PendingSendMessage_HEADER_GUARD_ #define _TelepathyQt_PendingSendMessage_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AbstractAdaptor0000664000175000017500000000037412470405660020221 0ustar jrjr#ifndef _TelepathyQt_AbstractAdaptor_HEADER_GUARD_ #define _TelepathyQt_AbstractAdaptor_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceBalanceInterface0000664000175000017500000000043612470405660024151 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceBalanceInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceBalanceInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Object0000664000175000017500000000034012470405660016342 0ustar jrjr#ifndef _TelepathyQt_Object_HEADER_GUARD_ #define _TelepathyQt_Object_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-account.h0000664000175000017500000000413412470405660020445 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_account_h_HEADER_GUARD_ #define _TelepathyQt_pending_account_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include class QDBusPendingCallWatcher; namespace Tp { class AccountManager; class TP_QT_EXPORT PendingAccount : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingAccount); public: ~PendingAccount(); AccountManagerPtr manager() const; AccountPtr account() const; private Q_SLOTS: TP_QT_NO_EXPORT void onCallFinished(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onAccountBuilt(Tp::PendingOperation *readyOp); TP_QT_NO_EXPORT void onNewAccount(const Tp::AccountPtr &account); private: friend class AccountManager; TP_QT_NO_EXPORT PendingAccount(const AccountManagerPtr &manager, const QString &connectionManager, const QString &protocol, const QString &displayName, const QVariantMap ¶meters, const QVariantMap &properties = QVariantMap()); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/types.cpp0000664000175000017500000000404412470405660017066 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "TelepathyQt/_gen/types-body.hpp" #include "TelepathyQt/future-internal.h" #include "TelepathyQt/_gen/future-types-body.hpp" namespace Tp { /** * \\ingroup types * \headerfile TelepathyQt/types.h * * Register the types used by the library with the QtDBus type system. * * Call this function to register the types used before using anything else in * the library. */ void registerTypes() { qDBusRegisterMetaType(); Tp::_registerTypes(); TpFuture::_registerTypes(); } bool operator==(const SUSocketAddress& v1, const SUSocketAddress& v2) { return ((v1.address == v2.address) && (v1.port == v2.port) ); } QDBusArgument& operator<<(QDBusArgument& arg, const SUSocketAddress& val) { arg.beginStructure(); arg << val.address << val.port; arg.endStructure(); return arg; } const QDBusArgument& operator>>(const QDBusArgument& arg, SUSocketAddress& val) { arg.beginStructure(); arg >> val.address >> val.port; arg.endStructure(); return arg; } } telepathy-qt-0.9.6~git1/TelepathyQt/media-stream-handler.xml0000664000175000017500000000035712470405660021726 0ustar jrjr Media stream handler telepathy-qt-0.9.6~git1/TelepathyQt/channel-dispatch-operation.cpp0000664000175000017500000006040512470405660023130 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/channel-dispatch-operation-internal.h" #include "TelepathyQt/_gen/cli-channel-dispatch-operation-body.hpp" #include "TelepathyQt/_gen/cli-channel-dispatch-operation.moc.hpp" #include "TelepathyQt/_gen/channel-dispatch-operation.moc.hpp" #include "TelepathyQt/_gen/channel-dispatch-operation-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/fake-handler-manager-internal.h" #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ChannelDispatchOperation::Private { Private(ChannelDispatchOperation *parent); ~Private(); static void introspectMain(Private *self); void extractMainProps(const QVariantMap &props, bool immutableProperties); // Public object ChannelDispatchOperation *parent; // Context AccountFactoryConstPtr accFactory; ConnectionFactoryConstPtr connFactory; ChannelFactoryConstPtr chanFactory; ContactFactoryConstPtr contactFactory; // Instance of generated interface class Client::ChannelDispatchOperationInterface *baseInterface; // Mandatory properties interface proxy Client::DBus::PropertiesInterface *properties; ReadinessHelper *readinessHelper; // Introspection QVariantMap immutableProperties; ConnectionPtr connection; AccountPtr account; QList channels; QStringList possibleHandlers; bool gotPossibleHandlers; }; ChannelDispatchOperation::Private::Private(ChannelDispatchOperation *parent) : parent(parent), baseInterface(new Client::ChannelDispatchOperationInterface(parent)), properties(parent->interface()), readinessHelper(parent->readinessHelper()), gotPossibleHandlers(false) { debug() << "Creating new ChannelDispatchOperation:" << parent->objectPath(); parent->connect(baseInterface, SIGNAL(Finished()), SLOT(onFinished())); parent->connect(baseInterface, SIGNAL(ChannelLost(QDBusObjectPath,QString,QString)), SLOT(onChannelLost(QDBusObjectPath,QString,QString))); ReadinessHelper::Introspectables introspectables; // As ChannelDispatchOperation does not have predefined statuses let's simulate one (0) ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMain, this); introspectables[FeatureCore] = introspectableCore; readinessHelper->addIntrospectables(introspectables); } ChannelDispatchOperation::Private::~Private() { } void ChannelDispatchOperation::Private::introspectMain(ChannelDispatchOperation::Private *self) { QVariantMap mainProps; foreach (QString key, self->immutableProperties.keys()) { if (key.startsWith(TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String("."))) { QVariant value = self->immutableProperties.value(key); mainProps.insert( key.remove(TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION + QLatin1String(".")), value); } } if (!self->channels.isEmpty() && mainProps.contains(QLatin1String("Account")) && mainProps.contains(QLatin1String("Connection")) && mainProps.contains(QLatin1String("Interfaces")) && mainProps.contains(QLatin1String("PossibleHandlers"))) { debug() << "Supplied properties were sufficient, not introspecting" << self->parent->objectPath(); self->extractMainProps(mainProps, true); return; } debug() << "Calling Properties::GetAll(ChannelDispatchOperation)"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->GetAll(TP_QT_IFACE_CHANNEL_DISPATCH_OPERATION), self->parent); self->parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotMainProperties(QDBusPendingCallWatcher*))); } void ChannelDispatchOperation::Private::extractMainProps(const QVariantMap &props, bool immutableProperties) { parent->setInterfaces(qdbus_cast(props.value(QLatin1String("Interfaces")))); QList readyOps; if (!connection && props.contains(QLatin1String("Connection"))) { QDBusObjectPath connectionObjectPath = qdbus_cast(props.value(QLatin1String("Connection"))); QString connectionBusName = connectionObjectPath.path().mid(1).replace(QLatin1String("/"), QLatin1String(".")); PendingReady *readyOp = connFactory->proxy(connectionBusName, connectionObjectPath.path(), chanFactory, contactFactory); connection = ConnectionPtr::qObjectCast(readyOp->proxy()); readyOps.append(readyOp); } if (!account && props.contains(QLatin1String("Account"))) { QDBusObjectPath accountObjectPath = qdbus_cast(props.value(QLatin1String("Account"))); PendingReady *readyOp = accFactory->proxy(TP_QT_ACCOUNT_MANAGER_BUS_NAME, accountObjectPath.path(), connFactory, chanFactory, contactFactory); account = AccountPtr::qObjectCast(readyOp->proxy()); readyOps.append(readyOp); } if (!immutableProperties) { // If we're here, it means we had to introspect the object, and now for sure have the // correct channels list, so let's overwrite the initial channels - but keep the refs around // for a while as an optimization enabling the factory to still return the same ones instead // of constructing everything anew. Note that this is not done at all in the case the // immutable props and initial channels etc were sufficient. QList saveChannels = channels; channels.clear(); ChannelDetailsList channelDetailsList = qdbus_cast(props.value(QLatin1String("Channels"))); ChannelPtr channel; foreach (const ChannelDetails &channelDetails, channelDetailsList) { PendingReady *readyOp = chanFactory->proxy(connection, channelDetails.channel.path(), channelDetails.properties); channels.append(ChannelPtr::qObjectCast(readyOp->proxy())); readyOps.append(readyOp); } // saveChannels goes out of scope now, so any initial channels which don't exist anymore are // freed } if (props.contains(QLatin1String("PossibleHandlers"))) { possibleHandlers = qdbus_cast(props.value(QLatin1String("PossibleHandlers"))); gotPossibleHandlers = true; } if (readyOps.isEmpty()) { debug() << "No proxies to prepare for CDO" << parent->objectPath(); readinessHelper->setIntrospectCompleted(FeatureCore, true); } else { parent->connect(new PendingComposite(readyOps, ChannelDispatchOperationPtr(parent)), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onProxiesPrepared(Tp::PendingOperation*))); } } ChannelDispatchOperation::PendingClaim::PendingClaim(const ChannelDispatchOperationPtr &op, const AbstractClientHandlerPtr &handler) : PendingOperation(op), mDispatchOp(op), mHandler(handler) { debug() << "Invoking CDO.Claim"; connect(new PendingVoid(op->baseInterface()->Claim(), op), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onClaimFinished(Tp::PendingOperation*))); } ChannelDispatchOperation::PendingClaim::~PendingClaim() { } void ChannelDispatchOperation::PendingClaim::onClaimFinished( PendingOperation *op) { if (!op->isError()) { debug() << "CDO.Claim returned successfully, updating HandledChannels"; if (mHandler) { // register the channels in HandledChannels FakeHandlerManager::instance()->registerChannels( mDispatchOp->channels()); } setFinished(); } else { warning() << "CDO.Claim failed with" << op->errorName() << "-" << op->errorMessage(); setFinishedWithError(op->errorName(), op->errorMessage()); } } /** * \class ChannelDispatchOperation * \ingroup clientchanneldispatchoperation * \headerfile TelepathyQt/channel-dispatch-operation.h * * \brief The ChannelDispatchOperation class represents a Telepathy channel * dispatch operation. * * One of the channel dispatcher's functions is to offer incoming channels to * Approver clients for approval. An approver should generally ask the user * whether they want to participate in the requested communication channels * (join the chat or chatroom, answer the call, accept the file transfer, or * whatever is appropriate). A collection of channels offered in this way * is represented by a ChannelDispatchOperation object. * * If the user wishes to accept the communication channels, the approver * should call handleWith() to indicate the user's or approver's preferred * handler for the channels (the empty string indicates no particular * preference, and will cause any suitable handler to be used). * * If the user wishes to reject the communication channels, or if the user * accepts the channels and the approver will handle them itself, the approver * should call claim(). If the resulting PendingOperation succeeds, the approver * immediately has control over the channels as their primary handler, * and may do anything with them (in particular, it may close them in whatever * way seems most appropriate). * * There are various situations in which the channel dispatch operation will * be closed, causing the DBusProxy::invalidated() signal to be emitted. If this * happens, the approver should stop prompting the user. * * Because all approvers are launched simultaneously, the user might respond * to another approver; if this happens, the invalidated signal will be * emitted with the error code #TP_QT_ERROR_OBJECT_REMOVED. * * If a channel closes, the signal channelLost() is emitted. If all channels * close, there is nothing more to dispatch, so the invalidated signal will be * emitted with the error code #TP_QT_ERROR_OBJECT_REMOVED. * * If the channel dispatcher crashes or exits, the invalidated * signal will be emitted with the error code * #TP_QT_DBUS_ERROR_NAME_HAS_NO_OWNER. In a high-quality implementation, * the dispatcher should be restarted, at which point it will create new * channel dispatch operations for any undispatched channels, and the approver * will be notified again. */ /** * Feature representing the core that needs to become ready to make the * ChannelDispatchOperation object usable. * * Note that this feature must be enabled in order to use most * ChannelDispatchOperation methods. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature ChannelDispatchOperation::FeatureCore = Feature(QLatin1String(ChannelDispatchOperation::staticMetaObject.className()), 0, true); /** * Create a new channel dispatch operation object using the given \a bus, the given factories and * the given initial channels. * * \param bus QDBusConnection to use. * \param objectPath The channel dispatch operation object path. * \param immutableProperties The channel dispatch operation immutable properties. * \param initialChannels The channels this CDO has initially (further tracking is done internally). * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return A ChannelDispatchOperationPtr object pointing to the newly created * ChannelDispatchOperation object. */ ChannelDispatchOperationPtr ChannelDispatchOperation::create(const QDBusConnection &bus, const QString &objectPath, const QVariantMap &immutableProperties, const QList &initialChannels, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return ChannelDispatchOperationPtr(new ChannelDispatchOperation( bus, objectPath, immutableProperties, initialChannels, accountFactory, connectionFactory, channelFactory, contactFactory)); } /** * Construct a new channel dispatch operation object using the given \a bus, the given factories and * the given initial channels. * * \param bus QDBusConnection to use * \param objectPath The channel dispatch operation object path. * \param immutableProperties The channel dispatch operation immutable properties. * \param initialChannels The channels this CDO has initially (further tracking is done internally). * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. */ ChannelDispatchOperation::ChannelDispatchOperation(const QDBusConnection &bus, const QString &objectPath, const QVariantMap &immutableProperties, const QList &initialChannels, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) : StatefulDBusProxy(bus, TP_QT_IFACE_CHANNEL_DISPATCHER, objectPath, FeatureCore), OptionalInterfaceFactory(this), mPriv(new Private(this)) { if (accountFactory->dbusConnection().name() != bus.name()) { warning() << " The D-Bus connection in the account factory is not the proxy connection"; } if (connectionFactory->dbusConnection().name() != bus.name()) { warning() << " The D-Bus connection in the connection factory is not the proxy connection"; } if (channelFactory->dbusConnection().name() != bus.name()) { warning() << " The D-Bus connection in the channel factory is not the proxy connection"; } mPriv->channels = initialChannels; mPriv->accFactory = accountFactory; mPriv->connFactory = connectionFactory; mPriv->chanFactory = channelFactory; mPriv->contactFactory = contactFactory; mPriv->immutableProperties = immutableProperties; } /** * Class destructor. */ ChannelDispatchOperation::~ChannelDispatchOperation() { delete mPriv; } /** * Return the connection with which the channels for this dispatch * operation are associated. * * This method requires ChannelDispatchOperation::FeatureCore to be ready. * * \return A pointer to the Connection object. */ ConnectionPtr ChannelDispatchOperation::connection() const { return mPriv->connection; } /** * Return the account with which the connection and channels for this dispatch * operation are associated. * * This method requires ChannelDispatchOperation::FeatureCore to be ready. * * \return A pointer to the Account object. */ AccountPtr ChannelDispatchOperation::account() const { return mPriv->account; } /** * Return the channels to be dispatched. * * This method requires ChannelDispatchOperation::FeatureCore to be ready. * * \return A list of pointers to Channel objects. */ QList ChannelDispatchOperation::channels() const { if (!isReady()) { warning() << "ChannelDispatchOperation::channels called with channel " "not ready"; } return mPriv->channels; } /** * Return the well known bus names (starting with * org.freedesktop.Telepathy.Client.) of the possible Handlers for this * dispatch operation channels with the preferred handlers first. * * As a result, approvers should use the first handler by default, unless they * have a reason to do otherwise. * * This method requires ChannelDispatchOperation::FeatureCore to be ready. * * \return List of possible handlers names. */ QStringList ChannelDispatchOperation::possibleHandlers() const { return mPriv->possibleHandlers; } /** * Called by an approver to accept a channel bundle and request that the given * handler be used to handle it. * * If successful, this method will cause the ChannelDispatchOperation object to * disappear, emitting invalidated with error * #TP_QT_ERROR_OBJECT_REMOVED. * * However, this method may fail because the dispatch has already been completed * and the object has already gone. If this occurs, it indicates that another * approver has asked for the bundle to be handled by a particular handler. The * approver must not attempt to interact with the channels further in this case, * unless it is separately invoked as the handler. * * Approvers which are also channel handlers should use claim() instead of * this method to request that they can handle a channel bundle themselves. * * \param handler The well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the channel handler that * should handle the channel, or an empty string if * the client has no preferred channel handler. * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *ChannelDispatchOperation::handleWith(const QString &handler) { return new PendingVoid( mPriv->baseInterface->HandleWith(handler), ChannelDispatchOperationPtr(this)); } /** * Called by an approver to claim channels for closing them. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *ChannelDispatchOperation::claim() { return new PendingClaim(ChannelDispatchOperationPtr(this)); } /** * Called by an approver to claim channels for handling internally. If this * method is called successfully, the \a handler becomes the * handler for the channel, but does not have the * AbstractClientHandler::handleChannels() method called on it. * * Approvers wishing to reject channels must call this method to claim ownership * of them, and must not call requestClose() on the channels unless/until this * method returns successfully. * * The channel dispatcher can't know how best to close arbitrary channel types, * so it leaves it up to the approver to do so. For instance, for text channels * it is necessary to acknowledge any messages that have already been displayed * to the user first - ideally, the approver would display and then acknowledge * the messages - or to call Channel::requestClose() if the destructive * behaviour of that method is desired. * * Similarly, an approver for streamed media channels can close the channel with * a reason (e.g. "busy") if desired. The channel dispatcher, which is designed * to have no specific knowledge of particular channel types, can't do that. * * If successful, this method will cause the ChannelDispatchOperation object to * disappear, emitting Finished, in the same way as for handleWith(). * * This method may fail because the dispatch operation has already been * completed. Again, see handleWith() for more details. The approver must not * attempt to interact with the channels further in this case. * * \param handler The channel handler, that should remain registered during the * lifetime of channels(), otherwise dispatching will fail if the * channel dispatcher restarts. * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa claim(), handleWith() */ PendingOperation *ChannelDispatchOperation::claim(const AbstractClientHandlerPtr &handler) { if (!handler->isRegistered()) { return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Handler must be registered for using claim(handler)"), ChannelDispatchOperationPtr(this)); } return new PendingClaim(ChannelDispatchOperationPtr(this), handler); } /** * \fn void ChannelDispatchOperation::channelLost(const ChannelPtr &channel, * const QString &errorName, const QString &errorMessage); * * Emitted when a channel has closed before it could be claimed or handled. If this is * emitted for the last remaining channel in a channel dispatch operation, it * will immediately be followed by invalidated() with error * #TP_QT_ERROR_OBJECT_REMOVED. * * \param channel The channel that was closed. * \param error The name of a D-Bus error indicating why the channel closed. * \param errorMessage The error message. */ /** * Return the ChannelDispatchOperationInterface for this ChannelDispatchOperation * class. This method is protected since the convenience methods provided by * this class should always be used instead of the interface by users of the * class. * * \return A pointer to the existing Client::ChannelDispatchOperationInterface object for this * ChannelDispatchOperation object. */ Client::ChannelDispatchOperationInterface *ChannelDispatchOperation::baseInterface() const { return mPriv->baseInterface; } void ChannelDispatchOperation::onFinished() { debug() << "ChannelDispatchOperation finished and was removed"; invalidate(TP_QT_ERROR_OBJECT_REMOVED, QLatin1String("ChannelDispatchOperation finished and was removed")); } void ChannelDispatchOperation::gotMainProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; // Watcher is NULL if we didn't have to introspect at all if (!reply.isError()) { debug() << "Got reply to Properties::GetAll(ChannelDispatchOperation)"; mPriv->extractMainProps(reply.value(), false); } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); warning().nospace() << "Properties::GetAll(ChannelDispatchOperation) failed with " << reply.error().name() << ": " << reply.error().message(); } } void ChannelDispatchOperation::onChannelLost( const QDBusObjectPath &channelObjectPath, const QString &errorName, const QString &errorMessage) { foreach (const ChannelPtr &channel, mPriv->channels) { if (channel->objectPath() == channelObjectPath.path()) { emit channelLost(channel, errorName, errorMessage); mPriv->channels.removeOne(channel); return; } } } void ChannelDispatchOperation::onProxiesPrepared(Tp::PendingOperation *op) { if (op->isError()) { warning() << "Preparing proxies for CDO" << objectPath() << "failed with" << op->errorName() << ":" << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false); } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/StreamedMediaChannel0000664000175000017500000000041412470405660021133 0ustar jrjr#ifndef _TelepathyQt_StreamedMediaChannel_HEADER_GUARD_ #define _TelepathyQt_StreamedMediaChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceContactGroupsInterface0000664000175000017500000000045212470405660025415 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceContactGroupsInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceContactGroupsInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-ready.h0000664000175000017500000000377212470405660020124 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_ready_h_HEADER_GUARD_ #define _TelepathyQt_pending_ready_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include namespace Tp { class TP_QT_EXPORT PendingReady: public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingReady); public: ~PendingReady(); DBusProxyPtr proxy() const; Features requestedFeatures() const; private Q_SLOTS: TP_QT_NO_EXPORT void onNestedFinished(Tp::PendingOperation *); private: friend class Connection; friend class DBusProxyFactory; friend class ReadinessHelper; TP_QT_NO_EXPORT PendingReady(const SharedPtr &object, const Features &requestedFeatures); TP_QT_NO_EXPORT PendingReady(const SharedPtr &factory, const DBusProxyPtr &proxy, const Features &requestedFeatures); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/CallChannel0000664000175000017500000000036012470405660017302 0ustar jrjr#ifndef _TelepathyQt_CallChannel_HEADER_GUARD_ #define _TelepathyQt_CallChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-string.cpp0000664000175000017500000000531512470405660020654 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-string.moc.hpp" #include "TelepathyQt/debug-internal.h" #include namespace Tp { struct TP_QT_NO_EXPORT PendingString::Private { QString result; }; /** * \class PendingString * \ingroup utils * \headerfile TelepathyQt/pending-string.h * * \brief The PendingString class is a generic subclass of PendingOperation * representing a pending D-Bus method call that returns a string. * * See \ref async_model */ PendingString::PendingString(QDBusPendingCall call, const SharedPtr &object) : PendingOperation(object), mPriv(new Private) { connect(new QDBusPendingCallWatcher(call), SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(watcherFinished(QDBusPendingCallWatcher*))); } PendingString::PendingString(const QString &errorName, const QString &errorMessage) : PendingOperation(SharedPtr()), mPriv(new Private) { setFinishedWithError(errorName, errorMessage); } /** * Class destructor. */ PendingString::~PendingString() { delete mPriv; } QString PendingString::result() const { return mPriv->result; } void PendingString::setResult(const QString &result) { mPriv->result = result; } void PendingString::watcherFinished(QDBusPendingCallWatcher* watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got reply to PendingString call"; setResult(reply.value()); setFinished(); } else { debug().nospace() << "PendingString call failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/pending-dbus-tube-connection.h0000664000175000017500000000441712470405660023044 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_dbus_tube_connection_h_HEADER_GUARD_ #define _TelepathyQt_pending_dbus_tube_connection_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class PendingString; class TP_QT_EXPORT PendingDBusTubeConnection : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingDBusTubeConnection) public: virtual ~PendingDBusTubeConnection(); QString address() const; bool allowsOtherUsers() const; private Q_SLOTS: TP_QT_NO_EXPORT void onConnectionFinished(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onStateChanged(Tp::TubeChannelState state); TP_QT_NO_EXPORT void onChannelInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage); private: TP_QT_NO_EXPORT PendingDBusTubeConnection(PendingString *string, bool allowOtherUsers, const QVariantMap ¶meters, const DBusTubeChannelPtr &object); TP_QT_NO_EXPORT PendingDBusTubeConnection(const QString &errorName, const QString &errorMessage, const DBusTubeChannelPtr &object); struct Private; friend class OutgoingDBusTubeChannel; friend class IncomingDBusTubeChannel; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/dbus.xml0000664000175000017500000000052312470405660016673 0ustar jrjr D-Bus interfaces telepathy-qt-0.9.6~git1/TelepathyQt/MessageContentPart0000664000175000017500000000040612470405660020705 0ustar jrjr#ifndef _TelepathyQt_MessageContentPart_HEADER_GUARD_ #define _TelepathyQt_MessageContentPart_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/account-manager.xml0000664000175000017500000000036012470405660021001 0ustar jrjr Account Manager interfaces telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionManager0000664000175000017500000000040212470405660020525 0ustar jrjr#ifndef _TelepathyQt_ConnectionManager_HEADER_GUARD_ #define _TelepathyQt_ConnectionManager_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AbstractClientApprover0000664000175000017500000000041112470405660021554 0ustar jrjr#ifndef _TelepathyQt_AbstractClientApprover_HEADER_GUARD_ #define _TelepathyQt_AbstractClientApprover_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/incoming-stream-tube-channel.cpp0000664000175000017500000004263512470405660023371 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/incoming-stream-tube-channel.moc.hpp" #include "TelepathyQt/types-internal.h" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT IncomingStreamTubeChannel::Private { Private(IncomingStreamTubeChannel *parent); // Public object IncomingStreamTubeChannel *parent; static bool initRandom; }; bool IncomingStreamTubeChannel::Private::initRandom = true; IncomingStreamTubeChannel::Private::Private(IncomingStreamTubeChannel *parent) : parent(parent) { } /** * \class IncomingStreamTubeChannel * \ingroup clientchannel * \headerfile TelepathyQt/incoming-stream-tube-channel.h * * \brief The IncomingStreamTubeChannel class represents an incoming Telepathy channel * of type StreamTube. * * In particular, this class is meant to be used as a comfortable way for * accepting incoming stream tubes. Tubes can be accepted as TCP and/or Unix sockets with various * access control methods depending on what the service supports using the various overloads of * acceptTubeAsTcpSocket() and acceptTubeAsUnixSocket(). * * Once a tube is successfully accepted and open (the PendingStreamTubeConnection returned from the * accepting methods has finished), the application can connect to the socket the address of which * can be retrieved from PendingStreamTubeConnection::ipAddress() and/or * PendingStreamTubeConnection::localAddress() depending on which accepting method was used. * Connecting to this socket will open a tunneled connection to the service listening at the * offering end of the tube. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * IncomingStreamTubeChannel object usable. * * This is currently the same as StreamTubeChannel::FeatureCore, but may change to include more. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature IncomingStreamTubeChannel::FeatureCore = Feature(QLatin1String(StreamTubeChannel::staticMetaObject.className()), 0); // ST::FeatureCore /** * Create a new IncomingStreamTubeChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A IncomingStreamTubeChannelPtr object pointing to the newly created * IncomingStreamTubeChannel object. */ IncomingStreamTubeChannelPtr IncomingStreamTubeChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return IncomingStreamTubeChannelPtr(new IncomingStreamTubeChannel(connection, objectPath, immutableProperties, IncomingStreamTubeChannel::FeatureCore)); } /** * Construct a new IncomingStreamTubeChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on IncomingStreamTubeChannel::FeatureCore. */ IncomingStreamTubeChannel::IncomingStreamTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : StreamTubeChannel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ IncomingStreamTubeChannel::~IncomingStreamTubeChannel() { delete mPriv; } /** * Accept an incoming stream tube as a TCP socket. * * This method accepts an incoming connection request for a stream tube. It can be called * only if the tube is in the #TubeStateLocalPending state. * * The connection manager will open a TCP socket for the application to connect to. The address of * the socket will be returned in PendingStreamTubeConnection::ipAddress() once the operation has * finished successfully. * * This overload lets you specify an allowed address/port combination for connecting to the CM * socket. Connections with other source addresses won't be accepted. The accessors * supportsIPv4SocketsWithSpecifiedAddress() and supportsIPv6SocketsWithSpecifiedAddress() can be * used to verify that the connection manager supports this kind of access control; otherwise, this * method will always fail unless QHostAddress::Any (or QHostAddress::AnyIPv4 in Qt5) or * QHostAddress::AnyIPv6 is passed, in which case the behavior is identical to the always supported * acceptTubeAsTcpSocket() overload. * * Note that when using QHostAddress::Any (or QHostAddress::AnyIPv4 in Qt5) or * QHostAddress::AnyIPv6, \a allowedPort is ignored. * * This method requires IncomingStreamTubeChannel::FeatureCore to be ready. * * \param allowedAddress An allowed address for connecting to the socket. * \param allowedPort An allowed port for connecting to the socket. * \return A PendingStreamTubeConnection which will emit PendingStreamTubeConnection::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). */ PendingStreamTubeConnection *IncomingStreamTubeChannel::acceptTubeAsTcpSocket( const QHostAddress &allowedAddress, quint16 allowedPort) { if (!isReady(IncomingStreamTubeChannel::FeatureCore)) { warning() << "IncomingStreamTubeChannel::FeatureCore must be ready before " "calling acceptTubeAsTcpSocket"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingStreamTubeChannelPtr(this)); } // The tube must be in local pending state if (state() != TubeChannelStateLocalPending) { warning() << "You can accept tubes only when they are in LocalPending state"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingStreamTubeChannelPtr(this)); } QVariant controlParameter; SocketAccessControl accessControl; QHostAddress hostAddress = allowedAddress; #if QT_VERSION >= 0x050000 if (hostAddress == QHostAddress::Any) { hostAddress = QHostAddress::AnyIPv4; } #endif // Now, let's check what we need to do with accessControl. There is just one special case, Port. if (hostAddress != QHostAddress::Any && #if QT_VERSION >= 0x050000 hostAddress != QHostAddress::AnyIPv4 && #endif hostAddress != QHostAddress::AnyIPv6) { // We need to have a valid QHostAddress AND Port. if (hostAddress.isNull() || allowedPort == 0) { warning() << "You have to set a valid allowed address+port to use Port access control"; return new PendingStreamTubeConnection(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("The supplied allowed address and/or port was invalid"), IncomingStreamTubeChannelPtr(this)); } accessControl = SocketAccessControlPort; // IPv4 or IPv6? if (hostAddress.protocol() == QAbstractSocket::IPv4Protocol) { // IPv4 case SocketAddressIPv4 addr; addr.address = hostAddress.toString(); addr.port = allowedPort; controlParameter = QVariant::fromValue(addr); } else if (hostAddress.protocol() == QAbstractSocket::IPv6Protocol) { // IPv6 case SocketAddressIPv6 addr; addr.address = hostAddress.toString(); addr.port = allowedPort; controlParameter = QVariant::fromValue(addr); } else { // We're handling an IPv4/IPv6 socket only warning() << "acceptTubeAsTcpSocket can be called only with a QHostAddress " "representing an IPv4 or IPv6 address"; return new PendingStreamTubeConnection(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid host given"), IncomingStreamTubeChannelPtr(this)); } } else { // We have to do no special stuff here accessControl = SocketAccessControlLocalhost; // Since QDBusMarshaller does not like null variants, just add an empty string. controlParameter = QVariant(QString()); } // Set the correct address type and access control setAddressType(hostAddress.protocol() == QAbstractSocket::IPv4Protocol ? SocketAddressTypeIPv4 : SocketAddressTypeIPv6); setAccessControl(accessControl); // Fail early if the combination is not supported if ((accessControl == SocketAccessControlLocalhost && addressType() == SocketAddressTypeIPv4 && !supportsIPv4SocketsOnLocalhost()) || (accessControl == SocketAccessControlPort && addressType() == SocketAddressTypeIPv4 && !supportsIPv4SocketsWithSpecifiedAddress()) || (accessControl == SocketAccessControlLocalhost && addressType() == SocketAddressTypeIPv6 && !supportsIPv6SocketsOnLocalhost()) || (accessControl == SocketAccessControlPort && addressType() == SocketAddressTypeIPv6 && !supportsIPv6SocketsWithSpecifiedAddress())) { warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), IncomingStreamTubeChannelPtr(this)); } // Perform the actual call PendingVariant *pv = new PendingVariant( interface()->Accept( addressType(), accessControl, QDBusVariant(controlParameter)), IncomingStreamTubeChannelPtr(this)); PendingStreamTubeConnection *op = new PendingStreamTubeConnection(pv, addressType(), false, 0, IncomingStreamTubeChannelPtr(this)); return op; } /** * Accept an incoming stream tube as a TCP socket. * * This method accepts an incoming connection request for a stream tube. It can be called * only if the tube is in the #TubeStateLocalPending state. * * The connection manager will open a TCP socket for the application to connect to. The address of * the socket will be returned in PendingStreamTubeConnection::ipAddress() once the operation has * finished successfully. * * Using this overload, the connection manager will accept every incoming connection from localhost. * * This accept method must be supported by all connection managers adhering to the \telepathy_spec. * * This method requires IncomingStreamTubeChannel::FeatureCore to be ready. * * \return A PendingStreamTubeConnection which will emit PendingStreamTubeConnection::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). */ PendingStreamTubeConnection *IncomingStreamTubeChannel::acceptTubeAsTcpSocket() { return acceptTubeAsTcpSocket(QHostAddress::Any, 0); } /** * Accept an incoming stream tube as a Unix socket. * * This method accepts an incoming connection request for a stream tube. It can be called * only if the tube is in the #TubeStateLocalPending state. * * An Unix socket (can be used with QLocalSocket or alike) will be opened by the connection manager * as the local tube endpoint. This is only supported if supportsUnixSocketsOnLocalhost() is \c * true. * * You can also specify whether the CM should require an SCM_CREDS or SCM_CREDENTIALS message * upon connection instead of accepting every incoming connection from localhost. This provides * additional security, but requires sending the byte retrieved from * PendingStreamTubeConnection::credentialByte() in-line in the socket byte stream (in a credentials * message if available on the platform), which might not be compatible with all protocols or * libraries. Also, only connection managers for which supportsUnixSocketsWithCredentials() is \c * true support this type of access control. * * This method requires IncomingStreamTubeChannel::FeatureCore to be ready. * * \param requireCredentials Whether the CM should require an SCM_CREDS or SCM_CREDENTIALS message * upon connection. * \return A PendingStreamTubeConnection which will emit PendingStreamTubeConnection::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). * \sa StreamTubeChannel::supportsUnixSocketsOnLocalhost(), * StreamTubeChannel::supportsUnixSocketsWithCredentials(), * StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost(), * StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials() */ PendingStreamTubeConnection *IncomingStreamTubeChannel::acceptTubeAsUnixSocket( bool requireCredentials) { if (!isReady(IncomingStreamTubeChannel::FeatureCore)) { warning() << "IncomingStreamTubeChannel::FeatureCore must be ready before " "calling acceptTubeAsUnixSocket"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingStreamTubeChannelPtr(this)); } // The tube must be in local pending state if (state() != TubeChannelStateLocalPending) { warning() << "You can accept tubes only when they are in LocalPending state"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingStreamTubeChannelPtr(this)); } SocketAccessControl accessControl = requireCredentials ? SocketAccessControlCredentials : SocketAccessControlLocalhost; setAddressType(SocketAddressTypeUnix); setAccessControl(accessControl); // Fail early if the combination is not supported if ((accessControl == SocketAccessControlLocalhost && addressType() == SocketAddressTypeUnix && !supportsUnixSocketsOnLocalhost()) || (accessControl == SocketAccessControlCredentials && addressType() == SocketAddressTypeUnix && !supportsUnixSocketsWithCredentials()) || (accessControl == SocketAccessControlLocalhost && addressType() == SocketAddressTypeAbstractUnix && !supportsAbstractUnixSocketsOnLocalhost()) || (accessControl == SocketAccessControlCredentials && addressType() == SocketAddressTypeAbstractUnix && !supportsAbstractUnixSocketsWithCredentials())) { warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), IncomingStreamTubeChannelPtr(this)); } QDBusVariant accessControlParam; uchar credentialByte = 0; if (accessControl == SocketAccessControlLocalhost) { accessControlParam.setVariant(qVariantFromValue(static_cast(0))); } else if (accessControl == SocketAccessControlCredentials) { if (mPriv->initRandom) { qsrand(QTime::currentTime().msec()); mPriv->initRandom = false; } credentialByte = static_cast(qrand()); accessControlParam.setVariant(qVariantFromValue(credentialByte)); } else { Q_ASSERT(false); } // Perform the actual call PendingVariant *pv = new PendingVariant( interface()->Accept( addressType(), accessControl, accessControlParam), IncomingStreamTubeChannelPtr(this)); PendingStreamTubeConnection *op = new PendingStreamTubeConnection(pv, addressType(), requireCredentials, credentialByte, IncomingStreamTubeChannelPtr(this)); return op; } void IncomingStreamTubeChannel::onNewLocalConnection(uint connectionId) { addConnection(connectionId); } } telepathy-qt-0.9.6~git1/TelepathyQt/abstract-adaptor.h0000664000175000017500000000307412470405660020624 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_abstract_adaptor_h_HEADER_GUARD_ #define _TelepathyQt_abstract_adaptor_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include class QDBusConnection; namespace Tp { class TP_QT_EXPORT AbstractAdaptor : public QDBusAbstractAdaptor { Q_OBJECT public: AbstractAdaptor(const QDBusConnection &connection, QObject *adaptee, QObject *parent); ~AbstractAdaptor(); QDBusConnection dbusConnection() const; QObject *adaptee() const; private: struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/manager-file.h0000664000175000017500000000443512470405660017722 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_manager_file_h_HEADER_GUARD_ #define _TelepathyQt_manager_file_h_HEADER_GUARD_ #include #include #include #include #include #ifndef DOXYGEN_SHOULD_SKIP_THIS namespace Tp { class TP_QT_NO_EXPORT ManagerFile { public: ManagerFile(); ManagerFile(const ManagerFile &other); ManagerFile(const QString &cmName); ~ManagerFile(); ManagerFile &operator=(const ManagerFile &other); QString cmName() const; bool isValid() const; QStringList protocols() const; ParamSpecList parameters(const QString &protocol) const; QString vcardField(const QString &protocol) const; QString englishName(const QString &protocol) const; QString iconName(const QString &protocol) const; RequestableChannelClassList requestableChannelClasses( const QString &protocol) const; PresenceSpecList allowedPresenceStatuses(const QString &protocol) const; AvatarSpec avatarRequirements(const QString &protocol) const; QStringList addressableVCardFields(const QString &protocol) const; QStringList addressableUriSchemes(const QString &protocol) const; private: struct Private; friend struct Private; Private *mPriv; }; } Q_DECLARE_METATYPE(Tp::ManagerFile); #endif /* DOXYGEN_SHOULD_SKIP_THIS */ #endif telepathy-qt-0.9.6~git1/TelepathyQt/captcha.cpp0000664000175000017500000001022212470405660017320 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include namespace Tp { struct TP_QT_NO_EXPORT Captcha::Private : public QSharedData { Private(); Private(const Captcha::Private &other); ~Private(); QString mimeType; QString label; QByteArray captchaData; CaptchaAuthentication::ChallengeType type; uint id; }; Captcha::Private::Private() : type(CaptchaAuthentication::NoChallenge), id(0) { } Captcha::Private::Private(const Private &other) : QSharedData(other), mimeType(other.mimeType), label(other.label), captchaData(other.captchaData), type(other.type), id(other.id) { } Captcha::Private::~Private() { } /** * \class Captcha * \ingroup client * \headerfile TelepathyQt/captcha.h * * \brief The Captcha class represents a Captcha ready to be answered. * * It exposes all the parameters needed for a handler to present the user with a captcha. * * Please note this class is meant to be read-only. It is usually created by PendingCaptchas * once a Captcha request operation succeeds. * * Please note that this class is implicitly shared. */ /** * Default constructor. */ Captcha::Captcha() { } /** * Copy constructor. */ Captcha::Captcha(const Captcha &other) : mPriv(other.mPriv) { } Captcha::Captcha(const QString &mimeType, const QString &label, const QByteArray &data, CaptchaAuthentication::ChallengeType type, uint id) : mPriv(new Captcha::Private) { mPriv->mimeType = mimeType; mPriv->label = label; mPriv->captchaData = data; mPriv->type = type; mPriv->id = id; } /** * Class destructor. */ Captcha::~Captcha() { } Captcha &Captcha::operator=(const Captcha &rhs) { if (this==&rhs) { //Protect against self-assignment return *this; } mPriv = rhs.mPriv; return *this; } /** * Return the mimetype of the captcha. * * \return The captcha's mimetype. * \sa data() */ QString Captcha::mimeType() const { if (!isValid()) { return QString(); } return mPriv->mimeType; } /** * Return the label of the captcha. For some captcha types, such as * CaptchaAuthentication::TextQuestionChallenge, the label is also * the challenge the user has to answer * * \return The captcha's label. * \sa data() * type() */ QString Captcha::label() const { if (!isValid()) { return QString(); } return mPriv->label; } /** * Return the raw data of the captcha. The handler can check its type and * metatype to know how to parse the blob. * * \return The captcha's data. * \sa mimeType(), type() */ QByteArray Captcha::data() const { if (!isValid()) { return QByteArray(); } return mPriv->captchaData; } /** * Return the type of the captcha. * * \return The captcha's type. * \sa data() */ CaptchaAuthentication::ChallengeType Captcha::type() const { if (!isValid()) { return CaptchaAuthentication::NoChallenge; } return mPriv->type; } /** * Return the id of the captcha. This parameter should be used to identify * the captcha when answering its challenge. * * \return The captcha's id. * \sa CaptchaAuthentication::answer() */ uint Captcha::id() const { if (!isValid()) { return 0; } return mPriv->id; } } telepathy-qt-0.9.6~git1/TelepathyQt/DBusObject0000664000175000017500000000035512470405660017126 0ustar jrjr#ifndef _TelepathyQt_DBusObject_HEADER_GUARD_ #define _TelepathyQt_DBusObject_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/CMakeLists.txt0000664000175000017500000011236412470405660017763 0ustar jrjrfile(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_gen") # Set the required flags found in TelepathyDefaults set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_HIDDEN_FLAGS} ${COMPILER_COVERAGE_FLAGS} ${DEPRECATED_DECLARATIONS_FLAGS}") set(LD_FLAGS "${LD_FLAGS} ${VISIBILITY_HIDDEN_FLAGS} ${COMPILER_COVERAGE_FLAGS} ${DEPRECATED_DECLARATIONS_FLAGS}") # We are building Telepathy-Qt add_definitions(-DBUILDING_TP_QT) configure_file(global.h.in ${CMAKE_CURRENT_BINARY_DIR}/global.h) # Sources for Tp-Qt set(telepathy_qt_SRCS abstract-client.cpp abstract-interface.cpp account.cpp account-factory.cpp account-manager.cpp account-property-filter.cpp account-set.cpp account-set-internal.h avatar.cpp call-channel.cpp call-content.cpp call-stream.cpp capabilities-base.cpp call-content.cpp call-content-media-description.cpp call-stream.cpp call-stream-endpoint.cpp captcha.cpp captcha-authentication.cpp channel.cpp channel-class-spec.cpp channel-dispatcher.cpp channel-dispatch-operation.cpp channel-factory.cpp channel-internal.h channel-request.cpp client.cpp client-registrar.cpp client-registrar-internal.h connection.cpp connection-capabilities.cpp connection-factory.cpp connection-internal.h connection-manager.cpp connection-manager-internal.h contact.cpp contact-capabilities.cpp contact-factory.cpp contact-manager.cpp contact-manager-roster.cpp contact-messenger.cpp contact-search-channel.cpp dbus.cpp dbus-proxy.cpp dbus-proxy-factory.cpp dbus-proxy-factory-internal.h dbus-tube-channel.cpp debug.cpp debug-receiver.cpp debug-internal.h fake-handler-manager-internal.cpp fake-handler-manager-internal.h feature.cpp file-transfer-channel.cpp file-transfer-channel-creation-properties.cpp fixed-feature-factory.cpp future.cpp future-internal.h handled-channel-notifier.cpp incoming-dbus-tube-channel.cpp incoming-file-transfer-channel.cpp incoming-stream-tube-channel.cpp key-file.cpp key-file.h location-info.cpp manager-file.cpp manager-file.h media-session-handler.cpp media-stream-handler.cpp message.cpp message-content-part.cpp object.cpp optional-interface-factory.cpp outgoing-dbus-tube-channel.cpp outgoing-file-transfer-channel.cpp outgoing-stream-tube-channel.cpp pending-account.cpp pending-captchas.cpp pending-channel.cpp pending-channel-request.cpp pending-channel-request-internal.h pending-connection.cpp pending-contact-attributes.cpp pending-contact-info.cpp pending-contacts.cpp pending-dbus-tube-connection.cpp pending-debug-message-list.cpp pending-handles.cpp pending-operation.cpp pending-ready.cpp pending-send-message.cpp pending-string.cpp pending-string-list.cpp pending-stream-tube-connection.cpp pending-variant.cpp presence.cpp pending-variant-map.cpp profile.cpp profile-manager.cpp properties.cpp protocol-info.cpp protocol-parameter.cpp readiness-helper.cpp requestable-channel-class-spec.cpp ready-object.cpp referenced-handles.cpp request-temporary-handler-internal.cpp request-temporary-handler-internal.h room-list-channel.cpp server-authentication-channel.cpp simple-call-observer.cpp simple-observer.cpp simple-observer-internal.h simple-stream-tube-handler.cpp simple-text-observer.cpp simple-text-observer-internal.h stream-tube-channel.cpp stream-tube-client.cpp stream-tube-client-internal.h stream-tube-server.cpp stream-tube-server-internal.h streamed-media-channel.cpp text-channel.cpp tls-certificate.cpp tube-channel.cpp types.cpp types-internal.h utils.cpp) # Exported headers for Tp-Qt set(telepathy_qt_HEADERS AbstractClient AbstractClientApprover abstract-client.h AbstractClientHandler AbstractClientObserver AbstractInterface abstract-interface.h Account account.h AccountCapabilityFilter account-capability-filter.h AccountFactory account-factory.h AccountFilter account-filter.h AccountInterface AccountInterfaceAddressingInterface AccountInterfaceAvatarInterface AccountInterfaceStorageInterface AccountManager account-manager.h AccountManagerInterface account-property-filter.h AccountPropertyFilter AccountSet account-set.h AndFilter and-filter.h AuthenticationTLSCertificateInterface AvatarData AvatarSpec avatar.h CallChannel call-channel.h Callbacks callbacks.h CallContent CallContentInterface CallContentInterfaceAudioControlInterface CallContentInterfaceDTMFInterface CallContentInterfaceMediaInterface CallContentInterfaceVideoControlInterface call-content.h CallContentMediaDescription CallContentMediaDescriptionInterface CallContentMediaDescriptionInterfaceRTCPExtendedReportsInterface CallContentMediaDescriptionInterfaceRTCPFeedbackInterface CallContentMediaDescriptionInterfaceRTPHeaderExtensionsInterface call-content-media-description.h CallStream CallStreamInterface CallStreamInterfaceMediaInterface call-stream.h CallStreamEndpoint CallStreamEndpoint CallStreamEndpointInterface call-stream-endpoint.h CapabilitiesBase capabilities-base.h Captcha captcha.h CaptchaAuthentication captcha-authentication.h Channel channel.h ChannelClassFeatures channel-class-features.h ChannelClassSpec ChannelClassSpecList channel-class-spec.h ChannelDispatcher ChannelDispatcherInterface channel-dispatcher.h ChannelDispatchOperation channel-dispatch-operation.h ChannelDispatchOperationInterface ChannelFactory channel-factory.h ChannelInterface ChannelInterfaceAnonymityInterface ChannelInterfaceCaptchaAuthenticationInterface ChannelInterfaceCallStateInterface ChannelInterfaceChatStateInterface ChannelInterfaceConferenceInterface ChannelInterfaceDestroyableInterface ChannelInterfaceDTMFInterface ChannelInterfaceFileTransferMetadataInterface ChannelInterfaceGroupInterface ChannelInterfaceHoldInterface ChannelInterfaceMediaSignallingInterface ChannelInterfaceMessagesInterface ChannelInterfacePasswordInterface ChannelInterfaceRoomInterface ChannelInterfaceRoomConfigInterface ChannelInterfaceSASLAuthenticationInterface ChannelInterfaceSecurableInterface ChannelInterfaceServicePointInterface ChannelInterfaceSMSInterface ChannelInterfaceSubjectInterface ChannelInterfaceTubeInterface ChannelRequest ChannelRequestHints channel-request.h ChannelRequestInterface ChannelTypeCallInterface ChannelTypeContactListInterface ChannelTypeContactSearchInterface ChannelTypeDBusTubeInterface ChannelTypeFileTransferInterface ChannelTypeRoomListInterface ChannelTypeServerAuthenticationInterface ChannelTypeServerTLSConnectionInterface ChannelTypeStreamedMediaInterface ChannelTypeStreamTubeInterface ChannelTypeTextInterface ChannelTypeTubeInterface ChannelTypeTubesInterface Client ClientApproverInterface client.h ClientHandlerInterface ClientInterface ClientInterfaceRequestsInterface ClientObserverInterface ClientRegistrar client-registrar.h Connection ConnectionCapabilities connection-capabilities.h connection.h ConnectionFactory connection-factory.h connection-lowlevel.h ConnectionInterface ConnectionInterfaceAddressingInterface ConnectionInterfaceAliasingInterface ConnectionInterfaceAnonymityInterface ConnectionInterfaceAvatarsInterface ConnectionInterfaceBalanceInterface ConnectionInterfaceCapabilitiesInterface ConnectionInterfaceCellularInterface ConnectionInterfaceContactBlockingInterface ConnectionInterfaceClientTypesInterface ConnectionInterfaceContactCapabilitiesInterface ConnectionInterfaceContactGroupsInterface ConnectionInterfaceContactInfoInterface ConnectionInterfaceContactListInterface ConnectionInterfaceContactsInterface ConnectionInterfaceLocationInterface ConnectionInterfaceMailNotificationInterface ConnectionInterfacePowerSavingInterface ConnectionInterfacePresenceInterface ConnectionInterfaceRequestsInterface ConnectionInterfaceServicePointInterface ConnectionInterfaceSimplePresenceInterface ConnectionLowlevel ConnectionManager connection-manager.h connection-manager-lowlevel.h ConnectionManagerInterface ConnectionManagerLowlevel Constants constants.h Contact contact.h ContactCapabilities contact-capabilities.h ContactFactory contact-factory.h ContactManager contact-manager.h ContactMessenger contact-messenger.h ContactSearchChannel contact-search-channel.h DBus DBusDaemonInterface dbus.h DBusProxy dbus-proxy.h DBusProxyFactory dbus-proxy-factory.h DBusTubeChannel dbus-tube-channel.h Debug debug.h DebugReceiver debug-receiver.h Feature Features feature.h FileTransferChannel FileTransferChannelCreationProperties file-transfer-channel-creation-properties.h file-transfer-channel.h Filter filter.h FixedFeatureFactory fixed-feature-factory.h Functors functors.h GenericCapabilityFilter generic-capability-filter.h GenericPropertyFilter generic-property-filter.h Global ${CMAKE_CURRENT_BINARY_DIR}/global.h HandledChannelNotifier handled-channel-notifier.h IncomingDBusTubeChannel incoming-dbus-tube-channel.h IncomingFileTransferChannel incoming-file-transfer-channel.h IncomingStreamTubeChannel incoming-stream-tube-channel.h IntrospectableInterface LocationInfo location-info.h MediaSessionHandler media-session-handler.h MediaSessionHandlerInterface MediaStreamHandler media-stream-handler.h MediaStreamHandlerInterface Message message.h MessageContentPart MessageContentPartList message-content-part.h MethodInvocationContext method-invocation-context.h NotFilter not-filter.h Object object.h OptionalInterfaceFactory optional-interface-factory.h OrFilter or-filter.h OutgoingDBusTubeChannel outgoing-dbus-tube-channel.h OutgoingFileTransferChannel outgoing-file-transfer-channel.h OutgoingStreamTubeChannel outgoing-stream-tube-channel.h PeerInterface PendingAccount pending-account.h PendingCallContent PendingCaptchas pending-captchas.h PendingChannel pending-channel.h PendingChannelRequest pending-channel-request.h PendingComposite PendingConnection pending-connection.h PendingContactAttributes pending-contact-attributes.h PendingContactInfo pending-contact-info.h PendingContacts pending-contacts.h PendingDBusTubeConnection pending-dbus-tube-connection.h PendingDebugMessageList pending-debug-message-list.h PendingFailure PendingHandles pending-handles.h PendingOperation pending-operation.h PendingReady pending-ready.h PendingSendMessage pending-send-message.h PendingStreamedMediaStreams PendingStreamTubeConnection pending-stream-tube-connection.h PendingString pending-string.h PendingStringList pending-string-list.h PendingSuccess PendingVariant pending-variant.h PendingVariantMap pending-variant-map.h PendingVoid Presence presence.h PresenceSpec PresenceSpecList Profile profile.h ProfileManager profile-manager.h Properties properties.h PropertiesInterface PropertiesInterfaceInterface ProtocolInfo ProtocolInfoList protocol-info.h ProtocolInterface ProtocolInterfaceAddressingInterface ProtocolInterfaceAvatarsInterface ProtocolInterfacePresenceInterface ProtocolParameter ProtocolParameterList protocol-parameter.h ReadinessHelper readiness-helper.h ReadyObject ready-object.h ReceivedMessage RefCounted ReferencedHandles referenced-handles.h ReferencedHandlesIterator requestable-channel-class-spec.h RequestableChannelClassSpec RequestableChannelClassSpecList RoomListChannel room-list-channel.h ServerAuthenticationChannel server-authentication-channel.h SharedPtr shared-ptr.h SimpleCallObserver simple-call-observer.h SimpleObserver simple-observer.h simple-pending-operations.h SimpleTextObserver simple-text-observer.h StatefulDBusProxy StatelessDBusProxy StreamTubeChannel StreamTubeClient StreamTubeServer stream-tube-channel.h stream-tube-client.h stream-tube-server.h StreamedMediaChannel streamed-media-channel.h StreamedMediaStream TextChannel text-channel.h tls-certificate.h TubeChannel tube-channel.h Types types.h Utils utils.h SharedPtr) # Generated headers which will be installed and exported set(telepathy_qt_gen_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-account.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-account-manager.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-call-content.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-call-content-media-description.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-call-stream.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-call-stream-endpoint.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-channel.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-channel-dispatcher.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-channel-dispatch-operation.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-channel-request.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-client.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-connection-manager.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-dbus.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-debug-receiver.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-media-session-handler.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-media-stream-handler.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-properties.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-tls-certificate.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/constants.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/types.h) # Headers file moc will be run on set(telepathy_qt_MOC_SRCS abstract-interface.h account.h account-factory.h account-manager.h account-set.h account-set-internal.h call-channel.h call-content.h call-stream.h captcha-authentication.h captcha-authentication-internal.h channel.h channel-dispatch-operation.h channel-dispatch-operation-internal.h channel-factory.h channel-internal.h channel-request.h client-registrar.h client-registrar-internal.h connection.h connection-internal.h connection-lowlevel.h connection-manager.h connection-manager-internal.h connection-manager-lowlevel.h contact.h contact-manager.h contact-manager-internal.h contact-messenger.h contact-search-channel.h contact-search-channel-internal.h dbus-proxy.h dbus-proxy-factory.h dbus-proxy-factory-internal.h debug-receiver.h dbus-tube-channel.h fake-handler-manager-internal.h file-transfer-channel.h fixed-feature-factory.h handled-channel-notifier.h incoming-dbus-tube-channel.h incoming-file-transfer-channel.h incoming-stream-tube-channel.h object.h outgoing-dbus-tube-channel.h outgoing-file-transfer-channel.h outgoing-stream-tube-channel.h outgoing-stream-tube-channel-internal.h pending-account.h pending-captchas.h pending-channel.h pending-channel-request.h pending-channel-request-internal.h pending-connection.h pending-contact-attributes.h pending-contact-info.h pending-contacts.h pending-contacts-internal.h pending-dbus-tube-connection.h pending-debug-message-list.h pending-handles.h pending-operation.h pending-ready.h pending-send-message.h pending-stream-tube-connection.h pending-string.h pending-string-list.h pending-variant.h pending-variant-map.h profile-manager.h readiness-helper.h request-temporary-handler-internal.h room-list-channel.h server-authentication-channel.h simple-call-observer.h simple-pending-operations.h simple-observer.h simple-observer-internal.h simple-stream-tube-handler.h simple-text-observer.h simple-text-observer-internal.h stream-tube-channel.h stream-tube-client.h stream-tube-client-internal.h stream-tube-server.h stream-tube-server-internal.h streamed-media-channel.h text-channel.h tube-channel.h) # Sources for test library, used by tests to test some unexported functionality set(telepathy_qt_test_backdoors_SRCS key-file.cpp manager-file.cpp test-backdoors.cpp utils.cpp) # Generate the spec files for both stable and future spec set(gen_stable_spec_xml ${CMAKE_CURRENT_BINARY_DIR}/_gen/stable-spec.xml) set(gen_future_spec_xml ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-spec.xml) tpqt_xincludator(stable-ifaces-includator ${CMAKE_CURRENT_SOURCE_DIR}/stable-interfaces.xml ${gen_stable_spec_xml}) tpqt_xincludator(future-ifaces-includator ${CMAKE_CURRENT_SOURCE_DIR}/future-interfaces.xml ${gen_future_spec_xml}) add_custom_target(all-generated-sources) tpqt_constants_gen(stable-constants ${gen_stable_spec_xml} ${CMAKE_CURRENT_BINARY_DIR}/_gen/constants.h --namespace=Tp --define-prefix=TP_QT_ --must-define=IN_TP_QT_HEADER DEPENDS stable-ifaces-includator) tpqt_constants_gen(future-constants ${gen_future_spec_xml} ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-constants.h --namespace=TpFuture --define-prefix=TP_QT_FUTURE_ DEPENDS future-ifaces-includator) tpqt_types_gen(stable-typesgen ${gen_stable_spec_xml} ${CMAKE_CURRENT_BINARY_DIR}/_gen/types.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/types-body.hpp Tp TelepathyQt/types.h TelepathyQt/Types --must-define=IN_TP_QT_HEADER --visibility=TP_QT_EXPORT DEPENDS stable-constants) tpqt_types_gen(future-typesgen ${gen_future_spec_xml} ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-types.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-types-body.hpp TpFuture TelepathyQt/future-internal.h TelepathyQt/future-internal.h DEPENDS future-constants) # Add the generated types to the library's sources list(APPEND telepathy_qt_SRCS ${CMAKE_CURRENT_BINARY_DIR}/_gen/types.h) list(APPEND telepathy_qt_SRCS ${CMAKE_CURRENT_BINARY_DIR}/_gen/types-body.hpp) list(APPEND telepathy_qt_SRCS ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-constants.h) list(APPEND telepathy_qt_SRCS ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-types.h) list(APPEND telepathy_qt_SRCS ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-types-body.hpp) # For each spec, both stable and future, generate a cli file and add it to the sources (including mocs). set(SPECS account account-manager call-content call-content-media-description call-stream call-stream-endpoint channel channel-dispatcher channel-dispatch-operation channel-request client connection connection-manager dbus debug-receiver media-session-handler media-stream-handler properties tls-certificate) foreach(spec ${SPECS}) tpqt_xincludator(${spec}-spec-xincludator ${CMAKE_CURRENT_SOURCE_DIR}/${spec}.xml ${CMAKE_CURRENT_BINARY_DIR}/_gen/spec-${spec}.xml DEPENDS stable-typesgen) set(NEW_FILES ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-${spec}-body.hpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/cli-${spec}.moc.hpp) list(APPEND telepathy_qt_SRCS ${NEW_FILES}) list(APPEND telepathy_qt_generated_specs_mocs "moc-cli-${spec}.moc.hpp") set_source_files_properties(${NEW_FILES} PROPERTIES GENERATED true) endforeach(spec ${SPECS}) set(FUTURE_SPECS channel channel-dispatcher misc) foreach(spec ${FUTURE_SPECS}) tpqt_xincludator(${spec}-future-xincludator ${CMAKE_CURRENT_SOURCE_DIR}/future-${spec}.xml ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}.xml DEPENDS stable-typesgen future-typesgen) set(NEW_FILES ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}-body.hpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/future-${spec}.moc.hpp) list(APPEND telepathy_qt_SRCS ${NEW_FILES}) list(APPEND telepathy_qt_generated_specs_mocs "moc-future-${spec}.moc.hpp") set_source_files_properties(${NEW_FILES} PROPERTIES GENERATED true) endforeach(spec ${FUTURE_SPECS}) # The escape character in MSVC is ^ if(MSVC) set(TYPES_INCLUDE ^ ) else(MSVC) set(TYPES_INCLUDE '' ) endif(MSVC) # Use the client generator for generating headers out of specs tpqt_client_generator(account clientaccount AccountManager Tp::Client --mainiface=Tp::Client::AccountInterface DEPENDS account-spec-xincludator) tpqt_client_generator(account-manager clientam AccountManager Tp::Client --mainiface=Tp::Client::AccountManagerInterface DEPENDS account-manager-spec-xincludator) tpqt_client_generator(call-content clientcall CallContent Tp::Client --mainiface=Tp::Client::CallContentInterface DEPENDS call-content-spec-xincludator) tpqt_client_generator(call-content-media-description clientcall CallContentMediaDescriptionInterface Tp::Client --mainiface=Tp::Client::CallContentMediaDescriptionInterface DEPENDS call-content-media-description-spec-xincludator) tpqt_client_generator(call-stream clientcall CallStream Tp::Client --mainiface=Tp::Client::CallStreamInterface DEPENDS call-stream-spec-xincludator) tpqt_client_generator(call-stream-endpoint clientcall CallStreamEndpoint Tp::Client --mainiface=Tp::Client::CallStreamEndpointInterface DEPENDS call-stream-endpoint-spec-xincludator) tpqt_client_generator(channel clientchannel Channel Tp::Client --mainiface=Tp::Client::ChannelInterface DEPENDS channel-spec-xincludator) tpqt_client_generator(channel-dispatcher clientchanneldispatcher ChannelDispatcher Tp::Client --mainiface=Tp::Client::ChannelDispatcherInterface DEPENDS channel-dispatcher-spec-xincludator) tpqt_client_generator(channel-dispatch-operation clientchanneldispatchoperation ChannelDispatchOperation Tp::Client --mainiface=Tp::Client::ChannelDispatchOperationInterface DEPENDS channel-dispatch-operation-spec-xincludator) tpqt_client_generator(channel-request clientchannelrequest ChannelRequest Tp::Client --mainiface=Tp::Client::ChannelRequestInterface DEPENDS channel-request-spec-xincludator) tpqt_client_generator(client clientclient Client Tp::Client --mainiface=Tp::Client::ClientInterface DEPENDS client-spec-xincludator) tpqt_client_generator(connection clientconn Connection Tp::Client --mainiface=Tp::Client::ConnectionInterface DEPENDS connection-spec-xincludator) tpqt_client_generator(connection-manager clientcm ConnectionManager Tp::Client --mainiface=Tp::Client::ConnectionManagerInterface DEPENDS connection-manager-spec-xincludator) tpqt_client_generator(dbus clientdbus DBus Tp::Client::DBus DEPENDS dbus-spec-xincludator) tpqt_client_generator(debug-receiver clientdebug DebugReceiver Tp::Client --mainiface=Tp::Client::DebugInterface DEPENDS debug-receiver-spec-xincludator) tpqt_client_generator(media-session-handler clientmsesh MediaSessionHandler Tp::Client --mainiface=Tp::Client::MediaSessionHandlerInterface DEPENDS media-session-handler-spec-xincludator) tpqt_client_generator(media-stream-handler clientmstrh MediaStreamHandler Tp::Client --mainiface=Tp::Client::MediaStreamHandlerInterface DEPENDS media-stream-handler-spec-xincludator) tpqt_client_generator(properties clientprops Properties Tp::Client DEPENDS properties-spec-xincludator) tpqt_client_generator(tls-certificate clienttls TLSCertificate Tp::Client DEPENDS tls-certificate-spec-xincludator) tpqt_future_client_generator(channel TpFuture::Client --mainiface=Tp::Client::ChannelInterface DEPENDS channel-future-xincludator) tpqt_future_client_generator(channel-dispatcher TpFuture::Client --mainiface=Tp::Client::ChannelDispatcherInterface DEPENDS channel-dispatcher-future-xincludator) tpqt_future_client_generator(misc TpFuture::Client DEPENDS misc-future-xincludator) if (TARGET doxygen-doc) add_dependencies(doxygen-doc all-generated-sources) endif (TARGET doxygen-doc) # Create the library if (ENABLE_COMPILER_COVERAGE) add_library(telepathy-qt${QT_VERSION_MAJOR} STATIC ${telepathy_qt_SRCS}) else (ENABLE_COMPILER_COVERAGE) add_library(telepathy-qt${QT_VERSION_MAJOR} SHARED ${telepathy_qt_SRCS}) endif (ENABLE_COMPILER_COVERAGE) # Library used by tests to test some unexported functionality add_library(telepathy-qt-test-backdoors STATIC ${telepathy_qt_test_backdoors_SRCS}) add_dependencies(telepathy-qt-test-backdoors stable-constants) add_dependencies(telepathy-qt-test-backdoors stable-typesgen) # generate client moc files foreach(moc_src ${telepathy_qt_MOC_SRCS}) set(generated_file _gen/${moc_src}) string(REPLACE ".h" ".moc.hpp" generated_file ${generated_file}) tpqt_generate_moc_i_target_deps(${CMAKE_CURRENT_SOURCE_DIR}/${moc_src} ${CMAKE_CURRENT_BINARY_DIR}/${generated_file} ${telepathy_qt_generated_specs_mocs}) list(APPEND telepathy_qt_SRCS ${CMAKE_CURRENT_BINARY_DIR}/${generated_file}) string(REPLACE ".h" ".moc.hpp" moc_src ${moc_src}) add_dependencies(telepathy-qt${QT_VERSION_MAJOR} "moc-${moc_src}") endforeach(moc_src ${telepathy_qt_MOC_SRCS}) # Link target_link_libraries(telepathy-qt${QT_VERSION_MAJOR} ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} ${TP_QT_LIBRARY_LINKER_FLAGS}) target_include_directories(telepathy-qt${QT_VERSION_MAJOR} PUBLIC "$") # Link - Library used by tests to test some unexported functionality target_link_libraries(telepathy-qt-test-backdoors ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTXML_LIBRARY} ${TP_QT_LIBRARY_LINKER_FLAGS}) if (ENABLE_COMPILER_COVERAGE) target_link_libraries(telepathy-qt${QT_VERSION_MAJOR} gcov) target_link_libraries(telepathy-qt-test-backdoors gcov) endif (ENABLE_COMPILER_COVERAGE) # Set the correct version number set_target_properties(telepathy-qt${QT_VERSION_MAJOR} PROPERTIES SOVERSION ${TP_QT_ABI_VERSION} VERSION ${TP_QT_LIBRARY_VERSION}) # Install header files install(FILES ${telepathy_qt_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/telepathy-qt${QT_VERSION_MAJOR}/TelepathyQt COMPONENT headers) install(FILES ${telepathy_qt_gen_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/telepathy-qt${QT_VERSION_MAJOR}/TelepathyQt/_gen COMPONENT headers) # Install the library - watch out for the correct components if (WIN32) install(TARGETS telepathy-qt${QT_VERSION_MAJOR} EXPORT TelepathyQt${QT_VERSION_MAJOR}Targets RUNTIME DESTINATION ${LIB_INSTALL_DIR} COMPONENT mainlibrary ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libs) else (WIN32) install(TARGETS telepathy-qt${QT_VERSION_MAJOR} EXPORT TelepathyQt${QT_VERSION_MAJOR}Targets LIBRARY DESTINATION ${LIB_INSTALL_DIR} COMPONENT mainlibrary ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libs) endif (WIN32) # pkg-config files, only if we are not using windows if (NOT WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TelepathyQt.pc.in ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}.pc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TelepathyQt-uninstalled.pc.in ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}-uninstalled.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig COMPONENT pkgconfig) endif (NOT WIN32) # CMake Version and config files include(MacroWriteBasicCMakeVersionFile) # all the following variables are put into TelepathyQt*Config.cmake, so # they are usable by projects using TelepathyQt. make_install_path_absolute(TELEPATHY_QT_INCLUDE_DIR ${INCLUDE_INSTALL_DIR}/telepathy-qt${QT_VERSION_MAJOR}) make_install_path_absolute(TELEPATHY_QT_LIB_DIR ${LIB_INSTALL_DIR}) make_install_path_absolute(TELEPATHY_QT_DATA_DIR ${DATA_INSTALL_DIR}) # Configure the actual Config file configure_file(TelepathyQtConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}Config.cmake" @ONLY) # this file is used by to check if the installed version can be used. macro_write_basic_cmake_version_file(${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}ConfigVersion.cmake ${PACKAGE_VERSION}) # Find out the correct installation directory if (USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) set(_TelepathyQtConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/TelepathyQt${QT_VERSION_MAJOR}) else (USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) set(_TelepathyQtConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/TelepathyQt${QT_VERSION_MAJOR}/cmake) endif (USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) install(EXPORT TelepathyQt${QT_VERSION_MAJOR}Targets DESTINATION ${_TelepathyQtConfig_INSTALL_DIR} COMPONENT headers) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}ConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}Config.cmake DESTINATION ${_TelepathyQtConfig_INSTALL_DIR} COMPONENT headers) add_subdirectory(Farstream) if(ENABLE_SERVICE_SUPPORT) # lets build tp-qt service side support as a separate library until we can guarantee API/ABI # stability set(telepathy_qt_service_SRCS base-call.cpp base-connection-manager.cpp base-connection.cpp base-channel.cpp base-protocol.cpp dbus-error.cpp dbus-object.cpp dbus-service.cpp abstract-adaptor.cpp) set(telepathy_qt_service_HEADERS AbstractAdaptor abstract-adaptor.h AbstractDBusServiceInterface AbstractProtocolInterface BaseCall base-call.h BaseConnectionManager base-connection-manager.h BaseConnection base-connection.h BaseChannel base-channel.h BaseProtocol BaseProtocolAddressingInterface BaseProtocolAvatarsInterface BaseProtocolPresenceInterface base-protocol.h DBusError dbus-error.h DBusObject dbus-object.h DBusService dbus-service.h ServiceTypes service-types.h) # Generated headers which will be installed and exported set(telepathy_qt_service_gen_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-channel.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-call.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-connection.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/svc-connection-manager.h) # Headers file moc will be run on set(telepathy_qt_service_MOC_SRCS abstract-adaptor.h base-call.h base-call-internal.h base-connection-manager.h base-connection-manager-internal.h base-channel.h base-channel-internal.h base-connection.h base-connection-internal.h base-protocol.h base-protocol-internal.h dbus-object.h dbus-service.h) add_custom_target(all-generated-service-sources) set(SPECS svc-channel svc-call svc-connection svc-connection-manager) foreach(spec ${SPECS}) tpqt_xincludator(${spec}-spec-xincludator ${CMAKE_CURRENT_SOURCE_DIR}/${spec}.xml ${CMAKE_CURRENT_BINARY_DIR}/_gen/spec-${spec}.xml DEPENDS stable-typesgen) set(NEW_FILES ${CMAKE_CURRENT_BINARY_DIR}/_gen/${spec}.h ${CMAKE_CURRENT_BINARY_DIR}/_gen/${spec}.cpp ${CMAKE_CURRENT_BINARY_DIR}/_gen/${spec}.moc.hpp) list(APPEND telepathy_qt_service_SRCS ${NEW_FILES}) list(APPEND telepathy_qt_service_generated_specs_mocs "moc-${spec}.moc.hpp") set_source_files_properties(${NEW_FILES} PROPERTIES GENERATED true) endforeach(spec ${SPECS}) tpqt_service_generator(svc-channel servicechannel Channel Tp::Service DEPENDS svc-channel-spec-xincludator) tpqt_service_generator(svc-call servicecall Channel Tp::Service DEPENDS svc-call-spec-xincludator) tpqt_service_generator(svc-connection serviceconn Connection Tp::Service DEPENDS svc-connection-spec-xincludator) tpqt_service_generator(svc-connection-manager servicecm ConnectionManager Tp::Service DEPENDS svc-connection-manager-spec-xincludator) if (TARGET doxygen-doc) add_dependencies(doxygen-doc all-generated-service-sources) endif (TARGET doxygen-doc) # Create the library #if (ENABLE_COMPILER_COVERAGE) # add_library(telepathy-qt${QT_VERSION_MAJOR}-service STATIC ${telepathy_qt_service_SRCS}) #else (ENABLE_COMPILER_COVERAGE) # add_library(telepathy-qt${QT_VERSION_MAJOR}-service SHARED ${telepathy_qt_service_SRCS}) #endif (ENABLE_COMPILER_COVERAGE) # lets build a static only library until we have a stable API/ABI add_library(telepathy-qt${QT_VERSION_MAJOR}-service STATIC ${telepathy_qt_service_SRCS}) # generate service moc files foreach(moc_src ${telepathy_qt_service_MOC_SRCS}) set(generated_file _gen/${moc_src}) string(REPLACE ".h" ".moc.hpp" generated_file ${generated_file}) tpqt_generate_moc_i_target_deps(${CMAKE_CURRENT_SOURCE_DIR}/${moc_src} ${CMAKE_CURRENT_BINARY_DIR}/${generated_file} ${telepathy_qt_service_generated_specs_mocs}) list(APPEND telepathy_qt_service_SRCS ${CMAKE_CURRENT_BINARY_DIR}/${generated_file}) string(REPLACE ".h" ".moc.hpp" moc_src ${moc_src}) add_dependencies(telepathy-qt${QT_VERSION_MAJOR}-service "moc-${moc_src}") endforeach(moc_src ${telepathy_qt_service_MOC_SRCS}) # Link target_link_libraries(telepathy-qt${QT_VERSION_MAJOR}-service ${QT_QTDBUS_LIBRARY} ${QT_QTCORE_LIBRARY} ${TP_QT_LIBRARY_LINKER_FLAGS}) # Set the correct version number set_target_properties(telepathy-qt${QT_VERSION_MAJOR}-service PROPERTIES SOVERSION ${TP_QT_ABI_VERSION} VERSION ${TP_QT_LIBRARY_VERSION}) # Install the library - watch out for the correct components if (WIN32) install(TARGETS telepathy-qt${QT_VERSION_MAJOR}-service EXPORT TelepathyQt${QT_VERSION_MAJOR}Targets RUNTIME DESTINATION ${LIB_INSTALL_DIR} COMPONENT service ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT service_libs) else (WIN32) install(TARGETS telepathy-qt${QT_VERSION_MAJOR}-service EXPORT TelepathyQt${QT_VERSION_MAJOR}Targets LIBRARY DESTINATION ${LIB_INSTALL_DIR} COMPONENT service ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT service_libs) endif (WIN32) # Install headers install(FILES ${telepathy_qt_service_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/telepathy-qt${QT_VERSION_MAJOR}/TelepathyQt COMPONENT service_headers) install(FILES ${telepathy_qt_service_gen_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/telepathy-qt${QT_VERSION_MAJOR}/TelepathyQt/_gen COMPONENT service_headers) # pkg-config files, only if not on windows if (NOT WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TelepathyQtService.pc.in ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}Service.pc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TelepathyQtService-uninstalled.pc.in ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}Service-uninstalled.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}Service.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig COMPONENT pkgconfig) endif (NOT WIN32) # Configure the actual Config file configure_file(TelepathyQtServiceConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}ServiceConfig.cmake" @ONLY) # this file is used by to check if the installed version can be used. macro_write_basic_cmake_version_file(${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}ServiceConfigVersion.cmake ${PACKAGE_VERSION}) if(USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) set(_TelepathyQtServiceConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/TelepathyQt${QT_VERSION_MAJOR}Service) else(USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) set(_TelepathyQtServiceConfig_INSTALL_DIR ${LIB_INSTALL_DIR}/TelepathyQt${QT_VERSION_MAJOR}Service/cmake) endif(USE_COMMON_CMAKE_PACKAGE_CONFIG_DIR) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}ServiceConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/TelepathyQt${QT_VERSION_MAJOR}ServiceConfig.cmake DESTINATION ${_TelepathyQtServiceConfig_INSTALL_DIR} COMPONENT headers) endif(ENABLE_SERVICE_SUPPORT) telepathy-qt-0.9.6~git1/TelepathyQt/avatar.cpp0000664000175000017500000000733712470405660017210 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include namespace Tp { /** * \class AvatarData * \ingroup wrappers * \headerfile TelepathyQt/avatar.h * * \brief The AvatarData class represents a Telepathy avatar. */ struct TP_QT_NO_EXPORT AvatarSpec::Private : public QSharedData { Private(const QStringList &supportedMimeTypes, uint minHeight, uint maxHeight, uint recommendedHeight, uint minWidth, uint maxWidth, uint recommendedWidth, uint maxBytes) : supportedMimeTypes(supportedMimeTypes), minHeight(minHeight), maxHeight(maxHeight), recommendedHeight(recommendedHeight), minWidth(minWidth), maxWidth(maxWidth), recommendedWidth(recommendedWidth), maxBytes(maxBytes) { } QStringList supportedMimeTypes; uint minHeight; uint maxHeight; uint recommendedHeight; uint minWidth; uint maxWidth; uint recommendedWidth; uint maxBytes; }; /** * \class AvatarSpec * \ingroup wrappers * \headerfile TelepathyQt/avatar.h * * \brief The AvatarSpec class represents a Telepathy avatar information * supported by a protocol. */ AvatarSpec::AvatarSpec() { } AvatarSpec::AvatarSpec(const QStringList &supportedMimeTypes, uint minHeight, uint maxHeight, uint recommendedHeight, uint minWidth, uint maxWidth, uint recommendedWidth, uint maxBytes) : mPriv(new Private(supportedMimeTypes, minHeight, maxHeight, recommendedHeight, minWidth, maxWidth, recommendedWidth, maxBytes)) { } AvatarSpec::AvatarSpec(const AvatarSpec &other) : mPriv(other.mPriv) { } AvatarSpec::~AvatarSpec() { } AvatarSpec &AvatarSpec::operator=(const AvatarSpec &other) { this->mPriv = other.mPriv; return *this; } QStringList AvatarSpec::supportedMimeTypes() const { if (!isValid()) { return QStringList(); } return mPriv->supportedMimeTypes; } uint AvatarSpec::minimumHeight() const { if (!isValid()) { return 0; } return mPriv->minHeight; } uint AvatarSpec::maximumHeight() const { if (!isValid()) { return 0; } return mPriv->maxHeight; } uint AvatarSpec::recommendedHeight() const { if (!isValid()) { return 0; } return mPriv->recommendedHeight; } uint AvatarSpec::minimumWidth() const { if (!isValid()) { return 0; } return mPriv->minWidth; } uint AvatarSpec::maximumWidth() const { if (!isValid()) { return 0; } return mPriv->maxWidth; } uint AvatarSpec::recommendedWidth() const { if (!isValid()) { return 0; } return mPriv->recommendedWidth; } uint AvatarSpec::maximumBytes() const { if (!isValid()) { return 0; } return mPriv->maxBytes; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/channel-dispatch-operation-internal.h0000664000175000017500000000317212470405660024405 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_channel_dispatch_operation_internal_h_HEADER_GUARD_ #define _TelepathyQt_channel_dispatch_operation_internal_h_HEADER_GUARD_ #include #include namespace Tp { class TP_QT_NO_EXPORT ChannelDispatchOperation::PendingClaim : public PendingOperation { Q_OBJECT public: PendingClaim(const ChannelDispatchOperationPtr &op, const AbstractClientHandlerPtr &handler = AbstractClientHandlerPtr()); ~PendingClaim(); private Q_SLOTS: TP_QT_NO_EXPORT void onClaimFinished(Tp::PendingOperation *op); private: ChannelDispatchOperationPtr mDispatchOp; AbstractClientHandlerPtr mHandler; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/account-property-filter.h0000664000175000017500000000314712470405660022173 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_account_property_filter_h_HEADER_GUARD_ #define _TelepathyQt_account_property_filter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class TP_QT_EXPORT AccountPropertyFilter : public GenericPropertyFilter { public: static AccountPropertyFilterPtr create() { return AccountPropertyFilterPtr(new AccountPropertyFilter); } ~AccountPropertyFilter(); bool isValid() const; private: AccountPropertyFilter(); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/future.cpp0000664000175000017500000000243312470405660017234 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/future-internal.h" #include "TelepathyQt/_gen/future-channel-body.hpp" #include "TelepathyQt/_gen/future-channel.moc.hpp" #include "TelepathyQt/_gen/future-channel-dispatcher-body.hpp" #include "TelepathyQt/_gen/future-channel-dispatcher.moc.hpp" #include "TelepathyQt/_gen/future-misc-body.hpp" #include "TelepathyQt/_gen/future-misc.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/text-channel.cpp0000664000175000017500000013347412470405660020326 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/text-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT TextChannel::Private { Private(TextChannel *parent); ~Private(); static void introspectMessageQueue(Private *self); static void introspectMessageCapabilities(Private *self); static void introspectMessageSentSignal(Private *self); static void enableChatStateNotifications(Private *self); void updateInitialMessages(); void updateCapabilities(); void processMessageQueue(); void processChatStateQueue(); void contactLost(uint handle); void contactFound(ContactPtr contact); // Public object TextChannel *parent; Client::ChannelTypeTextInterface *textInterface; Client::DBus::PropertiesInterface *properties; ReadinessHelper *readinessHelper; // FeatureMessageCapabilities and FeatureMessageQueue QVariantMap props; bool getAllInFlight; bool gotProperties; // requires FeatureMessageCapabilities QList supportedMessageTypes; QStringList supportedContentTypes; MessagePartSupportFlags messagePartSupport; DeliveryReportingSupportFlags deliveryReportingSupport; // FeatureMessageQueue bool initialMessagesReceived; struct MessageEvent { MessageEvent(const ReceivedMessage &message) : isMessage(true), message(message), removed(0) { } MessageEvent(uint removed) : isMessage(false), message(), removed(removed) { } bool isMessage; ReceivedMessage message; uint removed; }; QList messages; QList incompleteMessages; QHash acknowledgeBatches; // FeatureChatState struct ChatStateEvent { ChatStateEvent(uint contactHandle, uint state) : contactHandle(contactHandle), state(state) { } ContactPtr contact; uint contactHandle; uint state; }; QList chatStateQueue; QHash chatStates; QSet awaitingContacts; }; TextChannel::Private::Private(TextChannel *parent) : parent(parent), textInterface(parent->interface()), properties(parent->interface()), readinessHelper(parent->readinessHelper()), getAllInFlight(false), gotProperties(false), messagePartSupport(0), deliveryReportingSupport(0), initialMessagesReceived(false) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableMessageQueue( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMessageQueue, this); introspectables[FeatureMessageQueue] = introspectableMessageQueue; ReadinessHelper::Introspectable introspectableMessageCapabilities( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMessageCapabilities, this); introspectables[FeatureMessageCapabilities] = introspectableMessageCapabilities; ReadinessHelper::Introspectable introspectableMessageSentSignal( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMessageSentSignal, this); introspectables[FeatureMessageSentSignal] = introspectableMessageSentSignal; ReadinessHelper::Introspectable introspectableChatState( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList() << TP_QT_IFACE_CHANNEL_INTERFACE_CHAT_STATE, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::enableChatStateNotifications, this); introspectables[FeatureChatState] = introspectableChatState; readinessHelper->addIntrospectables(introspectables); } TextChannel::Private::~Private() { foreach (MessageEvent *e, incompleteMessages) { delete e; } foreach (ChatStateEvent *e, chatStateQueue) { delete e; } } void TextChannel::Private::introspectMessageQueue( TextChannel::Private *self) { TextChannel *parent = self->parent; if (parent->hasMessagesInterface()) { Client::ChannelInterfaceMessagesInterface *messagesInterface = parent->interface(); // FeatureMessageQueue needs signal connections + Get (but we // might as well do GetAll and reduce the number of code paths) parent->connect(messagesInterface, SIGNAL(MessageReceived(Tp::MessagePartList)), SLOT(onMessageReceived(Tp::MessagePartList))); parent->connect(messagesInterface, SIGNAL(PendingMessagesRemoved(Tp::UIntList)), SLOT(onPendingMessagesRemoved(Tp::UIntList))); if (!self->gotProperties && !self->getAllInFlight) { self->getAllInFlight = true; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->GetAll( TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotProperties(QDBusPendingCallWatcher*))); } else if (self->gotProperties) { self->updateInitialMessages(); } } else { // FeatureMessageQueue needs signal connections + ListPendingMessages parent->connect(self->textInterface, SIGNAL(Received(uint,uint,uint,uint,uint,QString)), SLOT(onTextReceived(uint,uint,uint,uint,uint,const QString))); // we present SendError signals as if they were incoming // messages, to be consistent with Messages parent->connect(self->textInterface, SIGNAL(SendError(uint,uint,uint,QString)), SLOT(onTextSendError(uint,uint,uint,QString))); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->textInterface->ListPendingMessages(false), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotPendingMessages(QDBusPendingCallWatcher*))); } } void TextChannel::Private::introspectMessageCapabilities( TextChannel::Private *self) { TextChannel *parent = self->parent; if (parent->hasMessagesInterface()) { if (!self->gotProperties && !self->getAllInFlight) { self->getAllInFlight = true; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->GetAll( TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotProperties(QDBusPendingCallWatcher*))); } else if (self->gotProperties) { self->updateCapabilities(); } } else { self->supportedContentTypes = (QStringList(QLatin1String("text/plain"))); parent->readinessHelper()->setIntrospectCompleted( FeatureMessageCapabilities, true); } } void TextChannel::Private::introspectMessageSentSignal( TextChannel::Private *self) { TextChannel *parent = self->parent; if (parent->hasMessagesInterface()) { Client::ChannelInterfaceMessagesInterface *messagesInterface = parent->interface(); parent->connect(messagesInterface, SIGNAL(MessageSent(Tp::MessagePartList,uint,QString)), SLOT(onMessageSent(Tp::MessagePartList,uint,QString))); } else { parent->connect(self->textInterface, SIGNAL(Sent(uint,uint,QString)), SLOT(onTextSent(uint,uint,QString))); } self->readinessHelper->setIntrospectCompleted(FeatureMessageSentSignal, true); } void TextChannel::Private::enableChatStateNotifications( TextChannel::Private *self) { TextChannel *parent = self->parent; Client::ChannelInterfaceChatStateInterface *chatStateInterface = parent->interface(); parent->connect(chatStateInterface, SIGNAL(ChatStateChanged(uint,uint)), SLOT(onChatStateChanged(uint,uint))); // FIXME fd.o#24882 - Download contacts' initial chat states self->readinessHelper->setIntrospectCompleted(FeatureChatState, true); } void TextChannel::Private::updateInitialMessages() { if (!readinessHelper->requestedFeatures().contains(FeatureMessageQueue) || readinessHelper->isReady(Features() << FeatureMessageQueue)) { return; } Q_ASSERT(!initialMessagesReceived); initialMessagesReceived = true; MessagePartListList messages = qdbus_cast( props[QLatin1String("PendingMessages")]); if (messages.isEmpty()) { debug() << "Message queue empty: FeatureMessageQueue is now ready"; readinessHelper->setIntrospectCompleted(FeatureMessageQueue, true); } else { foreach (const MessagePartList &message, messages) { parent->onMessageReceived(message); } } } void TextChannel::Private::updateCapabilities() { if (!readinessHelper->requestedFeatures().contains(FeatureMessageCapabilities) || readinessHelper->isReady(Features() << FeatureMessageCapabilities)) { return; } UIntList messageTypesAsUIntList = qdbus_cast(props[QLatin1String("MessageTypes")]); // Populate the list with the correct variable type supportedMessageTypes.clear(); foreach (uint messageType, messageTypesAsUIntList) { supportedMessageTypes.append(static_cast(messageType)); } supportedContentTypes = qdbus_cast( props[QLatin1String("SupportedContentTypes")]); if (supportedContentTypes.isEmpty()) { supportedContentTypes << QLatin1String("text/plain"); } messagePartSupport = MessagePartSupportFlags(qdbus_cast( props[QLatin1String("MessagePartSupportFlags")])); deliveryReportingSupport = DeliveryReportingSupportFlags( qdbus_cast(props[QLatin1String("DeliveryReportingSupport")])); readinessHelper->setIntrospectCompleted(FeatureMessageCapabilities, true); } void TextChannel::Private::processMessageQueue() { // Proceed as far as we can with the processing of incoming messages // and message-removal events; message IDs aren't necessarily globally // unique, so we need to process them in the correct order relative // to incoming messages while (!incompleteMessages.isEmpty()) { const MessageEvent *e = incompleteMessages.first(); debug() << "MessageEvent:" << reinterpret_cast(e); if (e->isMessage) { if (e->message.senderHandle() != 0 && !e->message.sender()) { // the message doesn't have a sender Contact, but needs one. // We'll have to stop processing here, and come back to it // when we have more Contact objects break; } // if we reach here, the message is ready debug() << "Message is usable, copying to main queue"; messages << e->message; emit parent->messageReceived(e->message); } else { // forget about the message(s) with ID e->removed (there should be // at most one under normal circumstances) int i = 0; while (i < messages.size()) { if (messages.at(i).pendingId() == e->removed) { ReceivedMessage removedMessage = messages.at(i); messages.removeAt(i); emit parent->pendingMessageRemoved(removedMessage); } else { i++; } } } debug() << "Dropping first event"; delete incompleteMessages.takeFirst(); } if (incompleteMessages.isEmpty()) { if (readinessHelper->requestedFeatures().contains(FeatureMessageQueue) && !readinessHelper->isReady(Features() << FeatureMessageQueue)) { debug() << "incompleteMessages empty for the first time: " "FeatureMessageQueue is now ready"; readinessHelper->setIntrospectCompleted(FeatureMessageQueue, true); } return; } // What Contact objects do we need in order to proceed, ignoring those // for which we've already sent a request? HandleIdentifierMap contactsRequired; foreach (const MessageEvent *e, incompleteMessages) { if (e->isMessage) { uint handle = e->message.senderHandle(); if (handle != 0 && !e->message.sender() && !awaitingContacts.contains(handle)) { contactsRequired.insert(handle, e->message.senderId()); } } } if (contactsRequired.isEmpty()) { return; } ConnectionPtr conn = parent->connection(); conn->lowlevel()->injectContactIds(contactsRequired); parent->connect(conn->contactManager()->contactsForHandles( contactsRequired.keys()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactsFinished(Tp::PendingOperation*))); awaitingContacts |= contactsRequired.keys().toSet(); } void TextChannel::Private::processChatStateQueue() { while (!chatStateQueue.isEmpty()) { const ChatStateEvent *e = chatStateQueue.first(); debug() << "ChatStateEvent:" << reinterpret_cast(e); if (e->contact.isNull()) { // the chat state Contact object wasn't retrieved yet, but needs // one. We'll have to stop processing here, and come back to it // when we have more Contact objects break; } chatStates.insert(e->contact, (ChannelChatState) e->state); // if we reach here, the Contact object is ready emit parent->chatStateChanged(e->contact, (ChannelChatState) e->state); debug() << "Dropping first event"; delete chatStateQueue.takeFirst(); } // What Contact objects do we need in order to proceed, ignoring those // for which we've already sent a request? QSet contactsRequired; foreach (const ChatStateEvent *e, chatStateQueue) { if (!e->contact && !awaitingContacts.contains(e->contactHandle)) { contactsRequired << e->contactHandle; } } if (contactsRequired.isEmpty()) { return; } // TODO: pass id hints to ContactManager if we ever gain support to retrieve contact ids // from ChatState. parent->connect(parent->connection()->contactManager()->contactsForHandles( contactsRequired.toList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactsFinished(Tp::PendingOperation*))); awaitingContacts |= contactsRequired; } void TextChannel::Private::contactLost(uint handle) { // we're not going to get a Contact object for this handle, so mark the // messages from that handle as "unknown sender" foreach (MessageEvent *e, incompleteMessages) { if (e->isMessage && e->message.senderHandle() == handle && !e->message.sender()) { e->message.clearSenderHandle(); } } // there is no point in sending chat state notifications for unknown // contacts, removing chat state events from queue that refer to this handle foreach (ChatStateEvent *e, chatStateQueue) { if (e->contactHandle == handle) { chatStateQueue.removeOne(e); delete e; } } } void TextChannel::Private::contactFound(ContactPtr contact) { uint handle = contact->handle().at(0); foreach (MessageEvent *e, incompleteMessages) { if (e->isMessage && e->message.senderHandle() == handle && !e->message.sender()) { e->message.setSender(contact); } } foreach (ChatStateEvent *e, chatStateQueue) { if (e->contactHandle == handle) { e->contact = contact; } } } /** * \class TextChannel * \ingroup clientchannel * \headerfile TelepathyQt/text-channel.h * * \brief The TextChannel class represents a Telepathy channel of type Text. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * TextChannel object usable. * * This is currently the same as Channel::FeatureCore, but may change to include more. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature TextChannel::FeatureCore = Feature(QLatin1String(Channel::staticMetaObject.className()), 0, true); /** * Feature used in order to access the message queue info. * * See message queue methods' documentation for more details. * * \sa messageQueue(), messageReceived(), pendingMessageRemoved(), forget(), acknowledge() */ const Feature TextChannel::FeatureMessageQueue = Feature(QLatin1String(TextChannel::staticMetaObject.className()), 0); /** * Feature used in order to access message capabilities info. * * See message capabilities methods' documentation for more details. * * \sa supportedContentTypes(), messagePartSupport(), deliveryReportingSupport() */ const Feature TextChannel::FeatureMessageCapabilities = Feature(QLatin1String(TextChannel::staticMetaObject.className()), 1); /** * Feature used in order to receive notification when a message is sent. * * \sa messageSent() */ const Feature TextChannel::FeatureMessageSentSignal = Feature(QLatin1String(TextChannel::staticMetaObject.className()), 2); /** * Feature used in order to keep track of chat state changes. * * See chat state methods' documentation for more details. * * \sa chatState(), chatStateChanged() */ const Feature TextChannel::FeatureChatState = Feature(QLatin1String(TextChannel::staticMetaObject.className()), 3); /** * \fn void TextChannel::messageSent(const Tp::Message &message, * Tp::MessageSendingFlags flags, * const QString &sentMessageToken) * * Emitted when a message is sent, if the TextChannel::FeatureMessageSentSignal * has been enabled. * * This signal is emitted regardless of whether the message is sent by this * client, or another client using the same channel via D-Bus. * * \param message A message. This may differ slightly from what the client * requested to send, for instance if it has been altered due * to limitations of the instant messaging protocol used. * \param flags #MessageSendingFlags that were in effect when the message was * sent. Clients can use these in conjunction with * deliveryReportingSupport() to determine whether delivery * reporting can be expected. * \param sentMessageToken Either an empty QString, or an opaque token used * to match the message to any delivery reports. */ /** * \fn void TextChannel::messageReceived(const Tp::ReceivedMessage &message) * * Emitted when a message is added to messageQueue(), if the * TextChannel::FeatureMessageQueue Feature has been enabled. * * This occurs slightly later than the message being received over D-Bus; * see messageQueue() for details. * * \param message The message received. * \sa messageQueue(), acknowledge(), forget() */ /** * \fn void TextChannel::pendingMessageRemoved( * const Tp::ReceivedMessage &message) * * Emitted when a message is removed from messageQueue(), if the * TextChannel::FeatureMessageQueue Feature has been enabled. See messageQueue() for the * circumstances in which this happens. * * \param message The message removed. * \sa messageQueue(), acknowledge(), forget() */ /** * \fn void TextChannel::chatStateChanged(const Tp::ContactPtr &contact, * ChannelChatState state) * * Emitted when the state of a member of the channel has changed, if the * TextChannel::FeatureChatState feature has been enabled. * * Local state changes are also emitted here. * * \param contact The contact whose chat state changed. * \param state The new chat state for \a contact. * \sa chatState() */ /** * Create a new TextChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A TextChannelPtr object pointing to the newly created * TextChannel object. */ TextChannelPtr TextChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return TextChannelPtr(new TextChannel(connection, objectPath, immutableProperties, TextChannel::FeatureCore)); } /** * Construct a new TextChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on TextChannel::FeatureCore. */ TextChannel::TextChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : Channel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ TextChannel::~TextChannel() { delete mPriv; } /** * Return whether this channel supports the Messages interface. * * If the interface is not supported, some advanced functionality will be unavailable. * * This method requires TextChannel::FeatureCore to be ready. * * \return \c true if the Messages interface is supported, \c false otherwise. */ bool TextChannel::hasMessagesInterface() const { return interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES); } /** * Return whether this channel supports the ChatState interface. * * If the interface is not supported, requestChatState() will fail and all contacts' chat states * will appear to be #ChannelChatStateInactive. * * This method requires TextChannel::FeatureCore to be ready. * * \return \c true if the ChatState interface is supported, \c false otherwise. * \sa requestChatState(), chatStateChanged() */ bool TextChannel::hasChatStateInterface() const { return interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_CHAT_STATE); } /** * Return whether contacts can be invited into this channel using * inviteContacts() (which is equivalent to Channel::groupAddContacts()). * * Whether this is the case depends on the underlying protocol, the type of channel, * and the user's privileges (in some chatrooms, only a privileged user * can invite other contacts). * * This is an alias for Channel::groupCanAddContacts(), to indicate its meaning more * clearly for Text channels. * * This method requires Channel::FeatureCore to be ready. * * \return \c true if contacts can be invited, \c false otherwise. * \sa inviteContacts(), Channel::groupCanAddContacts(), Channel::groupAddContacts() */ bool TextChannel::canInviteContacts() const { return groupCanAddContacts(); } /* in the block below is used to escape the star-slash sequence */ /** * Return a list of supported MIME content types for messages on this channel. * * For a simple text channel this will be a list containing one item, * "text/plain". * * This list may contain the special value "*/*", which * indicates that any content type is supported. * * This method requires TextChannel::FeatureMessageCapabilities to be ready. * * \return The list of MIME content types. */ QStringList TextChannel::supportedContentTypes() const { return mPriv->supportedContentTypes; } /** * Return the message types supported by this channel. * * This method requires TextChannel::FeatureMessageCapabilities to be ready. * * \return The list of supported message types */ QList TextChannel::supportedMessageTypes() const { if (!isReady(FeatureMessageCapabilities)) { warning() << "TextChannel::supportedMessageTypes() used with " "FeatureMessageCapabilities not ready"; } return mPriv->supportedMessageTypes; } /** * Return whether the provided message type is supported. * * This method requires TextChannel::FeatureMessageCapabilities to be ready. * * \param messageType The message type to check. * \return \c true if supported, \c false otherwise */ bool TextChannel::supportsMessageType(ChannelTextMessageType messageType) const { if (!isReady(FeatureMessageCapabilities)) { warning() << "TextChannel::supportsMessageType() used with " "FeatureMessageCapabilities not ready"; } return mPriv->supportedMessageTypes.contains(messageType); } /** * Return a set of flags indicating support for multi-part messages on this * channel. * * This is zero on simple text channels, or greater than zero if * there is partial or full support for multi-part messages. * * This method requires TextChannel::FeatureMessageCapabilities to be ready. * * \return The flags as #MessagePartSupportFlags. */ MessagePartSupportFlags TextChannel::messagePartSupport() const { return mPriv->messagePartSupport; } /** * Return a set of flags indicating support for delivery reporting on this * channel. * * This is zero if there are no particular guarantees, or greater * than zero if delivery reports can be expected under certain circumstances. * * This method requires TextChannel::FeatureMessageCapabilities to be ready. * * \return The flags as #DeliveryReportingSupportFlags. */ DeliveryReportingSupportFlags TextChannel::deliveryReportingSupport() const { return mPriv->deliveryReportingSupport; } /** * Return a list of messages received in this channel. * * Messages are added to this list when they are received from the instant * messaging service; the messageReceived() signal is emitted. * * There is a small delay between the message being received over D-Bus and * becoming available to users of this C++ API, since a small amount of * additional information needs to be fetched. However, the relative ordering * of all the messages in a channel is preserved. * * Messages are removed from this list when they are acknowledged with the * acknowledge() or forget() methods. On channels where hasMessagesInterface() * returns \c true, they will also be removed when acknowledged by a different * client. In either case, the pendingMessageRemoved() signal is emitted. * * This method requires TextChannel::FeatureMessageQueue to be ready. * * \return A list of ReceivedMessage objects. * \sa messageReceived() */ QList TextChannel::messageQueue() const { return mPriv->messages; } /** * Return the current chat state for \a contact. * * If hasChatStateInterface() returns \c false, this method will always return * #ChannelChatStateInactive. * * This method requires TextChannel::FeatureChatState to be ready. * * \return The contact chat state as #ChannelChatState. */ ChannelChatState TextChannel::chatState(const ContactPtr &contact) const { if (!isReady(FeatureChatState)) { warning() << "TextChannel::chatState() used with " "FeatureChatState not ready"; return ChannelChatStateInactive; } if (mPriv->chatStates.contains(contact)) { return mPriv->chatStates.value(contact); } return ChannelChatStateInactive; } void TextChannel::onAcknowledgePendingMessagesReply( QDBusPendingCallWatcher *watcher) { UIntList ids = mPriv->acknowledgeBatches.value(watcher); QDBusPendingReply<> reply = *watcher; if (reply.isError()) { // One of the IDs was bad, and we can't know which one. Recover by // doing as much as possible, and hope for the best... debug() << "Recovering from AcknowledgePendingMessages failure for: " << ids; foreach (uint id, ids) { mPriv->textInterface->AcknowledgePendingMessages(UIntList() << id); } } mPriv->acknowledgeBatches.remove(watcher); watcher->deleteLater(); } /** * Acknowledge that received messages have been displayed to the user. * * Note that this method should only be called by the main handler of a channel, usually * meaning the user interface process that displays the channel to the user * (when a channel dispatcher is used, the handler must acknowledge messages, * and other approvers or observers must not acknowledge messages). * * Processes other than the main handler of a channel can free memory used * by the library by calling forget() instead. * * This method requires TextChannel::FeatureMessageQueue to be ready. * * \param messages A list of received messages that have now been displayed. * \sa forget(), messageQueue(), messageReceived(), pendingMessageRemoved() */ void TextChannel::acknowledge(const QList &messages) { UIntList ids; foreach (const ReceivedMessage &m, messages) { if (m.isFromChannel(TextChannelPtr(this))) { ids << m.pendingId(); } else { warning() << "message did not come from this channel, ignoring"; } } if (ids.isEmpty()) { return; } // we're going to acknowledge these messages (or as many as possible, if // we lose a race with another acknowledging process), so let's remove // them from the list immediately forget(messages); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( mPriv->textInterface->AcknowledgePendingMessages(ids), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onAcknowledgePendingMessagesReply(QDBusPendingCallWatcher*))); mPriv->acknowledgeBatches[watcher] = ids; } /** * Remove messages from the message queue without acknowledging them. * * Note that this method frees memory used by the library, but * does not free the corresponding memory in the CM process. * It should be used by clients that are not the main handler for a channel; * the main handler for a channel should use acknowledge() instead. * * This method requires TextChannel::FeatureMessageQueue to be ready. * * \param messages A list of received messages that have now been processed. * \sa acknowledge(), messageQueue(), messageReceived(), pendingMessageRemoved() */ void TextChannel::forget(const QList &messages) { foreach (const ReceivedMessage &m, messages) { if (!m.isFromChannel(TextChannelPtr(this))) { warning() << "message did not come from this channel, ignoring"; } else if (mPriv->messages.removeOne(m)) { emit pendingMessageRemoved(m); } } } /** * Request that a message be sent on this channel. * * When the message has been submitted for delivery, * this method will return and the messageSent() signal will be emitted. * * If the message cannot be submitted for delivery, the returned pending operation will fail and no * signal is emitted. * * This method requires TextChannel::FeatureCore to be ready. * * \param text The message body. * \param type The message type. * \param flags Flags affecting how the message is sent. * Note that the channel may ignore some or all flags, depending on * deliveryReportingSupport(); the flags that were handled by the CM are provided in * messageSent(). * \return A PendingOperation which will emit PendingOperation::finished * when the message has been submitted for delivery. * \sa messageSent() */ PendingSendMessage *TextChannel::send(const QString &text, ChannelTextMessageType type, MessageSendingFlags flags) { Message m(type, text); PendingSendMessage *op = new PendingSendMessage(TextChannelPtr(this), m); if (hasMessagesInterface()) { Client::ChannelInterfaceMessagesInterface *messagesInterface = interface(); connect(new QDBusPendingCallWatcher( messagesInterface->SendMessage(m.parts(), (uint) flags)), SIGNAL(finished(QDBusPendingCallWatcher*)), op, SLOT(onMessageSent(QDBusPendingCallWatcher*))); } else { connect(new QDBusPendingCallWatcher(mPriv->textInterface->Send(type, text)), SIGNAL(finished(QDBusPendingCallWatcher*)), op, SLOT(onTextSent(QDBusPendingCallWatcher*))); } return op; } /** * Request that a message be sent on this channel. * * When the message has been submitted for delivery, * this method will return and the messageSent() signal will be emitted. * * If the message cannot be submitted for delivery, the returned pending operation will fail and no * signal is emitted. * * This method requires TextChannel::FeatureCore to be ready. * * \param part The message parts. * \param flags Flags affecting how the message is sent. * Note that the channel may ignore some or all flags, depending on * deliveryReportingSupport(); the flags that were handled by the CM are provided in * messageSent(). * \return A PendingOperation which will emit PendingOperation::finished * when the message has been submitted for delivery. * \sa messageSent() */ PendingSendMessage *TextChannel::send(const MessagePartList &parts, MessageSendingFlags flags) { Message m(parts); PendingSendMessage *op = new PendingSendMessage(TextChannelPtr(this), m); if (hasMessagesInterface()) { Client::ChannelInterfaceMessagesInterface *messagesInterface = interface(); connect(new QDBusPendingCallWatcher( messagesInterface->SendMessage(m.parts(), (uint) flags)), SIGNAL(finished(QDBusPendingCallWatcher*)), op, SLOT(onMessageSent(QDBusPendingCallWatcher*))); } else { connect(new QDBusPendingCallWatcher(mPriv->textInterface->Send( m.messageType(), m.text())), SIGNAL(finished(QDBusPendingCallWatcher*)), op, SLOT(onTextSent(QDBusPendingCallWatcher*))); } return op; } /** * Set the local chat state and notify other members of the channel that it has * changed. * * Note that only the primary handler of the channel should set its chat * state. * * This method requires TextChannel::FeatureCore to be ready. * * \param state The new state. * \sa chatStateChanged() */ PendingOperation *TextChannel::requestChatState(ChannelChatState state) { if (!interfaces().contains(TP_QT_IFACE_CHANNEL_INTERFACE_CHAT_STATE)) { warning() << "TextChannel::requestChatState() used with no chat " "state interface"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("TextChannel does not support chat state interface"), TextChannelPtr(this)); } Client::ChannelInterfaceChatStateInterface *chatStateInterface = interface(); return new PendingVoid(chatStateInterface->SetChatState( (uint) state), TextChannelPtr(this)); } void TextChannel::onMessageSent(const MessagePartList &parts, uint flags, const QString &sentMessageToken) { emit messageSent(Message(parts), MessageSendingFlag(flags), sentMessageToken); } void TextChannel::onContactsFinished(PendingOperation *op) { PendingContacts *pc = qobject_cast(op); UIntList failed; Q_ASSERT(pc->isForHandles()); foreach (uint handle, pc->handles()) { mPriv->awaitingContacts -= handle; } if (pc->isError()) { warning().nospace() << "Gathering contacts failed: " << pc->errorName() << ": " << pc->errorMessage(); foreach (uint handle, pc->handles()) { mPriv->contactLost(handle); } } else { foreach (const ContactPtr &contact, pc->contacts()) { mPriv->contactFound(contact); } foreach (uint handle, pc->invalidHandles()) { mPriv->contactLost(handle); } } // all contacts for messages and chat state events we were asking about // should now be ready mPriv->processMessageQueue(); mPriv->processChatStateQueue(); } void TextChannel::onMessageReceived(const MessagePartList &parts) { if (!mPriv->initialMessagesReceived) { return; } mPriv->incompleteMessages << new Private::MessageEvent( ReceivedMessage(parts, TextChannelPtr(this))); mPriv->processMessageQueue(); } void TextChannel::onPendingMessagesRemoved(const UIntList &ids) { if (!mPriv->initialMessagesReceived) { return; } foreach (uint id, ids) { mPriv->incompleteMessages << new Private::MessageEvent(id); } mPriv->processMessageQueue(); } void TextChannel::onTextSent(uint timestamp, uint type, const QString &text) { emit messageSent(Message(timestamp, type, text), 0, QLatin1String("")); } void TextChannel::onTextReceived(uint id, uint timestamp, uint sender, uint type, uint flags, const QString &text) { if (!mPriv->initialMessagesReceived) { return; } MessagePart header; if (timestamp == 0) { timestamp = QDateTime::currentDateTime().toTime_t(); } header.insert(QLatin1String("message-received"), QDBusVariant(static_cast(timestamp))); header.insert(QLatin1String("pending-message-id"), QDBusVariant(id)); header.insert(QLatin1String("message-sender"), QDBusVariant(sender)); header.insert(QLatin1String("message-type"), QDBusVariant(type)); if (flags & ChannelTextMessageFlagScrollback) { header.insert(QLatin1String("scrollback"), QDBusVariant(true)); } if (flags & ChannelTextMessageFlagRescued) { header.insert(QLatin1String("rescued"), QDBusVariant(true)); } MessagePart body; body.insert(QLatin1String("content-type"), QDBusVariant(QLatin1String("text/plain"))); body.insert(QLatin1String("content"), QDBusVariant(text)); if (flags & ChannelTextMessageFlagTruncated) { header.insert(QLatin1String("truncated"), QDBusVariant(true)); } MessagePartList parts; parts << header; parts << body; ReceivedMessage m(parts, TextChannelPtr(this)); if (flags & ChannelTextMessageFlagNonTextContent) { // set the "you are not expected to understand this" flag m.setForceNonText(); } mPriv->incompleteMessages << new Private::MessageEvent(m); mPriv->processMessageQueue(); } void TextChannel::onTextSendError(uint error, uint timestamp, uint type, const QString &text) { if (!mPriv->initialMessagesReceived) { return; } MessagePart header; header.insert(QLatin1String("message-received"), QDBusVariant(static_cast( QDateTime::currentDateTime().toTime_t()))); header.insert(QLatin1String("message-type"), QDBusVariant(static_cast( ChannelTextMessageTypeDeliveryReport))); // we can't tell whether it's a temporary or permanent failure here, // so guess based on the delivery-error uint deliveryStatus; switch (error) { case ChannelTextSendErrorOffline: case ChannelTextSendErrorPermissionDenied: deliveryStatus = DeliveryStatusTemporarilyFailed; break; case ChannelTextSendErrorInvalidContact: case ChannelTextSendErrorTooLong: case ChannelTextSendErrorNotImplemented: deliveryStatus = DeliveryStatusPermanentlyFailed; break; case ChannelTextSendErrorUnknown: default: deliveryStatus = DeliveryStatusTemporarilyFailed; break; } header.insert(QLatin1String("delivery-status"), QDBusVariant(deliveryStatus)); header.insert(QLatin1String("delivery-error"), QDBusVariant(error)); MessagePart echoHeader; echoHeader.insert(QLatin1String("message-sent"), QDBusVariant(timestamp)); echoHeader.insert(QLatin1String("message-type"), QDBusVariant(type)); MessagePart echoBody; echoBody.insert(QLatin1String("content-type"), QDBusVariant(QLatin1String("text/plain"))); echoBody.insert(QLatin1String("content"), QDBusVariant(text)); MessagePartList echo; echo << echoHeader; echo << echoBody; header.insert(QLatin1String("delivery-echo"), QDBusVariant(QVariant::fromValue(echo))); MessagePartList parts; parts << header; } void TextChannel::gotProperties(QDBusPendingCallWatcher *watcher) { Q_ASSERT(mPriv->getAllInFlight); mPriv->getAllInFlight = false; mPriv->gotProperties = true; QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Properties::GetAll(Channel.Interface.Messages)" " failed with " << reply.error().name() << ": " << reply.error().message(); ReadinessHelper *readinessHelper = mPriv->readinessHelper; if (readinessHelper->requestedFeatures().contains(FeatureMessageQueue) && !readinessHelper->isReady(Features() << FeatureMessageQueue)) { readinessHelper->setIntrospectCompleted(FeatureMessageQueue, false, reply.error()); } if (readinessHelper->requestedFeatures().contains(FeatureMessageCapabilities) && !readinessHelper->isReady(Features() << FeatureMessageCapabilities)) { readinessHelper->setIntrospectCompleted(FeatureMessageCapabilities, false, reply.error()); } return; } debug() << "Properties::GetAll(Channel.Interface.Messages) returned"; mPriv->props = reply.value(); mPriv->updateInitialMessages(); mPriv->updateCapabilities(); watcher->deleteLater(); } void TextChannel::gotPendingMessages(QDBusPendingCallWatcher *watcher) { Q_ASSERT(!mPriv->initialMessagesReceived); mPriv->initialMessagesReceived = true; QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Properties::GetAll(Channel.Interface.Messages)" " failed with " << reply.error().name() << ": " << reply.error().message(); // TODO should we fail here? mPriv->readinessHelper->setIntrospectCompleted(FeatureMessageQueue, false, reply.error()); return; } debug() << "Text::ListPendingMessages returned"; PendingTextMessageList list = reply.value(); if (!list.isEmpty()) { foreach (const PendingTextMessage &message, list) { onTextReceived(message.identifier, message.unixTimestamp, message.sender, message.messageType, message.flags, message.text); } // processMessageQueue sets FeatureMessageQueue ready when the queue is empty for the first // time } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureMessageQueue, true); } watcher->deleteLater(); } void TextChannel::onChatStateChanged(uint contactHandle, uint state) { mPriv->chatStateQueue.append(new Private::ChatStateEvent( contactHandle, state)); mPriv->processChatStateQueue(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/constants.h0000664000175000017500000001346612470405660017413 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_constants_h_HEADER_GUARD_ #define _TelepathyQt_constants_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif /** * \addtogroup typesconstants Types and constants * * Enumerated, flag, structure, list and mapping types and utility constants. */ /** * \defgroup utilityconsts Utility string constants * \ingroup typesconstants * * Utility constants which aren't generated from the specification but are * useful for working with the Telepathy protocol. * @{ */ /** * The prefix for a connection manager's bus name, to which the CM's name (e.g. * "gabble") should be appended. */ #define TP_QT_CONNECTION_MANAGER_BUS_NAME_BASE QLatin1String("org.freedesktop.Telepathy.ConnectionManager.") /** * The prefix for a connection manager's object path, to which the CM's name * (e.g. "gabble") should be appended. */ #define TP_QT_CONNECTION_MANAGER_OBJECT_PATH_BASE QLatin1String("/org/freedesktop/Telepathy/ConnectionManager/") /** * The prefix for a connection's bus name, to which the CM's name (e.g. * "gabble"), the protocol (e.g. "jabber") and an element * representing the account should be appended. */ #define TP_QT_CONNECTION_BUS_NAME_BASE QLatin1String("org.freedesktop.Telepathy.Connection.") /** * The prefix for a connection's object path, to which the CM's name (e.g. * "gabble"), the protocol (e.g. "jabber") and an element * representing the account should be appended. */ #define TP_QT_CONNECTION_OBJECT_PATH_BASE QLatin1String("/org/freedesktop/Telepathy/Connection/") /** * The well-known bus name of the Account Manager. * * \see Tp::AccountManager */ #define TP_QT_ACCOUNT_MANAGER_BUS_NAME \ (QLatin1String("org.freedesktop.Telepathy.AccountManager")) /** * The object path of the Account Manager object. * * \see Tp::AccountManager */ #define TP_QT_ACCOUNT_MANAGER_OBJECT_PATH \ (QLatin1String("/org/freedesktop/Telepathy/AccountManager")) /** * The well-known bus name of the Channel Dispatcher. */ #define TP_QT_CHANNEL_DISPATCHER_BUS_NAME \ (QLatin1String("org.freedesktop.Telepathy.ChannelDispatcher")) /** * The object path of the Channel Dispatcherr object. */ #define TP_QT_CHANNEL_DISPATCHER_OBJECT_PATH \ (QLatin1String("/org/freedesktop/Telepathy/ChannelDispatcher")) /** * The prefix for an Account's object path, to which the CM's name (e.g. * "gabble"), the protocol (e.g. "jabber") and an element * identifying the particular account should be appended. * * \see Tp::Account */ #define TP_QT_ACCOUNT_OBJECT_PATH_BASE \ (QLatin1String("/org/freedesktop/Telepathy/Account")) /** * The object path of the Debug object of various services. */ #define TP_QT_DEBUG_OBJECT_PATH \ (QLatin1String("/org/freedesktop/Telepathy/debug")) /** * @} */ #include /** * \ingroup errorstrconsts * * The error name "org.freedesktop.DBus.Error.NameHasNoOwner" as a QLatin1String. * * Raised by the D-Bus daemon when looking up the owner of a well-known name, * if no process owns that name. * * Also used by DBusProxy to indicate that the owner of a well-known name * has disappeared (usually indicating that the process owning that name * exited or crashed). */ #define TP_QT_DBUS_ERROR_NAME_HAS_NO_OWNER \ (QLatin1String("org.freedesktop.DBus.Error.NameHasNoOwner")) /** * \ingroup errorstrconsts * * The error name "org.freedesktop.DBus.Error.UnknownInterface" as a QLatin1String. */ #define TP_QT_DBUS_ERROR_UNKNOWN_INTERFACE \ (QLatin1String("org.freedesktop.DBus.Error.UnknownInterface")) /** * \ingroup errorstrconsts * * The error name "org.freedesktop.DBus.Error.UnknownMethod" as a QLatin1String. * * Raised by the D-Bus daemon when the method name invoked isn't * known by the object you invoked it on. */ #define TP_QT_DBUS_ERROR_UNKNOWN_METHOD \ (QLatin1String("org.freedesktop.DBus.Error.UnknownMethod")) /** * \ingroup errorstrconsts * * The error name "org.freedesktop.Telepathy.Qt.Error.ObjectRemoved" as a QLatin1String. */ #define TP_QT_ERROR_OBJECT_REMOVED \ (QLatin1String("org.freedesktop.Telepathy.Qt.Error.ObjectRemoved")) /** * \ingroup errorstrconsts * * The error name "org.freedesktop.Telepathy.Qt.Error.Inconsistent" as a QLatin1String. */ #define TP_QT_ERROR_INCONSISTENT \ (QLatin1String("org.freedesktop.Telepathy.Qt.Error.Inconsistent")) /** * \ingroup errorstrconsts * * The error name "org.freedesktop.Telepathy.Qt.Error.Orphaned" as a QLatin1String. * * This error is used when the "parent" proxy of an object gets invalidated. For example, a Channel * whose corresponding Connection is invalidated invalidates itself with this error, as do leftover * StreamTube connections when their parent StreamTubeChannel is invalidated. The invalidation * reason of the parent proxy might provide more information on the cause of the error. */ #define TP_QT_ERROR_ORPHANED \ (QLatin1String("org.freedesktop.Telepathy.Qt.Error.Orphaned")) #endif telepathy-qt-0.9.6~git1/TelepathyQt/handled-channel-notifier.cpp0000664000175000017500000000673712470405660022557 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/handled-channel-notifier.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/request-temporary-handler-internal.h" #include #include namespace Tp { struct TP_QT_NO_EXPORT HandledChannelNotifier::Private { Private(const ClientRegistrarPtr &cr, const SharedPtr &handler) : cr(cr), handler(handler), channel(handler->channel()) { } ClientRegistrarPtr cr; SharedPtr handler; ChannelPtr channel; // needed to keep channel alive, since RTH maintains only a weak ref }; /** * \class HandledChannelNotifier * \ingroup clientchannel * \headerfile TelepathyQt/handled-channel-notifier.h * * \brief The HandledChannelNotifier class can be used to keep track of * channel() being re-requested. * * Instances of this class cannot be constructed directly; the only way to get * one is trough PendingChannel. */ HandledChannelNotifier::HandledChannelNotifier(const ClientRegistrarPtr &cr, const SharedPtr &handler) : mPriv(new Private(cr, handler)) { connect(mPriv->channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onChannelInvalidated())); connect(handler.data(), SIGNAL(channelReceived(Tp::ChannelPtr,QDateTime,Tp::ChannelRequestHints)), SLOT(onChannelReceived(Tp::ChannelPtr,QDateTime,Tp::ChannelRequestHints))); } HandledChannelNotifier::~HandledChannelNotifier() { delete mPriv; } ChannelPtr HandledChannelNotifier::channel() const { return mPriv->channel; } void HandledChannelNotifier::onChannelReceived(const Tp::ChannelPtr &channel, const QDateTime &userActionTime, const Tp::ChannelRequestHints &requestHints) { emit handledAgain(userActionTime, requestHints); } void HandledChannelNotifier::onChannelInvalidated() { deleteLater(); } #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) void HandledChannelNotifier::connectNotify(const QMetaMethod &signal) { if (signal == QMetaMethod::fromSignal(&HandledChannelNotifier::handledAgain)) { mPriv->handler->setQueueChannelReceived(false); } } #else void HandledChannelNotifier::connectNotify(const char *signalName) { if (qstrcmp(signalName, SIGNAL(handledAgain(QDateTime,Tp::ChannelRequestHints))) == 0) { mPriv->handler->setQueueChannelReceived(false); } } #endif } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ProtocolInfo0000664000175000017500000000036312470405660017556 0ustar jrjr#ifndef _TelepathyQt_ProtocolInfo_HEADER_GUARD_ #define _TelepathyQt_ProtocolInfo_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Feature0000664000175000017500000000034312470405660016532 0ustar jrjr#ifndef _TelepathyQt_Feature_HEADER_GUARD_ #define _TelepathyQt_Feature_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/media-session-handler.h0000664000175000017500000000340112470405660021536 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_media_session_handler_h_HEADER_GUARD_ #define _TelepathyQt_media_session_handler_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif /** * \addtogroup clientsideproxies Client-side proxies * * Proxy objects representing remote service objects accessed via D-Bus. * * In addition to providing direct access to methods, signals and properties * exported by the remote objects, some of these proxies offer features like * automatic inspection of remote object capabilities, property tracking, * backwards compatibility helpers for older services and other utilities. */ /** * \defgroup clientmsesh Media session handler proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy MediaSessionHandler objects. */ #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/types-internal.h0000664000175000017500000001240112470405660020341 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_types_internal_h_HEADER_GUARD_ #define _TelepathyQt_types_internal_h_HEADER_GUARD_ #include #include #include namespace Tp { /** * Private structure used to circumvent QtDBus' strict demarshalling */ struct TP_QT_EXPORT SUSocketAddress { /** * A dotted-quad IPv4 address literal: four ASCII decimal numbers, each * between 0 and 255 inclusive, e.g. "192.168.0.1". */ QString address; /** * The TCP or UDP port number. */ uint port; }; TP_QT_EXPORT bool operator==(const SUSocketAddress& v1, const SUSocketAddress& v2); TP_QT_EXPORT inline bool operator!=(const SUSocketAddress& v1, const SUSocketAddress& v2) { return !operator==(v1, v2); } TP_QT_EXPORT QDBusArgument& operator<<(QDBusArgument& arg, const SUSocketAddress& val); TP_QT_EXPORT const QDBusArgument& operator>>(const QDBusArgument& arg, SUSocketAddress& val); } // Tp // specialise for Tp::SocketAddressIPv4, allowing it to be used in place of QDBusVariant template<> inline Tp::SocketAddressIPv4 qdbus_cast(const QDBusArgument &arg, Tp::SocketAddressIPv4 *) { if (arg.currentSignature() == QLatin1String("(su)")) { // Use Tp::SUSocketAddress Tp::SUSocketAddress saddr = qdbus_cast(arg); Tp::SocketAddressIPv4 addr; addr.address = saddr.address; addr.port = saddr.port; return addr; } else if (arg.currentSignature() == QLatin1String("(sq)")) { // Keep it standard Tp::SocketAddressIPv4 item; arg >> item; return item; } else { // This should never happen... return Tp::SocketAddressIPv4(); } } template<> inline Tp::SocketAddressIPv4 qdbus_cast(const QVariant &v, Tp::SocketAddressIPv4 *) { int id = v.userType(); if (id == qMetaTypeId()) { QDBusArgument arg = qvariant_cast(v); if (arg.currentSignature() == QLatin1String("(su)")) { // Use Tp::SUSocketAddress Tp::SUSocketAddress saddr = qdbus_cast(arg); Tp::SocketAddressIPv4 addr; addr.address = saddr.address; addr.port = saddr.port; return addr; } else if (arg.currentSignature() == QLatin1String("(sq)")) { // Keep it standard Tp::SocketAddressIPv4 item; arg >> item; return item; } else { // This should never happen... return Tp::SocketAddressIPv4(); } } else return qvariant_cast(v); } // specialise for Tp::SocketAddressIPv6, allowing it to be used in place of QDBusVariant template<> inline Tp::SocketAddressIPv6 qdbus_cast(const QDBusArgument &arg, Tp::SocketAddressIPv6 *) { if (arg.currentSignature() == QLatin1String("(su)")) { // Use Tp::SUSocketAddress Tp::SUSocketAddress saddr = qdbus_cast(arg); Tp::SocketAddressIPv6 addr; addr.address = saddr.address; addr.port = saddr.port; return addr; } else if (arg.currentSignature() == QLatin1String("(sq)")) { // Keep it standard Tp::SocketAddressIPv6 item; arg >> item; return item; } else { // This should never happen... return Tp::SocketAddressIPv6(); } } template<> inline Tp::SocketAddressIPv6 qdbus_cast(const QVariant &v, Tp::SocketAddressIPv6 *) { int id = v.userType(); if (id == qMetaTypeId()) { QDBusArgument arg = qvariant_cast(v); if (arg.currentSignature() == QLatin1String("(su)")) { // Use Tp::SUSocketAddress Tp::SUSocketAddress saddr = qdbus_cast(arg); Tp::SocketAddressIPv6 addr; addr.address = saddr.address; addr.port = saddr.port; return addr; } else if (arg.currentSignature() == QLatin1String("(sq)")) { // Keep it standard Tp::SocketAddressIPv6 item; arg >> item; return item; } else { // This should never happen... return Tp::SocketAddressIPv6(); } } else return qvariant_cast(v); } Q_DECLARE_METATYPE(Tp::SUSocketAddress) #endif telepathy-qt-0.9.6~git1/TelepathyQt/ReferencedHandlesIterator0000664000175000017500000000025712470405660022216 0ustar jrjr#ifndef _TelepathyQt_ReferencedHandlesIterator_HEADER_GUARD_ #define _TelepathyQt_ReferencedHandlesIterator_HEADER_GUARD_ #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/ProtocolInterfaceAvatarsInterface0000664000175000017500000000044212470405660023724 0ustar jrjr#ifndef _TelepathyQt_ProtocolInterfaceAvatarsInterface_HEADER_GUARD_ #define _TelepathyQt_ProtocolInterfaceAvatarsInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PendingChannelRequest0000664000175000017500000000041712470405660021367 0ustar jrjr#ifndef _TelepathyQt_PendingChannelRequest_HEADER_GUARD_ #define _TelepathyQt_PendingChannelRequest_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/future-channel-dispatcher.xml0000664000175000017500000000032212470405660022777 0ustar jrjr Channel Dispatcher extensions from the future telepathy-qt-0.9.6~git1/TelepathyQt/MediaStreamHandler0000664000175000017500000000040612470405660020630 0ustar jrjr#ifndef _TelepathyQt_MediaStreamHandler_HEADER_GUARD_ #define _TelepathyQt_MediaStreamHandler_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/account-factory.h0000664000175000017500000000466712470405660020503 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_account_factory_h_HEADER_GUARD_ #define _TelepathyQt_account_factory_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include class QDBusConnection; namespace Tp { class PendingReady; class TP_QT_EXPORT AccountFactory : public FixedFeatureFactory { Q_OBJECT Q_DISABLE_COPY(AccountFactory) public: static AccountFactoryPtr create(const QDBusConnection &bus, const Features &features = Features()); virtual ~AccountFactory(); PendingReady *proxy(const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const; protected: AccountFactory(const QDBusConnection &bus, const Features &features); virtual AccountPtr construct(const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const; virtual QString finalBusNameFrom(const QString &uniqueOrWellKnown) const; // Nothing we'd like to prepare() // Fixed features private: struct Private; Private *mPriv; // Currently unused, just for future-proofing }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/generic-capability-filter.dox0000664000175000017500000000274112470405660022752 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \class Tp::GenericCapabilityFilter * \ingroup utils * \headerfile TelepathyQt/generic-capability-filter.h * * \brief The GenericCapabilityFilter class provides a generic filter object to * be used to filter objects by capabilities. * * The objects used in conjunction with this filter must implement a method * called capabilities() returning a CapabilitiesBase (or a subclass of it) * instance. * Specialized classes such as AccountCapabilityFilter are also provided and * should be used where appropriate. */ telepathy-qt-0.9.6~git1/TelepathyQt/shared-ptr.h0000664000175000017500000001665012470405660017446 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2011 Collabora Ltd. * @copyright Copyright (C) 2009-2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_shared_ptr_h_HEADER_GUARD_ #define _TelepathyQt_shared_ptr_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class RefCounted; template class SharedPtr; template class WeakPtr; class TP_QT_EXPORT RefCounted { Q_DISABLE_COPY(RefCounted) class SharedCount { Q_DISABLE_COPY(SharedCount) public: SharedCount(RefCounted *d) : d(d), strongref(0), weakref(0) { } private: template friend class SharedPtr; template friend class WeakPtr; friend class RefCounted; RefCounted *d; mutable QAtomicInt strongref; mutable QAtomicInt weakref; }; public: inline RefCounted() : sc(new SharedCount(this)) { sc->weakref.ref(); } inline virtual ~RefCounted() { sc->d = 0; if (!sc->weakref.deref()) { delete sc; } } private: template friend class SharedPtr; template friend class WeakPtr; // TODO: Remove when Conn.I.ContactList, etc becomes mandatory. This is required to circumvent // a reference cycle when using contact list channels, due to the fact that Channels hold // strong references to their parent Connection, but not needed when using // Conn.I.ContactList and friends. friend class ContactManager; inline void ref() const { sc->strongref.ref(); } inline bool deref() const { return sc->strongref.deref(); } SharedCount *sc; }; template class SharedPtr { typedef bool (SharedPtr::*UnspecifiedBoolType)() const; public: inline SharedPtr() : d(0) { } explicit inline SharedPtr(T *d) : d(d) { if (d) { d->ref(); } } template inline SharedPtr(const SharedPtr &o) : d(o.data()) { if (d) { d->ref(); } } inline SharedPtr(const SharedPtr &o) : d(o.d) { if (d) { d->ref(); } } explicit inline SharedPtr(const WeakPtr &o) { RefCounted::SharedCount *sc = o.sc; if (sc) { // increase the strongref, but never up from zero // or less (negative is used on untracked objects) register int tmp = sc->strongref.fetchAndAddOrdered(0); while (tmp > 0) { // try to increment from "tmp" to "tmp + 1" if (sc->strongref.testAndSetRelaxed(tmp, tmp + 1)) { // succeeded break; } // failed, try again tmp = sc->strongref.fetchAndAddOrdered(0); } if (tmp > 0) { d = dynamic_cast(sc->d); Q_ASSERT(d != NULL); } else { d = 0; } } else { d = 0; } } inline ~SharedPtr() { if (d && !d->deref()) { T *saved = d; d = 0; delete saved; } } inline void reset() { SharedPtr().swap(*this); } inline T *data() const { return d; } inline const T *constData() const { return d; } inline T *operator->() { return d; } inline T *operator->() const { return d; } inline bool isNull() const { return !d; } inline bool operator!() const { return isNull(); } operator UnspecifiedBoolType() const { return !isNull() ? &SharedPtr::operator! : 0; } inline bool operator==(const SharedPtr &o) const { return d == o.d; } inline bool operator!=(const SharedPtr &o) const { return d != o.d; } inline bool operator==(const T *ptr) const { return d == ptr; } inline bool operator!=(const T *ptr) const { return d != ptr; } inline SharedPtr &operator=(const SharedPtr &o) { SharedPtr(o).swap(*this); return *this; } inline void swap(SharedPtr &o) { T *tmp = d; d = o.d; o.d = tmp; } template static inline SharedPtr staticCast(const SharedPtr &src) { return SharedPtr(static_cast(src.data())); } template static inline SharedPtr dynamicCast(const SharedPtr &src) { return SharedPtr(dynamic_cast(src.data())); } template static inline SharedPtr constCast(const SharedPtr &src) { return SharedPtr(const_cast(src.data())); } template static inline SharedPtr qObjectCast(const SharedPtr &src) { return SharedPtr(qobject_cast(src.data())); } private: friend class WeakPtr; T *d; }; template inline uint qHash(const SharedPtr &ptr) { return QT_PREPEND_NAMESPACE(qHash(ptr.data())); } template inline uint qHash(const WeakPtr &ptr); template class WeakPtr { typedef bool (WeakPtr::*UnspecifiedBoolType)() const; public: inline WeakPtr() : sc(0) { } explicit inline WeakPtr(T *d) { if (d) { sc = d->sc; sc->weakref.ref(); } else { sc = 0; } } inline WeakPtr(const WeakPtr &o) : sc(o.sc) { if (sc) { sc->weakref.ref(); } } inline WeakPtr(const SharedPtr &o) { if (o.d) { sc = o.d->sc; sc->weakref.ref(); } else { sc = 0; } } inline ~WeakPtr() { if (sc && !sc->weakref.deref()) { delete sc; } } inline bool isNull() const { return !sc || sc->strongref.fetchAndAddOrdered(0) <= 0; } inline bool operator!() const { return isNull(); } operator UnspecifiedBoolType() const { return !isNull() ? &WeakPtr::operator! : 0; } inline WeakPtr &operator=(const WeakPtr &o) { WeakPtr(o).swap(*this); return *this; } inline WeakPtr &operator=(const SharedPtr &o) { WeakPtr(o).swap(*this); return *this; } inline void swap(WeakPtr &o) { RefCounted::SharedCount *tmp = sc; sc = o.sc; o.sc = tmp; } SharedPtr toStrongRef() const { return SharedPtr(*this); } private: friend class SharedPtr; friend uint qHash(const WeakPtr &ptr); RefCounted::SharedCount *sc; }; template inline uint qHash(const WeakPtr &ptr) { T *actualPtr = ptr.sc ? ptr.sc.d : 0; return QT_PREPEND_NAMESPACE(qHash(actualPtr)); } } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/examples.dox0000664000175000017500000001026012470405660017545 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \page accounts_example Accounts Example * * \li \subpage accounts_example_account_item_cpp * \li \subpage accounts_example_account_item_h * \li \subpage accounts_example_accounts_window_cpp * \li \subpage accounts_example_accounts_window_h * \li \subpage accounts_example_main */ /** * \page accounts_example_account_item_cpp accounts/account-item.cpp * \include examples/accounts/account-item.cpp */ /** * \page accounts_example_account_item_h accounts/account-item.h * \include examples/accounts/account-item.h */ /** * \page accounts_example_accounts_window_cpp accounts/accounts-window.cpp * \include examples/accounts/accounts-window.cpp */ /** * \page accounts_example_accounts_window_h accounts/accounts-window.h * \include examples/accounts/accounts-window.h */ /** * \page accounts_example_main accounts/main.cpp * \include examples/accounts/main.cpp */ /** * \page contact_messenger_example Contact Messenger Example * * \li \subpage contact_messenger_example_sender_cpp * \li \subpage contact_messenger_example_sender_h */ /** * \page contact_messenger_example_sender_cpp contact-messenger/sender.cpp * \include examples/contact-messenger/sender.cpp */ /** * \page contact_messenger_example_sender_h contact-messenger/sender.h * \include examples/contact-messenger/sender.h */ /** * \page protocols_example Protocols Example * * \li \subpage protocols_example_main * \li \subpage protocols_example_cm_wrapper_cpp * \li \subpage protocols_example_cm_wrapper_h * \li \subpage protocols_example_protocols_cpp * \li \subpage protocols_example_protocols_h */ /** * \page protocols_example_main protocols/main.cpp * \include examples/protocols/main.cpp */ /** * \page protocols_example_cm_wrapper_cpp protocols/cm-wrapper.cpp * \include examples/protocols/cm-wrapper.cpp */ /** * \page protocols_example_cm_wrapper_h protocols/cm-wrapper.h * \include examples/protocols/cm-wrapper.h */ /** * \page protocols_example_protocols_cpp protocols/protocols.cpp * \include examples/protocols/protocols.cpp */ /** * \page protocols_example_protocols_h protocols/protocols.h * \include examples/protocols/protocols.h */ /** * \page roster_example Roster Example * * \li \subpage roster_example_main * \li \subpage roster_example_roster_item_cpp * \li \subpage roster_example_roster_item_h * \li \subpage roster_example_roster_widget_cpp * \li \subpage roster_example_roster_widget_h * \li \subpage roster_example_roster_window_cpp * \li \subpage roster_example_roster_window_h */ /** * \page roster_example_main roster/main.cpp * \include examples/roster/main.cpp */ /** * \page roster_example_roster_item_cpp roster/roster-item.cpp * \include examples/roster/roster-item.cpp */ /** * \page roster_example_roster_item_h roster/roster-item.h * \include examples/roster/roster-item.h */ /** * \page roster_example_roster_widget_cpp roster/roster-widget.cpp * \include examples/roster/roster-widget.cpp */ /** * \page roster_example_roster_widget_h roster/roster-widget.h * \include examples/roster/roster-widget.h */ /** * \page roster_example_roster_window_cpp roster/roster-window.cpp * \include examples/roster/roster-window.cpp */ /** * \page roster_example_roster_window_h roster/roster-window.h * \include examples/roster/roster-window.h */ telepathy-qt-0.9.6~git1/TelepathyQt/pending-channel-request.cpp0000664000175000017500000002354012470405660022444 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/pending-channel-request-internal.h" #include "TelepathyQt/_gen/pending-channel-request.moc.hpp" #include "TelepathyQt/_gen/pending-channel-request-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingChannelRequest::Private { Private(const QDBusConnection &dbusConnection) : dbusConnection(dbusConnection), cancelOperation(0) { } QDBusConnection dbusConnection; ChannelRequestPtr channelRequest; PendingChannelRequestCancelOperation *cancelOperation; }; /** * \class PendingChannelRequest * \ingroup clientchannelrequest * \headerfile TelepathyQt/pending-channel-request.h * * \brief The PendingChannelRequest class represents the parameters of and * the reply to an asynchronous ChannelRequest request. * * Instances of this class cannot be constructed directly; the only way to get * one is through Account. * * See \ref async_model */ /** * Construct a new PendingChannelRequest object. * * \param account Account to use. * \param requestedProperties A dictionary containing the desirable properties. * \param userActionTime The time at which user action occurred, or QDateTime() * if this channel request is for some reason not * involving user action. * \param preferredHandler Either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred * handler for this channel, or an empty string to * indicate that any handler would be acceptable. * \param create Whether createChannel or ensureChannel should be called. * \param account The account the request was made through. */ PendingChannelRequest::PendingChannelRequest(const AccountPtr &account, const QVariantMap &requestedProperties, const QDateTime &userActionTime, const QString &preferredHandler, bool create, const ChannelRequestHints &hints) : PendingOperation(account), mPriv(new Private(account->dbusConnection())) { QString channelDispatcherObjectPath = QString(QLatin1String("/%1")).arg(TP_QT_IFACE_CHANNEL_DISPATCHER); channelDispatcherObjectPath.replace(QLatin1String("."), QLatin1String("/")); Client::ChannelDispatcherInterface *channelDispatcherInterface = account->dispatcherInterface(); QDBusPendingCallWatcher *watcher = 0; if (create) { if (hints.isValid()) { if (account->supportsRequestHints()) { watcher = new QDBusPendingCallWatcher( channelDispatcherInterface->CreateChannelWithHints( QDBusObjectPath(account->objectPath()), requestedProperties, userActionTime.isNull() ? 0 : userActionTime.toTime_t(), preferredHandler, hints.allHints()), this); } else { warning() << "Hints passed to channel request won't have an effect" << "because the Channel Dispatcher service in use is too old"; } } if (!watcher) { watcher = new QDBusPendingCallWatcher( channelDispatcherInterface->CreateChannel( QDBusObjectPath(account->objectPath()), requestedProperties, userActionTime.isNull() ? 0 : userActionTime.toTime_t(), preferredHandler), this); } } else { if (hints.isValid()) { if (account->supportsRequestHints()) { watcher = new QDBusPendingCallWatcher( channelDispatcherInterface->EnsureChannelWithHints( QDBusObjectPath(account->objectPath()), requestedProperties, userActionTime.isNull() ? 0 : userActionTime.toTime_t(), preferredHandler, hints.allHints()), this); } else { warning() << "Hints passed to channel request won't have an effect" << "because the Channel Dispatcher service in use is too old"; } } if (!watcher) { watcher = new QDBusPendingCallWatcher( channelDispatcherInterface->EnsureChannel( QDBusObjectPath(account->objectPath()), requestedProperties, userActionTime.isNull() ? 0 : userActionTime.toTime_t(), preferredHandler), this); } } // TODO: This is a Qt bug fixed upstream, should be in the next Qt release. // We should not need to check watcher->isFinished() here, remove the // check when we depend on the fixed Qt version. if (watcher->isFinished()) { onWatcherFinished(watcher); } else { connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onWatcherFinished(QDBusPendingCallWatcher*))); } } /** * Construct a new PendingChannelRequest object that always fails. * * \param account Account to use. * \param errorName The name of a D-Bus error. * \param errorMessage The error message. */ PendingChannelRequest::PendingChannelRequest(const AccountPtr &account, const QString &errorName, const QString &errorMessage) : PendingOperation(ConnectionPtr()), mPriv(new Private(account->dbusConnection())) { setFinishedWithError(errorName, errorMessage); } /** * Class destructor. */ PendingChannelRequest::~PendingChannelRequest() { delete mPriv; } /** * Return the account through which the request was made. * * \return A pointer to the Account object. */ AccountPtr PendingChannelRequest::account() const { return AccountPtr(qobject_cast((Account*) object().data())); } ChannelRequestPtr PendingChannelRequest::channelRequest() const { return mPriv->channelRequest; } PendingOperation *PendingChannelRequest::cancel() { if (isFinished()) { // CR has already succeeded or failed, so let's just fail here return new PendingFailure(TP_QT_DBUS_ERROR_UNKNOWN_METHOD, QLatin1String("ChannnelRequest already finished"), object()); } if (!mPriv->cancelOperation) { mPriv->cancelOperation = new PendingChannelRequestCancelOperation(); connect(mPriv->cancelOperation, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onCancelOperationFinished(Tp::PendingOperation*))); if (mPriv->channelRequest) { mPriv->cancelOperation->go(mPriv->channelRequest); } } return mPriv->cancelOperation; } void PendingChannelRequest::onWatcherFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { QDBusObjectPath objectPath = reply.argumentAt<0>(); debug() << "Got reply to ChannelDispatcher.Ensure/CreateChannel " "- object path:" << objectPath.path(); if (!account().isNull()) { mPriv->channelRequest = ChannelRequest::create(account(), objectPath.path(), QVariantMap()); } if (mPriv->cancelOperation) { mPriv->cancelOperation->go(mPriv->channelRequest); } else { emit channelRequestCreated(mPriv->channelRequest); connect(mPriv->channelRequest.data(), SIGNAL(failed(QString,QString)), SLOT(setFinishedWithError(QString,QString))); connect(mPriv->channelRequest.data(), SIGNAL(succeeded(Tp::ChannelPtr)), SLOT(setFinished())); connect(mPriv->channelRequest->proceed(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onProceedOperationFinished(Tp::PendingOperation*))); } } else { debug().nospace() << "Ensure/CreateChannel failed:" << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } void PendingChannelRequest::onProceedOperationFinished(PendingOperation *op) { if (op->isError()) { setFinishedWithError(op->errorName(), op->errorMessage()); } } void PendingChannelRequest::onCancelOperationFinished(PendingOperation *op) { mPriv->cancelOperation = 0; if (!isFinished()) { setFinishedWithError(TP_QT_ERROR_CANCELLED, QLatin1String("ChannelRequest cancelled")); } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/captcha-authentication-internal.h0000664000175000017500000000531712470405660023625 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_captcha_authentication_internal_h_HEADER_GUARD_ #define _TelepathyQt_captcha_authentication_internal_h_HEADER_GUARD_ #include #include namespace Tp { class PendingVoid; class TP_QT_NO_EXPORT PendingCaptchaAnswer : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingCaptchaAnswer) public: PendingCaptchaAnswer(const QDBusPendingCall &call, const CaptchaAuthenticationPtr &object); ~PendingCaptchaAnswer(); private Q_SLOTS: void onCaptchaStatusChanged(Tp::CaptchaStatus status); void onAnswerFinished(); void onRequestCloseFinished(Tp::PendingOperation *operation); private: // Public object PendingCaptchaAnswer *mParent; QDBusPendingCallWatcher *mWatcher; CaptchaAuthenticationPtr mCaptcha; ChannelPtr mChannel; }; class TP_QT_NO_EXPORT PendingCaptchaCancel : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingCaptchaCancel) public: PendingCaptchaCancel(const QDBusPendingCall &call, const CaptchaAuthenticationPtr &object); ~PendingCaptchaCancel(); private Q_SLOTS: void onCancelFinished(); void onRequestCloseFinished(Tp::PendingOperation *operation); private: // Public object PendingCaptchaCancel *mParent; QDBusPendingCallWatcher *mWatcher; CaptchaAuthenticationPtr mCaptcha; ChannelPtr mChannel; }; struct TP_QT_NO_EXPORT CaptchaAuthentication::Private { Private(CaptchaAuthentication *parent); void extractCaptchaAuthenticationProperties(const QVariantMap &props); // Public object CaptchaAuthentication *parent; WeakPtr channel; // Introspection bool canRetry; CaptchaStatus status; QString error; QVariantMap errorDetails; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/protocol-parameter.h0000664000175000017500000000546512470405660021216 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_protocol_parameter_h_HEADER_GUARD_ #define _TelepathyQt_protocol_parameter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include namespace Tp { class TP_QT_EXPORT ProtocolParameter { public: ProtocolParameter(); ProtocolParameter(const ParamSpec &spec); ProtocolParameter(const QString &name, const QDBusSignature &dbusSignature, ConnMgrParamFlags flags, QVariant defaultValue = QVariant()); ProtocolParameter(const QString &name, const QString &dbusSignature, ConnMgrParamFlags flags, QVariant defaultValue = QVariant()); ProtocolParameter(const ProtocolParameter &other); ~ProtocolParameter(); bool isValid() const { return mPriv.constData() != 0; } ProtocolParameter &operator=(const ProtocolParameter &other); bool operator==(const ProtocolParameter &other) const; bool operator==(const QString &name) const; bool operator<(const ProtocolParameter &other) const; QString name() const; QDBusSignature dbusSignature() const; QVariant::Type type() const; QVariant defaultValue() const; bool isRequired() const; bool isSecret() const; bool isRequiredForRegistration() const; ParamSpec bareParameter() const; private: friend class ConnectionManager; friend class ProtocolInfo; struct Private; friend struct Private; QSharedDataPointer mPriv; }; typedef QList ProtocolParameterList; uint qHash(const ProtocolParameter ¶meter); } // Tp Q_DECLARE_METATYPE(Tp::ProtocolParameter); Q_DECLARE_METATYPE(Tp::ProtocolParameterList); #endif telepathy-qt-0.9.6~git1/TelepathyQt/Client0000664000175000017500000000034012470405660016352 0ustar jrjr#ifndef _TelepathyQt_Client_HEADER_GUARD_ #define _TelepathyQt_Client_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/BaseChannel0000664000175000017500000000036012470405660017301 0ustar jrjr#ifndef _TelepathyQt_BaseChannel_HEADER_GUARD_ #define _TelepathyQt_BaseChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/RequestableChannelClassSpecList0000664000175000017500000000045212470405660023342 0ustar jrjr#ifndef _TelepathyQt_RequestableChannelClassSpecList_HEADER_GUARD_ #define _TelepathyQt_RequestableChannelClassSpecList_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ProtocolParameterList0000664000175000017500000000041212470405660021432 0ustar jrjr#ifndef _TelepathyQt_ProtocolParameterList_HEADER_GUARD_ #define _TelepathyQt_ProtocolParameterList_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-string-list.h0000664000175000017500000000334712470405660021275 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_string_list_h_HEADER_GUARD_ #define _TelepathyQt_pending_string_list_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT PendingStringList : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingStringList); public: PendingStringList(const SharedPtr &object); PendingStringList(QDBusPendingCall call, const SharedPtr &object); ~PendingStringList(); QStringList result() const; protected: void setResult(const QStringList &result); private Q_SLOTS: TP_QT_NO_EXPORT void watcherFinished(QDBusPendingCallWatcher *watcher); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/feature.h0000664000175000017500000000454312470405660017026 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_feature_h_HEADER_GUARD_ #define _TelepathyQt_feature_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include namespace Tp { class TP_QT_EXPORT Feature : public QPair { public: Feature(); Feature(const QString &className, uint id, bool critical = false); Feature(const Feature &other); ~Feature(); bool isValid() const { return mPriv.constData() != 0; } Feature &operator=(const Feature &other); bool isCritical() const; private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; class TP_QT_EXPORT Features : public QSet { public: Features() { } Features(const Feature &feature) { insert(feature); } Features(const QSet &s) : QSet(s) { } }; inline Features operator|(const Feature &feature1, const Feature &feature2) { return Features() << feature1 << feature2; } inline Features operator|(const Features &features, const Feature &feature) { return Features(features) << feature; } inline uint qHash(const Features &features) { int ret = 0; Q_FOREACH (const Feature &feature, features) { int h = qHash(feature); ret ^= h; } return ret; } } // Tp Q_DECLARE_METATYPE(Tp::Feature); Q_DECLARE_METATYPE(Tp::Features); #endif telepathy-qt-0.9.6~git1/TelepathyQt/avatar.h0000664000175000017500000000451712470405660016652 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2011 Collabora Ltd. * @copyright Copyright (C) 2010-2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_avatar_h_HEADER_GUARD_ #define _TelepathyQt_avatar_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include namespace Tp { struct TP_QT_EXPORT AvatarData { public: inline AvatarData(const QString &fileName, const QString &mimeType) : fileName(fileName), mimeType(mimeType) {} inline AvatarData() {} QString fileName; QString mimeType; }; class TP_QT_EXPORT AvatarSpec { public: AvatarSpec(); AvatarSpec(const QStringList &supportedMimeTypes, uint minHeight, uint maxHeight, uint recommendedHeight, uint minWidth, uint maxWidth, uint recommendedWidth, uint maxBytes); AvatarSpec(const AvatarSpec &other); ~AvatarSpec(); bool isValid() const { return mPriv.constData() != 0; } AvatarSpec &operator=(const AvatarSpec &other); QStringList supportedMimeTypes() const; uint minimumHeight() const; uint maximumHeight() const; uint recommendedHeight() const; uint minimumWidth() const; uint maximumWidth() const; uint recommendedWidth() const; uint maximumBytes() const; private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::AvatarData); Q_DECLARE_METATYPE(Tp::AvatarSpec); #endif telepathy-qt-0.9.6~git1/TelepathyQt/base-connection-manager-internal.h0000664000175000017500000000435212470405660023662 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/_gen/svc-connection-manager.h" #include #include #include #include #include #include #include namespace Tp { class TP_QT_NO_EXPORT BaseConnectionManager::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QStringList interfaces READ interfaces) Q_PROPERTY(Tp::ProtocolPropertiesMap protocols READ protocols) public: Adaptee(const QDBusConnection &dbusConnection, BaseConnectionManager *cm); ~Adaptee(); QStringList interfaces() const; Tp::ProtocolPropertiesMap protocols() const; Q_SIGNALS: void newConnection(const QString &busName, const QDBusObjectPath &objectPath, const QString &protocolName); private Q_SLOTS: void getParameters(const QString &protocolName, const Tp::Service::ConnectionManagerAdaptor::GetParametersContextPtr &context); void listProtocols( const Tp::Service::ConnectionManagerAdaptor::ListProtocolsContextPtr &context); void requestConnection(const QString &protocolName, const QVariantMap ¶meters, const Tp::Service::ConnectionManagerAdaptor::RequestConnectionContextPtr &context); public: BaseConnectionManager *mCM; Service::ConnectionManagerAdaptor *mAdaptor; }; } telepathy-qt-0.9.6~git1/TelepathyQt/AccountFilter0000664000175000017500000000036612470405660017706 0ustar jrjr#ifndef _TelepathyQt_AccountFilter_HEADER_GUARD_ #define _TelepathyQt_AccountFilter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/simple-text-observer-internal.h0000664000175000017500000000442312470405660023302 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT SimpleTextObserver::Private { Private(SimpleTextObserver *parent, const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization); ~Private(); class TextChannelWrapper; SimpleTextObserver *parent; AccountPtr account; QString contactIdentifier; SimpleObserverPtr observer; QHash channels; }; class TP_QT_NO_EXPORT SimpleTextObserver::Private::TextChannelWrapper : public QObject { Q_OBJECT Q_DISABLE_COPY(TextChannelWrapper) public: TextChannelWrapper(const Tp::TextChannelPtr &channel); ~TextChannelWrapper() { } Q_SIGNALS: void channelMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken, const Tp::TextChannelPtr &channel); void channelMessageReceived(const Tp::ReceivedMessage &message, const Tp::TextChannelPtr &channel); private Q_SLOTS: void onChannelMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken); void onChannelMessageReceived(const Tp::ReceivedMessage &message); private: TextChannelPtr mChannel; }; } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/CallStreamEndpoint0000664000175000017500000000040612470405660020667 0ustar jrjr#ifndef _TelepathyQt_CallStreamEndpoint_HEADER_GUARD_ #define _TelepathyQt_CallStreamEndpoint_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/account-set-internal.h0000664000175000017500000000522312470405660021426 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include namespace Tp { class ConnectionCapabilities; struct TP_QT_NO_EXPORT AccountSet::Private { class AccountWrapper; Private(AccountSet *parent, const AccountManagerPtr &accountManager, const AccountFilterConstPtr &filter); Private(AccountSet *parent, const AccountManagerPtr &accountManager, const QVariantMap &filter); void init(); void connectSignals(); void insertAccounts(); void insertAccount(const AccountPtr &account); void removeAccount(const AccountPtr &account); void wrapAccount(const AccountPtr &account); void filterAccount(const AccountPtr &account); bool accountMatchFilter(AccountWrapper *account); AccountSet *parent; AccountManagerPtr accountManager; AccountFilterConstPtr filter; QHash wrappers; QHash accounts; bool ready; }; class TP_QT_NO_EXPORT AccountSet::Private::AccountWrapper : public QObject { Q_OBJECT public: AccountWrapper(const AccountPtr &account, QObject *parent = 0); ~AccountWrapper(); AccountPtr account() const { return mAccount; } Q_SIGNALS: void accountRemoved(const Tp::AccountPtr &account); void accountPropertyChanged(const Tp::AccountPtr &account, const QString &propertyName); void accountCapabilitiesChanged(const Tp::AccountPtr &account, const Tp::ConnectionCapabilities &capabilities); private Q_SLOTS: TP_QT_NO_EXPORT void onAccountRemoved(); TP_QT_NO_EXPORT void onAccountPropertyChanged(const QString &propertyName); TP_QT_NO_EXPORT void onAccountCapalitiesChanged(const Tp::ConnectionCapabilities &capabilities); private: AccountPtr mAccount; }; } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/PendingOperation0000664000175000017500000000037712470405660020413 0ustar jrjr#ifndef _TelepathyQt_PendingOperation_HEADER_GUARD_ #define _TelepathyQt_PendingOperation_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-string.h0000664000175000017500000000340012470405660020312 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_string_h_HEADER_GUARD_ #define _TelepathyQt_pending_string_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT PendingString : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingString); public: PendingString(QDBusPendingCall call, const SharedPtr &object); ~PendingString(); QString result() const; protected: void setResult(const QString &result); private Q_SLOTS: TP_QT_NO_EXPORT void watcherFinished(QDBusPendingCallWatcher *watcher); private: friend class ProtocolInfo; TP_QT_NO_EXPORT PendingString(const QString &errorName, const QString &errorMessage); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/svc-channel.xml0000664000175000017500000000422312470405660020140 0ustar jrjr Channel interfaces telepathy-qt-0.9.6~git1/TelepathyQt/channel-dispatcher.cpp0000664000175000017500000000211312470405660021451 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/cli-channel-dispatcher-body.hpp" #include "TelepathyQt/_gen/cli-channel-dispatcher.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/pending-account.cpp0000664000175000017500000001371612470405660021006 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-account.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingAccount::Private { AccountPtr account; }; /** * \class PendingAccount * \ingroup clientaccount * \headerfile TelepathyQt/pending-account.h * * \brief The PendingAccount class represents the parameters of and the reply to * an asynchronous account request. * * Instances of this class cannot be constructed directly; the only way to get * one is via AccountManager. * * See \ref async_model */ /** * Construct a new PendingAccount object. * * \param manager AccountManager to use. * \param connectionManager Name of the connection manager to create the account * for. * \param protocol Name of the protocol to create the account for. * \param displayName Account display name. * \param parameters Account parameters. * \param properties An optional map from fully qualified D-Bus property * names such as "org.freedesktop.Telepathy.Account.Enabled" * to their values. */ PendingAccount::PendingAccount(const AccountManagerPtr &manager, const QString &connectionManager, const QString &protocol, const QString &displayName, const QVariantMap ¶meters, const QVariantMap &properties) : PendingOperation(manager), mPriv(new Private) { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( manager->baseInterface()->CreateAccount(connectionManager, protocol, displayName, parameters, properties), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onCallFinished(QDBusPendingCallWatcher*))); } /** * Class destructor. */ PendingAccount::~PendingAccount() { delete mPriv; } /** * Return the account manager through which the request was made. * * \return A pointer to the AccountManager object. */ AccountManagerPtr PendingAccount::manager() const { return AccountManagerPtr(qobject_cast((AccountManager*) object().data())); } /** * Return the newly created account. * * \return A pointer to an Account object, or a null AccountPtr if an error occurred. */ AccountPtr PendingAccount::account() const { if (!isFinished()) { warning() << "PendingAccount::account called before finished, returning 0"; return AccountPtr(); } else if (!isValid()) { warning() << "PendingAccount::account called when not valid, returning 0"; return AccountPtr(); } return mPriv->account; } void PendingAccount::onCallFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { QString objectPath = reply.value().path(); debug() << "Got reply to AccountManager.CreateAccount - object path:" << objectPath; PendingReady *readyOp = manager()->accountFactory()->proxy(manager()->busName(), objectPath, manager()->connectionFactory(), manager()->channelFactory(), manager()->contactFactory()); mPriv->account = AccountPtr::qObjectCast(readyOp->proxy()); connect(readyOp, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountBuilt(Tp::PendingOperation*))); } else { debug().nospace() << "CreateAccount failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } void PendingAccount::onAccountBuilt(Tp::PendingOperation *op) { Q_ASSERT(op->isFinished()); if (op->isError()) { warning() << "Making account ready using the factory failed:" << op->errorName() << op->errorMessage(); setFinishedWithError(op->errorName(), op->errorMessage()); } else { // AM is stateless, so the only way for it to become invalid is in the introspection phase, // and a PendingAccount should never be created if AM introspection hasn't succeeded Q_ASSERT(!manager().isNull() && manager()->isValid()); if (manager()->allAccounts().contains(mPriv->account)) { setFinished(); debug() << "New account" << mPriv->account->objectPath() << "built"; } else { // Have to wait for the AM to pick up the change and signal it so the world can be // assumed to be ~round when we finish connect(manager().data(), SIGNAL(newAccount(Tp::AccountPtr)), SLOT(onNewAccount(Tp::AccountPtr))); } } } void PendingAccount::onNewAccount(const AccountPtr &account) { if (account != mPriv->account) { return; } debug() << "Account" << account->objectPath() << "added to AM, finishing PendingAccount"; setFinished(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/CallContentMediaDescriptionInterfaceRTPHeaderExtensionsInterface0000664000175000017500000000055412470405660031736 0ustar jrjr#ifndef _TelepathyQt_CallContentMediaDescriptionInterfaceRTPHeaderExtensionsInterface_HEADER_GUARD_ #define _TelepathyQt_CallContentMediaDescriptionInterfaceRTPHeaderExtensionsInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/stream-tube-channel.cpp0000664000175000017500000006715312470405660021572 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/stream-tube-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT StreamTubeChannel::Private { Private(StreamTubeChannel *parent); static void introspectStreamTube(Private *self); static void introspectConnectionMonitoring(Private *self); void extractStreamTubeProperties(const QVariantMap &props); // Public object StreamTubeChannel *parent; ReadinessHelper *readinessHelper; // Introspection SupportedSocketMap socketTypes; QString serviceName; QSet connections; QPair ipAddress; QString unixAddress; SocketAddressType addressType; SocketAccessControl accessControl; bool droppingConnections; }; StreamTubeChannel::Private::Private(StreamTubeChannel *parent) : parent(parent), readinessHelper(parent->readinessHelper()), addressType(SocketAddressTypeUnix), accessControl(SocketAccessControlLocalhost), droppingConnections(false) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableStreamTube( QSet() << 0, // makesSenseForStatuses Features() << TubeChannel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &StreamTubeChannel::Private::introspectStreamTube, this); introspectables[StreamTubeChannel::FeatureCore] = introspectableStreamTube; ReadinessHelper::Introspectable introspectableConnectionMonitoring( QSet() << 0, // makesSenseForStatuses Features() << StreamTubeChannel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &StreamTubeChannel::Private::introspectConnectionMonitoring, this); introspectables[StreamTubeChannel::FeatureConnectionMonitoring] = introspectableConnectionMonitoring; parent->connect( parent, SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(dropConnections())); readinessHelper->addIntrospectables(introspectables); } void StreamTubeChannel::Private::introspectStreamTube( StreamTubeChannel::Private *self) { StreamTubeChannel *parent = self->parent; debug() << "Introspecting stream tube properties"; Client::ChannelTypeStreamTubeInterface *streamTubeInterface = parent->interface(); PendingVariantMap *pvm = streamTubeInterface->requestAllProperties(); parent->connect(pvm, SIGNAL(finished(Tp::PendingOperation *)), SLOT(gotStreamTubeProperties(Tp::PendingOperation *))); } void StreamTubeChannel::Private::introspectConnectionMonitoring( StreamTubeChannel::Private *self) { StreamTubeChannel *parent = self->parent; Client::ChannelTypeStreamTubeInterface *streamTubeInterface = parent->interface(); parent->connect(streamTubeInterface, SIGNAL(ConnectionClosed(uint,QString,QString)), SLOT(onConnectionClosed(uint,QString,QString))); if (parent->isRequested()) { parent->connect(streamTubeInterface, SIGNAL(NewRemoteConnection(uint,QDBusVariant,uint)), SLOT(onNewRemoteConnection(uint,QDBusVariant,uint))); } else { parent->connect(streamTubeInterface, SIGNAL(NewLocalConnection(uint)), SLOT(onNewLocalConnection(uint))); } self->readinessHelper->setIntrospectCompleted( StreamTubeChannel::FeatureConnectionMonitoring, true); } void StreamTubeChannel::Private::extractStreamTubeProperties(const QVariantMap &props) { serviceName = qdbus_cast(props[QLatin1String("Service")]); socketTypes = qdbus_cast(props[QLatin1String("SupportedSocketTypes")]); } /** * \class StreamTubeChannel * \ingroup clientchannel * \headerfile TelepathyQt/stream-tube-channel.h * * \brief The StreamTubeChannel class represents a Telepathy channel of type StreamTube. * * It provides a transport for reliable and ordered data transfer, similar to SOCK_STREAM sockets. * * StreamTubeChannel is an intermediate base class; OutgoingStreamTubeChannel and * IncomingStreamTubeChannel are the specialized classes used for locally and remotely initiated * tubes respectively. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * StreamTubeChannel object usable. * * Note that this feature must be enabled in order to use most * StreamTubeChannel methods. * See specific methods documentation for more details. */ const Feature StreamTubeChannel::FeatureCore = Feature(QLatin1String(StreamTubeChannel::staticMetaObject.className()), 0); /** * Feature used in order to monitor connections to this stream tube. * * See connection monitoring specific methods' documentation for more details. * * \sa newConnection(), connectionClosed() */ const Feature StreamTubeChannel::FeatureConnectionMonitoring = Feature(QLatin1String(StreamTubeChannel::staticMetaObject.className()), 1); /** * Create a new StreamTubeChannel channel. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A StreamTubeChannelPtr object pointing to the newly created * StreamTubeChannel object. */ StreamTubeChannelPtr StreamTubeChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return StreamTubeChannelPtr(new StreamTubeChannel(connection, objectPath, immutableProperties, StreamTubeChannel::FeatureCore)); } /** * Construct a new StreamTubeChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on StreamTubeChannel::FeatureCore. */ StreamTubeChannel::StreamTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : TubeChannel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ StreamTubeChannel::~StreamTubeChannel() { delete mPriv; } /** * Return the service name which will be used over this stream tube. This should be a * well-known TCP service name, for instance "rsync" or "daap". * * This method requires StreamTubeChannel::FeatureCore to be ready. * * \return The service name. */ QString StreamTubeChannel::service() const { if (!isReady(FeatureCore)) { warning() << "StreamTubeChannel::service() used with " "FeatureCore not ready"; return QString(); } return mPriv->serviceName; } /** * Return whether this stream tube is capable to accept or offer an IPv4 socket accepting all * incoming connections coming from localhost. * * Note that the \telepathy_spec implies that any connection manager, if capable of providing * stream tubes, must at least support IPv4 sockets with localhost access control. * For this reason, this method should always return \c true. * * This method requires StreamTubeChannel::FeatureCore to be ready. * * \return \c true if the stream tube is capable to accept or offer an IPv4 socket * accepting all incoming connections coming from localhost, \c false otherwise. * \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(), * OutgoingStreamTubeChannel::offerTcpSocket(), * supportsIPv4SocketsWithSpecifiedAddress() */ bool StreamTubeChannel::supportsIPv4SocketsOnLocalhost() const { if (!isReady(FeatureCore)) { warning() << "StreamTubeChannel::supportsIPv4SocketsOnLocalhost() used with " "FeatureCore not ready"; return false; } return mPriv->socketTypes.value(SocketAddressTypeIPv4).contains(SocketAccessControlLocalhost); } /** * Return whether this stream tube is capable to accept an IPv4 socket accepting all * incoming connections coming from a specific address for incoming tubes or whether * this stream tube is capable of mapping connections to the socket's source address for outgoing * tubes. * * For incoming tubes, when this capability is available, the stream tube can be accepted specifying * an IPv4 address. Every connection coming from any other address than the specified one will be * rejected. * * For outgoing tubes, when this capability is available, one can keep track of incoming connections * by enabling StreamTubeChannel::FeatureConnectionMonitoring (possibly before * opening the stream tube itself), and checking OutgoingStreamTubeChannel::contactsForConnections() * or OutgoingStreamTubeChannel::connectionsForSourceAddresses(). * * Note that it is strongly advised to call this method before attempting to call * IncomingStreamTubeChannel::acceptTubeAsTcpSocket() or * OutgoingStreamTubeChannel::offerTcpSocket() with a specified address to prevent failures, * as the spec implies this feature is not compulsory for connection managers. * * This method requires StreamTubeChannel::FeatureCore to be ready. * * \return \c true if the stream tube is capable to accept an IPv4 socket accepting all * incoming connections coming from a specific address for incoming tubes or * the stream tube is capable of mapping connections to the socket's source address for * outgoing tubes, \c false otherwise. * \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(), * OutgoingStreamTubeChannel::offerTcpSocket(), * OutgoingStreamTubeChannel::connectionsForSourceAddresses(), * OutgoingStreamTubeChannel::contactsForConnections(), * supportsIPv4SocketsOnLocalhost() */ bool StreamTubeChannel::supportsIPv4SocketsWithSpecifiedAddress() const { if (!isReady(FeatureCore)) { warning() << "StreamTubeChannel::supportsIPv4SocketsWithSpecifiedAddress() used with " "FeatureCore not ready"; return false; } return mPriv->socketTypes.value(SocketAddressTypeIPv4).contains(SocketAccessControlPort); } /** * Return whether this stream tube is capable to accept or offer an IPv6 socket accepting all * incoming connections coming from localhost. * * Note that it is strongly advised to call this method before attempting to call * IncomingStreamTubeChannel::acceptTubeAsTcpSocket() or * OutgoingStreamTubeChannel::offerTcpSocket() with a specified address to prevent failures, * as the spec implies this feature is not compulsory for connection managers. * * This method requires StreamTubeChannel::FeatureCore to be ready. * * \return \c true if the stream tube is capable to accept or offer an IPv6 socket * accepting all incoming connections coming from localhost, \c false otherwise. * \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(), * OutgoingStreamTubeChannel::offerTcpSocket(), * supportsIPv6SocketsWithSpecifiedAddress() */ bool StreamTubeChannel::supportsIPv6SocketsOnLocalhost() const { if (!isReady(FeatureCore)) { warning() << "StreamTubeChannel::supportsIPv6SocketsOnLocalhost() used with " "FeatureCore not ready"; return false; } return mPriv->socketTypes.value(SocketAddressTypeIPv6).contains(SocketAccessControlLocalhost); } /** * Return whether this stream tube is capable to accept an IPv6 socket accepting all * incoming connections coming from a specific address for incoming tubes or whether * this stream tube is capable of mapping connections to the socket's source address for outgoing * tubes. * * For incoming tubes, when this capability is available, the stream tube can be accepted specifying * an IPv6 address. Every connection coming from any other address than the specified one will be * rejected. * * For outgoing tubes, when this capability is available, one can keep track of incoming connections * by enabling StreamTubeChannel::FeatureConnectionMonitoring (possibly before * opening the stream tube itself), and checking OutgoingStreamTubeChannel::contactsForConnections() * or OutgoingStreamTubeChannel::connectionsForSourceAddresses(). * * Note that it is strongly advised to call this method before attempting to call * IncomingStreamTubeChannel::acceptTubeAsTcpSocket() or * OutgoingStreamTubeChannel::offerTcpSocket() with a specified address to prevent failures, * as the spec implies this feature is not compulsory for connection managers. * * This method requires StreamTubeChannel::FeatureCore to be ready. * * \return \c true if the stream tube is capable to accept an IPv6 socket accepting all * incoming connections coming from a specific address for incoming tubes or * the stream tube is capable of mapping connections to the socket's source address for * outgoing tubes, \c false otherwise. * \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(), * OutgoingStreamTubeChannel::offerTcpSocket(), * OutgoingStreamTubeChannel::connectionsForSourceAddresses(), * OutgoingStreamTubeChannel::contactsForConnections(), * supportsIPv6SocketsOnLocalhost() */ bool StreamTubeChannel::supportsIPv6SocketsWithSpecifiedAddress() const { if (!isReady(FeatureCore)) { warning() << "StreamTubeChannel::supportsIPv6SocketsWithSpecifiedAddress() used with " "FeatureCore not ready"; return false; } return mPriv->socketTypes.value(SocketAddressTypeIPv6).contains(SocketAccessControlPort); } /** * Return whether this stream tube is capable to accept or offer an Unix socket accepting all * incoming connections coming from localhost. * * Note that it is strongly advised to call this method before attempting to call * IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or * OutgoingStreamTubeChannel::offerUnixSocket() without credentials enabled, as the spec implies * this feature is not compulsory for connection managers. * * This method requires StreamTubeChannel::FeatureCore to be ready. * * \return \c true if the stream tube is capable to accept or offer an Unix socket * accepting all incoming connections coming from localhost, \c false otherwise. * \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(), * OutgoingStreamTubeChannel::offerUnixSocket(), * supportsUnixSocketsWithCredentials() * supportsAbstractUnixSocketsOnLocalhost(), * supportsAbstractUnixSocketsWithCredentials(), */ bool StreamTubeChannel::supportsUnixSocketsOnLocalhost() const { if (!isReady(FeatureCore)) { warning() << "StreamTubeChannel::supportsUnixSocketsOnLocalhost() used with " "FeatureCore not ready"; return false; } return mPriv->socketTypes.value(SocketAddressTypeUnix).contains(SocketAccessControlLocalhost); } /** * Return whether this stream tube is capable to accept or offer an Unix socket which will require * credentials upon connection. * * When this capability is available and enabled, the connecting process must send a byte when * it first connects, which is not considered to be part of the data stream. * If the operating system uses sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass * credentials over sockets, the connecting process must do so if possible; * if not, it must still send the byte. * * The listening process will disconnect the connection unless it can determine * by OS-specific means that the connecting process has the same user ID as the listening process. * * Note that it is strongly advised to call this method before attempting to call * IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or * OutgoingStreamTubeChannel::offerUnixSocket() with credentials enabled, as the spec implies * this feature is not compulsory for connection managers. * * This method requires StreamTubeChannel::FeatureCore to be ready. * * \return \c true if the stream tube is capable to accept or offer an Unix socket * which will require credentials upon connection, \c false otherwise. * \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(), * OutgoingStreamTubeChannel::offerUnixSocket(), * supportsUnixSocketsOnLocalhost(), * supportsAbstractUnixSocketsOnLocalhost(), * supportsAbstractUnixSocketsWithCredentials(), */ bool StreamTubeChannel::supportsUnixSocketsWithCredentials() const { if (!isReady(FeatureCore)) { warning() << "StreamTubeChannel::supportsUnixSocketsWithCredentials() used with " "FeatureCore not ready"; return false; } return mPriv->socketTypes[SocketAddressTypeUnix].contains(SocketAccessControlCredentials); } /** * Return whether this stream tube is capable to accept or offer an abstract Unix socket accepting * all incoming connections coming from localhost. * * Note that it is strongly advised to call this method before attempting to call * IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or * OutgoingStreamTubeChannel::offerUnixSocket() without credentials enabled, as the spec implies * this feature is not compulsory for connection managers. * * This method requires StreamTubeChannel::FeatureCore to be ready. * * \return \c true if the stream tube is capable to accept or offer an abstract Unix socket * accepting all incoming connections coming from localhost, \c false otherwise. * \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(), * OutgoingStreamTubeChannel::offerUnixSocket(), * supportsUnixSocketsOnLocalhost(), * supportsUnixSocketsWithCredentials(), * supportsAbstractUnixSocketsWithCredentials() */ bool StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost() const { if (!isReady(FeatureCore)) { warning() << "StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost() used with " "FeatureCore not ready"; return false; } return mPriv->socketTypes[SocketAddressTypeAbstractUnix].contains(SocketAccessControlLocalhost); } /** * Return whether this stream tube is capable to accept or offer an abstract Unix socket which will * require credentials upon connection. * * When this capability is available and enabled, the connecting process must send a byte when * it first connects, which is not considered to be part of the data stream. * If the operating system uses sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass * credentials over sockets, the connecting process must do so if possible; * if not, it must still send the byte. * * The listening process will disconnect the connection unless it can determine * by OS-specific means that the connecting process has the same user ID as the listening process. * * Note that it is strongly advised to call this method before attempting to call * IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or * OutgoingStreamTubeChannel::offerUnixSocket() with credentials enabled, as the spec implies * this feature is not compulsory for connection managers. * * This method requires StreamTubeChannel::FeatureCore to be ready. * * \return \c true if the stream tube is capable to accept or offer an abstract Unix socket * which will require credentials upon connection, \c false otherwise. * \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(), * OutgoingStreamTubeChannel::offerUnixSocket(), * supportsUnixSocketsOnLocalhost(), * supportsUnixSocketsWithCredentials(), * supportsAbstractUnixSocketsOnLocalhost() */ bool StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials() const { if (!isReady(FeatureCore)) { warning() << "StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials() used with " "FeatureCore not ready"; return false; } return mPriv->socketTypes[SocketAddressTypeAbstractUnix].contains(SocketAccessControlCredentials); } /** * Return all the known active connections since StreamTubeChannel::FeatureConnectionMonitoring has * been enabled. * * For this method to return all known connections, you need to make * StreamTubeChannel::FeatureConnectionMonitoring ready before accepting or offering the stream * tube. * * This method requires StreamTubeChannel::FeatureConnectionMonitoring to be ready. * * \return The list of active connection ids. * \sa newConnection(), connectionClosed() */ QSet StreamTubeChannel::connections() const { if (!isReady(FeatureConnectionMonitoring)) { warning() << "StreamTubeChannel::connections() used with " "FeatureConnectionMonitoring not ready"; return QSet(); } return mPriv->connections; } /** * Return the type of the tube's local endpoint socket. * * Note that this function will return a valid value only after state() has gone #TubeStateOpen. * * \return The socket type as #SocketAddressType. * \sa localAddress(), ipAddress() */ SocketAddressType StreamTubeChannel::addressType() const { return mPriv->addressType; } /** * Return the access control used by this stream tube. * * Note that this function will only return a valid value after state() has gone #TubeStateOpen. * * \return The access control as #SocketAccessControl. * \sa addressType() */ SocketAccessControl StreamTubeChannel::accessControl() const { return mPriv->accessControl; } /** * Return the IP address/port combination used by this stream tube. * * This method will return a meaningful value only if the local endpoint socket for the tube is a * TCP socket, i.e. addressType() is #SocketAddressTypeIPv4 or #SocketAddressTypeIPv6. * * Note that this function will return a valid value only after state() has gone #TubeStateOpen. * * \return Pair of IP address as QHostAddress and port if using a TCP socket, * or an undefined value otherwise. * \sa localAddress() */ QPair StreamTubeChannel::ipAddress() const { if (state() != TubeChannelStateOpen) { warning() << "Tube not open, returning invalid IP address"; return qMakePair(QHostAddress::Null, 0); } return mPriv->ipAddress; } /** * Return the local address used by this stream tube. * * This method will return a meaningful value only if the local endpoint socket for the tube is an * UNIX socket, i.e. addressType() is #SocketAddressTypeUnix or #SocketAddressTypeAbstractUnix. * * Note that this function will return a valid value only after state() has gone #TubeStateOpen. * * \return Unix socket address if using an Unix socket, * or an undefined value otherwise. * \sa ipAddress() */ QString StreamTubeChannel::localAddress() const { if (state() != TubeChannelStateOpen) { warning() << "Tube not open, returning invalid local socket address"; return QString(); } return mPriv->unixAddress; } void StreamTubeChannel::addConnection(uint connection) { if (!mPriv->connections.contains(connection)) { mPriv->connections.insert(connection); emit newConnection(connection); } else { warning() << "Tried to add connection" << connection << "on StreamTube" << objectPath() << "but it already was there"; } } void StreamTubeChannel::removeConnection(uint connection, const QString &error, const QString &message) { if (mPriv->connections.contains(connection)) { mPriv->connections.remove(connection); emit connectionClosed(connection, error, message); } else { warning() << "Tried to remove connection" << connection << "from StreamTube" << objectPath() << "but it wasn't there"; } } void StreamTubeChannel::setAddressType(SocketAddressType type) { mPriv->addressType = type; } void StreamTubeChannel::setAccessControl(SocketAccessControl accessControl) { mPriv->accessControl = accessControl; } void StreamTubeChannel::setIpAddress(const QPair &address) { mPriv->ipAddress = address; } void StreamTubeChannel::setLocalAddress(const QString &address) { mPriv->unixAddress = address; } bool StreamTubeChannel::isDroppingConnections() const { return mPriv->droppingConnections; } void StreamTubeChannel::gotStreamTubeProperties(PendingOperation *op) { if (!op->isError()) { PendingVariantMap *pvm = qobject_cast(op); mPriv->extractStreamTubeProperties(pvm->result()); debug() << "Got reply to Properties::GetAll(StreamTubeChannel)"; mPriv->readinessHelper->setIntrospectCompleted(StreamTubeChannel::FeatureCore, true); } else { warning().nospace() << "Properties::GetAll(StreamTubeChannel) failed " "with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(StreamTubeChannel::FeatureCore, false, op->errorName(), op->errorMessage()); } } void StreamTubeChannel::onConnectionClosed(uint connId, const QString &error, const QString &message) { removeConnection(connId, error, message); } void StreamTubeChannel::dropConnections() { if (!mPriv->connections.isEmpty()) { debug() << "StreamTubeChannel invalidated with" << mPriv->connections.size() << "connections remaining, synthesizing close events"; mPriv->droppingConnections = true; foreach (uint connId, mPriv->connections) { removeConnection(connId, TP_QT_ERROR_ORPHANED, QLatin1String("parent tube invalidated, streams closing")); } mPriv->droppingConnections = false; } } /** * \fn void StreamTubeChannel::connectionClosed(uint connectionId, * const QString &errorName, const QString &errorMessage) * * Emitted when a connection on this stream tube has been closed. * * \param connectionId The unique ID associated with the connection that was closed. * \param errorName The name of a D-Bus error describing the error that occurred. * \param errorMessage A debugging message associated with the error. * \sa newConnection(), connections() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/base-channel-internal.h0000664000175000017500000004765212470405660021535 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2013 Matthias Gehre * @copyright Copyright 2013 Canonical Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/_gen/svc-channel.h" #include #include #include #include "TelepathyQt/debug-internal.h" namespace Tp { class TP_QT_NO_EXPORT BaseChannel::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QString channelType READ channelType) Q_PROPERTY(QStringList interfaces READ interfaces) Q_PROPERTY(uint targetHandle READ targetHandle) Q_PROPERTY(QString targetID READ targetID) Q_PROPERTY(uint targetHandleType READ targetHandleType) Q_PROPERTY(bool requested READ requested) Q_PROPERTY(uint initiatorHandle READ initiatorHandle) Q_PROPERTY(QString initiatorID READ initiatorID) public: Adaptee(const QDBusConnection &dbusConnection, BaseChannel *cm); ~Adaptee(); QString channelType() const { return mChannel->channelType(); } QStringList interfaces() const; uint targetHandle() const { return mChannel->targetHandle(); } QString targetID() const { return mChannel->targetID(); } uint targetHandleType() const { return mChannel->targetHandleType(); } bool requested() const { return mChannel->requested(); } uint initiatorHandle() const { return mChannel->initiatorHandle(); } QString initiatorID() const { return mChannel->initiatorID(); } private Q_SLOTS: void close(const Tp::Service::ChannelAdaptor::CloseContextPtr &context); void getChannelType(const Tp::Service::ChannelAdaptor::GetChannelTypeContextPtr &context) { context->setFinished(channelType()); } void getHandle(const Tp::Service::ChannelAdaptor::GetHandleContextPtr &context) { context->setFinished(targetHandleType(), targetHandle()); } void getInterfaces(const Tp::Service::ChannelAdaptor::GetInterfacesContextPtr &context) { context->setFinished(interfaces()); } public: BaseChannel *mChannel; Service::ChannelAdaptor *mAdaptor; signals: void closed(); }; class TP_QT_NO_EXPORT BaseChannelTextType::Adaptee : public QObject { Q_OBJECT public: Adaptee(BaseChannelTextType *interface); ~Adaptee(); public slots: void acknowledgePendingMessages(const Tp::UIntList &IDs, const Tp::Service::ChannelTypeTextAdaptor::AcknowledgePendingMessagesContextPtr &context); //deprecated: //void getMessageTypes(const Tp::Service::ChannelTypeTextAdaptor::GetMessageTypesContextPtr &context); //void listPendingMessages(bool clear, const Tp::Service::ChannelTypeTextAdaptor::ListPendingMessagesContextPtr &context); //void send(uint type, const QString &text, const Tp::Service::ChannelTypeTextAdaptor::SendContextPtr &context); signals: void lostMessage(); void received(uint ID, uint timestamp, uint sender, uint type, uint flags, const QString &text); void sendError(uint error, uint timestamp, uint type, const QString &text); void sent(uint timestamp, uint type, const QString &text); public: BaseChannelTextType *mInterface; }; class TP_QT_NO_EXPORT BaseChannelMessagesInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QStringList supportedContentTypes READ supportedContentTypes) Q_PROPERTY(Tp::UIntList messageTypes READ messageTypes) Q_PROPERTY(uint messagePartSupportFlags READ messagePartSupportFlags) Q_PROPERTY(Tp::MessagePartListList pendingMessages READ pendingMessages) Q_PROPERTY(uint deliveryReportingSupport READ deliveryReportingSupport) public: Adaptee(BaseChannelMessagesInterface *interface); ~Adaptee(); QStringList supportedContentTypes() { return mInterface->supportedContentTypes(); } Tp::UIntList messageTypes() { return mInterface->messageTypes(); } uint messagePartSupportFlags() { return mInterface->messagePartSupportFlags(); } uint deliveryReportingSupport() { return mInterface->deliveryReportingSupport(); } Tp::MessagePartListList pendingMessages() { return mInterface->pendingMessages(); } public slots: void sendMessage(const Tp::MessagePartList &message, uint flags, const Tp::Service::ChannelInterfaceMessagesAdaptor::SendMessageContextPtr &context); //deprecated, never implemented: //void getPendingMessageContent(uint messageID, const Tp::UIntList &parts, const Tp::Service::ChannelInterfaceMessagesAdaptor::GetPendingMessageContentContextPtr &context); signals: void messageSent(const Tp::MessagePartList &content, uint flags, const QString &messageToken); void pendingMessagesRemoved(const Tp::UIntList &messageIDs); void messageReceived(const Tp::MessagePartList &message); public: BaseChannelMessagesInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelServerAuthenticationType::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QString authenticationMethod READ authenticationMethod) public: Adaptee(BaseChannelServerAuthenticationType *interface); ~Adaptee(); QString authenticationMethod() const; public: BaseChannelServerAuthenticationType *mInterface; }; class TP_QT_NO_EXPORT BaseChannelCaptchaAuthenticationInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(bool canRetryCaptcha READ canRetryCaptcha) Q_PROPERTY(uint captchaStatus READ captchaStatus) Q_PROPERTY(QString captchaError READ captchaError) Q_PROPERTY(QVariantMap captchaErrorDetails READ captchaErrorDetails) public: Adaptee(BaseChannelCaptchaAuthenticationInterface *interface); ~Adaptee(); bool canRetryCaptcha() const; uint captchaStatus() const; QString captchaError() const; QVariantMap captchaErrorDetails() const; public slots: void getCaptchas(const Tp::Service::ChannelInterfaceCaptchaAuthenticationAdaptor::GetCaptchasContextPtr &context); void getCaptchaData(uint ID, const QString &mimeType, const Tp::Service::ChannelInterfaceCaptchaAuthenticationAdaptor::GetCaptchaDataContextPtr &context); void answerCaptchas(const Tp::CaptchaAnswers &answers, const Tp::Service::ChannelInterfaceCaptchaAuthenticationAdaptor::AnswerCaptchasContextPtr &context); void cancelCaptcha(uint reason, const QString &debugMessage, const Tp::Service::ChannelInterfaceCaptchaAuthenticationAdaptor::CancelCaptchaContextPtr &context); public: BaseChannelCaptchaAuthenticationInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelSASLAuthenticationInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QStringList availableMechanisms READ availableMechanisms) Q_PROPERTY(bool hasInitialData READ hasInitialData) Q_PROPERTY(bool canTryAgain READ canTryAgain) Q_PROPERTY(uint saslStatus READ saslStatus) Q_PROPERTY(QString saslError READ saslError) Q_PROPERTY(QVariantMap saslErrorDetails READ saslErrorDetails) Q_PROPERTY(QString authorizationIdentity READ authorizationIdentity) Q_PROPERTY(QString defaultUsername READ defaultUsername) Q_PROPERTY(QString defaultRealm READ defaultRealm) Q_PROPERTY(bool maySaveResponse READ maySaveResponse) public: Adaptee(BaseChannelSASLAuthenticationInterface *interface); ~Adaptee(); QStringList availableMechanisms() const; bool hasInitialData() const; bool canTryAgain() const; uint saslStatus() const; QString saslError() const; QVariantMap saslErrorDetails() const; QString authorizationIdentity() const; QString defaultUsername() const; QString defaultRealm() const; bool maySaveResponse() const; private Q_SLOTS: void startMechanism(const QString &mechanism, const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::StartMechanismContextPtr &context); void startMechanismWithData(const QString &mechanism, const QByteArray &initialData, const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::StartMechanismWithDataContextPtr &context); void respond(const QByteArray &responseData, const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::RespondContextPtr &context); void acceptSasl( const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::AcceptSASLContextPtr &context); void abortSasl(uint reason, const QString &debugMessage, const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::AbortSASLContextPtr &context); signals: void saslStatusChanged(uint status, const QString &reason, const QVariantMap &details); void newChallenge(const QByteArray &challengeData); private: BaseChannelSASLAuthenticationInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelSecurableInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(bool encrypted READ encrypted) Q_PROPERTY(bool verified READ verified) public: Adaptee(BaseChannelSecurableInterface *interface); ~Adaptee(); bool encrypted() const; bool verified() const; private: BaseChannelSecurableInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelChatStateInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(Tp::ChatStateMap chatStates READ chatStates) public: Adaptee(BaseChannelChatStateInterface *interface); ~Adaptee(); Tp::ChatStateMap chatStates() const; private Q_SLOTS: void setChatState(uint state, const Tp::Service::ChannelInterfaceChatStateAdaptor::SetChatStateContextPtr &context); signals: void chatStateChanged(uint contact, uint state); private: BaseChannelChatStateInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelGroupInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(uint groupFlags READ groupFlags) Q_PROPERTY(Tp::HandleOwnerMap handleOwners READ handleOwners) Q_PROPERTY(Tp::LocalPendingInfoList localPendingMembers READ localPendingMembers) Q_PROPERTY(Tp::UIntList members READ members) Q_PROPERTY(Tp::UIntList remotePendingMembers READ remotePendingMembers) Q_PROPERTY(uint selfHandle READ selfHandle) Q_PROPERTY(Tp::HandleIdentifierMap memberIdentifiers READ memberIdentifiers) public: Adaptee(BaseChannelGroupInterface *interface); ~Adaptee(); uint groupFlags() const; Tp::HandleOwnerMap handleOwners() const; Tp::LocalPendingInfoList localPendingMembers() const; Tp::UIntList members() const; Tp::UIntList remotePendingMembers() const; uint selfHandle() const; Tp::HandleIdentifierMap memberIdentifiers() const; public slots: void addMembers(const Tp::UIntList &contacts, const QString &message, const Tp::Service::ChannelInterfaceGroupAdaptor::AddMembersContextPtr &context); void getAllMembers(const Tp::Service::ChannelInterfaceGroupAdaptor::GetAllMembersContextPtr &context); void getGroupFlags(const Tp::Service::ChannelInterfaceGroupAdaptor::GetGroupFlagsContextPtr &context); void getHandleOwners(const Tp::UIntList &handles, const Tp::Service::ChannelInterfaceGroupAdaptor::GetHandleOwnersContextPtr &context); void getLocalPendingMembers(const Tp::Service::ChannelInterfaceGroupAdaptor::GetLocalPendingMembersContextPtr &context); void getLocalPendingMembersWithInfo(const Tp::Service::ChannelInterfaceGroupAdaptor::GetLocalPendingMembersWithInfoContextPtr &context); void getMembers(const Tp::Service::ChannelInterfaceGroupAdaptor::GetMembersContextPtr &context); void getRemotePendingMembers(const Tp::Service::ChannelInterfaceGroupAdaptor::GetRemotePendingMembersContextPtr &context); void getSelfHandle(const Tp::Service::ChannelInterfaceGroupAdaptor::GetSelfHandleContextPtr &context); void removeMembers(const Tp::UIntList &contacts, const QString &message, const Tp::Service::ChannelInterfaceGroupAdaptor::RemoveMembersContextPtr &context); void removeMembersWithReason(const Tp::UIntList &contacts, const QString &message, uint reason, const Tp::Service::ChannelInterfaceGroupAdaptor::RemoveMembersWithReasonContextPtr &context); signals: void handleOwnersChangedDetailed(const Tp::HandleOwnerMap &added, const Tp::UIntList &removed, const Tp::HandleIdentifierMap &identifiers); void selfContactChanged(uint selfHandle, const QString &selfID); void groupFlagsChanged(uint added, uint removed); void membersChanged(const QString &message, const Tp::UIntList &added, const Tp::UIntList &removed, const Tp::UIntList &localPending, const Tp::UIntList &remotePending, uint actor, uint reason); void membersChangedDetailed(const Tp::UIntList &added, const Tp::UIntList &removed, const Tp::UIntList &localPending, const Tp::UIntList &remotePending, const QVariantMap &details); //All other signals are deprecated public: BaseChannelGroupInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelCallType::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(Tp::ObjectPathList contents READ contents) Q_PROPERTY(QVariantMap callStateDetails READ callStateDetails) Q_PROPERTY(uint callState READ callState) Q_PROPERTY(uint callFlags READ callFlags) Q_PROPERTY(Tp::CallStateReason callStateReason READ callStateReason) Q_PROPERTY(bool hardwareStreaming READ hardwareStreaming) Q_PROPERTY(Tp::CallMemberMap callMembers READ callMembers) Q_PROPERTY(Tp::HandleIdentifierMap memberIdentifiers READ memberIdentifiers) Q_PROPERTY(uint initialTransport READ initialTransport) Q_PROPERTY(bool initialAudio READ initialAudio) Q_PROPERTY(bool initialVideo READ initialVideo) Q_PROPERTY(QString initialVideoName READ initialVideoName) Q_PROPERTY(QString initialAudioName READ initialAudioName) Q_PROPERTY(bool mutableContents READ mutableContents) public: Adaptee(BaseChannelCallType *interface); ~Adaptee(); Tp::ObjectPathList contents() const { return mInterface->contents(); } QVariantMap callStateDetails() const { return mInterface->callStateDetails(); } uint callState() const { return mInterface->callState(); } uint callFlags() const { return mInterface->callFlags(); } Tp::CallStateReason callStateReason() const { return mInterface->callStateReason(); } bool hardwareStreaming() const { return mInterface->hardwareStreaming(); } Tp::CallMemberMap callMembers() const { return mInterface->callMembers(); } Tp::HandleIdentifierMap memberIdentifiers() const { return mInterface->memberIdentifiers(); } uint initialTransport() const { return mInterface->initialTransport(); } bool initialAudio() const { return mInterface->initialAudio(); } bool initialVideo() const { return mInterface->initialVideo(); } QString initialVideoName() const { return mInterface->initialVideoName(); } QString initialAudioName() const { return mInterface->initialAudioName(); } bool mutableContents() const { return mInterface->mutableContents(); } public slots: void setRinging(const Tp::Service::ChannelTypeCallAdaptor::SetRingingContextPtr &context); void setQueued(const Tp::Service::ChannelTypeCallAdaptor::SetQueuedContextPtr &context); void accept(const Tp::Service::ChannelTypeCallAdaptor::AcceptContextPtr &context); void hangup(uint reason, const QString &detailedHangupReason, const QString &message, const Tp::Service::ChannelTypeCallAdaptor::HangupContextPtr &context); void addContent(const QString &contentName, const Tp::MediaStreamType &contentType, const Tp::MediaStreamDirection &initialDirection, const Tp::Service::ChannelTypeCallAdaptor::AddContentContextPtr &context); signals: void contentAdded(const QDBusObjectPath &content); void contentRemoved(const QDBusObjectPath &content, const Tp::CallStateReason &reason); void callStateChanged(uint callState, uint callFlags, const Tp::CallStateReason &stateReason, const QVariantMap &callStateDetails); void callMembersChanged(const Tp::CallMemberMap &flagsChanged, const Tp::HandleIdentifierMap &identifiers, const Tp::UIntList &removed, const Tp::CallStateReason &reason); public: BaseChannelCallType *mInterface; }; class TP_QT_NO_EXPORT BaseChannelSMSInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(bool flash READ flash) Q_PROPERTY(bool smsChannel READ smsChannel) public: Adaptee(BaseChannelSMSInterface *interface); ~Adaptee(); bool flash() { return mInterface->flash(); } bool smsChannel() { return mInterface->smsChannel(); } public slots: void getSMSLength(const Tp::MessagePartList &messages, const Tp::Service::ChannelInterfaceSMSAdaptor::GetSMSLengthContextPtr &context); signals: void smsChannelChanged(bool smsChannel); public: BaseChannelSMSInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelHoldInterface::Adaptee : public QObject { Q_OBJECT public: Adaptee(BaseChannelHoldInterface *interface); ~Adaptee(); public slots: void getHoldState(const Tp::Service::ChannelInterfaceHoldAdaptor::GetHoldStateContextPtr &context); void requestHold(bool hold, const Tp::Service::ChannelInterfaceHoldAdaptor::RequestHoldContextPtr &context); signals: void holdStateChanged(uint holdState, uint reason); public: BaseChannelHoldInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelConferenceInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(Tp::ObjectPathList channels READ channels) Q_PROPERTY(Tp::ObjectPathList initialChannels READ initialChannels) Q_PROPERTY(Tp::UIntList initialInviteeHandles READ initialInviteeHandles) Q_PROPERTY(QStringList initialInviteeIDs READ initialInviteeIDs) Q_PROPERTY(QString invitationMessage READ invitationMessage) Q_PROPERTY(ChannelOriginatorMap originalChannels READ originalChannels) public: Adaptee(BaseChannelConferenceInterface *interface); ~Adaptee(); Tp::ObjectPathList channels() const { return mInterface->channels(); } Tp::ObjectPathList initialChannels() const { return mInterface->initialChannels(); } Tp::UIntList initialInviteeHandles() const { return mInterface->initialInviteeHandles(); } QStringList initialInviteeIDs() const { return mInterface->initialInviteeIDs(); } QString invitationMessage() const { return mInterface->invitationMessage(); } ChannelOriginatorMap originalChannels() const { return mInterface->originalChannels(); } signals: void channelMerged(const QDBusObjectPath &channel, uint channelHandle, const QVariantMap &properties); void channelRemoved(const QDBusObjectPath &channel, const QVariantMap& details); public: BaseChannelConferenceInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelMergeableConferenceInterface::Adaptee : public QObject { Q_OBJECT public: Adaptee(BaseChannelMergeableConferenceInterface *interface); ~Adaptee(); public slots: void merge(const QDBusObjectPath &channel, const Tp::Service::ChannelInterfaceMergeableConferenceAdaptor::MergeContextPtr &context); public: BaseChannelMergeableConferenceInterface *mInterface; }; class TP_QT_NO_EXPORT BaseChannelSplittableInterface::Adaptee : public QObject { Q_OBJECT public: Adaptee(BaseChannelSplittableInterface *interface); ~Adaptee(); public slots: void split(const Tp::Service::ChannelInterfaceSplittableAdaptor::SplitContextPtr &context); public: BaseChannelSplittableInterface *mInterface; }; } telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeContactSearchInterface0000664000175000017500000000042712470405660023637 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeContactSearchInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeContactSearchInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelClassSpecList0000664000175000017500000000041012470405660021137 0ustar jrjr#ifndef _TelepathyQt_ChannelClassSpecList_HEADER_GUARD_ #define _TelepathyQt_ChannelClassSpecList_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/contact-search-channel-internal.h0000664000175000017500000000324212470405660023504 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_contact_search_channel_internal_h_HEADER_GUARD_ #define _TelepathyQt_contact_search_channel_internal_h_HEADER_GUARD_ #include #include namespace Tp { class TP_QT_NO_EXPORT ContactSearchChannel::PendingSearch : public PendingOperation { Q_OBJECT public: PendingSearch(const ContactSearchChannelPtr &chan, QDBusPendingCall call); private Q_SLOTS: TP_QT_NO_EXPORT void onSearchStateChanged(Tp::ChannelContactSearchState state, const QString &errorName, const Tp::ContactSearchChannel::SearchStateChangeDetails &details); TP_QT_NO_EXPORT void watcherFinished(QDBusPendingCallWatcher*); private: bool mFinished; QDBusError mError; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/pending-string-list.cpp0000664000175000017500000000532612470405660021627 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-string-list.moc.hpp" #include "TelepathyQt/debug-internal.h" #include namespace Tp { struct TP_QT_NO_EXPORT PendingStringList::Private { QStringList result; }; /** * \class PendingStringList * \ingroup utils * \headerfile TelepathyQt/pending-string-list.h * * \brief The PendingStringList class is a generic subclass of PendingOperation * representing a pending D-Bus method call that returns a string list. * * See \ref async_model */ PendingStringList::PendingStringList(const SharedPtr &object) : PendingOperation(object), mPriv(new Private) { } PendingStringList::PendingStringList(QDBusPendingCall call, const SharedPtr &object) : PendingOperation(object), mPriv(new Private) { connect(new QDBusPendingCallWatcher(call), SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(watcherFinished(QDBusPendingCallWatcher*))); } /** * Class destructor. */ PendingStringList::~PendingStringList() { delete mPriv; } QStringList PendingStringList::result() const { return mPriv->result; } void PendingStringList::setResult(const QStringList &result) { mPriv->result = result; } void PendingStringList::watcherFinished(QDBusPendingCallWatcher* watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got reply to PendingStringList call"; setResult(reply.value()); setFinished(); } else { debug().nospace() << "PendingStringList call failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceRequestsInterface0000664000175000017500000000044012470405660024432 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceRequestsInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceRequestsInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Functors0000664000175000017500000000034612470405660016745 0ustar jrjr#ifndef _TelepathyQt_Functors_HEADER_GUARD_ #define _TelepathyQt_Functors_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/RequestableChannelClassSpec0000664000175000017500000000044212470405660022505 0ustar jrjr#ifndef _TelepathyQt_RequestableChannelClassSpec_HEADER_GUARD_ #define _TelepathyQt_RequestableChannelClassSpec_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/key-file.cpp0000664000175000017500000003554412470405660017440 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/key-file.h" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT KeyFile::Private { Private(); Private(const QString &fName); void setFileName(const QString &fName); void setError(KeyFile::Status status, const QString &reason); bool read(); bool validateKey(const QByteArray &data, int from, int to, QString &result); QStringList allGroups() const; QStringList allKeys() const; QStringList keys() const; bool contains(const QString &key) const; QString rawValue(const QString &key) const; QString value(const QString &key) const; QStringList valueAsStringList(const QString &key) const; QString fileName; KeyFile::Status status; QHash > groups; QString currentGroup; }; KeyFile::Private::Private() : status(KeyFile::None) { } KeyFile::Private::Private(const QString &fName) : fileName(fName), status(KeyFile::NoError) { read(); } void KeyFile::Private::setFileName(const QString &fName) { fileName = fName; status = KeyFile::NoError; currentGroup = QString(); groups.clear(); read(); } void KeyFile::Private::setError(KeyFile::Status st, const QString &reason) { warning() << QString(QLatin1String("ERROR: filename(%1) reason(%2)")) .arg(fileName).arg(reason); status = st; groups.clear(); } bool KeyFile::Private::read() { QFile file(fileName); if (!file.exists()) { setError(KeyFile::NotFoundError, QLatin1String("file does not exist")); return false; } if (!file.open(QFile::ReadOnly)) { setError(KeyFile::AccessError, QLatin1String("cannot open file for readonly access")); return false; } QByteArray data; QByteArray group; QString currentGroup; QHash groupMap; QByteArray rawValue; int line = 0; int idx; while (!file.atEnd()) { data = file.readLine().trimmed(); line++; if (data.size() == 0) { // skip empty lines continue; } char ch = data.at(0); if (ch == '#') { // skip comments continue; } else if (ch == '[') { if (groupMap.size()) { groups[currentGroup] = groupMap; groupMap.clear(); } idx = data.indexOf(']'); if (idx == -1) { // line starts with [ and it's not a group setError(KeyFile::FormatError, QString(QLatin1String("invalid group at line %2 - missing ']'")) .arg(line)); return false; } group = data.mid(1, idx - 1).trimmed(); if (groups.contains(QLatin1String(group))) { setError(KeyFile::FormatError, QString(QLatin1String("duplicated group '%1' at line %2")) .arg(QLatin1String(group)).arg(line)); return false; } currentGroup = QLatin1String(""); if (!unescapeString(group, 0, group.size(), currentGroup)) { setError(KeyFile::FormatError, QString(QLatin1String("invalid group '%1' at line %2")) .arg(currentGroup).arg(line)); return false; } } else { idx = data.indexOf('='); if (idx == -1) { setError(KeyFile::FormatError, QString(QLatin1String("format error at line %1 - missing '='")) .arg(line)); return false; } // remove trailing spaces char ch; int idxKeyEnd = idx; while ((ch = data.at(idxKeyEnd - 1)) == ' ' || ch == '\t') { --idxKeyEnd; } QString key; if (!validateKey(data, 0, idxKeyEnd, key)) { setError(KeyFile::FormatError, QString(QLatin1String("invalid key '%1' at line %2")) .arg(key).arg(line)); return false; } if (groupMap.contains(key)) { setError(KeyFile::FormatError, QString(QLatin1String("duplicated key '%1' on group '%2' at line %3")) .arg(key).arg(currentGroup).arg(line)); return false; } data = data.mid(idx + 1).trimmed(); rawValue = data.mid(0, data.size()); groupMap[key] = rawValue; } } if (groupMap.size()) { groups[currentGroup] = groupMap; groupMap.clear(); } return true; } bool KeyFile::Private::validateKey(const QByteArray &data, int from, int to, QString &result) { int i = from; bool ret = true; while (i < to) { uint ch = data.at(i++); // as an extension to the Desktop Entry spec, we allow " ", "_", "." and "@" // as valid key characters - "_" and "." are needed for keys that are // D-Bus property names, and GKeyFile and KConfigIniBackend also accept // all four of those characters. if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == ' ') || (ch == '-') || (ch == '_') || (ch == '.') || (ch == '@'))) { ret = false; } result += ch; } return ret; } QStringList KeyFile::Private::allGroups() const { return groups.keys(); } QStringList KeyFile::Private::allKeys() const { QStringList keys; QHash >::const_iterator itrGroups = groups.begin(); while (itrGroups != groups.end()) { keys << itrGroups.value().keys(); ++itrGroups; } return keys; } QStringList KeyFile::Private::keys() const { QHash groupMap = groups[currentGroup]; return groupMap.keys(); } bool KeyFile::Private::contains(const QString &key) const { QHash groupMap = groups[currentGroup]; return groupMap.contains(key); } QString KeyFile::Private::rawValue(const QString &key) const { QHash groupMap = groups[currentGroup]; QByteArray rawValue = groupMap.value(key); return QLatin1String(rawValue); } QString KeyFile::Private::value(const QString &key) const { QHash groupMap = groups[currentGroup]; QString result; QByteArray rawValue = groupMap.value(key); if (unescapeString(rawValue, 0, rawValue.size(), result)) { return result; } return QString(); } QStringList KeyFile::Private::valueAsStringList(const QString &key) const { QHash groupMap = groups[currentGroup]; QStringList result; QByteArray rawValue = groupMap.value(key); if (unescapeStringList(rawValue, 0, rawValue.size(), result)) { return result; } return QStringList(); } /** * \class KeyFile * \ingroup utils * \headerfile TelepathyQt/key-file.h * * \brief The KeyFile class provides an easy way to read key-pair files such as * INI style files and .desktop files. * * It follows the rules regarding string escaping as defined in * http://standards.freedesktop.org/desktop-entry-spec/latest/index.html */ /** * Create a KeyFile object used to read (key-pair) compliant files. * * The status will be KeyFile::None * \sa setFileName() */ KeyFile::KeyFile() : mPriv(new Private()) { } /** * Create a KeyFile object used to read (key-pair) compliant files. * * \param fileName Name of the file to be read. */ KeyFile::KeyFile(const QString &fileName) : mPriv(new Private(fileName)) { } /** * Create a KeyFile object used to read (key-pair) compliant files. */ KeyFile::KeyFile(const KeyFile &other) : mPriv(new Private()) { mPriv->fileName = other.mPriv->fileName; mPriv->status = other.mPriv->status; mPriv->groups = other.mPriv->groups; mPriv->currentGroup = other.mPriv->currentGroup; } /** * Class destructor. */ KeyFile::~KeyFile() { delete mPriv; } KeyFile &KeyFile::operator=(const KeyFile &other) { mPriv->fileName = other.mPriv->fileName; mPriv->status = other.mPriv->status; mPriv->groups = other.mPriv->groups; mPriv->currentGroup = other.mPriv->currentGroup; return *this; } /** * Set the name of the file to be read. * * \param fileName Name of the file to be read. */ void KeyFile::setFileName(const QString &fileName) { mPriv->setFileName(fileName); } /** * Return the name of the file associated with this object. * * \return Name of the file associated with this object. */ QString KeyFile::fileName() const { return mPriv->fileName; } /** * Return a status code indicating the first error that was met by #KeyFile, * or KeyFile::NoError if no error occurred. * * Make sure to use this method if you set the filename to be read using * setFileName(). * * \return Status code. * \sa setFileName() */ KeyFile::Status KeyFile::status() const { return mPriv->status; } /** * Set the current group to be used while reading keys. * * Query functions such as keys(), contains() and value() are based on this * group. * * By default a empty group is used as the group for global * keys and is used as the default group if none is set. * * \param group Name of the group to be used. * \sa group() */ void KeyFile::setGroup(const QString &group) { mPriv->currentGroup = group; } /** * Return the current group. * * \return Name of the current group. * \sa setGroup() */ QString KeyFile::group() const { return mPriv->currentGroup; } /** * Return all groups in the desktop file. * * Global keys will be added to a empty group. * * \return List of all groups in the desktop file. */ QStringList KeyFile::allGroups() const { return mPriv->allGroups(); } /** * Return all keys described in the desktop file. * * \return List of all keys in the desktop file. */ QStringList KeyFile::allKeys() const { return mPriv->allKeys(); } /** * Return a list of keys in the current group. * * \return List of all keys in the current group. * \sa group(), setGroup() */ QStringList KeyFile::keys() const { return mPriv->keys(); } /** * Check if the current group contains a key named \a key. * * \return true if \a key exists, false otherwise. * \sa group(), setGroup() */ bool KeyFile::contains(const QString &key) const { return mPriv->contains(key); } /** * Get the raw value for the key in the current group named \a key. * * The raw value is the value as is in the key file. * * \return Value of \a key, empty string if not found. * \sa group(), setGroup() */ QString KeyFile::rawValue(const QString &key) const { return mPriv->rawValue(key); } /** * Get the value for the key in the current group named \a key. * * Escape sequences in the value are interpreted as defined in: * http://standards.freedesktop.org/desktop-entry-spec/latest/ * * \return Value of \a key, empty string if not found or an error occurred. * \sa group(), setGroup() */ QString KeyFile::value(const QString &key) const { return mPriv->value(key); } /** * Get the value for the key in the current group named \a key as a list. * * Return a list containing all strings on this key separated by ';'. * Escape sequences in the value are interpreted as defined in: * http://standards.freedesktop.org/desktop-entry-spec/latest/ * * \return Value of \a key as a list, empty string list if not found or an error occurred. * \sa group(), setGroup() */ QStringList KeyFile::valueAsStringList(const QString &key) const { return mPriv->valueAsStringList(key); } bool KeyFile::unescapeString(const QByteArray &data, int from, int to, QString &result) { int i = from; while (i < to) { uint ch = data.at(i++); if (ch == '\\') { if (i == to) { result += QLatin1String("\\"); return true; } char nextCh = data.at(i++); switch (nextCh) { case 's': result += QLatin1String(" "); break; case 'n': result += QLatin1String("\n"); break; case 't': result += QLatin1String("\t"); break; case 'r': result += QLatin1String("\r"); break; case ';': result += QLatin1String(";"); break; case '\\': result += QLatin1String("\\"); break; default: return false; } } else { result += ch; } } return true; } bool KeyFile::unescapeStringList(const QByteArray &data, int from, int to, QStringList &result) { QByteArray value; QList valueList; int i = from; char ch; while (i < to) { ch = data.at(i++); if (ch == '\\') { value += ch; if (i < to) { value += data.at(i++); continue; } else { valueList << value; break; } } else if (ch == ';') { valueList << value; value = ""; } else { value += ch; if (i == to) { valueList << value; } } } foreach (value, valueList) { QString str; if (!unescapeString(value, 0, value.size(), str)) { return false; } result << str; } return true; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeStreamTubeInterface0000664000175000017500000000042112470405660023163 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeStreamTubeInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeStreamTubeInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/call-stream-endpoint.h0000664000175000017500000000222512470405660021410 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_call_stream_endpoint_h_HEADER_GUARD_ #define _TelepathyQt_call_stream_endpoint_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/OptionalInterfaceFactory0000664000175000017500000000043012470405660022072 0ustar jrjr#ifndef _TelepathyQt_OptionalInterfaceFactory_HEADER_GUARD_ #define _TelepathyQt_OptionalInterfaceFactory_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceContactCapabilitiesInterface0000664000175000017500000000046612470405660026534 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceContactCapabilitiesInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceContactCapabilitiesInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/NotFilter0000664000175000017500000000035212470405660017045 0ustar jrjr#ifndef _TelepathyQt_NotFilter_HEADER_GUARD_ #define _TelepathyQt_NotFilter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceRoomInterface0000664000175000017500000000041712470405660023010 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceRoomInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceRoomInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/dbus-error.h0000664000175000017500000000320212470405660017446 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_dbus_error_h_HEADER_GUARD_ #define _TelepathyQt_dbus_error_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class TP_QT_EXPORT DBusError { Q_DISABLE_COPY(DBusError) public: DBusError(); DBusError(const QString &name, const QString &message); ~DBusError(); bool isValid() const { return mPriv != 0; } bool operator==(const DBusError &other) const; bool operator!=(const DBusError &other) const; QString name() const; QString message() const; void set(const QString &name, const QString &message); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/dbus-proxy.cpp0000664000175000017500000002650212470405660020041 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include #include "TelepathyQt/_gen/dbus-proxy.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include namespace Tp { // ==== DBusProxy ====================================================== // Features in TpProxy but not here: // * tracking which interfaces we have (in tpqt, subclasses do that) // * being Introspectable, a Peer and a Properties implementation // * disconnecting from signals when invalidated (probably has to be in the // generated code) // * making methods always raise an error when called after invalidated // (has to be in the generated code) struct TP_QT_NO_EXPORT DBusProxy::Private { Private(const QDBusConnection &dbusConnection, const QString &busName, const QString &objectPath); QDBusConnection dbusConnection; QString busName; QString objectPath; QString invalidationReason; QString invalidationMessage; }; DBusProxy::Private::Private(const QDBusConnection &dbusConnection, const QString &busName, const QString &objectPath) : dbusConnection(dbusConnection), busName(busName), objectPath(objectPath) { debug() << "Creating new DBusProxy"; } /** * \class DBusProxy * \ingroup clientproxies * \headerfile TelepathyQt/dbus-proxy.h * * \brief The DBusProxy class is a base class representing a remote object available over D-Bus. * * All Telepathy-Qt client convenience classes that wrap Telepathy interfaces * inherit from this class in order to provide basic D-Bus interface * information. */ /** * Construct a new DBusProxy object. * * \param dbusConnection QDBusConnection to use. * \param busName D-Bus bus name of the service that provides the remote object. * \param objectPath The object path. * \param featureCore The object core feature. */ DBusProxy::DBusProxy(const QDBusConnection &dbusConnection, const QString &busName, const QString &objectPath, const Feature &featureCore) : Object(), ReadyObject(this, featureCore), mPriv(new Private(dbusConnection, busName, objectPath)) { if (!dbusConnection.isConnected()) { invalidate(TP_QT_ERROR_DISCONNECTED, QLatin1String("DBus connection disconnected")); } } /** * Class destructor. */ DBusProxy::~DBusProxy() { delete mPriv; } /** * Return the D-Bus connection through which the remote object is * accessed. * * \return A QDBusConnection object. */ QDBusConnection DBusProxy::dbusConnection() const { return mPriv->dbusConnection; } /** * Return the D-Bus object path of the remote object within the service. * * \return The D-Bus object path. */ QString DBusProxy::objectPath() const { return mPriv->objectPath; } /** * Return the D-Bus bus name (either a unique name or a well-known * name) of the service that provides the remote object. * * \return The D-Bus bus name. */ QString DBusProxy::busName() const { return mPriv->busName; } /** * Sets the D-Bus bus name. This is used by subclasses after converting * well-known names to unique names. * * \param busName The D-Bus bus name to set. */ void DBusProxy::setBusName(const QString &busName) { mPriv->busName = busName; } /** * Return whether this proxy is still valid (has not emitted invalidated()). * * \return \c true if still valid, \c false otherwise. */ bool DBusProxy::isValid() const { return mPriv->invalidationReason.isEmpty(); } /** * Return the error name indicating the reason this proxy became invalid. * * \return A D-Bus error name, or QString() if this object is still valid. */ QString DBusProxy::invalidationReason() const { return mPriv->invalidationReason; } /** * Return a debugging message indicating the reason this proxy became invalid. * * \return A debugging message, or QString() if this object is still valid. */ QString DBusProxy::invalidationMessage() const { return mPriv->invalidationMessage; } /** * Called by subclasses when the DBusProxy should become invalid. * * This method takes care of setting the invalidationReason, * invalidationMessage, and emitting the invalidated signal. * * \param reason A D-Bus error name (a string in a subset of ASCII, * prefixed with a reversed domain name) * \param message A debugging message associated with the error */ void DBusProxy::invalidate(const QString &reason, const QString &message) { if (!isValid()) { debug().nospace() << "Already invalidated by " << mPriv->invalidationReason << ", not replacing with " << reason << " \"" << message << "\""; return; } Q_ASSERT(!reason.isEmpty()); debug().nospace() << "proxy invalidated: " << reason << ": " << message; mPriv->invalidationReason = reason; mPriv->invalidationMessage = message; Q_ASSERT(!isValid()); // Defer emitting the invalidated signal until we next // return to the mainloop. QTimer::singleShot(0, this, SLOT(emitInvalidated())); } void DBusProxy::invalidate(const QDBusError &error) { invalidate(error.name(), error.message()); } void DBusProxy::emitInvalidated() { Q_ASSERT(!isValid()); emit invalidated(this, mPriv->invalidationReason, mPriv->invalidationMessage); } /** * \fn void DBusProxy::invalidated(Tp::DBusProxy *proxy, * const QString &errorName, const QString &errorMessage) * * Emitted when this object is no longer usable. * * After this signal is emitted, any D-Bus method calls on the object * will fail, but it may be possible to retrieve information that has * already been retrieved and cached. * * \param proxy This proxy. * \param errorName The name of a D-Bus error describing the reason for the invalidation. * \param errorMessage A debugging message associated with the error. */ // ==== StatefulDBusProxy ============================================== struct TP_QT_NO_EXPORT StatefulDBusProxy::Private { Private(const QString &originalName) : originalName(originalName) {} QString originalName; }; /** * \class StatefulDBusProxy * \ingroup clientproxies * \headerfile TelepathyQt/dbus-proxy.h * * \brief The StatefulDBusProxy class is a base class representing a remote object whose API is * stateful. * * These objects do not remain useful if the service providing them exits or * crashes, so they emit invalidated() if this happens. * * Examples include the Connection and Channel classes. */ /** * Construct a new StatefulDBusProxy object. * * \param dbusConnection QDBusConnection to use. * \param busName D-Bus bus name of the service that provides the remote object. * \param objectPath The object path. * \param featureCore The object core feature. */ StatefulDBusProxy::StatefulDBusProxy(const QDBusConnection &dbusConnection, const QString &busName, const QString &objectPath, const Feature &featureCore) : DBusProxy(dbusConnection, busName, objectPath, featureCore), mPriv(new Private(busName)) { QDBusServiceWatcher *serviceWatcher = new QDBusServiceWatcher(busName, dbusConnection, QDBusServiceWatcher::WatchForUnregistration, this); connect(serviceWatcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), SLOT(onServiceOwnerChanged(QString,QString,QString))); QString error, message; QString uniqueName = uniqueNameFrom(dbusConnection, busName, error, message); if (uniqueName.isEmpty()) { invalidate(error, message); return; } setBusName(uniqueName); } /** * Class destructor. */ StatefulDBusProxy::~StatefulDBusProxy() { delete mPriv; } QString StatefulDBusProxy::uniqueNameFrom(const QDBusConnection &bus, const QString &name) { QString error, message; QString uniqueName = uniqueNameFrom(bus, name, error, message); if (uniqueName.isEmpty()) { warning() << "StatefulDBusProxy::uniqueNameFrom(): Failed to get unique name of" << name; warning() << " error:" << error << "message:" << message; } return uniqueName; } QString StatefulDBusProxy::uniqueNameFrom(const QDBusConnection &bus, const QString &name, QString &error, QString &message) { if (name.startsWith(QLatin1String(":"))) { return name; } // For a stateful interface, it makes no sense to follow name-owner // changes, so we want to bind to the unique name. QDBusReply reply = bus.interface()->serviceOwner(name); if (reply.isValid()) { return reply.value(); } else { error = reply.error().name(); message = reply.error().message(); return QString(); } } void StatefulDBusProxy::onServiceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) { // We only want to invalidate this object if it is not already invalidated, // and its (not any other object's) name owner changed signal is emitted. if (isValid() && name == mPriv->originalName && newOwner.isEmpty()) { invalidate(TP_QT_DBUS_ERROR_NAME_HAS_NO_OWNER, QLatin1String("Name owner lost (service crashed?)")); } } // ==== StatelessDBusProxy ============================================= /** * \class StatelessDBusProxy * \ingroup clientproxies * \headerfile TelepathyQt/dbus-proxy.h * * \brief The StatelessDBusProxy class is a base class representing a remote object whose API is * basically stateless. * * These objects can remain valid even if the service providing them exits * and is restarted. * * Examples include the AccountManager, Account and ConnectionManager. */ /** * Construct a new StatelessDBusProxy object. * * \param dbusConnection QDBusConnection to use. * \param busName D-Bus bus name of the service that provides the remote object. * \param objectPath The object path. * \param featureCore The object core feature. */ StatelessDBusProxy::StatelessDBusProxy(const QDBusConnection &dbusConnection, const QString &busName, const QString &objectPath, const Feature &featureCore) : DBusProxy(dbusConnection, busName, objectPath, featureCore), mPriv(0) { if (busName.startsWith(QLatin1String(":"))) { warning() << "Using StatelessDBusProxy for a unique name does not make sense"; } } /** * Class destructor. */ StatelessDBusProxy::~StatelessDBusProxy() { } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ReferencedHandles0000664000175000017500000000035712470405660020505 0ustar jrjr#ifndef _TelepathyQt_ReferencedHandles_HEADER_GUARD_ #define _TelepathyQt_ReferencedHandles_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif telepathy-qt-0.9.6~git1/TelepathyQt/fixed-feature-factory.h0000664000175000017500000000342212470405660021563 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_fixed_feature_factory_h_HEADER_GUARD_ #define _TelepathyQt_fixed_feature_factory_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include class QDBusConnection; namespace Tp { class Feature; class Features; class TP_QT_EXPORT FixedFeatureFactory : public DBusProxyFactory { Q_OBJECT Q_DISABLE_COPY(FixedFeatureFactory) public: virtual ~FixedFeatureFactory(); Features features() const; void addFeature(const Feature &feature); void addFeatures(const Features &features); protected: FixedFeatureFactory(const QDBusConnection &bus); virtual Features featuresFor(const DBusProxyPtr &proxy) const; private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/dbus-service.h0000664000175000017500000000516012470405660017762 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_dbus_service_h_HEADER_GUARD_ #define _TelepathyQt_dbus_service_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include class QDBusConnection; class QString; namespace Tp { class DBusObject; class TP_QT_EXPORT DBusService : public Object { Q_OBJECT Q_DISABLE_COPY(DBusService) public: DBusService(const QDBusConnection &dbusConnection); virtual ~DBusService(); virtual QVariantMap immutableProperties() const = 0; QDBusConnection dbusConnection() const; QString busName() const; QString objectPath() const; DBusObject *dbusObject() const; bool isRegistered() const; protected: virtual bool registerObject(const QString &busName, const QString &objectPath, DBusError *error); private: class Private; friend class Private; Private *mPriv; }; class TP_QT_EXPORT AbstractDBusServiceInterface : public Object { Q_OBJECT Q_DISABLE_COPY(AbstractDBusServiceInterface) public: AbstractDBusServiceInterface(const QString &interfaceName); virtual ~AbstractDBusServiceInterface(); QString interfaceName() const; virtual QVariantMap immutableProperties() const = 0; DBusObject *dbusObject() const; bool isRegistered() const; protected: virtual bool registerInterface(DBusObject *dbusObject); virtual void createAdaptor() = 0; public: bool notifyPropertyChanged(const QString &propertyName, const QVariant &propertyValue); private: class Private; friend class Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/dbus-daemon.xml0000664000175000017500000000515312470405660020140 0ustar jrjr D-Bus Daemon telepathy-qt-0.9.6~git1/TelepathyQt/CallContentInterface0000664000175000017500000000040212470405660021162 0ustar jrjr#ifndef _TelepathyQt_CallContentInterface_HEADER_GUARD_ #define _TelepathyQt_CallContentInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AvatarData0000664000175000017500000000035012470405660017145 0ustar jrjr#ifndef _TelepathyQt_AvatarData_HEADER_GUARD_ #define _TelepathyQt_AvatarData_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/connection-manager-lowlevel.h0000664000175000017500000000344312470405660022767 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_connection_manager_lowlevel_h_HEADER_GUARD_ #define _TelepathyQt_connection_manager_lowlevel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class PendingConnection; class TP_QT_EXPORT ConnectionManagerLowlevel : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(ConnectionManagerLowlevel) public: ~ConnectionManagerLowlevel(); bool isValid() const; ConnectionManagerPtr connectionManager() const; PendingConnection *requestConnection(const QString &protocolName, const QVariantMap ¶meters); private: friend class ConnectionManager; TP_QT_NO_EXPORT ConnectionManagerLowlevel(ConnectionManager *parent); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceHoldInterface0000664000175000017500000000041712470405660022762 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceHoldInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceHoldInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ProtocolInterfaceAddressingInterface0000664000175000017500000000045012470405660024405 0ustar jrjr#ifndef _TelepathyQt_ProtocolInterfaceAddressingInterface_HEADER_GUARD_ #define _TelepathyQt_ProtocolInterfaceAddressingInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/dbus-object.h0000664000175000017500000000315212470405660017567 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_dbus_object_h_HEADER_GUARD_ #define _TelepathyQt_dbus_object_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include class QDBusConnection; namespace Tp { class TP_QT_EXPORT DBusObject : public QObject { Q_OBJECT Q_DISABLE_COPY(DBusObject) public: DBusObject(const QDBusConnection &dbusConnection, QObject *parent = 0); virtual ~DBusObject(); QString objectPath() const; QDBusConnection dbusConnection() const; protected: void setObjectPath(const QString &path); private: class Private; friend class Private; Private *mPriv; friend class DBusService; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/account.xml0000664000175000017500000000062412470405660017374 0ustar jrjr Account interfaces telepathy-qt-0.9.6~git1/TelepathyQt/outgoing-file-transfer-channel.cpp0000664000175000017500000002740712470405660023732 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/outgoing-file-transfer-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include namespace Tp { static const int FT_BLOCK_SIZE = 16 * 1024; struct TP_QT_NO_EXPORT OutgoingFileTransferChannel::Private { Private(OutgoingFileTransferChannel *parent); ~Private(); // Public object OutgoingFileTransferChannel *parent; Client::ChannelTypeFileTransferInterface *fileTransferInterface; // Introspection QIODevice *input; QTcpSocket *socket; SocketAddressIPv4 addr; qint64 pos; }; OutgoingFileTransferChannel::Private::Private(OutgoingFileTransferChannel *parent) : parent(parent), fileTransferInterface(parent->interface()), input(0), socket(0), pos(0) { } OutgoingFileTransferChannel::Private::~Private() { } /** * \class OutgoingFileTransferChannel * \ingroup clientchannel * \headerfile TelepathyQt/outgoing-file-transfer-channel.h * * \brief The OutgoingFileTransferChannel class represents a Telepathy channel * of type FileTransfer for outgoing file transfers. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * OutgoingFileTransferChannel object usable. * * This is currently the same as FileTransferChannel::FeatureCore, but may change to include more. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature OutgoingFileTransferChannel::FeatureCore = Feature(QLatin1String(FileTransferChannel::staticMetaObject.className()), 0); // FT::FeatureCore /** * Create a new OutgoingFileTransferChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return An OutgoingFileTransferChannelPtr object pointing to the newly created * OutgoingFileTransferChannel object. */ OutgoingFileTransferChannelPtr OutgoingFileTransferChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return OutgoingFileTransferChannelPtr(new OutgoingFileTransferChannel( connection, objectPath, immutableProperties, OutgoingFileTransferChannel::FeatureCore)); } /** * Construct a new OutgoingFileTransferChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on OutgoingFileTransferChannel::FeatureCore. */ OutgoingFileTransferChannel::OutgoingFileTransferChannel( const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : FileTransferChannel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ OutgoingFileTransferChannel::~OutgoingFileTransferChannel() { delete mPriv; } /** * Provide the file for an outgoing file transfer which has been offered. * * The state will change to #FileTransferStateOpen as soon as the transfer * starts. * The given input device should not be destroyed until the state() * changes to #FileTransferStateCompleted or #FileTransferStateCancelled. * If input is a sequential device QIODevice::isSequential(), it should be * closed when no more data is available, so that it's known when to stop reading. * * Only the primary handler of a file transfer channel may call this method. * * This method requires FileTransferChannel::FeatureCore to be ready. * * \param input A QIODevice object where the data will be read from. * \return A PendingOperation object which will emit PendingOperation::finished * when the call has finished. * \sa stateChanged(), state(), stateReason() */ PendingOperation *OutgoingFileTransferChannel::provideFile(QIODevice *input) { if (!isReady(FileTransferChannel::FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling provideFile"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), OutgoingFileTransferChannelPtr(this)); } // let's fail here direclty as we may only have one device to handle if (mPriv->input) { warning() << "File transfer can only be started once in the same " "channel"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("File transfer can only be started once in the same channel"), OutgoingFileTransferChannelPtr(this)); } if ((!input->isOpen() && !input->open(QIODevice::ReadOnly)) && !input->isReadable()) { warning() << "Unable to open IO device for reading"; return new PendingFailure(TP_QT_ERROR_PERMISSION_DENIED, QLatin1String("Unable to open IO device for reading"), OutgoingFileTransferChannelPtr(this)); } mPriv->input = input; connect(input, SIGNAL(aboutToClose()), SLOT(onInputAboutToClose())); PendingVariant *pv = new PendingVariant( mPriv->fileTransferInterface->ProvideFile( SocketAddressTypeIPv4, SocketAccessControlLocalhost, QDBusVariant(QVariant(QString()))), OutgoingFileTransferChannelPtr(this)); connect(pv, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onProvideFileFinished(Tp::PendingOperation*))); return pv; } void OutgoingFileTransferChannel::onProvideFileFinished(PendingOperation *op) { if (op->isError()) { warning() << "Error providing file transfer " << op->errorName() << ":" << op->errorMessage(); invalidate(op->errorName(), op->errorMessage()); return; } PendingVariant *pv = qobject_cast(op); mPriv->addr = qdbus_cast(pv->result()); debug().nospace() << "Got address " << mPriv->addr.address << ":" << mPriv->addr.port; if (state() == FileTransferStateOpen) { connectToHost(); } } void OutgoingFileTransferChannel::connectToHost() { if (isConnected() || mPriv->addr.address.isNull()) { return; } mPriv->socket = new QTcpSocket(this); connect(mPriv->socket, SIGNAL(connected()), SLOT(onSocketConnected())); connect(mPriv->socket, SIGNAL(disconnected()), SLOT(onSocketDisconnected())); connect(mPriv->socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(onSocketError(QAbstractSocket::SocketError))); connect(mPriv->socket, SIGNAL(bytesWritten(qint64)), SLOT(doTransfer())); debug().nospace() << "Connecting to host " << mPriv->addr.address << ":" << mPriv->addr.port << "..."; mPriv->socket->connectToHost(mPriv->addr.address, mPriv->addr.port); } void OutgoingFileTransferChannel::onSocketConnected() { debug() << "Connected to host"; setConnected(); connect(mPriv->input, SIGNAL(readyRead()), SLOT(doTransfer())); // for non sequential devices, let's seek to the initialOffset if (!mPriv->input->isSequential()) { if (mPriv->input->seek(initialOffset())) { mPriv->pos = initialOffset(); } } debug() << "Starting transfer..."; doTransfer(); } void OutgoingFileTransferChannel::onSocketDisconnected() { debug() << "Disconnected from host"; setFinished(); } void OutgoingFileTransferChannel::onSocketError(QAbstractSocket::SocketError error) { debug() << "Socket error" << error; setFinished(); } void OutgoingFileTransferChannel::onInputAboutToClose() { debug() << "Input closed"; // read all remaining data from input device and write to output device if (isConnected()) { QByteArray data; data = mPriv->input->readAll(); mPriv->socket->write(data); // never fails } setFinished(); } void OutgoingFileTransferChannel::doTransfer() { // read FT_BLOCK_SIZE each time, as input can be a QFile, we don't want to // block reading the whole file char buffer[FT_BLOCK_SIZE]; char *p = buffer; memset(buffer, 0, sizeof(buffer)); qint64 len = mPriv->input->read(buffer, sizeof(buffer)); bool scheduleTransfer = false; if (((qulonglong) mPriv->pos < initialOffset()) && (len > 0)) { qint64 skip = (qint64) qMin(initialOffset() - mPriv->pos, (qulonglong) len); debug() << "skipping" << skip << "bytes"; if (skip == len) { // nothing to write, all data read was skipped // schedule a transfer, as readyRead may never be called and // bytesWriiten will not scheduleTransfer = true; goto end; } p += skip; len -= skip; } if (len > 0) { mPriv->socket->write(p, len); // never fails } end: if (len == -1 || (!mPriv->input->isSequential() && mPriv->input->atEnd())) { // error or EOF setFinished(); return; } mPriv->pos += len; if (scheduleTransfer) { QMetaObject::invokeMethod(this, SLOT(doTransfer()), Qt::QueuedConnection); } } void OutgoingFileTransferChannel::setFinished() { if (isFinished()) { // it shouldn't happen but let's make sure return; } if (mPriv->socket) { disconnect(mPriv->socket, SIGNAL(connected()), this, SLOT(onSocketConnected())); disconnect(mPriv->socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); disconnect(mPriv->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError))); disconnect(mPriv->socket, SIGNAL(bytesWritten(qint64)), this, SLOT(doTransfer())); mPriv->socket->close(); } if (mPriv->input) { disconnect(mPriv->input, SIGNAL(aboutToClose()), this, SLOT(onInputAboutToClose())); disconnect(mPriv->input, SIGNAL(readyRead()), this, SLOT(doTransfer())); mPriv->input->close(); } FileTransferChannel::setFinished(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/stream-tube-client.cpp0000664000175000017500000012461112470405660021431 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/stream-tube-client-internal.h" #include "TelepathyQt/_gen/stream-tube-client.moc.hpp" #include "TelepathyQt/_gen/stream-tube-client-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/simple-stream-tube-handler.h" #include #include #include #include #include #include #include namespace Tp { /** * \class StreamTubeClient::TcpSourceAddressGenerator * \ingroup serverclient * \headerfile TelepathyQt/stream-tube-client.h * * \brief The StreamTubeClient::TcpSourceAddressGenerator abstract interface allows using socket * source address/port based access control for connecting to tubes accepted as TCP sockets. * * By default, every application on the local computer is allowed to connect to the socket created * by the protocol backend as the local endpoint of the tube. This is not always desirable, as that * includes even other users. * * Note that since every TCP connection must have an unique source address, only one simultaneous * connection can be made through each tube for which this type of access control has been used. */ /** * \fn QPair StreamTubeClient::TcpSourceAddressGenerator::nextSourceAddress(const AccountPtr &, const * IncomingStreamTubeChannelPtr &) * * Return the source address from which connections will be allowed to the given \a tube once it has * been accepted. * * Returning the pair (QHostAddress::Any, 0) (or alternatively (QHostAddress::AnyIPv4, 0) in Qt5) * makes the protocol backend allow connections from any address on the local computer. * This can be used on a tube-by-tube basis if for some tubes its known that multiple connections * need to be made, so a single source address doesn't suffice. * * The \a account and \a tube parameters can be inspected to make the decision; typically by looking * at the tube's service type, parameters and/or initiator contact. * * The general pattern for implementing this method is: *
    *
  1. Determine whether \a tube needs to allow multiple connections, and if so, skip source address * access control completely
  2. *
  3. Otherwise, create a socket and bind it to a free address
  4. *
  5. Return this socket's address
  6. *
  7. Keep the socket bound so that no other process can (accidentally or maliciously) take the * address until it's used to connect to the tube when StreamTubeClient::tubeAcceptedAsTcp() is * emitted for the tube
  8. *
* * \param account The account from which the tube originates. * \param tube The tube channel which is going to be accepted by the StreamTubeClient. * * \return A pair containing the host address and port allowed to connect. */ /** * \fn StreamTubeClient::TcpSourceAddressGenerator::~TcpSourceAddressGenerator * * Class destructor. Protected, because StreamTubeClient never deletes a TcpSourceAddressGenerator passed * to it. */ struct TP_QT_NO_EXPORT StreamTubeClient::Tube::Private : public QSharedData { // empty placeholder for now }; /** * \class StreamTubeClient::Tube * \ingroup serverclient * \headerfile TelepathyQt/stream-tube-client.h * * \brief The StreamTubeClient::Tube class represents a tube being handled by the client. */ /** * Constructs a new invalid Tube instance. */ StreamTubeClient::Tube::Tube() { // invalid instance } /** * Constructs a Tube instance for the given tube \a channel from the given \a account. * * \param account A pointer to the account the online connection of which the tube originates from. * \param channel A pointer to the tube channel object. */ StreamTubeClient::Tube::Tube( const AccountPtr &account, const IncomingStreamTubeChannelPtr &channel) : QPair(account, channel), mPriv(new Private) { } /** * Copy constructor. */ StreamTubeClient::Tube::Tube( const Tube &other) : QPair(other.account(), other.channel()), mPriv(other.mPriv) { } /** * Class destructor. */ StreamTubeClient::Tube::~Tube() { // mPriv deleted automatically } /** * Assignment operator. */ StreamTubeClient::Tube &StreamTubeClient::Tube::operator=( const Tube &other) { if (&other == this) { return *this; } first = other.account(); second = other.channel(); mPriv = other.mPriv; return *this; } /** * \fn bool StreamTubeClient::Tube::isValid() const * * Return whether or not the tube is valid or is just the null object created using the default * constructor. * * \return \c true if valid, \c false otherwise. */ /** * \fn AccountPtr StreamTubeClient::Tube::account() const * * Return the account from which the tube originates. * * \return A pointer to the account object. */ /** * \fn IncomingStreamTubeChannelPtr StreamTubeClient::Tube::channel() const * * Return the actual tube channel. * * \return A pointer to the channel. */ struct TP_QT_NO_EXPORT StreamTubeClient::Private { Private(const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices, const QString &maybeClientName, bool monitorConnections, bool bypassApproval) : registrar(registrar), handler(SimpleStreamTubeHandler::create( p2pServices, roomServices, false, monitorConnections, bypassApproval)), clientName(maybeClientName), isRegistered(false), acceptsAsTcp(false), acceptsAsUnix(false), tcpGenerator(0), requireCredentials(false) { if (clientName.isEmpty()) { clientName = QString::fromLatin1("TpQtSTubeClient_%1_%2") .arg(registrar->dbusConnection().baseService() .replace(QLatin1Char(':'), QLatin1Char('_')) .replace(QLatin1Char('.'), QLatin1Char('_'))) .arg((quintptr) this, 0, 16); } } void ensureRegistered() { if (isRegistered) { return; } debug() << "Register StreamTubeClient with name " << clientName; if (registrar->registerClient(handler, clientName)) { isRegistered = true; } else { warning() << "StreamTubeClient" << clientName << "registration failed"; } } ClientRegistrarPtr registrar; SharedPtr handler; QString clientName; bool isRegistered; bool acceptsAsTcp, acceptsAsUnix; TcpSourceAddressGenerator *tcpGenerator; bool requireCredentials; QHash tubes; }; StreamTubeClient::TubeWrapper::TubeWrapper( const AccountPtr &acc, const IncomingStreamTubeChannelPtr &tube, const QHostAddress &sourceAddress, quint16 sourcePort, StreamTubeClient *parent) : QObject(parent), mAcc(acc), mTube(tube), mSourceAddress(sourceAddress), mSourcePort(sourcePort) { QHostAddress hostAddress = sourceAddress; if (sourcePort != 0) { #if QT_VERSION >= 0x050000 if (hostAddress == QHostAddress::Any || hostAddress == QHostAddress::LocalHost) { hostAddress = QHostAddress::AnyIPv4; } #endif if ((hostAddress.protocol() == QAbstractSocket::IPv4Protocol && !tube->supportsIPv4SocketsWithSpecifiedAddress()) || (hostAddress.protocol() == QAbstractSocket::IPv6Protocol && !tube->supportsIPv6SocketsWithSpecifiedAddress())) { debug() << "StreamTubeClient falling back to Localhost AC for tube" << tube->objectPath(); mSourceAddress = sourceAddress.protocol() == QAbstractSocket::IPv4Protocol ? QHostAddress::Any : QHostAddress::AnyIPv6; mSourcePort = 0; } } connect(tube->acceptTubeAsTcpSocket(mSourceAddress, mSourcePort), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onTubeAccepted(Tp::PendingOperation*))); connect(tube.data(), SIGNAL(newConnection(uint)), SLOT(onNewConnection(uint))); connect(tube.data(), SIGNAL(connectionClosed(uint,QString,QString)), SLOT(onConnectionClosed(uint,QString,QString))); } StreamTubeClient::TubeWrapper::TubeWrapper( const AccountPtr &acc, const IncomingStreamTubeChannelPtr &tube, bool requireCredentials, StreamTubeClient *parent) : QObject(parent), mAcc(acc), mTube(tube), mSourcePort(0) { if (requireCredentials && !tube->supportsUnixSocketsWithCredentials()) { debug() << "StreamTubeClient falling back to Localhost AC for tube" << tube->objectPath(); requireCredentials = false; } connect(tube->acceptTubeAsUnixSocket(requireCredentials), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onTubeAccepted(Tp::PendingOperation*))); connect(tube.data(), SIGNAL(newConnection(uint)), SLOT(onNewConnection(uint))); connect(tube.data(), SIGNAL(connectionClosed(uint,QString,QString)), SLOT(onConnectionClosed(uint,QString,QString))); } void StreamTubeClient::TubeWrapper::onTubeAccepted(Tp::PendingOperation *op) { emit acceptFinished(this, qobject_cast(op)); } void StreamTubeClient::TubeWrapper::onNewConnection(uint conn) { emit newConnection(this, conn); } void StreamTubeClient::TubeWrapper::onConnectionClosed(uint conn, const QString &error, const QString &message) { emit connectionClosed(this, conn, error, message); } /** * \class StreamTubeClient * \ingroup serverclient * \headerfile TelepathyQt/stream-tube-client.h * * \brief The StreamTubeClient class is a Handler implementation for incoming %Stream %Tube channels, * allowing an application to easily get notified about services they can connect to offered to them * over Telepathy Tubes without worrying about the channel dispatching details. * * Telepathy Tubes is a technology for connecting arbitrary applications together through the IM * network (and sometimes with direct peer-to-peer connections), such that issues like firewall/NAT * traversal are automatically handled. Stream Tubes in particular offer properties similar to * SOCK_STREAM sockets. The StreamTubeClient class negotiates tubes offered to us so that an * application can connect such bytestream sockets of theirs to them. The StreamTubeServer class is * the counterpart, offering services from a bytestream socket server to tubes requested to be * initiated. * * Both peer-to-peer (\c TargetHandleType == \ref HandleTypeContact) and group (\c TargetHandleType * == \ref HandleTypeRoom) channels are supported, and it's possible to specify the tube services to * handle for each separately. There must be at least one service in total declared, as it never * makes sense to handle stream tubes without considering the protocol of the service offered * through them. * * %Connection monitoring allows fine-grained error reporting for connections made through tubes, * and observing connections being made and broken even if the application code running * StreamTubeClient can't easily get this information from the code actually connecting through it. * Such a setting might occur e.g. when a wrapper application is developed to connect some existing * "black box" networked application through TCP tubes by launching it with the appropriate command * line arguments or alike for accepted tubes. * * Enabling connection monitoring adds a small overhead and latency to handling each incoming tube * and signaling each new incoming connection over them, though, so use it only when needed. * * A service activated Handler can be implemented using StreamTubeClient by passing a predefined \a * clientName manually to the chosen create() method, and installing Telepathy \c .client and D-Bus * \c .service files declaring the implemented tube services as channel classes and a path to the * executable. If this is not needed, the \a clientName can be omitted, in which case a random * unique client name is generated and used instead. However, then the tube client application must * already be running for remote contacts to be able to offer services to us over tubes. * * Whether the Handler application implemented using StreamTubeClient is service activatable or not, * incoming channels will typically first be given to an Approver, if there is one for tube services * corresponding to the tube in question. Only if the Approver decides that the tube communication * should be allowed (usually by asking the user), or if there is no matching Approver at all, is * the channel given to the actual Handler tube client. This can be overridden by setting \a * bypassApproval to \c true, which skips approval for the given services completely and directs * them straight to the Handler. * * StreamTubeClient shares Account, Connection and Channel proxies and Contact objects with the * rest of the application as long as a reference to the AccountManager, ClientRegistrar, or the * factories used elsewhere is passed to the create() method. A stand-alone tube client Handler can * get away without passing these however, or just passing select factories to make the desired * features prepared and subclasses employed for these objects for their own convenience. * * Whichever method is used, the ChannelFactory (perhaps indirectly) given must construct * IncomingStreamTubeChannel instances or subclasses thereof for all channel classes corresponding * to the tube services the client should be able to connect to. This is the default; overriding it * without obeying these constraints using ChannelFactory::setSubclassForIncomingStreamTubes() or * the related methods for room tubes prevents StreamTubeClient from operating correctly. * * \todo Coin up a small Python script or alike to easily generate the .client and .service files. * (fd.o #41614) */ /** * Create a new StreamTubeClient, which will register itself on the session bus using an internal * ClientRegistrar and use the given factories. * * \param p2pServices Names of the tube services to accept on peer-to-peer tube channels. * \param roomServices Names of the tube services to accept on room/group tube channels. * \param clientName The client name (without the \c org.freedesktop.Telepathy.Client. prefix). * \param monitorConnections Whether to enable connection monitoring or not. * \param bypassApproval \c true to skip approval, \c false to invoke an Approver for incoming * channels if there is one. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. */ StreamTubeClientPtr StreamTubeClient::create( const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections, bool bypassApproval, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return create( QDBusConnection::sessionBus(), accountFactory, connectionFactory, channelFactory, contactFactory, p2pServices, roomServices, clientName, monitorConnections, bypassApproval); } /** * Create a new StreamTubeClient, which will register itself on the given \a bus using an internal * ClientRegistrar and use the given factories. * * The factories must all be created for the given \a bus. * * \param bus Connection to the bus to register on. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \param p2pServices Names of the tube services to handle on peer-to-peer tube channels. * \param roomServices Names of the tube services to handle on room/group tube channels. * \param clientName The client name (without the \c org.freedesktop.Telepathy.Client. prefix). * \param monitorConnections Whether to enable connection monitoring or not. * \param bypassApproval \c true to skip approval, \c false to invoke an Approver for incoming * channels if there is one. */ StreamTubeClientPtr StreamTubeClient::create( const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections, bool bypassApproval) { return create( ClientRegistrar::create( bus, accountFactory, connectionFactory, channelFactory, contactFactory), p2pServices, roomServices, clientName, monitorConnections, bypassApproval); } /** * Create a new StreamTubeClient, which will register itself on the bus of and share objects with * the given \a accountManager, creating an internal ClientRegistrar. * * \param accountManager A pointer to the account manager to link up with. * \param p2pServices Names of the tube services to handle on peer-to-peer tube channels. * \param roomServices Names of the tube services to handle on room/group tube channels. * \param clientName The client name (without the \c org.freedesktop.Telepathy.Client. prefix). * \param monitorConnections Whether to enable connection monitoring or not. * \param bypassApproval \c true to skip approval, \c false to invoke an Approver for incoming * channels if there is one. */ StreamTubeClientPtr StreamTubeClient::create( const AccountManagerPtr &accountManager, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections, bool bypassApproval) { return create( accountManager->dbusConnection(), accountManager->accountFactory(), accountManager->connectionFactory(), accountManager->channelFactory(), accountManager->contactFactory(), p2pServices, roomServices, clientName, monitorConnections, bypassApproval); } /** * Create a new StreamTubeClient, which will register itself on the bus of and using the given * client \a registrar, and share objects with it. * * \param registrar The client registrar to use. * \param p2pServices Names of the tube services to handle on peer-to-peer tube channels. * \param roomServices Names of the tube services to handle on room/group tube channels. * \param clientName The client name (without the \c org.freedesktop.Telepathy.Client. prefix). * \param monitorConnections Whether to enable connection monitoring or not. * \param bypassApproval \c true to skip approval, \c false to invoke an Approver for incoming * channels if there is one. */ StreamTubeClientPtr StreamTubeClient::create( const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections, bool bypassApproval) { if (p2pServices.isEmpty() && roomServices.isEmpty()) { warning() << "Tried to create a StreamTubeClient with no services, returning NULL"; return StreamTubeClientPtr(); } return StreamTubeClientPtr( new StreamTubeClient(registrar, p2pServices, roomServices, clientName, monitorConnections, bypassApproval)); } StreamTubeClient::StreamTubeClient( const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections, bool bypassApproval) : mPriv(new Private(registrar, p2pServices, roomServices, clientName, monitorConnections, bypassApproval)) { connect(mPriv->handler.data(), SIGNAL(invokedForTube( Tp::AccountPtr, Tp::StreamTubeChannelPtr, QDateTime, Tp::ChannelRequestHints)), SLOT(onInvokedForTube( Tp::AccountPtr, Tp::StreamTubeChannelPtr, QDateTime, Tp::ChannelRequestHints))); } /** * Class destructor. */ StreamTubeClient::~StreamTubeClient() { if (isRegistered()) { mPriv->registrar->unregisterClient(mPriv->handler); } delete mPriv; } /** * Return the client registrar used by the client to register itself as a Telepathy channel Handler * %Client. * * This is the registrar originally passed to * create(const ClientRegistrarPtr &, const QStringList &, const QStringList &, const QString &, bool, bool) * if that was used, and an internally constructed one otherwise. In any case, it can be used to * e.g. register further clients, just like any other ClientRegistrar. * * \return A pointer to the registrar. */ ClientRegistrarPtr StreamTubeClient::registrar() const { return mPriv->registrar; } /** * Return the Telepathy %Client name of the client. * * \return The name, without the \c org.freedesktop.Telepathy.Client. prefix of the full D-Bus service name. */ QString StreamTubeClient::clientName() const { return mPriv->clientName; } /** * Return whether the client has been successfully registered or not. * * Registration is attempted, at the latest, when the client is first set to accept incoming tubes, * either as TCP sockets (setToAcceptAsTcp()) or Unix ones (setToAcceptAsUnix()). It can fail e.g. * because the connection to the bus has failed, or a predefined \a clientName has been passed to * create(), and a %Client with the same name is already registered. Typically, failure registering * would be a fatal error for a stand-alone tube handler, but only a warning event for an * application serving other purposes. In any case, a high-quality user of the API will check the * return value of this accessor after choosing the desired address family. * * \return \c true if the client has been successfully registered, \c false if not. */ bool StreamTubeClient::isRegistered() const { return mPriv->isRegistered; } /** * Return whether connection monitoring is enabled on this client. * * For technical reasons, connection monitoring can't be enabled when the client is already running, * so there is no corresponding setter method. It has to be enabled by passing \c true as the \a * monitorConnections parameter to the create() method. * * If connection monitoring isn't enabled, newConnection() and connectionClosed() won't be * emitted and connections() won't be populated. * * \return \c true if monitoring is enabled, \c false if not. */ bool StreamTubeClient::monitorsConnections() const { return mPriv->handler->monitorsConnections(); } /** * Return whether the client is currently set to accept incoming tubes as TCP sockets. * * \return \c true if the client will accept tubes as TCP sockets, \c false if it will accept them * as Unix ones or hasn't been set to accept at all yet. */ bool StreamTubeClient::acceptsAsTcp() const { return mPriv->acceptsAsTcp; } /** * Return the TCP source address generator, if any, set by setToAcceptAsTcp() previously. * * \return A pointer to the generator instance. */ StreamTubeClient::TcpSourceAddressGenerator *StreamTubeClient::tcpGenerator() const { if (!acceptsAsTcp()) { warning() << "StreamTubeClient::tcpGenerator() used, but not accepting as TCP, returning 0"; return 0; } return mPriv->tcpGenerator; } /** * Return whether the client is currently set to accept incoming tubes as Unix sockets. * * \return \c true if the client will accept tubes as Unix sockets, \c false if it will accept them * as TCP ones or hasn't been set to accept at all yet. */ bool StreamTubeClient::acceptsAsUnix() const { return mPriv->acceptsAsUnix; } /** * Set the client to accept tubes received to handle in the future in a fashion which will yield a * TCP socket as the local endpoint to connect to. * * A source address generator can optionally be set. If non-null, it will be invoked for each new * tube received to handle and an attempt is made to restrict connections to the tube's local socket * endpoint to those from that source address. * * However, if the protocol backend doesn't actually support source address based access control, * tubeAcceptedAsTcp() will be emitted with QHostAddress::Any * as the allowed source address to signal that it doesn't matter where we connect from, but more * importantly, that anybody else on the same host could have, and can, connect to the tube. * The tube can be closed at this point if this would be unacceptable security-wise. * To totally prevent the tube from being accepted in the first place, one can close it already when * tubeOffered() is emitted for it - support for the needed security mechanism can be queried using * its supportsIPv4SocketsWithSpecifiedAddress() accessor. * * The handler is registered on the bus at the latest when this method or setToAcceptAsUnix() is * called for the first time, so one should check the return value of isRegistered() at that point * to verify that was successful. * * \param generator A pointer to the source address generator to use, or 0 to allow all * connections from the local host. * * \todo Make it possible to set the tube client to auto-close tubes if the desired access control * level is not achieved, as an alternative to the current best-effort behavior. */ void StreamTubeClient::setToAcceptAsTcp(TcpSourceAddressGenerator *generator) { mPriv->tcpGenerator = generator; mPriv->acceptsAsTcp = true; mPriv->acceptsAsUnix = false; mPriv->ensureRegistered(); } /** * Set the client to accept tubes received to handle in the future in a fashion which will yield a * Unix socket as the local endpoint to connect to. * * If that doesn't cause problems for the payload protocol, it's possible to increase security by * restricting the processes allowed to connect to the local endpoint socket to those from the same * user ID as the protocol backend is running as by setting \a requireCredentials to \c true. This * requires transmitting a single byte, signaled as the \a credentialByte parameter to the * tubeAcceptedAsUnix() signal, in a \c SCM_CREDS or SCM_CREDENTIALS message, whichever is supported * by the platform, as the first thing after having connected to the socket. Even if the platform * doesn't implement either concept, the byte must still be sent. * * However, not all protocol backends support the credential passing based access control on all the * platforms they can run on. If a tube is offered through such a backend, tubeAcceptedAsUnix() will * be emitted with \a requiresCredentials set to \c false, to signal that a credential byte should * NOT be sent for that tube, and that any local process can or could have connected to the tube * already. The tube can be closed at this point if this would be unacceptable security-wise. To * totally prevent the tube from being accepted in the first place, one can close it already when * tubeOffered() is emitted for it - support for the needed security mechanism can be queried using * its supportsIPv4SocketsWithSpecifiedAddress() * accessor. * * The handler is registered on the bus at the latest when this method or setToAcceptAsTcp() is * called for the first time, so one should check the return value of isRegistered() at that point * to verify that was successful. * * \param requireCredentials \c true to try and restrict connecting by UID, \c false to allow all * connections. * * \todo Make it possible to set the tube client to auto-close tubes if the desired access control * level is not achieved, as an alternative to the current best-effort behavior. */ void StreamTubeClient::setToAcceptAsUnix(bool requireCredentials) { mPriv->tcpGenerator = 0; mPriv->acceptsAsTcp = false; mPriv->acceptsAsUnix = true; mPriv->requireCredentials = requireCredentials; mPriv->ensureRegistered(); } /** * Return the tubes currently handled by the client. * * \return A list of Tube structures containing pointers to the account and tube channel for each * tube. */ QList StreamTubeClient::tubes() const { QList tubes; foreach (TubeWrapper *wrapper, mPriv->tubes.values()) { tubes.push_back(Tube(wrapper->mAcc, wrapper->mTube)); } return tubes; } /** * Return the ongoing connections established through tubes signaled by this client. * * The returned mapping has for each Tube a structure containing pointers to the account and tube * channel objects as keys, with the integer identifiers for the current connections on them as the * values. The IDs are unique amongst the connections active on a single tube at any given time, but * not globally. * * This is effectively a state recovery accessor corresponding to the change notification signals * newConnection() and connectionClosed(). * * The mapping is only populated if connection monitoring was requested when creating the client (so * monitorsConnections() returns \c true). * * \return The connections in a mapping with Tube structures containing pointers to the account and * channel objects for each tube as keys, and the sets of numerical IDs as values. */ QHash > StreamTubeClient::connections() const { QHash > conns; if (!monitorsConnections()) { warning() << "StreamTubeClient::connections() used, but connection monitoring is disabled"; return conns; } foreach (const Tube &tube, tubes()) { if (!tube.channel()->isValid()) { // The tube has been invalidated, so skip it to avoid warnings // We're going to get rid of the wrapper in the next mainloop iteration when we get the // invalidation signal continue; } QSet tubeConns = tube.channel()->connections(); if (!tubeConns.empty()) { conns.insert(tube, tubeConns); } } return conns; } void StreamTubeClient::onInvokedForTube( const AccountPtr &acc, const StreamTubeChannelPtr &tube, const QDateTime &time, const ChannelRequestHints &hints) { Q_ASSERT(isRegistered()); // our SSTH shouldn't be receiving any channels unless it's registered Q_ASSERT(!tube->isRequested()); Q_ASSERT(tube->isValid()); // SSTH won't emit invalid tubes if (mPriv->tubes.contains(tube)) { debug() << "Ignoring StreamTubeClient reinvocation for tube" << tube->objectPath(); return; } IncomingStreamTubeChannelPtr incoming = IncomingStreamTubeChannelPtr::qObjectCast(tube); if (!incoming) { warning() << "The ChannelFactory used by StreamTubeClient must construct" << "IncomingStreamTubeChannel subclasses for Requested=false StreamTubes"; tube->requestClose(); return; } TubeWrapper *wrapper = 0; if (mPriv->acceptsAsTcp) { QPair srcAddr = qMakePair(QHostAddress(QHostAddress::Any), quint16(0)); if (mPriv->tcpGenerator) { srcAddr = mPriv->tcpGenerator->nextSourceAddress(acc, incoming); } wrapper = new TubeWrapper(acc, incoming, srcAddr.first, srcAddr.second, this); } else { Q_ASSERT(mPriv->acceptsAsUnix); // we should only be registered when we're set to accept as either TCP or Unix wrapper = new TubeWrapper(acc, incoming, mPriv->requireCredentials, this); } connect(wrapper, SIGNAL(acceptFinished(TubeWrapper*,Tp::PendingStreamTubeConnection*)), SLOT(onAcceptFinished(TubeWrapper*,Tp::PendingStreamTubeConnection*))); connect(tube.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onTubeInvalidated(Tp::DBusProxy*,QString,QString))); if (monitorsConnections()) { connect(wrapper, SIGNAL(newConnection(TubeWrapper*,uint)), SLOT(onNewConnection(TubeWrapper*,uint))); connect(wrapper, SIGNAL(connectionClosed(TubeWrapper*,uint,QString,QString)), SLOT(onConnectionClosed(TubeWrapper*,uint,QString,QString))); } mPriv->tubes.insert(tube, wrapper); emit tubeOffered(acc, incoming); } void StreamTubeClient::onAcceptFinished(TubeWrapper *wrapper, PendingStreamTubeConnection *conn) { Q_ASSERT(wrapper != NULL); Q_ASSERT(conn != NULL); if (!mPriv->tubes.contains(wrapper->mTube)) { debug() << "StreamTubeClient ignoring Accept result for invalidated tube" << wrapper->mTube->objectPath(); return; } if (conn->isError()) { warning() << "StreamTubeClient couldn't accept tube" << wrapper->mTube->objectPath() << '-' << conn->errorName() << ':' << conn->errorMessage(); if (wrapper->mTube->isValid()) { wrapper->mTube->requestClose(); } wrapper->mTube->disconnect(this); emit tubeClosed(wrapper->mAcc, wrapper->mTube, conn->errorName(), conn->errorMessage()); mPriv->tubes.remove(wrapper->mTube); wrapper->deleteLater(); return; } debug() << "StreamTubeClient accepted tube" << wrapper->mTube->objectPath(); if (conn->addressType() == SocketAddressTypeIPv4 || conn->addressType() == SocketAddressTypeIPv6) { QPair addr = conn->ipAddress(); emit tubeAcceptedAsTcp(addr.first, addr.second, wrapper->mSourceAddress, wrapper->mSourcePort, wrapper->mAcc, wrapper->mTube); } else { emit tubeAcceptedAsUnix(conn->localAddress(), conn->requiresCredentials(), conn->credentialByte(), wrapper->mAcc, wrapper->mTube); } } void StreamTubeClient::onTubeInvalidated(Tp::DBusProxy *proxy, const QString &error, const QString &message) { StreamTubeChannelPtr tube(qobject_cast(proxy)); Q_ASSERT(!tube.isNull()); TubeWrapper *wrapper = mPriv->tubes.value(tube); if (!wrapper) { // Accept finish with error already removed it return; } debug() << "Client StreamTube" << tube->objectPath() << "invalidated - " << error << ':' << message; emit tubeClosed(wrapper->mAcc, wrapper->mTube, error, message); mPriv->tubes.remove(tube); delete wrapper; } void StreamTubeClient::onNewConnection( TubeWrapper *wrapper, uint conn) { Q_ASSERT(monitorsConnections()); emit newConnection(wrapper->mAcc, wrapper->mTube, conn); } void StreamTubeClient::onConnectionClosed( TubeWrapper *wrapper, uint conn, const QString &error, const QString &message) { Q_ASSERT(monitorsConnections()); emit connectionClosed(wrapper->mAcc, wrapper->mTube, conn, error, message); } /** * \fn void StreamTubeClient::tubeOffered(const AccountPtr &account, const * IncomingStreamTubeChannelPtr &tube) * * Emitted when one of the services we're interested in connecting to has been offered by us as a * tube, which we've began handling. * * This is emitted before invoking the TcpSourceAddressGenerator, if any, for the tube. * * \param account A pointer to the account through which the tube was offered. * \param tube A pointer to the actual tube channel. */ /** * \fn void StreamTubeClient::tubeAcceptedAsTcp(const QHostAddress &listenAddress, quint16 * listenPort, const QHostAddress &sourceAddress, quint16 sourcePort, const AccountPtr &account, * const IncomingStreamTubeChannelPtr &tube) * * Emitted when a tube offered to us (previously announced with tubeOffered()) has been successfully * accepted and a TCP socket established as the local endpoint, as specified by setToAcceptAsTcp(). * * The allowed source address and port are signaled here if there was a TcpSourceAddressGenerator set * at the time of accepting this tube, it yielded a non-zero address, and the protocol backend * supports source address based access control. This enables the application to use the correct one * of the sockets it currently has bound to the generated addresses. * * \param listenAddress The listen address of the local endpoint socket. * \param listenPort The listen port of the local endpoint socket. * \param sourceAddress The host address allowed to connect to the tube, or QHostAddress::Any * if source address based access control is not in use. * \param sourcePort The port from which connections are allowed to the tube, or 0 if source address * based access control is not in use. * \param account A pointer to the account object through which the tube was offered. * \param tube A pointer to the actual tube channel object. */ // Explicitly specifying Tp:: for this signal's argument types works around a doxygen bug causing it // to confuse the doc here being for StreamTubeServer::tubeClosed :/ /** * \fn void StreamTubeClient::tubeClosed(const Tp::AccountPtr &account, const * Tp::IncomingStreamTubeChannelPtr &tube, const QString &error, const QString &message) * * Emitted when a tube we've been handling (previously announced with tubeOffered()) has * encountered an error or has otherwise been closed from further communication. * * \param account A pointer to the account through which the tube was offered. * \param tube A pointer to the actual tube channel. * \param error The D-Bus error name corresponding to the reason for the closure. * \param message A freeform debug message associated with the error. */ /** * \fn void StreamTubeClient::tubeAcceptedAsUnix(const QHostAddress &listenAddress, quint16 * listenPort, const QHostAddress &sourceAddress, quint16 sourcePort, const AccountPtr &account, * const IncomingStreamTubeChannelPtr &tube) * * Emitted when a tube offered to us (previously announced with tubeOffered()) has been successfully * accepted and a Unix socket established as the local endpoint, as specified by setToAcceptAsUnix(). * * The credential byte which should be sent after connecting to the tube (in a SCM_CREDENTIALS or * SCM_CREDS message if supported by the platform) will be signaled here if the client was set to * attempt requiring credentials at the time of accepting this tube, and the protocol backend * supports credential passing based access control. Otherwise, \a requiresCredentials will be false * and no byte or associated out-of-band credentials metadata should be sent. * * \param listenAddress The listen address of the local endpoint socket. * \param requiresCredentials \c true if \a credentialByte should be sent after connecting to the * socket, \c false if not. * \param credentialByte The byte to send if \a requiresCredentials is \c true. * \param account A pointer to the account object through which the tube was offered. * \param tube A pointer to the actual tube channel object. */ /** * \fn void StreamTubeClient::newConnection(const AccountPtr &account, const * IncomingStreamTubeChannelPtr &tube, uint connectionId) * * Emitted when a new connection has been made to the local endpoint socket for \a tube. * * This can be used to later associate connection errors reported by connectionClosed() with the * corresponding application sockets. However, establishing the association generally requires * connecting only one socket at a time, waiting for newConnection() to be emitted, and only then * proceeding, as there is no identification for the connections unlike the incoming connections in * StreamTubeServer. * * Note that the connection IDs are only unique within a given tube, so identification of the tube * channel must also be recorded together with the ID to establish global uniqueness. Even then, the * a connection ID can be reused after the previous connection identified by it having been * signaled as closed with connectionClosed(). * * This is only emitted if connection monitoring was enabled when creating the StreamTubeClient. * * \param account A pointer to the account through which the tube was offered. * \param tube A pointer to the tube channel through which the connection has been made. * \param connectionId The integer ID of the new connection. */ /** * \fn void StreamTubeClient::connectionClosed(const AccountPtr &account, const * IncomingStreamTubeChannelPtr &tube, uint connectionId, const QString &error, const * QString &message) * * Emitted when a connection (previously announced with newConnection()) through one of our * handled tubes has been closed due to an error or by a graceful disconnect (in which case the * error is ::TP_QT_ERROR_CANCELLED). * * This is only emitted if connection monitoring was enabled when creating the StreamTubeClient. * * \param account A pointer to the account through which the tube was offered. * \param tube A pointer to the tube channel through which the connection had been made. * \param connectionId The integer ID of the connection closed. * \param error The D-Bus error name corresponding to the reason for the closure. * \param message A freeform debug message associated with the error. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/stream-tube-client.h0000664000175000017500000001617512470405660021103 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_stream_tube_client_h_HEADER_GUARD_ #define _TelepathyQt_stream_tube_client_h_HEADER_GUARD_ #include #include #include #include #include #include class QHostAddress; namespace Tp { class PendingStreamTubeConnection; class TP_QT_EXPORT StreamTubeClient : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(StreamTubeClient) class TubeWrapper; public: class TcpSourceAddressGenerator { public: virtual QPair nextSourceAddress(const AccountPtr &account, const IncomingStreamTubeChannelPtr &tube) = 0; protected: virtual ~TcpSourceAddressGenerator() {} }; class Tube : public QPair { public: Tube(); Tube(const AccountPtr &account, const IncomingStreamTubeChannelPtr &channel); Tube(const Tube &other); ~Tube(); bool isValid() const { return mPriv.constData() != 0; } Tube &operator=(const Tube &other); const AccountPtr &account() const { return first; } const IncomingStreamTubeChannelPtr &channel() const { return second; } private: struct Private; friend struct Private; QSharedDataPointer mPriv; }; static StreamTubeClientPtr create( const QStringList &p2pServices, const QStringList &roomServices = QStringList(), const QString &clientName = QString(), bool monitorConnections = false, bool bypassApproval = false, const AccountFactoryConstPtr &accountFactory = AccountFactory::create(QDBusConnection::sessionBus()), const ConnectionFactoryConstPtr &connectionFactory = ConnectionFactory::create(QDBusConnection::sessionBus()), const ChannelFactoryConstPtr &channelFactory = ChannelFactory::create(QDBusConnection::sessionBus()), const ContactFactoryConstPtr &contactFactory = ContactFactory::create()); static StreamTubeClientPtr create( const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const QStringList &p2pServices, const QStringList &roomServices = QStringList(), const QString &clientName = QString(), bool monitorConnections = false, bool bypassApproval = false); static StreamTubeClientPtr create( const AccountManagerPtr &accountManager, const QStringList &p2pServices, const QStringList &roomServices = QStringList(), const QString &clientName = QString(), bool monitorConnections = false, bool bypassApproval = false); static StreamTubeClientPtr create( const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices = QStringList(), const QString &clientName = QString(), bool monitorConnections = false, bool bypassApproval = false); virtual ~StreamTubeClient(); ClientRegistrarPtr registrar() const; QString clientName() const; bool isRegistered() const; bool monitorsConnections() const; bool acceptsAsTcp() const; TcpSourceAddressGenerator *tcpGenerator() const; bool acceptsAsUnix() const; void setToAcceptAsTcp(TcpSourceAddressGenerator *generator = 0); void setToAcceptAsUnix(bool requireCredentials = false); QList tubes() const; QHash > connections() const; Q_SIGNALS: void tubeOffered( const Tp::AccountPtr &account, const Tp::IncomingStreamTubeChannelPtr &tube); void tubeClosed( const Tp::AccountPtr &account, const Tp::IncomingStreamTubeChannelPtr &tube, const QString &error, const QString &message); void tubeAcceptedAsTcp( const QHostAddress &listenAddress, quint16 listenPort, const QHostAddress &sourceAddress, quint16 sourcePort, const Tp::AccountPtr &account, const Tp::IncomingStreamTubeChannelPtr &tube); void tubeAcceptedAsUnix( const QString &listenAddress, bool requiresCredentials, uchar credentialByte, const Tp::AccountPtr &account, const Tp::IncomingStreamTubeChannelPtr &tube); void newConnection( const Tp::AccountPtr &account, const Tp::IncomingStreamTubeChannelPtr &tube, uint connectionId); void connectionClosed( const Tp::AccountPtr &account, const Tp::IncomingStreamTubeChannelPtr &tube, uint connectionId, const QString &error, const QString &message); private Q_SLOTS: TP_QT_NO_EXPORT void onInvokedForTube( const Tp::AccountPtr &account, const Tp::StreamTubeChannelPtr &tube, const QDateTime &userActionTime, const Tp::ChannelRequestHints &requestHints); TP_QT_NO_EXPORT void onAcceptFinished(TubeWrapper *, Tp::PendingStreamTubeConnection *); TP_QT_NO_EXPORT void onTubeInvalidated(Tp::DBusProxy *, const QString &, const QString &); TP_QT_NO_EXPORT void onNewConnection( TubeWrapper *wrapper, uint conn); TP_QT_NO_EXPORT void onConnectionClosed( TubeWrapper *wrapper, uint conn, const QString &error, const QString &message); private: TP_QT_NO_EXPORT StreamTubeClient( const ClientRegistrarPtr ®istrar, const QStringList &p2pServices, const QStringList &roomServices, const QString &clientName, bool monitorConnections, bool bypassApproval); struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/StatefulDBusProxy0000664000175000017500000000037212470405660020550 0ustar jrjr#ifndef _TelepathyQt_StatefulDBusProxy_HEADER_GUARD_ #define _TelepathyQt_StatefulDBusProxy_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AccountInterfaceAddressingInterface0000664000175000017500000000043312470405660024201 0ustar jrjr#ifndef _TelepathyQt_AccountInterfaceAddressingInterface_HEADER_GUARD_ #define _TelepathyQt_AccountInterfaceAddressingInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/incoming-dbus-tube-channel.cpp0000664000175000017500000001650312470405660023026 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/incoming-dbus-tube-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT IncomingDBusTubeChannel::Private { public: Private(IncomingDBusTubeChannel *parent); // Public object IncomingDBusTubeChannel *parent; }; IncomingDBusTubeChannel::Private::Private(IncomingDBusTubeChannel *parent) : parent(parent) { } /** * \class IncomingDBusTubeChannel * \ingroup clientchannel * \headerfile TelepathyQt/incoming-dbus-tube-channel.h * * \brief The IncomingStreamTubeChannel class represents an incoming Telepathy channel * of type StreamTube. * * In particular, this class is meant to be used as a comfortable way for * accepting incoming DBus tubes. Unless a different behavior is specified, tubes * will be always accepted allowing connections just from the current user, unless this * or one of the other ends do not support that. Unless your application has specific needs, * you usually want to keep this behavior. * * Once a tube is successfully accepted and open (the PendingDBusTubeConnection returned from the * accepting methods has finished), the application can connect to the DBus server, the address of which * can be retrieved from PendingDBusTubeConnection::address(). * * \note If you plan to use QtDBus for the DBus connection, please note you should always use * QDBusConnection::connectToPeer(), regardless of the fact this tube is a p2p or a group one. * The above function has been introduced in Qt 4.8, previous versions of Qt do not allow the use * of DBus Tubes through QtDBus. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Create a new IncomingDBusTubeChannel channel. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The object path of this channel. * \param immutableProperties The immutable properties of this channel. * \return A IncomingDBusTubeChannelPtr object pointing to the newly created * IncomingDBusTubeChannel object. */ IncomingDBusTubeChannelPtr IncomingDBusTubeChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return IncomingDBusTubeChannelPtr(new IncomingDBusTubeChannel(connection, objectPath, immutableProperties)); } /** * Construct a new IncomingDBusTubeChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The object path of this channel. * \param immutableProperties The immutable properties of this channel. */ IncomingDBusTubeChannel::IncomingDBusTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) : DBusTubeChannel(connection, objectPath, immutableProperties), mPriv(new Private(this)) { } /** * Class destructor. */ IncomingDBusTubeChannel::~IncomingDBusTubeChannel() { delete mPriv; } /** * Accepts an incoming DBus tube. * * This method accepts an incoming connection request for a DBus tube. It can be called * only if the tube is in the \c LocalPending state. * * Once called, this method will try opening the tube, and will create a new private DBus connection * which can be used to communicate with the other end. You can then * retrieve the address either from \c PendingDBusTubeConnection or from %address(). * * This method requires DBusTubeChannel::FeatureCore to be enabled. * * \param allowOtherUsers Whether the server should allow other users to connect to this tube more * than just the current one. If your application has no specific needs, it is * advisable not to modify the default value of this argument. * * \note If allowOtherUsers == false, but one of the ends does not support current user restriction, * the tube will be offered regardless, falling back to allowing any connection. If your * application requires strictly this condition to be enforced, you should check * DBusTubeChannel::supportsRestrictingToCurrentUser before accepting the tube, * and take action from there. * The tube is guaranteed either to be accepted with the desired * restriction or to fail the accept phase if supportsRestrictingToCurrentUser is true * and allowOtherUsers is false. * * \return A %PendingDBusTubeConnection which will finish as soon as the tube is ready to be used * (hence in the Open state) */ PendingDBusTubeConnection *IncomingDBusTubeChannel::acceptTube(bool allowOtherUsers) { SocketAccessControl accessControl = allowOtherUsers ? SocketAccessControlLocalhost : SocketAccessControlCredentials; if (!isReady(DBusTubeChannel::FeatureCore)) { warning() << "DBusTubeChannel::FeatureCore must be ready before " "calling acceptTube"; return new PendingDBusTubeConnection(QLatin1String(TP_QT_ERROR_NOT_AVAILABLE), QLatin1String("Channel not ready"), IncomingDBusTubeChannelPtr(this)); } // The tube must be in local pending state if (state() != TubeChannelStateLocalPending) { warning() << "You can accept tubes only when they are in LocalPending state"; return new PendingDBusTubeConnection(QLatin1String(TP_QT_ERROR_NOT_AVAILABLE), QLatin1String("Channel busy"), IncomingDBusTubeChannelPtr(this)); } // Let's accept the tube if (!allowOtherUsers && !supportsRestrictingToCurrentUser()) { warning() << "Current user restriction is not available for this tube, " "falling back to allowing any connection"; accessControl = SocketAccessControlLocalhost; } PendingString *ps = new PendingString( interface()->Accept( accessControl), IncomingDBusTubeChannelPtr(this)); PendingDBusTubeConnection *op = new PendingDBusTubeConnection(ps, accessControl == SocketAccessControlLocalhost, QVariantMap(), IncomingDBusTubeChannelPtr(this)); return op; } } telepathy-qt-0.9.6~git1/TelepathyQt/or-filter.h0000664000175000017500000000444312470405660017275 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_or_filter_h_HEADER_GUARD_ #define _TelepathyQt_or_filter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { template class OrFilter : public Filter { public: static SharedPtr > create( const QList > > &filters = QList > >()) { return SharedPtr >(new OrFilter(filters)); } inline virtual ~OrFilter() { } inline virtual bool isValid() const { Q_FOREACH (const SharedPtr > &filter, mFilters) { if (!filter || !filter->isValid()) { return false; } } return true; } inline virtual bool matches(const SharedPtr &t) const { if (!isValid()) { return false; } Q_FOREACH (const SharedPtr > &filter, mFilters) { if (filter->matches(t)) { return true; } } return false; } inline QList > > filters() const { return mFilters; } private: OrFilter(const QList > > &filters) : Filter(), mFilters(filters) { } QList > > mFilters; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/and-filter.dox0000664000175000017500000000235212470405660017757 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \class Tp::AndFilter * \ingroup utils * \headerfile TelepathyQt/and-filter.h * * \brief The AndFilter class provides a generic filter object to be used * in conjunction of other filters. * * The AndFilter will match if all of its given list of filters matches * their criteria. */ telepathy-qt-0.9.6~git1/TelepathyQt/channel-dispatcher.h0000664000175000017500000000221712470405660021123 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_channel_dispatcher_h_HEADER_GUARD_ #define _TelepathyQt_channel_dispatcher_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/contact-messenger.h0000664000175000017500000000473012470405660021012 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_contact_messenger_h_HEADER_GUARD_ #define _TelepathyQt_contact_messenger_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class PendingSendMessage; class MessageContentPartList; class TP_QT_EXPORT ContactMessenger : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(ContactMessenger) public: static ContactMessengerPtr create(const AccountPtr &account, const ContactPtr &contact); static ContactMessengerPtr create(const AccountPtr &account, const QString &contactIdentifier); virtual ~ContactMessenger(); AccountPtr account() const; QString contactIdentifier() const; QList textChats() const; PendingSendMessage *sendMessage(const QString &text, ChannelTextMessageType type = ChannelTextMessageTypeNormal, MessageSendingFlags flags = 0); PendingSendMessage *sendMessage(const MessageContentPartList &parts, MessageSendingFlags flags = 0); Q_SIGNALS: void messageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken, const Tp::TextChannelPtr &channel); void messageReceived(const Tp::ReceivedMessage &message, const Tp::TextChannelPtr &channel); private: TP_QT_NO_EXPORT ContactMessenger(const AccountPtr &account, const QString &contactIdentifier); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/debug-receiver.cpp0000664000175000017500000001504412470405660020614 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011-2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/debug-receiver.moc.hpp" #include "TelepathyQt/_gen/cli-debug-receiver-body.hpp" #include "TelepathyQt/_gen/cli-debug-receiver.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT DebugReceiver::Private { Private(DebugReceiver *parent); static void introspectCore(Private *self); DebugReceiver *parent; Client::DebugInterface *baseInterface; }; DebugReceiver::Private::Private(DebugReceiver *parent) : parent(parent), baseInterface(new Client::DebugInterface(parent)) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &DebugReceiver::Private::introspectCore, this); introspectables[DebugReceiver::FeatureCore] = introspectableCore; parent->readinessHelper()->addIntrospectables(introspectables); } void DebugReceiver::Private::introspectCore(DebugReceiver::Private *self) { // this is done only to verify that the object exists... PendingVariantMap *op = self->baseInterface->requestAllProperties(); self->parent->connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onRequestAllPropertiesFinished(Tp::PendingOperation*))); } /** * \class DebugReceiver * \ingroup clientsideproxies * \headerfile TelepathyQt/debug-receiver.h * * \brief The DebugReceiver class provides a D-Bus proxy for a Telepathy * Debug object. * * A Debug object provides debugging messages from services. */ /** * Feature representing the core that needs to become ready to make the DebugReceiver * object usable. * * Note that this feature must be enabled in order to use most DebugReceiver methods. * See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature DebugReceiver::FeatureCore = Feature(QLatin1String(DebugReceiver::staticMetaObject.className()), 0, true); DebugReceiverPtr DebugReceiver::create(const QString &busName, const QDBusConnection &bus) { return DebugReceiverPtr(new DebugReceiver(bus, busName)); } DebugReceiver::DebugReceiver(const QDBusConnection &bus, const QString &busName) : StatefulDBusProxy(bus, busName, TP_QT_DEBUG_OBJECT_PATH, DebugReceiver::FeatureCore), mPriv(new Private(this)) { } DebugReceiver::~DebugReceiver() { delete mPriv; } /** * Retrieves buffered debug messages. * * This method returns a list of buffered debug messages. Depending on the service side * implementation, this may not be the entire list of all messages received during the * service's lifetime. Use monitoring instead for getting all the messages being streamed * in realtime. * * \return A pending operation returning a list of buffered debug messages when finished. * * \sa setMonitoringEnabled */ PendingDebugMessageList *DebugReceiver::fetchMessages() { return new PendingDebugMessageList(mPriv->baseInterface->GetMessages(), DebugReceiverPtr(this)); } /** * Enables or disables the emission of newDebugMessage. * * This function either enables or disables the emission of newDebugMessage. If monitoring is * enabled, everytime a message will be received, newDebugMessage will be emitted carrying the * new message. * * Monitoring should be disabled when not needed, as it generates a high amount of traffic on * the bus. It is always disabled by default. * * This method requires FeatureCore to be enabled. * * \param enabled Whether to enable or disable monitoring. * * \return A pending operation returning whether the operation succeeded or not. * * \sa newDebugMessage */ PendingOperation *DebugReceiver::setMonitoringEnabled(bool enabled) { if (!isReady()) { warning() << "DebugReceiver::setMonitoringEnabled called without DebugReceiver being ready"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("FeatureCore is not ready"), DebugReceiverPtr(this)); } return mPriv->baseInterface->setPropertyEnabled(enabled); } void DebugReceiver::onRequestAllPropertiesFinished(Tp::PendingOperation *op) { if (op->isError()) { readinessHelper()->setIntrospectCompleted( FeatureCore, false, op->errorName(), op->errorMessage()); } else { connect(mPriv->baseInterface, SIGNAL(NewDebugMessage(double,QString,uint,QString)), SLOT(onNewDebugMessage(double,QString,uint,QString))); readinessHelper()->setIntrospectCompleted(FeatureCore, true); } } void DebugReceiver::onNewDebugMessage(double time, const QString &domain, uint level, const QString &message) { DebugMessage msg; msg.timestamp = time; msg.domain = domain; msg.level = level; msg.message = message; emit newDebugMessage(msg); } /** * \fn void DebugReceiver::newDebugMessage(const Tp::DebugMessage &msg) * * Emitted whenever a new debug message is available. This will be emitted only if * monitoring has been previously enabled. * * \param msg The new debug message. * * \sa setMonitoringEnabled */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/PendingConnection0000664000175000017500000000040212470405660020537 0ustar jrjr#ifndef _TelepathyQt_PendingConnection_HEADER_GUARD_ #define _TelepathyQt_PendingConnection_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel-dispatch-operation.h0000664000175000017500000000727312470405660022601 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_channel_dispatch_operation_h_HEADER_GUARD_ #define _TelepathyQt_channel_dispatch_operation_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { class PendingOperation; class TP_QT_EXPORT ChannelDispatchOperation : public StatefulDBusProxy, public OptionalInterfaceFactory { Q_OBJECT Q_DISABLE_COPY(ChannelDispatchOperation) public: static const Feature FeatureCore; static ChannelDispatchOperationPtr create(const QDBusConnection &bus, const QString &objectPath, const QVariantMap &immutableProperties, const QList &initialChannels, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory); virtual ~ChannelDispatchOperation(); ConnectionPtr connection() const; AccountPtr account() const; QList channels() const; QStringList possibleHandlers() const; PendingOperation *handleWith(const QString &handler); PendingOperation *claim(); PendingOperation *claim(const AbstractClientHandlerPtr &handler); Q_SIGNALS: void channelLost(const Tp::ChannelPtr &channel, const QString &errorName, const QString &errorMessage); protected: ChannelDispatchOperation(const QDBusConnection &bus, const QString &objectPath, const QVariantMap &immutableProperties, const QList &initialChannels, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory); Client::ChannelDispatchOperationInterface *baseInterface() const; private Q_SLOTS: TP_QT_NO_EXPORT void onFinished(); TP_QT_NO_EXPORT void gotMainProperties(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onChannelLost(const QDBusObjectPath &channelObjectPath, const QString &errorName, const QString &errorMessage); TP_QT_NO_EXPORT void onProxiesPrepared(Tp::PendingOperation *op); private: class PendingClaim; friend class PendingClaim; struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeContactListInterface0000664000175000017500000000042312470405660023341 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeContactListInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeContactListInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterface0000664000175000017500000000036512470405660020334 0ustar jrjr#ifndef _TelepathyQt_ChannelInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/presence.cpp0000664000175000017500000002720012470405660017525 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/debug-internal.h" namespace Tp { struct TP_QT_NO_EXPORT Presence::Private : public QSharedData { Private(const SimplePresence &sp) : sp(sp) { } Private(ConnectionPresenceType type, const QString &status, const QString &statusMessage) { sp.type = type; sp.status = status; sp.statusMessage = statusMessage; } SimplePresence sp; }; /** * \class Presence * \ingroup wrappers * \headerfile TelepathyQt/presence.h * * \brief The Presence class represents a Telepathy simple presence. */ Presence::Presence() { } Presence::Presence(const SimplePresence &sp) : mPriv(new Private(sp)) { } Presence::Presence(ConnectionPresenceType type, const QString &status, const QString &statusMessage) : mPriv(new Private(type, status, statusMessage)) { } Presence::Presence(const Presence &other) : mPriv(other.mPriv) { } Presence::~Presence() { } Presence Presence::available(const QString &statusMessage) { return Presence(ConnectionPresenceTypeAvailable, QLatin1String("available"), statusMessage); } Presence Presence::chat(const QString &statusMessage) { return Presence(ConnectionPresenceTypeAvailable, QLatin1String("chat"), statusMessage); } Presence Presence::away(const QString &statusMessage) { return Presence(ConnectionPresenceTypeAway, QLatin1String("away"), statusMessage); } Presence Presence::brb(const QString &statusMessage) { return Presence(ConnectionPresenceTypeAway, QLatin1String("brb"), statusMessage); } Presence Presence::busy(const QString &statusMessage) { return Presence(ConnectionPresenceTypeBusy, QLatin1String("busy"), statusMessage); } Presence Presence::dnd(const QString &statusMessage) { return Presence(ConnectionPresenceTypeBusy, QLatin1String("dnd"), statusMessage); } Presence Presence::xa(const QString &statusMessage) { return Presence(ConnectionPresenceTypeExtendedAway, QLatin1String("xa"), statusMessage); } Presence Presence::hidden(const QString &statusMessage) { return Presence(ConnectionPresenceTypeHidden, QLatin1String("hidden"), statusMessage); } Presence Presence::offline(const QString &statusMessage) { return Presence(ConnectionPresenceTypeOffline, QLatin1String("offline"), statusMessage); } Presence &Presence::operator=(const Presence &other) { this->mPriv = other.mPriv; return *this; } bool Presence::operator==(const Presence &other) const { if (!isValid() || !other.isValid()) { if (!isValid() && !other.isValid()) { return true; } return false; } return mPriv->sp == other.mPriv->sp; } bool Presence::operator!=(const Presence &other) const { if (!isValid() || !other.isValid()) { if (!isValid() && !other.isValid()) { return false; } return true; } return mPriv->sp != other.mPriv->sp; } ConnectionPresenceType Presence::type() const { if (!isValid()) { return ConnectionPresenceTypeUnknown; } return (ConnectionPresenceType) mPriv->sp.type; } QString Presence::status() const { if (!isValid()) { return QString(); } return mPriv->sp.status; } QString Presence::statusMessage() const { if (!isValid()) { return QString(); } return mPriv->sp.statusMessage; } // Sets all fields void Presence::setStatus(const SimplePresence &value) { if (!isValid()) { mPriv = new Private(value); return; } mPriv->sp = value; } // TODO: explain in proper docs that we don't have setStatusType and setStatus(QString status) // separately, because: // 1) type and status are tightly related with each other // 2) all statuses can't have status message so changing the status alone might make the presence // illegal if a message was left around void Presence::setStatus(ConnectionPresenceType type, const QString &status, const QString &statusMessage) { if (!isValid()) { mPriv = new Private(type, status, statusMessage); return; } mPriv->sp.type = type; mPriv->sp.status = status; mPriv->sp.statusMessage = statusMessage; } void Presence::setStatusMessage(const QString &statusMessage) { if (!isValid()) { return; } mPriv->sp.statusMessage = statusMessage; } SimplePresence Presence::barePresence() const { if (!isValid()) { return SimplePresence(); } return mPriv->sp; } struct TP_QT_NO_EXPORT PresenceSpec::Private : public QSharedData { Private(const QString &status, const SimpleStatusSpec &spec) : status(status), spec(spec) { } QString status; SimpleStatusSpec spec; }; /** * \class PresenceSpec * \ingroup wrappers * \headerfile TelepathyQt/presence.h * * \brief The PresenceSpec class represents a Telepathy presence information * supported by a protocol. */ PresenceSpec::PresenceSpec() { } PresenceSpec::PresenceSpec(const QString &status, const SimpleStatusSpec &spec) : mPriv(new Private(status, spec)) { } PresenceSpec::PresenceSpec(const PresenceSpec &other) : mPriv(other.mPriv) { } PresenceSpec::~PresenceSpec() { } PresenceSpec PresenceSpec::available(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeAvailable; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("available"), spec); } PresenceSpec PresenceSpec::chat(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeAvailable; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("chat"), spec); } PresenceSpec PresenceSpec::pstn(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeAvailable; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("pstn"), spec); } PresenceSpec PresenceSpec::away(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeAway; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("away"), spec); } PresenceSpec PresenceSpec::brb(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeAway; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("brb"), spec); } PresenceSpec PresenceSpec::busy(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeBusy; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("busy"), spec); } PresenceSpec PresenceSpec::dnd(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeBusy; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("dnd"), spec); } PresenceSpec PresenceSpec::xa(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeExtendedAway; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("xa"), spec); } PresenceSpec PresenceSpec::hidden(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeHidden; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("hidden"), spec); } PresenceSpec PresenceSpec::offline(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeOffline; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("offline"), spec); } PresenceSpec PresenceSpec::unknown(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeUnknown; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("unknown"), spec); } PresenceSpec PresenceSpec::error(PresenceSpec::SimpleStatusFlags flags) { SimpleStatusSpec spec; spec.type = ConnectionPresenceTypeError; spec.maySetOnSelf = flags & MaySetOnSelf; spec.canHaveMessage = flags & CanHaveStatusMessage; return PresenceSpec(QLatin1String("error"), spec); } PresenceSpec &PresenceSpec::operator=(const PresenceSpec &other) { this->mPriv = other.mPriv; return *this; } bool PresenceSpec::operator==(const PresenceSpec &other) const { if (!isValid() || !other.isValid()) { if (!isValid() && !other.isValid()) { return true; } return false; } return (mPriv->status == other.mPriv->status) && (mPriv->spec == other.mPriv->spec); } bool PresenceSpec::operator!=(const PresenceSpec &other) const { if (!isValid() || !other.isValid()) { if (!isValid() && !other.isValid()) { return false; } return true; } return (mPriv->status != other.mPriv->status) && (mPriv->spec != other.mPriv->spec); } bool PresenceSpec::operator<(const PresenceSpec &other) const { if (!isValid()) { return false; } if (!other.isValid()) { return true; } return (mPriv->status < other.mPriv->status); } Presence PresenceSpec::presence(const QString &statusMessage) const { if (!isValid()) { return Presence(); } if (!canHaveStatusMessage() && !statusMessage.isEmpty()) { warning() << "Passing a status message to PresenceSpec with " "canHaveStatusMessage() being false"; } return Presence((ConnectionPresenceType) mPriv->spec.type, mPriv->status, statusMessage); } bool PresenceSpec::maySetOnSelf() const { if (!isValid()) { return false; } return mPriv->spec.maySetOnSelf; } bool PresenceSpec::canHaveStatusMessage() const { if (!isValid()) { return false; } return mPriv->spec.canHaveMessage; } SimpleStatusSpec PresenceSpec::bareSpec() const { if (!isValid()) { return SimpleStatusSpec(); } return mPriv->spec; } /** * \class PresenceSpecList * \ingroup wrappers * \headerfile TelepathyQt/presence.h * * \brief The PresenceSpecList class represents a list of PresenceSpec. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ServerAuthenticationChannel0000664000175000017500000000044112470405660022575 0ustar jrjr#ifndef _TelepathyQt_ServerAuthenticationChannel_HEADER_GUARD_ #define _TelepathyQt_ServerAuthenticationChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PresenceSpec0000664000175000017500000000035612470405660017522 0ustar jrjr#ifndef _TelepathyQt_PresenceSpec_HEADER_GUARD_ #define _TelepathyQt_PresenceSpec_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/dbus.h0000664000175000017500000000372312470405660016327 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_dbus_h_HEADER_GUARD_ #define _TelepathyQt_dbus_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif /** * \addtogroup clientsideproxies Client-side proxies * * Proxy objects representing remote service objects accessed via D-Bus. * * In addition to providing direct access to methods, signals and properties * exported by the remote objects, some of these proxies offer features like * automatic inspection of remote object capabilities, property tracking, * backwards compatibility helpers for older services and other utilities. */ /** * \defgroup clientdbus Generic D-Bus proxies * \ingroup clientsideproxies * * Proxy objects representing well-known generic D-Bus interfaces on remote * objects. Note that QDBus already has QDBusConnectionInterface for accessing * the bus daemon, so in the parts where there is an overlap in the * functionality, using the QDBus proxy should be given consideration instead * of blindly using the proxy provided here. */ #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/Captcha0000664000175000017500000000034312470405660016502 0ustar jrjr#ifndef _TelepathyQt_Captcha_HEADER_GUARD_ #define _TelepathyQt_Captcha_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/incoming-file-transfer-channel.cpp0000664000175000017500000003263112470405660023675 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/incoming-file-transfer-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT IncomingFileTransferChannel::Private { Private(IncomingFileTransferChannel *parent); ~Private(); // Public object IncomingFileTransferChannel *parent; Client::ChannelTypeFileTransferInterface *fileTransferInterface; QIODevice *output; QTcpSocket *socket; SocketAddressIPv4 addr; qulonglong requestedOffset; qint64 pos; }; IncomingFileTransferChannel::Private::Private(IncomingFileTransferChannel *parent) : parent(parent), fileTransferInterface(parent->interface()), output(0), socket(0), requestedOffset(0), pos(0) { parent->connect(fileTransferInterface, SIGNAL(URIDefined(QString)), SLOT(onUriDefined(QString))); parent->connect(fileTransferInterface, SIGNAL(URIDefined(QString)), SIGNAL(uriDefined(QString))); } IncomingFileTransferChannel::Private::~Private() { } /** * \class IncomingFileTransferChannel * \ingroup clientchannel * \headerfile TelepathyQt/incoming-file-transfer-channel.h * * \brief The IncomingFileTransferChannel class represents a Telepathy channel * of type FileTransfer for incoming file transfers. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * IncomingFileTransferChannel object usable. * * This is currently the same as FileTransferChannel::FeatureCore, but may change to include more. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature IncomingFileTransferChannel::FeatureCore = Feature(QLatin1String(FileTransferChannel::staticMetaObject.className()), 0); // FT::FeatureCore /** * Create a new IncomingFileTransferChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A IncomingFileTransferChannelPtr object pointing to the newly created * IncomingFileTransfer object. */ IncomingFileTransferChannelPtr IncomingFileTransferChannel::create( const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return IncomingFileTransferChannelPtr(new IncomingFileTransferChannel( connection, objectPath, immutableProperties, IncomingFileTransferChannel::FeatureCore)); } /** * Construct a new IncomingFileTransferChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on IncomingFileTransferChannel::FeatureCore. */ IncomingFileTransferChannel::IncomingFileTransferChannel( const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : FileTransferChannel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ IncomingFileTransferChannel::~IncomingFileTransferChannel() { delete mPriv; } /** * Set the URI where the file will be saved. * * This property may be set by the channel handler before calling AcceptFile to inform observers * where the incoming file will be saved. When the URI property is set, the signal * uriDefined() is emitted. * * This method requires IncomingFileTransferChannel::FeatureCore to be ready. * * \param uri The URI where the file will be saved. * \return A PendingOperation object which will emit PendingOperation::finished * when the call has finished. * \sa FileTransferChannel::uri(), uriDefined() */ PendingOperation *IncomingFileTransferChannel::setUri(const QString& uri) { if (!isReady(FileTransferChannel::FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling setUri"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingFileTransferChannelPtr(this)); } if (state() != FileTransferStatePending) { warning() << "setUri must be called before calling acceptFile"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Cannot set URI after calling acceptFile"), IncomingFileTransferChannelPtr(this)); } return mPriv->fileTransferInterface->setPropertyURI(uri); } /** * Accept a file transfer that's in the #FileTransferStatePending state(). * * The state will change to #FileTransferStateOpen as soon as the transfer * starts. * The given output device should not be closed/destroyed until the state() * changes to #FileTransferStateCompleted or #FileTransferStateCancelled. * * Only the primary handler of a file transfer channel may call this method. * * This method requires IncomingFileTransferChannel::FeatureCore to be ready. * * \param offset The desired offset in bytes where the file transfer should * start. The offset is taken from the beginning of the file. * Specifying an offset of zero will start the transfer from the * beginning of the file. The offset that is actually given in the * initialOffset() method can differ from this argument where the * requested offset is not supported. (For example, some * protocols do not support offsets at all so the initialOffset() * will always be 0.). * \param output A QIODevice object where the data will be written to. The * device should be ready to use when the state() changes to * #FileTransferStateCompleted. * If the transfer is cancelled, state() becomes * #FileTransferStateCancelled, the data in \a output should be * ignored * \return A PendingOperation object which will emit PendingOperation::finished * when the call has finished. * \sa FileTransferChannel::stateChanged(), FileTransferChannel::state(), * FileTransferChannel::stateReason(), FileTransferChannel::initialOffset() */ PendingOperation *IncomingFileTransferChannel::acceptFile(qulonglong offset, QIODevice *output) { if (!isReady(FileTransferChannel::FeatureCore)) { warning() << "FileTransferChannel::FeatureCore must be ready before " "calling acceptFile"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), IncomingFileTransferChannelPtr(this)); } // let's fail here direclty as we may only have one device to handle if (mPriv->output) { warning() << "File transfer can only be started once in the same " "channel"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("File transfer can only be started once in the same channel"), IncomingFileTransferChannelPtr(this)); } if ((!output->isOpen() && !output->open(QIODevice::WriteOnly)) && (!output->isWritable())) { warning() << "Unable to open IO device for writing"; return new PendingFailure(TP_QT_ERROR_PERMISSION_DENIED, QLatin1String("Unable to open IO device for writing"), IncomingFileTransferChannelPtr(this)); } mPriv->output = output; mPriv->requestedOffset = offset; PendingVariant *pv = new PendingVariant( mPriv->fileTransferInterface->AcceptFile(SocketAddressTypeIPv4, SocketAccessControlLocalhost, QDBusVariant(QVariant(QString())), offset), IncomingFileTransferChannelPtr(this)); connect(pv, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAcceptFileFinished(Tp::PendingOperation*))); return pv; } void IncomingFileTransferChannel::onAcceptFileFinished(PendingOperation *op) { if (op->isError()) { warning() << "Error accepting file transfer " << op->errorName() << ":" << op->errorMessage(); invalidate(op->errorName(), op->errorMessage()); return; } PendingVariant *pv = qobject_cast(op); mPriv->addr = qdbus_cast(pv->result()); debug().nospace() << "Got address " << mPriv->addr.address << ":" << mPriv->addr.port; if (state() == FileTransferStateOpen) { // now we have the address and we are already opened, // connect to host connectToHost(); } } void IncomingFileTransferChannel::connectToHost() { if (isConnected() || mPriv->addr.address.isNull()) { return; } // we already have initialOffsetDefined, called before State became Open, so // let's make sure everything is ok. if (initialOffset() > mPriv->requestedOffset) { // either the CM or the sender is doing something really wrong here, // cancel the transfer. warning() << "InitialOffset bigger than requested offset, " "cancelling the transfer"; cancel(); invalidate(TP_QT_ERROR_INCONSISTENT, QLatin1String("Initial offset bigger than requested offset")); return; } mPriv->pos = initialOffset(); mPriv->socket = new QTcpSocket(this); connect(mPriv->socket, SIGNAL(connected()), SLOT(onSocketConnected())); connect(mPriv->socket, SIGNAL(disconnected()), SLOT(onSocketDisconnected())); connect(mPriv->socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(onSocketError(QAbstractSocket::SocketError))); connect(mPriv->socket, SIGNAL(readyRead()), SLOT(doTransfer())); debug().nospace() << "Connecting to host " << mPriv->addr.address << ":" << mPriv->addr.port << "..."; mPriv->socket->connectToHost(mPriv->addr.address, mPriv->addr.port); } void IncomingFileTransferChannel::onSocketConnected() { debug() << "Connected to host"; setConnected(); doTransfer(); } void IncomingFileTransferChannel::onSocketDisconnected() { debug() << "Disconnected from host"; setFinished(); } void IncomingFileTransferChannel::onSocketError(QAbstractSocket::SocketError error) { setFinished(); } void IncomingFileTransferChannel::doTransfer() { QByteArray data; while (mPriv->socket->bytesAvailable()) { data = mPriv->socket->readAll(); // skip until we reach requetedOffset and start writing from there if ((qulonglong) mPriv->pos < mPriv->requestedOffset) { if ((qulonglong) data.length() <= (mPriv->requestedOffset - mPriv->pos)) { break; } data = data.mid(mPriv->requestedOffset - mPriv->pos); } mPriv->output->write(data); // never fails } mPriv->pos += data.length(); } void IncomingFileTransferChannel::setFinished() { if (isFinished()) { // it shouldn't happen but let's make sure return; } if (mPriv->socket) { disconnect(mPriv->socket, SIGNAL(connected()), this, SLOT(onSocketConnected())); disconnect(mPriv->socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); disconnect(mPriv->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError))); disconnect(mPriv->socket, SIGNAL(readyRead()), this, SLOT(doTransfer())); mPriv->socket->close(); } if (mPriv->output) { mPriv->output->close(); } FileTransferChannel::setFinished(); } /** * \fn void IncomingFileTransferChannel::uriDefined(const QString &uri) * * Emitted when the value of uri() changes. * * \param uri The new URI of this file transfer channel. * \sa FileTransferChannel::uri(), setUri() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceContactsInterface0000664000175000017500000000044012470405660024375 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceContactsInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceContactsInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelClassSpec0000664000175000017500000000040012470405660020302 0ustar jrjr#ifndef _TelepathyQt_ChannelClassSpec_HEADER_GUARD_ #define _TelepathyQt_ChannelClassSpec_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/contact-search-channel.cpp0000664000175000017500000005561112470405660022234 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/contact-search-channel-internal.h" #include "TelepathyQt/_gen/contact-search-channel.moc.hpp" #include "TelepathyQt/_gen/contact-search-channel-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ContactSearchChannel::Private { Private(ContactSearchChannel *parent, const QVariantMap &immutableProperties); ~Private(); static void introspectMain(Private *self); void extractImmutableProperties(const QVariantMap &props); void processSignalsQueue(); void processSearchStateChangeQueue(); void processSearchResultQueue(); struct SearchStateChangeInfo { SearchStateChangeInfo(uint state, const QString &errorName, const Tp::ContactSearchChannel::SearchStateChangeDetails &details) : state(state), errorName(errorName), details(details) { } uint state; QString errorName; ContactSearchChannel::SearchStateChangeDetails details; }; // Public object ContactSearchChannel *parent; QVariantMap immutableProperties; Client::ChannelTypeContactSearchInterface *contactSearchInterface; Client::DBus::PropertiesInterface *properties; ReadinessHelper *readinessHelper; // Introspection uint searchState; uint limit; QStringList availableSearchKeys; QString server; QQueue signalsQueue; QQueue searchStateChangeQueue; QQueue searchResultQueue; bool processingSignalsQueue; }; ContactSearchChannel::Private::Private(ContactSearchChannel *parent, const QVariantMap &immutableProperties) : parent(parent), immutableProperties(immutableProperties), contactSearchInterface(parent->interface()), properties(parent->interface()), readinessHelper(parent->readinessHelper()), searchState(ChannelContactSearchStateNotStarted), limit(0), processingSignalsQueue(false) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMain, this); introspectables[FeatureCore] = introspectableCore; readinessHelper->addIntrospectables(introspectables); } ContactSearchChannel::Private::~Private() { } void ContactSearchChannel::Private::introspectMain(ContactSearchChannel::Private *self) { /* we need to at least introspect SearchState here as it's not immutable */ self->parent->connect(self->contactSearchInterface, SIGNAL(SearchStateChanged(uint,QString,QVariantMap)), SLOT(onSearchStateChanged(uint,QString,QVariantMap))); self->parent->connect(self->contactSearchInterface, SIGNAL(SearchResultReceived(Tp::ContactSearchResultMap)), SLOT(onSearchResultReceived(Tp::ContactSearchResultMap))); QVariantMap props; bool needIntrospectMainProps = false; const unsigned numNames = 3; const static QString names[numNames] = { QLatin1String("Limit"), QLatin1String("AvailableSearchKeys"), QLatin1String("Server") }; const static QString qualifiedNames[numNames] = { TP_QT_IFACE_CHANNEL + QLatin1String(".Limit"), TP_QT_IFACE_CHANNEL + QLatin1String(".AvailableSearchKeys"), TP_QT_IFACE_CHANNEL + QLatin1String(".Server") }; for (unsigned i = 0; i < numNames; ++i) { const QString &qualified = qualifiedNames[i]; if (!self->immutableProperties.contains(qualified)) { needIntrospectMainProps = true; break; } props.insert(names[i], self->immutableProperties.value(qualified)); } if (needIntrospectMainProps) { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->GetAll( TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH), self->parent); self->parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotProperties(QDBusPendingCallWatcher*))); } else { self->extractImmutableProperties(props); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->Get( TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, QLatin1String("SearchState")), self->parent); self->parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotSearchState(QDBusPendingCallWatcher*))); } } void ContactSearchChannel::Private::extractImmutableProperties(const QVariantMap &props) { limit = qdbus_cast(props[QLatin1String("Limit")]); availableSearchKeys = qdbus_cast(props[QLatin1String("AvailableSearchKeys")]); server = qdbus_cast(props[QLatin1String("Server")]); } void ContactSearchChannel::Private::processSignalsQueue() { if (processingSignalsQueue || signalsQueue.isEmpty()) { return; } processingSignalsQueue = true; (this->*(signalsQueue.dequeue()))(); } void ContactSearchChannel::Private::processSearchStateChangeQueue() { const SearchStateChangeInfo &info = searchStateChangeQueue.dequeue(); searchState = info.state; emit parent->searchStateChanged( static_cast(info.state), info.errorName, SearchStateChangeDetails(info.details)); processingSignalsQueue = false; processSignalsQueue(); } void ContactSearchChannel::Private::processSearchResultQueue() { const ContactSearchResultMap &result = searchResultQueue.first(); if (!result.isEmpty()) { ContactManagerPtr manager = parent->connection()->contactManager(); PendingContacts *pendingContacts = manager->contactsForIdentifiers( result.keys()); parent->connect(pendingContacts, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotSearchResultContacts(Tp::PendingOperation*))); } else { searchResultQueue.dequeue(); emit parent->searchResultReceived(SearchResult()); processingSignalsQueue = false; processSignalsQueue(); } } struct TP_QT_NO_EXPORT ContactSearchChannel::SearchStateChangeDetails::Private : public QSharedData { Private(const QVariantMap &details) : details(details) {} QVariantMap details; }; ContactSearchChannel::SearchStateChangeDetails::SearchStateChangeDetails(const QVariantMap &details) : mPriv(new Private(details)) { } ContactSearchChannel::SearchStateChangeDetails::SearchStateChangeDetails() { } ContactSearchChannel::SearchStateChangeDetails::SearchStateChangeDetails( const ContactSearchChannel::SearchStateChangeDetails &other) : mPriv(other.mPriv) { } ContactSearchChannel::SearchStateChangeDetails::~SearchStateChangeDetails() { } ContactSearchChannel::SearchStateChangeDetails &ContactSearchChannel::SearchStateChangeDetails::operator=( const ContactSearchChannel::SearchStateChangeDetails &other) { this->mPriv = other.mPriv; return *this; } QVariantMap ContactSearchChannel::SearchStateChangeDetails::allDetails() const { return isValid() ? mPriv->details : QVariantMap(); } ContactSearchChannel::PendingSearch::PendingSearch(const ContactSearchChannelPtr &channel, QDBusPendingCall call) : PendingOperation(channel), mFinished(false) { connect(channel.data(), SIGNAL(searchStateChanged(Tp::ChannelContactSearchState, const QString &, const Tp::ContactSearchChannel::SearchStateChangeDetails &)), SLOT(onSearchStateChanged(Tp::ChannelContactSearchState, const QString &, const Tp::ContactSearchChannel::SearchStateChangeDetails &))); connect(new QDBusPendingCallWatcher(call), SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(watcherFinished(QDBusPendingCallWatcher*))); } void ContactSearchChannel::PendingSearch::onSearchStateChanged( Tp::ChannelContactSearchState state, const QString &errorName, const Tp::ContactSearchChannel::SearchStateChangeDetails &details) { if (state != ChannelContactSearchStateNotStarted) { if (mFinished) { if (mError.isValid()) { setFinishedWithError(mError); } else { setFinished(); } } mFinished = true; } } void ContactSearchChannel::PendingSearch::watcherFinished(QDBusPendingCallWatcher *watcher) { if (watcher->isError()) { if (mFinished) { setFinishedWithError(watcher->error()); } else { mError = watcher->error(); } } else { if (mFinished) { setFinished(); } } mFinished = true; watcher->deleteLater(); } /** * \class ContactSearchChannel * \ingroup clientchannel * \headerfile TelepathyQt/contact-search-channel.h * * \brief The ContactSearchChannel class represents a Telepathy channel of type * ContactSearch. */ /** * \class ContactSearchChannel::SearchStateChangeDetails * \ingroup wrappers * \headerfile TelepathyQt/contact-search-channel.h * * \brief The ContactSearchChannel::SearchStateChangeDetails class provides * a wrapper around the details for a search state change. * * \sa ContactSearchChannel */ /** * Feature representing the core that needs to become ready to make the * ContactSearchChannel object usable. * * Note that this feature must be enabled in order to use most * ContactSearchChannel methods. * See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature ContactSearchChannel::FeatureCore = Feature(QLatin1String(ContactSearchChannel::staticMetaObject.className()), 0); /** * Create a new ContactSearchChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A ContactSearchChannelPtr object pointing to the newly created * ContactSearchChannel object. */ ContactSearchChannelPtr ContactSearchChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return ContactSearchChannelPtr(new ContactSearchChannel(connection, objectPath, immutableProperties, ContactSearchChannel::FeatureCore)); } /** * Construct a new ContactSearchChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on ContactSearchChannel::FeatureCore. */ ContactSearchChannel::ContactSearchChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : Channel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this, immutableProperties)) { } /** * Class destructor. */ ContactSearchChannel::~ContactSearchChannel() { delete mPriv; } /** * Return the current search state of this channel. * * Change notification is via the searchStateChanged() signal. * * This method requires ContactSearchChannel::FeatureCore to be ready. * * \return The current search state as #ChannelContactSearchState. * \sa searchStateChanged() */ ChannelContactSearchState ContactSearchChannel::searchState() const { return static_cast(mPriv->searchState); } /** * Return the maximum number of results that should be returned by calling search(), where * 0 represents no limit. * * For example, if the terms passed to search() match Antonius, Bridget and Charles and * this property is 2, the search service will only return Antonius and Bridget. * * This method requires ContactSearchChannel::FeatureCore to be ready. * * \return The maximum number of results, or 0 if there is no limit. * \sa availableSearchKeys(), search() */ uint ContactSearchChannel::limit() const { return mPriv->limit; } /** * Return the set of search keys supported by this channel. * * Example values include [""] (for protocols where several address fields are implicitly searched) * or ["x-n-given", "x-n-family", "nickname", "email"] (for XMPP XEP-0055, without extensibility via * Data Forms). * * This method requires ContactSearchChannel::FeatureCore to be ready. * * \return The supported search keys. * \sa limit(), search() */ QStringList ContactSearchChannel::availableSearchKeys() const { return mPriv->availableSearchKeys; } /** * Return the DNS name of the server being searched by this channel. * * This method requires ContactSearchChannel::FeatureCore to be ready. * * \return For protocols which support searching for contacts on multiple servers with different DNS * names (like XMPP), the DNS name of the server being searched by this channel, e.g. * "characters.shakespeare.lit". Otherwise, an empty string. */ QString ContactSearchChannel::server() const { return mPriv->server; } /** * Send a request to start a search for contacts on this connection. * * This may only be called while the searchState() is #ChannelContactSearchStateNotStarted; * a valid search request will cause the searchStateChanged() signal to be emitted with the * state #ChannelContactSearchStateInProgress. * * Search results are signalled by searchResultReceived(). * * This method requires ContactSearchChannel::FeatureCore to be ready. * * This is an overloaded method for search(const ContactSearchMap &searchTerms). * * \param searchKey The search key. * \param searchTerm The search term. * \return A PendingOperation which will emit PendingOperation::finished * when the search has started. * \sa searchState(), searchStateChanged(), searchResultReceived() */ PendingOperation *ContactSearchChannel::search(const QString &searchKey, const QString &searchTerm) { ContactSearchMap searchTerms; searchTerms.insert(searchKey, searchTerm); return search(searchTerms); } /** * Send a request to start a search for contacts on this connection. * * This may only be called while the searchState() is #ChannelContactSearchStateNotStarted; * a valid search request will cause the searchStateChanged() signal to be emitted with the * state #ChannelContactSearchStateInProgress. * * Search results are signalled by searchResultReceived(). * * This method requires ContactSearchChannel::FeatureCore to be ready. * * \param terms The search terms. * \return A PendingOperation which will emit PendingOperation::finished * when the search has started. * \sa searchState(), searchStateChanged(), searchResultReceived() */ PendingOperation *ContactSearchChannel::search(const ContactSearchMap &terms) { if (!isReady(FeatureCore)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), ContactSearchChannelPtr(this)); } if (searchState() != ChannelContactSearchStateNotStarted) { warning() << "ContactSearchChannel::search called with " "searchState() != ChannelContactSearchStateNotStarted. Doing nothing"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Search already started"), ContactSearchChannelPtr(this)); } return new PendingSearch(ContactSearchChannelPtr(this), mPriv->contactSearchInterface->Search(terms)); } /** * Request that a search which searchState() is ChannelContactSearchStateMoreAvailable * move back to state ChannelContactSearchStateInProgress and continue listing up to limit() * more results. */ void ContactSearchChannel::continueSearch() { if (!isReady(FeatureCore)) { return; } if (searchState() != ChannelContactSearchStateMoreAvailable) { warning() << "ContactSearchChannel::continueSearch called with " "searchState() != ChannelContactSearchStateMoreAvailable. Doing nothing"; return; } (void) new PendingVoid(mPriv->contactSearchInterface->More(), ContactSearchChannelPtr(this)); } /** * Stop the current search. * * This may not be called while the searchState() is #ChannelContactSearchStateNotStarted. * If called while the searchState() is #ChannelContactSearchStateInProgress, * searchStateChanged() will be emitted, with the state #ChannelContactSearchStateFailed and * the error #TP_QT_ERROR_CANCELLED. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa searchState(), searchStateChanged() */ void ContactSearchChannel::stopSearch() { if (!isReady(FeatureCore)) { return; } if (searchState() != ChannelContactSearchStateInProgress && searchState() != ChannelContactSearchStateMoreAvailable) { warning() << "ContactSearchChannel::stopSearch called with " "searchState() != ChannelContactSearchStateInProgress or " "ChannelContactSearchStateMoreAvailable. Doing nothing"; return; } (void) new PendingVoid(mPriv->contactSearchInterface->Stop(), ContactSearchChannelPtr(this)); } void ContactSearchChannel::gotProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { QVariantMap props = reply.value(); mPriv->extractImmutableProperties(props); mPriv->searchState = qdbus_cast(props[QLatin1String("SearchState")]); debug() << "Got reply to Properties::GetAll(ContactSearchChannel)"; mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } else { warning().nospace() << "Properties::GetAll(ContactSearchChannel) failed " "with " << reply.error().name() << ": " << reply.error().message(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); } watcher->deleteLater(); } void ContactSearchChannel::gotSearchState(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { mPriv->searchState = qdbus_cast(reply.value()); debug() << "Got reply to Properties::Get(SearchState)"; mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } else { warning().nospace() << "Properties::Get(SearchState) failed " "with " << reply.error().name() << ": " << reply.error().message(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); } watcher->deleteLater(); } void ContactSearchChannel::onSearchStateChanged(uint state, const QString &error, const QVariantMap &details) { mPriv->searchStateChangeQueue.enqueue(Private::SearchStateChangeInfo(state, error, details)); mPriv->signalsQueue.enqueue(&Private::processSearchStateChangeQueue); mPriv->processSignalsQueue(); } void ContactSearchChannel::onSearchResultReceived(const ContactSearchResultMap &result) { mPriv->searchResultQueue.enqueue(result); mPriv->signalsQueue.enqueue(&Private::processSearchResultQueue); mPriv->processSignalsQueue(); } void ContactSearchChannel::gotSearchResultContacts(PendingOperation *op) { PendingContacts *pc = qobject_cast(op); const ContactSearchResultMap &result = mPriv->searchResultQueue.dequeue(); if (!pc->isValid()) { warning().nospace() << "Getting search result contacts " "failed with " << pc->errorName() << ":" << pc->errorMessage() << ". Ignoring search result"; mPriv->processingSignalsQueue = false; mPriv->processSignalsQueue(); return; } const QList &contacts = pc->contacts(); Q_ASSERT(result.count() == contacts.count()); SearchResult ret; uint i = 0; for (ContactSearchResultMap::const_iterator it = result.constBegin(); it != result.constEnd(); ++it, ++i) { ret.insert(contacts.at(i), Contact::InfoFields(it.value())); } emit searchResultReceived(ret); mPriv->processingSignalsQueue = false; mPriv->processSignalsQueue(); } /** * \fn void ContactSearchChannel::searchStateChanged(Tp::ChannelContactSearchState state, * const QString &errorName, * const Tp::ContactSearchChannel::SearchStateChangeDetails &details) * * Emitted when the value of searchState() changes. * * \param state The new state. * \param errorName The name of the error if any. * \param details The details for the state change. * \sa searchState() */ /** * \fn void ContactSearchChannel::searchResultReceived( * const Tp::ContactSearchChannel::SearchResult &result) * * Emitted when a result for a search is received. It can be emitted multiple times * until the searchState() goes to #ChannelContactSearchStateCompleted or * #ChannelContactSearchStateFailed. * * \param result The search result. * \sa searchState() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/PendingVariantMap0000664000175000017500000000040312470405660020503 0ustar jrjr#ifndef _TelepathyQt_PendingVariantMap_HEADER_GUARD_ #define _TelepathyQt_PendingVariantMap_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/contact-factory.h0000664000175000017500000000411012470405660020461 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_contact_factory_h_HEADER_GUARD_ #define _TelepathyQt_contact_factory_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include namespace Tp { class ContactManager; class ReferencedHandles; class TP_QT_EXPORT ContactFactory : public RefCounted { Q_DISABLE_COPY(ContactFactory) public: static ContactFactoryPtr create(const Features &features = Features()); virtual ~ContactFactory(); Features features() const; void addFeature(const Feature &feature); void addFeatures(const Features &features); protected: ContactFactory(const Features &features); virtual ContactPtr construct(ContactManager *manager, const ReferencedHandles &handle, const Features &features, const QVariantMap &attributes) const; virtual PendingOperation *prepare(const ContactPtr &contact) const; private: friend class ContactManager; friend class PendingContacts; struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/dbus-proxy-factory.h0000664000175000017500000000472512470405660021156 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_dbus_proxy_factory_h_HEADER_GUARD_ #define _TelepathyQt_dbus_proxy_factory_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include // For Q_DISABLE_COPY #include #include class QDBusConnection; namespace Tp { class Features; class PendingReady; class PendingOperation; class TP_QT_EXPORT DBusProxyFactory : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(DBusProxyFactory) public: virtual ~DBusProxyFactory(); const QDBusConnection &dbusConnection() const; protected: DBusProxyFactory(const QDBusConnection &bus); DBusProxyPtr cachedProxy(const QString &busName, const QString &objectPath) const; PendingReady *nowHaveProxy(const DBusProxyPtr &proxy) const; // I don't want this to be non-pure virtual, because I want ALL subclasses to have to think // about whether or not they need to uniquefy the name or not. If a subclass doesn't implement // this while it should, matching with the cache for future requests and invalidation breaks. virtual QString finalBusNameFrom(const QString &uniqueOrWellKnown) const = 0; virtual PendingOperation *initialPrepare(const DBusProxyPtr &proxy) const; virtual PendingOperation *readyPrepare(const DBusProxyPtr &proxy) const; virtual Features featuresFor(const DBusProxyPtr &proxy) const = 0; private: class Cache; struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ClientObserverInterface0000664000175000017500000000040212470405660021702 0ustar jrjr#ifndef _TelepathyQt_ClientObserverInterface_HEADER_GUARD_ #define _TelepathyQt_ClientObserverInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceContactBlockingInterface0000664000175000017500000000045612470405660025672 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceContactBlockingInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceContactBlockingInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AccountInterfaceStorageInterface0000664000175000017500000000042512470405660023523 0ustar jrjr#ifndef _TelepathyQt_AccountInterfaceStorageInterface_HEADER_GUARD_ #define _TelepathyQt_AccountInterfaceStorageInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AccountManagerInterface0000664000175000017500000000041312470405660021645 0ustar jrjr#ifndef _TelepathyQt_AccountManagerInterface_HEADER_GUARD_ #define _TelepathyQt_AccountManagerInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/connection-factory.h0000664000175000017500000000450712470405660021177 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_connection_factory_h_HEADER_GUARD_ #define _TelepathyQt_connection_factory_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include // For Q_DISABLE_COPY #include #include class QDBusConnection; namespace Tp { class PendingReady; class TP_QT_EXPORT ConnectionFactory : public FixedFeatureFactory { public: static ConnectionFactoryPtr create(const QDBusConnection &bus, const Features &features = Features()); virtual ~ConnectionFactory(); PendingReady *proxy(const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const; protected: ConnectionFactory(const QDBusConnection &bus, const Features &features); virtual ConnectionPtr construct(const QString &busName, const QString &objectPath, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const; virtual QString finalBusNameFrom(const QString &uniqueOrWellKnown) const; // Nothing we'd like to prepare() // Fixed features private: struct Private; Private *mPriv; // Currently unused, just for future-proofing }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/shared-ptr.dox0000664000175000017500000001252212470405660020003 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2011 Collabora Ltd. * @copyright Copyright (C) 2008-2011 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \page shared_ptr Shared Pointer Usage * * \section shared_ptr_overview Overview * * The Qt parent/child object model does not fit well with Telepathy-Qt object * model, where in some places we either don't know the object parent or we * can't use a parent, as the object can stay alive without it. * * To avoid memory leaks, caused by objects that got instantiated and don't have * any parent, we decided to make some of our objects reference counted, by * making them inherit RefCounted. * * Making the object reference counted, does not guarantee that it will get * deleted when nobody is referencing it. * * When instantiating new classes that inherits RefCounted the reference count * is 0, this is referred to as the floating state. Again this may lead to * memory leaks, caused by objects in the floating state that never get deleted. * * So the solution is to put the object in a SharedPtr as soon as possible, * letting the SharedPtr manage the object lifetime. * * The pattern used is that classes inherit RefCounted and are used * together with SharedPtr. When the reference count hits 0, the object * is deleted. * * In order to assure that the object is put in a SharedPtr as soon as possible, * our objects inheriting RefCounted will have the constructor either private * or protected, in case we want to support custom classes, and will have a * public static create method that will return a SharedPtr pointing to the * object instance. * * Note that when developing custom classes, this pattern should be followed, * to avoid objects in floating state, avoiding memory leaks. */ /** * \class Tp::RefCounted * \ingroup utils * \headerfile TelepathyQt/shared-ptr.h * * \brief The RefCounted class is a base class for shared objects used by * SharedPtr. * * See \ref shared_ptr */ /** * \class Tp::SharedPtr * \ingroup utils * \headerfile TelepathyQt/shared-ptr.h * * \brief The SharedPtr class is a pointer to an explicitly shared object. * * Note that from Telepathy-Qt >= 0.9.0, Tp::SharedPtr cannot be constructed from a QWeakPointer as * the conversion from a QWeakPointer to a Tp::SharedPtr can't be made thread-safe. * Tp::WeakPtr is reintroduced as a weak pointer class safely promoteable to a Tp::SharedPtr. * * See \ref shared_ptr */ /** * \fn static SharedPtr Tp::SharedPtr::dynamicCast(const SharedPtr &) * * Casts the pointer given by src to a pointer pointing to an object of type T. The cast will * succeed if the C++ runtime type identification mechanism considers the type T to be the actual * runtime type of the object pointed to by src or one of its (possibly indirect) parent classes. * Otherwise, a null pointer is returned. * * Note that this also allows down-casting a baseclass pointer to a subclass pointer. * * This cast method should not be used for QObject-derived classes, as Qt provides a more portable * and efficient type identification mechanism, which is used by qObjectCast(). * * This cast method requires the C++ dynamic runtime type identification facility to be enabled * (which might be disabled by eg. the -fno-rtti flag of the GNU G++ compiler). */ /** * \fn static SharedPtr Tp::SharedPtr::qObjectCast(const SharedPtr &) * * Casts the pointer given by src to a pointer pointing to an object of type T. The cast will * succeed if the Qt runtime type identification mechanism considers the type T to be the actual * runtime type of the object pointed to by src or one of its (possibly indirect) parent classes. * Otherwise, a null pointer is returned. * * Note that this also allows down-casting a baseclass pointer to a subclass pointer. * * This cast method MUST not be used for classes not derived from QObject. However, dynamicCast() * provides the same semantics for all classes, provided the C++ runtime type identification * facility is enabled. This method, on the other hand, doesn't require the standard C++ facility * and is probably also faster for the types it can be used with. */ /** * \class Tp::WeakPtr * \ingroup utils * \headerfile TelepathyQt/shared-ptr.h * * \brief The WeakPtr class holds a weak reference to an object managed by SharedPtr. * * Tp::WeakPtr is useful for example for breaking reference cycles which would result from * using a Tp::SharedPtr for both ends of a pair of mutually linked objects to refer to each other. * * See \ref shared_ptr */ telepathy-qt-0.9.6~git1/TelepathyQt/TelepathyQtService-uninstalled.pc.in0000664000175000017500000000121212470405660024246 0ustar jrjrprefix=/nonexistent exec_prefix=/nonexistent abs_top_builddir=${CMAKE_BINARY_DIR} abs_top_srcdir=${CMAKE_SOURCE_DIR} Name: TelepathyQt${QT_VERSION_MAJOR}Service (uninstalled copy) Description: Qt Telepathy Service side bindings Version: ${PACKAGE_VERSION} Requires.private: Qt${QT_VERSION_PC}Core >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Core < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}DBus >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}DBus < ${QT_MAX_VERSION}, TelepathyQt${QT_VERSION_MAJOR} = ${PACKAGE_VERSION} Libs: ${CMAKE_BINARY_DIR}/TelepathyQt/Farsight/libtelepathy-qt${QT_VERSION_MAJOR}-service.so Cflags: -I${CMAKE_SOURCE_DIR} -I${CMAKE_BINARY_DIR} telepathy-qt-0.9.6~git1/TelepathyQt/dbus-proxy.h0000664000175000017500000000654012470405660017506 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_dbus_proxy_h_HEADER_GUARD_ #define _TelepathyQt_dbus_proxy_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include class QDBusConnection; class QDBusError; namespace Tp { class TestBackdoors; class TP_QT_EXPORT DBusProxy : public Object, public ReadyObject { Q_OBJECT Q_DISABLE_COPY(DBusProxy) public: DBusProxy(const QDBusConnection &dbusConnection, const QString &busName, const QString &objectPath, const Feature &featureCore); virtual ~DBusProxy(); QDBusConnection dbusConnection() const; QString busName() const; QString objectPath() const; bool isValid() const; QString invalidationReason() const; QString invalidationMessage() const; Q_SIGNALS: void invalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage); protected: void setBusName(const QString &busName); void invalidate(const QString &reason, const QString &message); void invalidate(const QDBusError &error); private Q_SLOTS: TP_QT_NO_EXPORT void emitInvalidated(); private: friend class TestBackdoors; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT StatelessDBusProxy : public DBusProxy { Q_OBJECT Q_DISABLE_COPY(StatelessDBusProxy) public: StatelessDBusProxy(const QDBusConnection &dbusConnection, const QString &busName, const QString &objectPath, const Feature &featureCore); virtual ~StatelessDBusProxy(); private: struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT StatefulDBusProxy : public DBusProxy { Q_OBJECT Q_DISABLE_COPY(StatefulDBusProxy) public: StatefulDBusProxy(const QDBusConnection &dbusConnection, const QString &busName, const QString &objectPath, const Feature &featureCore); virtual ~StatefulDBusProxy(); static QString uniqueNameFrom(const QDBusConnection &bus, const QString &wellKnownOrUnique); static QString uniqueNameFrom(const QDBusConnection &bus, const QString &wellKnownOrUnique, QString &error, QString &message); private Q_SLOTS: TP_QT_NO_EXPORT void onServiceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ClientApproverInterface0000664000175000017500000000040212470405660021711 0ustar jrjr#ifndef _TelepathyQt_ClientApproverInterface_HEADER_GUARD_ #define _TelepathyQt_ClientApproverInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/TelepathyQtService.pc.in0000664000175000017500000000132612470405660021734 0ustar jrjrprefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${CMAKE_INSTALL_PREFIX} libdir=${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR} includedir=${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR} Name: TelepathyQt${QT_VERSION_MAJOR}Service Description: Qt Telepathy Service side bindings Version: ${PACKAGE_VERSION} Requires.private: Qt${QT_VERSION_PC}Core >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Core < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}DBus >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}DBus < ${QT_MAX_VERSION}, TelepathyQt${QT_VERSION_MAJOR} = ${PACKAGE_VERSION} Libs: -L${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR} -ltelepathy-qt${QT_VERSION_MAJOR}-service Cflags: -I${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR}/telepathy-qt${QT_VERSION_MAJOR} telepathy-qt-0.9.6~git1/TelepathyQt/Features0000664000175000017500000000034512470405660016717 0ustar jrjr#ifndef _TelepathyQt_Features_HEADER_GUARD_ #define _TelepathyQt_Features_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/base-connection-internal.h0000664000175000017500000003243512470405660022255 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/_gen/svc-connection.h" #include #include #include #include "TelepathyQt/debug-internal.h" namespace Tp { class TP_QT_NO_EXPORT BaseConnection::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QStringList interfaces READ interfaces) Q_PROPERTY(uint selfHandle READ selfHandle) Q_PROPERTY(uint status READ status) Q_PROPERTY(bool hasImmortalHandles READ hasImmortalHandles) public: Adaptee(const QDBusConnection &dbusConnection, BaseConnection *cm); ~Adaptee(); QStringList interfaces() const; uint status() const { return mConnection->status(); } uint selfHandle() const; bool hasImmortalHandles() const { return true; } private Q_SLOTS: void getSelfHandle(const Tp::Service::ConnectionAdaptor::GetSelfHandleContextPtr &context); void getStatus(const Tp::Service::ConnectionAdaptor::GetStatusContextPtr &context); void connect(const Tp::Service::ConnectionAdaptor::ConnectContextPtr &context); void getInterfaces(const Tp::Service::ConnectionAdaptor::GetInterfacesContextPtr &context) { context->setFinished(interfaces()); } void getProtocol(const Tp::Service::ConnectionAdaptor::GetProtocolContextPtr &context) { context->setFinished(mConnection->protocolName()); } void holdHandles(uint handleType, const Tp::UIntList &handles, const Tp::Service::ConnectionAdaptor::HoldHandlesContextPtr &context) { context->setFinished(); } void inspectHandles(uint handleType, const Tp::UIntList &handles, const Tp::Service::ConnectionAdaptor::InspectHandlesContextPtr &context); void listChannels(const Tp::Service::ConnectionAdaptor::ListChannelsContextPtr &context) { context->setFinished(mConnection->channelsInfo()); } void disconnect(const Tp::Service::ConnectionAdaptor::DisconnectContextPtr &context); //void releaseHandles(uint handleType, const Tp::UIntList &handles, const Tp::Service::ConnectionAdaptor::ReleaseHandlesContextPtr &context); void requestChannel(const QString &type, uint handleType, uint handle, bool suppressHandler, const Tp::Service::ConnectionAdaptor::RequestChannelContextPtr &context); void requestHandles(uint handleType, const QStringList &identifiers, const Tp::Service::ConnectionAdaptor::RequestHandlesContextPtr &context); //void addClientInterest(const QStringList &tokens, const Tp::Service::ConnectionAdaptor::AddClientInterestContextPtr &context); //void removeClientInterest(const QStringList &tokens, const Tp::Service::ConnectionAdaptor::RemoveClientInterestContextPtr &context); public: BaseConnection *mConnection; Service::ConnectionAdaptor *mAdaptor; Q_SIGNALS: void selfHandleChanged(uint selfHandle); void newChannel(const QDBusObjectPath &objectPath, const QString &channelType, uint handleType, uint handle, bool suppressHandler); void connectionError(const QString &error, const QVariantMap &details); void statusChanged(uint status, uint reason); }; class TP_QT_NO_EXPORT BaseConnectionRequestsInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(Tp::ChannelDetailsList channels READ channels) Q_PROPERTY(Tp::RequestableChannelClassList requestableChannelClasses READ requestableChannelClasses) public: Adaptee(BaseConnectionRequestsInterface *interface); ~Adaptee(); Tp::ChannelDetailsList channels() const; Tp::RequestableChannelClassList requestableChannelClasses() const { debug() << "BaseConnectionRequestsInterface::requestableChannelClasses"; return mInterface->requestableChannelClasses; } private Q_SLOTS: void createChannel(const QVariantMap &request, const Tp::Service::ConnectionInterfaceRequestsAdaptor::CreateChannelContextPtr &context); void ensureChannel(const QVariantMap &request, const Tp::Service::ConnectionInterfaceRequestsAdaptor::EnsureChannelContextPtr &context); Q_SIGNALS: void newChannels(const Tp::ChannelDetailsList &channels); void channelClosed(const QDBusObjectPath &removed); public: BaseConnectionRequestsInterface *mInterface; }; class TP_QT_NO_EXPORT BaseConnectionContactsInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QStringList contactAttributeInterfaces READ contactAttributeInterfaces) public: Adaptee(BaseConnectionContactsInterface *interface); ~Adaptee(); QStringList contactAttributeInterfaces() const; private Q_SLOTS: void getContactAttributes(const Tp::UIntList &handles, const QStringList &interfaces, bool hold, const Tp::Service::ConnectionInterfaceContactsAdaptor::GetContactAttributesContextPtr &context); public: BaseConnectionContactsInterface *mInterface; }; class TP_QT_NO_EXPORT BaseConnectionSimplePresenceInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(Tp::SimpleStatusSpecMap statuses READ statuses) Q_PROPERTY(uint maximumStatusMessageLength READ maximumStatusMessageLength) public: Adaptee(BaseConnectionSimplePresenceInterface *interface); ~Adaptee(); Tp::SimpleStatusSpecMap statuses() const; int maximumStatusMessageLength() const; private Q_SLOTS: void setPresence(const QString &status, const QString &statusMessage, const Tp::Service::ConnectionInterfaceSimplePresenceAdaptor::SetPresenceContextPtr &context); void getPresences(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceSimplePresenceAdaptor::GetPresencesContextPtr &context); Q_SIGNALS: void presencesChanged(const Tp::SimpleContactPresences &presence); public: BaseConnectionSimplePresenceInterface *mInterface; }; class TP_QT_NO_EXPORT BaseConnectionContactListInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(uint contactListState READ contactListState) Q_PROPERTY(bool contactListPersists READ contactListPersists) Q_PROPERTY(bool canChangeContactList READ canChangeContactList) Q_PROPERTY(bool requestUsesMessage READ requestUsesMessage) Q_PROPERTY(bool downloadAtConnection READ downloadAtConnection) public: Adaptee(BaseConnectionContactListInterface *interface); ~Adaptee(); uint contactListState() const; bool contactListPersists() const; bool canChangeContactList() const; bool requestUsesMessage() const; bool downloadAtConnection() const; private Q_SLOTS: void getContactListAttributes(const QStringList &interfaces, bool hold, const Tp::Service::ConnectionInterfaceContactListAdaptor::GetContactListAttributesContextPtr &context); void requestSubscription(const Tp::UIntList &contacts, const QString &message, const Tp::Service::ConnectionInterfaceContactListAdaptor::RequestSubscriptionContextPtr &context); void authorizePublication(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactListAdaptor::AuthorizePublicationContextPtr &context); void removeContacts(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactListAdaptor::RemoveContactsContextPtr &context); void unsubscribe(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactListAdaptor::UnsubscribeContextPtr &context); void unpublish(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactListAdaptor::UnpublishContextPtr &context); void download( const Tp::Service::ConnectionInterfaceContactListAdaptor::DownloadContextPtr &context); Q_SIGNALS: void contactListStateChanged(uint contactListState); void contactsChangedWithID(const Tp::ContactSubscriptionMap &changes, const Tp::HandleIdentifierMap &identifiers, const Tp::HandleIdentifierMap &removals); private: BaseConnectionContactListInterface *mInterface; }; class TP_QT_NO_EXPORT BaseConnectionContactInfoInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(uint contactInfoFlags READ contactInfoFlags) Q_PROPERTY(Tp::FieldSpecs supportedFields READ supportedFields) public: Adaptee(BaseConnectionContactInfoInterface *interface); ~Adaptee(); uint contactInfoFlags() const; Tp::FieldSpecs supportedFields() const; private Q_SLOTS: void getContactInfo(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactInfoAdaptor::GetContactInfoContextPtr &context); void refreshContactInfo(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceContactInfoAdaptor::RefreshContactInfoContextPtr &context); void requestContactInfo(uint contact, const Tp::Service::ConnectionInterfaceContactInfoAdaptor::RequestContactInfoContextPtr &context); void setContactInfo(const Tp::ContactInfoFieldList &contactInfo, const Tp::Service::ConnectionInterfaceContactInfoAdaptor::SetContactInfoContextPtr &context); signals: void contactInfoChanged(uint contact, const Tp::ContactInfoFieldList &contactInfo); private: BaseConnectionContactInfoInterface *mInterface; }; class TP_QT_NO_EXPORT BaseConnectionAddressingInterface::Adaptee : public QObject { Q_OBJECT public: Adaptee(BaseConnectionAddressingInterface *interface); ~Adaptee(); private Q_SLOTS: void getContactsByVCardField(const QString &field, const QStringList &addresses, const QStringList &interfaces, const Tp::Service::ConnectionInterfaceAddressingAdaptor::GetContactsByVCardFieldContextPtr &context); void getContactsByURI(const QStringList &URIs, const QStringList &interfaces, const Tp::Service::ConnectionInterfaceAddressingAdaptor::GetContactsByURIContextPtr &context); Q_SIGNALS: public: BaseConnectionAddressingInterface *mInterface; }; class TP_QT_NO_EXPORT BaseConnectionAliasingInterface::Adaptee : public QObject { Q_OBJECT public: Adaptee(BaseConnectionAliasingInterface *interface); ~Adaptee(); private Q_SLOTS: void getAliasFlags( const Tp::Service::ConnectionInterfaceAliasingAdaptor::GetAliasFlagsContextPtr &context); void requestAliases(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceAliasingAdaptor::RequestAliasesContextPtr &context); void getAliases(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceAliasingAdaptor::GetAliasesContextPtr &context); void setAliases(const Tp::AliasMap &aliases, const Tp::Service::ConnectionInterfaceAliasingAdaptor::SetAliasesContextPtr &context); Q_SIGNALS: void aliasesChanged(const Tp::AliasPairList &aliases); private: BaseConnectionAliasingInterface *mInterface; }; class TP_QT_NO_EXPORT BaseConnectionAvatarsInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QStringList supportedAvatarMimeTypes READ supportedAvatarMimeTypes) Q_PROPERTY(uint minimumAvatarHeight READ minimumAvatarHeight) Q_PROPERTY(uint minimumAvatarWidth READ minimumAvatarWidth) Q_PROPERTY(uint recommendedAvatarHeight READ recommendedAvatarHeight) Q_PROPERTY(uint recommendedAvatarWidth READ recommendedAvatarWidth) Q_PROPERTY(uint maximumAvatarHeight READ maximumAvatarHeight) Q_PROPERTY(uint maximumAvatarWidth READ maximumAvatarWidth) Q_PROPERTY(uint maximumAvatarBytes READ maximumAvatarBytes) public: Adaptee(BaseConnectionAvatarsInterface *interface); ~Adaptee(); QStringList supportedAvatarMimeTypes() const; uint minimumAvatarHeight() const; uint minimumAvatarWidth() const; uint recommendedAvatarHeight() const; uint recommendedAvatarWidth() const; uint maximumAvatarHeight() const; uint maximumAvatarWidth() const; uint maximumAvatarBytes() const; private Q_SLOTS: void getKnownAvatarTokens(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceAvatarsAdaptor::GetKnownAvatarTokensContextPtr &context); void requestAvatars(const Tp::UIntList &contacts, const Tp::Service::ConnectionInterfaceAvatarsAdaptor::RequestAvatarsContextPtr &context); void setAvatar(const QByteArray &avatar, const QString &mimeType, const Tp::Service::ConnectionInterfaceAvatarsAdaptor::SetAvatarContextPtr &context); void clearAvatar( const Tp::Service::ConnectionInterfaceAvatarsAdaptor::ClearAvatarContextPtr &context); Q_SIGNALS: void avatarUpdated(uint contact, const QString &newAvatarToken); void avatarRetrieved(uint contact, const QString &token, const QByteArray &avatar, const QString &type); private: BaseConnectionAvatarsInterface *mInterface; }; } telepathy-qt-0.9.6~git1/TelepathyQt/call-channel.h0000664000175000017500000001242612470405660017713 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_call_channel_h_HEADER_GUARD_ #define _TelepathyQt_call_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT CallChannel : public Channel { Q_OBJECT Q_DISABLE_COPY(CallChannel) public: static const Feature FeatureCore; static const Feature FeatureCallState; static const Feature FeatureCallMembers; static const Feature FeatureContents; static const Feature FeatureLocalHoldState; static CallChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~CallChannel(); bool handlerStreamingRequired() const; StreamTransportType initialTransportType() const; bool hasInitialAudio() const; bool hasInitialVideo() const; QString initialAudioName() const; QString initialVideoName() const; bool hasMutableContents() const; PendingOperation *setRinging(); PendingOperation *setQueued(); PendingOperation *accept(); PendingOperation *hangup(CallStateChangeReason reason = CallStateChangeReasonUserRequested, const QString &detailedReason = QString(), const QString &message = QString()); // FeatureCallState CallState callState() const; CallFlags callFlags() const; CallStateReason callStateReason() const; QVariantMap callStateDetails() const; // FeatureCallMembers Contacts remoteMembers() const; CallMemberFlags remoteMemberFlags(const ContactPtr &member) const; // FeatureContents CallContents contents() const; CallContents contentsForType(MediaStreamType type) const; CallContentPtr contentByName(const QString &contentName) const; PendingCallContent *requestContent(const QString &name, MediaStreamType type, MediaStreamDirection direction); // FeatureLocalHoldState LocalHoldState localHoldState() const; LocalHoldStateReason localHoldStateReason() const; PendingOperation *requestHold(bool hold); Q_SIGNALS: // FeatureCallState void callStateChanged(Tp::CallState state); void callFlagsChanged(Tp::CallFlags flags); // FeatureCallMembers void remoteMemberFlagsChanged( const QHash &remoteMemberFlags, const Tp::CallStateReason &reason); void remoteMembersRemoved(const Tp::Contacts &remoteMembers, const Tp::CallStateReason &reason); // FeatureContents void contentAdded(const Tp::CallContentPtr &content); void contentRemoved(const Tp::CallContentPtr &content, const Tp::CallStateReason &reason); // FeatureLocalHoldState void localHoldStateChanged(Tp::LocalHoldState state, Tp::LocalHoldStateReason reason); protected: CallChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = CallChannel::FeatureCore); private Q_SLOTS: TP_QT_NO_EXPORT void gotMainProperties(Tp::PendingOperation *op); TP_QT_NO_EXPORT void gotCallState(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onCallStateChanged(uint state, uint flags, const Tp::CallStateReason &stateReason, const QVariantMap &stateDetails); TP_QT_NO_EXPORT void gotCallMembers(Tp::PendingOperation *op); TP_QT_NO_EXPORT void gotCallMembersContacts(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onCallMembersChanged(const Tp::CallMemberMap &updates, const Tp::HandleIdentifierMap &identifiers, const Tp::UIntList &removed, const Tp::CallStateReason &reason); TP_QT_NO_EXPORT void gotContents(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onContentAdded(const QDBusObjectPath &contentPath); TP_QT_NO_EXPORT void onContentRemoved(const QDBusObjectPath &contentPath, const Tp::CallStateReason &reason); TP_QT_NO_EXPORT void onContentReady(Tp::PendingOperation *op); TP_QT_NO_EXPORT void gotLocalHoldState(QDBusPendingCallWatcher *); TP_QT_NO_EXPORT void onLocalHoldStateChanged(uint, uint); private: friend class PendingCallContent; TP_QT_NO_EXPORT CallContentPtr addContent(const QDBusObjectPath &contentPath); TP_QT_NO_EXPORT CallContentPtr lookupContent(const QDBusObjectPath &contentPath) const; struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/SimpleObserver0000664000175000017500000000037112470405660020101 0ustar jrjr#ifndef _TelepathyQt_SimpleObserver_HEADER_GUARD_ #define _TelepathyQt_SimpleObserver_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/fake-handler-manager-internal.cpp0000664000175000017500000001205612470405660023467 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/fake-handler-manager-internal.h" #include "TelepathyQt/_gen/fake-handler-manager-internal.moc.hpp" #include namespace Tp { FakeHandler::FakeHandler(const QDBusConnection &bus) : QObject(), mBus(bus) { } FakeHandler::~FakeHandler() { } ObjectPathList FakeHandler::handledChannels() const { ObjectPathList ret; foreach (const Channel *channel, mChannels) { ret << QDBusObjectPath(channel->objectPath()); } return ret; } void FakeHandler::registerChannel(const ChannelPtr &channel) { if (mChannels.contains(channel.data())) { return; } mChannels.insert(channel.data()); connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onChannelInvalidated(Tp::DBusProxy*))); connect(channel.data(), SIGNAL(destroyed(QObject*)), SLOT(onChannelDestroyed(QObject*))); } void FakeHandler::onChannelInvalidated(DBusProxy *channel) { disconnect(channel, SIGNAL(destroyed(QObject*)), this, SLOT(onChannelDestroyed(QObject*))); onChannelDestroyed(channel); } void FakeHandler::onChannelDestroyed(QObject *obj) { Channel *channel = reinterpret_cast(obj); Q_ASSERT(mChannels.contains(channel)); mChannels.remove(channel); if (mChannels.isEmpty()) { // emit invalidated here instead of relying on QObject::destroyed as FakeHandlerManager // may reuse this fake handler if FakeHandlerManager::registerChannel is called before the // slot from QObject::destroyed is invoked (deleteLater()). emit invalidated(this); deleteLater(); } } FakeHandlerManager *FakeHandlerManager::mInstance = 0; FakeHandlerManager *FakeHandlerManager::instance() { if (!mInstance) { mInstance = new FakeHandlerManager(); } return mInstance; } FakeHandlerManager::FakeHandlerManager() : QObject() { } FakeHandlerManager::~FakeHandlerManager() { mInstance = 0; } ObjectPathList FakeHandlerManager::handledChannels(const QDBusConnection &bus) const { QPair busUniqueId(bus.name(), bus.baseService()); if (mFakeHandlers.contains(busUniqueId)) { FakeHandler *fakeHandler = mFakeHandlers.value(busUniqueId); return fakeHandler->handledChannels(); } return ObjectPathList(); } void FakeHandlerManager::registerClientRegistrar(const ClientRegistrarPtr &cr) { QDBusConnection bus(cr->dbusConnection()); QPair busUniqueId(bus.name(), bus.baseService()); // keep one registrar around per bus so at least the handlers registered by it will be // around until all channels on that bus gets invalidated/destroyed if (!mClientRegistrars.contains(busUniqueId)) { mClientRegistrars.insert(busUniqueId, cr); } } void FakeHandlerManager::registerChannels(const QList &channels) { foreach (const ChannelPtr &channel, channels) { QDBusConnection bus(channel->dbusConnection()); QPair busUniqueId(bus.name(), bus.baseService()); FakeHandler *fakeHandler = mFakeHandlers.value(busUniqueId); if (!fakeHandler) { fakeHandler = new FakeHandler(bus); mFakeHandlers.insert(busUniqueId, fakeHandler); connect(fakeHandler, SIGNAL(invalidated(Tp::FakeHandler*)), SLOT(onFakeHandlerInvalidated(Tp::FakeHandler*))); } fakeHandler->registerChannel(channel); } } void FakeHandlerManager::onFakeHandlerInvalidated(FakeHandler *fakeHandler) { QDBusConnection bus(fakeHandler->dbusConnection()); QPair busUniqueId(bus.name(), bus.baseService()); mFakeHandlers.remove(busUniqueId); // all channels for the bus represented by busUniqueId were already destroyed/invalidated, // we can now free the CR (thus the handlers registered by it) registered for that bus mClientRegistrars.remove(busUniqueId); if (mFakeHandlers.isEmpty()) { // set mInstance to 0 here as we don't want instance() to return a already // deleted instance mInstance = 0; deleteLater(); } } } telepathy-qt-0.9.6~git1/TelepathyQt/base-connection-manager.cpp0000664000175000017500000003256312470405660022410 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/base-connection-manager-internal.h" #include "TelepathyQt/_gen/base-connection-manager.moc.hpp" #include "TelepathyQt/_gen/base-connection-manager-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT BaseConnectionManager::Private { Private(BaseConnectionManager *parent, const QDBusConnection &dbusConnection, const QString &name) : parent(parent), name(name), adaptee(new BaseConnectionManager::Adaptee(dbusConnection, parent)) { } BaseConnectionManager *parent; QString name; BaseConnectionManager::Adaptee *adaptee; QHash protocols; QSet connections; }; BaseConnectionManager::Adaptee::Adaptee(const QDBusConnection &dbusConnection, BaseConnectionManager *cm) : QObject(cm), mCM(cm) { mAdaptor = new Service::ConnectionManagerAdaptor(dbusConnection, this, cm->dbusObject()); } BaseConnectionManager::Adaptee::~Adaptee() { } QStringList BaseConnectionManager::Adaptee::interfaces() const { // No interfaces suitable for listing in this property are currently defined; // it's provided as a hook for possible future functionality. return QStringList(); } ProtocolPropertiesMap BaseConnectionManager::Adaptee::protocols() const { ProtocolPropertiesMap ret; foreach (const BaseProtocolPtr &protocol, mCM->protocols()) { ret.insert(protocol->name(), protocol->immutableProperties()); } return ret; } void BaseConnectionManager::Adaptee::getParameters(const QString &protocolName, const Tp::Service::ConnectionManagerAdaptor::GetParametersContextPtr &context) { if (!checkValidProtocolName(protocolName)) { context->setFinishedWithError(TP_QT_ERROR_INVALID_ARGUMENT, protocolName + QLatin1String(" is not a valid protocol name")); return; } if (!mCM->hasProtocol(protocolName)) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("unknown protocol ") + protocolName); return; } BaseProtocolPtr protocol = mCM->protocol(protocolName); ParamSpecList ret; foreach (const ProtocolParameter ¶m, protocol->parameters()) { ParamSpec paramSpec = param.bareParameter(); if (!(paramSpec.flags & ConnMgrParamFlagHasDefault)) { // we cannot pass QVariant::Invalid over D-Bus, lets build a dummy value // that should be ignored according to the spec paramSpec.defaultValue = QDBusVariant( parseValueWithDBusSignature(QString(), paramSpec.signature)); } ret << paramSpec; } context->setFinished(ret); } void BaseConnectionManager::Adaptee::listProtocols( const Tp::Service::ConnectionManagerAdaptor::ListProtocolsContextPtr &context) { QStringList ret; QList protocols = mCM->protocols(); foreach (const BaseProtocolPtr &protocol, protocols) { ret << protocol->name(); } context->setFinished(ret); } void BaseConnectionManager::Adaptee::requestConnection(const QString &protocolName, const QVariantMap ¶meters, const Tp::Service::ConnectionManagerAdaptor::RequestConnectionContextPtr &context) { if (!checkValidProtocolName(protocolName)) { context->setFinishedWithError(TP_QT_ERROR_INVALID_ARGUMENT, protocolName + QLatin1String(" is not a valid protocol name")); return; } if (!mCM->hasProtocol(protocolName)) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("unknown protocol ") + protocolName); return; } BaseProtocolPtr protocol = mCM->protocol(protocolName); DBusError error; BaseConnectionPtr connection; connection = protocol->createConnection(parameters, &error); if (!connection) { context->setFinishedWithError(error.name(), error.message()); return; } if (!connection->registerObject(&error)) { context->setFinishedWithError(error.name(), error.message()); return; } mCM->addConnection(connection); emit newConnection(connection->busName(), QDBusObjectPath(connection->objectPath()), protocol->name()); context->setFinished(connection->busName(), QDBusObjectPath(connection->objectPath())); } /** * \class BaseConnectionManager * \ingroup servicecm * \headerfile TelepathyQt/base-connection-manager.h * * \brief Base class for connection manager implementations. */ /** * Constructs a new BaseConnectionManager object that implements a connection manager * on the given \a dbusConnection and has the given \a name. * * \param dbusConnection The QDBusConnection to use. * \param name The name of the connection manager. */ BaseConnectionManager::BaseConnectionManager(const QDBusConnection &dbusConnection, const QString &name) : DBusService(dbusConnection), mPriv(new Private(this, dbusConnection, name)) { } /** * Class destructor. */ BaseConnectionManager::~BaseConnectionManager() { delete mPriv; } /** * Return the connection manager's name, as given on the constructor. * * \return The connection manager's name. */ QString BaseConnectionManager::name() const { return mPriv->name; } /** * Return the immutable properties of this connection manager object. * * Immutable properties cannot change after the object has been registered * on the bus with registerObject(). * * \return The immutable properties of this connection manager object. */ QVariantMap BaseConnectionManager::immutableProperties() const { QVariantMap ret; ret.insert(TP_QT_IFACE_CONNECTION_MANAGER + QLatin1String(".Protocols"), QVariant::fromValue(mPriv->adaptee->protocols())); return ret; } /** * Return a list of all protocols that this connection manager implements. * * This property is immutable and cannot change after the connection manager * has been registered on the bus with registerObject(). * * \return A list of all protocols that this connection manager implements. * \sa addProtocol(), hasProtocol(), protocol() */ QList BaseConnectionManager::protocols() const { return mPriv->protocols.values(); } /** * Return a pointer to the BaseProtocol instance that implements the protocol * with the given \a protocolName, or a null BaseProtocolPtr if no such * protocol has been added to the connection manager. * * \param protocolName The name of the protocol in interest. * \return The BaseProtocol instance that implements the protocol with * the given \a protocolName. * \sa hasProtocol(), protocols(), addProtocol() */ BaseProtocolPtr BaseConnectionManager::protocol(const QString &protocolName) const { return mPriv->protocols.value(protocolName); } /** * Return whether a protocol with the given \a protocolName has been * added to the connection manager. * * \param protocolName The name of the protocol in interest. * \return \c true if a protocol with the given \a protocolName has been * added to the connection manager, or \c false otherwise. * \sa addProtocol(), protocol(), protocols() */ bool BaseConnectionManager::hasProtocol(const QString &protocolName) const { return mPriv->protocols.contains(protocolName); } /** * Add a new \a protocol to the list of protocols that this connection * manager implements. * * Note that you cannot add new protocols after the connection manager * has been registered on the bus with registerObject(). In addition, * you cannot add two protocols with the same name. If any of these * conditions is not met, this function will return false and print * a suitable warning. * * \param protocol The protocol to add. * \return \c true on success or \c false otherwise. */ bool BaseConnectionManager::addProtocol(const BaseProtocolPtr &protocol) { if (isRegistered()) { warning() << "Unable to add protocol" << protocol->name() << "- CM already registered"; return false; } if (protocol->dbusConnection().name() != dbusConnection().name()) { warning() << "Unable to add protocol" << protocol->name() << "- protocol must have the same D-Bus connection as the owning CM"; return false; } if (protocol->isRegistered()) { warning() << "Unable to add protocol" << protocol->name() << "- protocol already registered"; return false; } if (mPriv->protocols.contains(protocol->name())) { warning() << "Unable to add protocol" << protocol->name() << "- another protocol with same name already added"; return false; } debug() << "Protocol" << protocol->name() << "added to CM"; mPriv->protocols.insert(protocol->name(), protocol); return true; } /** * Register this connection manager on the bus. * * A connection manager can only be registered once, and it * should be registered only after all the protocols it implements * have been added with addProtocol(). * * If \a error is passed, any D-Bus error that may occur will * be stored there. * * \param error A pointer to an empty DBusError where any * possible D-Bus error will be stored. * \return \c true on success and \c false if there was an error * or this connection manager is already registered. * \sa isRegistered() */ bool BaseConnectionManager::registerObject(DBusError *error) { if (isRegistered()) { return true; } QString busName = TP_QT_CONNECTION_MANAGER_BUS_NAME_BASE; busName.append(mPriv->name); QString objectPath = TP_QT_CONNECTION_MANAGER_OBJECT_PATH_BASE; objectPath.append(mPriv->name); DBusError _error; bool ret = registerObject(busName, objectPath, &_error); if (!ret && error) { error->set(_error.name(), _error.message()); } return ret; } /** * Reimplemented from DBusService. */ bool BaseConnectionManager::registerObject(const QString &busName, const QString &objectPath, DBusError *error) { if (isRegistered()) { return true; } // register protocols foreach (const BaseProtocolPtr &protocol, protocols()) { QString escapedProtocolName = protocol->name(); escapedProtocolName.replace(QLatin1Char('-'), QLatin1Char('_')); QString protoObjectPath = QString( QLatin1String("%1/%2")).arg(objectPath).arg(escapedProtocolName); debug() << "Registering protocol" << protocol->name() << "at path" << protoObjectPath << "for CM" << objectPath << "at bus name" << busName; if (!protocol->registerObject(busName, protoObjectPath, error)) { return false; } } debug() << "Registering CM" << objectPath << "at bus name" << busName; // Only call DBusService::registerObject after registering the protocols as we don't want to // advertise isRegistered if some protocol cannot be registered if (!DBusService::registerObject(busName, objectPath, error)) { return false; } return true; } /** * Return a list of all connections that have currently been made. * * \return A list of all connections that have currently been made. */ QList BaseConnectionManager::connections() const { return mPriv->connections.toList(); } void BaseConnectionManager::addConnection(const BaseConnectionPtr &connection) { Q_ASSERT(!mPriv->connections.contains(connection)); mPriv->connections.insert(connection); connect(connection.data(), SIGNAL(disconnected()), SLOT(removeConnection())); emit newConnection(connection); } void BaseConnectionManager::removeConnection() { BaseConnectionPtr connection = BaseConnectionPtr( qobject_cast(sender())); Q_ASSERT(connection); Q_ASSERT(mPriv->connections.contains(connection)); mPriv->connections.remove(connection); } /** * \fn void newConnection(const BaseConnectionPtr &connection) * * Emitted when a new connection has been requested by a client and * the connection object has been constructed. * * To handle the connection request before a connection has been created, * use BaseProtocol::setCreateConnectionCallback(). * * \param connection The newly created connection */ } telepathy-qt-0.9.6~git1/TelepathyQt/AbstractClientHandler0000664000175000017500000000040712470405660021340 0ustar jrjr#ifndef _TelepathyQt_AbstractClientHandler_HEADER_GUARD_ #define _TelepathyQt_AbstractClientHandler_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PendingStreamTubeConnection0000664000175000017500000000044212470405660022537 0ustar jrjr#ifndef _TelepathyQt_PendingStreamTubeConnection_HEADER_GUARD_ #define _TelepathyQt_PendingStreamTubeConnection_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/dbus.cpp0000664000175000017500000000204212470405660016653 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/cli-dbus-body.hpp" #include "TelepathyQt/_gen/cli-dbus.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/PendingCallContent0000664000175000017500000000037612470405660020660 0ustar jrjr#ifndef _TelepathyQt_PendingCallContent_HEADER_GUARD_ #define _TelepathyQt_PendingCallContent_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/location-info.cpp0000664000175000017500000001206212470405660020462 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include namespace Tp { struct TP_QT_NO_EXPORT LocationInfo::Private : public QSharedData { QVariantMap location; }; /** * \class LocationInfo * \ingroup clientconn * \headerfile TelepathyQt/location-info.h * * \brief The LocationInfo class represents the location of a * Telepathy Contact. */ /** * Construct a new LocationInfo object. */ LocationInfo::LocationInfo() : mPriv(new Private) { } LocationInfo::LocationInfo(const QVariantMap &location) : mPriv(new Private) { mPriv->location = location; } LocationInfo::LocationInfo(const LocationInfo &other) : mPriv(other.mPriv) { } /** * Class destructor. */ LocationInfo::~LocationInfo() { } LocationInfo &LocationInfo::operator=(const LocationInfo &other) { this->mPriv = other.mPriv; return *this; } QString LocationInfo::countryCode() const { return qdbus_cast(mPriv->location.value( QLatin1String("countrycode"))); } QString LocationInfo::country() const { return qdbus_cast(mPriv->location.value( QLatin1String("country"))); } QString LocationInfo::region() const { return qdbus_cast(mPriv->location.value( QLatin1String("region"))); } QString LocationInfo::locality() const { return qdbus_cast(mPriv->location.value( QLatin1String("locality"))); } QString LocationInfo::area() const { return qdbus_cast(mPriv->location.value( QLatin1String("area"))); } QString LocationInfo::postalCode() const { return qdbus_cast(mPriv->location.value( QLatin1String("postalcode"))); } QString LocationInfo::street() const { return qdbus_cast(mPriv->location.value( QLatin1String("street"))); } QString LocationInfo::building() const { return qdbus_cast(mPriv->location.value( QLatin1String("building"))); } QString LocationInfo::floor() const { return qdbus_cast(mPriv->location.value( QLatin1String("floor"))); } QString LocationInfo::room() const { return qdbus_cast(mPriv->location.value( QLatin1String("room"))); } QString LocationInfo::text() const { return qdbus_cast(mPriv->location.value( QLatin1String("text"))); } QString LocationInfo::description() const { return qdbus_cast(mPriv->location.value( QLatin1String("description"))); } QString LocationInfo::uri() const { return qdbus_cast(mPriv->location.value( QLatin1String("uri"))); } QString LocationInfo::language() const { return qdbus_cast(mPriv->location.value( QLatin1String("language"))); } double LocationInfo::latitude() const { return qdbus_cast(mPriv->location.value( QLatin1String("lat"))); } double LocationInfo::longitude() const { return qdbus_cast(mPriv->location.value( QLatin1String("lon"))); } double LocationInfo::altitude() const { return qdbus_cast(mPriv->location.value( QLatin1String("alt"))); } double LocationInfo::accuracy() const { return qdbus_cast(mPriv->location.value( QLatin1String("accuracy"))); } double LocationInfo::speed() const { return qdbus_cast(mPriv->location.value( QLatin1String("speed"))); } double LocationInfo::bearing() const { return qdbus_cast(mPriv->location.value( QLatin1String("bearing"))); } QDateTime LocationInfo::timestamp() const { // FIXME See http://bugs.freedesktop.org/show_bug.cgi?id=21690 qlonglong t = qdbus_cast(mPriv->location.value( QLatin1String("timestamp"))); if (t != 0) { return QDateTime::fromTime_t((uint) t); } return QDateTime(); } QVariantMap LocationInfo::allDetails() const { return mPriv->location; } void LocationInfo::updateData(const QVariantMap &location) { if (!isValid()) { mPriv = new Private; } mPriv->location = location; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/PendingSuccess0000664000175000017500000000040312470405660020051 0ustar jrjr#ifndef _TelepathyQt_PendingSuccess_HEADER_GUARD_ #define _TelepathyQt_PendingSuccess_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-variant.h0000664000175000017500000000315412470405660020456 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_variant_h_HEADER_GUARD_ #define _TelepathyQt_pending_variant_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class TP_QT_EXPORT PendingVariant : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingVariant); public: PendingVariant(QDBusPendingCall call, const SharedPtr &object); ~PendingVariant(); QVariant result() const; private Q_SLOTS: TP_QT_NO_EXPORT void watcherFinished(QDBusPendingCallWatcher*); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/pending-dbus-tube-connection.cpp0000664000175000017500000001513712470405660023400 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-dbus-tube-connection.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingDBusTubeConnection::Private { Private(PendingDBusTubeConnection *parent); // Public object PendingDBusTubeConnection *parent; DBusTubeChannelPtr tube; bool allowOtherUsers; QVariantMap parameters; }; PendingDBusTubeConnection::Private::Private(PendingDBusTubeConnection *parent) : parent(parent), allowOtherUsers(false) { } /** * \class PendingDBusTubeConnection * \ingroup clientchannel * \headerfile TelepathyQt/pending-dbus-tube-connection.h * * A pending operation for accepting or offering a DBus tube * * This class represents an asynchronous operation for accepting or offering a DBus tube. * Upon completion, the address of the opened tube is returned as a QString. */ PendingDBusTubeConnection::PendingDBusTubeConnection( PendingString* string, bool allowOtherUsers, const QVariantMap& parameters, const DBusTubeChannelPtr& object) : PendingOperation(object) , mPriv(new Private(this)) { mPriv->tube = object; mPriv->allowOtherUsers = allowOtherUsers; mPriv->parameters = parameters; connect(mPriv->tube.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), this, SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString))); if (string->isFinished()) { onConnectionFinished(string); } else { // Connect the pending void connect(string, SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(onConnectionFinished(Tp::PendingOperation*))); } } PendingDBusTubeConnection::PendingDBusTubeConnection( const QString &errorName, const QString &errorMessage, const DBusTubeChannelPtr &object) : PendingOperation(object) , mPriv(new PendingDBusTubeConnection::Private(this)) { setFinishedWithError(errorName, errorMessage); } /** * Class destructor */ PendingDBusTubeConnection::~PendingDBusTubeConnection() { delete mPriv; } /** * When the operation has been completed successfully, returns the address of the opened DBus connection. * * Please note this function will return a meaningful value only if the operation has already * been completed successfully: in case of failure or non-completion, an empty QString will be * returned. * * \note If you plan to use QtDBus for the DBus connection, please note you should always use * QDBusConnection::connectToPeer(), regardless of the fact this tube is a p2p or a group one. * The above function has been introduced in Qt 4.8, previous versions of Qt do not allow the use * of DBus Tubes through QtDBus. * * \returns The address of the opened DBus connection. */ QString PendingDBusTubeConnection::address() const { return mPriv->tube->address(); } /** * Return whether this tube allows other users more than the current one to connect to the * private bus created by the tube. * * Note that even if the tube was accepted or offered specifying not to allow other users, this * method might still return true if one of the ends did not support such a restriction. * * In fact, if one of the ends does not support current user restriction, * the tube will be offered regardless, falling back to allowing any connection. If your * application requires strictly this condition to be enforced, you should check * DBusTubeChannel::supportsRestrictingToCurrentUser before offering the tube, * and take action from there. * * This function, however, is guaranteed to return the same value of the given allowOtherUsers * parameter when accepting or offering a tube if supportsRestrictingToCurrentUser is true. * * \return \c true if any user is allow to connect, \c false otherwise. */ bool PendingDBusTubeConnection::allowsOtherUsers() const { return mPriv->allowOtherUsers; } void PendingDBusTubeConnection::onConnectionFinished(PendingOperation *op) { if (isFinished()) { // The operation has already failed return; } if (op->isError()) { // Fail setFinishedWithError(op->errorName(), op->errorMessage()); return; } debug() << "Accept/Offer tube finished successfully"; // Now get the address and set it PendingString *ps = qobject_cast(op); debug() << "Got address " << ps->result(); mPriv->tube->setAddress(ps->result()); // It might have been already opened - check if (mPriv->tube->state() == TubeChannelStateOpen) { onStateChanged(mPriv->tube->state()); } else { // Wait until the tube gets opened on the other side connect(mPriv->tube.data(), SIGNAL(stateChanged(Tp::TubeChannelState)), this, SLOT(onStateChanged(Tp::TubeChannelState))); } } void PendingDBusTubeConnection::onStateChanged(TubeChannelState state) { debug() << "Tube state changed to " << state; if (state == TubeChannelStateOpen) { if (!mPriv->parameters.isEmpty()) { // Inject the parameters into the tube mPriv->tube->setParameters(mPriv->parameters); } // The tube is ready: mark the operation as finished setFinished(); } } void PendingDBusTubeConnection::onChannelInvalidated(DBusProxy* proxy, const QString& errorName, const QString& errorMessage) { Q_UNUSED(proxy); if (isFinished()) { // The operation has already finished return; } setFinishedWithError(errorName, errorMessage); } } telepathy-qt-0.9.6~git1/TelepathyQt/Contact0000664000175000017500000000034312470405660016532 0ustar jrjr#ifndef _TelepathyQt_Contact_HEADER_GUARD_ #define _TelepathyQt_Contact_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionCapabilities0000664000175000017500000000042112470405660021545 0ustar jrjr#ifndef _TelepathyQt_ConnectionCapabilities_HEADER_GUARD_ #define _TelepathyQt_ConnectionCapabilities_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/dbus-tube-channel.h0000664000175000017500000000512212470405660020665 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_dbus_tube_channel_h_HEADER_GUARD_ #define _TelepathyQt_dbus_tube_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class TP_QT_EXPORT DBusTubeChannel : public TubeChannel { Q_OBJECT Q_DISABLE_COPY(DBusTubeChannel) public: static const Feature FeatureCore; static const Feature FeatureBusNameMonitoring; static DBusTubeChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~DBusTubeChannel(); QString serviceName() const; bool supportsRestrictingToCurrentUser() const; QHash contactsForBusNames() const; QString address() const; protected: DBusTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); Q_SIGNALS: void busNameAdded(const QString &busName, const Tp::ContactPtr &contact); void busNameRemoved(const QString &busName, const Tp::ContactPtr &contact); private Q_SLOTS: TP_QT_NO_EXPORT void onRequestAllPropertiesFinished(Tp::PendingOperation*); TP_QT_NO_EXPORT void onRequestPropertyDBusNamesFinished(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onDBusNamesChanged(const Tp::DBusTubeParticipants &added, const Tp::UIntList &removed); TP_QT_NO_EXPORT void onContactsRetrieved(const QUuid &uuid, const QList &contacts); TP_QT_NO_EXPORT void onQueueCompleted(); private: TP_QT_NO_EXPORT void setAddress(const QString &address); struct Private; friend struct PendingDBusTubeConnection; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/PendingCaptchas0000664000175000017500000000037412470405660020176 0ustar jrjr#ifndef _TelepathyQt_PendingCaptchas_HEADER_GUARD_ #define _TelepathyQt_PendingCaptchas_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelDispatchOperation0000664000175000017500000000043012470405660022045 0ustar jrjr#ifndef _TelepathyQt_ChannelDispatchOperation_HEADER_GUARD_ #define _TelepathyQt_ChannelDispatchOperation_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/filter.dox0000664000175000017500000000224712470405660017222 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \class Tp::Filter * \ingroup utils * \headerfile TelepathyQt/filter.h * * \brief The Filter class provides a base class to be used by specialized * filters such as GenericCapabilityFilter, GenericPropertyFilter, etc. */ telepathy-qt-0.9.6~git1/TelepathyQt/client.h0000664000175000017500000000215312470405660016644 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_client_h_HEADER_GUARD_ #define _TelepathyQt_client_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/call-channel.cpp0000664000175000017500000013034412470405660020246 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/call-channel.moc.hpp" #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT CallChannel::Private { Private(CallChannel *parent); ~Private(); static void introspectCore(Private *self); static void introspectCallState(Private *self); static void introspectCallMembers(Private *self); static void introspectContents(Private *self); static void introspectLocalHoldState(Private *self); void processCallMembersChanged(); struct CallMembersChangedInfo; // Public object CallChannel *parent; // Mandatory proxies Client::ChannelTypeCallInterface *callInterface; ReadinessHelper *readinessHelper; // Introspection uint state; uint flags; CallStateReason stateReason; QVariantMap stateDetails; CallMemberMap callMembers; QHash callMembersContacts; QQueue< QSharedPointer > callMembersChangedQueue; QSharedPointer currentCallMembersChangedInfo; bool hardwareStreaming; uint initialTransportType; bool initialAudio; bool initialVideo; QString initialAudioName; QString initialVideoName; bool mutableContents; CallContents contents; CallContents incompleteContents; uint localHoldState; uint localHoldStateReason; }; struct TP_QT_NO_EXPORT CallChannel::Private::CallMembersChangedInfo { CallMembersChangedInfo(const CallMemberMap &updates, const HandleIdentifierMap &identifiers, const UIntList &removed, const CallStateReason &reason) : updates(updates), identifiers(identifiers), removed(removed), reason(reason) { } static QSharedPointer create( const CallMemberMap &updates, const HandleIdentifierMap &identifiers, const UIntList &removed, const CallStateReason &reason) { CallMembersChangedInfo *info = new CallMembersChangedInfo( updates, identifiers, removed, reason); return QSharedPointer(info); } CallMemberMap updates; HandleIdentifierMap identifiers; UIntList removed; CallStateReason reason; }; CallChannel::Private::Private(CallChannel *parent) : parent(parent), callInterface(parent->interface()), readinessHelper(parent->readinessHelper()), state(CallStateUnknown), flags((uint) -1), hardwareStreaming(false), initialTransportType(StreamTransportTypeUnknown), initialAudio(false), initialVideo(false), mutableContents(false), localHoldState(LocalHoldStateUnheld), localHoldStateReason(LocalHoldStateReasonNone) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectCore, this); introspectables[FeatureCore] = introspectableCore; ReadinessHelper::Introspectable introspectableCallState( QSet() << 0, // makesSenseForStatuses Features() << CallChannel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectCallState, this); introspectables[FeatureCallState] = introspectableCallState; ReadinessHelper::Introspectable introspectableCallMembers( QSet() << 0, // makesSenseForStatuses Features() << CallChannel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectCallMembers, this); introspectables[FeatureCallMembers] = introspectableCallMembers; ReadinessHelper::Introspectable introspectableContents( QSet() << 0, // makesSenseForStatuses Features() << CallChannel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectContents, this); introspectables[FeatureContents] = introspectableContents; ReadinessHelper::Introspectable introspectableLocalHoldState( QSet() << 0, // makesSenseForStatuses Features() << CallChannel::FeatureCore, // dependsOnFeatures (core) QStringList() << TP_QT_IFACE_CHANNEL_INTERFACE_HOLD, // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectLocalHoldState, this); introspectables[FeatureLocalHoldState] = introspectableLocalHoldState; readinessHelper->addIntrospectables(introspectables); } CallChannel::Private::~Private() { } void CallChannel::Private::introspectCore(CallChannel::Private *self) { const static QString qualifiedNames[] = { TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".HardwareStreaming"), TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialTransport"), TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"), TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo"), TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudioName"), TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideoName"), TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".MutableContents") }; CallChannel *parent = self->parent; QVariantMap immutableProperties = parent->immutableProperties(); bool needIntrospectMainProps = false; for (unsigned i = 0; i < sizeof(qualifiedNames)/sizeof(QString); ++i) { const QString &qualified = qualifiedNames[i]; if (!immutableProperties.contains(qualified)) { needIntrospectMainProps = true; break; } } if (needIntrospectMainProps) { debug() << "Introspecting immutable properties of CallChannel"; parent->connect(self->callInterface->requestAllProperties(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotMainProperties(Tp::PendingOperation*))); } else { self->hardwareStreaming = qdbus_cast(immutableProperties[ TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".HardwareStreaming")]); self->initialTransportType = qdbus_cast(immutableProperties[ TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialTransport")]); self->initialAudio = qdbus_cast(immutableProperties[ TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio")]); self->initialVideo = qdbus_cast(immutableProperties[ TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo")]); self->initialAudioName = qdbus_cast(immutableProperties[ TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudioName")]); self->initialVideoName = qdbus_cast(immutableProperties[ TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideoName")]); self->mutableContents = qdbus_cast(immutableProperties[ TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".MutableContents")]); self->readinessHelper->setIntrospectCompleted(FeatureCore, true); } } void CallChannel::Private::introspectCallState(CallChannel::Private *self) { CallChannel *parent = self->parent; parent->connect(self->callInterface, SIGNAL(CallStateChanged(uint,uint,Tp::CallStateReason,QVariantMap)), SLOT(onCallStateChanged(uint,uint,Tp::CallStateReason,QVariantMap))); parent->connect(self->callInterface->requestAllProperties(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotCallState(Tp::PendingOperation*))); } void CallChannel::Private::introspectCallMembers(CallChannel::Private *self) { CallChannel *parent = self->parent; parent->connect(self->callInterface, SIGNAL(CallMembersChanged(Tp::CallMemberMap,Tp::HandleIdentifierMap,Tp::UIntList,Tp::CallStateReason)), SLOT(onCallMembersChanged(Tp::CallMemberMap,Tp::HandleIdentifierMap,Tp::UIntList,Tp::CallStateReason))); parent->connect(self->callInterface->requestAllProperties(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotCallMembers(Tp::PendingOperation*))); } void CallChannel::Private::introspectContents(CallChannel::Private *self) { CallChannel *parent = self->parent; parent->connect(self->callInterface, SIGNAL(ContentAdded(QDBusObjectPath)), SLOT(onContentAdded(QDBusObjectPath))); parent->connect(self->callInterface, SIGNAL(ContentRemoved(QDBusObjectPath,Tp::CallStateReason)), SLOT(onContentRemoved(QDBusObjectPath,Tp::CallStateReason))); parent->connect(self->callInterface->requestPropertyContents(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotContents(Tp::PendingOperation*))); } void CallChannel::Private::introspectLocalHoldState(CallChannel::Private *self) { CallChannel *parent = self->parent; Client::ChannelInterfaceHoldInterface *holdInterface = parent->interface(); parent->connect(holdInterface, SIGNAL(HoldStateChanged(uint,uint)), SLOT(onLocalHoldStateChanged(uint,uint))); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( holdInterface->GetHoldState(), parent); parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotLocalHoldState(QDBusPendingCallWatcher*))); } void CallChannel::Private::processCallMembersChanged() { if (currentCallMembersChangedInfo) { // currently building contacts return; } if (callMembersChangedQueue.isEmpty()) { if (!parent->isReady(FeatureCallMembers)) { readinessHelper->setIntrospectCompleted(FeatureCallMembers, true); } return; } currentCallMembersChangedInfo = callMembersChangedQueue.dequeue(); QSet pendingCallMembers; for (ContactSendingStateMap::const_iterator i = currentCallMembersChangedInfo->updates.constBegin(); i != currentCallMembersChangedInfo->updates.constEnd(); ++i) { pendingCallMembers.insert(i.key()); } foreach(uint i, currentCallMembersChangedInfo->removed) { pendingCallMembers.insert(i); } if (!pendingCallMembers.isEmpty()) { ConnectionPtr connection = parent->connection(); connection->lowlevel()->injectContactIds(currentCallMembersChangedInfo->identifiers); ContactManagerPtr contactManager = connection->contactManager(); PendingContacts *contacts = contactManager->contactsForHandles( pendingCallMembers.toList()); parent->connect(contacts, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotCallMembersContacts(Tp::PendingOperation*))); } else { currentCallMembersChangedInfo.clear(); processCallMembersChanged(); } } /** * \class CallChannel * \ingroup clientchannel * \headerfile TelepathyQt/call-channel.h * * \brief The CallChannel class provides an object representing a * Telepathy channel of type Call. */ /** * Feature representing the core that needs to become ready to make the * CallChannel object usable. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature CallChannel::FeatureCore = Feature(QLatin1String(CallChannel::staticMetaObject.className()), 0, true); /** * Feature used in order to access call state specific methods. * * See call state specific methods' documentation for more details. */ const Feature CallChannel::FeatureCallState = Feature(QLatin1String(CallChannel::staticMetaObject.className()), 1); /** * Feature used in order to access members specific methods. * * See local members specific methods' documentation for more details. */ const Feature CallChannel::FeatureCallMembers = Feature(QLatin1String(CallChannel::staticMetaObject.className()), 2); /** * Feature used in order to access content specific methods. * * See media content specific methods' documentation for more details. */ const Feature CallChannel::FeatureContents = Feature(QLatin1String(CallChannel::staticMetaObject.className()), 3); /** * Feature used in order to access local hold state info. * * See local hold state specific methods' documentation for more details. */ const Feature CallChannel::FeatureLocalHoldState = Feature(QLatin1String(CallChannel::staticMetaObject.className()), 4); /** * Create a new CallChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The object path of this channel. * \param immutableProperties The immutable properties of this channel. * \return A CallChannelPtr object pointing to the newly created * CallChannel object. */ CallChannelPtr CallChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return CallChannelPtr(new CallChannel(connection, objectPath, immutableProperties)); } /** * Construct a new CallChannel associated with the given object on the same * service as the given connection. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The object path of this channel. * \param immutableProperties The immutable properties of this channel. * \param coreFeature The core feature of the channel type. The corresponding introspectable * should depend on Channel::FeatureCore. */ CallChannel::CallChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : Channel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ CallChannel::~CallChannel() { delete mPriv; } /** * Return the current high-level state of this call. * * This function requires CallChannel::FeatureCallState to be enabled. * * \return The current high-level state of this call. * \sa callStateChanged() */ CallState CallChannel::callState() const { if (!isReady(FeatureCallState)) { warning() << "CallChannel::callState() used with FeatureCallState not ready"; } return (CallState) mPriv->state; } /** * Return the flags representing the status of this call as a whole, providing more specific * information than callState(). * * This function requires CallChannel::FeatureCallState to be enabled. * * \return The flags representing the status of this call. * \sa callFlagsChanged() */ CallFlags CallChannel::callFlags() const { if (!isReady(FeatureCallState)) { warning() << "CallChannel::callFlags() used with FeatureCallState not ready"; } return (CallFlags) mPriv->flags; } /** * Return the reason for the last change to the callState() and/or callFlags(). * * This function requires CallChannel::FeatureCallState to be enabled. * * \return The reason for the last change to the callState() and/or callFlags(). * \sa callStateChanged(), callFlagsChanged() */ CallStateReason CallChannel::callStateReason() const { if (!isReady(FeatureCallState)) { warning() << "CallChannel::callStateReason() used with FeatureCallState not ready"; } return mPriv->stateReason; } /** * Return optional extensible details for the callState(), * callFlags() and/or callStateReason(). * * This function requires CallChannel::FeatureCallState to be enabled. * * \return The optional extensible details for the callState(), * callFlags() and/or callStateReason(). * \sa callStateChanged(), callFlagsChanged() */ QVariantMap CallChannel::callStateDetails() const { if (!isReady(FeatureCallState)) { warning() << "CallChannel::callStateDetails() used with FeatureCallState not ready"; } return mPriv->stateDetails; } /** * Return the remote members of this call. * * This function requires CallChannel::FeatureCallMembers to be enabled. * * \return The remote members of this call. * \sa remoteMemberFlags(), remoteMemberFlagsChanged(), remoteMembersRemoved() */ Contacts CallChannel::remoteMembers() const { if (!isReady(FeatureCallMembers)) { warning() << "CallChannel::remoteMembers() used with FeatureCallMembers not ready"; return Contacts(); } return mPriv->callMembersContacts.values().toSet(); } /** * Return the flags that describe the status of a given \a member of this call. * * This function requires CallChannel::FeatureCallMembers to be enabled. * * \param member The member of interest. * \return The flags that describe the status of the requested member. * \sa remoteMemberFlagsChanged(), remoteMembers(), remoteMembersRemoved() */ CallMemberFlags CallChannel::remoteMemberFlags(const ContactPtr &member) const { if (!isReady(FeatureCallMembers)) { warning() << "CallChannel::remoteMemberFlags() used with FeatureCallMembers not ready"; return (CallMemberFlags) 0; } if (!member) { return (CallMemberFlags) 0; } for (CallMemberMap::const_iterator i = mPriv->callMembers.constBegin(); i != mPriv->callMembers.constEnd(); ++i) { uint handle = i.key(); CallMemberFlags sendingState = (CallMemberFlags) i.value(); if (handle == member->handle()[0]) { return sendingState; } } return (CallMemberFlags) 0; } /** * Check whether media streaming by the handler is required for this channel. * * If \c false, all of the media streaming is done by some mechanism outside the scope * of Telepathy, otherwise the handler is responsible for doing the actual media streaming. * * \return \c true if required, \c false otherwise. */ bool CallChannel::handlerStreamingRequired() const { return !mPriv->hardwareStreaming; } /** * Return the initial transport type used for this call if set on a requested channel. * * Where not applicable, this property is defined to be #StreamTransportTypeUnknown, in * particular, on CMs with hardware streaming. * * \return The initial transport type used for this call. */ StreamTransportType CallChannel::initialTransportType() const { return (StreamTransportType) mPriv->initialTransportType; } /** * Return whether an audio content was requested at the channel's creation time. * * \return \c true if an audio content was requested, \c false otherwise. */ bool CallChannel::hasInitialAudio() const { return mPriv->initialAudio; } /** * Return whether a video content was requested at the channel's creation time. * * \return \c true if an video content was requested, \c false otherwise. */ bool CallChannel::hasInitialVideo() const { return mPriv->initialVideo; } /** * Return the name of the initial audio content if hasInitialAudio() returns \c true. * * \return The name of the initial audio content. */ QString CallChannel::initialAudioName() const { return mPriv->initialAudioName; } /** * Return the name of the initial video content if hasInitialVideo() returns \c true. * * \return The name of the initial video content. */ QString CallChannel::initialVideoName() const { return mPriv->initialVideoName; } /** * Return whether new contents can be added on the call after the Channel has * been requested. * * \return \c true if a new content can be added after the Channel has been * requested, \c false otherwise. * \sa requestContent() */ bool CallChannel::hasMutableContents() const { return mPriv->mutableContents; } /** * Indicate that the local user has been alerted about the incoming call. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *CallChannel::setRinging() { return new PendingVoid(mPriv->callInterface->SetRinging(), CallChannelPtr(this)); } /** * Notify the CM that the local user is already in a call, so this * call has been put in a call-waiting style queue. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *CallChannel::setQueued() { return new PendingVoid(mPriv->callInterface->SetQueued(), CallChannelPtr(this)); } /** * Accept an incoming call, or begin calling the remote contact on an outgoing call. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *CallChannel::accept() { return new PendingVoid(mPriv->callInterface->Accept(), CallChannelPtr(this)); } /** * Request that the call is ended. * * \param reason A generic hangup reason. * \param detailedReason A more specific reason for the call hangup, if one is * available, or an empty string otherwise. * \param message A human-readable message to be sent to the remote contact(s). * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *CallChannel::hangup(CallStateChangeReason reason, const QString &detailedReason, const QString &message) { return new PendingVoid(mPriv->callInterface->Hangup(reason, detailedReason, message), CallChannelPtr(this)); } /** * Return a list of media contents in this channel. * * This methods requires CallChannel::FeatureContents to be enabled. * * \return The contents in this channel. * \sa contentAdded(), contentRemoved(), contentsForType(), contentByName(), requestContent() */ CallContents CallChannel::contents() const { if (!isReady(FeatureContents)) { warning() << "CallChannel::contents() used with FeatureContents not ready"; return CallContents(); } return mPriv->contents; } /** * Return a list of media contents in this channel for the given type \a type. * * This methods requires CallChannel::FeatureContents to be enabled. * * \param type The interested type. * \return A list of media contents in this channel for the given type \a type. * \sa contentAdded(), contentRemoved(), contents(), contentByName(), requestContent() */ CallContents CallChannel::contentsForType(MediaStreamType type) const { if (!isReady(FeatureContents)) { warning() << "CallChannel::contents() used with FeatureContents not ready"; return CallContents(); } CallContents contents; foreach (const CallContentPtr &content, mPriv->contents) { if (content->type() == type) { contents.append(content); } } return contents; } /** * Return the media content in this channel that has the specified \a name. * * This methods requires CallChannel::FeatureContents to be enabled. * * \param name The interested name. * \return The media content in this channel that has the specified \a name. * \sa contentAdded(), contentRemoved(), contents(), contentsForType(), requestContent() */ CallContentPtr CallChannel::contentByName(const QString &contentName) const { if (!isReady(FeatureContents)) { warning() << "CallChannel::contentByName() used with FeatureContents not ready"; return CallContentPtr(); } foreach (const CallContentPtr &content, mPriv->contents) { if (content->name() == contentName) { return content; } } return CallContentPtr(); } /** * Request a new media content to be created to exchange the given type \a type * of media. * * This methods requires CallChannel::FeatureContents to be enabled. * * \return A PendingCallContent which will emit PendingCallContent::finished * when the call has finished. * \sa contentAdded(), contents(), contentsForType(), contentByName() */ PendingCallContent *CallChannel::requestContent(const QString &name, MediaStreamType type, MediaStreamDirection direction) { return new PendingCallContent(CallChannelPtr(this), name, type, direction); } /** * Return whether the local user has placed this channel on hold. * * This method requires CallChannel::FeatureHoldState to be enabled. * * \return The channel's local hold state. * \sa requestHold(), localHoldStateChanged() */ LocalHoldState CallChannel::localHoldState() const { if (!isReady(FeatureLocalHoldState)) { warning() << "CallChannel::localHoldState() used with FeatureLocalHoldState not ready"; } else if (!hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD)) { warning() << "CallChannel::localHoldStateReason() used with no hold interface"; } return (LocalHoldState) mPriv->localHoldState; } /** * Return the reason why localHoldState() changed to its current value. * * This method requires CallChannel::FeatureLocalHoldState to be enabled. * * \return The channel local hold state reason. * \sa requestHold(), localHoldStateChanged() */ LocalHoldStateReason CallChannel::localHoldStateReason() const { if (!isReady(FeatureLocalHoldState)) { warning() << "CallChannel::localHoldStateReason() used with FeatureLocalHoldState not ready"; } else if (!hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD)) { warning() << "CallChannel::localHoldStateReason() used with no hold interface"; } return (LocalHoldStateReason) mPriv->localHoldStateReason; } /** * Request that the channel be put on hold (be instructed not to send any media * streams to you) or be taken off hold. * * If the connection manager can immediately tell that the requested state * change could not possibly succeed, the resulting PendingOperation will fail * with error code #TP_QT_ERROR_NOT_AVAILABLE. * If the requested state is the same as the current state, the resulting * PendingOperation will finish successfully. * * Otherwise, the channel's local hold state will change to * Tp::LocalHoldStatePendingHold or Tp::LocalHoldStatePendingUnhold (as * appropriate), then the resulting PendingOperation will finish successfully. * * The eventual success or failure of the request is indicated by a subsequent * localHoldStateChanged() signal, changing the local hold state to * Tp::LocalHoldStateHeld or Tp::LocalHoldStateUnheld. * * If the channel has multiple streams, and the connection manager succeeds in * changing the hold state of one stream but fails to change the hold state of * another, it will attempt to revert all streams to their previous hold * states. * * If the channel does not support the #TP_QT_IFACE_CHANNEL_INTERFACE_HOLD * interface, the PendingOperation will fail with error code * #TP_QT_ERROR_NOT_IMPLEMENTED. * * \param hold A boolean indicating whether or not the channel should be on hold * \return A PendingOperation, which will emit PendingOperation::finished * when the request finishes. * \sa localHoldState(), localHoldStateReason(), localHoldStateChanged() */ PendingOperation *CallChannel::requestHold(bool hold) { if (!hasInterface(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD)) { warning() << "CallChannel::requestHold() used with no hold interface"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("CallChannel does not support hold interface"), CallChannelPtr(this)); } Client::ChannelInterfaceHoldInterface *holdInterface = interface(); return new PendingVoid(holdInterface->RequestHold(hold), CallChannelPtr(this)); } void CallChannel::gotMainProperties(PendingOperation *op) { if (op->isError()) { warning().nospace() << "CallInterface::requestAllProperties() failed with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, op->errorName(), op->errorMessage()); return; } debug() << "Got reply to CallInterface::requestAllProperties()"; PendingVariantMap *pvm = qobject_cast(op); Q_ASSERT(pvm); QVariantMap props = pvm->result(); mPriv->hardwareStreaming = qdbus_cast(props[QLatin1String("HardwareStreaming")]); mPriv->initialTransportType = qdbus_cast(props[QLatin1String("InitialTransport")]); mPriv->initialAudio = qdbus_cast(props[QLatin1String("InitialAudio")]); mPriv->initialVideo = qdbus_cast(props[QLatin1String("InitialVideo")]); mPriv->initialAudioName = qdbus_cast(props[QLatin1String("InitialAudioName")]); mPriv->initialVideoName = qdbus_cast(props[QLatin1String("InitialVideoName")]); mPriv->mutableContents = qdbus_cast(props[QLatin1String("MutableContents")]); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } void CallChannel::gotCallState(PendingOperation *op) { if (op->isError()) { warning().nospace() << "CallInterface::requestAllProperties() failed with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCallState, false, op->errorName(), op->errorMessage()); return; } debug() << "Got reply to CallInterface::requestAllProperties()"; PendingVariantMap *pvm = qobject_cast(op); Q_ASSERT(pvm); QVariantMap props = pvm->result(); mPriv->state = qdbus_cast(props[QLatin1String("CallState")]); mPriv->flags = qdbus_cast(props[QLatin1String("CallFlags")]); mPriv->stateReason = qdbus_cast(props[QLatin1String("CallStateReason")]); mPriv->stateDetails = qdbus_cast(props[QLatin1String("CallStateDetails")]); mPriv->readinessHelper->setIntrospectCompleted(FeatureCallState, true); } void CallChannel::onCallStateChanged(uint state, uint flags, const CallStateReason &stateReason, const QVariantMap &stateDetails) { if (mPriv->state == state && mPriv->flags == flags && mPriv->stateReason == stateReason && mPriv->stateDetails == stateDetails) { // nothing changed return; } uint oldState = mPriv->state; uint oldFlags = mPriv->flags; mPriv->state = state; mPriv->flags = flags; mPriv->stateReason = stateReason; mPriv->stateDetails = stateDetails; if (oldState != state) { emit callStateChanged((CallState) state); } if (oldFlags != flags) { emit callFlagsChanged((CallFlags) flags); } } void CallChannel::gotCallMembers(PendingOperation *op) { if (op->isError()) { warning().nospace() << "CallInterface::requestAllProperties() failed with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCallMembers, false, op->errorName(), op->errorMessage()); return; } debug() << "Got reply to CallInterface::requestAllProperties()"; PendingVariantMap *pvm = qobject_cast(op); Q_ASSERT(pvm); QVariantMap props = pvm->result(); HandleIdentifierMap ids = qdbus_cast(props[QLatin1String("MemberIdentifiers")]); CallMemberMap callMembers = qdbus_cast(props[QLatin1String("CallMembers")]); mPriv->callMembersChangedQueue.enqueue(Private::CallMembersChangedInfo::create( callMembers, ids, UIntList(), CallStateReason())); mPriv->processCallMembersChanged(); } void CallChannel::gotCallMembersContacts(PendingOperation *op) { PendingContacts *pc = qobject_cast(op); if (!pc->isValid()) { warning().nospace() << "Getting contacts failed with " << pc->errorName() << ":" << pc->errorMessage() << ", ignoring"; mPriv->currentCallMembersChangedInfo.clear(); mPriv->processCallMembersChanged(); return; } QHash removed; for (ContactSendingStateMap::const_iterator i = mPriv->currentCallMembersChangedInfo->updates.constBegin(); i != mPriv->currentCallMembersChangedInfo->updates.constEnd(); ++i) { mPriv->callMembers.insert(i.key(), i.value()); } foreach (const ContactPtr &contact, pc->contacts()) { mPriv->callMembersContacts.insert(contact->handle()[0], contact); } foreach (uint handle, mPriv->currentCallMembersChangedInfo->removed) { mPriv->callMembers.remove(handle); if (isReady(FeatureCallMembers) && mPriv->callMembersContacts.contains(handle)) { removed.insert(handle, mPriv->callMembersContacts[handle]); // make sure we don't have updates for removed contacts mPriv->currentCallMembersChangedInfo->updates.remove(handle); } mPriv->callMembersContacts.remove(handle); } foreach (uint handle, pc->invalidHandles()) { mPriv->callMembers.remove(handle); if (isReady(FeatureCallMembers) && mPriv->callMembersContacts.contains(handle)) { removed.insert(handle, mPriv->callMembersContacts[handle]); // make sure we don't have updates for invalid handles mPriv->currentCallMembersChangedInfo->updates.remove(handle); } mPriv->callMembersContacts.remove(handle); } if (isReady(FeatureCallMembers)) { QHash remoteMemberFlags; for (CallMemberMap::const_iterator i = mPriv->currentCallMembersChangedInfo->updates.constBegin(); i != mPriv->currentCallMembersChangedInfo->updates.constEnd(); ++i) { uint handle = i.key(); CallMemberFlags flags = (CallMemberFlags) i.value(); Q_ASSERT(mPriv->callMembersContacts.contains(handle)); remoteMemberFlags.insert(mPriv->callMembersContacts[handle], flags); mPriv->callMembers.insert(i.key(), i.value()); } if (!remoteMemberFlags.isEmpty()) { emit remoteMemberFlagsChanged(remoteMemberFlags, mPriv->currentCallMembersChangedInfo->reason); } if (!removed.isEmpty()) { emit remoteMembersRemoved(removed.values().toSet(), mPriv->currentCallMembersChangedInfo->reason); } } mPriv->currentCallMembersChangedInfo.clear(); mPriv->processCallMembersChanged(); } void CallChannel::onCallMembersChanged(const CallMemberMap &updates, const HandleIdentifierMap &identifiers, const UIntList &removed, const CallStateReason &reason) { if (updates.isEmpty() && removed.isEmpty()) { debug() << "Received Call::CallMembersChanged with 0 removals and updates, skipping it"; return; } debug() << "Received Call::CallMembersChanged with" << updates.size() << "updated and" << removed.size() << "removed"; mPriv->callMembersChangedQueue.enqueue( Private::CallMembersChangedInfo::create(updates, identifiers, removed, reason)); mPriv->processCallMembersChanged(); } void CallChannel::gotContents(PendingOperation *op) { if (op->isError()) { warning().nospace() << "CallInterface::requestPropertyContents() failed with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureContents, false, op->errorName(), op->errorMessage()); return; } debug() << "Got reply to CallInterface::requestPropertyContents()"; PendingVariant *pv = qobject_cast(op); Q_ASSERT(pv); ObjectPathList contentsPaths = qdbus_cast(pv->result()); if (contentsPaths.size() > 0) { foreach (const QDBusObjectPath &contentPath, contentsPaths) { CallContentPtr content = lookupContent(contentPath); if (!content) { addContent(contentPath); } } } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureContents, true); } } void CallChannel::onContentAdded(const QDBusObjectPath &contentPath) { debug() << "Received Call::ContentAdded for content" << contentPath.path(); if (lookupContent(contentPath)) { debug() << "Content already exists, ignoring"; return; } addContent(contentPath); } void CallChannel::onContentRemoved(const QDBusObjectPath &contentPath, const CallStateReason &reason) { debug() << "Received Call::ContentRemoved for content" << contentPath.path(); CallContentPtr content = lookupContent(contentPath); if (!content) { debug() << "Content does not exist, ignoring"; return; } bool incomplete = mPriv->incompleteContents.contains(content); if (incomplete) { mPriv->incompleteContents.removeOne(content); } else { mPriv->contents.removeOne(content); } if (isReady(FeatureContents) && !incomplete) { emit contentRemoved(content, reason); } // the content was added/removed before become ready if (!isReady(FeatureContents) && mPriv->contents.size() == 0 && mPriv->incompleteContents.size() == 0) { mPriv->readinessHelper->setIntrospectCompleted(FeatureContents, true); } } void CallChannel::onContentReady(PendingOperation *op) { PendingReady *pr = qobject_cast(op); CallContentPtr content = CallContentPtr::qObjectCast(pr->proxy()); if (op->isError()) { mPriv->incompleteContents.removeOne(content); if (!isReady(FeatureContents) && mPriv->incompleteContents.size() == 0) { // let's not fail because a content could not become ready mPriv->readinessHelper->setIntrospectCompleted(FeatureContents, true); } return; } // the content was removed before become ready if (!mPriv->incompleteContents.contains(content)) { if (!isReady(FeatureContents) && mPriv->incompleteContents.size() == 0) { mPriv->readinessHelper->setIntrospectCompleted(FeatureContents, true); } return; } mPriv->incompleteContents.removeOne(content); mPriv->contents.append(content); if (isReady(FeatureContents)) { emit contentAdded(content); } if (!isReady(FeatureContents) && mPriv->incompleteContents.size() == 0) { mPriv->readinessHelper->setIntrospectCompleted(FeatureContents, true); } } void CallChannel::gotLocalHoldState(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Call::Hold::GetHoldState() failed with " << reply.error().name() << ": " << reply.error().message(); debug() << "Ignoring error getting hold state and assuming we're not on hold"; onLocalHoldStateChanged(mPriv->localHoldState, mPriv->localHoldStateReason); watcher->deleteLater(); return; } debug() << "Got reply to Call::Hold::GetHoldState()"; onLocalHoldStateChanged(reply.argumentAt<0>(), reply.argumentAt<1>()); watcher->deleteLater(); } void CallChannel::onLocalHoldStateChanged(uint localHoldState, uint localHoldStateReason) { bool changed = false; if (mPriv->localHoldState != localHoldState || mPriv->localHoldStateReason != localHoldStateReason) { changed = true; } mPriv->localHoldState = localHoldState; mPriv->localHoldStateReason = localHoldStateReason; if (!isReady(FeatureLocalHoldState)) { mPriv->readinessHelper->setIntrospectCompleted(FeatureLocalHoldState, true); } else { if (changed) { emit localHoldStateChanged((LocalHoldState) mPriv->localHoldState, (LocalHoldStateReason) mPriv->localHoldStateReason); } } } CallContentPtr CallChannel::addContent(const QDBusObjectPath &contentPath) { CallContentPtr content = CallContentPtr( new CallContent(CallChannelPtr(this), contentPath)); mPriv->incompleteContents.append(content); connect(content->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContentReady(Tp::PendingOperation*))); return content; } CallContentPtr CallChannel::lookupContent(const QDBusObjectPath &contentPath) const { foreach (const CallContentPtr &content, mPriv->contents) { if (content->objectPath() == contentPath.path()) { return content; } } foreach (const CallContentPtr &content, mPriv->incompleteContents) { if (content->objectPath() == contentPath.path()) { return content; } } return CallContentPtr(); } /** * \fn void CallChannel::callStateChanged(Tp::CallState state); * * This signal is emitted when the value of callState() changes. * * \param state The new state. */ /** * \fn void CallChannel::callFlagsChanged(Tp::CallFlags flags); * * This signal is emitted when the value of callFlags() changes. * * \param flags The new flags. */ /** * \fn void CallChannel::remoteMemberFlagsChanged(const QHash &remoteMemberFlags, const Tp::CallStateReason &reason); * * This signal is emitted when the flags of members of the call change, * or when new members are added in the call. * * \param remoteMemberFlags A maping of all the call members whose flags were * changed to their new flags, and of all the new members of the call to their initial flags. * \param reason The reason for this change. */ /** * \fn void CallChannel::remoteMembersRemoved(const Tp::Contacts &remoteMembers, const Tp::CallStateReason &reason); * * This signal is emitted when remote members are removed from the call. * * \param remoteMembers The members that were removed. * \param reason The reason for this removal. */ /** * \fn void CallChannel::contentAdded(const Tp::CallContentPtr &content); * * This signal is emitted when a media content is added to this channel. * * \param content The media content that was added. * \sa contents(), contentsForType() */ /** * \fn void CallChannel::contentRemoved(const Tp::CallContentPtr &content, const Tp::CallStateReason &reason); * * This signal is emitted when a media content is removed from this channel. * * \param content The media content that was removed. * \param reason The reason for this removal. * \sa contents(), contentsForType() */ /** * \fn void CallChannel::localHoldStateChanged(Tp::LocalHoldState state, Tp::LocalHoldStateReason reason); * * This signal is emitted when the local hold state of this channel changes. * * \param state The new local hold state of this channel. * \param reason The reason why the change occurred. * \sa localHoldState(), localHoldStateReason() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/Types0000664000175000017500000000033512470405660016244 0ustar jrjr#ifndef _TelepathyQt_Types_HEADER_GUARD_ #define _TelepathyQt_Types_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AbstractProtocolInterface0000664000175000017500000000041512470405660022245 0ustar jrjr#ifndef _TelepathyQt_AbstractProtocolInterface_HEADER_GUARD_ #define _TelepathyQt_AbstractProtocolInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/DBusError0000664000175000017500000000035212470405660017006 0ustar jrjr#ifndef _TelepathyQt_DBusError_HEADER_GUARD_ #define _TelepathyQt_DBusError_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel-dispatch-operation.xml0000664000175000017500000000040512470405660023140 0ustar jrjr Channel Dispatch Operation interface telepathy-qt-0.9.6~git1/TelepathyQt/dbus-peer.xml0000664000175000017500000000063512470405660017630 0ustar jrjr D-Bus peer telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeServerTLSConnectionInterface0000664000175000017500000000044312470405660024765 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeServerTLSConnectionInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeServerTLSConnectionInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ClientInterfaceRequestsInterface0000664000175000017500000000042412470405660023553 0ustar jrjr#ifndef _TelepathyQt_ClientInterfaceRequestsInterface_HEADER_GUARD_ #define _TelepathyQt_ClientInterfaceRequestsInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/RoomListChannel0000664000175000017500000000037512470405660020205 0ustar jrjr#ifndef _TelepathyQt_RoomListChannel_HEADER_GUARD_ #define _TelepathyQt_RoomListChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/base-protocol.cpp0000664000175000017500000011705512470405660020502 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/base-protocol-internal.h" #include "TelepathyQt/_gen/base-protocol.moc.hpp" #include "TelepathyQt/_gen/base-protocol-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT BaseProtocol::Private { Private(BaseProtocol *parent, const QDBusConnection &dbusConnection, const QString &name) : parent(parent), name(name), adaptee(new BaseProtocol::Adaptee(dbusConnection, parent)) { } BaseProtocol *parent; QString name; BaseProtocol::Adaptee *adaptee; QHash interfaces; QStringList connInterfaces; ProtocolParameterList parameters; RequestableChannelClassSpecList rccSpecs; QString vcardField; QString englishName; QString iconName; QStringList authTypes; CreateConnectionCallback createConnectionCb; IdentifyAccountCallback identifyAccountCb; NormalizeContactCallback normalizeContactCb; }; BaseProtocol::Adaptee::Adaptee(const QDBusConnection &dbusConnection, BaseProtocol *protocol) : QObject(protocol), mProtocol(protocol) { (void) new Service::ProtocolAdaptor(dbusConnection, this, protocol->dbusObject()); } BaseProtocol::Adaptee::~Adaptee() { } QStringList BaseProtocol::Adaptee::interfaces() const { QStringList ret; foreach (const AbstractProtocolInterfacePtr &iface, mProtocol->interfaces()) { ret << iface->interfaceName(); } return ret; } QStringList BaseProtocol::Adaptee::connectionInterfaces() const { return mProtocol->connectionInterfaces(); } ParamSpecList BaseProtocol::Adaptee::parameters() const { ParamSpecList ret; foreach (const ProtocolParameter ¶m, mProtocol->parameters()) { ParamSpec paramSpec = param.bareParameter(); if (!(paramSpec.flags & ConnMgrParamFlagHasDefault)) { // we cannot pass QVariant::Invalid over D-Bus, lets build a dummy value // that should be ignored according to the spec paramSpec.defaultValue = QDBusVariant( parseValueWithDBusSignature(QString(), paramSpec.signature)); } ret << paramSpec; } return ret; } RequestableChannelClassList BaseProtocol::Adaptee::requestableChannelClasses() const { return mProtocol->requestableChannelClasses().bareClasses(); } QString BaseProtocol::Adaptee::vcardField() const { return mProtocol->vcardField(); } QString BaseProtocol::Adaptee::englishName() const { return mProtocol->englishName(); } QString BaseProtocol::Adaptee::icon() const { return mProtocol->iconName(); } QStringList BaseProtocol::Adaptee::authenticationTypes() const { return mProtocol->authenticationTypes(); } void BaseProtocol::Adaptee::identifyAccount(const QVariantMap ¶meters, const Tp::Service::ProtocolAdaptor::IdentifyAccountContextPtr &context) { DBusError error; QString accountId; accountId = mProtocol->identifyAccount(parameters, &error); if (accountId.isEmpty()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(accountId); } void BaseProtocol::Adaptee::normalizeContact(const QString &contactId, const Tp::Service::ProtocolAdaptor::NormalizeContactContextPtr &context) { DBusError error; QString normalizedContactId; normalizedContactId = mProtocol->normalizeContact(contactId, &error); if (normalizedContactId.isEmpty()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(normalizedContactId); } /** * \class BaseProtocol * \ingroup servicecm * \headerfile TelepathyQt/base-protocol.h * * \brief Base class for protocol implementations. * * A Protocol is a D-Bus object that implements an IM protocol (for instance, jabber or msn). * The BaseProtocol class provides an easy way to implement a Protocol D-Bus object, * by providing the basic functionality itself and allowing you to extend it by setting * the appropriate properties and callbacks. * * A BaseProtocol instance cannot be registered by itself on the bus. You should add it * to a BaseConnectionManager instance using BaseConnectionManager::addProtocol(). When * the BaseConnectionManager is registered on the bus, all the BaseProtocol instances * will also be registered. */ /** * Constructs a new BaseProtocol object. * * \param dbusConnection The D-Bus connection to use. * \param name The name of this protocol. */ BaseProtocol::BaseProtocol(const QDBusConnection &dbusConnection, const QString &name) : DBusService(dbusConnection), mPriv(new Private(this, dbusConnection, name)) { } /** * Class destructor. */ BaseProtocol::~BaseProtocol() { delete mPriv; } /** * Return the protocol's name, as given on the constructor. * * \return The protocol's name. */ QString BaseProtocol::name() const { return mPriv->name; } /** * Return the immutable properties of this protocol object. * * Immutable properties cannot change after the object has been registered * on the bus with registerObject(). * * \return The immutable properties of this protocol object. */ QVariantMap BaseProtocol::immutableProperties() const { QVariantMap ret; foreach (const AbstractProtocolInterfacePtr &iface, mPriv->interfaces) { ret.unite(iface->immutableProperties()); } ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".Interfaces"), QVariant::fromValue(mPriv->adaptee->interfaces())); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".Parameters"), QVariant::fromValue(mPriv->adaptee->parameters())); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".ConnectionInterfaces"), QVariant::fromValue(mPriv->adaptee->connectionInterfaces())); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".RequestableChannelClasses"), QVariant::fromValue(mPriv->adaptee->requestableChannelClasses())); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".VCardField"), QVariant::fromValue(mPriv->adaptee->vcardField())); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".EnglishName"), QVariant::fromValue(mPriv->adaptee->englishName())); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".Icon"), QVariant::fromValue(mPriv->adaptee->icon())); ret.insert(TP_QT_IFACE_PROTOCOL + QLatin1String(".AuthenticationTypes"), QVariant::fromValue(mPriv->adaptee->authenticationTypes())); return ret; } /** * Return the list of interface names that have been set with * setConnectionInterfaces(). * * This list is exposed as the ConnectionInterfaces property of * this Protocol object on the bus and represents interface names * that might be in the Interfaces property of a Connection to this protocol. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \return The list of interface names that have been set with * setConnectionInterfaces(). * \sa setConnectionInterfaces() */ QStringList BaseProtocol::connectionInterfaces() const { return mPriv->connInterfaces; } /** * Set the interface names that may appear on Connection objects of * this protocol. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param connInterfaces The list of interface names to set. * \sa connectionInterfaces() */ void BaseProtocol::setConnectionInterfaces(const QStringList &connInterfaces) { if (isRegistered()) { warning() << "BaseProtocol::setConnectionInterfaces: cannot change property after " "registration, immutable property"; return; } mPriv->connInterfaces = connInterfaces; } /** * Return the list of parameters that have been set with setParameters(). * * This list is exposed as the Parameters property of this Protocol object * on the bus and represents the parameters which may be specified in the * Parameters property of an Account for this protocol. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \return The list of parameters that have been set with setParameters(). * \sa setParameters() */ ProtocolParameterList BaseProtocol::parameters() const { return mPriv->parameters; } /** * Set the parameters that may be specified in the Parameters property * of an Account for this protocol. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param parameters The list of parameters to set. * \sa parameters() */ void BaseProtocol::setParameters(const ProtocolParameterList ¶meters) { if (isRegistered()) { warning() << "BaseProtocol::setParameters: cannot change property after " "registration, immutable property"; return; } mPriv->parameters = parameters; } /** * Return the list of requestable channel classes that have been set * with setRequestableChannelClasses(). * * This list is exposed as the RequestableChannelClasses property of * this Protocol object on the bus and represents the channel classes * which might be requestable from a Connection to this protocol. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \returns The list of requestable channel classes that have been set * with setRequestableChannelClasses() * \sa setRequestableChannelClasses() */ RequestableChannelClassSpecList BaseProtocol::requestableChannelClasses() const { return mPriv->rccSpecs; } /** * Set the channel classes which might be requestable from a Connection * to this protocol. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param rccSpecs The list of requestable channel classes to set. * \sa requestableChannelClasses() */ void BaseProtocol::setRequestableChannelClasses(const RequestableChannelClassSpecList &rccSpecs) { if (isRegistered()) { warning() << "BaseProtocol::setRequestableChannelClasses: cannot change property after " "registration, immutable property"; return; } mPriv->rccSpecs = rccSpecs; } /** * Return the name of the vcard field that has been set with setVCardField(). * * This is exposed as the VCardField property of this Protocol object on * the bus and represents the name of the most common vcard field used for * this protocol's contact identifiers, normalized to lower case. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \return The name of the vcard field that has been set with setVCardField(). * \sa setVCardField() */ QString BaseProtocol::vcardField() const { return mPriv->vcardField; } /** * Set the name of the most common vcard field used for * this protocol's contact identifiers, normalized to lower case. * * For example, this would be x-jabber for Jabber/XMPP * (including Google Talk), or tel for the PSTN. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param vcardField The name of the vcard field to set. * \sa vcardField() */ void BaseProtocol::setVCardField(const QString &vcardField) { if (isRegistered()) { warning() << "BaseProtocol::setVCardField: cannot change property after " "registration, immutable property"; return; } mPriv->vcardField = vcardField; } /** * Return the name that has been set with setEnglishName(). * * This is exposed as the EnglishName property of this Protocol object on * the bus and represents the name of the protocol in a form suitable * for display to users, such as "AIM" or "Yahoo!". * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \return The name that has been set with setEnglishName(). * \sa setEnglishName() */ QString BaseProtocol::englishName() const { return mPriv->englishName; } /** * Set the name of the protocol in a form suitable for display to users, * such as "AIM" or "Yahoo!". * * This string should be in the C (english) locale. Clients are expected * to lookup a translation on their own translation catalogs and fall back * to this name if they have no translation for it. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param englishName The name to set. * \sa englishName() */ void BaseProtocol::setEnglishName(const QString &englishName) { if (isRegistered()) { warning() << "BaseProtocol::setEnglishName: cannot change property after " "registration, immutable property"; return; } mPriv->englishName = englishName; } /** * Return the icon name that has been set with setIconName(). * * This is exposed as the Icon property of this Protocol object on * the bus and represents the name of an icon in the system's icon * theme suitable for this protocol, such as "im-msn". * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \return The icon name set with setIconName(). * \sa setIconName() */ QString BaseProtocol::iconName() const { return mPriv->iconName; } /** * Set the name of an icon in the system's icon theme suitable * for this protocol, such as "im-msn". * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param iconName The icon name to set. * \sa iconName() */ void BaseProtocol::setIconName(const QString &iconName) { if (isRegistered()) { warning() << "BaseProtocol::setIconName: cannot change property after " "registration, immutable property"; return; } mPriv->iconName = iconName; } /** * Return the list of interfaces that have been set with setAuthenticationTypes(). * * This is exposed as the AuthenticationTypes property of this Protocol object * on the bus and represents a list of D-Bus interfaces which provide * information as to what kind of authentication channels can possibly appear * before the connection reaches the CONNECTED state. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \return The list of authentication types that have been * set with setAuthenticationTypes(). * \sa setAuthenticationTypes() */ QStringList BaseProtocol::authenticationTypes() const { return mPriv->authTypes; } /** * Set a list of D-Bus interfaces which provide information as to * what kind of authentication channels can possibly appear before * the connection reaches the CONNECTED state. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param authenticationTypes The list of interfaces to set. * \sa authenticationTypes() */ void BaseProtocol::setAuthenticationTypes(const QStringList &authenticationTypes) { if (isRegistered()) { warning() << "BaseProtocol::setAuthenticationTypes: cannot change property after " "registration, immutable property"; return; } mPriv->authTypes = authenticationTypes; } /** * Set a callback that will be called to create a new connection, when this * has been requested by a client. * * \param cb The callback to set. * \sa createConnection() */ void BaseProtocol::setCreateConnectionCallback(const CreateConnectionCallback &cb) { mPriv->createConnectionCb = cb; } /** * Create a new connection object by calling the callback that has been set * with setCreateConnectionCallback(). * * \param parameters The connection parameters. * \param error A pointer to a DBusError instance where any possible error * will be stored. * \return A pointer to the new connection, or a null BaseConnectionPtr if * no connection could be created, in which case \a error will contain an * appropriate error. * \sa setCreateConnectionCallback() */ BaseConnectionPtr BaseProtocol::createConnection(const QVariantMap ¶meters, Tp::DBusError *error) { if (!mPriv->createConnectionCb.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return BaseConnectionPtr(); } return mPriv->createConnectionCb(parameters, error); } /** * Set a callback that will be called from a client to identify an account. * * This callback will be called when the IdentifyAccount method on the Protocol * D-Bus object has been called. * * \param cb The callback to set. * \sa identifyAccount() */ void BaseProtocol::setIdentifyAccountCallback(const IdentifyAccountCallback &cb) { mPriv->identifyAccountCb = cb; } /** * Return a string which uniquely identifies the account to which * the given parameters would connect, by calling the callback that * has been set with setIdentifyAccountCallback(). * * \param parameters The connection parameters, as they would * be provided to createConnection(). * \param error A pointer to a DBusError instance where any possible error * will be stored. * \return A string which uniquely identifies the account to which * the given parameters would connect, or an empty string if no callback * to create this string has been set with setIdentifyAccountCallback(). * \sa setIdentifyAccountCallback() */ QString BaseProtocol::identifyAccount(const QVariantMap ¶meters, Tp::DBusError *error) { if (!mPriv->identifyAccountCb.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return QString(); } return mPriv->identifyAccountCb(parameters, error); } /** * Set a callback that will be called from a client to normalize a contact id. * * \param cb The callback to set. * \sa normalizeContact() */ void BaseProtocol::setNormalizeContactCallback(const NormalizeContactCallback &cb) { mPriv->normalizeContactCb = cb; } /** * Return a normalized version of the given \a contactId, by calling the callback * that has been set with setNormalizeContactCallback(). * * \param contactId The contact ID to normalize. * \param error A pointer to a DBusError instance where any possible error * will be stored. * \return A normalized version of the given \a contactId, or an empty string * if no callback to do the normalization has been set with setNormalizeContactCallback(). * \sa setNormalizeContactCallback() */ QString BaseProtocol::normalizeContact(const QString &contactId, Tp::DBusError *error) { if (!mPriv->normalizeContactCb.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return QString(); } return mPriv->normalizeContactCb(contactId, error); } /** * Return a list of interfaces that have been plugged into this Protocol * D-Bus object with plugInterface(). * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \return A list containing all the Protocol interface implementation objects. * \sa plugInterface(), interface() */ QList BaseProtocol::interfaces() const { return mPriv->interfaces.values(); } /** * Return a pointer to the interface with the given name. * * \param interfaceName The D-Bus name of the interface, * ex. TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING. * \return A pointer to the AbstractProtocolInterface object that implements * the D-Bus interface with the given name, or a null pointer if such an interface * has not been plugged into this object. * \sa plugInterface(), interfaces() */ AbstractProtocolInterfacePtr BaseProtocol::interface(const QString &interfaceName) const { return mPriv->interfaces.value(interfaceName); } /** * Plug a new interface into this Protocol D-Bus object. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param interface An AbstractProtocolInterface instance that implements * the interface that is to be plugged. * \return \c true on success or \c false otherwise * \sa interfaces(), interface() */ bool BaseProtocol::plugInterface(const AbstractProtocolInterfacePtr &interface) { if (isRegistered()) { warning() << "Unable to plug protocol interface " << interface->interfaceName() << "- protocol already registered"; return false; } if (interface->isRegistered()) { warning() << "Unable to plug protocol interface" << interface->interfaceName() << "- interface already registered"; return false; } if (mPriv->interfaces.contains(interface->interfaceName())) { warning() << "Unable to plug protocol interface" << interface->interfaceName() << "- another interface with same name already plugged"; return false; } debug() << "Interface" << interface->interfaceName() << "plugged"; mPriv->interfaces.insert(interface->interfaceName(), interface); return true; } /** * Reimplemented from DBusService. */ bool BaseProtocol::registerObject(const QString &busName, const QString &objectPath, DBusError *error) { if (isRegistered()) { return true; } foreach (const AbstractProtocolInterfacePtr &iface, mPriv->interfaces) { if (!iface->registerInterface(dbusObject())) { // lets not fail if an optional interface fails registering, lets warn only warning() << "Unable to register interface" << iface->interfaceName() << "for protocol" << mPriv->name; } } return DBusService::registerObject(busName, objectPath, error); } /** * \class AbstractProtocolInterface * \ingroup servicecm * \headerfile TelepathyQt/base-protocol.h * * \brief Base class for all the Protocol object interface implementations. */ // AbstractProtocolInterface AbstractProtocolInterface::AbstractProtocolInterface(const QString &interfaceName) : AbstractDBusServiceInterface(interfaceName) { } AbstractProtocolInterface::~AbstractProtocolInterface() { } // Proto.I.Addressing BaseProtocolAddressingInterface::Adaptee::Adaptee(BaseProtocolAddressingInterface *interface) : QObject(interface), mInterface(interface) { } BaseProtocolAddressingInterface::Adaptee::~Adaptee() { } QStringList BaseProtocolAddressingInterface::Adaptee::addressableVCardFields() const { return mInterface->addressableVCardFields(); } QStringList BaseProtocolAddressingInterface::Adaptee::addressableURISchemes() const { return mInterface->addressableUriSchemes(); } void BaseProtocolAddressingInterface::Adaptee::normalizeVCardAddress(const QString& vcardField, const QString& vcardAddress, const Tp::Service::ProtocolInterfaceAddressingAdaptor::NormalizeVCardAddressContextPtr &context) { DBusError error; QString normalizedAddress; normalizedAddress = mInterface->normalizeVCardAddress(vcardField, vcardAddress, &error); if (normalizedAddress.isEmpty()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(normalizedAddress); } void BaseProtocolAddressingInterface::Adaptee::normalizeContactURI(const QString& uri, const Tp::Service::ProtocolInterfaceAddressingAdaptor::NormalizeContactURIContextPtr &context) { DBusError error; QString normalizedUri; normalizedUri = mInterface->normalizeContactUri(uri, &error); if (normalizedUri.isEmpty()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(normalizedUri); } struct TP_QT_NO_EXPORT BaseProtocolAddressingInterface::Private { Private(BaseProtocolAddressingInterface *parent) : adaptee(new BaseProtocolAddressingInterface::Adaptee(parent)) { } BaseProtocolAddressingInterface::Adaptee *adaptee; QStringList addressableVCardFields; QStringList addressableUriSchemes; NormalizeVCardAddressCallback normalizeVCardAddressCb; NormalizeContactUriCallback normalizeContactUriCb; }; /** * \class BaseProtocolAddressingInterface * \ingroup servicecm * \headerfile TelepathyQt/base-protocol.h * * \brief Base class for implementations of Protocol.Interface.Addressing */ /** * Class constructor. */ BaseProtocolAddressingInterface::BaseProtocolAddressingInterface() : AbstractProtocolInterface(TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING), mPriv(new Private(this)) { } /** * Class destructor. */ BaseProtocolAddressingInterface::~BaseProtocolAddressingInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseProtocolAddressingInterface::immutableProperties() const { // no immutable property return QVariantMap(); } /** * Return the list of addressable vcard fields that have been set with * setAddressableVCardFields(). * * This list is exposed as the AddressableVCardFields property of this * interface on the bus and represents the vcard fields that can be used * to request a contact for this protocol, normalized to lower case. * * \return The list of addressable vcard fields that have been set with * setAddressableVCardFields(). * \sa setAddressableVCardFields() */ QStringList BaseProtocolAddressingInterface::addressableVCardFields() const { return mPriv->addressableVCardFields; } /** * Set the list of vcard fields that can be used to request a contact for this protocol. * * All the field names should be normalized to lower case. * * \param vcardFields The list of vcard fields to set. * \sa addressableVCardFields() */ void BaseProtocolAddressingInterface::setAddressableVCardFields(const QStringList &vcardFields) { mPriv->addressableVCardFields = vcardFields; } /** * Return the list of URI schemes that have been set with * setAddressableUriSchemes(). * * This list is exposed as the AddressableURISchemes property of this interface * on the bus and represents the URI schemes that are supported by this * protocol, like "tel" or "sip". * * \return The list of addressable URI schemes that have been set with * setAddressableUriSchemes(). * \sa setAddressableUriSchemes() */ QStringList BaseProtocolAddressingInterface::addressableUriSchemes() const { return mPriv->addressableUriSchemes; } /** * Set the list of URI schemes that are supported by this protocol. * * \param uriSchemes The list of URI schemes to set. * \sa addressableUriSchemes() */ void BaseProtocolAddressingInterface::setAddressableUriSchemes(const QStringList &uriSchemes) { mPriv->addressableUriSchemes = uriSchemes; } /** * Set a callback that will be called from a client to normalize a given * vcard address. * * This callback will be called when the NormalizeVCardAddress method * on the Protocol.Interface.Addressing D-Bus interface has been called. * * \param cb The callback to set. * \sa normalizeVCardAddress() */ void BaseProtocolAddressingInterface::setNormalizeVCardAddressCallback( const NormalizeVCardAddressCallback &cb) { mPriv->normalizeVCardAddressCb = cb; } /** * Return a normalized version of the given \a vcardAddress, which corresponds * to the given \a vcardField, by calling the callback that has been set * with setNormalizeVCardAddressCallback(). * * \param vcardField The vcard field of the address we are normalizing. * \param vcardAddress The address to normalize, which is assumed to belong to a contact. * \param error A pointer to a DBusError instance where any possible error * will be stored. * \return A normalized version of the given \a vcardAddress, or an empty * string if no callback to do the normalization has been set with * setNormalizeVCardAddressCallback(). * \sa setNormalizeVCardAddressCallback() */ QString BaseProtocolAddressingInterface::normalizeVCardAddress(const QString &vcardField, const QString &vcardAddress, DBusError *error) { if (!mPriv->normalizeVCardAddressCb.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return QString(); } return mPriv->normalizeVCardAddressCb(vcardField, vcardAddress, error); } /** * Set a callback that will be called from a client to normalize a given contact URI. * * This callback will be called when the NormalizeContactURI method * on the Protocol.Interface.Addressing D-Bus interface has been called. * * \param cb The callback to set. * \sa normalizeContactUri() */ void BaseProtocolAddressingInterface::setNormalizeContactUriCallback( const NormalizeContactUriCallback &cb) { mPriv->normalizeContactUriCb = cb; } /** * Return a normalized version of the given contact URI, \a uri, by calling * the callback that has been set with setNormalizeContactUriCallback(). * * \param uri The contact URI to normalize. * \param error A pointer to a DBusError instance where any possible error * will be stored. * \return A normalized version of the given \a uri, or an empty string if no * callback to do the normalization has been set with setNormalizeContactUriCallback(). * \sa setNormalizeContactUriCallback() */ QString BaseProtocolAddressingInterface::normalizeContactUri(const QString &uri, DBusError *error) { if (!mPriv->normalizeContactUriCb.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return QString(); } return mPriv->normalizeContactUriCb(uri, error); } void BaseProtocolAddressingInterface::createAdaptor() { (void) new Service::ProtocolInterfaceAddressingAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } // Proto.I.Avatars BaseProtocolAvatarsInterface::Adaptee::Adaptee(BaseProtocolAvatarsInterface *interface) : QObject(interface), mInterface(interface) { } BaseProtocolAvatarsInterface::Adaptee::~Adaptee() { } QStringList BaseProtocolAvatarsInterface::Adaptee::supportedAvatarMIMETypes() const { return mInterface->avatarDetails().supportedMimeTypes(); } uint BaseProtocolAvatarsInterface::Adaptee::minimumAvatarHeight() const { return mInterface->avatarDetails().minimumHeight(); } uint BaseProtocolAvatarsInterface::Adaptee::minimumAvatarWidth() const { return mInterface->avatarDetails().minimumWidth(); } uint BaseProtocolAvatarsInterface::Adaptee::recommendedAvatarHeight() const { return mInterface->avatarDetails().recommendedHeight(); } uint BaseProtocolAvatarsInterface::Adaptee::recommendedAvatarWidth() const { return mInterface->avatarDetails().recommendedWidth(); } uint BaseProtocolAvatarsInterface::Adaptee::maximumAvatarHeight() const { return mInterface->avatarDetails().maximumHeight(); } uint BaseProtocolAvatarsInterface::Adaptee::maximumAvatarWidth() const { return mInterface->avatarDetails().maximumWidth(); } uint BaseProtocolAvatarsInterface::Adaptee::maximumAvatarBytes() const { return mInterface->avatarDetails().maximumBytes(); } struct TP_QT_NO_EXPORT BaseProtocolAvatarsInterface::Private { Private(BaseProtocolAvatarsInterface *parent) : adaptee(new BaseProtocolAvatarsInterface::Adaptee(parent)) { } BaseProtocolAvatarsInterface::Adaptee *adaptee; AvatarSpec avatarDetails; }; /** * \class BaseProtocolAvatarsInterface * \ingroup servicecm * \headerfile TelepathyQt/base-protocol.h * * \brief Base class for implementations of Protocol.Interface.Avatars */ /** * Class constructor. */ BaseProtocolAvatarsInterface::BaseProtocolAvatarsInterface() : AbstractProtocolInterface(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS), mPriv(new Private(this)) { } /** * Class destructor. */ BaseProtocolAvatarsInterface::~BaseProtocolAvatarsInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseProtocolAvatarsInterface::immutableProperties() const { QVariantMap ret; ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".SupportedAvatarMIMETypes"), QVariant::fromValue(mPriv->adaptee->supportedAvatarMIMETypes())); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarHeight"), QVariant::fromValue(mPriv->adaptee->minimumAvatarHeight())); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MinimumAvatarWidth"), QVariant::fromValue(mPriv->adaptee->minimumAvatarWidth())); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarHeight"), QVariant::fromValue(mPriv->adaptee->recommendedAvatarHeight())); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".RecommendedAvatarWidth"), QVariant::fromValue(mPriv->adaptee->recommendedAvatarWidth())); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarHeight"), QVariant::fromValue(mPriv->adaptee->maximumAvatarHeight())); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarWidth"), QVariant::fromValue(mPriv->adaptee->maximumAvatarWidth())); ret.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_AVATARS + QLatin1String(".MaximumAvatarBytes"), QVariant::fromValue(mPriv->adaptee->maximumAvatarBytes())); return ret; } /** * Return the AvatarSpec that has been set with setAvatarDetails(). * * The contents of this AvatarSpec are exposed as the various properties * of this interface on the bus and represent the expected values of the * Connection.Interface.Avatars properties on connections of this protocol. * * This property is immutable and cannot change after this interface * has been registered on an object on the bus with registerInterface(). * * \return The AvatarSpec that has been set with setAvatarDetails(). * \sa setAvatarDetails() */ AvatarSpec BaseProtocolAvatarsInterface::avatarDetails() const { return mPriv->avatarDetails; } /** * Set the avatar details that will be exposed on the properties of this * interface on the bus. * * This property is immutable and cannot change after this interface * has been registered on an object on the bus with registerInterface(). * * \param details The details to set. * \sa avatarDetails() */ void BaseProtocolAvatarsInterface::setAvatarDetails(const AvatarSpec &details) { if (isRegistered()) { warning() << "BaseProtocolAvatarsInterface::setAvatarDetails: cannot change property after " "registration, immutable property"; return; } mPriv->avatarDetails = details; } void BaseProtocolAvatarsInterface::createAdaptor() { (void) new Service::ProtocolInterfaceAvatarsAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } // Proto.I.Presence BaseProtocolPresenceInterface::Adaptee::Adaptee(BaseProtocolPresenceInterface *interface) : QObject(interface), mInterface(interface) { } BaseProtocolPresenceInterface::Adaptee::~Adaptee() { } SimpleStatusSpecMap BaseProtocolPresenceInterface::Adaptee::statuses() const { return mInterface->statuses().bareSpecs(); } struct TP_QT_NO_EXPORT BaseProtocolPresenceInterface::Private { Private(BaseProtocolPresenceInterface *parent) : adaptee(new BaseProtocolPresenceInterface::Adaptee(parent)) { } BaseProtocolPresenceInterface::Adaptee *adaptee; PresenceSpecList statuses; }; /** * \class BaseProtocolPresenceInterface * \ingroup servicecm * \headerfile TelepathyQt/base-protocol.h * * \brief Base class for implementations of Protocol.Interface.Presence */ /** * Class constructor. */ BaseProtocolPresenceInterface::BaseProtocolPresenceInterface() : AbstractProtocolInterface(TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE), mPriv(new Private(this)) { } /** * Class destructor. */ BaseProtocolPresenceInterface::~BaseProtocolPresenceInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseProtocolPresenceInterface::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_PROTOCOL_INTERFACE_PRESENCE + QLatin1String(".Statuses"), QVariant::fromValue(mPriv->adaptee->statuses())); return map; } /** * Return the list of presence statuses that have been set with setStatuses(). * * This list is exposed as the Statuses property of this interface on the bus * and represents the statuses that might appear in the * Connection.Interface.SimplePresence.Statuses property on a connection to * this protocol that supports SimplePresence. * * This property is immutable and cannot change after this interface * has been registered on an object on the bus with registerInterface(). * * \return The list of presence statuses that have been set with setStatuses(). * \sa setStatuses() */ PresenceSpecList BaseProtocolPresenceInterface::statuses() const { return mPriv->statuses; } /** * Set the list of statuses that might appear in the * Connection.Interface.SimplePresence.Statuses property on a connection to * this protocol that supports SimplePresence. * * This property is immutable and cannot change after this interface * has been registered on an object on the bus with registerInterface(). * * \param statuses The statuses list to set. * \sa statuses() */ void BaseProtocolPresenceInterface::setStatuses(const PresenceSpecList &statuses) { if (isRegistered()) { warning() << "BaseProtocolPresenceInterface::setStatuses: cannot change property after " "registration, immutable property"; return; } mPriv->statuses = statuses; } void BaseProtocolPresenceInterface::createAdaptor() { (void) new Service::ProtocolInterfacePresenceAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } } telepathy-qt-0.9.6~git1/TelepathyQt/test-backdoors.cpp0000664000175000017500000000315012470405660020643 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include namespace Tp { void TestBackdoors::invalidateProxy(DBusProxy *proxy, const QString &reason, const QString &message) { Q_ASSERT(proxy != 0); Q_ASSERT(proxy->isValid()); proxy->invalidate(reason, message); } ConnectionCapabilities TestBackdoors::createConnectionCapabilities( const RequestableChannelClassSpecList &rccSpecs) { return ConnectionCapabilities(rccSpecs); } ContactCapabilities TestBackdoors::createContactCapabilities( const RequestableChannelClassSpecList &rccSpecs, bool specificToContact) { return ContactCapabilities(rccSpecs, specificToContact); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/method-invocation-context.h0000664000175000017500000001277312470405660022510 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_method_invocation_context_h_HEADER_GUARD_ #define _TelepathyQt_method_invocation_context_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { #ifndef DOXYGEN_SHOULD_SKIP_THIS namespace MethodInvocationContextTypes { struct Nil { }; template struct Select { typedef Select Next; typedef typename Next::Type Type; }; template struct Select<0, T1, T2, T3, T4, T5, T6, T7, T8> { typedef T1 Type; }; template struct ForEach { typedef ForEach Next; enum { Total = Next::Total + 1 }; }; template<> struct ForEach { enum { Total = 0 }; }; } #endif /* DOXYGEN_SHOULD_SKIP_THIS */ template class MethodInvocationContext : public RefCounted { #ifndef DOXYGEN_SHOULD_SKIP_THIS template struct Select : MethodInvocationContextTypes::Select { }; typedef MethodInvocationContextTypes::ForEach ForEach; enum { Count = ForEach::Total }; #endif /* DOXYGEN_SHOULD_SKIP_THIS */ public: MethodInvocationContext(const QDBusConnection &bus, const QDBusMessage &message) : mBus(bus), mMessage(message), mFinished(false) { mMessage.setDelayedReply(true); } virtual ~MethodInvocationContext() { if (!mFinished) { setFinishedWithError(QString(), QString()); } } bool isFinished() const { return mFinished; } bool isError() const { return !mErrorName.isEmpty(); } QString errorName() const { return mErrorName; } QString errorMessage() const { return mErrorMessage; } void setFinished(const T1 &t1 = T1(), const T2 &t2 = T2(), const T3 &t3 = T3(), const T4 &t4 = T4(), const T5 &t5 = T5(), const T6 &t6 = T6(), const T7 &t7 = T7(), const T8 &t8 = T8()) { if (mFinished) { return; } mFinished = true; setReplyValue(0, qVariantFromValue(t1)); setReplyValue(1, qVariantFromValue(t2)); setReplyValue(2, qVariantFromValue(t3)); setReplyValue(3, qVariantFromValue(t4)); setReplyValue(4, qVariantFromValue(t5)); setReplyValue(5, qVariantFromValue(t6)); setReplyValue(6, qVariantFromValue(t7)); setReplyValue(7, qVariantFromValue(t8)); if (mReply.isEmpty()) { mBus.send(mMessage.createReply()); } else { mBus.send(mMessage.createReply(mReply)); } onFinished(); } void setFinishedWithError(const QString &errorName, const QString &errorMessage) { if (mFinished) { return; } mFinished = true; if (errorName.isEmpty()) { mErrorName = QLatin1String("org.freedesktop.Telepathy.Qt.ErrorHandlingError"); } else { mErrorName = errorName; } mErrorMessage = errorMessage; mBus.send(mMessage.createErrorReply(mErrorName, mErrorMessage)); onFinished(); } template inline typename Select::Type argumentAt() const { Q_ASSERT(Index >= 0 && Index < Count); return qdbus_cast::Type>(mReply.value(Index)); } protected: virtual void onFinished() {} private: Q_DISABLE_COPY(MethodInvocationContext) void setReplyValue(int index, const QVariant &value) { if (index >= Count) { return; } mReply.insert(index, value); } QDBusConnection mBus; QDBusMessage mMessage; bool mFinished; QList mReply; QString mErrorName; QString mErrorMessage; }; } // Tp Q_DECLARE_METATYPE(Tp::MethodInvocationContextTypes::Nil) #endif telepathy-qt-0.9.6~git1/TelepathyQt/TelepathyQt.pc.in0000664000175000017500000000152412470405660020413 0ustar jrjrprefix=${CMAKE_INSTALL_PREFIX} exec_prefix=${CMAKE_INSTALL_PREFIX} libdir=${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR} includedir=${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR} Name: TelepathyQt${QT_VERSION_MAJOR} Description: Qt utility library for the Telepathy framework Version: ${PACKAGE_VERSION} Requires.private: Qt${QT_VERSION_PC}Core >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Core < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}DBus >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}DBus < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}Network >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Network < ${QT_MAX_VERSION}, Qt${QT_VERSION_PC}Xml >= ${QT_MIN_VERSION}, Qt${QT_VERSION_PC}Xml < ${QT_MAX_VERSION} Libs: -L${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR} -ltelepathy-qt${QT_VERSION_MAJOR} Cflags: -I${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR}/telepathy-qt${QT_VERSION_MAJOR} telepathy-qt-0.9.6~git1/TelepathyQt/CallContentInterfaceVideoControlInterface0000664000175000017500000000045412470405660025342 0ustar jrjr#ifndef _TelepathyQt_CallContentInterfaceVideoControlInterface_HEADER_GUARD_ #define _TelepathyQt_CallContentInterfaceVideoControlInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/callbacks.h0000664000175000017500000003456612470405660017322 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_callbacks_h_HEADER_GUARD_ #define _TelepathyQt_callbacks_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { struct TP_QT_EXPORT AbstractFunctorCaller { typedef void *(*HookType)(void*); AbstractFunctorCaller(HookType invokeMethodHook) : invokeMethodHook(invokeMethodHook) {} virtual ~AbstractFunctorCaller() {} virtual AbstractFunctorCaller *clone() const = 0; HookType invokeMethodHook; private: AbstractFunctorCaller(const AbstractFunctorCaller &other); AbstractFunctorCaller &operator=(const AbstractFunctorCaller &other); }; template struct BaseFunctorCaller : public AbstractFunctorCaller { BaseFunctorCaller(const Functor &functor, AbstractFunctorCaller::HookType invokeMethodHook) : AbstractFunctorCaller(invokeMethodHook), functor(functor) {} virtual ~BaseFunctorCaller() {} virtual AbstractFunctorCaller *clone() const { return new T(functor); } Functor functor; }; struct TP_QT_EXPORT BaseCallback { BaseCallback() : caller(0) {} /* takes ownership of caller */ BaseCallback(AbstractFunctorCaller *caller) : caller(caller) {} BaseCallback(const BaseCallback &other) : caller(other.caller->clone()) {} virtual ~BaseCallback() { delete caller; } bool isValid() const { return caller != 0; } BaseCallback &operator=(const BaseCallback &other) { if (caller == other.caller) return *this; delete caller; caller = other.caller->clone(); return *this; } protected: /* may be null */ AbstractFunctorCaller *caller; }; template struct FunctorCaller0 : public BaseFunctorCaller, Functor> { typedef R ResultType; typedef R (*InvokeType)(AbstractFunctorCaller* ); explicit FunctorCaller0(const Functor &functor) : BaseFunctorCaller(functor, reinterpret_cast(&FunctorCaller0::invoke)) {} static ResultType invoke(AbstractFunctorCaller *call ) { typedef FunctorCaller0 Type; Type *typed = static_cast(call); return (typed->functor)(); } }; template struct Callback0 : public BaseCallback { typedef R (*FunctionType)(); typedef R ResultType; Callback0() {} template Callback0(const Functor &functor) : BaseCallback(new FunctorCaller0(functor)) {} ResultType operator()() const { if (caller) { typedef R (*InvokeType)(AbstractFunctorCaller* ); InvokeType invokeMethod = reinterpret_cast(caller->invokeMethodHook); return invokeMethod(caller ); } return ResultType(); } }; template struct FunctorCaller1 : public BaseFunctorCaller, Functor> { typedef R ResultType; typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1); explicit FunctorCaller1(const Functor &functor) : BaseFunctorCaller(functor, reinterpret_cast(&FunctorCaller1::invoke)) {} static ResultType invoke(AbstractFunctorCaller *call , Arg1 a1) { typedef FunctorCaller1 Type; Type *typed = static_cast(call); return (typed->functor)(a1); } }; template struct Callback1 : public BaseCallback { typedef R (*FunctionType)(Arg1); typedef R ResultType; Callback1() {} template Callback1(const Functor &functor) : BaseCallback(new FunctorCaller1(functor)) {} ResultType operator()(Arg1 a1) const { if (caller) { typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1); InvokeType invokeMethod = reinterpret_cast(caller->invokeMethodHook); return invokeMethod(caller , a1); } return ResultType(); } }; template struct FunctorCaller2 : public BaseFunctorCaller, Functor> { typedef R ResultType; typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2); explicit FunctorCaller2(const Functor &functor) : BaseFunctorCaller(functor, reinterpret_cast(&FunctorCaller2::invoke)) {} static ResultType invoke(AbstractFunctorCaller *call , Arg1 a1, Arg2 a2) { typedef FunctorCaller2 Type; Type *typed = static_cast(call); return (typed->functor)(a1, a2); } }; template struct Callback2 : public BaseCallback { typedef R (*FunctionType)(Arg1, Arg2); typedef R ResultType; Callback2() {} template Callback2(const Functor &functor) : BaseCallback(new FunctorCaller2(functor)) {} ResultType operator()(Arg1 a1, Arg2 a2) const { if (caller) { typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2); InvokeType invokeMethod = reinterpret_cast(caller->invokeMethodHook); return invokeMethod(caller , a1, a2); } return ResultType(); } }; template struct FunctorCaller3 : public BaseFunctorCaller, Functor> { typedef R ResultType; typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3); explicit FunctorCaller3(const Functor &functor) : BaseFunctorCaller(functor, reinterpret_cast(&FunctorCaller3::invoke)) {} static ResultType invoke(AbstractFunctorCaller *call , Arg1 a1, Arg2 a2, Arg3 a3) { typedef FunctorCaller3 Type; Type *typed = static_cast(call); return (typed->functor)(a1, a2, a3); } }; template struct Callback3 : public BaseCallback { typedef R (*FunctionType)(Arg1, Arg2, Arg3); typedef R ResultType; Callback3() {} template Callback3(const Functor &functor) : BaseCallback(new FunctorCaller3(functor)) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3) const { if (caller) { typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3); InvokeType invokeMethod = reinterpret_cast(caller->invokeMethodHook); return invokeMethod(caller , a1, a2, a3); } return ResultType(); } }; template struct FunctorCaller4 : public BaseFunctorCaller, Functor> { typedef R ResultType; typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3, Arg4); explicit FunctorCaller4(const Functor &functor) : BaseFunctorCaller(functor, reinterpret_cast(&FunctorCaller4::invoke)) {} static ResultType invoke(AbstractFunctorCaller *call , Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) { typedef FunctorCaller4 Type; Type *typed = static_cast(call); return (typed->functor)(a1, a2, a3, a4); } }; template struct Callback4 : public BaseCallback { typedef R (*FunctionType)(Arg1, Arg2, Arg3, Arg4); typedef R ResultType; Callback4() {} template Callback4(const Functor &functor) : BaseCallback(new FunctorCaller4(functor)) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) const { if (caller) { typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3, Arg4); InvokeType invokeMethod = reinterpret_cast(caller->invokeMethodHook); return invokeMethod(caller , a1, a2, a3, a4); } return ResultType(); } }; template struct FunctorCaller5 : public BaseFunctorCaller, Functor> { typedef R ResultType; typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3, Arg4, Arg5); explicit FunctorCaller5(const Functor &functor) : BaseFunctorCaller(functor, reinterpret_cast(&FunctorCaller5::invoke)) {} static ResultType invoke(AbstractFunctorCaller *call , Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) { typedef FunctorCaller5 Type; Type *typed = static_cast(call); return (typed->functor)(a1, a2, a3, a4, a5); } }; template struct Callback5 : public BaseCallback { typedef R (*FunctionType)(Arg1, Arg2, Arg3, Arg4, Arg5); typedef R ResultType; Callback5() {} template Callback5(const Functor &functor) : BaseCallback(new FunctorCaller5(functor)) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) const { if (caller) { typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3, Arg4, Arg5); InvokeType invokeMethod = reinterpret_cast(caller->invokeMethodHook); return invokeMethod(caller , a1, a2, a3, a4, a5); } return ResultType(); } }; template struct FunctorCaller6 : public BaseFunctorCaller, Functor> { typedef R ResultType; typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); explicit FunctorCaller6(const Functor &functor) : BaseFunctorCaller(functor, reinterpret_cast(&FunctorCaller6::invoke)) {} static ResultType invoke(AbstractFunctorCaller *call , Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) { typedef FunctorCaller6 Type; Type *typed = static_cast(call); return (typed->functor)(a1, a2, a3, a4, a5, a6); } }; template struct Callback6 : public BaseCallback { typedef R (*FunctionType)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); typedef R ResultType; Callback6() {} template Callback6(const Functor &functor) : BaseCallback(new FunctorCaller6(functor)) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) const { if (caller) { typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); InvokeType invokeMethod = reinterpret_cast(caller->invokeMethodHook); return invokeMethod(caller , a1, a2, a3, a4, a5, a6); } return ResultType(); } }; template struct FunctorCaller7 : public BaseFunctorCaller, Functor> { typedef R ResultType; typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7); explicit FunctorCaller7(const Functor &functor) : BaseFunctorCaller(functor, reinterpret_cast(&FunctorCaller7::invoke)) {} static ResultType invoke(AbstractFunctorCaller *call , Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7) { typedef FunctorCaller7 Type; Type *typed = static_cast(call); return (typed->functor)(a1, a2, a3, a4, a5, a6, a7); } }; template struct Callback7 : public BaseCallback { typedef R (*FunctionType)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7); typedef R ResultType; Callback7() {} template Callback7(const Functor &functor) : BaseCallback(new FunctorCaller7(functor)) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7) const { if (caller) { typedef R (*InvokeType)(AbstractFunctorCaller* , Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7); InvokeType invokeMethod = reinterpret_cast(caller->invokeMethodHook); return invokeMethod(caller , a1, a2, a3, a4, a5, a6, a7); } return ResultType(); } }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/ContactSearchChannel0000664000175000017500000000041412470405660021150 0ustar jrjr#ifndef _TelepathyQt_ContactSearchChannel_HEADER_GUARD_ #define _TelepathyQt_ContactSearchChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/client.cpp0000664000175000017500000000205012470405660017173 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/cli-client-body.hpp" #include "TelepathyQt/_gen/cli-client.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/account-filter.h0000664000175000017500000000226112470405660020305 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_account_filter_h_HEADER_GUARD_ #define _TelepathyQt_account_filter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { typedef Filter AccountFilter; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeFileTransferInterface0000664000175000017500000000042512470405660023500 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeFileTransferInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeFileTransferInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/future-internal.h0000664000175000017500000000256212470405660020516 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_future_internal_h_HEADER_GUARD_ #define _TelepathyQt_future_internal_h_HEADER_GUARD_ #include "TelepathyQt/_gen/future-constants.h" #include "TelepathyQt/_gen/future-types.h" #include "TelepathyQt/Channel" #include "TelepathyQt/ChannelDispatcher" #include "TelepathyQt/Connection" #include "TelepathyQt/_gen/future-channel.h" #include "TelepathyQt/_gen/future-channel-dispatcher.h" #include "TelepathyQt/_gen/future-misc.h" #endif telepathy-qt-0.9.6~git1/TelepathyQt/svc-connection.xml0000664000175000017500000000272412470405660020673 0ustar jrjr Connection interfaces telepathy-qt-0.9.6~git1/TelepathyQt/AndFilter0000664000175000017500000000035212470405660017007 0ustar jrjr#ifndef _TelepathyQt_AndFilter_HEADER_GUARD_ #define _TelepathyQt_AndFilter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/generic-capability-filter.h0000664000175000017500000000752612470405660022415 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_generic_capability_filter_h_HEADER_GUARD_ #define _TelepathyQt_generic_capability_filter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { template class GenericCapabilityFilter : public Filter { public: static SharedPtr > create( const RequestableChannelClassSpecList &rccSpecs = RequestableChannelClassSpecList()) { return SharedPtr >(new GenericCapabilityFilter( rccSpecs)); } inline virtual ~GenericCapabilityFilter() { } inline virtual bool isValid() const { return true; } inline virtual bool matches(const SharedPtr &t) const { bool supportedRcc; RequestableChannelClassSpecList objectRccSpecs = t->capabilities().allClassSpecs(); Q_FOREACH (const RequestableChannelClassSpec &filterRccSpec, mFilter) { supportedRcc = false; Q_FOREACH (const RequestableChannelClassSpec &objectRccSpec, objectRccSpecs) { /* check if fixed properties match */ if (filterRccSpec.fixedProperties() == objectRccSpec.fixedProperties()) { supportedRcc = true; /* check if all allowed properties in the filter RCC * are in the object RCC allowed properties */ Q_FOREACH (const QString &value, filterRccSpec.allowedProperties()) { if (!objectRccSpec.allowsProperty(value)) { /* one of the properties in the filter RCC * allowed properties is not in the object RCC * allowed properties */ supportedRcc = false; break; } } /* this RCC is supported, no need to check anymore */ if (supportedRcc) { break; } } } /* one of the filter RCC is not supported, this object * won't match filter */ if (!supportedRcc) { return false; } } return true; } inline RequestableChannelClassSpecList filter() const { return mFilter; } inline void addRequestableChannelClassSubset(const RequestableChannelClassSpec &rccSpec) { mFilter.append(rccSpec.bareClass()); } inline void setRequestableChannelClassesSubset(const RequestableChannelClassSpecList &rccSpecs) { mFilter = rccSpecs.bareClasses(); } private: GenericCapabilityFilter(const RequestableChannelClassSpecList &rccSpecs) : Filter(), mFilter(rccSpecs) { } RequestableChannelClassSpecList mFilter; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/AccountInterfaceAvatarInterface0000664000175000017500000000042312470405660023333 0ustar jrjr#ifndef _TelepathyQt_AccountInterfaceAvatarInterface_HEADER_GUARD_ #define _TelepathyQt_AccountInterfaceAvatarInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/server-authentication-channel.h0000664000175000017500000000442312470405660023321 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_server_authentication_channel_h_HEADER_GUARD_ #define _TelepathyQt_server_authentication_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class TP_QT_EXPORT ServerAuthenticationChannel : public Channel { Q_OBJECT Q_DISABLE_COPY(ServerAuthenticationChannel) public: static const Feature FeatureCore; static ServerAuthenticationChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~ServerAuthenticationChannel(); CaptchaAuthenticationPtr captchaAuthentication() const; // TODO: Add something for SASL here as well bool hasCaptchaInterface() const; // TODO: Enable when SASL high-level support is in // bool hasSaslInterface() const; protected: ServerAuthenticationChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = ServerAuthenticationChannel::FeatureCore); private Q_SLOTS: TP_QT_NO_EXPORT void gotCaptchaAuthenticationProperties(Tp::PendingOperation *op); TP_QT_NO_EXPORT void gotServerAuthenticationProperties(Tp::PendingOperation *op); private: struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/MediaSessionHandler0000664000175000017500000000041112470405660021014 0ustar jrjr#ifndef _TelepathyQt_MediaSessionHandler_HEADER_GUARD_ #define _TelepathyQt_MediaSessionHandler_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/location-info.h0000664000175000017500000000460512470405660020133 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_location_info_h_HEADER_GUARD_ #define _TelepathyQt_location_info_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include namespace Tp { class TP_QT_EXPORT LocationInfo { public: LocationInfo(); LocationInfo(const QVariantMap &location); LocationInfo(const LocationInfo &other); virtual ~LocationInfo(); bool isValid() const { return mPriv.constData() != 0; } LocationInfo &operator=(const LocationInfo &other); QString countryCode() const; QString country() const; QString region() const; QString locality() const; QString area() const; QString postalCode() const; QString street() const; QString building() const; QString floor() const; QString room() const; QString text() const; QString description() const; QString uri() const; QString language() const; double latitude() const; double longitude() const; double altitude() const; double accuracy() const; double speed() const; double bearing() const; QDateTime timestamp() const; QVariantMap allDetails() const; private: friend class Contact; TP_QT_NO_EXPORT void updateData(const QVariantMap &location); struct Private; friend struct Private; QSharedDataPointer mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::LocationInfo); #endif telepathy-qt-0.9.6~git1/TelepathyQt/fixed-feature-factory.cpp0000664000175000017500000000625112470405660022121 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/fixed-feature-factory.moc.hpp" #include namespace Tp { struct TP_QT_NO_EXPORT FixedFeatureFactory::Private { Features features; }; /** * \class FixedFeatureFactory * \ingroup utils * \headerfile TelepathyQt/fixed-feature-factory.h * * \brief The FixedFeatureFactory class is a base class for all D-Bus proxy * factories which want the same set of features for all constructed proxies. */ /** * Class constructor. * * The intention for storing the bus here is that it generally doesn't make sense to construct * proxies for multiple buses in the same context. Allowing that would lead to more complex keying * needs in the cache, as well. * * \param bus The D-Bus bus connection for the objects constructed using this factory. */ FixedFeatureFactory::FixedFeatureFactory(const QDBusConnection &bus) : DBusProxyFactory(bus), mPriv(new Private) { } /** * Class destructor. */ FixedFeatureFactory::~FixedFeatureFactory() { delete mPriv; } /** * Gets the features this factory will make ready on constructed proxies. * * \return The set of features. */ Features FixedFeatureFactory::features() const { return mPriv->features; } /** * Adds a single feature this factory will make ready on further constructed proxies. * * No feature removal is provided, to guard against uncooperative modules removing features other * modules have set and depend on. * * \param feature The feature to add. */ void FixedFeatureFactory::addFeature(const Feature &feature) { addFeatures(Features(feature)); } /** * Adds a set of features this factory will make ready on further constructed proxies. * * No feature removal is provided, to guard against uncooperative modules removing features other * modules have set and depend on. * * \param features The features to add. */ void FixedFeatureFactory::addFeatures(const Features &features) { mPriv->features.unite(features); } /** * Fixed implementation of the per-proxy feature getter. * * \return features(), irrespective of the actual \a proxy. */ Features FixedFeatureFactory::featuresFor(const DBusProxyPtr &proxy) const { Q_UNUSED(proxy); return features(); } } telepathy-qt-0.9.6~git1/TelepathyQt/BaseConnectionManager0000664000175000017500000000041712470405660021326 0ustar jrjr#ifndef _TelepathyQt_BaseConnectionManager_HEADER_GUARD_ #define _TelepathyQt_BaseConnectionManager_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/contact-manager-internal.h0000664000175000017500000003233512470405660022250 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_contact_manager_internal_h_HEADER_GUARD_ #define _TelepathyQt_contact_manager_internal_h_HEADER_GUARD_ #include #include #include #include #include #include #include #include #include namespace Tp { class TP_QT_NO_EXPORT ContactManager::Roster : public QObject { Q_OBJECT public: Roster(ContactManager *manager); virtual ~Roster(); ContactListState state() const; PendingOperation *introspect(); PendingOperation *introspectGroups(); void reset(); Contacts allKnownContacts() const; QStringList allKnownGroups() const; PendingOperation *addGroup(const QString &group); PendingOperation *removeGroup(const QString &group); Contacts groupContacts(const QString &group) const; PendingOperation *addContactsToGroup(const QString &group, const QList &contacts); PendingOperation *removeContactsFromGroup(const QString &group, const QList &contacts); bool canRequestPresenceSubscription() const; bool subscriptionRequestHasMessage() const; PendingOperation *requestPresenceSubscription( const QList &contacts, const QString &message); bool canRemovePresenceSubscription() const; bool subscriptionRemovalHasMessage() const; bool canRescindPresenceSubscriptionRequest() const; bool subscriptionRescindingHasMessage() const; PendingOperation *removePresenceSubscription( const QList &contacts, const QString &message); bool canAuthorizePresencePublication() const; bool publicationAuthorizationHasMessage() const; PendingOperation *authorizePresencePublication( const QList &contacts, const QString &message); bool publicationRejectionHasMessage() const; bool canRemovePresencePublication() const; bool publicationRemovalHasMessage() const; PendingOperation *removePresencePublication( const QList &contacts, const QString &message); PendingOperation *removeContacts( const QList &contacts, const QString &message); bool canBlockContacts() const; bool canReportAbuse() const; PendingOperation *blockContacts(const QList &contacts, bool value, bool reportAbuse); private Q_SLOTS: void gotContactBlockingCapabilities(Tp::PendingOperation *op); void gotContactBlockingBlockedContacts(QDBusPendingCallWatcher *watcher); void onContactBlockingBlockedContactsChanged( const Tp::HandleIdentifierMap &added, const Tp::HandleIdentifierMap &removed); void gotContactListProperties(Tp::PendingOperation *op); void gotContactListContacts(QDBusPendingCallWatcher *watcher); void setStateSuccess(); void onContactListStateChanged(uint state); void onContactListContactsChangedWithId(const Tp::ContactSubscriptionMap &changes, const Tp::HandleIdentifierMap &ids, const Tp::HandleIdentifierMap &removals); void onContactListContactsChanged(const Tp::ContactSubscriptionMap &changes, const Tp::UIntList &removals); void onContactListBlockedContactsConstructed(Tp::PendingOperation *op); void onContactListNewContactsConstructed(Tp::PendingOperation *op); void onContactListGroupsChanged(const Tp::UIntList &contacts, const QStringList &added, const QStringList &removed); void onContactListGroupsCreated(const QStringList &names); void onContactListGroupRenamed(const QString &oldName, const QString &newName); void onContactListGroupsRemoved(const QStringList &names); void onModifyFinished(Tp::PendingOperation *op); void onModifyFinishSignaled(); void gotContactListChannelHandle(Tp::PendingOperation *op); void gotContactListChannel(Tp::PendingOperation *op); void onContactListChannelReady(); void gotContactListGroupsProperties(Tp::PendingOperation *op); void onContactListContactsUpgraded(Tp::PendingOperation *op); void onNewChannels(const Tp::ChannelDetailsList &channelDetailsList); void onContactListGroupChannelReady(Tp::PendingOperation *op); void gotChannels(QDBusPendingCallWatcher *watcher); void onStoredChannelMembersChanged( const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupLocalPendingMembersAdded, const Tp::Contacts &groupRemotePendingMembersAdded, const Tp::Contacts &groupMembersRemoved, const Tp::Channel::GroupMemberChangeDetails &details); void onSubscribeChannelMembersChanged( const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupLocalPendingMembersAdded, const Tp::Contacts &groupRemotePendingMembersAdded, const Tp::Contacts &groupMembersRemoved, const Tp::Channel::GroupMemberChangeDetails &details); void onPublishChannelMembersChanged( const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupLocalPendingMembersAdded, const Tp::Contacts &groupRemotePendingMembersAdded, const Tp::Contacts &groupMembersRemoved, const Tp::Channel::GroupMemberChangeDetails &details); void onDenyChannelMembersChanged( const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupLocalPendingMembersAdded, const Tp::Contacts &groupRemotePendingMembersAdded, const Tp::Contacts &groupMembersRemoved, const Tp::Channel::GroupMemberChangeDetails &details); void onContactListGroupMembersChanged( const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupLocalPendingMembersAdded, const Tp::Contacts &groupRemotePendingMembersAdded, const Tp::Contacts &groupMembersRemoved, const Tp::Channel::GroupMemberChangeDetails &details); void onContactListGroupRemoved(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage); private: struct ChannelInfo; struct BlockedContactsChangedInfo; struct UpdateInfo; struct GroupsUpdateInfo; struct GroupRenamedInfo; class ModifyFinishOp; class RemoveGroupOp; void introspectContactBlocking(); void introspectContactBlockingBlockedContacts(); void introspectContactList(); void introspectContactListContacts(); void processContactListChanges(); void processContactListBlockedContactsChanged(); void processContactListUpdates(); void processContactListGroupsUpdates(); void processContactListGroupsCreated(); void processContactListGroupRenamed(); void processContactListGroupsRemoved(); void processFinishedModify(); PendingOperation *queuedFinishVoid(const QDBusPendingCall &call); void setContactListChannelsReady(); void updateContactsBlockState(); void updateContactsPresenceState(); void computeKnownContactsChanges(const Contacts &added, const Contacts &pendingAdded, const Contacts &remotePendingAdded, const Contacts &removed, const Channel::GroupMemberChangeDetails &details); void checkContactListGroupsReady(); void setContactListGroupChannelsReady(); QString addContactListGroupChannel(const ChannelPtr &contactListGroupChannel); ContactManager *contactManager; Contacts cachedAllKnownContacts; bool usingFallbackContactList; bool hasContactBlockingInterface; PendingOperation *introspectPendingOp; PendingOperation *introspectGroupsPendingOp; uint pendingContactListState; uint contactListState; bool canReportAbusive; bool gotContactBlockingInitialBlockedContacts; bool canChangeContactList; bool contactListRequestUsesMessage; bool gotContactListInitialContacts; bool gotContactListContactsChangedWithId; bool groupsReintrospectionRequired; QSet cachedAllKnownGroups; bool contactListGroupPropertiesReceived; QQueue contactListChangesQueue; QQueue contactListBlockedContactsChangedQueue; QQueue contactListUpdatesQueue; QQueue contactListGroupsUpdatesQueue; QQueue contactListGroupsCreatedQueue; QQueue contactListGroupRenamedQueue; QQueue contactListGroupsRemovedQueue; bool processingContactListChanges; QHash returnedModifyOps; QQueue modifyFinishQueue; // old roster API uint contactListChannelsReady; QHash contactListChannels; ChannelPtr subscribeChannel; ChannelPtr publishChannel; ChannelPtr storedChannel; ChannelPtr denyChannel; // Number of things left to do before the Groups feature is ready // 1 for Get("Channels") + 1 per channel not ready uint featureContactListGroupsTodo; QList pendingContactListGroupChannels; QHash contactListGroupChannels; QList removedContactListGroupChannels; // If RosterGroups introspection completing should advance the ContactManager state to Success bool groupsSetSuccess; // Contact list contacts using the Conn.I.ContactList API Contacts contactListContacts; // Blocked contacts using the new ContactBlocking API Contacts blockedContacts; }; struct TP_QT_NO_EXPORT ContactManager::Roster::ChannelInfo { enum Type { TypeSubscribe = 0, TypePublish, TypeStored, TypeDeny, LastType }; ChannelInfo() : type((Type) -1) { } ChannelInfo(Type type) : type(type) { } static QString identifierForType(Type type); static uint typeForIdentifier(const QString &identifier); Type type; ReferencedHandles handle; ChannelPtr channel; }; struct TP_QT_NO_EXPORT ContactManager::Roster::BlockedContactsChangedInfo { BlockedContactsChangedInfo(const HandleIdentifierMap &added, const HandleIdentifierMap &removed, bool continueIntrospectionWhenFinished = false) : added(added), removed(removed), continueIntrospectionWhenFinished(continueIntrospectionWhenFinished) { } HandleIdentifierMap added; HandleIdentifierMap removed; bool continueIntrospectionWhenFinished; }; struct TP_QT_NO_EXPORT ContactManager::Roster::UpdateInfo { UpdateInfo(const ContactSubscriptionMap &changes, const HandleIdentifierMap &ids, const HandleIdentifierMap &removals) : changes(changes), ids(ids), removals(removals) { } ContactSubscriptionMap changes; HandleIdentifierMap ids; HandleIdentifierMap removals; }; struct TP_QT_NO_EXPORT ContactManager::Roster::GroupsUpdateInfo { GroupsUpdateInfo(const UIntList &contacts, const QStringList &groupsAdded, const QStringList &groupsRemoved) : contacts(contacts), groupsAdded(groupsAdded), groupsRemoved(groupsRemoved) { } UIntList contacts; QStringList groupsAdded; QStringList groupsRemoved; }; struct TP_QT_NO_EXPORT ContactManager::Roster::GroupRenamedInfo { GroupRenamedInfo(const QString &oldName, const QString &newName) : oldName(oldName), newName(newName) { } QString oldName; QString newName; }; class TP_QT_NO_EXPORT ContactManager::Roster::ModifyFinishOp : public PendingOperation { Q_OBJECT public: ModifyFinishOp(const ConnectionPtr &conn); ~ModifyFinishOp() {}; void setError(const QString &errorName, const QString &errorMessage); void finish(); private: QString errorName, errorMessage; }; class TP_QT_NO_EXPORT ContactManager::Roster::RemoveGroupOp : public PendingOperation { Q_OBJECT public: RemoveGroupOp(const ChannelPtr &channel); ~RemoveGroupOp() {}; private Q_SLOTS: void onContactsRemoved(Tp::PendingOperation *); void onChannelClosed(Tp::PendingOperation *); }; class TP_QT_NO_EXPORT ContactManager::PendingRefreshContactInfo : public PendingOperation { Q_OBJECT public: PendingRefreshContactInfo(const ConnectionPtr &conn); ~PendingRefreshContactInfo(); void addContact(Contact *contact); void refreshInfo(); private Q_SLOTS: void onRefreshInfoFinished(Tp::PendingOperation *op); private: ConnectionPtr mConn; QSet mToRequest; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/captcha-authentication.cpp0000664000175000017500000003732112470405660022346 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/_gen/captcha-authentication.moc.hpp" #include "TelepathyQt/_gen/captcha-authentication-internal.moc.hpp" #include #include #include #include #include namespace Tp { // --- PendingCaptchaAnswer::PendingCaptchaAnswer(const QDBusPendingCall &call, const CaptchaAuthenticationPtr &object) : PendingOperation(object), mWatcher(new QDBusPendingCallWatcher(call, this)), mCaptcha(object), mChannel(mCaptcha->channel()) { debug() << "Calling Captcha.Answer"; if (mWatcher->isFinished()) { onAnswerFinished(); } else { // Connect the pending void connect(mWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onAnswerFinished())); } } PendingCaptchaAnswer::~PendingCaptchaAnswer() { } void PendingCaptchaAnswer::onAnswerFinished() { QDBusReply reply = mWatcher->reply(); if (!reply.isValid()) { warning().nospace() << "Captcha.Answer failed with " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); return; } debug() << "Captcha.Answer returned successfully"; // It might have been already opened - check if (mCaptcha->status() == CaptchaStatusLocalPending || mCaptcha->status() == CaptchaStatusRemotePending) { debug() << "Awaiting captcha to be answered from server"; // Wait until status becomes relevant connect(mCaptcha.data(), SIGNAL(statusChanged(Tp::CaptchaStatus)), SLOT(onCaptchaStatusChanged(Tp::CaptchaStatus))); } else { onCaptchaStatusChanged(mCaptcha->status()); } } void PendingCaptchaAnswer::onCaptchaStatusChanged(Tp::CaptchaStatus status) { if (status == CaptchaStatusSucceeded) { // Perfect. Close the channel now. connect(mChannel->requestClose(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onRequestCloseFinished(Tp::PendingOperation*))); } else if (status == CaptchaStatusFailed || status == CaptchaStatusTryAgain) { warning() << "Captcha status changed to" << status << ", failing"; setFinishedWithError(mCaptcha->error(), mCaptcha->errorDetails().debugMessage()); } } void PendingCaptchaAnswer::onRequestCloseFinished(Tp::PendingOperation *operation) { if (operation->isError()) { // We cannot really fail just because the channel didn't close. Throw a warning instead. warning() << "Could not close the channel after a successful captcha answer!!" << operation->errorMessage(); } setFinished(); } PendingCaptchaCancel::PendingCaptchaCancel(const QDBusPendingCall &call, const CaptchaAuthenticationPtr &object) : PendingOperation(object), mWatcher(new QDBusPendingCallWatcher(call, this)), mCaptcha(object), mChannel(mCaptcha->channel()) { debug() << "Calling Captcha.Cancel"; if (mWatcher->isFinished()) { onCancelFinished(); } else { // Connect the pending void connect(mWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onCancelFinished())); } } PendingCaptchaCancel::~PendingCaptchaCancel() { } void PendingCaptchaCancel::onCancelFinished() { QDBusReply reply = mWatcher->reply(); if (!reply.isValid()) { warning().nospace() << "Captcha.Answer failed with " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); return; } debug() << "Captcha.Cancel returned successfully"; // Perfect. Close the channel now. connect(mChannel->requestClose(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onRequestCloseFinished(Tp::PendingOperation*))); } void PendingCaptchaCancel::onRequestCloseFinished(Tp::PendingOperation *operation) { if (operation->isError()) { // We cannot really fail just because the channel didn't close. Throw a warning instead. warning() << "Could not close the channel after a successful captcha cancel!!" << operation->errorMessage(); } setFinished(); } // -- CaptchaAuthentication::Private::Private(CaptchaAuthentication *parent) : parent(parent) { } void CaptchaAuthentication::Private::extractCaptchaAuthenticationProperties(const QVariantMap &props) { canRetry = qdbus_cast(props[QLatin1String("CanRetryCaptcha")]); status = static_cast(qdbus_cast(props[QLatin1String("Status")])); } /** * \class CaptchaAuthentication * \ingroup clientchannel * \headerfile TelepathyQt/captcha-authentication.h * * \brief The CaptchaAuthentication class exposes CaptchaAuthentication's features for channels implementing it. * * A ServerAuthentication channel can implement a CaptchaAuthentication interface: this class exposes all the features * this interface provides in a high-level fashion. It is a mechanism for retrieving a captcha challenge from * a connection manager and answering it. * * This class is meant to be used just during authentication phase. It is useful just for platform-level handlers * which are meant to handle authentication - if you are implementing a client which is meant to live in a * Telepathy-aware platform, you probably won't need to handle this unless you have very special needs. * * Note that CaptchaAuthentication cannot be instantiated directly, instead the accessor method from * ServerAuthenticationChannel (ServerAuthenticationChannel::captchaAuthentication) should be used. * * See \ref async_model, \ref shared_ptr */ CaptchaAuthentication::CaptchaAuthentication(const ChannelPtr &channel) : Object(), mPriv(new Private(this)) { mPriv->channel = channel; } /** * Class destructor. */ CaptchaAuthentication::~CaptchaAuthentication() { delete mPriv; } /** * Return the channel associated with this captcha. * * CaptchaAuthentication is just a representation of an interface which can be implemented by * a ServerAuthentication channel. This function will return the channel implementing the interface * represented by this instance. * * Note that it is currently guaranteed the ChannelPtr returned by this function will be a ServerAuthenticationChannel. * * \return The channel implementing the CaptchaAuthentication interface represented by this instance. */ Tp::ChannelPtr CaptchaAuthentication::channel() const { return ChannelPtr(mPriv->channel); } /** * Return whether this channel supports updating its captchas or not. * * Some protocols allow their captchas to be reloaded providing new data to the user; for example, in case * the image provided is not easily readable. This function checks if this instance supports such a feature. * * Note that in case this function returns \c true, requestCaptchas can be called safely after a failed answer attempt. * * \return \c true if a new captcha can be fetched from this channel, \c false otherwise. */ bool CaptchaAuthentication::canRetry() const { return mPriv->canRetry; } /** * Return the current status of the captcha. * * \return The current status of the captcha. */ Tp::CaptchaStatus CaptchaAuthentication::status() const { return mPriv->status; } /** * Return the code of the last error happened on the interface. * * \return An error code describing the last error occurred. * \sa errorDetails */ QString CaptchaAuthentication::error() const { return mPriv->error; } /** * Return the details of the last error happened on the interface. * * \return Further details describing the last error occurred. * \sa error */ Connection::ErrorDetails CaptchaAuthentication::errorDetails() const { return Connection::ErrorDetails(mPriv->errorDetails); } /** * Request captcha challenges from the connection manager. * * Even if most protocols usually provide a single captcha challenge (OCR), for a variety * of reasons some of them could provide a number of different challenge types, requiring * one or more of them to be answered. * * This method initiates a request to the connection manager for obtaining the most compatible captcha * challenges available. It allows to supply a number of supported mimetypes and types, so that the * request will fail if the CM is unable to provide a challenge compatible with what the handler supports, * or will provide the best one available otherwise. * * Please note that all the challenges returned by this request must be answered in order for the authentication * to succeed. * * Note that if the CM supports retrying the captcha, this function can also be used to load a new set of captchas. * In general, if canRetry returns true, one can expect this function to always return a different set * of challenges which invalidates any other obtained previously. * * \param preferredMimeTypes A list of mimetypes supported by the handler, or an empty list if every * mimetype can be supported. * \param preferredTypes A list of challenge types supported by the handler. * \return A PendingCaptchas which will emit PendingCaptchas::finished when the request has been completed and all the payloads * have been downloaded. * \sa canRetry * \sa cancel * \sa answer */ PendingCaptchas *CaptchaAuthentication::requestCaptchas(const QStringList &preferredMimeTypes, ChallengeTypes preferredTypes) { // The captcha should be either LocalPending or TryAgain if (status() != CaptchaStatusLocalPending && status() != CaptchaStatusTryAgain) { warning() << "Status must be local pending or try again"; return new PendingCaptchas(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel busy"), CaptchaAuthenticationPtr(this)); } ChannelPtr serverAuthChannel = ChannelPtr(mPriv->channel); return new PendingCaptchas( serverAuthChannel->interface()->GetCaptchas(), preferredMimeTypes, preferredTypes, CaptchaAuthenticationPtr(this)); } /** * Overloaded function. Convenience method when just a single captcha requires to be answered. * * Note that you need to answer only the last set of challenges returned, in case requestCaptchas * was invoked multiple times. * * Please note that if this operation succeeds, the channel will be closed right after. * * \param id The id of the challenge being answered. * \param response The answer of this challenge. * \return A PendingOperation which will emit PendingOperation::finished upon the outcome of the answer procedure. * Upon success, the operation will complete once the channel is closed. * \sa requestCaptchas * \sa answer */ Tp::PendingOperation *CaptchaAuthentication::answer(uint id, const QString &response) { QMap answers; answers.insert(id, response); return answer(answers); } /** * Answer a set of challenges. * * Challenges obtained with requestCaptchas should be answered using this method. Note that * every challenge returned by the last invocation of requestCaptchas must be answered * in order for the operation to succeed. * * Usually, most protocols will require just a single challenge to be answered: if that is the * case, you can use the convenience overload. * * Note that you need to answer only the last set of challenges returned, in case requestCaptchas * was invoked multiple times. * * Please note that if this operation succeeds, the channel will be closed right after. * * \param response A set of answers mapped by their id to the challenges obtained previously * \return A PendingOperation which will emit PendingOperation::finished upon the outcome of the answer procedure. * Upon success, the operation will complete once the channel is closed. * \sa requestCaptchas * \sa answer */ Tp::PendingOperation *CaptchaAuthentication::answer(const Tp::CaptchaAnswers &response) { // The captcha should be LocalPending or TryAgain if (status() != CaptchaStatusLocalPending) { warning() << "Status must be local pending"; return new PendingCaptchas(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel busy"), CaptchaAuthenticationPtr(this)); } ChannelPtr serverAuthChannel = ChannelPtr(mPriv->channel); return new PendingCaptchaAnswer(serverAuthChannel->interface()->AnswerCaptchas(response), CaptchaAuthenticationPtr(this)); } /** * Cancel the current challenge. * * Please note that if this operation succeeds, the channel will be closed right after. * * Note that this function has not the same semantics as retry. The status of the CaptchaAuthentication * will change to Failed even if the channel supports retrying. This function should be called * only if the user refuses to answer any challenge. Instead, if the user wishes to retry, * you should just call requestCaptchas one more time. * * \param reason The reason why the challenge has been cancelled. * \param message A message detailing the cancel reason. * \return A PendingOperation which will emit PendingOperation::finished upon the outcome of the cancel procedure. * Upon success, the operation will complete once the channel is closed. * \sa requestCaptchas */ Tp::PendingOperation *CaptchaAuthentication::cancel(CaptchaCancelReason reason, const QString &message) { ChannelPtr serverAuthChannel = ChannelPtr(mPriv->channel); return new PendingCaptchaCancel(serverAuthChannel->interface()->CancelCaptcha( reason, message), CaptchaAuthenticationPtr(this)); } void CaptchaAuthentication::onPropertiesChanged(const QVariantMap &changedProperties, const QStringList &invalidatedProperties) { Q_UNUSED(invalidatedProperties); if (changedProperties.contains(QLatin1String("CaptchaStatus"))) { mPriv->status = static_cast(changedProperties.value(QLatin1String("CaptchaStatus")).value()); emit statusChanged(mPriv->status); } if (changedProperties.contains(QLatin1String("CaptchaErrorDetails"))) { mPriv->errorDetails = changedProperties.value(QLatin1String("CaptchaErrorDetails")).toMap(); } if (changedProperties.contains(QLatin1String("CaptchaError"))) { mPriv->error = changedProperties.value(QLatin1String("CaptchaError")).toString(); } } /** * \fn void CaptchaAuthentication::statusChanged(Tp::CaptchaStatus status) * * Emitted when the value of status() changes. * * \sa status The new status of this CaptchaAuthentication. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ready-object.h0000664000175000017500000000360512470405660017741 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_ready_object_h_HEADER_GUARD_ #define _TelepathyQt_ready_object_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class DBusProxy; class PendingReady; class ReadinessHelper; class RefCounted; class TP_QT_EXPORT ReadyObject { Q_DISABLE_COPY(ReadyObject) public: ReadyObject(RefCounted *object, const Feature &featureCore); ReadyObject(DBusProxy *proxy, const Feature &featureCore); virtual ~ReadyObject(); virtual bool isReady(const Features &features = Features()) const; virtual PendingReady *becomeReady(const Features &requestedFeatures = Features()); virtual Features requestedFeatures() const; virtual Features actualFeatures() const; virtual Features missingFeatures() const; protected: ReadinessHelper *readinessHelper() const; private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/CallStreamInterface0000664000175000017500000000037712470405660021016 0ustar jrjr#ifndef _TelepathyQt_CallStreamInterface_HEADER_GUARD_ #define _TelepathyQt_CallStreamInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/tls-certificate.h0000664000175000017500000000212312470405660020445 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_tls_certificate_h_HEADER_GUARD_ #define _TelepathyQt_tls_certificate_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/IncomingFileTransferChannel0000664000175000017500000000044212470405660022500 0ustar jrjr#ifndef _TelepathyQt_IncomingFileTransferChannel_HEADER_GUARD_ #define _TelepathyQt_IncomingFileTransferChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceCallStateInterface0000664000175000017500000000043112470405660023744 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceCallStateInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceCallStateInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/call-content-media-description.xml0000664000175000017500000000104012470405660023712 0ustar jrjr Call misc interfaces, version 1 telepathy-qt-0.9.6~git1/TelepathyQt/channel-factory.h0000664000175000017500000004013412470405660020444 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_channel_factory_h_HEADER_GUARD_ #define _TelepathyQt_channel_factory_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include // For Q_DISABLE_COPY #include #include #include class QDBusConnection; namespace Tp { class ChannelClassSpec; class TP_QT_EXPORT ChannelFactory : public DBusProxyFactory { Q_OBJECT Q_DISABLE_COPY(ChannelFactory) public: #ifndef DOXYGEN_SHOULD_SKIP_THIS struct TP_QT_EXPORT Constructor : public RefCounted { virtual ~Constructor() {} virtual ChannelPtr construct(const ConnectionPtr &conn, const QString &objectPath, const QVariantMap &immutableProperties) const = 0; }; typedef SharedPtr ConstructorPtr; typedef SharedPtr ConstructorConstPtr; #endif /* DOXYGEN_SHOULD_SKIP_THIS */ static ChannelFactoryPtr create(const QDBusConnection &bus); virtual ~ChannelFactory(); Features featuresForTextChats(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForTextChats(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForTextChats( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForTextChats(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForTextChats(SubclassCtor::create(), additionalProps); } void setConstructorForTextChats(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForTextChatrooms(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForTextChatrooms(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForTextChatrooms( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForTextChatrooms(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForTextChatrooms(SubclassCtor::create(), additionalProps); } void setConstructorForTextChatrooms(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForCalls(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForCalls(const Features &features, const QVariantMap &additionalProps = QVariantMap()); template void setSubclassForCalls(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForCalls(SubclassCtor::create(), additionalProps); } void setConstructorForCalls(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); TP_QT_DEPRECATED Features featuresForStreamedMediaCalls(const QVariantMap &additionalProps = QVariantMap()) const; TP_QT_DEPRECATED void addFeaturesForStreamedMediaCalls(const Features &features, const QVariantMap &additionalProps = QVariantMap()); TP_QT_DEPRECATED ConstructorConstPtr constructorForStreamedMediaCalls( const QVariantMap &additionalProps = QVariantMap()) const; template TP_QT_DEPRECATED void setSubclassForStreamedMediaCalls(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForStreamedMediaCalls(SubclassCtor::create(), additionalProps); } TP_QT_DEPRECATED void setConstructorForStreamedMediaCalls(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForRoomLists(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForRoomLists(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForRoomLists( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForRoomLists(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForRoomLists(SubclassCtor::create(), additionalProps); } void setConstructorForRoomLists(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForOutgoingFileTransfers(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForOutgoingFileTransfers(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForOutgoingFileTransfers( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForOutgoingFileTransfers(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForOutgoingFileTransfers(SubclassCtor::create(), additionalProps); } void setConstructorForOutgoingFileTransfers(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForIncomingFileTransfers(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForIncomingFileTransfers(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForIncomingFileTransfers( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForIncomingFileTransfers(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForIncomingFileTransfers(SubclassCtor::create(), additionalProps); } void setConstructorForIncomingFileTransfers(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForOutgoingStreamTubes(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForOutgoingStreamTubes(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForOutgoingStreamTubes( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForOutgoingStreamTubes(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForOutgoingStreamTubes(SubclassCtor::create(), additionalProps); } void setConstructorForOutgoingStreamTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForIncomingStreamTubes(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForIncomingStreamTubes(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForIncomingStreamTubes( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForIncomingStreamTubes(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForIncomingStreamTubes(SubclassCtor::create(), additionalProps); } void setConstructorForIncomingStreamTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForOutgoingRoomStreamTubes(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForOutgoingRoomStreamTubes(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForOutgoingRoomStreamTubes( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForOutgoingRoomStreamTubes(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForOutgoingRoomStreamTubes(SubclassCtor::create(), additionalProps); } void setConstructorForOutgoingRoomStreamTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForIncomingRoomStreamTubes(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForIncomingRoomStreamTubes(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForIncomingRoomStreamTubes( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForIncomingRoomStreamTubes(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForIncomingRoomStreamTubes(SubclassCtor::create(), additionalProps); } void setConstructorForIncomingRoomStreamTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForOutgoingDBusTubes(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForOutgoingDBusTubes(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForOutgoingDBusTubes( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForOutgoingDBusTubes(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForOutgoingDBusTubes(SubclassCtor::create(), additionalProps); } void setConstructorForOutgoingDBusTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForIncomingDBusTubes(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForIncomingDBusTubes(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForIncomingDBusTubes( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForIncomingDBusTubes(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForIncomingDBusTubes(SubclassCtor::create(), additionalProps); } void setConstructorForIncomingDBusTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForOutgoingRoomDBusTubes(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForOutgoingRoomDBusTubes(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForOutgoingRoomDBusTubes( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForOutgoingRoomDBusTubes(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForOutgoingRoomDBusTubes(SubclassCtor::create(), additionalProps); } void setConstructorForOutgoingRoomDBusTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForIncomingRoomDBusTubes(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForIncomingRoomDBusTubes(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForIncomingRoomDBusTubes( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForIncomingRoomDBusTubes(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForIncomingRoomDBusTubes(SubclassCtor::create(), additionalProps); } void setConstructorForIncomingRoomDBusTubes(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForContactSearches(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForContactSearches(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForContactSearches( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForContactSearches(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForContactSearches(SubclassCtor::create(), additionalProps); } void setConstructorForContactSearches(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features featuresForServerAuthentication(const QVariantMap &additionalProps = QVariantMap()) const; void addFeaturesForServerAuthentication(const Features &features, const QVariantMap &additionalProps = QVariantMap()); ConstructorConstPtr constructorForServerAuthentication( const QVariantMap &additionalProps = QVariantMap()) const; template void setSubclassForServerAuthentication(const QVariantMap &additionalProps = QVariantMap()) { setConstructorForServerAuthentication(SubclassCtor::create(), additionalProps); } void setConstructorForServerAuthentication(const ConstructorConstPtr &ctor, const QVariantMap &additionalProps = QVariantMap()); Features commonFeatures() const; void addCommonFeatures(const Features &features); ConstructorConstPtr fallbackConstructor() const; template void setFallbackSubclass() { setFallbackConstructor(SubclassCtor::create()); } void setFallbackConstructor(const ConstructorConstPtr &ctor); Features featuresFor(const ChannelClassSpec &channelClass) const; void addFeaturesFor(const ChannelClassSpec &channelClass, const Features &features); template void setSubclassFor(const ChannelClassSpec &channelClass) { setConstructorFor(channelClass, SubclassCtor::create()); } ConstructorConstPtr constructorFor(const ChannelClassSpec &channelClass) const; void setConstructorFor(const ChannelClassSpec &channelClass, const ConstructorConstPtr &ctor); PendingReady *proxy(const ConnectionPtr &connection, const QString &channelPath, const QVariantMap &immutableProperties) const; protected: ChannelFactory(const QDBusConnection &bus); #ifndef DOXYGEN_SHOULD_SKIP_THIS template struct SubclassCtor : public Constructor { static ConstructorPtr create() { return ConstructorPtr(new SubclassCtor()); } virtual ~SubclassCtor() {} ChannelPtr construct(const ConnectionPtr &conn, const QString &objectPath, const QVariantMap &immutableProperties) const { return Subclass::create(conn, objectPath, immutableProperties); } }; #endif /* DOXYGEN_SHOULD_SKIP_THIS */ virtual QString finalBusNameFrom(const QString &uniqueOrWellKnown) const; // Nothing we'd like to prepare() virtual Features featuresFor(const DBusProxyPtr &proxy) const; private: struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/call-content.cpp0000664000175000017500000004061112470405660020305 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/call-content.moc.hpp" #include "TelepathyQt/_gen/cli-call-content-body.hpp" #include "TelepathyQt/_gen/cli-call-content.moc.hpp" #include #include #include #include #include #include #include namespace Tp { /* ====== CallContent ====== */ struct TP_QT_NO_EXPORT CallContent::Private { Private(CallContent *parent, const CallChannelPtr &channel); static void introspectMainProperties(Private *self); void checkIntrospectionCompleted(); CallStreamPtr addStream(const QDBusObjectPath &streamPath); CallStreamPtr lookupStream(const QDBusObjectPath &streamPath); // Public object CallContent *parent; WeakPtr channel; // Mandatory proxies Client::CallContentInterface *contentInterface; ReadinessHelper *readinessHelper; // Introspection QString name; uint type; uint disposition; CallStreams streams; CallStreams incompleteStreams; }; CallContent::Private::Private(CallContent *parent, const CallChannelPtr &channel) : parent(parent), channel(channel.data()), contentInterface(parent->interface()), readinessHelper(parent->readinessHelper()) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMainProperties, this); introspectables[FeatureCore] = introspectableCore; readinessHelper->addIntrospectables(introspectables); readinessHelper->becomeReady(FeatureCore); } void CallContent::Private::introspectMainProperties(CallContent::Private *self) { CallContent *parent = self->parent; CallChannelPtr channel = parent->channel(); parent->connect(self->contentInterface, SIGNAL(StreamsAdded(Tp::ObjectPathList)), SLOT(onStreamsAdded(Tp::ObjectPathList))); parent->connect(self->contentInterface, SIGNAL(StreamsRemoved(Tp::ObjectPathList,Tp::CallStateReason)), SLOT(onStreamsRemoved(Tp::ObjectPathList,Tp::CallStateReason))); parent->connect(self->contentInterface->requestAllProperties(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotMainProperties(Tp::PendingOperation*))); } void CallContent::Private::checkIntrospectionCompleted() { if (!parent->isReady(FeatureCore) && incompleteStreams.size() == 0) { readinessHelper->setIntrospectCompleted(FeatureCore, true); } } CallStreamPtr CallContent::Private::addStream(const QDBusObjectPath &streamPath) { CallStreamPtr stream = CallStreamPtr( new CallStream(CallContentPtr(parent), streamPath)); incompleteStreams.append(stream); parent->connect(stream->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onStreamReady(Tp::PendingOperation*))); return stream; } CallStreamPtr CallContent::Private::lookupStream(const QDBusObjectPath &streamPath) { foreach (const CallStreamPtr &stream, streams) { if (stream->objectPath() == streamPath.path()) { return stream; } } foreach (const CallStreamPtr &stream, incompleteStreams) { if (stream->objectPath() == streamPath.path()) { return stream; } } return CallStreamPtr(); } /** * \class CallContent * \ingroup clientchannel * \headerfile TelepathyQt/call-content.h * * \brief The CallContent class provides an object representing a Telepathy * Call.Content. * * Instances of this class cannot be constructed directly; the only way to get * one is via CallChannel. * * See \ref async_model */ /** * Feature representing the core that needs to become ready to make the * CallContent object usable. * * Note that this feature must be enabled in order to use most CallContent * methods. See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature CallContent::FeatureCore = Feature(QLatin1String(CallContent::staticMetaObject.className()), 0); /** * Construct a new CallContent object. * * \param channel The channel owning this media content. * \param name The object path of this media content. */ CallContent::CallContent(const CallChannelPtr &channel, const QDBusObjectPath &objectPath) : StatefulDBusProxy(channel->dbusConnection(), channel->busName(), objectPath.path(), FeatureCore), OptionalInterfaceFactory(this), mPriv(new Private(this, channel)) { } /** * Class destructor. */ CallContent::~CallContent() { delete mPriv; } /** * Return the channel owning this media content. * * \return The channel owning this media content. */ CallChannelPtr CallContent::channel() const { return CallChannelPtr(mPriv->channel); } /** * Return the name of this media content. * * \return The name of this media content. */ QString CallContent::name() const { return mPriv->name; } /** * Return the type of this media content. * * \return The type of this media content. */ MediaStreamType CallContent::type() const { return (MediaStreamType) mPriv->type; } /** * Return the disposition of this media content. * * \return The disposition of this media content. */ CallContentDisposition CallContent::disposition() const { return (CallContentDisposition) mPriv->disposition; } /** * Return the media streams of this media content. * * \return A list of media streams of this media content. * \sa streamAdded(), streamRemoved() */ CallStreams CallContent::streams() const { return mPriv->streams; } /** * Removes this media content from the call. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *CallContent::remove() { return new PendingVoid(mPriv->contentInterface->Remove(), CallContentPtr(this)); } /** * Return whether sending DTMF events is supported on this content. * DTMF is only supported on audio contents that implement the * #TP_QT_IFACE_CALL_CONTENT_INTERFACE_DTMF interface. * * \returns \c true if DTMF is supported, or \c false otherwise. */ bool CallContent::supportsDTMF() const { return hasInterface(TP_QT_IFACE_CALL_CONTENT_INTERFACE_DTMF); } /** * Start sending a DTMF tone on this media stream. * * Where possible, the tone will continue until stopDTMFTone() is called. * On certain protocols, it may only be possible to send events with a predetermined * length. In this case, the implementation may emit a fixed-length tone, * and the stopDTMFTone() method call should return #TP_QT_ERROR_NOT_AVAILABLE. * * If this content does not support the #TP_QT_IFACE_CALL_CONTENT_INTERFACE_DTMF * interface, the resulting PendingOperation will fail with error code * #TP_QT_ERROR_NOT_IMPLEMENTED. * * \param event A numeric event code from the #DTMFEvent enum. * \return A PendingOperation which will emit PendingOperation::finished * when the request finishes. * \sa stopDTMFTone(), supportsDTMF() */ PendingOperation *CallContent::startDTMFTone(DTMFEvent event) { if (!supportsDTMF()) { warning() << "CallContent::startDTMFTone() used with no dtmf interface"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("This CallContent does not support the dtmf interface"), CallContentPtr(this)); } Client::CallContentInterfaceDTMFInterface *dtmfInterface = interface(); return new PendingVoid(dtmfInterface->StartTone(event), CallContentPtr(this)); } /** * Stop sending any DTMF tone which has been started using the startDTMFTone() * method. * * If there is no current tone, the resulting PendingOperation will * finish successfully. * * If this content does not support the #TP_QT_IFACE_CALL_CONTENT_INTERFACE_DTMF * interface, the resulting PendingOperation will fail with error code * #TP_QT_ERROR_NOT_IMPLEMENTED. * * \return A PendingOperation which will emit PendingOperation::finished * when the request finishes. * \sa startDTMFTone(), supportsDTMF() */ PendingOperation *CallContent::stopDTMFTone() { if (!supportsDTMF()) { warning() << "CallContent::stopDTMFTone() used with no dtmf interface"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("This CallContent does not support the dtmf interface"), CallContentPtr(this)); } Client::CallContentInterfaceDTMFInterface *dtmfInterface = interface(); return new PendingVoid(dtmfInterface->StopTone(), CallContentPtr(this)); } void CallContent::gotMainProperties(PendingOperation *op) { if (op->isError()) { warning().nospace() << "CallContentInterface::requestAllProperties() failed with" << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, op->errorName(), op->errorMessage()); return; } debug() << "Got reply to CallContentInterface::requestAllProperties()"; PendingVariantMap *pvm = qobject_cast(op); Q_ASSERT(pvm); QVariantMap props = pvm->result(); mPriv->name = qdbus_cast(props[QLatin1String("Name")]); mPriv->type = qdbus_cast(props[QLatin1String("Type")]); mPriv->disposition = qdbus_cast(props[QLatin1String("Disposition")]); setInterfaces(qdbus_cast(props[QLatin1String("Interfaces")])); ObjectPathList streamsPaths = qdbus_cast(props[QLatin1String("Streams")]); if (streamsPaths.size() != 0) { foreach (const QDBusObjectPath &streamPath, streamsPaths) { CallStreamPtr stream = mPriv->lookupStream(streamPath); if (!stream) { mPriv->addStream(streamPath); } } } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } } void CallContent::onStreamsAdded(const ObjectPathList &streamsPaths) { foreach (const QDBusObjectPath &streamPath, streamsPaths) { debug() << "Received Call::Content::StreamAdded for stream" << streamPath.path(); if (mPriv->lookupStream(streamPath)) { debug() << "Stream already exists, ignoring"; return; } mPriv->addStream(streamPath); } } void CallContent::onStreamsRemoved(const ObjectPathList &streamsPaths, const CallStateReason &reason) { foreach (const QDBusObjectPath &streamPath, streamsPaths) { debug() << "Received Call::Content::StreamRemoved for stream" << streamPath.path(); CallStreamPtr stream = mPriv->lookupStream(streamPath); if (!stream) { debug() << "Stream does not exist, ignoring"; return; } bool incomplete = mPriv->incompleteStreams.contains(stream); if (incomplete) { mPriv->incompleteStreams.removeOne(stream); } else { mPriv->streams.removeOne(stream); } if (isReady(FeatureCore) && !incomplete) { emit streamRemoved(stream, reason); } mPriv->checkIntrospectionCompleted(); } } void CallContent::onStreamReady(PendingOperation *op) { PendingReady *pr = qobject_cast(op); CallStreamPtr stream = CallStreamPtr::qObjectCast(pr->proxy()); if (op->isError() || !mPriv->incompleteStreams.contains(stream)) { mPriv->incompleteStreams.removeOne(stream); mPriv->checkIntrospectionCompleted(); return; } mPriv->incompleteStreams.removeOne(stream); mPriv->streams.append(stream); if (isReady(FeatureCore)) { emit streamAdded(stream); } mPriv->checkIntrospectionCompleted(); } /** * \fn void CallContent::streamAdded(const Tp::CallStreamPtr &stream); * * This signal is emitted when a new media stream is added to this media * content. * * \param stream The media stream that was added. * \sa streams() */ /** * \fn void CallContent::streamRemoved(const Tp::CallStreamPtr &stream, const Tp::CallStateReason &reason); * * This signal is emitted when a new media stream is removed from this media * content. * * \param stream The media stream that was removed. * \param reason The reason for this removal. * \sa streams() */ /* ====== PendingCallContent ====== */ struct TP_QT_NO_EXPORT PendingCallContent::Private { Private(PendingCallContent *parent, const CallChannelPtr &channel) : parent(parent), channel(channel) { } PendingCallContent *parent; CallChannelPtr channel; CallContentPtr content; }; PendingCallContent::PendingCallContent(const CallChannelPtr &channel, const QString &name, MediaStreamType type, MediaStreamDirection direction) : PendingOperation(channel), mPriv(new Private(this, channel)) { Client::ChannelTypeCallInterface *callInterface = channel->interface(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( callInterface->AddContent(name, type, direction), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotContent(QDBusPendingCallWatcher*))); } PendingCallContent::~PendingCallContent() { delete mPriv; } CallContentPtr PendingCallContent::content() const { if (!isFinished() || !isValid()) { return CallContentPtr(); } return mPriv->content; } void PendingCallContent::gotContent(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { warning().nospace() << "Call::AddContent failed with " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); watcher->deleteLater(); return; } QDBusObjectPath contentPath = reply.value(); CallChannelPtr channel(mPriv->channel); CallContentPtr content = channel->lookupContent(contentPath); if (!content) { content = channel->addContent(contentPath); } connect(content->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContentReady(Tp::PendingOperation*))); connect(channel.data(), SIGNAL(contentRemoved(Tp::CallContentPtr,Tp::CallStateReason)), SLOT(onContentRemoved(Tp::CallContentPtr))); mPriv->content = content; watcher->deleteLater(); } void PendingCallContent::onContentReady(PendingOperation *op) { if (op->isError()) { setFinishedWithError(op->errorName(), op->errorMessage()); return; } setFinished(); } void PendingCallContent::onContentRemoved(const CallContentPtr &content) { if (isFinished()) { return; } if (mPriv->content == content) { // the content was removed before becoming ready setFinishedWithError(TP_QT_ERROR_CANCELLED, QLatin1String("Content removed before ready")); } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/BaseProtocolAvatarsInterface0000664000175000017500000000042312470405660022675 0ustar jrjr#ifndef _TelepathyQt_BaseProtocolAvatarsInterface_HEADER_GUARD_ #define _TelepathyQt_BaseProtocolAvatarsInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceConferenceInterface0000664000175000017500000000043312470405660024141 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceConferenceInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceConferenceInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/profile-manager.cpp0000664000175000017500000002600412470405660020772 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/profile-manager.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ProfileManager::Private { Private(ProfileManager *parent, const QDBusConnection &bus); static void introspectMain(Private *self); static void introspectFakeProfiles(Private *self); ProfileManager *parent; ReadinessHelper *readinessHelper; QDBusConnection bus; QHash profiles; QList cms; }; ProfileManager::Private::Private(ProfileManager *parent, const QDBusConnection &bus) : parent(parent), readinessHelper(parent->readinessHelper()), bus(bus) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMain, this); introspectables[FeatureCore] = introspectableCore; ReadinessHelper::Introspectable introspectableFakeProfiles( QSet() << 0, // makesSenseForStatuses Features() << FeatureCore, // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectFakeProfiles, this); introspectables[FeatureFakeProfiles] = introspectableFakeProfiles; readinessHelper->addIntrospectables(introspectables); } void ProfileManager::Private::introspectMain(ProfileManager::Private *self) { QStringList searchDirs = Profile::searchDirs(); foreach (const QString searchDir, searchDirs) { QDir dir(searchDir); dir.setFilter(QDir::Files); QFileInfoList list = dir.entryInfoList(); for (int i = 0; i < list.size(); ++i) { QFileInfo fi = list.at(i); if (fi.completeSuffix() != QLatin1String("profile")) { continue; } QString fileName = fi.absoluteFilePath(); QString serviceName = fi.baseName(); if (self->profiles.contains(serviceName)) { debug() << "Profile for service" << serviceName << "already " "exists. Ignoring profile file:" << fileName; continue; } ProfilePtr profile = Profile::createForFileName(fileName); if (!profile->isValid()) { continue; } if (profile->type() != QLatin1String("IM")) { debug() << "Ignoring profile for service" << serviceName << ": type != IM. Profile file:" << fileName; continue; } debug() << "Found profile for service" << serviceName << "- profile file:" << fileName; self->profiles.insert(serviceName, profile); } } self->readinessHelper->setIntrospectCompleted(FeatureCore, true); } void ProfileManager::Private::introspectFakeProfiles(ProfileManager::Private *self) { PendingStringList *pendingCmNames = ConnectionManager::listNames(self->bus); self->parent->connect(pendingCmNames, SIGNAL(finished(Tp::PendingOperation *)), SLOT(onCmNamesRetrieved(Tp::PendingOperation *))); } /** * \class ProfileManager * \headerfile TelepathyQt/profile-manager.h * * \brief The ProfileManager class provides helper methods to retrieve Profile * objects. */ /** * Feature representing the core that needs to become ready to make the ProfileManager * object usable. * * Note that this feature must be enabled in order to use all ProfileManager methods. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature ProfileManager::FeatureCore = Feature(QLatin1String(ProfileManager::staticMetaObject.className()), 0, true); /** * Enabling this feature will make ProfileManager create fake Profile objects to all protocols * supported on the installed connection managers, even if they don't have .profile files installed * making use of them. * * Fake profiles are identified by Profile::isFake() returning \c true. * * The fake profile will contain the following info: * - Profile::type() will return "IM" * - Profile::provider() will return an empty string * - Profile::serviceName() will return cmName-protocolName * - Profile::name() and Profile::protocolName() will return protocolName * - Profile::iconName() will return "im-protocolName" * - Profile::cmName() will return cmName * - Profile::parameters() will return a list matching CM default parameters for protocol with name * protocolName. * - Profile::presences() will return an empty list and * Profile::allowOtherPresences() will return \c true, meaning that CM * presences should be used * - Profile::unsupportedChannelClassSpecs() will return an empty list * * Where cmName and protocolName are the name of the connection manager and the name of the protocol * for which this fake Profile is created, respectively. */ const Feature ProfileManager::FeatureFakeProfiles = Feature(QLatin1String(ProfileManager::staticMetaObject.className()), 1); /** * Create a new ProfileManager object. */ ProfileManagerPtr ProfileManager::create(const QDBusConnection &bus) { return ProfileManagerPtr(new ProfileManager(bus)); } /** * Construct a new ProfileManager object. */ ProfileManager::ProfileManager(const QDBusConnection &bus) : Object(), ReadyObject(this, FeatureCore), mPriv(new Private(this, bus)) { } /** * Class destructor. */ ProfileManager::~ProfileManager() { delete mPriv; } /** * Return a list of all available profiles. * * \return A list of all available profiles. */ QList ProfileManager::profiles() const { return mPriv->profiles.values(); } /** * Return a list of all available profiles for a given connection manager. * * \param cmName Connection manager name. * \return A list of all available profiles for a given connection manager. */ QList ProfileManager::profilesForCM(const QString &cmName) const { QList ret; foreach (const ProfilePtr &profile, mPriv->profiles) { if (profile->cmName() == cmName) { ret << profile; } } return ret; } /** * Return a list of all available profiles for a given \a protocol. * * \param protocolName Protocol name. * \return A list of all available profiles for a given \a protocol. */ QList ProfileManager::profilesForProtocol( const QString &protocolName) const { QList ret; foreach (const ProfilePtr &profile, mPriv->profiles) { if (profile->protocolName() == protocolName) { ret << profile; } } return ret; } /** * Return the profile for a given \a service. * * \param serviceName Service name. * \return The profile for \a service. */ ProfilePtr ProfileManager::profileForService(const QString &serviceName) const { return mPriv->profiles.value(serviceName); } void ProfileManager::onCmNamesRetrieved(Tp::PendingOperation *op) { if (op->isError()) { warning().nospace() << "Getting available CMs failed with " << op->errorName() << ":" << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureFakeProfiles, false, op->errorName(), op->errorMessage()); return; } PendingStringList *pendingCmNames = qobject_cast(op); QStringList cmNames(pendingCmNames->result()); if (cmNames.isEmpty()) { mPriv->readinessHelper->setIntrospectCompleted(FeatureFakeProfiles, true); return; } QList ops; foreach (const QString &cmName, cmNames) { ConnectionManagerPtr cm = ConnectionManager::create(mPriv->bus, cmName); mPriv->cms.append(cm); ops.append(cm->becomeReady()); } PendingComposite *pc = new PendingComposite(ops, false, ProfileManagerPtr(this)); connect(pc, SIGNAL(finished(Tp::PendingOperation *)), SLOT(onCMsReady(Tp::PendingOperation *))); } void ProfileManager::onCMsReady(Tp::PendingOperation *op) { if (op->isError()) { warning() << "Failed introspecting all CMs, trying to create fake profiles anyway"; } ProfilePtr profile; foreach (const ConnectionManagerPtr &cm, mPriv->cms) { if (!cm->isReady()) { continue; } foreach (const QString &protocolName, cm->supportedProtocols()) { /* check if there is a profile whose service name is protocolName, and if found, * check if the profile is for cm, if not check if there is a profile whose service * name is cm-protocolName, and if not found create one named cm-protocolName. */ profile = profileForService(protocolName); if (profile && profile->cmName() == cm->name()) { continue; } QString serviceName = QString(QLatin1String("%1-%2")).arg(cm->name()).arg(protocolName); profile = profileForService(serviceName); if (profile) { continue; } profile = ProfilePtr(new Profile( serviceName, cm->name(), protocolName, cm->protocol(protocolName))); mPriv->profiles.insert(serviceName, profile); } } mPriv->readinessHelper->setIntrospectCompleted(FeatureFakeProfiles, true); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/pending-ready.cpp0000664000175000017500000001041312470405660020445 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-ready.moc.hpp" #include "TelepathyQt/debug-internal.h" #include namespace Tp { struct TP_QT_NO_EXPORT PendingReady::Private { Private(const DBusProxyPtr &proxy, const Features &requestedFeatures) : proxy(proxy), requestedFeatures(requestedFeatures) { } DBusProxyPtr proxy; Features requestedFeatures; }; /** * \class PendingReady * \ingroup utils * \headerfile TelepathyQt/pending-ready.h * * \brief The PendingReady class represents the features requested and the reply * to a request for an object to become ready. * * Instances of this class cannot be constructed directly; the only way to get * one is via ReadyObject::becomeReady() or a DBusProxyFactory subclass. * * See \ref async_model */ /** * Construct a new PendingReady object. * * \todo Actually make it do the prepare ops. Currently they aren't taken into account in any way. * * \param object The object that will become ready. * \param requestedFeatures Features to be made ready on the object. */ PendingReady::PendingReady(const SharedPtr &object, const Features &requestedFeatures) : PendingOperation(object), mPriv(new Private(DBusProxyPtr(dynamic_cast((DBusProxy*) object.data())), requestedFeatures)) { // This is a PendingReady created by ReadinessHelper, and will be set ready by it - so should // not do anything ourselves here. } /** * Construct a new PendingReady object. * * \todo Actually make it do the prepare ops. Currently they aren't taken into account in any way. * * \param factory The factory the request was made with. * \param proxy The proxy that will become ready. * \param requestedFeatures Features to be made ready on the object. */ PendingReady::PendingReady(const SharedPtr &factory, const DBusProxyPtr &proxy, const Features &requestedFeatures) : PendingOperation(factory), mPriv(new Private(proxy, requestedFeatures)) { if (requestedFeatures.isEmpty()) { setFinished(); return; } connect(proxy->becomeReady(requestedFeatures), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onNestedFinished(Tp::PendingOperation*))); } /** * Class destructor. */ PendingReady::~PendingReady() { delete mPriv; } /** * Return the proxy that should become ready. * * \return A pointer to the DBusProxy object if the operation was * created by a proxy object or a DBusProxyFactory, * otherwise a null DBusProxyPtr. */ DBusProxyPtr PendingReady::proxy() const { return mPriv->proxy; } /** * Return the features that were requested to become ready on the * object. * * \return The requested features as a set of Feature objects. */ Features PendingReady::requestedFeatures() const { return mPriv->requestedFeatures; } void PendingReady::onNestedFinished(Tp::PendingOperation *nested) { Q_ASSERT(nested->isFinished()); if (nested->isValid()) { setFinished(); } else { warning() << "Nested PendingReady for" << object() << "failed with" << nested->errorName() << ":" << nested->errorMessage(); setFinishedWithError(nested->errorName(), nested->errorMessage()); } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeTubesInterface0000664000175000017500000000040712470405660022176 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeTubesInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeTubesInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/stream-tube-channel.h0000664000175000017500000000637312470405660021234 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_stream_tube_channel_h_HEADER_GUARD_ #define _TelepathyQt_stream_tube_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include class QHostAddress; namespace Tp { class TP_QT_EXPORT StreamTubeChannel : public TubeChannel { Q_OBJECT Q_DISABLE_COPY(StreamTubeChannel) public: static const Feature FeatureCore; static const Feature FeatureConnectionMonitoring; static StreamTubeChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~StreamTubeChannel(); QString service() const; bool supportsIPv4SocketsOnLocalhost() const; bool supportsIPv4SocketsWithSpecifiedAddress() const; bool supportsIPv6SocketsOnLocalhost() const; bool supportsIPv6SocketsWithSpecifiedAddress() const; bool supportsUnixSocketsOnLocalhost() const; bool supportsUnixSocketsWithCredentials() const; bool supportsAbstractUnixSocketsOnLocalhost() const; bool supportsAbstractUnixSocketsWithCredentials() const; QSet connections() const; SocketAddressType addressType() const; QPair< QHostAddress, quint16 > ipAddress() const; QString localAddress() const; Q_SIGNALS: void newConnection(uint connectionId); void connectionClosed(uint connectionId, const QString &errorName, const QString &errorMessage); protected: StreamTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = StreamTubeChannel::FeatureCore); void addConnection(uint connection); void removeConnection(uint connection, const QString &error, const QString &message); void setAddressType(SocketAddressType type); SocketAccessControl accessControl() const; void setAccessControl(SocketAccessControl accessControl); void setIpAddress(const QPair &address); void setLocalAddress(const QString &address); bool isDroppingConnections() const; private Q_SLOTS: TP_QT_NO_EXPORT void gotStreamTubeProperties(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onConnectionClosed(uint, const QString &, const QString &); TP_QT_NO_EXPORT void dropConnections(); private: struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/OutgoingFileTransferChannel0000664000175000017500000000044212470405660022530 0ustar jrjr#ifndef _TelepathyQt_OutgoingFileTransferChannel_HEADER_GUARD_ #define _TelepathyQt_OutgoingFileTransferChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/requestable-channel-class-spec.cpp0000664000175000017500000004775612470405660023720 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include namespace Tp { struct TP_QT_NO_EXPORT RequestableChannelClassSpec::Private : public QSharedData { Private(const RequestableChannelClass &rcc) : rcc(rcc) {} RequestableChannelClass rcc; }; /** * \class RequestableChannelClassSpec * \ingroup wrappers * \headerfile TelepathyQt/requestable-channel-class-spec.h * * \brief The RequestableChannelClassSpec class represents a Telepathy * requestable channel class. */ RequestableChannelClassSpec::RequestableChannelClassSpec(const RequestableChannelClass &rcc) : mPriv(new Private(rcc)) { } RequestableChannelClassSpec::RequestableChannelClassSpec() { } RequestableChannelClassSpec::RequestableChannelClassSpec(const RequestableChannelClassSpec &other) : mPriv(other.mPriv) { } RequestableChannelClassSpec::~RequestableChannelClassSpec() { } RequestableChannelClassSpec RequestableChannelClassSpec::textChat() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::textChatroom() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeRoom); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::audioCall() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"), true); rcc.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudioName")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::audioCallWithVideoAllowed() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"), true); rcc.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudioName")); rcc.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo")); rcc.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideoName")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::videoCall() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo"), true); rcc.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideoName")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::videoCallWithAudioAllowed() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CALL); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo"), true); rcc.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideoName")); rcc.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio")); rcc.allowedProperties.append(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudioName")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::streamedMediaCall() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::streamedMediaAudioCall() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::streamedMediaVideoCall() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::streamedMediaVideoCallWithAudio() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialAudio")); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA + QLatin1String(".InitialVideo")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::fileTransfer() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_FILE_TRANSFER); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::conferenceTextChat() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::conferenceTextChatWithInvitees() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::conferenceTextChatroom() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeRoom); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::conferenceTextChatroomWithInvitees() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_TEXT); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeRoom); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::conferenceStreamedMediaCall() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::conferenceStreamedMediaCallWithInvitees() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::contactSearch() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::contactSearchWithSpecificServer() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Server")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::contactSearchWithLimit() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Limit")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::contactSearchWithSpecificServerAndLimit() { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Server")); rcc.allowedProperties.append( TP_QT_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Limit")); spec = RequestableChannelClassSpec(rcc); } return spec; } RequestableChannelClassSpec RequestableChannelClassSpec::dbusTube(const QString &serviceName) { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); spec = RequestableChannelClassSpec(rcc); } if (serviceName.isEmpty()) { return spec; } RequestableChannelClass rcc = spec.bareClass(); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL_TYPE_DBUS_TUBE + QLatin1String(".ServiceName"), serviceName); return RequestableChannelClassSpec(rcc); } RequestableChannelClassSpec RequestableChannelClassSpec::streamTube(const QString &service) { static RequestableChannelClassSpec spec; if (!spec.isValid()) { RequestableChannelClass rcc; rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeContact); spec = RequestableChannelClassSpec(rcc); } if (service.isEmpty()) { return spec; } RequestableChannelClass rcc = spec.bareClass(); rcc.fixedProperties.insert(TP_QT_IFACE_CHANNEL_TYPE_STREAM_TUBE + QLatin1String(".Service"), service); return RequestableChannelClassSpec(rcc); } RequestableChannelClassSpec &RequestableChannelClassSpec::operator=(const RequestableChannelClassSpec &other) { this->mPriv = other.mPriv; return *this; } bool RequestableChannelClassSpec::operator==(const RequestableChannelClassSpec &other) const { if (!isValid() || !other.isValid()) { if (!isValid() && !other.isValid()) { return true; } return false; } return mPriv->rcc == other.mPriv->rcc; } bool RequestableChannelClassSpec::supports(const RequestableChannelClassSpec &other) const { if (!isValid()) { return false; } if (mPriv->rcc.fixedProperties == other.fixedProperties()) { foreach (const QString &prop, other.allowedProperties()) { if (!mPriv->rcc.allowedProperties.contains(prop)) { return false; } } return true; } return false; } QString RequestableChannelClassSpec::channelType() const { if (!isValid()) { return QString(); } return qdbus_cast(mPriv->rcc.fixedProperties.value( TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"))); } bool RequestableChannelClassSpec::hasTargetHandleType() const { if (!isValid()) { return false; } return mPriv->rcc.fixedProperties.contains( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")); } HandleType RequestableChannelClassSpec::targetHandleType() const { if (!hasTargetHandleType()) { return (HandleType) -1; } return (HandleType) qdbus_cast(mPriv->rcc.fixedProperties.value( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"))); } bool RequestableChannelClassSpec::hasFixedProperty(const QString &name) const { if (!isValid()) { return false; } return mPriv->rcc.fixedProperties.contains(name); } QVariant RequestableChannelClassSpec::fixedProperty(const QString &name) const { if (!isValid()) { return QVariant(); } return mPriv->rcc.fixedProperties.value(name); } QVariantMap RequestableChannelClassSpec::fixedProperties() const { if (!isValid()) { return QVariantMap(); } return mPriv->rcc.fixedProperties; } bool RequestableChannelClassSpec::allowsProperty(const QString &name) const { if (!isValid()) { return false; } return mPriv->rcc.allowedProperties.contains(name); } QStringList RequestableChannelClassSpec::allowedProperties() const { if (!isValid()) { return QStringList(); } return mPriv->rcc.allowedProperties; } RequestableChannelClass RequestableChannelClassSpec::bareClass() const { return isValid() ? mPriv->rcc : RequestableChannelClass(); } /** * \class RequestableChannelClassSpecList * \ingroup wrappers * \headerfile TelepathyQt/requestable-channel-class-spec.h * * \brief The RequestableChannelClassSpecList class represents a list of * RequestableChannelClassSpec. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/file-transfer-channel.h0000664000175000017500000000614412470405660021541 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_file_transfer_channel_h_HEADER_GUARD_ #define _TelepathyQt_file_transfer_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class TP_QT_EXPORT FileTransferChannel : public Channel { Q_OBJECT Q_DISABLE_COPY(FileTransferChannel) public: static const Feature FeatureCore; static FileTransferChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~FileTransferChannel(); FileTransferState state() const; FileTransferStateChangeReason stateReason() const; QString fileName() const; QString contentType() const; qulonglong size() const; QString uri() const; FileHashType contentHashType() const; QString contentHash() const; QString description() const; QDateTime lastModificationTime() const; qulonglong initialOffset() const; qulonglong transferredBytes() const; PendingOperation *cancel(); Q_SIGNALS: void stateChanged(Tp::FileTransferState state, Tp::FileTransferStateChangeReason reason); void initialOffsetDefined(qulonglong initialOffset); void transferredBytesChanged(qulonglong count); protected: FileTransferChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = FileTransferChannel::FeatureCore); SupportedSocketMap availableSocketTypes() const; virtual void connectToHost(); bool isConnected() const; void setConnected(); bool isFinished() const; virtual void setFinished(); private Q_SLOTS: TP_QT_NO_EXPORT void gotProperties(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void changeState(); TP_QT_NO_EXPORT void onStateChanged(uint state, uint stateReason); TP_QT_NO_EXPORT void onInitialOffsetDefined(qulonglong initialOffset); TP_QT_NO_EXPORT void onTransferredBytesChanged(qulonglong count); protected Q_SLOTS: TP_QT_NO_EXPORT void onUriDefined(const QString &uri); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/pending-debug-message-list.h0000664000175000017500000000327012470405660022472 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011-2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_debug_message_list_h_HEADER_GUARD_ #define _TelepathyQt_pending_debug_message_list_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT PendingDebugMessageList : public Tp::PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingDebugMessageList) public: virtual ~PendingDebugMessageList(); DebugMessageList result() const; private Q_SLOTS: TP_QT_NO_EXPORT void watcherFinished(QDBusPendingCallWatcher*); private: friend class DebugReceiver; TP_QT_NO_EXPORT PendingDebugMessageList(const QDBusPendingCall &call, const SharedPtr &object); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ProtocolInterfacePresenceInterface0000664000175000017500000000044412470405660024071 0ustar jrjr#ifndef _TelepathyQt_ProtocolInterfacePresenceInterface_HEADER_GUARD_ #define _TelepathyQt_ProtocolInterfacePresenceInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceMailNotificationInterface0000664000175000017500000000046012470405660026052 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceMailNotificationInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceMailNotificationInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-operation.h0000664000175000017500000000425312470405660021013 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_operation_h_HEADER_GUARD_ #define _TelepathyQt_pending_operation_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include class QDBusError; class QDBusPendingCall; class QDBusPendingCallWatcher; namespace Tp { class ReadinessHelper; class TP_QT_EXPORT PendingOperation : public QObject { Q_OBJECT Q_DISABLE_COPY(PendingOperation) public: virtual ~PendingOperation(); bool isFinished() const; bool isValid() const; bool isError() const; QString errorName() const; QString errorMessage() const; Q_SIGNALS: void finished(Tp::PendingOperation *operation); protected: PendingOperation(const SharedPtr &object); SharedPtr object() const; protected Q_SLOTS: void setFinished(); void setFinishedWithError(const QString &name, const QString &message); void setFinishedWithError(const QDBusError &error); private Q_SLOTS: TP_QT_NO_EXPORT void emitFinished(); private: friend class ContactManager; friend class ReadinessHelper; struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/PendingContactInfo0000664000175000017500000000040612470405660020653 0ustar jrjr#ifndef _TelepathyQt_PendingContactInfo_HEADER_GUARD_ #define _TelepathyQt_PendingContactInfo_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ClientInterface0000664000175000017500000000036212470405660020177 0ustar jrjr#ifndef _TelepathyQt_ClientInterface_HEADER_GUARD_ #define _TelepathyQt_ClientInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/text-channel.h0000664000175000017500000001120512470405660017756 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_text_channel_h_HEADER_GUARD_ #define _TelepathyQt_text_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class Message; class ReceivedMessage; class TP_QT_EXPORT TextChannel : public Channel { Q_OBJECT Q_DISABLE_COPY(TextChannel) public: static const Feature FeatureCore; static const Feature FeatureMessageQueue; static const Feature FeatureMessageCapabilities; static const Feature FeatureMessageSentSignal; static const Feature FeatureChatState; static TextChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~TextChannel(); bool hasMessagesInterface() const; bool hasChatStateInterface() const; bool canInviteContacts() const; // requires FeatureMessageCapabilities bool supportsMessageType(ChannelTextMessageType messageType) const; QList supportedMessageTypes() const; QStringList supportedContentTypes() const; MessagePartSupportFlags messagePartSupport() const; DeliveryReportingSupportFlags deliveryReportingSupport() const; // requires FeatureMessageQueue QList messageQueue() const; // requires FeatureChatState ChannelChatState chatState(const ContactPtr &contact) const; public Q_SLOTS: void acknowledge(const QList &messages); void forget(const QList &messages); PendingSendMessage *send(const QString &text, ChannelTextMessageType type = ChannelTextMessageTypeNormal, MessageSendingFlags flags = 0); PendingSendMessage *send(const MessagePartList &parts, MessageSendingFlags flags = 0); inline PendingOperation *inviteContacts( const QList &contacts, const QString &message = QString()) { return groupAddContacts(contacts, message); } PendingOperation *requestChatState(ChannelChatState state); Q_SIGNALS: // FeatureMessageSentSignal void messageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken); // FeatureMessageQueue void messageReceived(const Tp::ReceivedMessage &message); void pendingMessageRemoved( const Tp::ReceivedMessage &message); // FeatureChatState void chatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state); protected: TextChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = TextChannel::FeatureCore); private Q_SLOTS: TP_QT_NO_EXPORT void onContactsFinished(Tp::PendingOperation *); TP_QT_NO_EXPORT void onAcknowledgePendingMessagesReply(QDBusPendingCallWatcher *); TP_QT_NO_EXPORT void onMessageSent(const Tp::MessagePartList &, uint, const QString &); TP_QT_NO_EXPORT void onMessageReceived(const Tp::MessagePartList &); TP_QT_NO_EXPORT void onPendingMessagesRemoved(const Tp::UIntList &); TP_QT_NO_EXPORT void onTextSent(uint, uint, const QString &); TP_QT_NO_EXPORT void onTextReceived(uint, uint, uint, uint, uint, const QString &); TP_QT_NO_EXPORT void onTextSendError(uint, uint, uint, const QString &); TP_QT_NO_EXPORT void gotProperties(QDBusPendingCallWatcher *); TP_QT_NO_EXPORT void gotPendingMessages(QDBusPendingCallWatcher *); TP_QT_NO_EXPORT void onChatStateChanged(uint, uint); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/pending-send-message.h0000664000175000017500000000421212470405660021361 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_send_message_h_HEADER_GUARD_ #define _TelepathyQt_pending_send_message_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include class QDBusPendingCallWatcher; class QString; namespace Tp { class Message; class TP_QT_EXPORT PendingSendMessage : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingSendMessage) public: ~PendingSendMessage(); TextChannelPtr channel() const; ContactMessengerPtr messenger() const; QString sentMessageToken() const; Message message() const; private Q_SLOTS: TP_QT_NO_EXPORT void onTextSent(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onMessageSent(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onCDMessageSent(QDBusPendingCallWatcher *watcher); private: friend class TextChannel; friend class ContactMessenger; TP_QT_NO_EXPORT PendingSendMessage(const TextChannelPtr &channel, const Message &message); TP_QT_NO_EXPORT PendingSendMessage(const ContactMessengerPtr &messenger, const Message &message); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/pending-debug-message-list.cpp0000664000175000017500000000372012470405660023025 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011-2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-debug-message-list.moc.hpp" #include namespace Tp { struct TP_QT_NO_EXPORT PendingDebugMessageList::Private { DebugMessageList result; }; PendingDebugMessageList::PendingDebugMessageList(const QDBusPendingCall &call, const SharedPtr &object) : PendingOperation(object), mPriv(new Private) { connect(new QDBusPendingCallWatcher(call), SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(watcherFinished(QDBusPendingCallWatcher*))); } PendingDebugMessageList::~PendingDebugMessageList() { delete mPriv; } DebugMessageList PendingDebugMessageList::result() const { return mPriv->result; } void PendingDebugMessageList::watcherFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (reply.isError()) { setFinishedWithError(reply.error()); } else { mPriv->result = reply.value(); setFinished(); } watcher->deleteLater(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/BaseProtocol0000664000175000017500000000036312470405660017535 0ustar jrjr#ifndef _TelepathyQt_BaseProtocol_HEADER_GUARD_ #define _TelepathyQt_BaseProtocol_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/debug-internal.h0000664000175000017500000000633612470405660020275 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_debug_HEADER_GUARD_ #define _TelepathyQt_debug_HEADER_GUARD_ #include #include namespace Tp { class TP_QT_EXPORT Debug { public: inline Debug() : debug(0) { } inline Debug(QtMsgType type) : type(type), debug(new QDebug(&msg)) { } inline Debug(const Debug &a) : type(a.type), debug(a.debug ? new QDebug(&msg) : 0) { if (debug) { (*debug) << qPrintable(a.msg); } } inline Debug &operator=(const Debug &a) { if (this != &a) { type = a.type; delete debug; debug = 0; if (a.debug) { debug = new QDebug(&msg); (*debug) << qPrintable(a.msg); } } return *this; } inline ~Debug() { if (!msg.isEmpty()) { invokeDebugCallback(); } delete debug; } inline Debug &space() { if (debug) { debug->space(); } return *this; } inline Debug &nospace() { if (debug) { debug->nospace(); } return *this; } inline Debug &maybeSpace() { if (debug) { debug->maybeSpace(); } return *this; } template inline Debug &operator<<(T a) { if (debug) { (*debug) << a; } return *this; } private: QString msg; QtMsgType type; QDebug *debug; void invokeDebugCallback(); }; // The telepathy-farsight Qt 4 binding links to these - they're not API outside // this source tarball, but they *are* ABI TP_QT_EXPORT Debug enabledDebug(); TP_QT_EXPORT Debug enabledWarning(); #ifdef ENABLE_DEBUG inline Debug debug() { return enabledDebug(); } inline Debug warning() { return enabledWarning(); } #else /* #ifdef ENABLE_DEBUG */ struct NoDebug { template NoDebug& operator<<(const T&) { return *this; } NoDebug& space() { return *this; } NoDebug& nospace() { return *this; } NoDebug& maybeSpace() { return *this; } }; inline NoDebug debug() { return NoDebug(); } inline NoDebug warning() { return NoDebug(); } #endif /* #ifdef ENABLE_DEBUG */ } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/debug-receiver.h0000664000175000017500000000420212470405660020253 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011-2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_debug_receiver_h_HEADER_GUARD_ #define _TelepathyQt_debug_receiver_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include namespace Tp { class PendingDebugMessageList; class TP_QT_EXPORT DebugReceiver : public StatefulDBusProxy { Q_OBJECT Q_DISABLE_COPY(DebugReceiver) public: static const Feature FeatureCore; static DebugReceiverPtr create(const QString &busName, const QDBusConnection &bus = QDBusConnection::sessionBus()); virtual ~DebugReceiver(); PendingDebugMessageList *fetchMessages(); PendingOperation *setMonitoringEnabled(bool enabled); Q_SIGNALS: void newDebugMessage(const Tp::DebugMessage & message); protected: DebugReceiver(const QDBusConnection &bus, const QString &busName); private Q_SLOTS: TP_QT_NO_EXPORT void onRequestAllPropertiesFinished(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onNewDebugMessage(double time, const QString &domain, uint level, const QString &message); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/pending-connection.cpp0000664000175000017500000001242112470405660021501 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-connection.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingConnection::Private { ConnectionPtr connection; }; /** * \class PendingConnection * \ingroup clientconn * \headerfile TelepathyQt/pending-connection.h * * \brief The PendingConnection class represents the parameters of and the reply * to an asynchronous connection request. * * Instances of this class cannot be constructed directly; the only way to get * one is via ConnectionManager. * * See \ref async_model */ /** * Construct a new PendingConnection object. * * \param manager ConnectionManager to use. * \param protocol Name of the protocol to create the connection for. * \param parameters Connection parameters. */ PendingConnection::PendingConnection(const ConnectionManagerPtr &manager, const QString &protocol, const QVariantMap ¶meters) : PendingOperation(manager), mPriv(new Private) { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( manager->baseInterface()->RequestConnection(protocol, parameters), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onCallFinished(QDBusPendingCallWatcher*))); } /** * Construct a new PendingConnection object that will fail immediately. * * \param error Name of the error to fail with. * \param errorMessage Detail message for the error. */ PendingConnection::PendingConnection(const QString &error, const QString &errorMessage) : PendingOperation(ConnectionManagerPtr()), mPriv(new Private) { setFinishedWithError(error, errorMessage); } /** * Class destructor. */ PendingConnection::~PendingConnection() { delete mPriv; } /** * Return the connection manager through which the request was made. * * \return A pointer to the ConnectionManager object. */ ConnectionManagerPtr PendingConnection::manager() const { return ConnectionManagerPtr(qobject_cast((ConnectionManager*) object().data())); } /** * Return the connection resulting from the connection request. * * \return A pointer to the Connection object. */ ConnectionPtr PendingConnection::connection() const { if (!isFinished()) { warning() << "PendingConnection::connection called before finished, returning 0"; return ConnectionPtr(); } else if (!isValid()) { warning() << "PendingConnection::connection called when not valid, returning 0"; return ConnectionPtr(); } return mPriv->connection; } void PendingConnection::onCallFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { QString busName = reply.argumentAt<0>(); QString objectPath = reply.argumentAt<1>().path(); debug() << "Got reply to ConnectionManager.CreateConnection - bus name:" << busName << "- object path:" << objectPath; PendingReady *readyOp = manager()->connectionFactory()->proxy(busName, objectPath, manager()->channelFactory(), manager()->contactFactory()); mPriv->connection = ConnectionPtr::qObjectCast(readyOp->proxy()); connect(readyOp, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onConnectionBuilt(Tp::PendingOperation*))); } else { debug().nospace() << "CreateConnection failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } void PendingConnection::onConnectionBuilt(Tp::PendingOperation *op) { Q_ASSERT(op->isFinished()); if (op->isError()) { warning() << "Making connection ready using the factory failed:" << op->errorName() << op->errorMessage(); setFinishedWithError(op->errorName(), op->errorMessage()); } else { setFinished(); debug() << "New connection" << mPriv->connection->objectPath() << "built"; } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceDTMFInterface0000664000175000017500000000041712470405660022626 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceDTMFInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceDTMFInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PresenceSpecList0000664000175000017500000000036612470405660020357 0ustar jrjr#ifndef _TelepathyQt_PresenceSpecList_HEADER_GUARD_ #define _TelepathyQt_PresenceSpecList_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/PendingDebugMessageList0000664000175000017500000000042612470405660021635 0ustar jrjr#ifndef _TelepathyQt_PendingDebugMessageList_HEADER_GUARD_ #define _TelepathyQt_PendingDebugMessageList_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Message0000664000175000017500000000034312470405660016523 0ustar jrjr#ifndef _TelepathyQt_Message_HEADER_GUARD_ #define _TelepathyQt_Message_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/properties.h0000664000175000017500000000334712470405660017570 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_properties_h_HEADER_GUARD_ #define _TelepathyQt_properties_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif /** * \addtogroup clientsideproxies Client-side proxies * * Proxy objects representing remote service objects accessed via D-Bus. * * In addition to providing direct access to methods, signals and properties * exported by the remote objects, some of these proxies offer features like * automatic inspection of remote object capabilities, property tracking, * backwards compatibility helpers for older services and other utilities. */ /** * \defgroup clientprops Telepathy Properties proxy * \ingroup clientsideproxies * * Proxy object representing the Telepathy Properties interface on remote * objects. */ #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/IncomingStreamTubeChannel0000664000175000017500000000043412470405660022170 0ustar jrjr#ifndef _TelepathyQt_IncomingStreamTubeChannel_HEADER_GUARD_ #define _TelepathyQt_IncomingStreamTubeChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionManagerLowlevel0000664000175000017500000000043112470405660022241 0ustar jrjr#ifndef _TelepathyQt_ConnectionManagerLowlevel_HEADER_GUARD #define _TelepathyQt_ConnectionManagerLowlevel_HEADER_GUARD #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-operation.cpp0000664000175000017500000002747612470405660021362 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #define IN_TP_QT_HEADER #include "simple-pending-operations.h" #undef IN_TP_QT_HEADER #include "TelepathyQt/_gen/pending-operation.moc.hpp" #include "TelepathyQt/_gen/simple-pending-operations.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingOperation::Private { Private(const SharedPtr &object) : object(object), finished(false) { } SharedPtr object; QString errorName; QString errorMessage; bool finished; }; /** * \class PendingOperation * \headerfile TelepathyQt/pending-operation.h * * \brief The PendingOperation class is a base class for pending asynchronous * operations. * * This class represents an incomplete asynchronous operation, such as a * D-Bus method call. When the operation has finished, it emits * finished(). The slot or slots connected to the finished() signal may obtain * additional information from the pending operation. * * In simple cases, like a D-Bus method with no 'out' arguments or for which * all 'out' arguments are to be ignored (so the possible results are * success with no extra information, or failure with an error code), the * trivial subclass PendingVoid can be used. * * For pending operations that produce a result, another subclass of * PendingOperation can be used, with additional methods that provide that * result to the library user. * * After finished() is emitted, the PendingOperation is automatically * deleted using deleteLater(), so library users must not explicitly * delete this object. * * The design is loosely based on KDE's KJob. * * See \ref async_model */ /** * Construct a new PendingOperation object. * * \param object The object on which this pending operation takes place. */ PendingOperation::PendingOperation(const SharedPtr &object) : QObject(), mPriv(new Private(object)) { } /** * Class destructor. */ PendingOperation::~PendingOperation() { if (!mPriv->finished) { warning() << this << "still pending when it was deleted - finished will " "never be emitted"; } delete mPriv; } /** * Return the object on which this pending operation takes place. * * \return A pointer to a RefCounted object. */ SharedPtr PendingOperation::object() const { return mPriv->object; } void PendingOperation::emitFinished() { Q_ASSERT(mPriv->finished); emit finished(this); deleteLater(); } /** * Record that this pending operation has finished successfully, and * emit the finished() signal next time the event loop runs. */ void PendingOperation::setFinished() { if (mPriv->finished) { if (!mPriv->errorName.isEmpty()) { warning() << this << "trying to finish with success, but already" " failed with" << mPriv->errorName << ":" << mPriv->errorMessage; } else { warning() << this << "trying to finish with success, but already" " succeeded"; } return; } mPriv->finished = true; Q_ASSERT(isValid()); QTimer::singleShot(0, this, SLOT(emitFinished())); } /** * Record that this pending operation has finished with an error, and * emit the finished() signal next time the event loop runs. * * \param name The D-Bus error name, which must be non-empty. * \param message The debugging message. */ void PendingOperation::setFinishedWithError(const QString &name, const QString &message) { if (mPriv->finished) { if (mPriv->errorName.isEmpty()) { warning() << this << "trying to fail with" << name << "but already failed with" << errorName() << ":" << errorMessage(); } else { warning() << this << "trying to fail with" << name << "but already succeeded"; } return; } if (name.isEmpty()) { warning() << this << "should be given a non-empty error name"; mPriv->errorName = QLatin1String("org.freedesktop.Telepathy.Qt.ErrorHandlingError"); } else { mPriv->errorName = name; } mPriv->errorMessage = message; mPriv->finished = true; Q_ASSERT(isError()); QTimer::singleShot(0, this, SLOT(emitFinished())); } /** * Record that this pending operation has finished with an error, and * emit the finished() signal next time the event loop runs. * * \param error The error. * \sa finished() */ void PendingOperation::setFinishedWithError(const QDBusError &error) { setFinishedWithError(error.name(), error.message()); } /** * Return whether or not the request completed successfully. If the * request has not yet finished processing (isFinished() returns * \c false), this cannot yet be known, and \c false * will be returned. * * Equivalent to (isFinished() && !isError()). * * \return \c true if the request has finished processing and * has completed successfully, \c false otherwise. */ bool PendingOperation::isValid() const { return (mPriv->finished && mPriv->errorName.isEmpty()); } /** * Return whether or not the request has finished processing. * * The signal finished() is emitted when this changes from \c false * to true. * * Equivalent to (isValid() || isError()). * * \return \c true if the request has finished, \c false otherwise. * \sa finished() */ bool PendingOperation::isFinished() const { return mPriv->finished; } /** * Return whether or not the request resulted in an error. * * If the request has not yet finished processing (isFinished() returns * \c false), this cannot yet be known, and \c false * will be returned. * * Equivalent to (isFinished() && !isValid()). * * \return \c true if the request has finished processing and * has resulted in an error, \c false otherwise. */ bool PendingOperation::isError() const { return (mPriv->finished && !mPriv->errorName.isEmpty()); } /** * If isError() returns \c true, returns the D-Bus error with which * the operation failed. If the operation succeeded or has not yet * finished, returns an empty string. * * \return A D-Bus error name, or an empty string. */ QString PendingOperation::errorName() const { return mPriv->errorName; } /** * If isError() would return \c true, returns a debugging message associated * with the error, which may be an empty string. Otherwise, return an * empty string. * * \return A debugging message, or an empty string. */ QString PendingOperation::errorMessage() const { return mPriv->errorMessage; } /** * \fn void PendingOperation::finished(Tp::PendingOperation* operation) * * Emitted when the pending operation finishes, i.e. when isFinished() * changes from \c false to \c true. * * \param operation This operation object, from which further information * may be obtained. */ /** * \class PendingSuccess * \ingroup utils * \headerfile TelepathyQt/simple-pending-operations.h * * \brief The PendingSuccess class represents PendingOperation that is always * successful. */ /** * \class PendingFailure * \ingroup utils * \headerfile TelepathyQt/simple-pending-operations.h * * \brief The PendingFailure class represents a PendingOperation that always * fails with the error passed to the constructor. */ /** * \class PendingVoid * \ingroup utils * \headerfile TelepathyQt/simple-pending-operations.h * * \brief The PendingVoid class is a generic subclass of PendingOperation * representing a pending D-Bus method call that does not return anything * (or returns a result that is not interesting). */ /** * Construct a new PendingVoid object. * * \param object The object on which this pending operation takes place. * \param call A pending call as returned by the auto-generated low level * Telepathy API; if the method returns anything, the return * value(s) will be ignored. */ PendingVoid::PendingVoid(QDBusPendingCall call, const SharedPtr &object) : PendingOperation(object) { connect(new QDBusPendingCallWatcher(call), SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(watcherFinished(QDBusPendingCallWatcher*))); } void PendingVoid::watcherFinished(QDBusPendingCallWatcher *watcher) { if (watcher->isError()) { setFinishedWithError(watcher->error()); } else { setFinished(); } watcher->deleteLater(); } struct TP_QT_NO_EXPORT PendingComposite::Private { Private(bool failOnFirstError, uint nOperations) : failOnFirstError(failOnFirstError), error(false), nOperations(nOperations), nOperationsFinished(0) { } bool failOnFirstError; bool error; QString errorName; QString errorMessage; uint nOperations; uint nOperationsFinished; }; /** * \class PendingComposite * \ingroup utils * \headerfile TelepathyQt/simple-pending-operations.h * * \brief The PendingComposite class is a PendingOperation that can be used * to track multiple pending operations at once. */ PendingComposite::PendingComposite(const QList &operations, const SharedPtr &object) : PendingOperation(object), mPriv(new Private(true, operations.size())) { foreach (PendingOperation *operation, operations) { connect(operation, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onOperationFinished(Tp::PendingOperation*))); } } PendingComposite::PendingComposite(const QList &operations, bool failOnFirstError, const SharedPtr &object) : PendingOperation(object), mPriv(new Private(failOnFirstError, operations.size())) { foreach (PendingOperation *operation, operations) { connect(operation, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onOperationFinished(Tp::PendingOperation*))); } } PendingComposite::~PendingComposite() { delete mPriv; } void PendingComposite::onOperationFinished(Tp::PendingOperation *op) { if (op->isError()) { if (mPriv->failOnFirstError) { setFinishedWithError(op->errorName(), op->errorMessage()); return; } else if (!mPriv->error) { /* only save the first error that will be used on setFinishedWithError when all * pending operations finish */ mPriv->error = true; mPriv->errorName = op->errorName(); mPriv->errorMessage = op->errorMessage(); } } if (++mPriv->nOperationsFinished == mPriv->nOperations) { if (!mPriv->error) { setFinished(); } else { setFinishedWithError(mPriv->errorName, mPriv->errorMessage); } } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/CallStreamInterfaceMediaInterface0000664000175000017500000000043312470405660023570 0ustar jrjr#ifndef _TelepathyQt_CallStreamInterfaceMediaInterface_HEADER_GUARD_ #define _TelepathyQt_CallStreamInterfaceMediaInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/fake-handler-manager-internal.h0000664000175000017500000000470712470405660023140 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_fake_handler_manager_internal_h_HEADER_GUARD_ #define _TelepathyQt_fake_handler_manager_internal_h_HEADER_GUARD_ #include #include #include namespace Tp { #ifndef DOXYGEN_SHOULD_SKIP_THIS class FakeHandler : public QObject { Q_OBJECT Q_DISABLE_COPY(FakeHandler) public: FakeHandler(const QDBusConnection &bus); ~FakeHandler(); QDBusConnection dbusConnection() const { return mBus; } ObjectPathList handledChannels() const; void registerChannel(const ChannelPtr &channel); Q_SIGNALS: void invalidated(Tp::FakeHandler *self); private Q_SLOTS: void onChannelInvalidated(Tp::DBusProxy *channel); void onChannelDestroyed(QObject *channel); private: QDBusConnection mBus; QSet mChannels; }; class FakeHandlerManager : public QObject { Q_OBJECT Q_DISABLE_COPY(FakeHandlerManager) public: static FakeHandlerManager *instance(); ~FakeHandlerManager(); ObjectPathList handledChannels(const QDBusConnection &bus) const; void registerClientRegistrar(const ClientRegistrarPtr &cr); void registerChannels(const QList &channels); private Q_SLOTS: void onFakeHandlerInvalidated(Tp::FakeHandler *fakeHandler); private: FakeHandlerManager(); static FakeHandlerManager *mInstance; QHash, ClientRegistrarPtr> mClientRegistrars; QHash, FakeHandler *> mFakeHandlers; }; #endif // DOXYGEN_SHOULD_SKIP_THIS } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/contact-search-channel.h0000664000175000017500000000742612470405660021702 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_contact_search_channel_h_HEADER_GUARD_ #define _TelepathyQt_contact_search_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class TP_QT_EXPORT ContactSearchChannel : public Channel { Q_OBJECT Q_DISABLE_COPY(ContactSearchChannel) public: static const Feature FeatureCore; class SearchStateChangeDetails { public: SearchStateChangeDetails(); SearchStateChangeDetails(const SearchStateChangeDetails &other); ~SearchStateChangeDetails(); bool isValid() const { return mPriv.constData() != 0; } SearchStateChangeDetails &operator=(const SearchStateChangeDetails &other); bool hasDebugMessage() const { return allDetails().contains(QLatin1String("debug-message")); } QString debugMessage() const { return qdbus_cast(allDetails().value(QLatin1String("debug-message"))); } QVariantMap allDetails() const; private: friend class ContactSearchChannel; TP_QT_NO_EXPORT SearchStateChangeDetails(const QVariantMap &details); struct Private; friend struct Private; QSharedDataPointer mPriv; }; typedef QHash SearchResult; static ContactSearchChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~ContactSearchChannel(); ChannelContactSearchState searchState() const; uint limit() const; QStringList availableSearchKeys() const; QString server() const; PendingOperation *search(const QString &searchKey, const QString &searchTerm); PendingOperation *search(const ContactSearchMap &searchTerms); void continueSearch(); void stopSearch(); Q_SIGNALS: void searchStateChanged(Tp::ChannelContactSearchState state, const QString &errorName, const Tp::ContactSearchChannel::SearchStateChangeDetails &details); void searchResultReceived(const Tp::ContactSearchChannel::SearchResult &result); protected: ContactSearchChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature); private Q_SLOTS: TP_QT_NO_EXPORT void gotProperties(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotSearchState(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onSearchStateChanged(uint state, const QString &error, const QVariantMap &details); TP_QT_NO_EXPORT void onSearchResultReceived(const Tp::ContactSearchResultMap &result); TP_QT_NO_EXPORT void gotSearchResultContacts(Tp::PendingOperation *op); private: class PendingSearch; struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/message.h0000664000175000017500000001031512470405660017011 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_message_h_HEADER_GUARD_ #define _TelepathyQt_message_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include class QDateTime; namespace Tp { class Contact; class TextChannel; class TP_QT_EXPORT Message { public: Message(ChannelTextMessageType, const QString &); Message(const Message &other); ~Message(); Message &operator=(const Message &other); bool operator==(const Message &other) const; inline bool operator!=(const Message &other) const { return !(*this == other); } // Convenient access to headers QDateTime sent() const; ChannelTextMessageType messageType() const; bool isTruncated() const; bool hasNonTextContent() const; QString messageToken() const; bool isSpecificToDBusInterface() const; QString dbusInterface() const; QString text() const; // Direct access to the whole message (header and body) MessagePart header() const; int size() const; MessagePart part(uint index) const; MessagePartList parts() const; private: friend class ContactMessenger; friend class ReceivedMessage; friend class TextChannel; TP_QT_NO_EXPORT Message(); TP_QT_NO_EXPORT Message(const MessagePartList &parts); TP_QT_NO_EXPORT Message(uint, uint, const QString &); struct Private; friend struct Private; QSharedDataPointer mPriv; }; class TP_QT_EXPORT ReceivedMessage : public Message { public: class DeliveryDetails { public: DeliveryDetails(); DeliveryDetails(const DeliveryDetails &other); ~DeliveryDetails(); DeliveryDetails &operator=(const DeliveryDetails &other); bool isValid() const { return mPriv.constData() != 0; } DeliveryStatus status() const; bool hasOriginalToken() const; QString originalToken() const; bool isError() const; ChannelTextSendError error() const; bool hasDebugMessage() const; QString debugMessage() const; QString dbusError() const; bool hasEchoedMessage() const; Message echoedMessage() const; private: friend class ReceivedMessage; TP_QT_NO_EXPORT DeliveryDetails(const MessagePartList &parts); struct Private; friend struct Private; QSharedDataPointer mPriv; }; ReceivedMessage(const ReceivedMessage &other); ReceivedMessage &operator=(const ReceivedMessage &other); ~ReceivedMessage(); QDateTime received() const; ContactPtr sender() const; QString senderNickname() const; QString supersededToken() const; bool isScrollback() const; bool isRescued() const; bool isDeliveryReport() const; DeliveryDetails deliveryDetails() const; bool isFromChannel(const TextChannelPtr &channel) const; protected: friend class TextChannel; ReceivedMessage(const MessagePartList &parts, const TextChannelPtr &channel); ReceivedMessage(); uint senderHandle() const; QString senderId() const; uint pendingId() const; void setForceNonText(); void clearSenderHandle(); void setSender(const ContactPtr &sender); }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/optional-interface-factory.h0000664000175000017500000000775212470405660022630 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_optional_interface_factory_h_HEADER_GUARD_ #define _TelepathyQt_optional_interface_factory_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include namespace Tp { class AbstractInterface; #ifndef DOXYGEN_SHOULD_SKIP_THIS class TP_QT_EXPORT OptionalInterfaceCache { Q_DISABLE_COPY(OptionalInterfaceCache) public: explicit OptionalInterfaceCache(QObject *proxy); ~OptionalInterfaceCache(); protected: AbstractInterface *getCached(const QString &name) const; void cache(AbstractInterface *interface) const; QObject *proxy() const; private: struct Private; friend struct Private; Private *mPriv; }; #endif /* DOXYGEN_SHOULD_SKIP_THIS */ template class OptionalInterfaceFactory #ifndef DOXYGEN_SHOULD_SKIP_THIS : private OptionalInterfaceCache #endif { Q_DISABLE_COPY(OptionalInterfaceFactory) public: enum InterfaceSupportedChecking { CheckInterfaceSupported, BypassInterfaceCheck }; inline OptionalInterfaceFactory(DBusProxySubclass *this_) : OptionalInterfaceCache(this_) { } inline ~OptionalInterfaceFactory() { } inline QStringList interfaces() const { return mInterfaces; } inline bool hasInterface(const QString &name) const { return mInterfaces.contains(name); } template inline Interface *optionalInterface( InterfaceSupportedChecking check = CheckInterfaceSupported) const { // Check for the remote object supporting the interface // Note that extra whitespace on "name" declaration is significant to avoid // vexing-parse QString name( (QLatin1String(Interface::staticInterfaceName())) ); if (check == CheckInterfaceSupported && !mInterfaces.contains(name)) { return 0; } // If present or forced, delegate to OptionalInterfaceFactory return interface(); } template inline Interface *interface() const { AbstractInterface* interfaceMustBeASubclassOfAbstractInterface = static_cast(NULL); Q_UNUSED(interfaceMustBeASubclassOfAbstractInterface); // If there is a interface cached already, return it // Note that extra whitespace on "name" declaration is significant to avoid // vexing-parse QString name( (QLatin1String(Interface::staticInterfaceName())) ); AbstractInterface *cached = getCached(name); if (cached) return static_cast(cached); // Otherwise, cache and return a newly constructed proxy Interface *interface = new Interface( static_cast(proxy())); cache(interface); return interface; } protected: inline void setInterfaces(const QStringList &interfaces) { mInterfaces = interfaces; } private: QStringList mInterfaces; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/StreamTubeChannel0000664000175000017500000000040312470405660020500 0ustar jrjr#ifndef _TelepathyQt_StreamTubeChannel_HEADER_GUARD_ #define _TelepathyQt_StreamTubeChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-captchas.h0000664000175000017500000000452512470405660020603 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_captcha_h_HEADER_GUARD_ #define _TelepathyQt_pending_captcha_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { class Captcha; class TP_QT_EXPORT PendingCaptchas : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingCaptchas) public: virtual ~PendingCaptchas(); Captcha captcha() const; QList captchaList() const; bool requiresMultipleCaptchas() const; private Q_SLOTS: TP_QT_NO_EXPORT void onChannelInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage); TP_QT_NO_EXPORT void onGetCaptchasWatcherFinished(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onGetCaptchaDataWatcherFinished(QDBusPendingCallWatcher *watcher); private: TP_QT_NO_EXPORT PendingCaptchas(const QDBusPendingCall &call, const QStringList &preferredMimeTypes, CaptchaAuthentication::ChallengeTypes preferredTypes, const CaptchaAuthenticationPtr &channel); TP_QT_NO_EXPORT PendingCaptchas( const QString &errorName, const QString &errorMessage, const CaptchaAuthenticationPtr &channel); struct Private; friend class CaptchaAuthentication; friend struct Private; Private *mPriv; }; } #endif // TP_PENDING_CAPTCHA_H telepathy-qt-0.9.6~git1/TelepathyQt/FileTransferChannel0000664000175000017500000000041112470405660021010 0ustar jrjr#ifndef _TelepathyQt_FileTransferChannel_HEADER_GUARD_ #define _TelepathyQt_FileTransferChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/test-backdoors.h0000664000175000017500000000370412470405660020315 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_test_backdoors_h_HEADER_GUARD_ #define _TelepathyQt_test_backdoors_h_HEADER_GUARD_ #ifdef IN_TP_QT_HEADER #error "This file is an internal header and should never be included by a public one" #endif #include #include #include #include #ifndef DOXYGEN_SHOULD_SKIP_THIS namespace Tp { class DBusProxy; // Exported so the tests can use it even if they link dynamically // The header is not installed though, so this should be considered private API struct TP_QT_EXPORT TestBackdoors { static void invalidateProxy(DBusProxy *proxy, const QString &reason, const QString &message); static ConnectionCapabilities createConnectionCapabilities( const RequestableChannelClassSpecList &rccSpecs); static ContactCapabilities createContactCapabilities( const RequestableChannelClassSpecList &rccSpecs, bool specificToContact); }; } // Tp #endif /* DOXYGEN_SHOULD_SKIP_THIS */ #endif telepathy-qt-0.9.6~git1/TelepathyQt/incoming-dbus-tube-channel.h0000664000175000017500000000342712470405660022474 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_incoming_dbus_tube_channel_h_HEADER_GUARD_ #define _TelepathyQt_incoming_dbus_tube_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { class PendingDBusTubeConnection; class TP_QT_EXPORT IncomingDBusTubeChannel : public DBusTubeChannel { Q_OBJECT Q_DISABLE_COPY(IncomingDBusTubeChannel) public: static IncomingDBusTubeChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~IncomingDBusTubeChannel(); PendingDBusTubeConnection *acceptTube(bool allowOtherUsers = false); protected: IncomingDBusTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); private: struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/PendingDBusTubeConnection0000664000175000017500000000043412470405660022142 0ustar jrjr#ifndef _TelepathyQt_PendingDBusTubeConnection_HEADER_GUARD_ #define _TelepathyQt_PendingDBusTubeConnection_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/debug.h0000664000175000017500000000275412470405660016463 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_debug_h_HEADER_GUARD_ #define _TelepathyQt_debug_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { TP_QT_EXPORT void enableDebug(bool enable); TP_QT_EXPORT void enableWarnings(bool enable); typedef void (*DebugCallback)(const QString &libraryName, const QString &libraryVersion, QtMsgType type, const QString &msg); TP_QT_EXPORT void setDebugCallback(DebugCallback cb); } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/abstract-adaptor.cpp0000664000175000017500000000601612470405660021156 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/abstract-adaptor.moc.hpp" #include "TelepathyQt/debug-internal.h" #include namespace Tp { struct TP_QT_NO_EXPORT AbstractAdaptor::Private { Private(const QDBusConnection &dbusConnection, QObject *adaptee) : dbusConnection(dbusConnection), adaptee(adaptee) { } QDBusConnection dbusConnection; QObject *adaptee; }; /** * \class AbstractAdaptor * \ingroup servicesideimpl * \headerfile TelepathyQt/abstract-adaptor.h * * \brief Base class for all the low-level service-side adaptors. * * This class serves as the parent for all the generated low-level service-side * adaptors. Adaptors provide the interface of an object on the bus. * * The implementation of this interface should be provided in a special object * called the adaptee. The adaptee is meant to provide properties, signals * and slots that are connected automatically with the adaptor using Qt's meta-object * system. */ /** * Construct a new AbstractAdaptor that operates on the given * \a dbusConnection and redirects calls to the given \a adaptee. * * \param dbusConnection The D-Bus connection to use. * \param adaptee The class the provides the implementation of the calls. * \param parent The QObject parent of this adaptor. */ AbstractAdaptor::AbstractAdaptor(const QDBusConnection &dbusConnection, QObject *adaptee, QObject *parent) : QDBusAbstractAdaptor(parent), mPriv(new Private(dbusConnection, adaptee)) { setAutoRelaySignals(false); } /** * Class destructor. */ AbstractAdaptor::~AbstractAdaptor() { delete mPriv; } /** * Return the D-Bus connection associated with this adaptor. * * \return The D-Bus connection associated with this adaptor. */ QDBusConnection AbstractAdaptor::dbusConnection() const { return mPriv->dbusConnection; } /** * Return the adaptee object, i.e. the object that provides the implementation * of this adaptor. * * \return The adaptee object. */ QObject *AbstractAdaptor::adaptee() const { return mPriv->adaptee; } } telepathy-qt-0.9.6~git1/TelepathyQt/pending-variant-map.cpp0000664000175000017500000000503612470405660021565 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-variant-map.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingVariantMap::Private { QVariantMap result; }; /** * \class PendingVariantMap * \ingroup utils * \headerfile TelepathyQt/pending-variant-map.h * * \brief The PendingVariantMap class is a generic subclass of PendingOperation * representing a pending D-Bus method call that returns a variant map. * * See \ref async_model */ PendingVariantMap::PendingVariantMap(QDBusPendingCall call, const SharedPtr &object) : PendingOperation(object), mPriv(new Private) { connect(new QDBusPendingCallWatcher(call), SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(watcherFinished(QDBusPendingCallWatcher*))); } /** * Class destructor. */ PendingVariantMap::~PendingVariantMap() { delete mPriv; } QVariantMap PendingVariantMap::result() const { return mPriv->result; } void PendingVariantMap::watcherFinished(QDBusPendingCallWatcher* watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got reply to PendingVariantMap call"; mPriv->result = reply.value(); setFinished(); } else { debug().nospace() << "PendingVariantMap call failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/types.h0000664000175000017500000001723412470405660016540 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2012 Collabora Ltd. * @copyright Copyright (C) 2008-2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_types_h_HEADER_GUARD_ #define _TelepathyQt_types_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include namespace Tp { TP_QT_EXPORT void registerTypes(); template class Filter; template class GenericCapabilityFilter; template class GenericPropertyFilter; class AbstractClient; class AbstractClientApprover; class AbstractClientHandler; class AbstractClientObserver; class Account; typedef GenericCapabilityFilter AccountCapabilityFilter; class AccountFactory; typedef Filter AccountFilter; class AccountManager; class AccountPropertyFilter; class AccountSet; class CallChannel; class CallContent; class CallStream; class CaptchaAuthentication; class Channel; class ChannelDispatchOperation; class ChannelFactory; class ChannelRequest; class ClientObject; class ClientRegistrar; class Connection; class ConnectionFactory; class ConnectionLowlevel; class ConnectionManager; class ConnectionManagerLowlevel; class Contact; class ContactFactory; class ContactManager; class ContactMessenger; class ContactSearchChannel; class DBusProxy; class DebugReceiver; class DBusTubeChannel; class FileTransferChannel; class IncomingDBusTubeChannel; class IncomingFileTransferChannel; class IncomingStreamTubeChannel; class OutgoingDBusTubeChannel; class OutgoingFileTransferChannel; class OutgoingStreamTubeChannel; class Profile; class ProfileManager; class RoomListChannel; class ServerAuthenticationChannel; class SimpleObserver; class SimpleCallObserver; class SimpleTextObserver; class StreamedMediaChannel; class StreamedMediaStream; class StreamTubeChannel; class StreamTubeClient; class StreamTubeServer; class TextChannel; class TubeChannel; #ifndef DOXYGEN_SHOULD_SKIP_THIS typedef SharedPtr AbstractClientPtr; typedef SharedPtr AbstractClientApproverPtr; typedef SharedPtr AbstractClientHandlerPtr; typedef SharedPtr AbstractClientObserverPtr; typedef SharedPtr AccountPtr; typedef SharedPtr AccountCapabilityFilterPtr; typedef SharedPtr AccountCapabilityFilterConstPtr; typedef SharedPtr AccountFactoryPtr; typedef SharedPtr AccountFactoryConstPtr; typedef SharedPtr AccountFilterPtr; typedef SharedPtr AccountFilterConstPtr; typedef SharedPtr AccountManagerPtr; typedef SharedPtr AccountPropertyFilterPtr; typedef SharedPtr AccountPropertyFilterConstPtr; typedef SharedPtr AccountSetPtr; typedef SharedPtr CallChannelPtr; typedef SharedPtr CallContentPtr; typedef SharedPtr CallStreamPtr; typedef SharedPtr CaptchaAuthenticationPtr; typedef SharedPtr ChannelPtr; typedef SharedPtr ChannelDispatchOperationPtr; typedef SharedPtr ChannelFactoryPtr; typedef SharedPtr ChannelFactoryConstPtr; typedef SharedPtr ChannelRequestPtr; typedef SharedPtr ClientObjectPtr; typedef SharedPtr ClientRegistrarPtr; typedef SharedPtr ConnectionPtr; typedef SharedPtr ConnectionFactoryPtr; typedef SharedPtr ConnectionFactoryConstPtr; typedef SharedPtr ConnectionLowlevelPtr; typedef SharedPtr ConnectionLowlevelConstPtr; typedef SharedPtr ConnectionManagerPtr; typedef SharedPtr ConnectionManagerLowlevelPtr; typedef SharedPtr ConnectionManagerLowlevelConstPtr; typedef SharedPtr ContactPtr; typedef QSet Contacts; typedef SharedPtr ContactFactoryPtr; typedef SharedPtr ContactFactoryConstPtr; typedef SharedPtr ContactManagerPtr; typedef SharedPtr ContactMessengerPtr; typedef SharedPtr ContactSearchChannelPtr; typedef SharedPtr DBusProxyPtr; typedef SharedPtr DBusTubeChannelPtr; typedef SharedPtr DebugReceiverPtr; typedef SharedPtr FileTransferChannelPtr; typedef SharedPtr IncomingDBusTubeChannelPtr; typedef SharedPtr IncomingFileTransferChannelPtr; typedef SharedPtr IncomingStreamTubeChannelPtr; typedef SharedPtr OutgoingDBusTubeChannelPtr; typedef SharedPtr OutgoingFileTransferChannelPtr; typedef SharedPtr OutgoingStreamTubeChannelPtr; typedef SharedPtr ProfilePtr; typedef SharedPtr ProfileManagerPtr; typedef SharedPtr RoomListChannelPtr; typedef SharedPtr ServerAuthenticationChannelPtr; typedef SharedPtr SimpleObserverPtr; typedef SharedPtr SimpleCallObserverPtr; typedef SharedPtr SimpleTextObserverPtr; typedef TP_QT_DEPRECATED SharedPtr StreamedMediaChannelPtr; typedef TP_QT_DEPRECATED SharedPtr StreamedMediaStreamPtr; typedef SharedPtr StreamTubeChannelPtr; typedef SharedPtr StreamTubeClientPtr; typedef SharedPtr StreamTubeServerPtr; typedef SharedPtr TextChannelPtr; typedef SharedPtr TubeChannelPtr; template class MethodInvocationContextPtr : public SharedPtr > { public: inline MethodInvocationContextPtr() { } explicit inline MethodInvocationContextPtr(MethodInvocationContext *d) : SharedPtr >(d) { } inline MethodInvocationContextPtr(const SharedPtr > &o) : SharedPtr >(o) { } }; #endif /* DOXYGEN_SHOULD_SKIP_THIS */ } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/MessageContentPartList0000664000175000017500000000041612470405660021542 0ustar jrjr#ifndef _TelepathyQt_MessageContentPartList_HEADER_GUARD_ #define _TelepathyQt_MessageContentPartList_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionManagerInterface0000664000175000017500000000042412470405660022352 0ustar jrjr#ifndef _TelepathyQt_ConnectionManagerInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionManagerInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-stream-tube-connection.h0000664000175000017500000000477212470405660023406 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_stream_tube_connection_h_HEADER_GUARD_ #define _TelepathyQt_pending_stream_tube_connection_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include class QHostAddress; namespace Tp { class PendingVariant; class IncomingStreamTubeChannel; class TP_QT_EXPORT PendingStreamTubeConnection : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingStreamTubeConnection) public: virtual ~PendingStreamTubeConnection(); SocketAddressType addressType() const; QPair ipAddress() const; QString localAddress() const; bool requiresCredentials() const; uchar credentialByte() const; private Q_SLOTS: TP_QT_NO_EXPORT void onChannelInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage); TP_QT_NO_EXPORT void onAcceptFinished(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onTubeStateChanged(Tp::TubeChannelState state); private: TP_QT_NO_EXPORT PendingStreamTubeConnection(PendingVariant *acceptOperation, SocketAddressType type, bool requiresCredentials, uchar credentialByte, const IncomingStreamTubeChannelPtr &channel); TP_QT_NO_EXPORT PendingStreamTubeConnection( const QString &errorName, const QString &errorMessage, const IncomingStreamTubeChannelPtr &channel); struct Private; friend class IncomingStreamTubeChannel; friend struct Private; Private *mPriv; }; } #endif // TP_PENDING_STREAM_TUBE_CONNECTION_H telepathy-qt-0.9.6~git1/TelepathyQt/connection-manager.xml0000664000175000017500000000073012470405660021505 0ustar jrjr Connection Manager interfaces telepathy-qt-0.9.6~git1/TelepathyQt/PendingComposite0000664000175000017500000000040712470405660020407 0ustar jrjr#ifndef _TelepathyQt_PendingComposite_HEADER_GUARD_ #define _TelepathyQt_PendingComposite_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/dbus-properties.xml0000664000175000017500000000152312470405660021066 0ustar jrjr D-Bus Properties telepathy-qt-0.9.6~git1/TelepathyQt/ReadinessHelper0000664000175000017500000000037412470405660020220 0ustar jrjr#ifndef _TelepathyQt_ReadinessHelper_HEADER_GUARD_ #define _TelepathyQt_ReadinessHelper_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceAnonymityInterface0000664000175000017500000000043112470405660024057 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceAnonymityInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceAnonymityInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeServerAuthenticationInterface0000664000175000017500000000044512470405660025264 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeServerAuthenticationInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeServerAuthenticationInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/LocationInfo0000664000175000017500000000036312470405660017525 0ustar jrjr#ifndef _TelepathyQt_LocationInfo_HEADER_GUARD_ #define _TelepathyQt_LocationInfo_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/simple-stream-tube-handler.h0000664000175000017500000000710612470405660022523 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_simple_stream_tube_handler_h_HEADER_GUARD_ #define _TelepathyQt_simple_stream_tube_handler_h_HEADER_GUARD_ #include #include #include #include #include #include #include #include #include namespace Tp { class PendingOperation; class TP_QT_NO_EXPORT SimpleStreamTubeHandler : public QObject, public AbstractClientHandler { Q_OBJECT Q_DISABLE_COPY(SimpleStreamTubeHandler) public: static SharedPtr create( const QStringList &p2pServices, const QStringList &roomServices, bool requested, bool monitorConnections, bool bypassApproval = false); ~SimpleStreamTubeHandler(); bool monitorsConnections() const { return mMonitorConnections; } bool bypassApproval() const { return mBypassApproval; } void handleChannels(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const QList &requestsSatisfied, const QDateTime &userActionTime, const HandlerInfo &handlerInfo); Q_SIGNALS: void invokedForTube( const Tp::AccountPtr &account, const Tp::StreamTubeChannelPtr &tube, const QDateTime &userActionTime, const Tp::ChannelRequestHints &requestHints); void tubeInvalidated( const Tp::AccountPtr &account, const Tp::StreamTubeChannelPtr &tube, const QString &errorName, const QString &errorMessage); private Q_SLOTS: void onReadyOpFinished(Tp::PendingOperation *); void onTubeInvalidated(Tp::DBusProxy *, const QString &, const QString &); private: SimpleStreamTubeHandler( const QStringList &p2pServices, const QStringList &roomServices, bool requested, bool monitorConnections, bool bypassApproval); bool mMonitorConnections; struct InvocationData : RefCounted { InvocationData() : readyOp(0) {} PendingOperation *readyOp; QString error, message; MethodInvocationContextPtr<> ctx; AccountPtr acc; QList tubes; QDateTime time; ChannelRequestHints hints; }; QLinkedList > mInvocations; QHash mTubes; bool mBypassApproval; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/base-channel.cpp0000664000175000017500000025070212470405660020246 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2013 Matthias Gehre * @copyright Copyright 2013 Canonical Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "TelepathyQt/base-channel-internal.h" #include "TelepathyQt/_gen/base-channel.moc.hpp" #include "TelepathyQt/_gen/base-channel-internal.moc.hpp" #include "TelepathyQt/future-internal.h" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT BaseChannel::Private { Private(BaseChannel *parent, const QDBusConnection &dbusConnection, BaseConnection* connection, const QString &channelType, uint targetHandle, uint targetHandleType) : parent(parent), connection(connection), channelType(channelType), targetHandle(targetHandle), targetHandleType(targetHandleType), adaptee(new BaseChannel::Adaptee(dbusConnection, parent)) { static uint s_channelIncrementalId = 0; QString baseName; static const QString s_channelTypePrefix = TP_QT_IFACE_CHANNEL + QLatin1String(".Type."); if (channelType.startsWith(s_channelTypePrefix)) { baseName = channelType.mid(s_channelTypePrefix.length()); } uniqueName = baseName + QLatin1String("Channel") + QString::number(s_channelIncrementalId); ++s_channelIncrementalId; } BaseChannel *parent; BaseConnection* connection; QString channelType; QHash interfaces; QString uniqueName; uint targetHandle; QString targetID; uint targetHandleType; bool requested; uint initiatorHandle; QString initiatorID; BaseChannel::Adaptee *adaptee; }; BaseChannel::Adaptee::Adaptee(const QDBusConnection &dbusConnection, BaseChannel *channel) : QObject(channel), mChannel(channel) { debug() << "Creating service::channelAdaptor for " << channel->dbusObject(); mAdaptor = new Service::ChannelAdaptor(dbusConnection, this, channel->dbusObject()); } BaseChannel::Adaptee::~Adaptee() { } QStringList BaseChannel::Adaptee::interfaces() const { QStringList ret; foreach(const AbstractChannelInterfacePtr & iface, mChannel->interfaces()) { if (iface->interfaceName().contains(QLatin1String(".Type."))) continue; //Do not include "Type" ret << iface->interfaceName(); } return ret; } void BaseChannel::Adaptee::close(const Tp::Service::ChannelAdaptor::CloseContextPtr &context) { mChannel->close(); context->setFinished(); } /** * \class BaseChannel * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for channel implementations. * */ BaseChannel::BaseChannel(const QDBusConnection &dbusConnection, BaseConnection* connection, const QString &channelType, uint targetHandle, uint targetHandleType) : DBusService(dbusConnection), mPriv(new Private(this, dbusConnection, connection, channelType, targetHandle, targetHandleType)) { } /** * Class destructor. */ BaseChannel::~BaseChannel() { delete mPriv; } /** * Return a unique name for this channel. * * \return A unique name for this channel. */ QString BaseChannel::uniqueName() const { return mPriv->uniqueName; } bool BaseChannel::registerObject(DBusError *error) { if (isRegistered()) { return true; } QString name = uniqueName(); QString busName = mPriv->connection->busName(); //QString busName = QString(QLatin1String("%1.%2")) // .arg(mPriv->connection->busName(),name); QString objectPath = QString(QLatin1String("%1/%2")) .arg(mPriv->connection->objectPath(), name); debug() << "Registering channel: busName: " << busName << " objectName: " << objectPath; DBusError _error; debug() << "Channel: registering interfaces at " << dbusObject(); foreach(const AbstractChannelInterfacePtr & iface, mPriv->interfaces) { if (!iface->registerInterface(dbusObject())) { // lets not fail if an optional interface fails registering, lets warn only warning() << "Unable to register interface" << iface->interfaceName(); } } bool ret = registerObject(busName, objectPath, &_error); if (!ret && error) { error->set(_error.name(), _error.message()); } return ret; } /** * Reimplemented from DBusService. */ bool BaseChannel::registerObject(const QString &busName, const QString &objectPath, DBusError *error) { return DBusService::registerObject(busName, objectPath, error); } QString BaseChannel::channelType() const { return mPriv->channelType; } QList BaseChannel::interfaces() const { return mPriv->interfaces.values(); } uint BaseChannel::targetHandle() const { return mPriv->targetHandle; } QString BaseChannel::targetID() const { return mPriv->targetID; } uint BaseChannel::targetHandleType() const { return mPriv->targetHandleType; } bool BaseChannel::requested() const { return mPriv->requested; } uint BaseChannel::initiatorHandle() const { return mPriv->initiatorHandle; } QString BaseChannel::initiatorID() const { return mPriv->initiatorID; } void BaseChannel::setInitiatorHandle(uint initiatorHandle) { mPriv->initiatorHandle = initiatorHandle; } void BaseChannel::setInitiatorID(const QString &initiatorID) { mPriv->initiatorID = initiatorID; } void BaseChannel::setTargetID(const QString &targetID) { mPriv->targetID = targetID; } void BaseChannel::setRequested(bool requested) { mPriv->requested = requested; } void BaseChannel::close() { // Method is used in destructor, so (to be sure that adaptee is exists) we should use DirectConnection QMetaObject::invokeMethod(mPriv->adaptee, "closed", Qt::DirectConnection); emit closed(); } /** * Return the immutable properties of this channel object. * * Immutable properties cannot change after the object has been registered * on the bus with registerObject(). * * \return The immutable properties of this channel object. */ QVariantMap BaseChannel::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), QVariant::fromValue(mPriv->adaptee->channelType())); map.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), QVariant::fromValue(mPriv->adaptee->targetHandle())); map.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".Interfaces"), QVariant::fromValue(mPriv->adaptee->interfaces())); map.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), QVariant::fromValue(mPriv->adaptee->targetID())); map.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), QVariant::fromValue(mPriv->adaptee->targetHandleType())); map.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".Requested"), QVariant::fromValue(mPriv->adaptee->requested())); map.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle"), QVariant::fromValue(mPriv->adaptee->initiatorHandle())); map.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorID"), QVariant::fromValue(mPriv->adaptee->initiatorID())); return map; } Tp::ChannelDetails BaseChannel::details() const { Tp::ChannelDetails details; details.channel = QDBusObjectPath(objectPath()); details.properties.unite(immutableProperties()); foreach(const AbstractChannelInterfacePtr & iface, mPriv->interfaces) { details.properties.unite(iface->immutableProperties()); } return details; } /** * Return a pointer to the interface with the given name. * * \param interfaceName The D-Bus name of the interface, * ex. TP_QT_IFACE_PROTOCOL_INTERFACE_ADDRESSING. * \return A pointer to the AbstractProtocolInterface object that implements * the D-Bus interface with the given name, or a null pointer if such an interface * has not been plugged into this object. * \sa plugInterface(), interfaces() */ AbstractChannelInterfacePtr BaseChannel::interface(const QString &interfaceName) const { return mPriv->interfaces.value(interfaceName); } /** * Plug a new interface into this Protocol D-Bus object. * * This property is immutable and cannot change after this Protocol * object has been registered on the bus with registerObject(). * * \param interface An AbstractProtocolInterface instance that implements * the interface that is to be plugged. * \return \c true on success or \c false otherwise * \sa interfaces(), interface() */ bool BaseChannel::plugInterface(const AbstractChannelInterfacePtr &interface) { if (isRegistered()) { warning() << "Unable to plug protocol interface " << interface->interfaceName() << "- protocol already registered"; return false; } if (interface->isRegistered()) { warning() << "Unable to plug protocol interface" << interface->interfaceName() << "- interface already registered"; return false; } if (mPriv->interfaces.contains(interface->interfaceName())) { warning() << "Unable to plug protocol interface" << interface->interfaceName() << "- another interface with same name already plugged"; return false; } debug() << "Interface" << interface->interfaceName() << "plugged"; mPriv->interfaces.insert(interface->interfaceName(), interface); return true; } /** * \class AbstractChannelInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for all the Channel object interface implementations. */ AbstractChannelInterface::AbstractChannelInterface(const QString &interfaceName) : AbstractDBusServiceInterface(interfaceName) { } AbstractChannelInterface::~AbstractChannelInterface() { } // Chan.T.Text BaseChannelTextType::Adaptee::Adaptee(BaseChannelTextType *interface) : QObject(interface), mInterface(interface) { } BaseChannelTextType::Adaptee::~Adaptee() { } void BaseChannelTextType::Adaptee::acknowledgePendingMessages(const Tp::UIntList &IDs, const Tp::Service::ChannelTypeTextAdaptor::AcknowledgePendingMessagesContextPtr &context) { qDebug() << "BaseConnectionContactsInterface::acknowledgePendingMessages " << IDs; DBusError error; mInterface->acknowledgePendingMessages(IDs, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } struct TP_QT_NO_EXPORT BaseChannelTextType::Private { Private(BaseChannelTextType *parent, BaseChannel* channel) : channel(channel), pendingMessagesId(0), adaptee(new BaseChannelTextType::Adaptee(parent)) { } BaseChannel* channel; /* maps pending-message-id to message part list */ QMap pendingMessages; /* increasing unique id of pending messages */ uint pendingMessagesId; MessageAcknowledgedCallback messageAcknowledgedCB; BaseChannelTextType::Adaptee *adaptee; }; /** * \class BaseChannelTextType * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Type.Text * */ /** * Class constructor. */ BaseChannelTextType::BaseChannelTextType(BaseChannel* channel) : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_TYPE_TEXT), mPriv(new Private(this, channel)) { } /** * Class destructor. */ BaseChannelTextType::~BaseChannelTextType() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelTextType::immutableProperties() const { return QVariantMap(); } void BaseChannelTextType::createAdaptor() { (void) new Service::ChannelTypeTextAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseChannelTextType::addReceivedMessage(const Tp::MessagePartList &msg) { MessagePartList message = msg; if (msg.empty()) { warning() << "empty message: not sent"; return; } MessagePart &header = message.front(); if (header.count(QLatin1String("pending-message-id"))) warning() << "pending-message-id will be overwritten"; /* Add pending-message-id to header */ uint pendingMessageId = mPriv->pendingMessagesId++; header[QLatin1String("pending-message-id")] = QDBusVariant(pendingMessageId); mPriv->pendingMessages[pendingMessageId] = message; uint timestamp = 0; if (header.count(QLatin1String("message-received"))) timestamp = header[QLatin1String("message-received")].variant().toUInt(); uint handle = 0; if (header.count(QLatin1String("message-sender"))) handle = header[QLatin1String("message-sender")].variant().toUInt(); uint type = ChannelTextMessageTypeNormal; if (header.count(QLatin1String("message-type"))) type = header[QLatin1String("message-type")].variant().toUInt(); //FIXME: flags are not parsed uint flags = 0; QString content; for (MessagePartList::Iterator i = message.begin() + 1; i != message.end(); ++i) if (i->count(QLatin1String("content-type")) && i->value(QLatin1String("content-type")).variant().toString() == QLatin1String("text/plain") && i->count(QLatin1String("content"))) { content = i->value(QLatin1String("content")).variant().toString(); break; } if (content.length() > 0) QMetaObject::invokeMethod(mPriv->adaptee, "received", Qt::QueuedConnection, Q_ARG(uint, pendingMessageId), Q_ARG(uint, timestamp), Q_ARG(uint, handle), Q_ARG(uint, type), Q_ARG(uint, flags), Q_ARG(QString, content)); /* Signal on ChannelMessagesInterface */ BaseChannelMessagesInterfacePtr messagesIface = BaseChannelMessagesInterfacePtr::dynamicCast( mPriv->channel->interface(TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES)); if (messagesIface) QMetaObject::invokeMethod(messagesIface.data(), "messageReceived", Qt::QueuedConnection, Q_ARG(Tp::MessagePartList, message)); } Tp::MessagePartListList BaseChannelTextType::pendingMessages() { return mPriv->pendingMessages.values(); } /* * Will be called with the value of the message-token field after a received message has been acknowledged, * if the message-token field existed in the header. */ void BaseChannelTextType::setMessageAcknowledgedCallback(const MessageAcknowledgedCallback &cb) { mPriv->messageAcknowledgedCB = cb; } void BaseChannelTextType::acknowledgePendingMessages(const Tp::UIntList &IDs, DBusError* error) { foreach(uint id, IDs) { QMap::Iterator i = mPriv->pendingMessages.find(id); if (i == mPriv->pendingMessages.end()) { error->set(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("id not found")); return; } MessagePart &header = i->front(); if (header.count(QLatin1String("message-token")) && mPriv->messageAcknowledgedCB.isValid()) mPriv->messageAcknowledgedCB(header[QLatin1String("message-token")].variant().toString()); mPriv->pendingMessages.erase(i); } /* Signal on ChannelMessagesInterface */ BaseChannelMessagesInterfacePtr messagesIface = BaseChannelMessagesInterfacePtr::dynamicCast( mPriv->channel->interface(TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES)); if (messagesIface) //emit after return QMetaObject::invokeMethod(messagesIface.data(), "pendingMessagesRemoved", Qt::QueuedConnection, Q_ARG(Tp::UIntList, IDs)); } void BaseChannelTextType::sent(uint timestamp, uint type, QString text) { QMetaObject::invokeMethod(mPriv->adaptee,"sent",Q_ARG(uint, timestamp), Q_ARG(uint, type), Q_ARG(QString, text)); //Can simply use emit in Qt5 } // Chan.I.Messages BaseChannelMessagesInterface::Adaptee::Adaptee(BaseChannelMessagesInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelMessagesInterface::Adaptee::~Adaptee() { } void BaseChannelMessagesInterface::Adaptee::sendMessage(const Tp::MessagePartList &message, uint flags, const Tp::Service::ChannelInterfaceMessagesAdaptor::SendMessageContextPtr &context) { DBusError error; QString token = mInterface->sendMessage(message, flags, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(token); } struct TP_QT_NO_EXPORT BaseChannelMessagesInterface::Private { Private(BaseChannelMessagesInterface *parent, BaseChannelTextType* textTypeInterface, QStringList supportedContentTypes, Tp::UIntList messageTypes, uint messagePartSupportFlags, uint deliveryReportingSupport) : textTypeInterface(textTypeInterface), supportedContentTypes(supportedContentTypes), messageTypes(messageTypes), messagePartSupportFlags(messagePartSupportFlags), deliveryReportingSupport(deliveryReportingSupport), adaptee(new BaseChannelMessagesInterface::Adaptee(parent)) { } BaseChannelTextType* textTypeInterface; QStringList supportedContentTypes; Tp::UIntList messageTypes; uint messagePartSupportFlags; uint deliveryReportingSupport; SendMessageCallback sendMessageCB; BaseChannelMessagesInterface::Adaptee *adaptee; }; /** * \class BaseChannelMessagesInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.Messages * */ /** * Class constructor. */ BaseChannelMessagesInterface::BaseChannelMessagesInterface(BaseChannelTextType *textType, QStringList supportedContentTypes, UIntList messageTypes, uint messagePartSupportFlags, uint deliveryReportingSupport) : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES), mPriv(new Private(this, textType, supportedContentTypes, messageTypes, messagePartSupportFlags, deliveryReportingSupport)) { } /** * Class destructor. */ BaseChannelMessagesInterface::~BaseChannelMessagesInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelMessagesInterface::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES + QLatin1String(".SupportedContentTypes"), QVariant::fromValue(mPriv->adaptee->supportedContentTypes())); map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES + QLatin1String(".MessageTypes"), QVariant::fromValue(mPriv->adaptee->messageTypes())); map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES + QLatin1String(".MessagePartSupportFlags"), QVariant::fromValue(mPriv->adaptee->messagePartSupportFlags())); map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_MESSAGES + QLatin1String(".DeliveryReportingSupport"), QVariant::fromValue(mPriv->adaptee->deliveryReportingSupport())); return map; } void BaseChannelMessagesInterface::createAdaptor() { (void) new Service::ChannelInterfaceMessagesAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } QStringList BaseChannelMessagesInterface::supportedContentTypes() { return mPriv->supportedContentTypes; } Tp::UIntList BaseChannelMessagesInterface::messageTypes() { return mPriv->messageTypes; } uint BaseChannelMessagesInterface::messagePartSupportFlags() { return mPriv->messagePartSupportFlags; } uint BaseChannelMessagesInterface::deliveryReportingSupport() { return mPriv->deliveryReportingSupport; } Tp::MessagePartListList BaseChannelMessagesInterface::pendingMessages() { return mPriv->textTypeInterface->pendingMessages(); } void BaseChannelMessagesInterface::messageSent(const Tp::MessagePartList &content, uint flags, const QString &messageToken) { QMetaObject::invokeMethod(mPriv->adaptee, "messageSent", Q_ARG(Tp::MessagePartList, content), Q_ARG(uint, flags), Q_ARG(QString, messageToken)); //Can simply use emit in Qt5 } void BaseChannelMessagesInterface::pendingMessagesRemoved(const Tp::UIntList &messageIDs) { QMetaObject::invokeMethod(mPriv->adaptee, "pendingMessagesRemoved", Q_ARG(Tp::UIntList, messageIDs)); //Can simply use emit in Qt5 } void BaseChannelMessagesInterface::messageReceived(const Tp::MessagePartList &message) { QMetaObject::invokeMethod(mPriv->adaptee, "messageReceived", Q_ARG(Tp::MessagePartList, message)); //Can simply use emit in Qt5 } void BaseChannelMessagesInterface::setSendMessageCallback(const SendMessageCallback &cb) { mPriv->sendMessageCB = cb; } QString BaseChannelMessagesInterface::sendMessage(const Tp::MessagePartList &message, uint flags, DBusError* error) { if (!mPriv->sendMessageCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return QString(); } const QString token = mPriv->sendMessageCB(message, flags, error); Tp::MessagePartList fixedMessage = message; MessagePart header = fixedMessage.front(); uint timestamp = 0; if (header.count(QLatin1String("message-sent"))) { timestamp = header[QLatin1String("message-sent")].variant().toUInt(); } else { timestamp = QDateTime::currentMSecsSinceEpoch() / 1000; header[QLatin1String("message-sent")] = QDBusVariant(timestamp); } fixedMessage.replace(0, header); //emit after return QMetaObject::invokeMethod(mPriv->adaptee, "messageSent", Qt::QueuedConnection, Q_ARG(Tp::MessagePartList, fixedMessage), Q_ARG(uint, flags), Q_ARG(QString, token)); if (message.empty()) { warning() << "Sending empty message"; return token; } uint type = ChannelTextMessageTypeNormal; if (header.count(QLatin1String("message-type"))) type = header[QLatin1String("message-type")].variant().toUInt(); QString content; for (MessagePartList::const_iterator i = message.begin() + 1; i != message.end(); ++i) if (i->count(QLatin1String("content-type")) && i->value(QLatin1String("content-type")).variant().toString() == QLatin1String("text/plain") && i->count(QLatin1String("content"))) { content = i->value(QLatin1String("content")).variant().toString(); break; } //emit after return QMetaObject::invokeMethod(mPriv->textTypeInterface, "sent", Qt::QueuedConnection, Q_ARG(uint, timestamp), Q_ARG(uint, type), Q_ARG(QString, content)); return token; } //Chan.T.ServerAuthentication BaseChannelServerAuthenticationType::Adaptee::Adaptee(BaseChannelServerAuthenticationType *interface) : QObject(interface), mInterface(interface) { } BaseChannelServerAuthenticationType::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseChannelServerAuthenticationType::Private { Private(BaseChannelServerAuthenticationType *parent, const QString& authenticationMethod) : authenticationMethod(authenticationMethod), adaptee(new BaseChannelServerAuthenticationType::Adaptee(parent)) { } QString authenticationMethod; BaseChannelServerAuthenticationType::Adaptee *adaptee; }; QString BaseChannelServerAuthenticationType::Adaptee::authenticationMethod() const { return mInterface->mPriv->authenticationMethod; } /** * \class BaseChannelServerAuthenticationType * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Type.ServerAuthentifcation * */ /** * Class constructor. */ BaseChannelServerAuthenticationType::BaseChannelServerAuthenticationType(const QString& authenticationMethod) : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION), mPriv(new Private(this, authenticationMethod)) { } /** * Class destructor. */ BaseChannelServerAuthenticationType::~BaseChannelServerAuthenticationType() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelServerAuthenticationType::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION + QLatin1String(".AuthenticationMethod"), QVariant::fromValue(mPriv->adaptee->authenticationMethod())); return map; } void BaseChannelServerAuthenticationType::createAdaptor() { (void) new Service::ChannelTypeServerAuthenticationAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } //Chan.I.CaptchaAuthentication BaseChannelCaptchaAuthenticationInterface::Adaptee::Adaptee(BaseChannelCaptchaAuthenticationInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelCaptchaAuthenticationInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseChannelCaptchaAuthenticationInterface::Private { Private(BaseChannelCaptchaAuthenticationInterface *parent, bool canRetryCaptcha) : canRetryCaptcha(canRetryCaptcha), captchaStatus(CaptchaStatusLocalPending), adaptee(new BaseChannelCaptchaAuthenticationInterface::Adaptee(parent)) { } bool canRetryCaptcha; bool captchaStatus; QString captchaError; QVariantMap captchaErrorDetails; GetCaptchasCallback getCaptchasCB; GetCaptchaDataCallback getCaptchaDataCB; AnswerCaptchasCallback answerCaptchasCB; CancelCaptchaCallback cancelCaptchaCB; BaseChannelCaptchaAuthenticationInterface::Adaptee *adaptee; }; bool BaseChannelCaptchaAuthenticationInterface::Adaptee::canRetryCaptcha() const { return mInterface->mPriv->canRetryCaptcha; } uint BaseChannelCaptchaAuthenticationInterface::Adaptee::captchaStatus() const { return mInterface->mPriv->captchaStatus; } QString BaseChannelCaptchaAuthenticationInterface::Adaptee::captchaError() const { return mInterface->mPriv->captchaError; } QVariantMap BaseChannelCaptchaAuthenticationInterface::Adaptee::captchaErrorDetails() const { return mInterface->mPriv->captchaErrorDetails; } void BaseChannelCaptchaAuthenticationInterface::Adaptee::getCaptchas(const Tp::Service::ChannelInterfaceCaptchaAuthenticationAdaptor::GetCaptchasContextPtr &context) { qDebug() << "BaseChannelCaptchaAuthenticationInterface::Adaptee::getCaptchas"; DBusError error; Tp::CaptchaInfoList captchaInfo; uint numberRequired; QString language; mInterface->mPriv->getCaptchasCB(captchaInfo, numberRequired, language, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(captchaInfo, numberRequired, language); } void BaseChannelCaptchaAuthenticationInterface::Adaptee::getCaptchaData(uint ID, const QString& mimeType, const Tp::Service::ChannelInterfaceCaptchaAuthenticationAdaptor::GetCaptchaDataContextPtr &context) { qDebug() << "BaseChannelCaptchaAuthenticationInterface::Adaptee::getCaptchaData " << ID << mimeType; DBusError error; QByteArray captchaData = mInterface->mPriv->getCaptchaDataCB(ID, mimeType, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(captchaData); } void BaseChannelCaptchaAuthenticationInterface::Adaptee::answerCaptchas(const Tp::CaptchaAnswers& answers, const Tp::Service::ChannelInterfaceCaptchaAuthenticationAdaptor::AnswerCaptchasContextPtr &context) { qDebug() << "BaseChannelCaptchaAuthenticationInterface::Adaptee::answerCaptchas"; DBusError error; mInterface->mPriv->answerCaptchasCB(answers, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelCaptchaAuthenticationInterface::Adaptee::cancelCaptcha(uint reason, const QString& debugMessage, const Tp::Service::ChannelInterfaceCaptchaAuthenticationAdaptor::CancelCaptchaContextPtr &context) { qDebug() << "BaseChannelCaptchaAuthenticationInterface::Adaptee::cancelCaptcha " << reason << " " << debugMessage; DBusError error; mInterface->mPriv->cancelCaptchaCB(reason, debugMessage, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseChannelCaptchaAuthenticationInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.CaptchaAuthentication * */ /** * Class constructor. */ BaseChannelCaptchaAuthenticationInterface::BaseChannelCaptchaAuthenticationInterface(bool canRetryCaptcha) : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION), mPriv(new Private(this, canRetryCaptcha)) { } /** * Class destructor. */ BaseChannelCaptchaAuthenticationInterface::~BaseChannelCaptchaAuthenticationInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelCaptchaAuthenticationInterface::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION + QLatin1String(".CanRetryCaptcha"), QVariant::fromValue(mPriv->adaptee->canRetryCaptcha())); return map; } void BaseChannelCaptchaAuthenticationInterface::createAdaptor() { (void) new Service::ChannelInterfaceCaptchaAuthenticationAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseChannelCaptchaAuthenticationInterface::setGetCaptchasCallback(const GetCaptchasCallback &cb) { mPriv->getCaptchasCB = cb; } void BaseChannelCaptchaAuthenticationInterface::setGetCaptchaDataCallback(const GetCaptchaDataCallback &cb) { mPriv->getCaptchaDataCB = cb; } void BaseChannelCaptchaAuthenticationInterface::setAnswerCaptchasCallback(const AnswerCaptchasCallback &cb) { mPriv->answerCaptchasCB = cb; } void BaseChannelCaptchaAuthenticationInterface::setCancelCaptchaCallback(const CancelCaptchaCallback &cb) { mPriv->cancelCaptchaCB = cb; } void BaseChannelCaptchaAuthenticationInterface::setCaptchaStatus(uint status) { mPriv->captchaStatus = status; notifyPropertyChanged(QLatin1String("CaptchaStatus"), QVariant::fromValue(status)); } void BaseChannelCaptchaAuthenticationInterface::setCaptchaError(const QString& busName) { mPriv->captchaError = busName; notifyPropertyChanged(QLatin1String("CaptchaError"), QVariant::fromValue(busName)); } void BaseChannelCaptchaAuthenticationInterface::setCaptchaErrorDetails(const QVariantMap& error) { mPriv->captchaErrorDetails = error; notifyPropertyChanged(QLatin1String("CaptchaErrorDetails"), QVariant::fromValue(error)); } //Chan.I.SASLAuthentication struct TP_QT_NO_EXPORT BaseChannelSASLAuthenticationInterface::Private { Private(BaseChannelSASLAuthenticationInterface *parent, const QStringList &availableMechanisms, bool hasInitialData, bool canTryAgain, const QString &authorizationIdentity, const QString &defaultUsername, const QString &defaultRealm, bool maySaveResponse) : availableMechanisms(availableMechanisms), hasInitialData(hasInitialData), canTryAgain(canTryAgain), saslStatus(0), authorizationIdentity(authorizationIdentity), defaultUsername(defaultUsername), defaultRealm(defaultRealm), maySaveResponse(maySaveResponse), adaptee(new BaseChannelSASLAuthenticationInterface::Adaptee(parent)) { } QStringList availableMechanisms; bool hasInitialData; bool canTryAgain; uint saslStatus; QString saslError; QVariantMap saslErrorDetails; QString authorizationIdentity; QString defaultUsername; QString defaultRealm; bool maySaveResponse; StartMechanismCallback startMechanismCB; StartMechanismWithDataCallback startMechanismWithDataCB; RespondCallback respondCB; AcceptSASLCallback acceptSaslCB; AbortSASLCallback abortSaslCB; BaseChannelSASLAuthenticationInterface::Adaptee *adaptee; }; BaseChannelSASLAuthenticationInterface::Adaptee::Adaptee(BaseChannelSASLAuthenticationInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelSASLAuthenticationInterface::Adaptee::~Adaptee() { } QStringList BaseChannelSASLAuthenticationInterface::Adaptee::availableMechanisms() const { return mInterface->availableMechanisms(); } bool BaseChannelSASLAuthenticationInterface::Adaptee::hasInitialData() const { return mInterface->hasInitialData(); } bool BaseChannelSASLAuthenticationInterface::Adaptee::canTryAgain() const { return mInterface->canTryAgain(); } uint BaseChannelSASLAuthenticationInterface::Adaptee::saslStatus() const { return mInterface->saslStatus(); } QString BaseChannelSASLAuthenticationInterface::Adaptee::saslError() const { return mInterface->saslError(); } QVariantMap BaseChannelSASLAuthenticationInterface::Adaptee::saslErrorDetails() const { return mInterface->saslErrorDetails(); } QString BaseChannelSASLAuthenticationInterface::Adaptee::authorizationIdentity() const { return mInterface->authorizationIdentity(); } QString BaseChannelSASLAuthenticationInterface::Adaptee::defaultUsername() const { return mInterface->defaultUsername(); } QString BaseChannelSASLAuthenticationInterface::Adaptee::defaultRealm() const { return mInterface->defaultRealm(); } bool BaseChannelSASLAuthenticationInterface::Adaptee::maySaveResponse() const { return mInterface->maySaveResponse(); } void BaseChannelSASLAuthenticationInterface::Adaptee::startMechanism(const QString &mechanism, const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::StartMechanismContextPtr &context) { qDebug() << "BaseChannelSASLAuthenticationInterface::Adaptee::startMechanism"; DBusError error; mInterface->startMechanism(mechanism, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelSASLAuthenticationInterface::Adaptee::startMechanismWithData(const QString &mechanism, const QByteArray &initialData, const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::StartMechanismWithDataContextPtr &context) { qDebug() << "BaseChannelSASLAuthenticationInterface::Adaptee::startMechanismWithData"; DBusError error; mInterface->startMechanismWithData(mechanism, initialData, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelSASLAuthenticationInterface::Adaptee::respond(const QByteArray &responseData, const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::RespondContextPtr &context) { qDebug() << "BaseChannelSASLAuthenticationInterface::Adaptee::respond"; DBusError error; mInterface->respond(responseData, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelSASLAuthenticationInterface::Adaptee::acceptSasl( const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::AcceptSASLContextPtr &context) { qDebug() << "BaseChannelSASLAuthenticationInterface::Adaptee::acceptSasl"; DBusError error; mInterface->acceptSasl(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelSASLAuthenticationInterface::Adaptee::abortSasl(uint reason, const QString &debugMessage, const Tp::Service::ChannelInterfaceSASLAuthenticationAdaptor::AbortSASLContextPtr &context) { qDebug() << "BaseChannelSASLAuthenticationInterface::Adaptee::abortSasl"; DBusError error; mInterface->abortSasl(reason, debugMessage, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseChannelSASLAuthenticationInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.SASLAuthentication * */ /** * Class constructor. */ BaseChannelSASLAuthenticationInterface::BaseChannelSASLAuthenticationInterface(const QStringList &availableMechanisms, bool hasInitialData, bool canTryAgain, const QString &authorizationIdentity, const QString &defaultUsername, const QString &defaultRealm, bool maySaveResponse) : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION), mPriv(new Private(this, availableMechanisms, hasInitialData, canTryAgain, authorizationIdentity, defaultUsername, defaultRealm, maySaveResponse)) { } /** * Class destructor. */ BaseChannelSASLAuthenticationInterface::~BaseChannelSASLAuthenticationInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelSASLAuthenticationInterface::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION + QLatin1String(".AvailableMechanisms"), QVariant::fromValue(mPriv->adaptee->availableMechanisms())); map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION + QLatin1String(".HasInitialData"), QVariant::fromValue(mPriv->adaptee->hasInitialData())); map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION + QLatin1String(".CanTryAgain"), QVariant::fromValue(mPriv->adaptee->canTryAgain())); map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION + QLatin1String(".AuthorizationIdentity"), QVariant::fromValue(mPriv->adaptee->authorizationIdentity())); map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION + QLatin1String(".DefaultUsername"), QVariant::fromValue(mPriv->adaptee->defaultUsername())); map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION + QLatin1String(".DefaultRealm"), QVariant::fromValue(mPriv->adaptee->defaultRealm())); map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION + QLatin1String(".MaySaveResponse"), QVariant::fromValue(mPriv->adaptee->maySaveResponse())); return map; } QStringList BaseChannelSASLAuthenticationInterface::availableMechanisms() const { return mPriv->availableMechanisms; } bool BaseChannelSASLAuthenticationInterface::hasInitialData() const { return mPriv->hasInitialData; } bool BaseChannelSASLAuthenticationInterface::canTryAgain() const { return mPriv->canTryAgain; } uint BaseChannelSASLAuthenticationInterface::saslStatus() const { return mPriv->saslStatus; } void BaseChannelSASLAuthenticationInterface::setSaslStatus(uint status, const QString &reason, const QVariantMap &details) { mPriv->saslStatus = status; QMetaObject::invokeMethod(mPriv->adaptee, "saslStatusChanged", Q_ARG(uint, status), Q_ARG(QString, reason), Q_ARG(QVariantMap, details)); //Can simply use emit in Qt5 } QString BaseChannelSASLAuthenticationInterface::saslError() const { return mPriv->saslError; } void BaseChannelSASLAuthenticationInterface::setSaslError(const QString &saslError) { mPriv->saslError = saslError; } QVariantMap BaseChannelSASLAuthenticationInterface::saslErrorDetails() const { return mPriv->saslErrorDetails; } void BaseChannelSASLAuthenticationInterface::setSaslErrorDetails(const QVariantMap &saslErrorDetails) { mPriv->saslErrorDetails = saslErrorDetails; } QString BaseChannelSASLAuthenticationInterface::authorizationIdentity() const { return mPriv->authorizationIdentity; } QString BaseChannelSASLAuthenticationInterface::defaultUsername() const { return mPriv->defaultUsername; } QString BaseChannelSASLAuthenticationInterface::defaultRealm() const { return mPriv->defaultRealm; } bool BaseChannelSASLAuthenticationInterface::maySaveResponse() const { return mPriv->maySaveResponse; } void BaseChannelSASLAuthenticationInterface::createAdaptor() { (void) new Service::ChannelInterfaceSASLAuthenticationAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseChannelSASLAuthenticationInterface::setStartMechanismCallback(const BaseChannelSASLAuthenticationInterface::StartMechanismCallback &cb) { mPriv->startMechanismCB = cb; } void BaseChannelSASLAuthenticationInterface::startMechanism(const QString &mechanism, DBusError *error) { if (!mPriv->startMechanismCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->startMechanismCB(mechanism, error); } void BaseChannelSASLAuthenticationInterface::setStartMechanismWithDataCallback(const BaseChannelSASLAuthenticationInterface::StartMechanismWithDataCallback &cb) { mPriv->startMechanismWithDataCB = cb; } void BaseChannelSASLAuthenticationInterface::startMechanismWithData(const QString &mechanism, const QByteArray &initialData, DBusError *error) { if (!mPriv->startMechanismWithDataCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->startMechanismWithDataCB(mechanism, initialData, error); } void BaseChannelSASLAuthenticationInterface::setRespondCallback(const BaseChannelSASLAuthenticationInterface::RespondCallback &cb) { mPriv->respondCB = cb; } void BaseChannelSASLAuthenticationInterface::respond(const QByteArray &responseData, DBusError *error) { if (!mPriv->respondCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->respondCB(responseData, error); } void BaseChannelSASLAuthenticationInterface::setAcceptSaslCallback(const BaseChannelSASLAuthenticationInterface::AcceptSASLCallback &cb) { mPriv->acceptSaslCB = cb; } void BaseChannelSASLAuthenticationInterface::acceptSasl(DBusError *error) { if (!mPriv->acceptSaslCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->acceptSaslCB(error); } void BaseChannelSASLAuthenticationInterface::setAbortSaslCallback(const BaseChannelSASLAuthenticationInterface::AbortSASLCallback &cb) { mPriv->abortSaslCB = cb; } void BaseChannelSASLAuthenticationInterface::abortSasl(uint reason, const QString &debugMessage, DBusError *error) { if (!mPriv->abortSaslCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->abortSaslCB(reason, debugMessage, error); } void BaseChannelSASLAuthenticationInterface::newChallenge(const QByteArray &challengeData) { QMetaObject::invokeMethod(mPriv->adaptee, "newChallenge", Q_ARG(QByteArray, challengeData)); //Can simply use emit in Qt5 } // Chan.I.Securable struct TP_QT_NO_EXPORT BaseChannelSecurableInterface::Private { Private(BaseChannelSecurableInterface *parent) : encrypted(false), verified(false), adaptee(new BaseChannelSecurableInterface::Adaptee(parent)) { } bool encrypted; bool verified; BaseChannelSecurableInterface::Adaptee *adaptee; }; BaseChannelSecurableInterface::Adaptee::Adaptee(BaseChannelSecurableInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelSecurableInterface::Adaptee::~Adaptee() { } bool BaseChannelSecurableInterface::Adaptee::encrypted() const { return mInterface->encrypted(); } bool BaseChannelSecurableInterface::Adaptee::verified() const { return mInterface->verified(); } /** * \class BaseChannelSecurableInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.Securable */ /** * Class constructor. */ BaseChannelSecurableInterface::BaseChannelSecurableInterface() : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_SECURABLE), mPriv(new Private(this)) { } /** * Class destructor. */ BaseChannelSecurableInterface::~BaseChannelSecurableInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelSecurableInterface::immutableProperties() const { QVariantMap map; return map; } bool BaseChannelSecurableInterface::encrypted() const { return mPriv->encrypted; } void BaseChannelSecurableInterface::setEncrypted(bool encrypted) { mPriv->encrypted = encrypted; } bool BaseChannelSecurableInterface::verified() const { return mPriv->verified; } void BaseChannelSecurableInterface::setVerified(bool verified) { mPriv->verified = verified; } void BaseChannelSecurableInterface::createAdaptor() { (void) new Service::ChannelInterfaceSecurableAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } // Chan.I.ChatState struct TP_QT_NO_EXPORT BaseChannelChatStateInterface::Private { Private(BaseChannelChatStateInterface *parent) : adaptee(new BaseChannelChatStateInterface::Adaptee(parent)) { } Tp::ChatStateMap chatStates; SetChatStateCallback setChatStateCB; BaseChannelChatStateInterface::Adaptee *adaptee; }; BaseChannelChatStateInterface::Adaptee::Adaptee(BaseChannelChatStateInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelChatStateInterface::Adaptee::~Adaptee() { } Tp::ChatStateMap BaseChannelChatStateInterface::Adaptee::chatStates() const { return mInterface->chatStates(); } void BaseChannelChatStateInterface::Adaptee::setChatState(uint state, const Tp::Service::ChannelInterfaceChatStateAdaptor::SetChatStateContextPtr &context) { qDebug() << "BaseChannelChatStateInterface::Adaptee::setChatState"; DBusError error; mInterface->setChatState(state, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseChannelChatStateInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.Chat.State */ /** * Class constructor. */ BaseChannelChatStateInterface::BaseChannelChatStateInterface() : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_CHAT_STATE), mPriv(new Private(this)) { } /** * Class destructor. */ BaseChannelChatStateInterface::~BaseChannelChatStateInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelChatStateInterface::immutableProperties() const { QVariantMap map; return map; } Tp::ChatStateMap BaseChannelChatStateInterface::chatStates() const { return mPriv->chatStates; } void BaseChannelChatStateInterface::setChatStates(const Tp::ChatStateMap &chatStates) { mPriv->chatStates = chatStates; } void BaseChannelChatStateInterface::createAdaptor() { (void) new Service::ChannelInterfaceChatStateAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseChannelChatStateInterface::setSetChatStateCallback(const BaseChannelChatStateInterface::SetChatStateCallback &cb) { mPriv->setChatStateCB = cb; } void BaseChannelChatStateInterface::setChatState(uint state, DBusError *error) { if (!mPriv->setChatStateCB.isValid()) { error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } return mPriv->setChatStateCB(state, error); } void BaseChannelChatStateInterface::chatStateChanged(uint contact, uint state) { QMetaObject::invokeMethod(mPriv->adaptee, "chatStateChanged", Q_ARG(uint, contact), Q_ARG(uint, state)); //Can simply use emit in Qt5 } //Chan.I.Group BaseChannelGroupInterface::Adaptee::Adaptee(BaseChannelGroupInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelGroupInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseChannelGroupInterface::Private { Private(BaseChannelGroupInterface *parent, ChannelGroupFlags initialFlags, uint selfHandle) : flags(initialFlags), selfHandle(selfHandle), adaptee(new BaseChannelGroupInterface::Adaptee(parent)) { } ChannelGroupFlags flags; Tp::HandleOwnerMap handleOwners; Tp::LocalPendingInfoList localPendingMembers; Tp::UIntList members; Tp::UIntList remotePendingMembers; uint selfHandle; Tp::HandleIdentifierMap memberIdentifiers; RemoveMembersCallback removeMembersCB; AddMembersCallback addMembersCB; Tp::UIntList getLocalPendingMembers() const { Tp::UIntList ret; foreach(const LocalPendingInfo & info, localPendingMembers) ret << info.toBeAdded; return ret; } BaseChannelGroupInterface::Adaptee *adaptee; }; uint BaseChannelGroupInterface::Adaptee::groupFlags() const { return mInterface->mPriv->flags; } Tp::HandleOwnerMap BaseChannelGroupInterface::Adaptee::handleOwners() const { return mInterface->mPriv->handleOwners; } Tp::LocalPendingInfoList BaseChannelGroupInterface::Adaptee::localPendingMembers() const { return mInterface->mPriv->localPendingMembers; } Tp::UIntList BaseChannelGroupInterface::Adaptee::members() const { return mInterface->mPriv->members; } Tp::UIntList BaseChannelGroupInterface::Adaptee::remotePendingMembers() const { return mInterface->mPriv->remotePendingMembers; } uint BaseChannelGroupInterface::Adaptee::selfHandle() const { return mInterface->mPriv->selfHandle; } Tp::HandleIdentifierMap BaseChannelGroupInterface::Adaptee::memberIdentifiers() const { return mInterface->mPriv->memberIdentifiers; } void BaseChannelGroupInterface::Adaptee::addMembers(const Tp::UIntList& contacts, const QString& message, const Tp::Service::ChannelInterfaceGroupAdaptor::AddMembersContextPtr &context) { debug() << "BaseChannelGroupInterface::Adaptee::addMembers"; if (!mInterface->mPriv->addMembersCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->addMembersCB(contacts, message, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelGroupInterface::Adaptee::removeMembers(const Tp::UIntList& contacts, const QString& message, const Tp::Service::ChannelInterfaceGroupAdaptor::RemoveMembersContextPtr &context) { debug() << "BaseChannelGroupInterface::Adaptee::removeMembers"; if (!mInterface->mPriv->removeMembersCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->removeMembersCB(contacts, message, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelGroupInterface::Adaptee::removeMembersWithReason(const Tp::UIntList& contacts, const QString& message, uint reason, const Tp::Service::ChannelInterfaceGroupAdaptor::RemoveMembersWithReasonContextPtr &context) { debug() << "BaseChannelGroupInterface::Adaptee::removeMembersWithReason"; removeMembers(contacts, message, context); } void BaseChannelGroupInterface::Adaptee::getAllMembers(const Tp::Service::ChannelInterfaceGroupAdaptor::GetAllMembersContextPtr &context) { context->setFinished(mInterface->mPriv->members, mInterface->mPriv->getLocalPendingMembers(), mInterface->mPriv->remotePendingMembers); } void BaseChannelGroupInterface::Adaptee::getGroupFlags(const Tp::Service::ChannelInterfaceGroupAdaptor::GetGroupFlagsContextPtr &context) { context->setFinished(mInterface->mPriv->flags); } void BaseChannelGroupInterface::Adaptee::getHandleOwners(const Tp::UIntList& handles, const Tp::Service::ChannelInterfaceGroupAdaptor::GetHandleOwnersContextPtr &context) { Tp::UIntList ret; foreach(uint handle, handles) ret.append(mInterface->mPriv->handleOwners.contains(handle) ? mInterface->mPriv->handleOwners[handle] : 0); context->setFinished(ret); } void BaseChannelGroupInterface::Adaptee::getLocalPendingMembers(const Tp::Service::ChannelInterfaceGroupAdaptor::GetLocalPendingMembersContextPtr &context) { context->setFinished(mInterface->mPriv->getLocalPendingMembers()); } void BaseChannelGroupInterface::Adaptee::getLocalPendingMembersWithInfo(const Tp::Service::ChannelInterfaceGroupAdaptor::GetLocalPendingMembersWithInfoContextPtr &context) { context->setFinished(mInterface->mPriv->localPendingMembers); } void BaseChannelGroupInterface::Adaptee::getMembers(const Tp::Service::ChannelInterfaceGroupAdaptor::GetMembersContextPtr &context) { context->setFinished(mInterface->mPriv->members); } void BaseChannelGroupInterface::Adaptee::getRemotePendingMembers(const Tp::Service::ChannelInterfaceGroupAdaptor::GetRemotePendingMembersContextPtr &context) { context->setFinished(mInterface->mPriv->remotePendingMembers); } void BaseChannelGroupInterface::Adaptee::getSelfHandle(const Tp::Service::ChannelInterfaceGroupAdaptor::GetSelfHandleContextPtr &context) { context->setFinished(mInterface->mPriv->selfHandle); } /** * \class BaseChannelGroupInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.Group * */ /** * Class constructor. */ BaseChannelGroupInterface::BaseChannelGroupInterface(ChannelGroupFlags initialFlags, uint selfHandle) : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_GROUP), mPriv(new Private(this, initialFlags, selfHandle)) { } /** * Class destructor. */ BaseChannelGroupInterface::~BaseChannelGroupInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelGroupInterface::immutableProperties() const { QVariantMap map; return map; } void BaseChannelGroupInterface::createAdaptor() { (void) new Service::ChannelInterfaceGroupAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseChannelGroupInterface::setRemoveMembersCallback(const RemoveMembersCallback &cb) { mPriv->removeMembersCB = cb; } void BaseChannelGroupInterface::setAddMembersCallback(const AddMembersCallback &cb) { mPriv->addMembersCB = cb; } void BaseChannelGroupInterface::addMembers(const Tp::UIntList& handles, const QStringList& identifiers) { if (handles.size() != identifiers.size()) { debug() << "BaseChannelGroupInterface::addMembers: handles.size() != identifiers.size()"; return; } Tp::UIntList added; for (int i = 0; i < handles.size(); ++i) { uint handle = handles[i]; if (mPriv->members.contains(handle)) continue; mPriv->memberIdentifiers[handle] = identifiers[i]; mPriv->members.append(handle); added.append(handle); } if (!added.isEmpty()) QMetaObject::invokeMethod(mPriv->adaptee,"membersChanged",Q_ARG(QString, QString()), Q_ARG(Tp::UIntList, added), Q_ARG(Tp::UIntList, Tp::UIntList()), Q_ARG(Tp::UIntList, Tp::UIntList()), Q_ARG(Tp::UIntList, Tp::UIntList()), Q_ARG(uint, 0), Q_ARG(uint, ChannelGroupChangeReasonNone)); //Can simply use emit in Qt5 } void BaseChannelGroupInterface::removeMembers(const Tp::UIntList& handles) { Tp::UIntList removed; foreach(uint handle, handles) { if (mPriv->members.contains(handle)) continue; mPriv->memberIdentifiers.remove(handle); mPriv->members.removeAll(handle); removed.append(handle); } if (!removed.isEmpty()) QMetaObject::invokeMethod(mPriv->adaptee,"membersChanged",Q_ARG(QString, QString()), Q_ARG(Tp::UIntList, Tp::UIntList()), Q_ARG(Tp::UIntList, removed), Q_ARG(Tp::UIntList, Tp::UIntList()), Q_ARG(Tp::UIntList, Tp::UIntList()), Q_ARG(uint, 0), Q_ARG(uint,ChannelGroupChangeReasonNone)); //Can simply use emit in Qt5 //Can simply use emit in Qt5 } // Chan.T.Call BaseChannelCallType::Adaptee::Adaptee(BaseChannelCallType *interface) : QObject(interface), mInterface(interface) { } BaseChannelCallType::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseChannelCallType::Private { Private(BaseChannelCallType *parent, BaseChannel* channel, bool hardwareStreaming, uint initialTransport, bool initialAudio, bool initialVideo, QString initialAudioName, QString initialVideoName, bool mutableContents) : hardwareStreaming(hardwareStreaming), initialTransport(initialTransport), initialAudio(initialAudio), initialVideo(initialVideo), initialAudioName(initialAudioName), initialVideoName(initialVideoName), mutableContents(mutableContents), channel(channel), adaptee(new BaseChannelCallType::Adaptee(parent)) { } Tp::ObjectPathList contents; QVariantMap callStateDetails; uint callState; uint callFlags; Tp::CallStateReason callStateReason; bool hardwareStreaming; Tp::CallMemberMap callMembers; Tp::HandleIdentifierMap memberIdentifiers; uint initialTransport; bool initialAudio; bool initialVideo; QString initialAudioName; QString initialVideoName; bool mutableContents; QList mCallContents; AcceptCallback acceptCB; HangupCallback hangupCB; SetQueuedCallback setQueuedCB; SetRingingCallback setRingingCB; AddContentCallback addContentCB; BaseChannel *channel; BaseChannelCallType::Adaptee *adaptee; }; void BaseChannelCallType::Adaptee::setRinging(const Tp::Service::ChannelTypeCallAdaptor::SetRingingContextPtr &context) { if (!mInterface->mPriv->setRingingCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->setRingingCB(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelCallType::Adaptee::setQueued(const Tp::Service::ChannelTypeCallAdaptor::SetQueuedContextPtr &context) { if (!mInterface->mPriv->setQueuedCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->setQueuedCB(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelCallType::Adaptee::accept(const Tp::Service::ChannelTypeCallAdaptor::AcceptContextPtr &context) { if (!mInterface->mPriv->acceptCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->acceptCB(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelCallType::Adaptee::hangup(uint reason, const QString &detailedHangupReason, const QString &message, const Tp::Service::ChannelTypeCallAdaptor::HangupContextPtr &context) { if (!mInterface->mPriv->hangupCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->hangupCB(reason, detailedHangupReason, message, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } void BaseChannelCallType::Adaptee::addContent(const QString &contentName, const Tp::MediaStreamType &contentType, const Tp::MediaStreamDirection &initialDirection, const Tp::Service::ChannelTypeCallAdaptor::AddContentContextPtr &context) { if (!mInterface->mPriv->addContentCB.isValid()) { Tp::BaseCallContentPtr ptr = mInterface->addContent(contentName, contentType, initialDirection); QDBusObjectPath objPath; objPath.setPath(ptr->objectPath()); context->setFinished(objPath); return; } DBusError error; QDBusObjectPath objPath = mInterface->mPriv->addContentCB(contentName, contentType, initialDirection, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(objPath); } /** * \class BaseChannelCallType * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Type.Call * */ /** * Class constructor. */ BaseChannelCallType::BaseChannelCallType(BaseChannel* channel, bool hardwareStreaming, uint initialTransport, bool initialAudio, bool initialVideo, QString initialAudioName, QString initialVideoName, bool mutableContents) : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_TYPE_CALL), mPriv(new Private(this, channel, hardwareStreaming, initialTransport, initialAudio, initialVideo, initialAudioName, initialVideoName, mutableContents)) { } Tp::ObjectPathList BaseChannelCallType::contents() { return mPriv->contents; } QVariantMap BaseChannelCallType::callStateDetails() { return mPriv->callStateDetails; } uint BaseChannelCallType::callState() { return mPriv->callState; } uint BaseChannelCallType::callFlags() { return mPriv->callFlags; } Tp::CallStateReason BaseChannelCallType::callStateReason() { return mPriv->callStateReason; } bool BaseChannelCallType::hardwareStreaming() { return mPriv->hardwareStreaming; } Tp::CallMemberMap BaseChannelCallType::callMembers() { return mPriv->callMembers; } Tp::HandleIdentifierMap BaseChannelCallType::memberIdentifiers() { return mPriv->memberIdentifiers; } uint BaseChannelCallType::initialTransport() { return mPriv->initialTransport; } bool BaseChannelCallType::initialAudio() { return mPriv->initialAudio; } bool BaseChannelCallType::initialVideo() { return mPriv->initialVideo; } QString BaseChannelCallType::initialVideoName() { return mPriv->initialVideoName; } QString BaseChannelCallType::initialAudioName() { return mPriv->initialAudioName; } bool BaseChannelCallType::mutableContents() { return mPriv->mutableContents; } /** * Class destructor. */ BaseChannelCallType::~BaseChannelCallType() { delete mPriv; } QVariantMap BaseChannelCallType::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".HardwareStreaming"), QVariant::fromValue(mPriv->adaptee->hardwareStreaming())); map.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialTransport"), QVariant::fromValue(mPriv->adaptee->initialTransport())); map.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudio"), QVariant::fromValue(mPriv->adaptee->initialAudio())); map.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideo"), QVariant::fromValue(mPriv->adaptee->initialVideo())); map.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialAudioName"), QVariant::fromValue(mPriv->adaptee->initialAudioName())); map.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".InitialVideoName"), QVariant::fromValue(mPriv->adaptee->initialVideoName())); map.insert(TP_QT_IFACE_CHANNEL_TYPE_CALL + QLatin1String(".MutableContents"), QVariant::fromValue(mPriv->adaptee->mutableContents())); return map; } void BaseChannelCallType::createAdaptor() { (void) new Service::ChannelTypeCallAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } void BaseChannelCallType::setCallState(const Tp::CallState &state, uint flags, const Tp::CallStateReason &stateReason, const QVariantMap &callStateDetails) { mPriv->callState = state; mPriv->callFlags = flags; mPriv->callStateReason = stateReason; mPriv->callStateDetails = callStateDetails; QMetaObject::invokeMethod(mPriv->adaptee, "callStateChanged", Q_ARG(Tp::CallState, state), Q_ARG(uint, flags), Q_ARG(Tp::CallStateReason, stateReason), Q_ARG(QVariantMap, callStateDetails)); } void BaseChannelCallType::setAcceptCallback(const AcceptCallback &cb) { mPriv->acceptCB = cb; } void BaseChannelCallType::setHangupCallback(const HangupCallback &cb) { mPriv->hangupCB = cb; } void BaseChannelCallType::setSetRingingCallback(const SetRingingCallback &cb) { mPriv->setRingingCB = cb; } void BaseChannelCallType::setSetQueuedCallback(const SetQueuedCallback &cb) { mPriv->setQueuedCB = cb; } void BaseChannelCallType::setAddContentCallback(const AddContentCallback &cb) { mPriv->addContentCB = cb; } void BaseChannelCallType::setMembersFlags(const Tp::CallMemberMap &flagsChanged, const Tp::HandleIdentifierMap &identifiers, const Tp::UIntList &removed, const Tp::CallStateReason &reason) { mPriv->callMembers = flagsChanged; mPriv->memberIdentifiers = identifiers; QMetaObject::invokeMethod(mPriv->adaptee, "callMembersChanged", Q_ARG(Tp::CallMemberMap, flagsChanged), Q_ARG(Tp::HandleIdentifierMap, identifiers), Q_ARG(Tp::UIntList, removed), Q_ARG(Tp::CallStateReason, reason)); } BaseCallContentPtr BaseChannelCallType::addContent(const QString &name, const Tp::MediaStreamType &type, const Tp::MediaStreamDirection &direction) { BaseCallContentPtr ptr = BaseCallContent::create(mPriv->channel->dbusConnection(), mPriv->channel, name, type, direction); DBusError error; ptr->registerObject(&error); QDBusObjectPath objpath; objpath.setPath(ptr->objectPath()); mPriv->contents.append(objpath); QMetaObject::invokeMethod(mPriv->adaptee, "contentAdded", Q_ARG(QDBusObjectPath, objpath)); return ptr; } void BaseChannelCallType::addContent(BaseCallContentPtr content) { DBusError error; content->registerObject(&error); QDBusObjectPath objpath; objpath.setPath(content->objectPath()); mPriv->contents.append(objpath); QMetaObject::invokeMethod(mPriv->adaptee, "contentAdded", Q_ARG(QDBusObjectPath, objpath)); } // Chan.I.Hold BaseChannelHoldInterface::Adaptee::Adaptee(BaseChannelHoldInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelHoldInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseChannelHoldInterface::Private { Private(BaseChannelHoldInterface *parent, Tp::LocalHoldState state) : state(state), reason(Tp::LocalHoldStateReasonNone), adaptee(new BaseChannelHoldInterface::Adaptee(parent)) { } SetHoldStateCallback setHoldStateCB; Tp::LocalHoldState state; Tp::LocalHoldStateReason reason; BaseChannelHoldInterface::Adaptee *adaptee; }; void BaseChannelHoldInterface::Adaptee::getHoldState(const Tp::Service::ChannelInterfaceHoldAdaptor::GetHoldStateContextPtr &context) { context->setFinished(mInterface->getHoldState(), mInterface->getHoldReason()); } void BaseChannelHoldInterface::Adaptee::requestHold(bool hold, const Tp::Service::ChannelInterfaceHoldAdaptor::RequestHoldContextPtr &context) { if (!mInterface->mPriv->setHoldStateCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } Tp::LocalHoldState state = hold ? Tp::LocalHoldStateHeld : Tp::LocalHoldStateUnheld; DBusError error; mInterface->mPriv->setHoldStateCB(state, Tp::LocalHoldStateReasonRequested, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseChannelHoldInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.Hold * */ /** * Class constructor. */ BaseChannelHoldInterface::BaseChannelHoldInterface() : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_HOLD), mPriv(new Private(this, Tp::LocalHoldStateUnheld)) { } Tp::LocalHoldState BaseChannelHoldInterface::getHoldState() const { return mPriv->state; } Tp::LocalHoldStateReason BaseChannelHoldInterface::getHoldReason() const { return mPriv->reason; } void BaseChannelHoldInterface::setSetHoldStateCallback(const SetHoldStateCallback &cb) { mPriv->setHoldStateCB = cb; } void BaseChannelHoldInterface::setHoldState(const Tp::LocalHoldState &state, const Tp::LocalHoldStateReason &reason) { if (mPriv->state != state) { mPriv->state = state; mPriv->reason = reason; QMetaObject::invokeMethod(mPriv->adaptee, "holdStateChanged", Q_ARG(Tp::LocalHoldState, state), Q_ARG(Tp::LocalHoldStateReason, reason)); } } /** * Class destructor. */ BaseChannelHoldInterface::~BaseChannelHoldInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelHoldInterface::immutableProperties() const { QVariantMap map; return map; } void BaseChannelHoldInterface::createAdaptor() { (void) new Service::ChannelInterfaceHoldAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } // Chan.I.MergeableConference BaseChannelMergeableConferenceInterface::Adaptee::Adaptee(BaseChannelMergeableConferenceInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelMergeableConferenceInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseChannelMergeableConferenceInterface::Private { Private(BaseChannelMergeableConferenceInterface *parent) :adaptee(new BaseChannelMergeableConferenceInterface::Adaptee(parent)) { } MergeCallback mergeCB; BaseChannelMergeableConferenceInterface::Adaptee *adaptee; }; void BaseChannelMergeableConferenceInterface::Adaptee::merge(const QDBusObjectPath &channelPath, const Tp::Service::ChannelInterfaceMergeableConferenceAdaptor::MergeContextPtr &context) { if (!mInterface->mPriv->mergeCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->mergeCB(channelPath, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseChannelMergeableConferenceInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.MergeableConference * */ /** * Class constructor. */ BaseChannelMergeableConferenceInterface::BaseChannelMergeableConferenceInterface() : AbstractChannelInterface(TP_QT_FUTURE_IFACE_CHANNEL_INTERFACE_MERGEABLE_CONFERENCE), mPriv(new Private(this)) { } void BaseChannelMergeableConferenceInterface::setMergeCallback(const MergeCallback &cb) { mPriv->mergeCB = cb; } /** * Class destructor. */ BaseChannelMergeableConferenceInterface::~BaseChannelMergeableConferenceInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelMergeableConferenceInterface::immutableProperties() const { QVariantMap map; return map; } void BaseChannelMergeableConferenceInterface::createAdaptor() { (void) new Service::ChannelInterfaceMergeableConferenceAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } // Chan.I.Splittable BaseChannelSplittableInterface::Adaptee::Adaptee(BaseChannelSplittableInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelSplittableInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseChannelSplittableInterface::Private { Private(BaseChannelSplittableInterface *parent) :adaptee(new BaseChannelSplittableInterface::Adaptee(parent)) { } SplitCallback splitCB; BaseChannelSplittableInterface::Adaptee *adaptee; }; void BaseChannelSplittableInterface::Adaptee::split(const Tp::Service::ChannelInterfaceSplittableAdaptor::SplitContextPtr &context) { if (!mInterface->mPriv->splitCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->splitCB(&error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } context->setFinished(); } /** * \class BaseChannelSplittableInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.Splittable * */ /** * Class constructor. */ BaseChannelSplittableInterface::BaseChannelSplittableInterface() : AbstractChannelInterface(TP_QT_FUTURE_IFACE_CHANNEL_INTERFACE_SPLITTABLE), mPriv(new Private(this)) { } void BaseChannelSplittableInterface::setSplitCallback(const SplitCallback &cb) { mPriv->splitCB = cb; } /** * Class destructor. */ BaseChannelSplittableInterface::~BaseChannelSplittableInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelSplittableInterface::immutableProperties() const { QVariantMap map; return map; } void BaseChannelSplittableInterface::createAdaptor() { (void) new Service::ChannelInterfaceSplittableAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } // Chan.I.Conference BaseChannelConferenceInterface::Adaptee::Adaptee(BaseChannelConferenceInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelConferenceInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseChannelConferenceInterface::Private { Private(BaseChannelConferenceInterface *parent, Tp::ObjectPathList initialChannels, Tp::UIntList initialInviteeHandles, QStringList initialInviteeIDs, QString invitationMessage, ChannelOriginatorMap originalChannels) : channels(initialChannels), initialChannels(initialChannels), initialInviteeHandles(initialInviteeHandles), initialInviteeIDs(initialInviteeIDs), invitationMessage(invitationMessage), originalChannels(originalChannels), adaptee(new BaseChannelConferenceInterface::Adaptee(parent)) { } Tp::ObjectPathList channels; Tp::ObjectPathList initialChannels; Tp::UIntList initialInviteeHandles; QStringList initialInviteeIDs; QString invitationMessage; ChannelOriginatorMap originalChannels; BaseChannelConferenceInterface::Adaptee *adaptee; }; /** * \class BaseChannelConferenceInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.Conference * */ /** * Class constructor. */ BaseChannelConferenceInterface::BaseChannelConferenceInterface(Tp::ObjectPathList initialChannels, Tp::UIntList initialInviteeHandles, QStringList initialInviteeIDs, QString invitationMessage, ChannelOriginatorMap originalChannels) : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE), mPriv(new Private(this, initialChannels, initialInviteeHandles, initialInviteeIDs, invitationMessage, originalChannels)) { } Tp::ObjectPathList BaseChannelConferenceInterface::channels() const { return mPriv->channels; } Tp::ObjectPathList BaseChannelConferenceInterface::initialChannels() const { return mPriv->initialChannels; } Tp::UIntList BaseChannelConferenceInterface::initialInviteeHandles() const { return mPriv->initialInviteeHandles; } QStringList BaseChannelConferenceInterface::initialInviteeIDs() const { return mPriv->initialInviteeIDs; } QString BaseChannelConferenceInterface::invitationMessage() const { return mPriv->invitationMessage; } void BaseChannelConferenceInterface::mergeChannel(const QDBusObjectPath &channel, uint channelHandle, const QVariantMap &properties) { mPriv->channels.append(channel); if (channelHandle != 0) { mPriv->originalChannels[channelHandle] = channel; } QMetaObject::invokeMethod(mPriv->adaptee, "channelMerged", Q_ARG(QDBusObjectPath, channel), Q_ARG(uint, channelHandle), Q_ARG(QVariantMap, properties)); } void BaseChannelConferenceInterface::removeChannel(const QDBusObjectPath &channel, const QVariantMap& details) { mPriv->channels.removeAll(channel); if (mPriv->originalChannels.values().contains(channel)) { mPriv->originalChannels.remove(mPriv->originalChannels.key(channel)); } QMetaObject::invokeMethod(mPriv->adaptee, "channelRemoved", Q_ARG(QDBusObjectPath, channel), Q_ARG(QVariantMap, details)); } ChannelOriginatorMap BaseChannelConferenceInterface::originalChannels() const { return mPriv->originalChannels; } /** * Class destructor. */ BaseChannelConferenceInterface::~BaseChannelConferenceInterface() { delete mPriv; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelConferenceInterface::immutableProperties() const { QVariantMap map; return map; } void BaseChannelConferenceInterface::createAdaptor() { (void) new Service::ChannelInterfaceConferenceAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } // Chan.I.SMS BaseChannelSMSInterface::Adaptee::Adaptee(BaseChannelSMSInterface *interface) : QObject(interface), mInterface(interface) { } BaseChannelSMSInterface::Adaptee::~Adaptee() { } struct TP_QT_NO_EXPORT BaseChannelSMSInterface::Private { Private(BaseChannelSMSInterface *parent, bool flash, bool smsChannel) : flash(flash), smsChannel(smsChannel), adaptee(new BaseChannelSMSInterface::Adaptee(parent)) { } bool flash; bool smsChannel; GetSMSLengthCallback getSMSLengthCB; BaseChannelSMSInterface::Adaptee *adaptee; }; void BaseChannelSMSInterface::Adaptee::getSMSLength(const Tp::MessagePartList & messages, const Tp::Service::ChannelInterfaceSMSAdaptor::GetSMSLengthContextPtr &context) { if (!mInterface->mPriv->getSMSLengthCB.isValid()) { context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); return; } DBusError error; mInterface->mPriv->getSMSLengthCB(messages, &error); if (error.isValid()) { context->setFinishedWithError(error.name(), error.message()); return; } // TODO: implement context->setFinished(0,0,0); } /** * \class BaseChannelSMSInterface * \ingroup servicecm * \headerfile TelepathyQt/base-channel.h * * \brief Base class for implementations of Channel.Interface.SMS * */ /** * Class constructor. */ BaseChannelSMSInterface::BaseChannelSMSInterface(bool flash, bool smsChannel) : AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_SMS), mPriv(new Private(this, flash, smsChannel)) { } void BaseChannelSMSInterface::setGetSMSLengthCallback(const GetSMSLengthCallback &cb) { mPriv->getSMSLengthCB = cb; } /** * Class destructor. */ BaseChannelSMSInterface::~BaseChannelSMSInterface() { delete mPriv; } bool BaseChannelSMSInterface::flash() const { return mPriv->flash; } bool BaseChannelSMSInterface::smsChannel() const { return mPriv->smsChannel; } /** * Return the immutable properties of this interface. * * Immutable properties cannot change after the interface has been registered * on a service on the bus with registerInterface(). * * \return The immutable properties of this interface. */ QVariantMap BaseChannelSMSInterface::immutableProperties() const { QVariantMap map; map.insert(TP_QT_IFACE_CHANNEL_INTERFACE_SMS + QLatin1String(".Flash"), QVariant::fromValue(mPriv->adaptee->flash())); return map; } void BaseChannelSMSInterface::createAdaptor() { (void) new Service::ChannelInterfaceSMSAdaptor(dbusObject()->dbusConnection(), mPriv->adaptee, dbusObject()); } } telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeRoomListInterface0000664000175000017500000000041512470405660022663 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeRoomListInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeRoomListInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AccountInterface0000664000175000017500000000036512470405660020360 0ustar jrjr#ifndef _TelepathyQt_AccountInterface_HEADER_GUARD_ #define _TelepathyQt_AccountInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionFactory0000664000175000017500000000040212470405660020562 0ustar jrjr#ifndef _TelepathyQt_ConnectionFactory_HEADER_GUARD_ #define _TelepathyQt_ConnectionFactory_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/SimpleCallObserver0000664000175000017500000000040612470405660020674 0ustar jrjr#ifndef _TelepathyQt_SimpleCallObserver_HEADER_GUARD_ #define _TelepathyQt_SimpleCallObserver_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceClientTypesInterface0000664000175000017500000000044612470405660025070 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceClientTypesInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceClientTypesInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Callbacks0000664000175000017500000000035112470405660017015 0ustar jrjr#ifndef _TelepathyQt_Callbacks_HEADER_GUARD_ #define _TelepathyQt_Callbacks_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/outgoing-stream-tube-channel.cpp0000664000175000017500000010366112470405660023416 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/outgoing-stream-tube-channel-internal.h" #include "TelepathyQt/_gen/outgoing-stream-tube-channel.moc.hpp" #include "TelepathyQt/_gen/outgoing-stream-tube-channel-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/types-internal.h" #include #include #include #include #include #include #include #include namespace Tp { PendingOpenTube::Private::Private(const QVariantMap ¶meters, PendingOpenTube *parent) : parent(parent), parameters(parameters) { } PendingOpenTube::PendingOpenTube( PendingVoid *offerOperation, const QVariantMap ¶meters, const OutgoingStreamTubeChannelPtr &object) : PendingOperation(object), mPriv(new Private(parameters, this)) { mPriv->tube = object; // FIXME: connect to channel invalidation here also debug() << "Calling StreamTube.Offer"; if (offerOperation->isFinished()) { onOfferFinished(offerOperation); } else { // Connect the pending void connect(offerOperation, SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(onOfferFinished(Tp::PendingOperation*))); } } PendingOpenTube::~PendingOpenTube() { delete mPriv; } void PendingOpenTube::onOfferFinished(PendingOperation *op) { if (op->isError()) { warning().nospace() << "StreamTube.Offer failed with " << op->errorName() << ": " << op->errorMessage(); setFinishedWithError(op->errorName(), op->errorMessage()); return; } debug() << "StreamTube.Offer returned successfully"; // It might have been already opened - check if (mPriv->tube->state() != TubeChannelStateOpen) { debug() << "Awaiting tube to be opened"; // Wait until the tube gets opened on the other side connect(mPriv->tube.data(), SIGNAL(stateChanged(Tp::TubeChannelState)), SLOT(onTubeStateChanged(Tp::TubeChannelState))); } onTubeStateChanged(mPriv->tube->state()); } void PendingOpenTube::onTubeStateChanged(TubeChannelState state) { if (state == TubeChannelStateOpen) { debug() << "Tube is now opened"; // Inject the parameters into the tube mPriv->tube->setParameters(mPriv->parameters); // The tube is ready: let's notify setFinished(); } else { if (state != TubeChannelStateRemotePending) { warning() << "Offering tube failed with" << TP_QT_ERROR_CONNECTION_REFUSED; // Something happened setFinishedWithError(TP_QT_ERROR_CONNECTION_REFUSED, QLatin1String("The connection to this tube was refused")); } else { debug() << "Awaiting remote to accept the tube"; } } } QueuedContactFactory::QueuedContactFactory(Tp::ContactManagerPtr contactManager, QObject* parent) : QObject(parent), m_isProcessing(false), m_manager(contactManager) { } QueuedContactFactory::~QueuedContactFactory() { } void QueuedContactFactory::processNextRequest() { if (m_isProcessing) { // Return, nothing to do return; } if (m_queue.isEmpty()) { // Queue completed, notify and return emit queueCompleted(); return; } m_isProcessing = true; Entry entry = m_queue.dequeue(); // TODO: pass id hints to ContactManager if we ever gain support to retrieve contact ids // from NewRemoteConnection. PendingContacts *pc = m_manager->contactsForHandles(entry.handles); pc->setProperty("__TpQt__QueuedContactFactoryUuid", entry.uuid.toString()); connect(pc, SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(onPendingContactsFinished(Tp::PendingOperation*))); } QUuid QueuedContactFactory::appendNewRequest(const Tp::UIntList &handles) { // Create a new entry Entry entry; entry.uuid = QUuid::createUuid(); entry.handles = handles; m_queue.enqueue(entry); // Enqueue a process request in the event loop QTimer::singleShot(0, this, SLOT(processNextRequest())); // Return the UUID return entry.uuid; } void QueuedContactFactory::onPendingContactsFinished(PendingOperation *op) { PendingContacts *pc = qobject_cast(op); QUuid uuid = QUuid(pc->property("__TpQt__QueuedContactFactoryUuid").toString()); emit contactsRetrieved(uuid, pc->contacts()); // No longer processing m_isProcessing = false; // Go for next one processNextRequest(); } OutgoingStreamTubeChannel::Private::Private(OutgoingStreamTubeChannel *parent) : parent(parent), queuedContactFactory(new QueuedContactFactory(parent->connection()->contactManager(), parent)) { } /** * \class OutgoingStreamTubeChannel * \ingroup clientchannel * \headerfile TelepathyQt/outgoing-stream-tube-channel.h * * \brief The OutgoingStreamTubeChannel class represents an outgoing Telepathy channel * of type StreamTube. * * Outgoing (locally initiated/requested) tubes are initially in the #TubeChannelStateNotOffered state. The * various offer methods in this class can be used to offer a local listening TCP or Unix socket for * the tube's target to connect to, at which point the tube becomes #TubeChannelStateRemotePending. * If the target accepts the connection request, the state goes #TubeChannelStateOpen and the * connection manager will start tunneling any incoming connections from the recipient side to the * local service. */ /** * Feature representing the core that needs to become ready to make the * OutgoingStreamTubeChannel object usable. * * This is currently the same as StreamTubeChannel::FeatureCore, but may change to include more. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature OutgoingStreamTubeChannel::FeatureCore = Feature(QLatin1String(StreamTubeChannel::staticMetaObject.className()), 0); // ST::FeatureCore /** * Create a new OutgoingStreamTubeChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A OutgoingStreamTubeChannelPtr object pointing to the newly created * OutgoingStreamTubeChannel object. */ OutgoingStreamTubeChannelPtr OutgoingStreamTubeChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return OutgoingStreamTubeChannelPtr(new OutgoingStreamTubeChannel(connection, objectPath, immutableProperties, OutgoingStreamTubeChannel::FeatureCore)); } /** * Construct a new OutgoingStreamTubeChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on OutgoingStreamTubeChannel::FeatureCore. */ OutgoingStreamTubeChannel::OutgoingStreamTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : StreamTubeChannel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { connect(mPriv->queuedContactFactory, SIGNAL(contactsRetrieved(QUuid,QList)), this, SLOT(onContactsRetrieved(QUuid,QList))); } /** * Class destructor. */ OutgoingStreamTubeChannel::~OutgoingStreamTubeChannel() { delete mPriv; } /** * Offer a TCP socket over this stream tube. * * This method offers a TCP socket over this tube. The socket's address is given as * a QHostAddress and a numerical port in native byte order. * * If your application uses QTcpServer as the local TCP server implementation, you can use the * offerTcpSocket(const QTcpServer *, const QVariantMap &) overload instead to more easily pass the * server's listen address. * * It is guaranteed that when the PendingOperation returned by this method will be completed, * the tube will be opened and ready to be used. * * Connection managers adhering to the \telepathy_spec should always support offering IPv4 TCP * sockets. IPv6 sockets are only supported if supportsIPv6SocketsOnLocalhost() is \c true. * * Note that the library will try to use #SocketAccessControlPort access control whenever possible, * as it allows to map connections to users based on their source addresses. If * supportsIPv4SocketsWithSpecifiedAddress() or supportsIPv6SocketsWithSpecifiedAddress() for IPv4 * and IPv6 sockets respectively is \c false, this feature is not available, and the * connectionsForSourceAddresses() map won't contain useful distinct keys. * * Arbitrary parameters can be associated with the offer to bootstrap legacy protocols; these will * in particular be available as IncomingStreamTubeChannel::parameters() for a tube receiver * implemented using TelepathyQt in the other end. * * This method requires OutgoingStreamTubeChannel::FeatureCore to be ready. * * \param address A valid IPv4 or IPv6 address pointing to an existing socket. * \param port The port the socket is listening for connections to. * \param parameters A dictionary of arbitrary parameters to send with the tube offer. * \return A PendingOperation which will emit PendingOperation::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). */ PendingOperation *OutgoingStreamTubeChannel::offerTcpSocket( const QHostAddress &address, quint16 port, const QVariantMap ¶meters) { if (!isReady(OutgoingStreamTubeChannel::FeatureCore)) { warning() << "OutgoingStreamTubeChannel::FeatureCore must be ready before " "calling offerTube"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), OutgoingStreamTubeChannelPtr(this)); } // The tube must be not offered if (state() != TubeChannelStateNotOffered) { warning() << "You can not expose more than a socket for each Stream Tube"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel busy"), OutgoingStreamTubeChannelPtr(this)); } SocketAccessControl accessControl = SocketAccessControlLocalhost; // Check if port is supported QHostAddress hostAddress = address; #if QT_VERSION >= 0x050000 if (hostAddress == QHostAddress::Any) { hostAddress = QHostAddress::AnyIPv4; } #endif // In this specific overload, we're handling an IPv4/IPv6 socket if (hostAddress.protocol() == QAbstractSocket::IPv4Protocol) { // IPv4 case SocketAccessControl accessControl; // Do some heuristics to find out the best access control.We always prefer port for tracking // connections and source addresses. if (supportsIPv4SocketsWithSpecifiedAddress()) { accessControl = SocketAccessControlPort; } else if (supportsIPv4SocketsOnLocalhost()) { accessControl = SocketAccessControlLocalhost; } else { // There are no combinations supported for this socket warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), OutgoingStreamTubeChannelPtr(this)); } setAddressType(SocketAddressTypeIPv4); setAccessControl(accessControl); setIpAddress(qMakePair(hostAddress, port)); SocketAddressIPv4 addr; addr.address = hostAddress.toString(); addr.port = port; PendingVoid *pv = new PendingVoid( interface()->Offer( SocketAddressTypeIPv4, QDBusVariant(QVariant::fromValue(addr)), accessControl, parameters), OutgoingStreamTubeChannelPtr(this)); PendingOpenTube *op = new PendingOpenTube(pv, parameters, OutgoingStreamTubeChannelPtr(this)); return op; } else if (hostAddress.protocol() == QAbstractSocket::IPv6Protocol) { // IPv6 case // Do some heuristics to find out the best access control.We always prefer port for tracking // connections and source addresses. if (supportsIPv6SocketsWithSpecifiedAddress()) { accessControl = SocketAccessControlPort; } else if (supportsIPv6SocketsOnLocalhost()) { accessControl = SocketAccessControlLocalhost; } else { // There are no combinations supported for this socket warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), OutgoingStreamTubeChannelPtr(this)); } setAddressType(SocketAddressTypeIPv6); setAccessControl(accessControl); setIpAddress(qMakePair(hostAddress, port)); SocketAddressIPv6 addr; addr.address = hostAddress.toString(); addr.port = port; PendingVoid *pv = new PendingVoid( interface()->Offer( SocketAddressTypeIPv6, QDBusVariant(QVariant::fromValue(addr)), accessControl, parameters), OutgoingStreamTubeChannelPtr(this)); PendingOpenTube *op = new PendingOpenTube(pv, parameters, OutgoingStreamTubeChannelPtr(this)); return op; } else { // We're handling an IPv4/IPv6 socket only warning() << "offerTube can be called only with a QHostAddress representing " "an IPv4 or IPv6 address"; return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid host given"), OutgoingStreamTubeChannelPtr(this)); } } /** * Offer a TCP socket over this stream tube. * * Otherwise identical to offerTcpSocket(const QHostAddress &, quint16, const QVariantMap &), but * allows passing the local service's address in an already listening QTcpServer. * * \param server A valid QTcpServer, which should be already listening for incoming connections. * \param parameters A dictionary of arbitrary parameters to send with the tube offer. * \return A PendingOperation which will emit PendingOperation::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). */ PendingOperation *OutgoingStreamTubeChannel::offerTcpSocket( const QTcpServer *server, const QVariantMap ¶meters) { // In this overload, we're handling a superset of QHostAddress. // Let's redirect the call to QHostAddress's overload return offerTcpSocket(server->serverAddress(), server->serverPort(), parameters); } /** * Offer an Unix socket over this stream tube. * * This method offers an Unix socket over this stream tube. The socket address is given as a * a QString, which should contain the path to the socket. Abstract Unix sockets are also supported, * and are given as addresses prefixed with a \c NUL byte. * * If your application uses QLocalServer as the local Unix server implementation, you can use the * offerUnixSocket(const QLocalServer *, const QVariantMap &, bool) overload instead to more easily * pass the server's listen address. * * Note that only connection managers for which supportsUnixSocketsOnLocalhost() or * supportsAbstractUnixSocketsOnLocalhost() is \c true support exporting Unix sockets. * * If supportsUnixSocketsWithCredentials() or supportsAbstractUnixSocketsWithCredentials(), as * appropriate, returns \c true, the \c requireCredentials parameter can be set to \c true to make * the connection manager pass an SCM_CREDS or SCM_CREDENTIALS message as supported by the platform * when making a new connection. This enables preventing other local users from connecting to the * service, but might not be possible to use with all protocols as the message is in-band in the * data stream. * * Arbitrary parameters can be associated with the offer to bootstrap legacy protocols; these will * in particular be available as IncomingStreamTubeChannel::parameters() for a tube receiver * implemented using TelepathyQt in the other end. * * This method requires OutgoingStreamTubeChannel::FeatureCore to be ready. * * \param address A valid path to an existing Unix socket or abstract Unix socket. * \param parameters A dictionary of arbitrary parameters to send with the tube offer. * \param requireCredentials Whether the server requires a SCM_CREDS or SCM_CREDENTIALS message * upon connection. * \return A PendingOperation which will emit PendingOperation::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). */ PendingOperation *OutgoingStreamTubeChannel::offerUnixSocket( const QString &socketAddress, const QVariantMap ¶meters, bool requireCredentials) { SocketAccessControl accessControl = requireCredentials ? SocketAccessControlCredentials : SocketAccessControlLocalhost; if (!isReady(OutgoingStreamTubeChannel::FeatureCore)) { warning() << "OutgoingStreamTubeChannel::FeatureCore must be ready before " "calling offerTube"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel not ready"), OutgoingStreamTubeChannelPtr(this)); } // The tube must be not offered if (state() != TubeChannelStateNotOffered) { warning() << "You can not expose more than a socket for each Stream Tube"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Channel busy"), OutgoingStreamTubeChannelPtr(this)); } // In this specific overload, we're handling an Unix/AbstractUnix socket if (socketAddress.startsWith(QLatin1Char('\0'))) { // Abstract Unix socket case // Check if the combination type/access control is supported if ((accessControl == SocketAccessControlLocalhost && !supportsAbstractUnixSocketsOnLocalhost()) || (accessControl == SocketAccessControlCredentials && !supportsAbstractUnixSocketsWithCredentials()) ) { warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), OutgoingStreamTubeChannelPtr(this)); } setAddressType(SocketAddressTypeAbstractUnix); setAccessControl(accessControl); setLocalAddress(socketAddress); PendingVoid *pv = new PendingVoid( interface()->Offer( SocketAddressTypeAbstractUnix, QDBusVariant(QVariant(socketAddress.toLatin1())), accessControl, parameters), OutgoingStreamTubeChannelPtr(this)); PendingOpenTube *op = new PendingOpenTube(pv, parameters, OutgoingStreamTubeChannelPtr(this)); return op; } else { // Unix socket case // Check if the combination type/access control is supported if ((accessControl == SocketAccessControlLocalhost && !supportsUnixSocketsOnLocalhost()) || (accessControl == SocketAccessControlCredentials && !supportsUnixSocketsWithCredentials()) || (accessControl != SocketAccessControlLocalhost && accessControl != SocketAccessControlCredentials) ) { warning() << "You requested an address type/access control combination " "not supported by this channel"; return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("The requested address type/access control " "combination is not supported"), OutgoingStreamTubeChannelPtr(this)); } setAddressType(SocketAddressTypeUnix); setAccessControl(accessControl); setLocalAddress(socketAddress); PendingVoid *pv = new PendingVoid( interface()->Offer( SocketAddressTypeUnix, QDBusVariant(QVariant(socketAddress.toLatin1())), accessControl, parameters), OutgoingStreamTubeChannelPtr(this)); PendingOpenTube *op = new PendingOpenTube(pv, parameters, OutgoingStreamTubeChannelPtr(this)); return op; } } /** * Offer an Unix socket over the tube. * * Otherwise identical to offerUnixSocket(const QString &, const QVariantMap &, bool), but allows * passing the local service's address as an already listening QLocalServer. * * This method requires OutgoingStreamTubeChannel::FeatureCore to be ready. * * \param server A valid QLocalServer, which should be already listening for incoming connections. * \param parameters A dictionary of arbitrary parameters to send with the tube offer. * \param requireCredentials Whether the server should require a SCM_CRED or SCM_CREDENTIALS message * upon connection. * \return A PendingOperation which will emit PendingOperation::finished * when the stream tube is ready to be used * (hence in the #TubeStateOpen state). * \sa StreamTubeChannel::supportsUnixSocketsOnLocalhost(), * StreamTubeChannel::supportsUnixSocketsWithCredentials(), * StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost(), * StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials() */ PendingOperation *OutgoingStreamTubeChannel::offerUnixSocket( const QLocalServer *server, const QVariantMap ¶meters, bool requireCredentials) { // In this overload, we're handling a superset of a local socket // Let's redirect the call to QString's overload return offerUnixSocket(server->fullServerName(), parameters, requireCredentials); } /** * Return a map from a source address to the corresponding connections ids. * * The connection ids retrieved here can be used to map a source address * which connected to your socket to a connection ID (for error reporting) and further, to a contact * (by using contactsForConnections()). * * This method is only useful if a TCP socket was offered on this tube and the connection manager * supports #SocketAccessControlPort, which can be discovered using * supportsIPv4SocketsWithSpecifiedAddress() and supportsIPv6SocketsWithSpecifiedAddress() for IPv4 * and IPv6 sockets respectively. * * Note that this function will only return valid data after the tube has been opened. * * This method requires StreamTubeChannel::FeatureConnectionMonitoring to be ready. * * \return The map from source addresses as (QHostAddress, port in native byte order) pairs to the * corresponding connection ids. * \sa connectionsForCredentials() */ QHash, uint> OutgoingStreamTubeChannel::connectionsForSourceAddresses() const { if (addressType() != SocketAddressTypeIPv4 && addressType() != SocketAddressTypeIPv6) { warning() << "OutgoingStreamTubeChannel::connectionsForSourceAddresses() makes sense " "just when offering a TCP socket"; return QHash, uint>(); } if (isValid() || !isDroppingConnections() || !requestedFeatures().contains(StreamTubeChannel::FeatureConnectionMonitoring)) { if (!isReady(StreamTubeChannel::FeatureConnectionMonitoring)) { warning() << "StreamTubeChannel::FeatureConnectionMonitoring must be ready before " " calling connectionsForSourceAddresses"; return QHash, uint>(); } if (state() != TubeChannelStateOpen) { warning() << "OutgoingStreamTubeChannel::connectionsForSourceAddresses() makes sense " "just when the tube is open"; return QHash, uint>(); } } return mPriv->connectionsForSourceAddresses; } /** * Return a map from a credential byte to the corresponding connections ids. * * The connection ids retrieved here can be used to map a source address * which connected to your socket to a connection ID (for error reporting) and further, to a contact * (by using contactsForConnections()). * * This method is only useful if this tube was offered using an Unix socket and passing credential * bytes was enabled (\c requireCredentials == true). * * Note that this function will only return valid data after the tube has been opened. * * This method requires StreamTubeChannel::FeatureConnectionMonitoring to be ready. * * \return The map from credential bytes to the corresponding connection ids. * \sa connectionsForSourceAddresses() */ QHash OutgoingStreamTubeChannel::connectionsForCredentials() const { if (addressType() != SocketAddressTypeUnix && addressType() != SocketAddressTypeAbstractUnix) { warning() << "OutgoingStreamTubeChannel::connectionsForCredentials() makes sense " "just when offering an Unix socket"; return QHash(); } if (accessControl() != SocketAccessControlCredentials) { warning() << "OutgoingStreamTubeChannel::connectionsForCredentials() makes sense " "just when offering an Unix socket requiring credentials"; return QHash(); } if (isValid() || !isDroppingConnections() || !requestedFeatures().contains(StreamTubeChannel::FeatureConnectionMonitoring)) { if (!isReady(StreamTubeChannel::FeatureConnectionMonitoring)) { warning() << "StreamTubeChannel::FeatureConnectionMonitoring must be ready before " "calling OutgoingStreamTubeChannel::connectionsForCredentials()"; return QHash(); } if (state() != TubeChannelStateOpen) { warning() << "OutgoingStreamTubeChannel::connectionsForCredentials() makes sense " "just when the tube is opened"; return QHash(); } } return mPriv->connectionsForCredentials; } /** * Return a map from connection ids to the associated contact. * * Note that this function will only return valid data after the tube has been opened. * * This method requires StreamTubeChannel::FeatureConnectionMonitoring to be ready. * \return The map from connection ids to pointer to Contact objects. * \sa connectionsForSourceAddresses(), connectionsForCredentials(), * StreamTubeChannel::addressType() */ QHash OutgoingStreamTubeChannel::contactsForConnections() const { if (isValid() || !isDroppingConnections() || !requestedFeatures().contains(StreamTubeChannel::FeatureConnectionMonitoring)) { if (!isReady(StreamTubeChannel::FeatureConnectionMonitoring)) { warning() << "StreamTubeChannel::FeatureConnectionMonitoring must be ready before " "calling contactsForConnections"; return QHash(); } if (state() != TubeChannelStateOpen) { warning() << "OutgoingStreamTubeChannel::contactsForConnections() makes sense " "just when the tube is open"; return QHash(); } } return mPriv->contactsForConnections; } void OutgoingStreamTubeChannel::onNewRemoteConnection( uint contactId, const QDBusVariant ¶meter, uint connectionId) { // Request the handles from our queued contact factory QUuid uuid = mPriv->queuedContactFactory->appendNewRequest(UIntList() << contactId); // Add a pending connection mPriv->pendingNewConnections.insert(uuid, qMakePair(connectionId, parameter)); } void OutgoingStreamTubeChannel::onContactsRetrieved( const QUuid &uuid, const QList &contacts) { if (!isValid()) { debug() << "Invalidated OutgoingStreamTubeChannel not emitting queued connection event"; return; } if (!mPriv->pendingNewConnections.contains(uuid)) { if (mPriv->pendingClosedConnections.contains(uuid)) { // closed connection Private::ClosedConnection conn = mPriv->pendingClosedConnections.take(uuid); // First, do removeConnection() so connectionClosed is emitted, and anybody connected to it // (like StreamTubeServer) has a chance to recover the source address / contact removeConnection(conn.id, conn.error, conn.message); // Remove stuff from our hashes mPriv->contactsForConnections.remove(conn.id); QHash, uint>::iterator srcAddrIter = mPriv->connectionsForSourceAddresses.begin(); while (srcAddrIter != mPriv->connectionsForSourceAddresses.end()) { if (srcAddrIter.value() == conn.id) { srcAddrIter = mPriv->connectionsForSourceAddresses.erase(srcAddrIter); } else { ++srcAddrIter; } } QHash::iterator credIter = mPriv->connectionsForCredentials.begin(); while (credIter != mPriv->connectionsForCredentials.end()) { if (credIter.value() == conn.id) { credIter = mPriv->connectionsForCredentials.erase(credIter); } else { ++credIter; } } } else { warning() << "No pending connections found in OSTC" << objectPath() << "for contacts" << contacts; } return; } // new connection QPair connectionProperties = mPriv->pendingNewConnections.take(uuid); // Add it to our connections hash foreach (const Tp::ContactPtr &contact, contacts) { mPriv->contactsForConnections.insert(connectionProperties.first, contact); } QPair address; address.first = QHostAddress::Null; // Now let's try to track the parameter if (addressType() == SocketAddressTypeIPv4) { // Try a qdbus_cast to our address struct: we're shielded from crashes // thanks to our specification SocketAddressIPv4 addr = qdbus_cast(connectionProperties.second.variant()); address.first = QHostAddress(addr.address); address.second = addr.port; } else if (addressType() == SocketAddressTypeIPv6) { SocketAddressIPv6 addr = qdbus_cast(connectionProperties.second.variant()); address.first = QHostAddress(addr.address); address.second = addr.port; } else if (addressType() == SocketAddressTypeUnix || addressType() == SocketAddressTypeAbstractUnix) { if (accessControl() == SocketAccessControlCredentials) { uchar credentialByte = qdbus_cast(connectionProperties.second.variant()); mPriv->connectionsForCredentials.insertMulti(credentialByte, connectionProperties.first); } } if (address.first != QHostAddress::Null) { // We can map it to a source address as well mPriv->connectionsForSourceAddresses.insertMulti(address, connectionProperties.first); } // Time for us to emit the signal addConnection(connectionProperties.first); } // This replaces the base class onConnectionClosed() slot, but unlike a virtual function, is ABI // compatible void OutgoingStreamTubeChannel::onConnectionClosed(uint connectionId, const QString &errorName, const QString &errorMessage) { // Insert a fake request to our queued contact factory to make the close events properly ordered // with new connection events QUuid uuid = mPriv->queuedContactFactory->appendNewRequest(UIntList()); // Add a pending connection close mPriv->pendingClosedConnections.insert(uuid, Private::ClosedConnection(connectionId, errorName, errorMessage)); } } telepathy-qt-0.9.6~git1/TelepathyQt/account-capability-filter.h0000664000175000017500000000236312470405660022427 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_account_capability_filter_h_HEADER_GUARD_ #define _TelepathyQt_account_capability_filter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { typedef GenericCapabilityFilter AccountCapabilityFilter; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/Constants0000664000175000017500000000035112470405660017112 0ustar jrjr#ifndef _TelepathyQt_Constants_HEADER_GUARD_ #define _TelepathyQt_Constants_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceLocationInterface0000664000175000017500000000044012470405660024367 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceLocationInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceLocationInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/simple-observer-internal.h0000664000175000017500000002115212470405660022316 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT SimpleObserver::Private { Private(SimpleObserver *parent, const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QString &contactIdentifier, bool requiresNormalization, const QList &extraChannelFeatures); bool filterChannel(const AccountPtr &channelAccount, const ChannelPtr &channel); void insertChannels(const AccountPtr &channelsAccount, const QList &channels); void removeChannel(const AccountPtr &channelAccount, const ChannelPtr &channel, const QString &errorName, const QString &errorMessage); void processChannelsQueue(); void processNewChannelsQueue(); void processChannelsInvalidationQueue(); class FakeAccountFactory; class Observer; class ChannelWrapper; struct NewChannelsInfo; struct ChannelInvalidationInfo; SimpleObserver *parent; AccountPtr account; ChannelClassSpecList channelFilter; QString contactIdentifier; QString normalizedContactIdentifier; QList extraChannelFeatures; ClientRegistrarPtr cr; SharedPtr observer; QSet channels; QQueue channelsQueue; QQueue channelsInvalidationQueue; QQueue newChannelsQueue; static QHash >, WeakPtr > observers; static uint numObservers; }; class TP_QT_NO_EXPORT SimpleObserver::Private::FakeAccountFactory : public AccountFactory { Q_OBJECT public: static SharedPtr create(const QDBusConnection &bus) { return SharedPtr(new FakeAccountFactory(bus)); } ~FakeAccountFactory() { } private: friend class Observer; FakeAccountFactory(const QDBusConnection &bus) : AccountFactory(bus, Features()) { } AccountPtr construct(const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const { if (mAccounts.contains(objectPath)) { return mAccounts.value(objectPath); } return AccountFactory::construct(busName, objectPath, connFactory, chanFactory, contactFactory); } QHash accounts() const { return mAccounts; } void registerAccount(const AccountPtr &account) { mAccounts.insert(account->objectPath(), account); } QHash mAccounts; }; class TP_QT_NO_EXPORT SimpleObserver::Private::Observer : public QObject, public AbstractClientObserver { Q_OBJECT Q_DISABLE_COPY(Observer) public: struct ContextInfo { ContextInfo() {} ContextInfo(const MethodInvocationContextPtr<> &context, const AccountPtr &account, const QList &channels) : context(context), account(account), channels(channels) { } MethodInvocationContextPtr<> context; AccountPtr account; QList channels; }; Observer(const WeakPtr &cr, const SharedPtr &fakeAccountFactory, const ChannelClassSpecList &channelFilter, const QString &observerName); ~Observer(); WeakPtr clientRegistrar() const { return mCr; } SharedPtr fakeAccountFactory() const { return mFakeAccountFactory; } QString observerName() const { return mObserverName; } QSet extraChannelFeatures() const { return mExtraChannelFeatures; } void registerExtraChannelFeatures(const QList &features) { mExtraChannelFeatures.unite(features.toSet()); } QSet accounts() const { return mAccounts; } void registerAccount(const AccountPtr &account) { mAccounts.insert(account); mFakeAccountFactory->registerAccount(account); } QHash channels() const { return mChannels; } void observeChannels( const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const ChannelDispatchOperationPtr &dispatchOperation, const QList &requestsSatisfied, const ObserverInfo &observerInfo); Q_SIGNALS: void newChannels(const Tp::AccountPtr &channelsAccount, const QList &channels); void channelInvalidated(const Tp::AccountPtr &channelAccount, const Tp::ChannelPtr &channel, const QString &errorName, const QString &errorMessage); private Q_SLOTS: void onChannelInvalidated(const Tp::AccountPtr &channelAccount, const Tp::ChannelPtr &channel, const QString &errorName, const QString &errorMessage); void onChannelsReady(Tp::PendingOperation *op); private: Features featuresFor(const ChannelClassSpec &channelClass) const; WeakPtr mCr; SharedPtr mFakeAccountFactory; QString mObserverName; QSet mExtraChannelFeatures; QSet mAccounts; QHash mChannels; QHash mIncompleteChannels; QHash mObserveChannelsInfo; }; class TP_QT_NO_EXPORT SimpleObserver::Private::ChannelWrapper : public QObject { Q_OBJECT Q_DISABLE_COPY(ChannelWrapper) public: ChannelWrapper(const AccountPtr &channelAccount, const ChannelPtr &channel, const Features &extraChannelFeatures, QObject *parent); ~ChannelWrapper() { } AccountPtr channelAccount() const { return mChannelAccount; } ChannelPtr channel() const { return mChannel; } Features extraChannelFeatures() const { return mExtraChannelFeatures; } PendingOperation *becomeReady(); Q_SIGNALS: void channelInvalidated(const Tp::AccountPtr &channelAccount, const Tp::ChannelPtr &channel, const QString &errorName, const QString &errorMessage); private Q_SLOTS: void onChannelInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage); private: AccountPtr mChannelAccount; ChannelPtr mChannel; Features mExtraChannelFeatures; }; struct TP_QT_NO_EXPORT SimpleObserver::Private::NewChannelsInfo { NewChannelsInfo(); NewChannelsInfo(const AccountPtr &channelsAccount, const QList &channels) : channelsAccount(channelsAccount), channels(channels) { } AccountPtr channelsAccount; QList channels; }; struct TP_QT_NO_EXPORT SimpleObserver::Private::ChannelInvalidationInfo { ChannelInvalidationInfo(); ChannelInvalidationInfo(const AccountPtr &channelAccount, const ChannelPtr &channel, const QString &errorName, const QString &errorMessage) : channelAccount(channelAccount), channel(channel), errorName(errorName), errorMessage(errorMessage) { } AccountPtr channelAccount; ChannelPtr channel; QString errorName; QString errorMessage; }; } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterface0000664000175000017500000000037612470405660021065 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/account-manager.h0000664000175000017500000001315212470405660020433 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_account_manager_h_HEADER_GUARD_ #define _TelepathyQt_account_manager_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { class PendingAccount; class TP_QT_EXPORT AccountManager : public StatelessDBusProxy, public OptionalInterfaceFactory { Q_OBJECT Q_DISABLE_COPY(AccountManager) public: static const Feature FeatureCore; static AccountManagerPtr create(const QDBusConnection &bus); static AccountManagerPtr create( const AccountFactoryConstPtr &accountFactory = AccountFactory::create(QDBusConnection::sessionBus(), Account::FeatureCore), const ConnectionFactoryConstPtr &connectionFactory = ConnectionFactory::create(QDBusConnection::sessionBus()), const ChannelFactoryConstPtr &channelFactory = ChannelFactory::create(QDBusConnection::sessionBus()), const ContactFactoryConstPtr &contactFactory = ContactFactory::create()); static AccountManagerPtr create(const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory = ContactFactory::create()); virtual ~AccountManager(); AccountFactoryConstPtr accountFactory() const; ConnectionFactoryConstPtr connectionFactory() const; ChannelFactoryConstPtr channelFactory() const; ContactFactoryConstPtr contactFactory() const; QList allAccounts() const; AccountSetPtr validAccounts() const; AccountSetPtr invalidAccounts() const; AccountSetPtr enabledAccounts() const; AccountSetPtr disabledAccounts() const; AccountSetPtr onlineAccounts() const; AccountSetPtr offlineAccounts() const; AccountSetPtr textChatAccounts() const; AccountSetPtr textChatroomAccounts() const; AccountSetPtr audioCallAccounts() const; AccountSetPtr videoCallAccounts() const; TP_QT_DEPRECATED AccountSetPtr streamedMediaCallAccounts() const; TP_QT_DEPRECATED AccountSetPtr streamedMediaAudioCallAccounts() const; TP_QT_DEPRECATED AccountSetPtr streamedMediaVideoCallAccounts() const; TP_QT_DEPRECATED AccountSetPtr streamedMediaVideoCallWithAudioAccounts() const; AccountSetPtr fileTransferAccounts() const; AccountSetPtr accountsByProtocol(const QString &protocolName) const; AccountSetPtr filterAccounts(const AccountFilterConstPtr &filter) const; AccountSetPtr filterAccounts(const QVariantMap &filter) const; AccountPtr accountForObjectPath(const QString &path) const; TP_QT_DEPRECATED AccountPtr accountForPath(const QString &path) const; QList accountsForObjectPaths(const QStringList &paths) const; TP_QT_DEPRECATED QList accountsForPaths(const QStringList &paths) const; QStringList supportedAccountProperties() const; PendingAccount *createAccount(const QString &connectionManager, const QString &protocol, const QString &displayName, const QVariantMap ¶meters, const QVariantMap &properties = QVariantMap()); Q_SIGNALS: void newAccount(const Tp::AccountPtr &account); protected: AccountManager(const QDBusConnection &bus, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory, const Feature &coreFeature); Client::AccountManagerInterface *baseInterface() const; private Q_SLOTS: TP_QT_NO_EXPORT void introspectMain(); TP_QT_NO_EXPORT void gotMainProperties(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onAccountReady(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onAccountValidityChanged(const QDBusObjectPath &objectPath, bool valid); TP_QT_NO_EXPORT void onAccountRemoved(const QDBusObjectPath &objectPath); private: friend class PendingAccount; struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/PendingHandles0000664000175000017500000000037112470405660020023 0ustar jrjr#ifndef _TelepathyQt_PendingHandles_HEADER_GUARD_ #define _TelepathyQt_PendingHandles_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel.h0000664000175000017500000002327112470405660017002 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_channel_h_HEADER_GUARD_ #define _TelepathyQt_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include #include #include #include namespace Tp { class Connection; class PendingOperation; class PendingReady; class TP_QT_EXPORT Channel : public StatefulDBusProxy, public OptionalInterfaceFactory { Q_OBJECT Q_DISABLE_COPY(Channel) public: static const Feature FeatureCore; static const Feature FeatureConferenceInitialInviteeContacts; static ChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~Channel(); ConnectionPtr connection() const; QVariantMap immutableProperties() const; QString channelType() const; HandleType targetHandleType() const; uint targetHandle() const; QString targetId() const; ContactPtr targetContact() const; bool isRequested() const; ContactPtr initiatorContact() const; PendingOperation *requestClose(); PendingOperation *requestLeave(const QString &message = QString(), ChannelGroupChangeReason reason = ChannelGroupChangeReasonNone); ChannelGroupFlags groupFlags() const; bool groupCanAddContacts() const; bool groupCanAddContactsWithMessage() const; bool groupCanAcceptContactsWithMessage() const; PendingOperation *groupAddContacts(const QList &contacts, const QString &message = QString()); bool groupCanRescindContacts() const; bool groupCanRescindContactsWithMessage() const; bool groupCanRemoveContacts() const; bool groupCanRemoveContactsWithMessage() const; bool groupCanRejectContactsWithMessage() const; bool groupCanDepartWithMessage() const; PendingOperation *groupRemoveContacts(const QList &contacts, const QString &message = QString(), ChannelGroupChangeReason reason = ChannelGroupChangeReasonNone); Contacts groupContacts(bool includeSelfContact = true) const; Contacts groupLocalPendingContacts(bool includeSelfContact = true) const; Contacts groupRemotePendingContacts(bool includeSelfContact = true) const; class GroupMemberChangeDetails { public: GroupMemberChangeDetails(); GroupMemberChangeDetails(const GroupMemberChangeDetails &other); ~GroupMemberChangeDetails(); GroupMemberChangeDetails &operator=(const GroupMemberChangeDetails &other); bool isValid() const { return mPriv.constData() != 0; } bool hasActor() const; ContactPtr actor() const; bool hasReason() const { return allDetails().contains(QLatin1String("change-reason")); } ChannelGroupChangeReason reason() const { return (ChannelGroupChangeReason) qdbus_cast(allDetails().value(QLatin1String("change-reason"))); } bool hasMessage() const { return allDetails().contains(QLatin1String("message")); } QString message () const { return qdbus_cast(allDetails().value(QLatin1String("message"))); } bool hasError() const { return allDetails().contains(QLatin1String("error")); } QString error() const { return qdbus_cast(allDetails().value(QLatin1String("error"))); } bool hasDebugMessage() const { return allDetails().contains(QLatin1String("debug-message")); } QString debugMessage() const { return qdbus_cast(allDetails().value(QLatin1String("debug-message"))); } QVariantMap allDetails() const; private: friend class Channel; friend class Contact; friend class ContactManager; TP_QT_NO_EXPORT GroupMemberChangeDetails(const ContactPtr &actor, const QVariantMap &details); struct Private; friend struct Private; QSharedDataPointer mPriv; }; GroupMemberChangeDetails groupLocalPendingContactChangeInfo(const ContactPtr &contact) const; GroupMemberChangeDetails groupSelfContactRemoveInfo() const; bool groupAreHandleOwnersAvailable() const; HandleOwnerMap groupHandleOwners() const; bool groupIsSelfContactTracked() const; ContactPtr groupSelfContact() const; bool isConference() const; Contacts conferenceInitialInviteeContacts() const; QList conferenceChannels() const; QList conferenceInitialChannels() const; QHash conferenceOriginalChannels() const; bool supportsConferenceMerging() const; PendingOperation *conferenceMergeChannel(const ChannelPtr &channel); bool supportsConferenceSplitting() const; PendingOperation *conferenceSplitChannel(); Q_SIGNALS: void groupFlagsChanged(Tp::ChannelGroupFlags flags, Tp::ChannelGroupFlags added, Tp::ChannelGroupFlags removed); void groupCanAddContactsChanged(bool canAddContacts); void groupCanRemoveContactsChanged(bool canRemoveContacts); void groupCanRescindContactsChanged(bool canRescindContacts); void groupMembersChanged( const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupLocalPendingMembersAdded, const Tp::Contacts &groupRemotePendingMembersAdded, const Tp::Contacts &groupMembersRemoved, const Tp::Channel::GroupMemberChangeDetails &details); void groupHandleOwnersChanged(const Tp::HandleOwnerMap &owners, const Tp::UIntList &added, const Tp::UIntList &removed); void groupSelfContactChanged(); void conferenceChannelMerged(const Tp::ChannelPtr &channel); void conferenceChannelRemoved(const Tp::ChannelPtr &channel, const Tp::Channel::GroupMemberChangeDetails &details); protected: Channel(const ConnectionPtr &connection,const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature); Client::ChannelInterface *baseInterface() const; bool groupSelfHandleIsLocalPending() const; protected Q_SLOTS: PendingOperation *groupAddSelfHandle(); private Q_SLOTS: TP_QT_NO_EXPORT void gotMainProperties(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotChannelType(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotHandle(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotInterfaces(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onClosed(); TP_QT_NO_EXPORT void onConnectionReady(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onConnectionInvalidated(); TP_QT_NO_EXPORT void gotGroupProperties(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotGroupFlags(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotAllMembers(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotLocalPendingMembersWithInfo(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotSelfHandle(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotContacts(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onGroupFlagsChanged(uint added, uint removed); TP_QT_NO_EXPORT void onMembersChanged(const QString &message, const Tp::UIntList &added, const Tp::UIntList &removed, const Tp::UIntList &localPending, const Tp::UIntList &remotePending, uint actor, uint reason); TP_QT_NO_EXPORT void onMembersChangedDetailed( const Tp::UIntList &added, const Tp::UIntList &removed, const Tp::UIntList &localPending, const Tp::UIntList &remotePending, const QVariantMap &details); TP_QT_NO_EXPORT void onHandleOwnersChanged(const Tp::HandleOwnerMap &added, const Tp::UIntList &removed); TP_QT_NO_EXPORT void onSelfHandleChanged(uint selfHandle); TP_QT_NO_EXPORT void gotConferenceProperties(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void gotConferenceInitialInviteeContacts(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onConferenceChannelMerged(const QDBusObjectPath &channel, uint channelSpecificHandle, const QVariantMap &properties); TP_QT_NO_EXPORT void onConferenceChannelMerged(const QDBusObjectPath &channel); TP_QT_NO_EXPORT void onConferenceChannelRemoved(const QDBusObjectPath &channel, const QVariantMap &details); TP_QT_NO_EXPORT void onConferenceChannelRemoved(const QDBusObjectPath &channel); TP_QT_NO_EXPORT void gotConferenceChannelRemovedActorContact(Tp::PendingOperation *op); private: class PendingLeave; friend class PendingLeave; struct Private; friend struct Private; Private *mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::Channel::GroupMemberChangeDetails); #endif telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceSecurableInterface0000664000175000017500000000043112470405660023775 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceSecurableInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceSecurableInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel-internal.h0000664000175000017500000000327312470405660020614 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_channel_internal_h_HEADER_GUARD_ #define _TelepathyQt_channel_internal_h_HEADER_GUARD_ #include #include namespace Tp { class TP_QT_NO_EXPORT Channel::PendingLeave : public PendingOperation { Q_OBJECT public: PendingLeave(const ChannelPtr &channel, const QString &message, ChannelGroupChangeReason reason); private Q_SLOTS: TP_QT_NO_EXPORT void onChanInvalidated(Tp::DBusProxy *proxy); TP_QT_NO_EXPORT void onRemoveFinished(Tp::PendingOperation *); TP_QT_NO_EXPORT void onMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &); TP_QT_NO_EXPORT void onCloseFinished(Tp::PendingOperation *); }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceContactListInterface0000664000175000017500000000044612470405660025054 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceContactListInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceContactListInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/contact.cpp0000664000175000017500000013230412470405660017356 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/contact.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/future-internal.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT Contact::Private { Private(Contact *parent, ContactManager *manager, const ReferencedHandles &handle) : parent(parent), manager(ContactManagerPtr(manager)), handle(handle), caps(manager->supportedFeatures().contains(Contact::FeatureCapabilities) ? ContactCapabilities(true) : ContactCapabilities( manager->connection()->capabilities().allClassSpecs(), false)), isContactInfoKnown(false), isAvatarTokenKnown(false), subscriptionState(SubscriptionStateUnknown), publishState(SubscriptionStateUnknown), blocked(false) { } void updateAvatarData(); Contact *parent; WeakPtr manager; ReferencedHandles handle; QString id; Features requestedFeatures; Features actualFeatures; QString alias; QMap vcardAddresses; QStringList uris; Presence presence; ContactCapabilities caps; LocationInfo location; bool isContactInfoKnown; InfoFields info; bool isAvatarTokenKnown; QString avatarToken; AvatarData avatarData; SubscriptionState subscriptionState; SubscriptionState publishState; QString publishStateMessage; bool blocked; QSet groups; QStringList clientTypes; }; void Contact::Private::updateAvatarData() { /* If token is NULL, it means that CM doesn't know the token. In that case we * have to request the avatar data to get the token. This happens with XMPP * for offline contacts. We don't want to bypass the avatar cache, so we won't * update avatar. */ if (avatarToken.isNull()) { return; } /* If token is empty (""), it means the contact has no avatar. */ if (avatarToken.isEmpty()) { debug() << "Contact" << parent->id() << "has no avatar"; avatarData = AvatarData(); emit parent->avatarDataChanged(avatarData); return; } parent->manager()->requestContactAvatars(QList() << ContactPtr(parent)); } struct TP_QT_NO_EXPORT Contact::InfoFields::Private : public QSharedData { Private(const ContactInfoFieldList &allFields) : allFields(allFields) {} ContactInfoFieldList allFields; }; /** * \class Contact::InfoFields * \ingroup clientconn * \headerfile TelepathyQt/contact.h * * \brief The Contact::InfoFields class represents the information of a * Telepathy contact. */ /** * Construct a info fields instance with the given fields. The instance will indicate that * it is valid. */ Contact::InfoFields::InfoFields(const ContactInfoFieldList &allFields) : mPriv(new Private(allFields)) { } /** * Constructs a new invalid InfoFields instance. */ Contact::InfoFields::InfoFields() { } /** * Copy constructor. */ Contact::InfoFields::InfoFields(const Contact::InfoFields &other) : mPriv(other.mPriv) { } /** * Class destructor. */ Contact::InfoFields::~InfoFields() { } /** * Assignment operator. */ Contact::InfoFields &Contact::InfoFields::operator=(const Contact::InfoFields &other) { this->mPriv = other.mPriv; return *this; } /** * Return a list containing all fields whose name are \a name. * * \param name The name used to match the fields. * \return A list of ContactInfoField objects. */ ContactInfoFieldList Contact::InfoFields::fields(const QString &name) const { if (!isValid()) { return ContactInfoFieldList(); } ContactInfoFieldList ret; foreach (const ContactInfoField &field, mPriv->allFields) { if (field.fieldName == name) { ret.append(field); } } return ret; } /** * Return a list containing all fields describing the contact information. * * \return The contact information as a list of ContactInfoField objects. */ ContactInfoFieldList Contact::InfoFields::allFields() const { return isValid() ? mPriv->allFields : ContactInfoFieldList(); } /** * \class Contact * \ingroup clientconn * \headerfile TelepathyQt/contact.h * * \brief The Contact class represents a Telepathy contact. * * The accessor functions on this object (id(), alias(), and so on) don't make any D-Bus calls; * instead, they return/use values cached from a previous introspection run. * The introspection process populates their values in the most efficient way possible based on what * the service implements. * * To avoid unnecessary D-Bus traffic, some accessors only return valid * information after specific features have been enabled. * For instance, to retrieve the contact avatar token, it is necessary to * enable the feature Contact::FeatureAvatarToken. * See the individual methods descriptions for more details. * * Contact features can be enabled by constructing a ContactFactory and enabling * the desired features, and passing it to AccountManager, Account or ClientRegistrar * when creating them as appropriate. However, if a particular * feature is only ever used in a specific circumstance, such as an user opening * some settings dialog separate from the general view of the application, * features can be later enabled as needed by calling ContactManager::upgradeContacts() with the * additional features, and waiting for the resulting PendingOperation to finish. * * As an addition to accessors, signals are emitted to indicate that properties have * changed, for example aliasChanged(), avatarTokenChanged(), etc. * * See \ref async_model, \ref shared_ptr */ /** * Feature used in order to access contact alias info. * * \sa alias(), aliasChanged() */ const Feature Contact::FeatureAlias = Feature(QLatin1String(Contact::staticMetaObject.className()), 0, false); /** * Feature used in order to access contact avatar data info. * * Enabling this feature will also enable FeatureAvatarToken. * * \sa avatarData(), avatarDataChanged() */ const Feature Contact::FeatureAvatarData = Feature(QLatin1String(Contact::staticMetaObject.className()), 1, false); /** * Feature used in order to access contact avatar token info. * * \sa isAvatarTokenKnown(), avatarToken(), avatarTokenChanged() */ const Feature Contact::FeatureAvatarToken = Feature(QLatin1String(Contact::staticMetaObject.className()), 2, false); /** * Feature used in order to access contact capabilities info. * * \sa capabilities(), capabilitiesChanged() */ const Feature Contact::FeatureCapabilities = Feature(QLatin1String(Contact::staticMetaObject.className()), 3, false); /** * Feature used in order to access contact info fields. * * \sa infoFields(), infoFieldsChanged() */ const Feature Contact::FeatureInfo = Feature(QLatin1String(Contact::staticMetaObject.className()), 4, false); /** * Feature used in order to access contact location info. * * \sa location(), locationUpdated() */ const Feature Contact::FeatureLocation = Feature(QLatin1String(Contact::staticMetaObject.className()), 5, false); /** * Feature used in order to access contact presence info. * * \sa presence(), presenceChanged() */ const Feature Contact::FeatureSimplePresence = Feature(QLatin1String(Contact::staticMetaObject.className()), 6, false); /** * Feature used in order to access contact roster groups. * * \sa groups(), addedToGroup(), removedFromGroup() */ const Feature Contact::FeatureRosterGroups = Feature(QLatin1String(Contact::staticMetaObject.className()), 7, false); /** * Feature used in order to access contact addressable addresses info. * * \sa vcardAddresses(), uris() */ const Feature Contact::FeatureAddresses = Feature(QLatin1String(Contact::staticMetaObject.className()), 8, false); /** * Feature used in order to access contact client types info. * * \sa clientTypes(), requestClientTypes(), clientTypesChanged() */ const Feature Contact::FeatureClientTypes = Feature(QLatin1String(Contact::staticMetaObject.className()), 9, false); /** * Construct a new Contact object. * * \param manager ContactManager owning this contact. * \param handle The contact handle. * \param requestedFeatures The contact requested features. * \param attributes The contact attributes. */ Contact::Contact(ContactManager *manager, const ReferencedHandles &handle, const Features &requestedFeatures, const QVariantMap &attributes) : Object(), mPriv(new Private(this, manager, handle)) { mPriv->requestedFeatures.unite(requestedFeatures); mPriv->id = qdbus_cast(attributes[ TP_QT_IFACE_CONNECTION + QLatin1String("/contact-id")]); } /** * Class destructor. */ Contact::~Contact() { debug() << "Contact" << id() << "destroyed"; delete mPriv; } /** * Return the contact nanager owning this contact. * * \return A pointer to the ContactManager object. */ ContactManagerPtr Contact::manager() const { return ContactManagerPtr(mPriv->manager); } /** * Return the handle of this contact. * * \return The handle as a ReferencedHandles object. */ ReferencedHandles Contact::handle() const { return mPriv->handle; } /** * Return the identifier of this contact. * * \return The identifier. */ QString Contact::id() const { return mPriv->id; } /** * Return the features requested on this contact. * * \return The requested features as a set of Feature objects. */ Features Contact::requestedFeatures() const { return mPriv->requestedFeatures; } /** * Return the features that are actually enabled on this contact. * * \return The actual features as a set of Feature objects. */ Features Contact::actualFeatures() const { return mPriv->actualFeatures; } /** * Return the alias of this contact. * * Change notification is via the aliasChanged() signal. * * This method requires Contact::FeatureAlias to be ready. * * \return The alias. */ QString Contact::alias() const { if (!mPriv->requestedFeatures.contains(FeatureAlias)) { warning() << "Contact::alias() used on" << this << "for which FeatureAlias hasn't been requested - returning id"; return id(); } return mPriv->alias; } /** * Return the various vcard addresses that identify this contact. * * This method requires Contact::FeatureAddresses to be ready. * * \return The vcard addresses identifying this contact. * \sa ContactManager::contactsForVCardAddresses(), uris() */ QMap Contact::vcardAddresses() const { return mPriv->vcardAddresses; } /** * Return the various URI addresses that identify this contact. * * This method requires Contact::FeatureAddresses to be ready. * * \return The URI addresses identifying this contact. * \sa ContactManager::contactsForUris(), vcardAddresses() */ QStringList Contact::uris() const { return mPriv->uris; } /** * Return whether the avatar token of this contact is known. * * This method requires Contact::FeatureAvatarToken to be ready. * * \return \c true if the avatar token is known, \c false otherwise. * \sa avatarToken() */ bool Contact::isAvatarTokenKnown() const { if (!mPriv->requestedFeatures.contains(FeatureAvatarToken)) { warning() << "Contact::isAvatarTokenKnown() used on" << this << "for which FeatureAvatarToken hasn't been requested - returning false"; return false; } return mPriv->isAvatarTokenKnown; } /** * Return the avatar token for this contact. * * Change notification is via the avatarTokenChanged() signal. * * This method requires Contact::FeatureAvatarToken to be ready. * * \return The avatar token. * \sa isAvatarTokenKnown(), avatarTokenChanged(), avatarData() */ QString Contact::avatarToken() const { if (!mPriv->requestedFeatures.contains(FeatureAvatarToken)) { warning() << "Contact::avatarToken() used on" << this << "for which FeatureAvatarToken hasn't been requested - returning \"\""; return QString(); } else if (!isAvatarTokenKnown()) { warning() << "Contact::avatarToken() used on" << this << "for which the avatar token is not (yet) known - returning \"\""; return QString(); } return mPriv->avatarToken; } /** * Return the actual avatar for this contact. * * Change notification is via the avatarDataChanged() signal. * * This method requires Contact::FeatureAvatarData to be ready. * * \return The avatar as an AvatarData object. * \sa avatarDataChanged(), avatarToken() */ AvatarData Contact::avatarData() const { if (!mPriv->requestedFeatures.contains(FeatureAvatarData)) { warning() << "Contact::avatarData() used on" << this << "for which FeatureAvatarData hasn't been requested - returning \"\""; return AvatarData(); } return mPriv->avatarData; } /** * Start a request to retrieve the avatar for this contact. * * Force the request of the avatar data. This method returns directly, emitting * avatarTokenChanged() and avatarDataChanged() signals once the token and data are * fetched from the server. * * This is only useful if the avatar token is unknown; see isAvatarTokenKnown(). * It happens in the case of offline XMPP contacts, because the server does not * send the token for them and an explicit request of the avatar data is needed. * * This method requires Contact::FeatureAvatarData to be ready. * * \sa avatarData(), avatarDataChanged(), avatarToken(), avatarTokenChanged() */ void Contact::requestAvatarData() { if (!mPriv->requestedFeatures.contains(FeatureAvatarData)) { warning() << "Contact::requestAvatarData() used on" << this << "for which FeatureAvatarData hasn't been requested - returning \"\""; return; } return manager()->requestContactAvatars(QList() << ContactPtr(this)); } /** * Return the actual presence of this contact. * * Change notification is via the presenceChanged() signal. * * This method requires Contact::FeatureSimplePresence to be ready. * * \return The presence as a Presence object. */ Presence Contact::presence() const { if (!mPriv->requestedFeatures.contains(FeatureSimplePresence)) { warning() << "Contact::presence() used on" << this << "for which FeatureSimplePresence hasn't been requested - returning Unknown"; return Presence(); } return mPriv->presence; } /** * Return the capabilities for this contact. * * User interfaces can use this information to show or hide UI components. * * If ContactManager::supportedFeatures() contains Contact::FeatureCapabilities, * the returned object will be a ContactCapabilities object, where * CapabilitiesBase::isSpecificToContact() will be \c true; if that feature * isn't present, this returned object is the subset of * Contact::manager()::connection()::capabilities() * and CapabilitiesBase::isSpecificToContact() will be \c false. * * Change notification is via the capabilitiesChanged() signal. * * This method requires Contact::FeatureCapabilities to be ready. * * @return An object representing the contact capabilities. */ ContactCapabilities Contact::capabilities() const { if (!mPriv->requestedFeatures.contains(FeatureCapabilities)) { warning() << "Contact::capabilities() used on" << this << "for which FeatureCapabilities hasn't been requested - returning 0"; return ContactCapabilities(false); } return mPriv->caps; } /** * Return the location for this contact. * * Change notification is via the locationUpdated() signal. * * This method requires Contact::FeatureLocation to be ready. * * \return The contact location as a LocationInfo object. */ LocationInfo Contact::location() const { if (!mPriv->requestedFeatures.contains(FeatureLocation)) { warning() << "Contact::location() used on" << this << "for which FeatureLocation hasn't been requested - returning 0"; return LocationInfo(); } return mPriv->location; } /** * Return whether the info card for this contact has been received. * * With some protocols (notably XMPP) information is not pushed from the server * and must be requested explicitely using refreshInfo() or requestInfo(). This * method can be used to know if the information is received from the server * or if an explicit request is needed. * * This method requires Contacat::FeatureInfo to be ready. * * \return \c true if the information is known; \c false otherwise. */ bool Contact::isContactInfoKnown() const { if (!mPriv->requestedFeatures.contains(FeatureInfo)) { warning() << "Contact::isContactInfoKnown() used on" << this << "for which FeatureInfo hasn't been requested - returning false"; return false; } return mPriv->isContactInfoKnown; } /** * Return the information for this contact. * * Note that this method only return cached information. In order to refresh the * information use refreshInfo(). * * Change notification is via the infoFieldsChanged() signal. * * This method requires Contact::FeatureInfo to be ready. * * \return The contact info as a Contact::InfoFields object. */ Contact::InfoFields Contact::infoFields() const { if (!mPriv->requestedFeatures.contains(FeatureInfo)) { warning() << "Contact::infoFields() used on" << this << "for which FeatureInfo hasn't been requested - returning empty " "InfoFields"; return InfoFields(); } return mPriv->info; } /** * Refresh information for the given contact. * * Once the information is retrieved infoFieldsChanged() will be emitted. * * This method requires Contact::FeatureInfo to be ready. * * \return A PendingOperation, which will emit PendingOperation::finished * when the call has finished. * \sa infoFieldsChanged() */ PendingOperation *Contact::refreshInfo() { ConnectionPtr conn = manager()->connection(); if (!mPriv->requestedFeatures.contains(FeatureInfo)) { warning() << "Contact::refreshInfo() used on" << this << "for which FeatureInfo hasn't been requested - failing"; return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("FeatureInfo needs to be ready in order to " "use this method"), ContactPtr(this)); } return manager()->refreshContactInfo(QList() << ContactPtr(this)); } /** * Start a request to retrieve the information for this contact. * * This method is useful for UIs that don't care about notification of changes * in the contact information but want to show the contact information * (e.g. right-click on a contact and show the contact info). * * \return A PendingContactInfo, which will emit PendingContactInfo::finished * when the information has been retrieved or an error occurred. */ PendingContactInfo *Contact::requestInfo() { return new PendingContactInfo(ContactPtr(this)); } /** * Return whether the presence subscription state of this contact is known. * * \return \c true if the presence subscription state is known, \c false otherwise. * \sa subscriptionState(), isSubscriptionRejected() */ bool Contact::isSubscriptionStateKnown() const { return mPriv->subscriptionState != SubscriptionStateUnknown; } /** * Return whether a request to see this contact's presence was denied. * * \return \c if the a request to see the presence subscription was denied, \c false otherwise. * \sa isSubscriptionStateKnown(), subscriptionState() */ bool Contact::isSubscriptionRejected() const { return mPriv->subscriptionState == SubscriptionStateRemovedRemotely; } /** * Return the presence subscription state of this contact (i.e. whether the local user can retrieve * information about this contact's presence). * * \return The presence subscription state as Contact::PresenceState. * \sa isSubscriptionStateKnown(), isSubscriptionRejected() */ Contact::PresenceState Contact::subscriptionState() const { return subscriptionStateToPresenceState(mPriv->subscriptionState); } /** * Return whether the presence publish state of this contact is known. * * \return \c true if the presence publish state is known, \c false otherwise. * \sa publishState(), isPublishCancelled() */ bool Contact::isPublishStateKnown() const { return mPriv->publishState != SubscriptionStateUnknown; } /** * Return whether a request to publish presence information to this contact was cancelled. * * \return \c true if a request to publish presence information was cancelled, * \c false otherwise. * \sa isPublishStateKnown(), publishState() */ bool Contact::isPublishCancelled() const { return mPriv->publishState == SubscriptionStateRemovedRemotely; } /** * Return the presence publish state of this contact (i.e. whether this contact can retrieve * information about the local user's presence). * * \return The presence publish state as Contact::PresenceState. * \sa isSubscriptionStateKnown(), isSubscriptionRejected() */ Contact::PresenceState Contact::publishState() const { return subscriptionStateToPresenceState(mPriv->publishState); } /** * If the publishState() is Contact::PresenceStateAsk, return an optional message that was sent * by the contact asking to receive the local user's presence; omitted if none was given. * * \return The message that was sent by the contact asking to receive the local user's presence. * \sa publishState() */ QString Contact::publishStateMessage() const { return mPriv->publishStateMessage; } /** * Start a request that this contact allow the local user to subscribe to their presence (i.e. that * this contact's subscribe attribute becomes Contact::PresenceStateYes) * * This method requires Connection::FeatureRoster to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa subscriptionState(), removePresenceSubscription() */ PendingOperation *Contact::requestPresenceSubscription(const QString &message) { return manager()->requestPresenceSubscription(QList() << ContactPtr(this), message); } /** * Start a request for the local user to stop receiving presence from this contact. * * This method requires Connection::FeatureRoster to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa subscriptionState(), requestPresenceSubscription() */ PendingOperation *Contact::removePresenceSubscription(const QString &message) { return manager()->removePresenceSubscription(QList() << ContactPtr(this), message); } /** * Start a request to authorize this contact's request to see the local user presence * (i.e. that this contact publish attribute becomes Contact::PresenceStateYes). * * This method requires Connection::FeatureRoster to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa publishState(), removePresencePublication() */ PendingOperation *Contact::authorizePresencePublication(const QString &message) { return manager()->authorizePresencePublication(QList() << ContactPtr(this), message); } /** * Start a request for the local user to stop sending presence to this contact. * * This method requires Connection::FeatureRoster to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when the request has been made. * \sa publishState(), authorizePresencePublication() */ PendingOperation *Contact::removePresencePublication(const QString &message) { return manager()->removePresencePublication(QList() << ContactPtr(this), message); } /** * Return whether this contact is blocked. * * Change notification is via the blockStatusChanged() signal. * * \return \c true if blocked, \c false otherwise. * \sa block() */ bool Contact::isBlocked() const { return mPriv->blocked; } /** * Block this contact. Blocked contacts cannot send messages to the user; * depending on the protocol, blocking a contact may have other effects. * * This method requires Connection::FeatureRoster to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when an attempt has been made to take the requested action. * \sa blockAndReportAbuse(), unblock() */ PendingOperation *Contact::block() { return manager()->blockContacts(QList() << ContactPtr(this)); } /** * Block this contact and additionally report abusive behaviour * to the server. * * If reporting abusive behaviour is not supported by the protocol, * this method has the same effect as block(). * * This method requires Connection::FeatureRoster to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when an attempt has been made to take the requested action. * \sa ContactManager::canReportAbuse(), block(), unblock() */ PendingOperation *Contact::blockAndReportAbuse() { return manager()->blockContactsAndReportAbuse(QList() << ContactPtr(this)); } /** * Unblock this contact. * * This method requires Connection::FeatureRoster to be ready. * * \return A PendingOperation which will emit PendingOperation::finished * when an attempt has been made to take the requested action. * \sa block(), blockAndReportAbuse() */ PendingOperation *Contact::unblock() { return manager()->unblockContacts(QList() << ContactPtr(this)); } /** * Return the names of the user-defined roster groups to which the contact * belongs. * * Change notification is via the addedToGroup() and removedFromGroup() signals. * * This method requires Connection::FeatureRosterGroups to be ready. * * \return A list of user-defined contact list groups names. * \sa addToGroup(), removedFromGroup() */ QStringList Contact::groups() const { return mPriv->groups.toList(); } /** * Attempt to add the contact to the user-defined contact list * group named \a group. * * This method requires Connection::FeatureRosterGroups to be ready. * * \param group The group name. * \return A PendingOperation which will emit PendingOperation::finished * when an attempt has been made to to add the contact to the user-defined contact * list group. * \sa groups(), removeFromGroup() */ PendingOperation *Contact::addToGroup(const QString &group) { return manager()->addContactsToGroup(group, QList() << ContactPtr(this)); } /** * Attempt to remove the contact from the user-defined contact list * group named \a group. * * This method requires Connection::FeatureRosterGroups to be ready. * * \param group The group name. * \return A PendingOperation which will emit PendingOperation::finished * when an attempt has been made to to remote the contact to the user-defined contact * list group. * \sa groups(), addToGroup() */ PendingOperation *Contact::removeFromGroup(const QString &group) { return manager()->removeContactsFromGroup(group, QList() << ContactPtr(this)); } /** * Return the client types of this contact, if known. * * Client types are represented using the values documented by the XMPP registrar, * with some additional types. A contact can set one or more client types, or can simply * advertise itself as unknown - in this case, an empty list is returned. * * This method returns cached information and is more appropriate for "lazy" * client type finding, for instance displaying the client types (if available) * of everyone in your contact list. For getting latest up-to-date information from * the server you should use requestClientTypes() instead. * * This method requires FeatureClientTypes to be ready. * * \return A list of the client types advertised by this contact. * \sa requestClientTypes(), clientTypesChanged() */ QStringList Contact::clientTypes() const { if (!mPriv->requestedFeatures.contains(FeatureClientTypes)) { warning() << "Contact::clientTypes() used on" << this << "for which FeatureClientTypes hasn't been requested - returning an empty list"; return QStringList(); } return mPriv->clientTypes; } /** * Return the current client types of the given contact. * * If necessary, this method will make a request to the server for up-to-date * information and wait for a reply. Therefore, this method is more appropriate * for use in a "Contact Information..." dialog; it can be used to show progress * information (while waiting for the method to return), and can distinguish * between various error conditions. * * This method requires FeatureClientTypes to be ready. * * \return A list of the client types advertised by this contact. * \sa clientTypes(), clientTypesChanged() */ PendingStringList *Contact::requestClientTypes() { if (!mPriv->requestedFeatures.contains(FeatureClientTypes)) { warning() << "Contact::requestClientTypes() used on" << this << "for which FeatureClientTypes hasn't been requested - the operation will fail"; } Client::ConnectionInterfaceClientTypesInterface *clientTypesInterface = manager()->connection()->interface(); return new PendingStringList( clientTypesInterface->RequestClientTypes(mPriv->handle.at(0)), ContactPtr(this)); } void Contact::augment(const Features &requestedFeatures, const QVariantMap &attributes) { mPriv->requestedFeatures.unite(requestedFeatures); mPriv->id = qdbus_cast(attributes[ TP_QT_IFACE_CONNECTION + QLatin1String("/contact-id")]); if (attributes.contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/subscribe"))) { uint subscriptionState = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/subscribe"))); setSubscriptionState((SubscriptionState) subscriptionState); } if (attributes.contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/publish"))) { uint publishState = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/publish"))); QString publishRequest = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/publish-request"))); setPublishState((SubscriptionState) publishState, publishRequest); } foreach (const Feature &feature, requestedFeatures) { QString maybeAlias; SimplePresence maybePresence; RequestableChannelClassList maybeCaps; QVariantMap maybeLocation; ContactInfoFieldList maybeInfo; if (feature == FeatureAlias) { maybeAlias = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_ALIASING + QLatin1String("/alias"))); if (!maybeAlias.isEmpty()) { receiveAlias(maybeAlias); } else if (mPriv->alias.isEmpty()) { mPriv->alias = mPriv->id; } } else if (feature == FeatureAvatarData) { if (manager()->supportedFeatures().contains(FeatureAvatarData)) { mPriv->actualFeatures.insert(FeatureAvatarData); mPriv->updateAvatarData(); } } else if (feature == FeatureAvatarToken) { if (attributes.contains( TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS + QLatin1String("/token"))) { receiveAvatarToken(qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS + QLatin1String("/token")))); } else { if (manager()->supportedFeatures().contains(FeatureAvatarToken)) { // AvatarToken being supported but not included in the mapping indicates // that the avatar token is not known - however, the feature is working fine mPriv->actualFeatures.insert(FeatureAvatarToken); } // In either case, the avatar token can't be known mPriv->isAvatarTokenKnown = false; mPriv->avatarToken = QLatin1String(""); } } else if (feature == FeatureCapabilities) { maybeCaps = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES + QLatin1String("/capabilities"))); if (!maybeCaps.isEmpty()) { receiveCapabilities(maybeCaps); } else { if (manager()->supportedFeatures().contains(FeatureCapabilities) && mPriv->requestedFeatures.contains(FeatureCapabilities)) { // Capabilities being supported but not updated in the // mapping indicates that the capabilities is not known - // however, the feature is working fine. mPriv->actualFeatures.insert(FeatureCapabilities); } } } else if (feature == FeatureInfo) { maybeInfo = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_INFO + QLatin1String("/info"))); if (!maybeInfo.isEmpty()) { receiveInfo(maybeInfo); } else { if (manager()->supportedFeatures().contains(FeatureInfo) && mPriv->requestedFeatures.contains(FeatureInfo)) { // Info being supported but not updated in the // mapping indicates that the info is not known - // however, the feature is working fine mPriv->actualFeatures.insert(FeatureInfo); } } } else if (feature == FeatureLocation) { maybeLocation = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_LOCATION + QLatin1String("/location"))); if (!maybeLocation.isEmpty()) { receiveLocation(maybeLocation); } else { if (manager()->supportedFeatures().contains(FeatureLocation) && mPriv->requestedFeatures.contains(FeatureLocation)) { // Location being supported but not updated in the // mapping indicates that the location is not known - // however, the feature is working fine mPriv->actualFeatures.insert(FeatureLocation); } } } else if (feature == FeatureSimplePresence) { maybePresence = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE + QLatin1String("/presence"))); if (!maybePresence.status.isEmpty()) { receiveSimplePresence(maybePresence); } else { mPriv->presence.setStatus(ConnectionPresenceTypeUnknown, QLatin1String("unknown"), QLatin1String("")); } } else if (feature == FeatureRosterGroups) { QStringList groups = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS + QLatin1String("/groups"))); mPriv->groups = groups.toSet(); } else if (feature == FeatureAddresses) { VCardFieldAddressMap addresses = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING + QLatin1String("/addresses"))); QStringList uris = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING + QLatin1String("/uris"))); receiveAddresses(addresses, uris); } else if (feature == FeatureClientTypes) { QStringList maybeClientTypes = qdbus_cast(attributes.value( TP_QT_IFACE_CONNECTION_INTERFACE_CLIENT_TYPES + QLatin1String("/client-types"))); if (!maybeClientTypes.isEmpty()) { receiveClientTypes(maybeClientTypes); } else { if (manager()->supportedFeatures().contains(FeatureClientTypes) && mPriv->requestedFeatures.contains(FeatureClientTypes)) { // ClientTypes being supported but not updated in the // mapping indicates that the info is not known - // however, the feature is working fine mPriv->actualFeatures.insert(FeatureClientTypes); } } } else { warning() << "Unknown feature" << feature << "encountered when augmenting Contact"; } } } void Contact::receiveAlias(const QString &alias) { if (!mPriv->requestedFeatures.contains(FeatureAlias)) { return; } mPriv->actualFeatures.insert(FeatureAlias); if (mPriv->alias != alias) { mPriv->alias = alias; emit aliasChanged(alias); } } void Contact::receiveAvatarToken(const QString &token) { setAvatarToken(token); if (mPriv->actualFeatures.contains(FeatureAvatarData)) { mPriv->updateAvatarData(); } } void Contact::setAvatarToken(const QString &token) { if (!mPriv->requestedFeatures.contains(FeatureAvatarToken)) { return; } mPriv->actualFeatures.insert(FeatureAvatarToken); if (!mPriv->isAvatarTokenKnown || mPriv->avatarToken != token) { mPriv->isAvatarTokenKnown = true; mPriv->avatarToken = token; emit avatarTokenChanged(mPriv->avatarToken); } } void Contact::receiveAvatarData(const AvatarData &avatar) { if (mPriv->avatarData.fileName != avatar.fileName) { mPriv->avatarData = avatar; emit avatarDataChanged(mPriv->avatarData); } } void Contact::receiveSimplePresence(const SimplePresence &presence) { if (!mPriv->requestedFeatures.contains(FeatureSimplePresence)) { return; } mPriv->actualFeatures.insert(FeatureSimplePresence); if (mPriv->presence.status() != presence.status || mPriv->presence.statusMessage() != presence.statusMessage) { mPriv->presence.setStatus(presence); emit presenceChanged(mPriv->presence); } } void Contact::receiveCapabilities(const RequestableChannelClassList &caps) { if (!mPriv->requestedFeatures.contains(FeatureCapabilities)) { return; } mPriv->actualFeatures.insert(FeatureCapabilities); if (mPriv->caps.allClassSpecs().bareClasses() != caps) { mPriv->caps.updateRequestableChannelClasses(caps); emit capabilitiesChanged(mPriv->caps); } } void Contact::receiveLocation(const QVariantMap &location) { if (!mPriv->requestedFeatures.contains(FeatureLocation)) { return; } mPriv->actualFeatures.insert(FeatureLocation); if (mPriv->location.allDetails() != location) { mPriv->location.updateData(location); emit locationUpdated(mPriv->location); } } void Contact::receiveInfo(const ContactInfoFieldList &info) { if (!mPriv->requestedFeatures.contains(FeatureInfo)) { return; } mPriv->actualFeatures.insert(FeatureInfo); mPriv->isContactInfoKnown = true; if (mPriv->info.allFields() != info) { mPriv->info = InfoFields(info); emit infoFieldsChanged(mPriv->info); } } void Contact::receiveAddresses(const QMap &addresses, const QStringList &uris) { if (!mPriv->requestedFeatures.contains(FeatureAddresses)) { return; } mPriv->actualFeatures.insert(FeatureAddresses); mPriv->vcardAddresses = addresses; mPriv->uris = uris; } void Contact::receiveClientTypes(const QStringList &clientTypes) { if (!mPriv->requestedFeatures.contains(FeatureClientTypes)) { return; } mPriv->actualFeatures.insert(FeatureClientTypes); if (mPriv->clientTypes != clientTypes) { mPriv->clientTypes = clientTypes; emit clientTypesChanged(mPriv->clientTypes); } } Contact::PresenceState Contact::subscriptionStateToPresenceState(uint subscriptionState) { switch (subscriptionState) { case SubscriptionStateAsk: return PresenceStateAsk; case SubscriptionStateYes: return PresenceStateYes; default: return PresenceStateNo; } } void Contact::setSubscriptionState(SubscriptionState state) { if (mPriv->subscriptionState == state) { return; } mPriv->subscriptionState = state; emit subscriptionStateChanged(subscriptionStateToPresenceState(state)); } void Contact::setPublishState(SubscriptionState state, const QString &message) { if (mPriv->publishState == state && mPriv->publishStateMessage == message) { return; } mPriv->publishState = state; mPriv->publishStateMessage = message; emit publishStateChanged(subscriptionStateToPresenceState(state), message); } void Contact::setBlocked(bool value) { if (mPriv->blocked == value) { return; } mPriv->blocked = value; emit blockStatusChanged(value); } void Contact::setAddedToGroup(const QString &group) { if (!mPriv->groups.contains(group)) { mPriv->groups.insert(group); emit addedToGroup(group); } } void Contact::setRemovedFromGroup(const QString &group) { if (mPriv->groups.remove(group)) { emit removedFromGroup(group); } } /** * \fn void Contact::aliasChanged(const QString &alias) * * Emitted when the value of alias() changes. * * \param alias The new alias of this contact. * \sa alias() */ /** * \fn void Contact::avatarTokenChanged(const QString &avatarToken) * * Emitted when the value of avatarToken() changes. * * \param avatarToken The new avatar token of this contact. * \sa avatarToken() */ /** * \fn void Contact::avatarDataChanged(const QString &avatarToken) * * Emitted when the value of avatarData() changes. * * \param avatarData The new avatar of this contact. * \sa avatarData() */ /** * \fn void Contact::presenceChanged(const Tp::Presence &presence) * * Emitted when the value of presence() changes. * * \param presence The new presence of this contact. * \sa presence() */ /** * \fn void Contact::capabilitiesChanged(const Tp::ContactCapabilities &caps) * * Emitted when the value of capabilities() changes. * * \param caps The new capabilities of this contact. * \sa capabilities() */ /** * \fn void Contact::locationUpdated(const Tp::LocationInfo &location) * * Emitted when the value of location() changes. * * \param caps The new location of this contact. * \sa location() */ /** * \fn void Contact::infoFieldsChanged(const Tp::Contact::InfoFields &infoFields) * * Emitted when the value of infoFields() changes. * * \param InfoFields The new info of this contact. * \sa infoFields() */ /** * \fn void Contact::subscriptionStateChanged(Tp::Contact::PresenceState state) * * Emitted when the value of subscriptionState() changes. * * \param state The new subscription state of this contact. * \sa subscriptionState() */ /** * \fn void Contact::publishStateChanged(Tp::Contact::PresenceState state, const QString &message) * * Emitted when the value of publishState() changes. * * \param state The new publish state of this contact. * \sa publishState() */ /** * \fn void Contact::blockStatusChanged(bool blocked) * * Emitted when the value of isBlocked() changes. * * \param status The new block status of this contact. * \sa isBlocked() */ /** * \fn void Contact::addedToGroup(const QString &group) * * Emitted when this contact is added to \a group of the contact list. * * \param group The group name. * \sa groups(), removedFromGroup() */ /** * \fn void Contact::removedFromGroup(const QString &group) * * Emitted when this contact is removed from \a group of the contact list. * * \param group The group name. * \sa groups(), addedToGroup() */ /** * \fn void Contact::clientTypesChanged(const QStringList &clientTypes) * * Emitted when the client types of this contact change or become known. * * \param clientTypes The contact's client types * \sa clientTypes(), requestClientTypes() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/pending-contact-info.cpp0000664000175000017500000000725512470405660021737 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-contact-info.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingContactInfo::Private { Contact::InfoFields info; }; /** * \class PendingContactInfo * \ingroup clientconn * \headerfile TelepathyQt/pending-contact-info.h * * \brief The PendingContactInfo class represents the parameters of and the * reply to an asynchronous contact info request. * * Instances of this class cannot be constructed directly; the only way to get * one is via Contact. * * See \ref async_model */ /** * Construct a new PendingContactInfo object. * * \param contact Contact to use. */ PendingContactInfo::PendingContactInfo(const ContactPtr &contact) : PendingOperation(contact), mPriv(new Private) { ConnectionPtr connection = contact->manager()->connection(); Client::ConnectionInterfaceContactInfoInterface *contactInfoInterface = connection->interface(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( contactInfoInterface->RequestContactInfo( contact->handle()[0]), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onCallFinished(QDBusPendingCallWatcher*))); } /** * Class destructor. */ PendingContactInfo::~PendingContactInfo() { delete mPriv; } /** * Return the contact through which the request was made. * * \return A pointer to the Contact object. */ ContactPtr PendingContactInfo::contact() const { return ContactPtr(qobject_cast((Contact*) object().data())); } /** * Return the information for contact(). * * \return The contact infor as a Contact::InfoFields object. */ Contact::InfoFields PendingContactInfo::infoFields() const { if (!isFinished()) { warning() << "PendingContactInfo::info called before finished"; } else if (!isValid()) { warning() << "PendingContactInfo::info called when not valid"; } return mPriv->info; } void PendingContactInfo::onCallFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { mPriv->info = Contact::InfoFields(reply.value()); debug() << "Got reply to ContactInfo.RequestContactInfo"; setFinished(); } else { debug().nospace() << "ContactInfo.RequestContactInfo failed: " << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/CapabilitiesBase0000664000175000017500000000037712470405660020332 0ustar jrjr#ifndef _TelepathyQt_CapabilitiesBase_HEADER_GUARD_ #define _TelepathyQt_CapabilitiesBase_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/utils.h0000664000175000017500000000275412470405660016535 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_utils_h_HEADER_GUARD_ #define _TelepathyQt_utils_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include namespace Tp { TP_QT_EXPORT QString escapeAsIdentifier(const QString &string); TP_QT_EXPORT bool checkValidProtocolName(const QString &protocolName); TP_QT_EXPORT QVariant::Type variantTypeFromDBusSignature(const QString &signature); TP_QT_EXPORT QVariant parseValueWithDBusSignature(const QString &value, const QString &dbusSignature); } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/channel-class-features.h0000664000175000017500000000253212470405660021716 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_channel_class_features_h_HEADER_GUARD_ #define _TelepathyQt_channel_class_features_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include namespace Tp { typedef QPair ChannelClassFeatures; } // Tp Q_DECLARE_METATYPE(Tp::ChannelClassFeatures); #endif telepathy-qt-0.9.6~git1/TelepathyQt/ServiceTypes0000664000175000017500000000036312470405660017566 0ustar jrjr#ifndef _TelepathyQt_ServiceTypes_HEADER_GUARD_ #define _TelepathyQt_ServiceTypes_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/GenericPropertyFilter0000664000175000017500000000041712470405660021430 0ustar jrjr#ifndef _TelepathyQt_GenericPropertyFilter_HEADER_GUARD_ #define _TelepathyQt_GenericPropertyFilter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AbstractClientObserver0000664000175000017500000000041112470405660021545 0ustar jrjr#ifndef _TelepathyQt_AbstractClientObserver_HEADER_GUARD_ #define _TelepathyQt_AbstractClientObserver_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AccountFactory0000664000175000017500000000037112470405660020064 0ustar jrjr#ifndef _TelepathyQt_AccountFactory_HEADER_GUARD_ #define _TelepathyQt_AccountFactory_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/pending-connection.h0000664000175000017500000000403012470405660021143 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_connection_h_HEADER_GUARD_ #define _TelepathyQt_pending_connection_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include class QDBusPendingCallWatcher; namespace Tp { class ConnectionManager; class TP_QT_EXPORT PendingConnection : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingConnection); public: ~PendingConnection(); ConnectionManagerPtr manager() const; ConnectionPtr connection() const; private Q_SLOTS: TP_QT_NO_EXPORT void onCallFinished(QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onConnectionBuilt(Tp::PendingOperation *op); private: friend class ConnectionManagerLowlevel; TP_QT_NO_EXPORT PendingConnection(const ConnectionManagerPtr &manager, const QString &protocol, const QVariantMap ¶meters); TP_QT_NO_EXPORT PendingConnection(const QString &error, const QString &errorMessage); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/utils.cpp0000664000175000017500000001424212470405660017063 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/key-file.h" #include #include /** * \defgroup utility functions */ namespace Tp { static inline bool isBad(char c, bool isFirst) { return ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9' || isFirst)); } /** * Escape an arbitrary string so it follows the rules for a C identifier, * and hence an object path component, interface element component, * bus name component or member name in D-Bus. * * This is a reversible encoding, so it preserves distinctness. * * The escaping consists of replacing all non-alphanumerics, and the first * character if it's a digit, with an underscore and two lower-case hex * digits: * * "0123abc_xyz\x01\xff" -> _30123abc_5fxyz_01_ff * * i.e. similar to URI encoding, but with _ taking the role of %, and a * smaller allowed set. As a special case, "" is escaped to "_" (just for * completeness, really). * * \param string The string to be escaped. * \return the escaped string. */ QString escapeAsIdentifier(const QString &string) { bool bad = false; QByteArray op; QByteArray utf8; const char *name; const char *ptr, *firstOk; /* This function is copy/pasted from tp_escape_as_identified from * telepathy-glib. */ /* fast path for empty name */ if (string.isEmpty()) { return QString::fromLatin1("_"); } utf8 = string.toUtf8(); name = utf8.constData(); for (ptr = name; *ptr; ptr++) { if (isBad(*ptr, ptr == name)) { bad = true; break; } } /* fast path if it's clean */ if (!bad) { return string; } /* If strictly less than ptr, firstOk is the first uncopied safe character. */ firstOk = name; for (ptr = name; *ptr; ptr++) { if (isBad(*ptr, ptr == name)) { char buf[4] = { 0, }; /* copy preceding safe characters if any */ if (firstOk < ptr) { op.append(firstOk, ptr - firstOk); } /* escape the unsafe character */ qsnprintf(buf, sizeof (buf), "_%02x", (unsigned char)(*ptr)); op.append(buf); /* restart after it */ firstOk = ptr + 1; } } /* copy trailing safe characters if any */ if (firstOk < ptr) { op.append(firstOk, ptr - firstOk); } return QString::fromLatin1(op.constData()); } bool checkValidProtocolName(const QString &protocolName) { if (protocolName.isEmpty()) { return false; } if (!protocolName[0].isLetter()) { return false; } int length = protocolName.length(); if (length <= 1) { return true; } QChar ch; for (int i = 1; i < length; ++i) { ch = protocolName[i]; if (!ch.isLetterOrNumber() && ch != QLatin1Char('-')) { return false; } } return true; } QVariant::Type variantTypeFromDBusSignature(const QString &signature) { QVariant::Type type; if (signature == QLatin1String("b")) { type = QVariant::Bool; } else if (signature == QLatin1String("n") || signature == QLatin1String("i")) { type = QVariant::Int; } else if (signature == QLatin1String("q") || signature == QLatin1String("u")) { type = QVariant::UInt; } else if (signature == QLatin1String("x")) { type = QVariant::LongLong; } else if (signature == QLatin1String("t")) { type = QVariant::ULongLong; } else if (signature == QLatin1String("d")) { type = QVariant::Double; } else if (signature == QLatin1String("as")) { type = QVariant::StringList; } else if (signature == QLatin1String("s") || signature == QLatin1String("o")) { type = QVariant::String; } else { type = QVariant::Invalid; } return type; } QVariant parseValueWithDBusSignature(const QString &value, const QString &dbusSignature) { QVariant::Type type = variantTypeFromDBusSignature(dbusSignature); if (type == QVariant::Invalid) { return QVariant(type); } switch (type) { case QVariant::Bool: { if (value.toLower() == QLatin1String("true") || value == QLatin1String("1")) { return QVariant(true); } else { return QVariant(false); } break; } case QVariant::Int: return QVariant(value.toInt()); case QVariant::UInt: return QVariant(value.toUInt()); case QVariant::LongLong: return QVariant(value.toLongLong()); case QVariant::ULongLong: return QVariant(value.toULongLong()); case QVariant::Double: return QVariant(value.toDouble()); case QVariant::StringList: { QStringList list; QByteArray rawValue = value.toLatin1(); if (KeyFile::unescapeStringList(rawValue, 0, rawValue.size(), list)) { return QVariant(list); } else { return QVariant(QVariant::Invalid); } } default: break; } return QVariant(value); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/server-authentication-channel.cpp0000664000175000017500000002574312470405660023664 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/server-authentication-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ServerAuthenticationChannel::Private { Private(ServerAuthenticationChannel *parent); static void introspectMain(ServerAuthenticationChannel::Private *self); void extractServerAuthenticationProperties(const QVariantMap &props); // Public object ServerAuthenticationChannel *parent; ReadinessHelper *readinessHelper; // Introspection QString authMethod; CaptchaAuthenticationPtr captchaAuthentication; }; ServerAuthenticationChannel::Private::Private(ServerAuthenticationChannel *parent) : parent(parent), readinessHelper(parent->readinessHelper()) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableServerAuthentication( QSet() << 0, // makesSenseForStatuses Features() << Channel::FeatureCore, // dependsOnFeatures (core) QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &ServerAuthenticationChannel::Private::introspectMain, this); introspectables[ServerAuthenticationChannel::FeatureCore] = introspectableServerAuthentication; readinessHelper->addIntrospectables(introspectables); } void ServerAuthenticationChannel::Private::introspectMain(ServerAuthenticationChannel::Private *self) { ServerAuthenticationChannel *parent = self->parent; Client::ChannelTypeServerAuthenticationInterface *serverAuthenticationInterface = parent->interface(); PendingVariantMap *pvm = serverAuthenticationInterface->requestAllProperties(); parent->connect(pvm, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotServerAuthenticationProperties(Tp::PendingOperation*))); } /** * \class ServerAuthenticationChannel * \ingroup clientchannel * \headerfile TelepathyQt/server-authentication-channel.h * * \brief The ServerAuthenticationChannel class is a base class for all ServerAuthentication types. * * A ServerAuthentication is a mechanism for a connection to perform an authentication operation. * Such an authentication can happen in several ways (at the moment, only Captcha is supported) - this * channel will expose a high-level object representing the requested method, allowing a handler to carry on * the authentication procedure. * * Note that when an authentication procedure succeeds, you can expect this channel to be closed automatically. * Please refer to the methods' implementation docs for more details about this. * * See \ref async_model, \ref shared_ptr */ /** * Feature representing the core that needs to become ready to make the * ServerAuthenticationChannel object usable. * * Note that this feature must be enabled in order to use most * ServerAuthenticationChannel methods. * See specific methods documentation for more details. */ const Feature ServerAuthenticationChannel::FeatureCore = Feature(QLatin1String(ServerAuthenticationChannel::staticMetaObject.className()), 0); /** * Create a new ServerAuthenticationChannel channel. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A ServerAuthenticationChannelPtr object pointing to the newly created * ServerAuthenticationChannel object. */ ServerAuthenticationChannelPtr ServerAuthenticationChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return ServerAuthenticationChannelPtr(new ServerAuthenticationChannel(connection, objectPath, immutableProperties)); } /** * Construct a new ServerAuthenticationChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * depend on ServerAuthenticationChannel::FeatureCore. */ ServerAuthenticationChannel::ServerAuthenticationChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : Channel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private(this)) { } /** * Class destructor. */ ServerAuthenticationChannel::~ServerAuthenticationChannel() { delete mPriv; } /** * Return whether this ServerAuthenticationChannel implements Captcha as its authentication mechanism. * Should this be true, captchaAuthentication() can be safely accessed. * * This method requires ServerAuthenticationChannel::FeatureCore to be ready. * * \return \c true if this channel implements the Captcha interface, \c false otherwise. * \sa captchaAuthentication */ bool ServerAuthenticationChannel::hasCaptchaInterface() const { if (!isReady(ServerAuthenticationChannel::FeatureCore)) { warning() << "ServerAuthenticationChannel::hasCaptchaInterface() used with FeatureCore not ready"; return false; } return mPriv->authMethod == TP_QT_IFACE_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION; } /* * Return whether this ServerAuthenticationChannel implements Sasl as its authentication mechanism. * * This method requires ServerAuthenticationChannel::FeatureCore to be ready. * * \return \c true if this channel implements the Sasl interface, \c false otherwise. * * TODO: Enable when high-level SASL Support will be in place bool ServerAuthenticationChannel::hasSaslInterface() const { if (!isReady(ServerAuthenticationChannel::FeatureCore)) { warning() << "ServerAuthenticationChannel::hasSaslInterface() used with FeatureCore not ready"; return false; } return mPriv->authMethod == TP_QT_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION; }*/ /** * Return the CaptchaAuthentication object for this channel, if the channel implements * the CaptchaAuthentication interface and is a ServerAuthentication Channel. * * Note that this method will return a meaningful value only if hasCaptchaInterface() * returns \c true. * * This method requires ServerAuthenticationChannel::FeatureCore to be ready. * * \return A shared pointer to the object representing the CaptchaAuthentication interface, * or a null shared pointer if the feature is not ready yet or the channel does not * implement Captcha interface. * \sa hasCaptchaInterface */ CaptchaAuthenticationPtr ServerAuthenticationChannel::captchaAuthentication() const { if (!isReady(ServerAuthenticationChannel::FeatureCore)) { warning() << "ServerAuthenticationChannel::captchaAuthentication() used with FeatureCore not ready"; return CaptchaAuthenticationPtr(); } return mPriv->captchaAuthentication; } void ServerAuthenticationChannel::gotCaptchaAuthenticationProperties(Tp::PendingOperation *op) { if (!op->isError()) { PendingVariantMap *pvm = qobject_cast(op); mPriv->captchaAuthentication->mPriv->extractCaptchaAuthenticationProperties(pvm->result()); debug() << "Got reply to Properties::GetAll(CaptchaAuthentication)"; mPriv->readinessHelper->setIntrospectCompleted(ServerAuthenticationChannel::FeatureCore, true); } else { warning().nospace() << "Properties::GetAll(CaptchaAuthentication) failed " "with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(ServerAuthenticationChannel::FeatureCore, false, op->errorName(), op->errorMessage()); } } void ServerAuthenticationChannel::gotServerAuthenticationProperties(Tp::PendingOperation *op) { if (!op->isError()) { PendingVariantMap *pvm = qobject_cast(op); debug() << "Got reply to Properties::GetAll(ServerAuthentication)"; mPriv->authMethod = qdbus_cast(pvm->result()[QLatin1String("AuthenticationMethod")]); if (mPriv->authMethod == TP_QT_IFACE_CHANNEL_INTERFACE_CAPTCHA_AUTHENTICATION) { mPriv->captchaAuthentication = CaptchaAuthenticationPtr(new CaptchaAuthentication(ChannelPtr(this))); Client::ChannelInterfaceCaptchaAuthenticationInterface *captchaAuthenticationInterface = interface(); captchaAuthenticationInterface->setMonitorProperties(true); QObject::connect(captchaAuthenticationInterface, SIGNAL(propertiesChanged(QVariantMap,QStringList)), mPriv->captchaAuthentication.data(), SLOT(onPropertiesChanged(QVariantMap,QStringList))); PendingVariantMap *pvm = captchaAuthenticationInterface->requestAllProperties(); connect(pvm, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotCaptchaAuthenticationProperties(Tp::PendingOperation*))); } else { // We have nothing else to do here at the moment mPriv->readinessHelper->setIntrospectCompleted(ServerAuthenticationChannel::FeatureCore, true); } } else { warning().nospace() << "Properties::GetAll(ServerAuthentication) failed " "with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(ServerAuthenticationChannel::FeatureCore, false, op->errorName(), op->errorMessage()); } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelRequest0000664000175000017500000000037112470405660020061 0ustar jrjr#ifndef _TelepathyQt_ChannelRequest_HEADER_GUARD_ #define _TelepathyQt_ChannelRequest_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/AvatarSpec0000664000175000017500000000035012470405660017166 0ustar jrjr#ifndef _TelepathyQt_AvatarSpec_HEADER_GUARD_ #define _TelepathyQt_AvatarSpec_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/base-protocol.h0000664000175000017500000002064412470405660020144 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_base_protocol_h_HEADER_GUARD_ #define _TelepathyQt_base_protocol_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include #include #include #include class QString; class QStringList; namespace Tp { class TP_QT_EXPORT BaseProtocol : public DBusService { Q_OBJECT Q_DISABLE_COPY(BaseProtocol) public: static BaseProtocolPtr create(const QString &name) { return BaseProtocolPtr(new BaseProtocol(QDBusConnection::sessionBus(), name)); } template static SharedPtr create(const QString &name) { return SharedPtr(new BaseProtocolSubclass( QDBusConnection::sessionBus(), name)); } static BaseProtocolPtr create(const QDBusConnection &dbusConnection, const QString &name) { return BaseProtocolPtr(new BaseProtocol(dbusConnection, name)); } template static SharedPtr create(const QDBusConnection &dbusConnection, const QString &name) { return SharedPtr(new BaseProtocolSubclass(dbusConnection, name)); } virtual ~BaseProtocol(); QString name() const; QVariantMap immutableProperties() const; // Proto QStringList connectionInterfaces() const; void setConnectionInterfaces(const QStringList &connInterfaces); ProtocolParameterList parameters() const; void setParameters(const ProtocolParameterList ¶meters); RequestableChannelClassSpecList requestableChannelClasses() const; void setRequestableChannelClasses(const RequestableChannelClassSpecList &rccSpecs); QString vcardField() const; void setVCardField(const QString &vcardField); QString englishName() const; void setEnglishName(const QString &englishName); QString iconName() const; void setIconName(const QString &iconName); QStringList authenticationTypes() const; void setAuthenticationTypes(const QStringList &authenticationTypes); typedef Callback2 CreateConnectionCallback; void setCreateConnectionCallback(const CreateConnectionCallback &cb); Tp::BaseConnectionPtr createConnection(const QVariantMap ¶meters, DBusError *error); typedef Callback2 IdentifyAccountCallback; void setIdentifyAccountCallback(const IdentifyAccountCallback &cb); QString identifyAccount(const QVariantMap ¶meters, DBusError *error); typedef Callback2 NormalizeContactCallback; void setNormalizeContactCallback(const NormalizeContactCallback &cb); QString normalizeContact(const QString &contactId, DBusError *error); QList interfaces() const; AbstractProtocolInterfacePtr interface(const QString & interfaceName) const; bool plugInterface(const AbstractProtocolInterfacePtr &interface); protected: BaseProtocol(const QDBusConnection &dbusConnection, const QString &name); virtual bool registerObject(const QString &busName, const QString &objectPath, DBusError *error); private: friend class BaseConnectionManager; class Adaptee; friend class Adaptee; class Private; friend class Private; Private *mPriv; }; class TP_QT_EXPORT AbstractProtocolInterface : public AbstractDBusServiceInterface { Q_OBJECT Q_DISABLE_COPY(AbstractProtocolInterface) public: AbstractProtocolInterface(const QString &interfaceName); virtual ~AbstractProtocolInterface(); private: friend class BaseProtocol; class Private; friend class Private; Private *mPriv; }; class TP_QT_EXPORT BaseProtocolAddressingInterface : public AbstractProtocolInterface { Q_OBJECT Q_DISABLE_COPY(BaseProtocolAddressingInterface) public: static BaseProtocolAddressingInterfacePtr create() { return BaseProtocolAddressingInterfacePtr(new BaseProtocolAddressingInterface()); } template static SharedPtr create() { return SharedPtr( new BaseProtocolAddressingInterfaceSubclass()); } virtual ~BaseProtocolAddressingInterface(); QVariantMap immutableProperties() const; QStringList addressableVCardFields() const; void setAddressableVCardFields(const QStringList &vcardFields); QStringList addressableUriSchemes() const; void setAddressableUriSchemes(const QStringList &uriSchemes); typedef Callback3 NormalizeVCardAddressCallback; void setNormalizeVCardAddressCallback(const NormalizeVCardAddressCallback &cb); QString normalizeVCardAddress(const QString &vcardField, const QString &vcardAddress, DBusError *error); typedef Callback2 NormalizeContactUriCallback; void setNormalizeContactUriCallback(const NormalizeContactUriCallback &cb); QString normalizeContactUri(const QString &uri, DBusError *error); protected: BaseProtocolAddressingInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseProtocolAvatarsInterface : public AbstractProtocolInterface { Q_OBJECT Q_DISABLE_COPY(BaseProtocolAvatarsInterface) public: static BaseProtocolAvatarsInterfacePtr create() { return BaseProtocolAvatarsInterfacePtr(new BaseProtocolAvatarsInterface()); } template static SharedPtr create() { return SharedPtr( new BaseProtocolAvatarsInterfaceSubclass()); } virtual ~BaseProtocolAvatarsInterface(); QVariantMap immutableProperties() const; AvatarSpec avatarDetails() const; void setAvatarDetails(const AvatarSpec &spec); protected: BaseProtocolAvatarsInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseProtocolPresenceInterface : public AbstractProtocolInterface { Q_OBJECT Q_DISABLE_COPY(BaseProtocolPresenceInterface) public: static BaseProtocolPresenceInterfacePtr create() { return BaseProtocolPresenceInterfacePtr(new BaseProtocolPresenceInterface()); } template static SharedPtr create() { return SharedPtr( new BaseProtocolPresenceInterfaceSubclass()); } virtual ~BaseProtocolPresenceInterface(); QVariantMap immutableProperties() const; PresenceSpecList statuses() const; void setStatuses(const PresenceSpecList &statuses); protected: BaseProtocolPresenceInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/optional-interface-factory.cpp0000664000175000017500000001201312470405660023145 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "TelepathyQt/debug-internal.h" #include #include namespace Tp { #ifndef DOXYGEN_SHOULD_SKIP_THIS struct TP_QT_NO_EXPORT OptionalInterfaceCache::Private { QObject *proxy; QHash interfaces; Private(QObject *proxy); }; OptionalInterfaceCache::Private::Private(QObject *proxy) : proxy(proxy) { } /** * Class constructor. */ OptionalInterfaceCache::OptionalInterfaceCache(QObject *proxy) : mPriv(new Private(proxy)) { } /** * Class destructor. * * Frees all interface instances constructed by this factory. */ OptionalInterfaceCache::~OptionalInterfaceCache() { delete mPriv; } QObject *OptionalInterfaceCache::proxy() const { return mPriv->proxy; } AbstractInterface *OptionalInterfaceCache::getCached(const QString &name) const { if (mPriv->interfaces.contains(name)) { return mPriv->interfaces.value(name); } else { return 0; } } void OptionalInterfaceCache::cache(AbstractInterface *interface) const { QString name = interface->interface(); Q_ASSERT(!mPriv->interfaces.contains(name)); mPriv->interfaces[name] = interface; } #endif /* ifndef DOXYGEN_SHOULD_SKIP_THIS */ /** * \class OptionalInterfaceFactory * \ingroup clientsideproxies * \headerfile TelepathyQt/optional-interface-factory.h * * \brief The OptionalInterfaceFactory class is a helper class for * high-level D-Bus proxy classes willing to offer access to shared * instances of interface proxies for optional interfaces. * * To use this helper in a subclass of DBusProxy (say, ExampleObject), * ExampleObject should inherit from * OptionalInterfaceFactory, and call * OptionalInterfaceFactory(this) in its constructor's initialization list. * * \tparam DBusProxySubclass A subclass of DBusProxy */ /** * \enum OptionalInterfaceFactory::InterfaceSupportedChecking * * Specifies if the interface being supported by the remote object should be * checked by optionalInterface() and the convenience functions for it. * * \sa optionalInterface() */ /** * \var OptionalInterfaceFactory::InterfaceSupportedChecking OptionalInterfaceFactory::CheckInterfaceSupported * * Don't return an interface instance unless it can be guaranteed that the * remote object actually implements the interface. */ /** * \var OptionalInterfaceFactory::InterfaceSupportedChecking OptionalInterfaceFactory::BypassInterfaceCheck * * Return an interface instance even if it can't be verified that the remote * object supports the interface. */ /** * \fn OptionalInterfaceFactory::OptionalInterfaceFactory(DBusProxySubclass *this_) * * Class constructor. * * \param this_ The class to which this OptionalInterfaceFactory is * attached */ /** * \fn OptionalInterfaceFactory::~OptionalInterfaceFactory() * * Class destructor. * * Frees all interface instances constructed by this factory. */ /** * \fn OptionalInterfaceFactory::interfaces() const; * * Return a list of interfaces supported by this object. * * \return List of supported interfaces. */ /** * \fn template inline Interface *OptionalInterfaceFactory::interface() const * * Return a pointer to a valid instance of a interface class, associated * with the same remote object as the given main interface instance. The * given main interface must be of the class the optional interface is * generated for (for eg. ChannelInterfaceGroupInterface this means * ChannelInterface) or a subclass. * * First invocation of this method for a particular optional interface * class will construct the instance; subsequent calls will return a * pointer to the same instance. * * The returned instance is freed when the factory is destroyed; using * it after destroying the factory will likely produce a crash. As the * instance is shared, it should not be freed directly. * * \tparam Interface Class of the interface instance to get. * \return A pointer to an optional interface instance. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/generic-property-filter.dox0000664000175000017500000000246012470405660022513 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \class Tp::GenericPropertyFilter * \ingroup utils * \headerfile TelepathyQt/generic-property-filter.h * * \brief The GenericPropertyFilter class provides a generic filter object * to be used to filter objects by properties. * * Specialized classes such as AccountPropertyFilter are also provided and * should be used where appropriate. */ telepathy-qt-0.9.6~git1/TelepathyQt/AccountCapabilityFilter0000664000175000017500000000042512470405660021704 0ustar jrjr#ifndef _TelepathyQt_AccountCapabilityFilter_HEADER_GUARD_ #define _TelepathyQt_AccountCapabilityFilter_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/Presence0000664000175000017500000000034612470405660016706 0ustar jrjr#ifndef _TelepathyQt_Presence_HEADER_GUARD_ #define _TelepathyQt_Presence_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/connection-capabilities.h0000664000175000017500000000434212470405660022156 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_connection_capabilities_h_HEADER_GUARD_ #define _TelepathyQt_connection_capabilities_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TestBackdoors; class TP_QT_EXPORT ConnectionCapabilities : public CapabilitiesBase { public: ConnectionCapabilities(); virtual ~ConnectionCapabilities(); bool textChatrooms() const; TP_QT_DEPRECATED bool conferenceStreamedMediaCalls() const; TP_QT_DEPRECATED bool conferenceStreamedMediaCallsWithInvitees() const; bool conferenceTextChats() const; bool conferenceTextChatsWithInvitees() const; bool conferenceTextChatrooms() const; bool conferenceTextChatroomsWithInvitees() const; bool contactSearches() const; bool contactSearchesWithSpecificServer() const; bool contactSearchesWithLimit() const; bool dbusTubes() const; bool streamTubes() const; protected: friend class Account; friend class Connection; friend class ProtocolInfo; friend class TestBackdoors; ConnectionCapabilities(const RequestableChannelClassList &rccs); ConnectionCapabilities(const RequestableChannelClassSpecList &rccSpecs); }; } // Tp Q_DECLARE_METATYPE(Tp::ConnectionCapabilities); #endif telepathy-qt-0.9.6~git1/TelepathyQt/pending-channel.cpp0000664000175000017500000004722212470405660020761 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/pending-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include "TelepathyQt/fake-handler-manager-internal.h" #include "TelepathyQt/request-temporary-handler-internal.h" #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT PendingChannel::Private { class FakeAccountFactory; ConnectionPtr connection; bool create; bool yours; QString channelType; uint handleType; uint handle; QVariantMap immutableProperties; ChannelPtr channel; ClientRegistrarPtr cr; SharedPtr handler; HandledChannelNotifier *notifier; static uint numHandlers; }; uint PendingChannel::Private::numHandlers = 0; class TP_QT_NO_EXPORT PendingChannel::Private::FakeAccountFactory : public AccountFactory { public: static AccountFactoryPtr create(const AccountPtr &account) { return AccountFactoryPtr(new FakeAccountFactory(account)); } ~FakeAccountFactory() { } AccountPtr account() const { return mAccount; } protected: AccountPtr construct(const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const { if (mAccount->objectPath() != objectPath) { warning() << "Account received by the fake factory is different from original account"; } return mAccount; } private: FakeAccountFactory(const AccountPtr &account) : AccountFactory(account->dbusConnection(), Features()), mAccount(account) { } AccountPtr mAccount; }; /** * \class PendingChannel * \ingroup clientchannel * \headerfile TelepathyQt/pending-channel.h * * \brief The PendingChannel class represents the parameters of and the reply to * an asynchronous channel request. * * Instances of this class cannot be constructed directly; the only way to get * one is trough Connection or Account. * * See \ref async_model */ /** * Construct a new PendingChannel object that will fail immediately. * * \param connection Connection to use. * \param errorName The error name. * \param errorMessage The error message. */ PendingChannel::PendingChannel(const ConnectionPtr &connection, const QString &errorName, const QString &errorMessage) : PendingOperation(connection), mPriv(new Private) { mPriv->connection = connection; mPriv->yours = false; mPriv->handleType = 0; mPriv->handle = 0; mPriv->notifier = 0; mPriv->create = false; setFinishedWithError(errorName, errorMessage); } /** * Construct a new PendingChannel object. * * \param connection Connection to use. * \param request A dictionary containing the desirable properties. * \param create Whether createChannel or ensureChannel should be called. */ PendingChannel::PendingChannel(const ConnectionPtr &connection, const QVariantMap &request, bool create, int timeout) : PendingOperation(connection), mPriv(new Private) { mPriv->connection = connection; mPriv->yours = create; mPriv->channelType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString(); mPriv->handleType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")).toUInt(); mPriv->handle = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")).toUInt(); mPriv->notifier = 0; mPriv->create = create; Client::ConnectionInterfaceRequestsInterface *requestsInterface = connection->interface(); if (create) { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( requestsInterface->CreateChannel(request, timeout), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onConnectionCreateChannelFinished(QDBusPendingCallWatcher*))); } else { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( requestsInterface->EnsureChannel(request, timeout), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(onConnectionEnsureChannelFinished(QDBusPendingCallWatcher*))); } } PendingChannel::PendingChannel(const AccountPtr &account, const QVariantMap &request, const QDateTime &userActionTime, bool create) : PendingOperation(account), mPriv(new Private) { mPriv->yours = true; mPriv->channelType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString(); mPriv->handleType = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")).toUInt(); mPriv->handle = request.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")).toUInt(); mPriv->cr = ClientRegistrar::create( Private::FakeAccountFactory::create(account), account->connectionFactory(), account->channelFactory(), account->contactFactory()); mPriv->handler = RequestTemporaryHandler::create(account); mPriv->notifier = 0; mPriv->create = create; QString handlerName = QString(QLatin1String("TpQtRaH_%1_%2")) .arg(account->dbusConnection().baseService() .replace(QLatin1String(":"), QLatin1String("_")) .replace(QLatin1String("."), QLatin1String("_"))) .arg(Private::numHandlers++); if (!mPriv->cr->registerClient(mPriv->handler, handlerName, false)) { warning() << "Unable to register handler" << handlerName; setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Unable to register handler")); return; } connect(mPriv->handler.data(), SIGNAL(error(QString,QString)), SLOT(onHandlerError(QString,QString))); connect(mPriv->handler.data(), SIGNAL(channelReceived(Tp::ChannelPtr,QDateTime,Tp::ChannelRequestHints)), SLOT(onHandlerChannelReceived(Tp::ChannelPtr))); handlerName = QString(QLatin1String("org.freedesktop.Telepathy.Client.%1")).arg(handlerName); debug() << "Requesting channel through account using handler" << handlerName; PendingChannelRequest *pcr; if (create) { pcr = account->createChannel(request, userActionTime, handlerName, ChannelRequestHints()); } else { pcr = account->ensureChannel(request, userActionTime, handlerName, ChannelRequestHints()); } connect(pcr, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountCreateChannelFinished(Tp::PendingOperation*))); } /** * Construct a new PendingChannel object that will fail immediately. * * \param errorName The name of a D-Bus error. * \param errorMessage The error message. */ PendingChannel::PendingChannel(const QString &errorName, const QString &errorMessage) : PendingOperation(ConnectionPtr()), mPriv(new Private) { setFinishedWithError(errorName, errorMessage); } /** * Class destructor. */ PendingChannel::~PendingChannel() { delete mPriv; } /** * Return the connection through which the channel request was made. * * Note that if this channel request was created through Account, a null ConnectionPtr will be * returned. * * \return A pointer to the Connection object. */ ConnectionPtr PendingChannel::connection() const { return mPriv->connection; } /** * Return whether this channel belongs to this process. * * If \c false, the caller must assume that some other process is * handling this channel; if \c true, the caller should handle it * themselves or delegate it to another client. * * \return \c true if it belongs, \c false otherwise. */ bool PendingChannel::yours() const { if (!isFinished()) { warning() << "PendingChannel::yours called before finished, returning undefined value"; } else if (!isValid()) { warning() << "PendingChannel::yours called when not valid, returning undefined value"; } return mPriv->yours; } /** * Return the channel type specified in the channel request. * * \return The D-Bus interface name for the type of the channel. */ const QString &PendingChannel::channelType() const { return mPriv->channelType; } /** * If the channel request has finished, return the handle type of the resulting * channel. Otherwise, return the handle type that was requested. * * (One example of a request producing a different target handle type is that * on protocols like MSN, one-to-one conversations don't really exist, and if * you request a text channel with handle type HandleTypeContact, what you * will actually get is a text channel with handle type HandleTypeNone, with * the requested contact as a member.) * * \return The target handle type as #HandleType. * \sa targetHandle() */ uint PendingChannel::targetHandleType() const { return mPriv->handleType; } /** * If the channel request has finished, return the target handle of the * resulting channel. Otherwise, return the target handle that was requested * (which might be different in some situations - see targetHandleType()). * * \return An integer representing the target handle, which is of the type * targetHandleType() indicates. * \sa targetHandleType() */ uint PendingChannel::targetHandle() const { return mPriv->handle; } /** * If this channel request has finished, return the immutable properties of * the resulting channel. Otherwise, return an empty map. * * The keys and values in this map are defined by the \telepathy_spec, * or by third-party extensions to that specification. * These are the properties that cannot change over the lifetime of the * channel; they're announced in the result of the request, for efficiency. * This map should be passed to the constructor of Channel or its subclasses * (such as TextChannel). * * These properties can also be used to process channels in a way that does * not require the creation of a Channel object - for instance, a * ChannelDispatcher implementation should be able to classify and process * channels based on their immutable properties, without needing to create * Channel objects. * * \return The immutable properties as QVariantMap. */ QVariantMap PendingChannel::immutableProperties() const { QVariantMap props = mPriv->immutableProperties; // This is a reasonable guess - if it's Yours it's guaranteedly Requested by us, and if it's not // it could be either Requested by somebody else but also an incoming channel just as well. if (!props.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".Requested"))) { debug() << "CM didn't provide Requested in channel immutable props, guessing" << mPriv->yours; props[TP_QT_IFACE_CHANNEL + QLatin1String(".Requested")] = mPriv->yours; } // Also, the spec says that if the channel was Requested by the local user, InitiatorHandle must // be the Connection's self handle if (!props.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle"))) { if (qdbus_cast(props.value(TP_QT_IFACE_CHANNEL + QLatin1String(".Requested")))) { if (connection() && connection()->isReady(Connection::FeatureCore)) { debug() << "CM didn't provide InitiatorHandle in channel immutable props, but we " "know it's the conn's self handle (and have it)"; props[TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle")] = connection()->selfHandle(); } } } return props; } /** * Return the channel resulting from the channel request. * * \return A pointer to the Channel object. */ ChannelPtr PendingChannel::channel() const { if (!isFinished()) { warning() << "PendingChannel::channel called before finished, returning 0"; return ChannelPtr(); } else if (!isValid()) { warning() << "PendingChannel::channel called when not valid, returning 0"; return ChannelPtr(); } return mPriv->channel; } /** * If this channel request has finished and was created through Account, * return a HandledChannelNotifier object that will keep track of channel() being re-requested. * * \return A HandledChannelNotifier instance, or 0 if an error occurred. */ HandledChannelNotifier *PendingChannel::handledChannelNotifier() const { if (!isFinished()) { warning() << "PendingChannel::handledChannelNotifier called before finished, returning 0"; return 0; } else if (!isValid()) { warning() << "PendingChannel::handledChannelNotifier called when not valid, returning 0"; return 0; } if (mPriv->cr && !mPriv->notifier) { mPriv->notifier = new HandledChannelNotifier(mPriv->cr, mPriv->handler); } return mPriv->notifier; } void PendingChannel::onConnectionCreateChannelFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { QString objectPath = reply.argumentAt<0>().path(); QVariantMap map = reply.argumentAt<1>(); debug() << "Got reply to Connection.CreateChannel - object path:" << objectPath; PendingReady *channelReady = connection()->channelFactory()->proxy(connection(), objectPath, map); mPriv->channel = ChannelPtr::qObjectCast(channelReady->proxy()); mPriv->immutableProperties = map; mPriv->channelType = map.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString(); mPriv->handleType = map.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")).toUInt(); mPriv->handle = map.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")).toUInt(); connect(channelReady, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onChannelReady(Tp::PendingOperation*))); } else { debug().nospace() << "CreateChannel failed:" << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } void PendingChannel::onConnectionEnsureChannelFinished(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { mPriv->yours = reply.argumentAt<0>(); QString objectPath = reply.argumentAt<1>().path(); QVariantMap map = reply.argumentAt<2>(); debug() << "Got reply to Connection.EnsureChannel - object path:" << objectPath; PendingReady *channelReady = connection()->channelFactory()->proxy(connection(), objectPath, map); mPriv->channel = ChannelPtr::qObjectCast(channelReady->proxy()); mPriv->immutableProperties = map; mPriv->channelType = map.value(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString(); mPriv->handleType = map.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")).toUInt(); mPriv->handle = map.value(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle")).toUInt(); connect(channelReady, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onChannelReady(Tp::PendingOperation*))); } else { debug().nospace() << "EnsureChannel failed:" << reply.error().name() << ": " << reply.error().message(); setFinishedWithError(reply.error()); } watcher->deleteLater(); } void PendingChannel::onChannelReady(PendingOperation *op) { if (!op->isError()) { setFinished(); } else { debug() << "Making the channel ready for" << this << "failed with" << op->errorName() << ":" << op->errorMessage(); setFinishedWithError(op->errorName(), op->errorMessage()); } } void PendingChannel::onHandlerError(const QString &errorName, const QString &errorMessage) { if (isFinished()) { return; } warning() << "Creating/ensuring channel failed with" << errorName << ":" << errorMessage; setFinishedWithError(errorName, errorMessage); } void PendingChannel::onHandlerChannelReceived(const ChannelPtr &channel) { if (isFinished()) { warning() << "Handler received the channel but this operation already finished due " "to failure in the channel request"; return; } mPriv->handleType = channel->targetHandleType(); mPriv->handle = channel->targetHandle(); mPriv->immutableProperties = channel->immutableProperties(); mPriv->channel = channel; // register the CR in FakeHandlerManager so that at least one handler per bus stays alive // until all channels requested using R&H gets invalidated/destroyed. // This is important in case Mission Control happens to restart while // the channel is still in use, since it will close each channel it // doesn't find a handler for it. FakeHandlerManager::instance()->registerClientRegistrar(mPriv->cr); setFinished(); } void PendingChannel::onAccountCreateChannelFinished(PendingOperation *op) { if (isFinished()) { if (isError()) { warning() << "Creating/ensuring channel finished with a failure after the internal " "handler already got a channel, ignoring"; } return; } if (op->isError()) { warning() << "Creating/ensuring channel failed with" << op->errorName() << ":" << op->errorMessage(); setFinishedWithError(op->errorName(), op->errorMessage()); return; } if (!mPriv->handler->isDBusHandlerInvoked()) { // Our handler hasn't be called but the channel request is complete. // That means another handler handled the channels so we don't own it. if (mPriv->create) { warning() << "Creating/ensuring channel failed with" << TP_QT_ERROR_SERVICE_CONFUSED << ":" << QLatin1String("CD.CreateChannel/WithHints returned successfully and " "the handler didn't receive the channel yet"); setFinishedWithError(TP_QT_ERROR_SERVICE_CONFUSED, QLatin1String("CD.CreateChannel/WithHints returned successfully and " "the handler didn't receive the channel yet")); } else { warning() << "Creating/ensuring channel failed with" << TP_QT_ERROR_NOT_YOURS << ":" << QLatin1String("Another handler is handling this channel"); setFinishedWithError(TP_QT_ERROR_NOT_YOURS, QLatin1String("Another handler is handling this channel")); } return; } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/abstract-interface.cpp0000664000175000017500000001631312470405660021465 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/abstract-interface.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT AbstractInterface::Private { Private(); QString mError; QString mMessage; bool monitorProperties; }; AbstractInterface::Private::Private() : monitorProperties(false) { } /** * \class AbstractInterface * \ingroup clientsideproxies * \headerfile TelepathyQt/abstract-interface.h * * \brief The AbstractInterface class is the base class for all client side * D-Bus interfaces, allowing access to remote methods/properties/signals. */ AbstractInterface::AbstractInterface(const QString &busName, const QString &path, const QLatin1String &interface, const QDBusConnection &dbusConnection, QObject *parent) : QDBusAbstractInterface(busName, path, interface.latin1(), dbusConnection, parent), mPriv(new Private) { } AbstractInterface::AbstractInterface(DBusProxy *parent, const QLatin1String &interface) : QDBusAbstractInterface(parent->busName(), parent->objectPath(), interface.latin1(), parent->dbusConnection(), parent), mPriv(new Private) { connect(parent, SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), this, SLOT(invalidate(Tp::DBusProxy*,QString,QString))); } AbstractInterface::~AbstractInterface() { delete mPriv; } bool AbstractInterface::isValid() const { return QDBusAbstractInterface::isValid() && mPriv->mError.isEmpty(); } QString AbstractInterface::invalidationReason() const { return mPriv->mError; } QString AbstractInterface::invalidationMessage() const { return mPriv->mMessage; } void AbstractInterface::invalidate(DBusProxy *proxy, const QString &error, const QString &message) { Q_ASSERT(!error.isEmpty()); if (mPriv->mError.isEmpty()) { mPriv->mError = error; mPriv->mMessage = message; } } PendingVariant *AbstractInterface::internalRequestProperty(const QString &name) const { QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), TP_QT_IFACE_PROPERTIES, QLatin1String("Get")); msg << interface() << name; QDBusPendingCall pendingCall = connection().asyncCall(msg); DBusProxy *proxy = qobject_cast(parent()); return new PendingVariant(pendingCall, DBusProxyPtr(proxy)); } PendingOperation *AbstractInterface::internalSetProperty(const QString &name, const QVariant &newValue) { QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), TP_QT_IFACE_PROPERTIES, QLatin1String("Set")); msg << interface() << name << QVariant::fromValue(QDBusVariant(newValue)); QDBusPendingCall pendingCall = connection().asyncCall(msg); DBusProxy *proxy = qobject_cast(parent()); return new PendingVoid(pendingCall, DBusProxyPtr(proxy)); } PendingVariantMap *AbstractInterface::internalRequestAllProperties() const { QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), TP_QT_IFACE_PROPERTIES, QLatin1String("GetAll")); msg << interface(); QDBusPendingCall pendingCall = connection().asyncCall(msg); DBusProxy *proxy = qobject_cast(parent()); return new PendingVariantMap(pendingCall, DBusProxyPtr(proxy)); } /** * Sets whether this abstract interface will be monitoring properties or not. If it's set to monitor, * the signal propertiesChanged will be emitted whenever a property on this interface will * change. * * By default, AbstractInterface does not monitor properties: you need to call this method * for this to happen. * * \param monitorProperties Whether this interface should monitor property changes or not. * \sa isMonitoringProperties * propertiesChanged() */ void AbstractInterface::setMonitorProperties(bool monitorProperties) { if (monitorProperties == mPriv->monitorProperties) { return; } QStringList argumentMatch; argumentMatch << interface(); bool success; if (monitorProperties) { success = connection().connect(service(), path(), TP_QT_IFACE_PROPERTIES, QLatin1String("PropertiesChanged"), argumentMatch, QString(), this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList))); } else { success = connection().disconnect(service(), path(), TP_QT_IFACE_PROPERTIES, QLatin1String("PropertiesChanged"), argumentMatch, QString(), this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList))); } if (!success) { warning() << "Connection or disconnection to " << TP_QT_IFACE_PROPERTIES << ".PropertiesChanged failed."; } } /** * Return whether this abstract interface is monitoring properties or not. If it's monitoring, * the signal propertiesChanged will be emitted whenever a property on this interface will * change. * * By default, AbstractInterface does not monitor properties: you need to call setMonitorProperties * for this to happen. * * \return \c true if the interface is monitoring for property changes, \c false otherwise. * \sa setMonitorProperties * propertiesChanged() */ bool AbstractInterface::isMonitoringProperties() const { return mPriv->monitorProperties; } void AbstractInterface::onPropertiesChanged(const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) { emit propertiesChanged(changedProperties, invalidatedProperties); } /** * \fn void AbstractInterface::propertiesChanged(const QVariantMap &changedProperties, * const QStringList &invalidatedProperties) * * Emitted when one or more properties on this interface change or become invalidated. * This signal will be emitted only if the interface is monitoring properties. * * \param changedProperties A map of the changed properties with their new value, if any. * \param invalidatedProperties A list of the invalidated properties, if any. * \sa isMonitoringProperties() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/FixedFeatureFactory0000664000175000017500000000041112470405660021036 0ustar jrjr#ifndef _TelepathyQt_FixedFeatureFactory_HEADER_GUARD_ #define _TelepathyQt_FixedFeatureFactory_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/room-list-channel.cpp0000664000175000017500000000624412470405660021261 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/room-list-channel.moc.hpp" #include "TelepathyQt/debug-internal.h" #include namespace Tp { struct TP_QT_NO_EXPORT RoomListChannel::Private { inline Private(); inline ~Private(); }; RoomListChannel::Private::Private() { } RoomListChannel::Private::~Private() { } /** * \class RoomListChannel * \ingroup clientchannel * \headerfile TelepathyQt/room-list-channel.h * * \brief The RoomListChannel class represents a Telepathy Channel of type RoomList. * * Note that this subclass of Channel will eventually provide a high-level API for the * RoomList interface. Until then, it's just a Channel. * * For more details, please refer to \telepathy_spec. * * See \ref async_model, \ref shared_ptr */ /** * Create a new RoomListChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \return A RoomListChannelPtr object pointing to the newly created * RoomListChannel object. */ RoomListChannelPtr RoomListChannel::create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties) { return RoomListChannelPtr(new RoomListChannel(connection, objectPath, immutableProperties)); } /** * Construct a new RoomListChannel object. * * \param connection Connection owning this channel, and specifying the * service. * \param objectPath The channel object path. * \param immutableProperties The channel immutable properties. * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should * should depend on Channel::FeatureCore. */ RoomListChannel::RoomListChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature) : Channel(connection, objectPath, immutableProperties, coreFeature), mPriv(new Private()) { } /** * Class destructor. */ RoomListChannel::~RoomListChannel() { delete mPriv; } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionLowlevel0000664000175000017500000000040312470405660020745 0ustar jrjr#ifndef _TelepathyQt_ConnectionLowlevel_HEADER_GUARD #define _TelepathyQt_ConnectionLowlevel_HEADER_GUARD #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/capabilities-base.h0000664000175000017500000000522712470405660020734 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_capabilities_base_h_HEADER_GUARD_ #define _TelepathyQt_capabilities_base_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT CapabilitiesBase { public: CapabilitiesBase(); CapabilitiesBase(const CapabilitiesBase &other); virtual ~CapabilitiesBase(); CapabilitiesBase &operator=(const CapabilitiesBase &other); RequestableChannelClassSpecList allClassSpecs() const; bool isSpecificToContact() const; bool textChats() const; bool audioCalls() const; bool videoCalls() const; bool videoCallsWithAudio() const; bool upgradingCalls() const; TP_QT_DEPRECATED bool streamedMediaCalls() const; TP_QT_DEPRECATED bool streamedMediaAudioCalls() const; TP_QT_DEPRECATED bool streamedMediaVideoCalls() const; TP_QT_DEPRECATED bool streamedMediaVideoCallsWithAudio() const; TP_QT_DEPRECATED bool upgradingStreamedMediaCalls() const; bool fileTransfers() const; // later: FIXME TODO why not now? // QList fileTransfersRequireHash() const; protected: CapabilitiesBase(bool specificToContact); CapabilitiesBase(const RequestableChannelClassList &rccs, bool specificToContact); CapabilitiesBase(const RequestableChannelClassSpecList &rccSpecs, bool specificToContact); virtual void updateRequestableChannelClasses( const RequestableChannelClassList &rccs); private: friend class Connection; friend class Contact; struct Private; friend struct Private; QSharedDataPointer mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::CapabilitiesBase); #endif telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceServicePointInterface0000664000175000017500000000045012470405660025232 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceServicePointInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceServicePointInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/incoming-stream-tube-channel.h0000664000175000017500000000446212470405660023032 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2011 Collabora Ltd. * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_incoming_stream_tube_channel_h_HEADER_GUARD_ #define _TelepathyQt_incoming_stream_tube_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include class QIODevice; namespace Tp { class PendingStreamTubeConnection; class TP_QT_EXPORT IncomingStreamTubeChannel : public StreamTubeChannel { Q_OBJECT Q_DISABLE_COPY(IncomingStreamTubeChannel) public: static const Feature FeatureCore; static IncomingStreamTubeChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~IncomingStreamTubeChannel(); PendingStreamTubeConnection *acceptTubeAsTcpSocket(); PendingStreamTubeConnection *acceptTubeAsTcpSocket(const QHostAddress &allowedAddress, quint16 allowedPort); PendingStreamTubeConnection *acceptTubeAsUnixSocket(bool requireCredentials = false); protected: IncomingStreamTubeChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = IncomingStreamTubeChannel::FeatureCore); private Q_SLOTS: TP_QT_NO_EXPORT void onNewLocalConnection(uint connectionId); private: struct Private; friend class PendingStreamTubeConnection; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceContactInfoInterface0000664000175000017500000000044612470405660025034 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceContactInfoInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceContactInfoInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/TelepathyQtServiceConfig.cmake.in0000664000175000017500000000236212470405660023541 0ustar jrjr# TelepathyQt@QT_VERSION_MAJOR@ServiceConfig.cmake is generated by CMake from TelepathyQt/TelepathyQtServiceConfig.cmake.in. # Any changed value in this file will be overwritten by CMake. # set the version number set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_VERSION_MAJOR @TP_QT_MAJOR_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_VERSION_MINOR @TP_QT_MINOR_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_VERSION_MICRO @TP_QT_MICRO_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_VERSION_NANO @TP_QT_NANO_VERSION@) set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_VERSION @PACKAGE_VERSION@) # set the directories if(NOT TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_INSTALL_DIR) set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_INSTALL_DIR "@CMAKE_INSTALL_PREFIX@") endif(NOT TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_INSTALL_DIR) set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_INCLUDE_DIR "@TELEPATHY_QT_INCLUDE_DIR@") set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_LIB_DIR "@TELEPATHY_QT_LIB_DIR@") set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_SHARE_DIR "@TELEPATHY_QT_DATA_DIR@") find_package(TelepathyQt@QT_VERSION_MAJOR@ REQUIRED) set(TELEPATHY_QT@QT_VERSION_MAJOR@_SERVICE_LIBRARIES telepathy-qt@QT_VERSION_MAJOR@-service) telepathy-qt-0.9.6~git1/TelepathyQt/DBusTubeChannel0000664000175000017500000000037512470405660020112 0ustar jrjr#ifndef _TelepathyQt_DBusTubeChannel_HEADER_GUARD_ #define _TelepathyQt_DBusTubeChannel_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/contact-factory.cpp0000664000175000017500000001017112470405660021020 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include namespace Tp { struct TP_QT_NO_EXPORT ContactFactory::Private { Features features; }; /** * \class ContactFactory * \ingroup utils * \headerfile TelepathyQt/contact-factory.h * * \brief The ContactFactory class is responsible for constructing Contact * objects according to application-defined settings. */ /** * Creates a new ContactFactory. * * \param features The features to make ready on constructed contacts. * \returns A pointer to the created factory. */ ContactFactoryPtr ContactFactory::create(const Features &features) { return ContactFactoryPtr(new ContactFactory(features)); } /** * Class constructor. * * \param features The features to make ready on constructed contacts. */ ContactFactory::ContactFactory(const Features &features) : mPriv(new Private) { addFeatures(features); } /** * Class destructor. */ ContactFactory::~ContactFactory() { delete mPriv; } /** * Gets the features this factory will make ready on constructed contacts. * * \return The set of features. */ Features ContactFactory::features() const { Features features = mPriv->features; // FeatureAvatarData depends on FeatureAvatarToken if (features.contains(Contact::FeatureAvatarData) && !features.contains(Contact::FeatureAvatarToken)) { features.insert(Contact::FeatureAvatarToken); } return features; } /** * Adds a single feature this factory will make ready on further constructed contacts. * * No feature removal is provided, to guard against uncooperative modules removing features other * modules have set and depend on. * * \param feature The feature to add. */ void ContactFactory::addFeature(const Feature &feature) { addFeatures(Features(feature)); } /** * Adds a set of features this factory will make ready on further constructed contacts. * * No feature removal is provided, to guard against uncooperative modules removing features other * modules have set and depend on. * * \param features The features to add. */ void ContactFactory::addFeatures(const Features &features) { mPriv->features.unite(features); } /** * Can be used by subclasses to override the Contact subclass constructed by the factory. * * The default implementation constructs Tp::Contact objects. * * \param manager The contact manager this contact belongs. * \param handle The contact handle. * \param features The desired contact features. * \param attributes The desired contact attributes. * \return A pointer to the constructed contact. */ ContactPtr ContactFactory::construct(Tp::ContactManager *manager, const ReferencedHandles &handle, const Features &features, const QVariantMap &attributes) const { ContactPtr contact = ContactPtr(new Contact(manager, handle, features, attributes)); return contact; } /** * Can be used by subclasses to do arbitrary manipulation on constructed Contact objects. * * The default implementation does nothing. * * \param contact The contact to be prepared. * \return A PendingOperation used to prepare the contact or NULL if there is nothing to prepare. */ PendingOperation *ContactFactory::prepare(const ContactPtr &contact) const { return NULL; } } telepathy-qt-0.9.6~git1/TelepathyQt/SimpleTextObserver0000664000175000017500000000040612470405660020745 0ustar jrjr#ifndef _TelepathyQt_SimpleTextObserver_HEADER_GUARD_ #define _TelepathyQt_SimpleTextObserver_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/call-stream.cpp0000664000175000017500000004202012470405660020122 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2010-2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/call-stream.moc.hpp" #include "TelepathyQt/_gen/cli-call-stream-body.hpp" #include "TelepathyQt/_gen/cli-call-stream.moc.hpp" #include #include #include #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT CallStream::Private { Private(CallStream *parent, const CallContentPtr &content); static void introspectMainProperties(Private *self); void processRemoteMembersChanged(); struct RemoteMembersChangedInfo; // Public object CallStream *parent; WeakPtr content; // Mandatory proxies Client::CallStreamInterface *streamInterface; ReadinessHelper *readinessHelper; // Introspection uint localSendingState; ContactSendingStateMap remoteMembers; QHash remoteMembersContacts; bool canRequestReceiving; QQueue< QSharedPointer > remoteMembersChangedQueue; QSharedPointer currentRemoteMembersChangedInfo; }; struct TP_QT_NO_EXPORT CallStream::Private::RemoteMembersChangedInfo { RemoteMembersChangedInfo(const ContactSendingStateMap &updates, const HandleIdentifierMap &identifiers, const UIntList &removed, const CallStateReason &reason) : updates(updates), identifiers(identifiers), removed(removed), reason(reason) { } static QSharedPointer create( const ContactSendingStateMap &updates, const HandleIdentifierMap &identifiers, const UIntList &removed, const CallStateReason &reason) { RemoteMembersChangedInfo *info = new RemoteMembersChangedInfo( updates, identifiers, removed, reason); return QSharedPointer(info); } ContactSendingStateMap updates; HandleIdentifierMap identifiers; UIntList removed; CallStateReason reason; }; CallStream::Private::Private(CallStream *parent, const CallContentPtr &content) : parent(parent), content(content.data()), streamInterface(parent->interface()), readinessHelper(parent->readinessHelper()), localSendingState(SendingStateNone), canRequestReceiving(true) { ReadinessHelper::Introspectables introspectables; ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMainProperties, this); introspectables[FeatureCore] = introspectableCore; readinessHelper->addIntrospectables(introspectables); readinessHelper->becomeReady(FeatureCore); } void CallStream::Private::introspectMainProperties(CallStream::Private *self) { CallStream *parent = self->parent; parent->connect(self->streamInterface, SIGNAL(LocalSendingStateChanged(uint,Tp::CallStateReason)), SLOT(onLocalSendingStateChanged(uint,Tp::CallStateReason))); parent->connect(self->streamInterface, SIGNAL(RemoteMembersChanged(Tp::ContactSendingStateMap,Tp::HandleIdentifierMap,Tp::UIntList,Tp::CallStateReason)), SLOT(onRemoteMembersChanged(Tp::ContactSendingStateMap,Tp::HandleIdentifierMap,Tp::UIntList,Tp::CallStateReason))); parent->connect(self->streamInterface->requestAllProperties(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotMainProperties(Tp::PendingOperation*))); } void CallStream::Private::processRemoteMembersChanged() { if (currentRemoteMembersChangedInfo) { // currently building contacts return; } if (remoteMembersChangedQueue.isEmpty()) { if (!parent->isReady(FeatureCore)) { readinessHelper->setIntrospectCompleted(FeatureCore, true); } return; } currentRemoteMembersChangedInfo = remoteMembersChangedQueue.dequeue(); QSet pendingRemoteMembers; for (ContactSendingStateMap::const_iterator i = currentRemoteMembersChangedInfo->updates.constBegin(); i != currentRemoteMembersChangedInfo->updates.constEnd(); ++i) { pendingRemoteMembers.insert(i.key()); } foreach(uint i, currentRemoteMembersChangedInfo->removed) { pendingRemoteMembers.insert(i); } if (!pendingRemoteMembers.isEmpty()) { ConnectionPtr connection = parent->content()->channel()->connection(); connection->lowlevel()->injectContactIds(currentRemoteMembersChangedInfo->identifiers); ContactManagerPtr contactManager = connection->contactManager(); PendingContacts *contacts = contactManager->contactsForHandles( pendingRemoteMembers.toList()); parent->connect(contacts, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotRemoteMembersContacts(Tp::PendingOperation*))); } else { currentRemoteMembersChangedInfo.clear(); processRemoteMembersChanged(); } } /** * \class CallStream * \ingroup clientchannel * \headerfile TelepathyQt/call-stream.h * * \brief The CallStream class provides an object representing a Telepathy * Call.Stream. * * Instances of this class cannot be constructed directly; the only way to get * one is via CallContent. * * See \ref async_model */ /** * Feature representing the core that needs to become ready to make the * CallStream object usable. * * Note that this feature must be enabled in order to use most CallStream * methods. See specific methods documentation for more details. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature CallStream::FeatureCore = Feature(QLatin1String(CallStream::staticMetaObject.className()), 0); /** * Construct a new CallStream object. * * \param content The content owning this call stream. * \param objectPath The object path of this call stream. */ CallStream::CallStream(const CallContentPtr &content, const QDBusObjectPath &objectPath) : StatefulDBusProxy(content->dbusConnection(), content->busName(), objectPath.path(), FeatureCore), OptionalInterfaceFactory(this), mPriv(new Private(this, content)) { } /** * Class destructor. */ CallStream::~CallStream() { delete mPriv; } /** * Return the content owning this call stream. * * \return The content owning this call stream. */ CallContentPtr CallStream::content() const { return CallContentPtr(mPriv->content); } /** * Returns whether the user can request that a remote contact starts * sending on this stream. Not all protocols allow the user to ask * the other side to start sending media. * * \return true if the user can request that a remote contact starts * sending on this stream, or false otherwise. * \sa requestReceiving() */ bool CallStream::canRequestReceiving() const { return mPriv->canRequestReceiving; } /** * Return the contacts whose the call stream is with. * * \return The contacts whose the call stream is with. * \sa remoteMembersRemoved() */ Contacts CallStream::remoteMembers() const { return mPriv->remoteMembersContacts.values().toSet(); } /** * Return the call stream local sending state. * * \return The call stream local sending state. * \sa localSendingStateChanged() */ SendingState CallStream::localSendingState() const { return (SendingState) mPriv->localSendingState; } /** * Return the call stream remote sending state for a given \a contact. * * \return The call stream remote sending state for a contact. * \sa remoteSendingStateChanged() */ SendingState CallStream::remoteSendingState(const ContactPtr &contact) const { if (!contact) { return SendingStateNone; } for (ContactSendingStateMap::const_iterator i = mPriv->remoteMembers.constBegin(); i != mPriv->remoteMembers.constEnd(); ++i) { uint handle = i.key(); SendingState sendingState = (SendingState) i.value(); if (handle == contact->handle()[0]) { return sendingState; } } return SendingStateNone; } /** * Request that media starts or stops being sent on this call stream. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa localSendingStateChanged() */ PendingOperation *CallStream::requestSending(bool send) { return new PendingVoid(mPriv->streamInterface->SetSending(send), CallStreamPtr(this)); } /** * Request that a remote \a contact stops or starts sending on this call stream. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. * \sa remoteSendingStateChanged() */ PendingOperation *CallStream::requestReceiving(const ContactPtr &contact, bool receive) { if (!contact) { return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid contact"), CallStreamPtr(this)); } else if (!mPriv->canRequestReceiving && receive) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Requesting the other side to start sending media " "is not allowed by this protocol"), CallStreamPtr(this)); } return new PendingVoid(mPriv->streamInterface->RequestReceiving(contact->handle()[0], receive), CallStreamPtr(this)); } void CallStream::gotMainProperties(PendingOperation *op) { if (op->isError()) { warning().nospace() << "CallStreamInterface::requestAllProperties() failed with " << op->errorName() << ": " << op->errorMessage(); mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, op->errorName(), op->errorMessage()); return; } debug() << "Got reply to CallStreamInterface::requestAllProperties()"; PendingVariantMap *pvm = qobject_cast(op); Q_ASSERT(pvm); QVariantMap props = pvm->result(); mPriv->canRequestReceiving = qdbus_cast(props[QLatin1String("CanRequestReceiving")]); mPriv->localSendingState = qdbus_cast(props[QLatin1String("LocalSendingState")]); ContactSendingStateMap remoteMembers = qdbus_cast(props[QLatin1String("RemoteMembers")]); HandleIdentifierMap remoteMemberIdentifiers = qdbus_cast(props[QLatin1String("RemoteMemberIdentifiers")]); mPriv->remoteMembersChangedQueue.enqueue(Private::RemoteMembersChangedInfo::create( remoteMembers, remoteMemberIdentifiers, UIntList(), CallStateReason())); mPriv->processRemoteMembersChanged(); } void CallStream::gotRemoteMembersContacts(PendingOperation *op) { PendingContacts *pc = qobject_cast(op); if (!pc->isValid()) { warning().nospace() << "Getting contacts failed with " << pc->errorName() << ":" << pc->errorMessage() << ", ignoring"; mPriv->currentRemoteMembersChangedInfo.clear(); mPriv->processRemoteMembersChanged(); return; } QMap removed; for (ContactSendingStateMap::const_iterator i = mPriv->currentRemoteMembersChangedInfo->updates.constBegin(); i != mPriv->currentRemoteMembersChangedInfo->updates.constEnd(); ++i) { mPriv->remoteMembers.insert(i.key(), i.value()); } foreach (const ContactPtr &contact, pc->contacts()) { mPriv->remoteMembersContacts.insert(contact->handle()[0], contact); } foreach (uint handle, mPriv->currentRemoteMembersChangedInfo->removed) { mPriv->remoteMembers.remove(handle); if (isReady(FeatureCore) && mPriv->remoteMembersContacts.contains(handle)) { removed.insert(handle, mPriv->remoteMembersContacts[handle]); // make sure we don't have updates for removed contacts mPriv->currentRemoteMembersChangedInfo->updates.remove(handle); } mPriv->remoteMembersContacts.remove(handle); } foreach (uint handle, pc->invalidHandles()) { mPriv->remoteMembers.remove(handle); if (isReady(FeatureCore) && mPriv->remoteMembersContacts.contains(handle)) { removed.insert(handle, mPriv->remoteMembersContacts[handle]); // make sure we don't have updates for invalid handles mPriv->currentRemoteMembersChangedInfo->updates.remove(handle); } mPriv->remoteMembersContacts.remove(handle); } if (isReady(FeatureCore)) { CallChannelPtr channel(content()->channel()); QHash remoteSendingStates; for (ContactSendingStateMap::const_iterator i = mPriv->currentRemoteMembersChangedInfo->updates.constBegin(); i != mPriv->currentRemoteMembersChangedInfo->updates.constEnd(); ++i) { uint handle = i.key(); SendingState sendingState = (SendingState) i.value(); Q_ASSERT(mPriv->remoteMembersContacts.contains(handle)); remoteSendingStates.insert(mPriv->remoteMembersContacts[handle], sendingState); mPriv->remoteMembers.insert(i.key(), i.value()); } if (!remoteSendingStates.isEmpty()) { emit remoteSendingStateChanged(remoteSendingStates, mPriv->currentRemoteMembersChangedInfo->reason); } if (!removed.isEmpty()) { emit remoteMembersRemoved(removed.values().toSet(), mPriv->currentRemoteMembersChangedInfo->reason); } } mPriv->currentRemoteMembersChangedInfo.clear(); mPriv->processRemoteMembersChanged(); } void CallStream::onLocalSendingStateChanged(uint state, const CallStateReason &reason) { mPriv->localSendingState = state; emit localSendingStateChanged((SendingState) state, reason); } void CallStream::onRemoteMembersChanged(const ContactSendingStateMap &updates, const HandleIdentifierMap &identifiers, const UIntList &removed, const CallStateReason &reason) { if (updates.isEmpty() && removed.isEmpty()) { debug() << "Received Call::Stream::RemoteMembersChanged with 0 removals and " "updates, skipping it"; return; } debug() << "Received Call::Stream::RemoteMembersChanged with" << updates.size() << "updated and" << removed.size() << "removed"; mPriv->remoteMembersChangedQueue.enqueue( Private::RemoteMembersChangedInfo::create(updates, identifiers, removed, reason)); mPriv->processRemoteMembersChanged(); } /** * \fn void CallStream::localSendingStateChanged(Tp::SendingState localSendingState, const Tp::CallStateReason &reason); * * This signal is emitted when the local sending state of this call stream * changes. * * \param localSendingState The new local sending state of this call stream. * \param reason The reason that caused this change * \sa localSendingState() */ /** * \fn void CallStream::remoteSendingStateChanged(const QHash &remoteSendingStates, const Tp::CallStateReason &reason); * * This signal is emitted when any remote sending state of this call stream * changes. * * \param remoteSendingStates The new remote sending states of this call stream. * \param reason The reason that caused these changes * \sa remoteSendingState() */ /** * \fn void CallStream::remoteMembersRemoved(const Tp::Contacts &members, const Tp::CallStateReason &reason); * * This signal is emitted when one or more members of this stream are removed. * * \param members The members that were removed from this call stream. * \param reason The reason for that caused these removals * \sa remoteMembers() */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/Properties0000664000175000017500000000035412470405660017275 0ustar jrjr#ifndef _TelepathyQt_Properties_HEADER_GUARD_ #define _TelepathyQt_Properties_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceAvatarsInterface0000664000175000017500000000043612470405660024225 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceAvatarsInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceAvatarsInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/profile.h0000664000175000017500000001154312470405660017031 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_profile_h_HEADER_GUARD_ #define _TelepathyQt_profile_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include namespace Tp { class ProtocolInfo; class TP_QT_EXPORT Profile : public RefCounted { Q_DISABLE_COPY(Profile); public: static ProfilePtr createForServiceName(const QString &serviceName); static ProfilePtr createForFileName(const QString &fileName); ~Profile(); QString serviceName() const; bool isValid() const; bool isFake() const; QString type() const; QString provider() const; QString name() const; QString iconName() const; QString cmName() const; QString protocolName() const; class Parameter { public: Parameter(); Parameter(const Parameter &other); Parameter(const QString &name, const QDBusSignature &dbusSignature, const QVariant &value, const QString &label, bool mandatory); ~Parameter(); QString name() const; QDBusSignature dbusSignature() const; QVariant::Type type() const; QVariant value() const; QString label() const; bool isMandatory() const; // TODO Add matches(Tp::Presence) method Parameter &operator=(const Parameter &other); private: friend class Profile; TP_QT_NO_EXPORT void setName(const QString &name); TP_QT_NO_EXPORT void setDBusSignature(const QDBusSignature &dbusSignature); TP_QT_NO_EXPORT void setValue(const QVariant &value); TP_QT_NO_EXPORT void setLabel(const QString &label); TP_QT_NO_EXPORT void setMandatory(bool mandatory); struct Private; friend struct Private; Private *mPriv; }; typedef QList ParameterList; ParameterList parameters() const; bool hasParameter(const QString &name) const; Parameter parameter(const QString &name) const; class Presence { public: Presence(); Presence(const Presence &other); Presence(const QString &id, const QString &label, const QString &iconName, const QString &message, bool disabled); ~Presence(); QString id() const; QString label() const; QString iconName() const; bool canHaveStatusMessage() const; bool isDisabled() const; Presence &operator=(const Presence &other); private: friend class Profile; TP_QT_NO_EXPORT void setId(const QString &id); TP_QT_NO_EXPORT void setLabel(const QString &label); TP_QT_NO_EXPORT void setIconName(const QString &iconName); TP_QT_NO_EXPORT void setMessage(const QString &message); TP_QT_NO_EXPORT void setDisabled(bool disabled); struct Private; friend struct Private; Private *mPriv; }; typedef QList PresenceList; bool allowOtherPresences() const; PresenceList presences() const; bool hasPresence(const QString &id) const; Presence presence(const QString &id) const; RequestableChannelClassSpecList unsupportedChannelClassSpecs() const; private: friend class Account; friend class ProfileManager; TP_QT_NO_EXPORT Profile(); TP_QT_NO_EXPORT Profile(const QString &serviceName, const QString &cmName, const QString &protocolName, const ProtocolInfo &protocolInfo); TP_QT_NO_EXPORT void setServiceName(const QString &serviceName); TP_QT_NO_EXPORT void setFileName(const QString &fileName); TP_QT_NO_EXPORT static QStringList searchDirs(); struct Private; friend struct Private; Private *mPriv; }; } // Tp Q_DECLARE_METATYPE(Tp::Profile::Parameter); Q_DECLARE_METATYPE(Tp::Profile::Presence); #endif telepathy-qt-0.9.6~git1/TelepathyQt/readiness-helper.h0000664000175000017500000000753612470405660020632 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_readiness_helper_h_HEADER_GUARD_ #define _TelepathyQt_readiness_helper_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include class QDBusError; namespace Tp { class DBusProxy; class PendingOperation; class PendingReady; class RefCounted; class TP_QT_EXPORT ReadinessHelper : public QObject { Q_OBJECT Q_DISABLE_COPY(ReadinessHelper) public: typedef void (*IntrospectFunc)(void *data); struct Introspectable { public: Introspectable(); Introspectable(const QSet &makesSenseForStatuses, const Features &dependsOnFeatures, const QStringList &dependsOnInterfaces, IntrospectFunc introspectFunc, void *introspectFuncData, bool critical = false); Introspectable(const Introspectable &other); ~Introspectable(); Introspectable &operator=(const Introspectable &other); private: friend class ReadinessHelper; struct Private; friend struct Private; QSharedDataPointer mPriv; }; typedef QMap Introspectables; ReadinessHelper(RefCounted *object, uint currentStatus = 0, const Introspectables &introspectables = Introspectables(), QObject *parent = 0); ReadinessHelper(DBusProxy *proxy, uint currentStatus = 0, const Introspectables &introspectables = Introspectables(), QObject *parent = 0); ~ReadinessHelper(); void addIntrospectables(const Introspectables &introspectables); uint currentStatus() const; void setCurrentStatus(uint currentStatus); void forceCurrentStatus(uint currentStatus); QStringList interfaces() const; void setInterfaces(const QStringList &interfaces); Features requestedFeatures() const; Features actualFeatures() const; Features missingFeatures() const; bool isReady(const Feature &feature, QString *errorName = 0, QString *errorMessage = 0) const; bool isReady(const Features &features, QString *errorName = 0, QString *errorMessage = 0) const; PendingReady *becomeReady(const Features &requestedFeatures); void setIntrospectCompleted(const Feature &feature, bool success, const QString &errorName = QString(), const QString &errorMessage = QString()); void setIntrospectCompleted(const Feature &feature, bool success, const QDBusError &error); Q_SIGNALS: void statusReady(uint status); private Q_SLOTS: TP_QT_NO_EXPORT void iterateIntrospection(); TP_QT_NO_EXPORT void onProxyInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage); private: struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/functors.h0000664000175000017500000002513312470405660017234 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_functors_h_HEADER_GUARD_ #define _TelepathyQt_functors_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include namespace Tp { struct TP_QT_EXPORT BaseFunctor { }; template struct PtrFunctor0 : public BaseFunctor { typedef R (*FunctionType)(); typedef R ResultType; PtrFunctor0(FunctionType fn) : fn(fn) {} ResultType operator()() const { return fn(); } FunctionType fn; }; template struct MemberFunctor0 : public BaseFunctor { typedef R (T::*FunctionType)(); typedef R ResultType; MemberFunctor0(T *object, FunctionType fn) : object(object), fn(fn) {} ResultType operator()() const { return (object->*(fn))(); } T *object; FunctionType fn; }; template struct PtrFunctor1 : public BaseFunctor { typedef R (*FunctionType)(Arg1); typedef R ResultType; PtrFunctor1(FunctionType fn) : fn(fn) {} ResultType operator()(Arg1 a1) const { return fn(a1); } FunctionType fn; }; template struct MemberFunctor1 : public BaseFunctor { typedef R (T::*FunctionType)(Arg1); typedef R ResultType; MemberFunctor1(T *object, FunctionType fn) : object(object), fn(fn) {} ResultType operator()(Arg1 a1) const { return (object->*(fn))(a1); } T *object; FunctionType fn; }; template struct PtrFunctor2 : public BaseFunctor { typedef R (*FunctionType)(Arg1, Arg2); typedef R ResultType; PtrFunctor2(FunctionType fn) : fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2) const { return fn(a1, a2); } FunctionType fn; }; template struct MemberFunctor2 : public BaseFunctor { typedef R (T::*FunctionType)(Arg1, Arg2); typedef R ResultType; MemberFunctor2(T *object, FunctionType fn) : object(object), fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2) const { return (object->*(fn))(a1, a2); } T *object; FunctionType fn; }; template struct PtrFunctor3 : public BaseFunctor { typedef R (*FunctionType)(Arg1, Arg2, Arg3); typedef R ResultType; PtrFunctor3(FunctionType fn) : fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3) const { return fn(a1, a2, a3); } FunctionType fn; }; template struct MemberFunctor3 : public BaseFunctor { typedef R (T::*FunctionType)(Arg1, Arg2, Arg3); typedef R ResultType; MemberFunctor3(T *object, FunctionType fn) : object(object), fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3) const { return (object->*(fn))(a1, a2, a3); } T *object; FunctionType fn; }; template struct PtrFunctor4 : public BaseFunctor { typedef R (*FunctionType)(Arg1, Arg2, Arg3, Arg4); typedef R ResultType; PtrFunctor4(FunctionType fn) : fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) const { return fn(a1, a2, a3, a4); } FunctionType fn; }; template struct MemberFunctor4 : public BaseFunctor { typedef R (T::*FunctionType)(Arg1, Arg2, Arg3, Arg4); typedef R ResultType; MemberFunctor4(T *object, FunctionType fn) : object(object), fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) const { return (object->*(fn))(a1, a2, a3, a4); } T *object; FunctionType fn; }; template struct PtrFunctor5 : public BaseFunctor { typedef R (*FunctionType)(Arg1, Arg2, Arg3, Arg4, Arg5); typedef R ResultType; PtrFunctor5(FunctionType fn) : fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) const { return fn(a1, a2, a3, a4, a5); } FunctionType fn; }; template struct MemberFunctor5 : public BaseFunctor { typedef R (T::*FunctionType)(Arg1, Arg2, Arg3, Arg4, Arg5); typedef R ResultType; MemberFunctor5(T *object, FunctionType fn) : object(object), fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) const { return (object->*(fn))(a1, a2, a3, a4, a5); } T *object; FunctionType fn; }; template struct PtrFunctor6 : public BaseFunctor { typedef R (*FunctionType)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); typedef R ResultType; PtrFunctor6(FunctionType fn) : fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) const { return fn(a1, a2, a3, a4, a5, a6); } FunctionType fn; }; template struct MemberFunctor6 : public BaseFunctor { typedef R (T::*FunctionType)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); typedef R ResultType; MemberFunctor6(T *object, FunctionType fn) : object(object), fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) const { return (object->*(fn))(a1, a2, a3, a4, a5, a6); } T *object; FunctionType fn; }; template struct PtrFunctor7 : public BaseFunctor { typedef R (*FunctionType)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7); typedef R ResultType; PtrFunctor7(FunctionType fn) : fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7) const { return fn(a1, a2, a3, a4, a5, a6, a7); } FunctionType fn; }; template struct MemberFunctor7 : public BaseFunctor { typedef R (T::*FunctionType)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7); typedef R ResultType; MemberFunctor7(T *object, FunctionType fn) : object(object), fn(fn) {} ResultType operator()(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7) const { return (object->*(fn))(a1, a2, a3, a4, a5, a6, a7); } T *object; FunctionType fn; }; // convenience methods // ptrFun template inline PtrFunctor0 ptrFun(R (*fn)() ) { return PtrFunctor0(fn); } template inline PtrFunctor1 ptrFun(R (*fn)(Arg1) ) { return PtrFunctor1(fn); } template inline PtrFunctor2 ptrFun(R (*fn)(Arg1, Arg2) ) { return PtrFunctor2(fn); } template inline PtrFunctor3 ptrFun(R (*fn)(Arg1, Arg2, Arg3) ) { return PtrFunctor3(fn); } template inline PtrFunctor4 ptrFun(R (*fn)(Arg1, Arg2, Arg3, Arg4) ) { return PtrFunctor4(fn); } template inline PtrFunctor5 ptrFun(R (*fn)(Arg1, Arg2, Arg3, Arg4, Arg5) ) { return PtrFunctor5(fn); } template inline PtrFunctor6 ptrFun(R (*fn)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) ) { return PtrFunctor6(fn); } template inline PtrFunctor7 ptrFun(R (*fn)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) ) { return PtrFunctor7(fn); } // memFun template inline MemberFunctor0 memFun(/**/ T *obj, R (T::*fn)() ) { return MemberFunctor0(obj, fn); } template inline MemberFunctor1 memFun(/**/ T *obj, R (T::*fn)(Arg1) ) { return MemberFunctor1(obj, fn); } template inline MemberFunctor2 memFun(/**/ T *obj, R (T::*fn)(Arg1, Arg2) ) { return MemberFunctor2(obj, fn); } template inline MemberFunctor3 memFun(/**/ T *obj, R (T::*fn)(Arg1, Arg2, Arg3) ) { return MemberFunctor3(obj, fn); } template inline MemberFunctor4 memFun(/**/ T *obj, R (T::*fn)(Arg1, Arg2, Arg3, Arg4) ) { return MemberFunctor4(obj, fn); } template inline MemberFunctor5 memFun(/**/ T *obj, R (T::*fn)(Arg1, Arg2, Arg3, Arg4, Arg5) ) { return MemberFunctor5(obj, fn); } template inline MemberFunctor6 memFun(/**/ T *obj, R (T::*fn)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) ) { return MemberFunctor6(obj, fn); } template inline MemberFunctor7 memFun(/**/ T *obj, R (T::*fn)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) ) { return MemberFunctor7(obj, fn); } } #endif telepathy-qt-0.9.6~git1/TelepathyQt/request-temporary-handler-internal.cpp0000664000175000017500000001056112470405660024660 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/request-temporary-handler-internal.h" #include "TelepathyQt/_gen/request-temporary-handler-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include namespace Tp { SharedPtr RequestTemporaryHandler::create(const AccountPtr &account) { return SharedPtr(new RequestTemporaryHandler(account)); } RequestTemporaryHandler::RequestTemporaryHandler(const AccountPtr &account) : AbstractClient(), QObject(), AbstractClientHandler(ChannelClassSpecList(), AbstractClientHandler::Capabilities(), false), mAccount(account), mQueueChannelReceived(true), dbusHandlerInvoked(false) { } RequestTemporaryHandler::~RequestTemporaryHandler() { } void RequestTemporaryHandler::handleChannels( const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const QList &requestsSatisfied, const QDateTime &userActionTime, const HandlerInfo &handlerInfo) { Q_ASSERT(dbusHandlerInvoked); QString errorMessage; ChannelPtr oldChannel = channel(); if (channels.size() != 1 || requestsSatisfied.size() != 1) { errorMessage = QLatin1String("Only one channel and one channel request should be given " "to HandleChannels"); } else if (account != mAccount) { errorMessage = QLatin1String("Account received is not the same as the account which made " "the request"); } else if (oldChannel && oldChannel != channels.first()) { errorMessage = QLatin1String("Received a channel that is not the same as the first " "one received"); } if (!errorMessage.isEmpty()) { warning() << "Handling channel failed with" << TP_QT_ERROR_SERVICE_CONFUSED << ":" << errorMessage; // Only emit error if we didn't receive any channel yet. if (!oldChannel) { emit error(TP_QT_ERROR_SERVICE_CONFUSED, errorMessage); } context->setFinishedWithError(TP_QT_ERROR_SERVICE_CONFUSED, errorMessage); return; } ChannelRequestPtr channelRequest = requestsSatisfied.first(); if (!oldChannel) { mChannel = WeakPtr(channels.first()); emit channelReceived(channel(), userActionTime, channelRequest->hints()); } else { if (mQueueChannelReceived) { mChannelReceivedQueue.enqueue(qMakePair(userActionTime, channelRequest->hints())); } else { emit channelReceived(oldChannel, userActionTime, channelRequest->hints()); } } context->setFinished(); } void RequestTemporaryHandler::setQueueChannelReceived(bool queue) { mQueueChannelReceived = queue; if (!queue) { processChannelReceivedQueue(); } } void RequestTemporaryHandler::setDBusHandlerInvoked() { dbusHandlerInvoked = true; } void RequestTemporaryHandler::setDBusHandlerErrored(const QString &errorName, const QString &errorMessage) { Q_ASSERT(dbusHandlerInvoked); if (!channel()) { emit error(errorName, errorMessage); } } void RequestTemporaryHandler::processChannelReceivedQueue() { while (!mChannelReceivedQueue.isEmpty()) { QPair info = mChannelReceivedQueue.dequeue(); emit channelReceived(channel(), info.first, info.second); } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/media-stream-handler.cpp0000664000175000017500000000212012470405660021676 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/cli-media-stream-handler-body.hpp" #include "TelepathyQt/_gen/cli-media-stream-handler.moc.hpp" telepathy-qt-0.9.6~git1/TelepathyQt/CallStream0000664000175000017500000000035512470405660017171 0ustar jrjr#ifndef _TelepathyQt_CallStream_HEADER_GUARD_ #define _TelepathyQt_CallStream_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/incoming-file-transfer-channel.h0000664000175000017500000000473212470405660023343 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_incoming_file_transfer_channel_h_HEADER_GUARD_ #define _TelepathyQt_incoming_file_transfer_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TP_QT_EXPORT IncomingFileTransferChannel : public FileTransferChannel { Q_OBJECT Q_DISABLE_COPY(IncomingFileTransferChannel) public: static const Feature FeatureCore; static IncomingFileTransferChannelPtr create(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties); virtual ~IncomingFileTransferChannel(); PendingOperation *setUri(const QString& uri); PendingOperation *acceptFile(qulonglong offset, QIODevice *output); Q_SIGNALS: void uriDefined(const QString &uri); protected: IncomingFileTransferChannel(const ConnectionPtr &connection, const QString &objectPath, const QVariantMap &immutableProperties, const Feature &coreFeature = IncomingFileTransferChannel::FeatureCore); private Q_SLOTS: TP_QT_NO_EXPORT void onAcceptFileFinished(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onSocketConnected(); TP_QT_NO_EXPORT void onSocketDisconnected(); TP_QT_NO_EXPORT void onSocketError(QAbstractSocket::SocketError error); TP_QT_NO_EXPORT void doTransfer(); private: TP_QT_NO_EXPORT void connectToHost(); TP_QT_NO_EXPORT void setFinished(); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/contact-capabilities.h0000664000175000017500000000402712470405660021452 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009-2010 Collabora Ltd. * @copyright Copyright (C) 2009-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_contact_capabilities_h_HEADER_GUARD_ #define _TelepathyQt_contact_capabilities_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { class TestBackdoors; class TP_QT_EXPORT ContactCapabilities : public CapabilitiesBase { public: ContactCapabilities(); virtual ~ContactCapabilities(); bool dbusTubes(const QString &serviceName) const; QStringList dbusTubeServices() const; bool streamTubes(const QString &service) const; QStringList streamTubeServices() const; // later: // bool dbusTubes(const QString &service) const; // QStringList dbusTubeServices() const; protected: friend class Contact; friend class TestBackdoors; ContactCapabilities(bool specificToContact); ContactCapabilities(const RequestableChannelClassList &rccs, bool specificToContact); ContactCapabilities(const RequestableChannelClassSpecList &rccSpecs, bool specificToContact); }; } // Tp Q_DECLARE_METATYPE(Tp::ContactCapabilities); #endif telepathy-qt-0.9.6~git1/TelepathyQt/BaseProtocolAddressingInterface0000664000175000017500000000043112470405660023356 0ustar jrjr#ifndef _TelepathyQt_BaseProtocolAddressingInterface_HEADER_GUARD_ #define _TelepathyQt_BaseProtocolAddressingInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel-dispatcher.xml0000664000175000017500000000130312470405660021467 0ustar jrjr Channel Dispatcher interface telepathy-qt-0.9.6~git1/TelepathyQt/AuthenticationTLSCertificateInterface0000664000175000017500000000044712470405660024472 0ustar jrjr#ifndef _TelepathyQt_AuthenticationTLSCertificateInterface_HEADER_GUARD_ #define _TelepathyQt_AuthenticationTLSCertificateInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/referenced-handles.cpp0000664000175000017500000002105512470405660021441 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2009 Collabora Ltd. * @copyright Copyright (C) 2008-2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/debug-internal.h" #include #include namespace Tp { struct TP_QT_NO_EXPORT ReferencedHandles::Private : public QSharedData { WeakPtr connection; HandleType handleType; UIntList handles; Private() { handleType = HandleTypeNone; } Private(const ConnectionPtr &conn, HandleType handleType, const UIntList &handles) : connection(conn), handleType(handleType), handles(handles) { Q_ASSERT(!conn.isNull()); Q_ASSERT(handleType != 0); foreach (uint handle, handles) { conn->refHandle(handleType, handle); } } Private(const Private &a) : QSharedData(a), connection(a.connection), handleType(a.handleType), handles(a.handles) { if (!handles.isEmpty()) { ConnectionPtr conn(connection); if (!conn) { debug() << " Destroyed after Connection, so the Connection " "has already released the handles"; return; } for (const_iterator i = handles.constBegin(); i != handles.constEnd(); ++i) { conn->refHandle(handleType, *i); } } } ~Private() { if (!handles.isEmpty()) { ConnectionPtr conn(connection); if (!conn) { debug() << " Destroyed after Connection, so the Connection " "has already released the handles"; return; } for (const_iterator i = handles.constBegin(); i != handles.constEnd(); ++i) { conn->unrefHandle(handleType, *i); } } } private: void operator=(const Private&); }; /** * \class ReferencedHandles * \ingroup clientconn * \headerfile TelepathyQt/referenced-handles.h * * \brief Helper container for safe management of handle lifetimes. Every handle * in a ReferencedHandles container is guaranteed to be valid (and stay valid, * as long it's in at least one ReferencedHandles container). * * The class offers a QList-style API. However, from the mutable operations, * only the operations for which the validity guarantees can be preserved are * provided. This means no functions which can add an arbitrary handle to the * container are included - the only way to add handles to the container is to * reference them using Connection::referenceHandles() and appending the * resulting ReferenceHandles instance. * * ReferencedHandles is a implicitly shared class. */ ReferencedHandles::ReferencedHandles() : mPriv(new Private) { } ReferencedHandles::ReferencedHandles(const ReferencedHandles &other) : mPriv(other.mPriv) { } ReferencedHandles::~ReferencedHandles() { } ConnectionPtr ReferencedHandles::connection() const { return ConnectionPtr(mPriv->connection); } HandleType ReferencedHandles::handleType() const { return mPriv->handleType; } uint ReferencedHandles::at(int i) const { return mPriv->handles[i]; } uint ReferencedHandles::value(int i, uint defaultValue) const { return mPriv->handles.value(i, defaultValue); } ReferencedHandles::const_iterator ReferencedHandles::begin() const { return mPriv->handles.begin(); } ReferencedHandles::const_iterator ReferencedHandles::end() const { return mPriv->handles.end(); } bool ReferencedHandles::contains(uint handle) const { return mPriv->handles.contains(handle); } int ReferencedHandles::count(uint handle) const { return mPriv->handles.count(handle); } int ReferencedHandles::indexOf(uint handle, int from) const { return mPriv->handles.indexOf(handle, from); } bool ReferencedHandles::isEmpty() const { return mPriv->handles.isEmpty(); } int ReferencedHandles::lastIndexOf(uint handle, int from) const { return mPriv->handles.lastIndexOf(handle, from); } ReferencedHandles ReferencedHandles::mid(int pos, int length) const { return ReferencedHandles(connection(), handleType(), mPriv->handles.mid(pos, length)); } int ReferencedHandles::size() const { return mPriv->handles.size(); } void ReferencedHandles::clear() { if (!mPriv->handles.empty()) { ConnectionPtr conn(mPriv->connection); if (conn) { foreach (uint handle, mPriv->handles) { conn->unrefHandle(handleType(), handle); } } else { warning() << "Connection already destroyed in " "ReferencedHandles::clear() so can't unref!"; } } mPriv->handles.clear(); } void ReferencedHandles::move(int from, int to) { mPriv->handles.move(from, to); } int ReferencedHandles::removeAll(uint handle) { int count = mPriv->handles.removeAll(handle); if (count > 0) { ConnectionPtr conn(mPriv->connection); if (conn) { for (int i = 0; i < count; ++i) { conn->unrefHandle(handleType(), handle); } } else { warning() << "Connection already destroyed in " "ReferencedHandles::removeAll() with handle ==" << handle << "so can't unref!"; } } return count; } void ReferencedHandles::removeAt(int i) { ConnectionPtr conn(mPriv->connection); if (conn) { conn->unrefHandle(handleType(), at(i)); } else { warning() << "Connection already destroyed in " "ReferencedHandles::removeAt() with i ==" << i << "so can't unref!"; } mPriv->handles.removeAt(i); } bool ReferencedHandles::removeOne(uint handle) { bool wasThere = mPriv->handles.removeOne(handle); if (wasThere) { ConnectionPtr conn(mPriv->connection); if (conn) { conn->unrefHandle(handleType(), handle); } else { warning() << "Connection already destroyed in " "ReferencedHandles::removeOne() with handle ==" << handle << "so can't unref!"; } } return wasThere; } void ReferencedHandles::swap(int i, int j) { mPriv->handles.swap(i, j); } uint ReferencedHandles::takeAt(int i) { ConnectionPtr conn(mPriv->connection); if (conn) { conn->unrefHandle(handleType(), at(i)); } else { warning() << "Connection already destroyed in " "ReferencedHandles::takeAt() with i ==" << i << "so can't unref!"; } return mPriv->handles.takeAt(i); } ReferencedHandles ReferencedHandles::operator+(const ReferencedHandles &another) const { if (connection() != another.connection() || handleType() != another.handleType()) { warning() << "Tried to concatenate ReferencedHandles instances " "with different connection and/or handle type"; return *this; } return ReferencedHandles(connection(), handleType(), mPriv->handles + another.mPriv->handles); } ReferencedHandles &ReferencedHandles::operator=( const ReferencedHandles &another) { mPriv = another.mPriv; return *this; } bool ReferencedHandles::operator==(const ReferencedHandles &another) const { return connection() == another.connection() && handleType() == another.handleType() && mPriv->handles == another.mPriv->handles; } bool ReferencedHandles::operator==(const UIntList &list) const { return mPriv->handles == list; } UIntList ReferencedHandles::toList() const { return mPriv->handles; } ReferencedHandles::ReferencedHandles(const ConnectionPtr &connection, HandleType handleType, const UIntList &handles) : mPriv(new Private(connection, handleType, handles)) { } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/account-factory.cpp0000664000175000017500000001406712470405660021031 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/account-factory.moc.hpp" #include namespace Tp { /** * \class AccountFactory * \ingroup utils * \headerfile TelepathyQt/account-factory.h * * \brief The AccountFactory class is responsible for constructing Account * objects according to application-defined settings. * * The class is used by AccountManager and other classes which construct Account * proxy instances to enable sharing instances of application-defined Account * subclasses with certain features always ready. */ /** * Create a new AccountFactory object. * * Optionally, the \a features to make ready on all constructed proxies can be specified. The * default is to make no features ready. It should be noted that unlike Account::becomeReady(), * FeatureCore isn't assumed. If no features are specified, which is the default behavior, no * Account::becomeReady() call is made at all and the proxy won't be Account::isReady(). * * \param bus The QDBusConnection for proxies constructed using this factory to use. * \param features The features to make ready on constructed Accounts. * \return An AccountFactoryPtr object pointing to the newly created * AccountFactory object. */ AccountFactoryPtr AccountFactory::create(const QDBusConnection &bus, const Features &features) { return AccountFactoryPtr(new AccountFactory(bus, features)); } /** * Construct a new AccountFactory object. * * As in create(), it should be noted that unlike Account::becomeReady(), FeatureCore isn't assumed. * If no \a features are specified, no Account::becomeReady() call is made at all and the proxy * won't be Account::isReady(). * * \param bus The QDBusConnection for proxies constructed using this factory to use. * \param features The features to make ready on constructed Accounts. */ AccountFactory::AccountFactory(const QDBusConnection &bus, const Features &features) : FixedFeatureFactory(bus) { addFeatures(features); } /** * Class destructor. */ AccountFactory::~AccountFactory() { } /** * Constructs an Account proxy and begins making it ready. * * If a valid proxy already exists in the factory cache for the given combination of \a busName and * \a objectPath, it is returned instead. All newly created proxies are automatically cached until * they're either DBusProxy::invalidated() or the last reference to them outside the factory has * been dropped. * * The proxy can be accessed immediately after this function returns using PendingReady::proxy(). * The ready operation only finishes, however, when the features specified by features(), if any, * are made ready as much as possible. If the service doesn't support a given feature, they won't * obviously be ready even if the operation finished successfully, as is the case for * Account::becomeReady(). * * \param busName The bus/service name of the D-Bus account object the proxy is constructed for. * (Usually #TP_QT_ACCOUNT_MANAGER_BUS_NAME). * \param objectPath The object path of the account. * \param connFactory The connection factory to use for the Account. * \param chanFactory The channel factory to use for the Account. * \param contactFactory The channel factory to use for the Account. * \return A PendingReady operation with the proxy in PendingReady::proxy(). */ PendingReady *AccountFactory::proxy(const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const { DBusProxyPtr proxy = cachedProxy(busName, objectPath); if (proxy.isNull()) { proxy = construct(busName, objectPath, connFactory, chanFactory, contactFactory); } return nowHaveProxy(proxy); } /** * Can be used by subclasses to override the Account subclass constructed by the factory. * * This is automatically called by proxy() to construct proxy instances if no valid cached proxy is * found. * * The default implementation constructs Tp::Account objects. * * \param busName The bus/service name of the D-Bus account object the proxy is constructed for. * (Usually #TP_QT_ACCOUNT_MANAGER_BUS_NAME). * \param objectPath The object path of the account. * \param connFactory The connection factory to use for the Account. * \param chanFactory The channel factory to use for the Account. * \param contactFactory The channel factory to use for the Account. * \return A pointer to the constructed Account object. */ AccountPtr AccountFactory::construct(const QString &busName, const QString &objectPath, const ConnectionFactoryConstPtr &connFactory, const ChannelFactoryConstPtr &chanFactory, const ContactFactoryConstPtr &contactFactory) const { return Account::create(dbusConnection(), busName, objectPath, connFactory, chanFactory, contactFactory); } /** * Identity transform, as is appropriate for Account objects. * * \param uniqueOrWellKnown The name to transform. * \return \a uniqueOrWellKnown */ QString AccountFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const { return uniqueOrWellKnown; } } telepathy-qt-0.9.6~git1/TelepathyQt/contact-manager-roster.cpp0000664000175000017500000023031212470405660022300 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/contact-manager-internal.h" #include "TelepathyQt/_gen/contact-manager-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include #include #include namespace Tp { ContactManager::Roster::Roster(ContactManager *contactManager) : QObject(), contactManager(contactManager), usingFallbackContactList(false), hasContactBlockingInterface(false), introspectPendingOp(0), introspectGroupsPendingOp(0), pendingContactListState((uint) -1), contactListState((uint) -1), canReportAbusive(false), gotContactBlockingInitialBlockedContacts(false), canChangeContactList(false), contactListRequestUsesMessage(false), gotContactListInitialContacts(false), gotContactListContactsChangedWithId(false), groupsReintrospectionRequired(false), contactListGroupPropertiesReceived(false), processingContactListChanges(false), contactListChannelsReady(0), featureContactListGroupsTodo(0), groupsSetSuccess(false) { } ContactManager::Roster::~Roster() { } ContactListState ContactManager::Roster::state() const { return (Tp::ContactListState) contactListState; } PendingOperation *ContactManager::Roster::introspect() { ConnectionPtr conn(contactManager->connection()); if (conn->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST)) { debug() << "Connection.ContactList found, using it"; usingFallbackContactList = false; if (conn->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_BLOCKING)) { debug() << "Connection.ContactBlocking found. using it"; hasContactBlockingInterface = true; introspectContactBlocking(); } else { debug() << "Connection.ContactBlocking not found, falling back " "to contact list deny channel"; debug() << "Requesting handle for deny channel"; contactListChannels.insert(ChannelInfo::TypeDeny, ChannelInfo(ChannelInfo::TypeDeny)); PendingHandles *ph = conn->lowlevel()->requestHandles(HandleTypeList, QStringList() << ChannelInfo::identifierForType( ChannelInfo::TypeDeny)); connect(ph, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotContactListChannelHandle(Tp::PendingOperation*))); } } else { debug() << "Connection.ContactList not found, falling back to contact list channels"; usingFallbackContactList = true; for (uint i = 0; i < ChannelInfo::LastType; ++i) { QString channelId = ChannelInfo::identifierForType( (ChannelInfo::Type) i); debug() << "Requesting handle for" << channelId << "channel"; contactListChannels.insert(i, ChannelInfo((ChannelInfo::Type) i)); PendingHandles *ph = conn->lowlevel()->requestHandles(HandleTypeList, QStringList() << channelId); connect(ph, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotContactListChannelHandle(Tp::PendingOperation*))); } } Q_ASSERT(!introspectPendingOp); introspectPendingOp = new PendingOperation(conn); return introspectPendingOp; } PendingOperation *ContactManager::Roster::introspectGroups() { ConnectionPtr conn(contactManager->connection()); Q_ASSERT(!introspectGroupsPendingOp); if (conn->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST)) { if (!conn->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS)) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Roster groups not supported"), conn); } debug() << "Connection.ContactGroups found, using it"; if (!gotContactListInitialContacts) { debug() << "Initial ContactList contacts not retrieved. Postponing introspection"; groupsReintrospectionRequired = true; return new PendingSuccess(conn); } Client::ConnectionInterfaceContactGroupsInterface *iface = conn->interface(); connect(iface, SIGNAL(GroupsChanged(Tp::UIntList,QStringList,QStringList)), SLOT(onContactListGroupsChanged(Tp::UIntList,QStringList,QStringList))); connect(iface, SIGNAL(GroupsCreated(QStringList)), SLOT(onContactListGroupsCreated(QStringList))); connect(iface, SIGNAL(GroupRenamed(QString,QString)), SLOT(onContactListGroupRenamed(QString,QString))); connect(iface, SIGNAL(GroupsRemoved(QStringList)), SLOT(onContactListGroupsRemoved(QStringList))); PendingVariantMap *pvm = iface->requestAllProperties(); connect(pvm, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotContactListGroupsProperties(Tp::PendingOperation*))); } else { debug() << "Connection.ContactGroups not found, falling back to contact list group channels"; ++featureContactListGroupsTodo; // decremented in gotChannels // we already checked if requests interface exists, so bypass requests // interface checking Client::ConnectionInterfaceRequestsInterface *iface = conn->interface(); debug() << "Connecting to Requests.NewChannels"; connect(iface, SIGNAL(NewChannels(Tp::ChannelDetailsList)), SLOT(onNewChannels(Tp::ChannelDetailsList))); debug() << "Retrieving channels"; Client::DBus::PropertiesInterface *properties = contactManager->connection()->interface(); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( properties->Get( TP_QT_IFACE_CONNECTION_INTERFACE_REQUESTS, QLatin1String("Channels")), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotChannels(QDBusPendingCallWatcher*))); } if (groupsReintrospectionRequired) { return NULL; } Q_ASSERT(!introspectGroupsPendingOp); introspectGroupsPendingOp = new PendingOperation(conn); return introspectGroupsPendingOp; } void ContactManager::Roster::reset() { contactListChannels.clear(); subscribeChannel.reset(); publishChannel.reset(); storedChannel.reset(); denyChannel.reset(); contactListGroupChannels.clear(); removedContactListGroupChannels.clear(); } Contacts ContactManager::Roster::allKnownContacts() const { return cachedAllKnownContacts; } QStringList ContactManager::Roster::allKnownGroups() const { if (usingFallbackContactList) { return contactListGroupChannels.keys(); } return cachedAllKnownGroups.toList(); } PendingOperation *ContactManager::Roster::addGroup(const QString &group) { ConnectionPtr conn(contactManager->connection()); if (usingFallbackContactList) { QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_LIST); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) Tp::HandleTypeGroup); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID"), group); return conn->lowlevel()->ensureChannel(request); } if (!conn->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS)) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented"), conn); } Client::ConnectionInterfaceContactGroupsInterface *iface = conn->interface(); Q_ASSERT(iface); return queuedFinishVoid(iface->AddToGroup(group, UIntList())); } PendingOperation *ContactManager::Roster::removeGroup(const QString &group) { ConnectionPtr conn(contactManager->connection()); if (usingFallbackContactList) { if (!contactListGroupChannels.contains(group)) { return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid group"), conn); } ChannelPtr channel = contactListGroupChannels[group]; return new RemoveGroupOp(channel); } if (!conn->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS)) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented"), conn); } Client::ConnectionInterfaceContactGroupsInterface *iface = conn->interface(); Q_ASSERT(iface); return queuedFinishVoid(iface->RemoveGroup(group)); } Contacts ContactManager::Roster::groupContacts(const QString &group) const { if (usingFallbackContactList) { if (!contactListGroupChannels.contains(group)) { return Contacts(); } ChannelPtr channel = contactListGroupChannels[group]; return channel->groupContacts(); } Contacts ret; foreach (const ContactPtr &contact, allKnownContacts()) { if (contact->groups().contains(group)) ret << contact; } return ret; } PendingOperation *ContactManager::Roster::addContactsToGroup(const QString &group, const QList &contacts) { ConnectionPtr conn(contactManager->connection()); if (usingFallbackContactList) { if (!contactListGroupChannels.contains(group)) { return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid group"), conn); } ChannelPtr channel = contactListGroupChannels[group]; return channel->groupAddContacts(contacts); } if (!conn->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS)) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented"), conn); } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } Client::ConnectionInterfaceContactGroupsInterface *iface = conn->interface(); Q_ASSERT(iface); return queuedFinishVoid(iface->AddToGroup(group, handles)); } PendingOperation *ContactManager::Roster::removeContactsFromGroup(const QString &group, const QList &contacts) { ConnectionPtr conn(contactManager->connection()); if (usingFallbackContactList) { if (!contactListGroupChannels.contains(group)) { return new PendingFailure(TP_QT_ERROR_INVALID_ARGUMENT, QLatin1String("Invalid group"), conn); } ChannelPtr channel = contactListGroupChannels[group]; return channel->groupRemoveContacts(contacts); } if (!conn->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS)) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented"), conn); } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } Client::ConnectionInterfaceContactGroupsInterface *iface = conn->interface(); Q_ASSERT(iface); return queuedFinishVoid(iface->RemoveFromGroup(group, handles)); } bool ContactManager::Roster::canRequestPresenceSubscription() const { if (usingFallbackContactList) { return subscribeChannel && subscribeChannel->groupCanAddContacts(); } return canChangeContactList; } bool ContactManager::Roster::subscriptionRequestHasMessage() const { if (usingFallbackContactList) { return subscribeChannel && (subscribeChannel->groupFlags() & ChannelGroupFlagMessageAdd); } return contactListRequestUsesMessage; } PendingOperation *ContactManager::Roster::requestPresenceSubscription( const QList &contacts, const QString &message) { ConnectionPtr conn(contactManager->connection()); if (usingFallbackContactList) { if (!subscribeChannel) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Cannot subscribe to contacts' presence on this protocol"), conn); } return subscribeChannel->groupAddContacts(contacts, message); } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } Client::ConnectionInterfaceContactListInterface *iface = conn->interface(); Q_ASSERT(iface); return queuedFinishVoid(iface->RequestSubscription(handles, message)); } bool ContactManager::Roster::canRemovePresenceSubscription() const { if (usingFallbackContactList) { return subscribeChannel && subscribeChannel->groupCanRemoveContacts(); } return canChangeContactList; } bool ContactManager::Roster::subscriptionRemovalHasMessage() const { if (usingFallbackContactList) { return subscribeChannel && (subscribeChannel->groupFlags() & ChannelGroupFlagMessageRemove); } return false; } bool ContactManager::Roster::canRescindPresenceSubscriptionRequest() const { if (usingFallbackContactList) { return subscribeChannel && subscribeChannel->groupCanRescindContacts(); } return canChangeContactList; } bool ContactManager::Roster::subscriptionRescindingHasMessage() const { if (usingFallbackContactList) { return subscribeChannel && (subscribeChannel->groupFlags() & ChannelGroupFlagMessageRescind); } return false; } PendingOperation *ContactManager::Roster::removePresenceSubscription( const QList &contacts, const QString &message) { ConnectionPtr conn(contactManager->connection()); if (usingFallbackContactList) { if (!subscribeChannel) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Cannot subscribe to contacts' presence on this protocol"), conn); } return subscribeChannel->groupRemoveContacts(contacts, message); } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } Client::ConnectionInterfaceContactListInterface *iface = conn->interface(); Q_ASSERT(iface); return queuedFinishVoid(iface->Unsubscribe(handles)); } bool ContactManager::Roster::canAuthorizePresencePublication() const { if (usingFallbackContactList) { // do not check for Channel::groupCanAddContacts as all contacts in local // pending can be added, even if the Channel::groupFlags() does not contain // the flag CanAdd return (bool) publishChannel; } return canChangeContactList; } bool ContactManager::Roster::publicationAuthorizationHasMessage() const { if (usingFallbackContactList) { return subscribeChannel && (subscribeChannel->groupFlags() & ChannelGroupFlagMessageAccept); } return false; } PendingOperation *ContactManager::Roster::authorizePresencePublication( const QList &contacts, const QString &message) { ConnectionPtr conn(contactManager->connection()); if (usingFallbackContactList) { if (!publishChannel) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Cannot control publication of presence on this protocol"), conn); } return publishChannel->groupAddContacts(contacts, message); } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } Client::ConnectionInterfaceContactListInterface *iface = conn->interface(); Q_ASSERT(iface); return queuedFinishVoid(iface->AuthorizePublication(handles)); } bool ContactManager::Roster::publicationRejectionHasMessage() const { if (usingFallbackContactList) { return subscribeChannel && (subscribeChannel->groupFlags() & ChannelGroupFlagMessageReject); } return false; } bool ContactManager::Roster::canRemovePresencePublication() const { if (usingFallbackContactList) { return publishChannel && publishChannel->groupCanRemoveContacts(); } return canChangeContactList; } bool ContactManager::Roster::publicationRemovalHasMessage() const { if (usingFallbackContactList) { return subscribeChannel && (subscribeChannel->groupFlags() & ChannelGroupFlagMessageRemove); } return false; } PendingOperation *ContactManager::Roster::removePresencePublication( const QList &contacts, const QString &message) { ConnectionPtr conn(contactManager->connection()); if (usingFallbackContactList) { if (!publishChannel) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Cannot control publication of presence on this protocol"), conn); } return publishChannel->groupRemoveContacts(contacts, message); } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } Client::ConnectionInterfaceContactListInterface *iface = conn->interface(); Q_ASSERT(iface); return queuedFinishVoid(iface->Unpublish(handles)); } PendingOperation *ContactManager::Roster::removeContacts( const QList &contacts, const QString &message) { ConnectionPtr conn(contactManager->connection()); if (usingFallbackContactList) { /* If the CM implements stored channel correctly, it should have the * wanted behaviour. Otherwise we have to to remove from publish * and subscribe channels. */ if (storedChannel && storedChannel->groupCanRemoveContacts()) { debug() << "Removing contacts from stored list"; return storedChannel->groupRemoveContacts(contacts, message); } QList operations; if (canRemovePresenceSubscription()) { debug() << "Removing contacts from subscribe list"; operations << removePresenceSubscription(contacts, message); } if (canRemovePresencePublication()) { debug() << "Removing contacts from publish list"; operations << removePresencePublication(contacts, message); } if (operations.isEmpty()) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Cannot remove contacts on this protocol"), conn); } return new PendingComposite(operations, conn); } UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } Client::ConnectionInterfaceContactListInterface *iface = conn->interface(); Q_ASSERT(iface); return queuedFinishVoid(iface->RemoveContacts(handles)); } bool ContactManager::Roster::canBlockContacts() const { if (!usingFallbackContactList && hasContactBlockingInterface) { return true; } else { return (bool) denyChannel; } } bool ContactManager::Roster::canReportAbuse() const { return canReportAbusive; } PendingOperation *ContactManager::Roster::blockContacts( const QList &contacts, bool value, bool reportAbuse) { if (!contactManager->connection()->isValid()) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection is invalid"), contactManager->connection()); } else if (!contactManager->connection()->isReady(Connection::FeatureRoster)) { return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String("Connection::FeatureRoster is not ready"), contactManager->connection()); } if (!usingFallbackContactList && hasContactBlockingInterface) { ConnectionPtr conn(contactManager->connection()); Client::ConnectionInterfaceContactBlockingInterface *iface = conn->interface(); UIntList handles; foreach (const ContactPtr &contact, contacts) { handles << contact->handle()[0]; } Q_ASSERT(iface); if(value) { return queuedFinishVoid(iface->BlockContacts(handles, reportAbuse)); } else { return queuedFinishVoid(iface->UnblockContacts(handles)); } } else { ConnectionPtr conn(contactManager->connection()); if (!denyChannel) { return new PendingFailure(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Cannot block contacts on this protocol"), conn); } if (value) { return denyChannel->groupAddContacts(contacts); } else { return denyChannel->groupRemoveContacts(contacts); } } } void ContactManager::Roster::gotContactBlockingCapabilities(PendingOperation *op) { if (op->isError()) { warning() << "Getting ContactBlockingCapabilities property failed with" << op->errorName() << ":" << op->errorMessage(); introspectContactList(); return; } debug() << "Got ContactBlockingCapabilities property"; PendingVariant *pv = qobject_cast(op); uint contactBlockingCaps = pv->result().toUInt(); canReportAbusive = contactBlockingCaps & ContactBlockingCapabilityCanReportAbusive; introspectContactBlockingBlockedContacts(); } void ContactManager::Roster::gotContactBlockingBlockedContacts( QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (watcher->isError()) { warning() << "Getting initial ContactBlocking blocked " "contacts failed with" << watcher->error().name() << ":" << watcher->error().message(); introspectContactList(); return; } debug() << "Got initial ContactBlocking blocked contacts"; gotContactBlockingInitialBlockedContacts = true; ConnectionPtr conn(contactManager->connection()); HandleIdentifierMap contactIds = reply.value(); if (!contactIds.isEmpty()) { conn->lowlevel()->injectContactIds(contactIds); //fake change event where all the contacts are added contactListBlockedContactsChangedQueue.enqueue( BlockedContactsChangedInfo(contactIds, HandleIdentifierMap(), true)); contactListChangesQueue.enqueue( &ContactManager::Roster::processContactListBlockedContactsChanged); processContactListChanges(); } else { introspectContactList(); } } void ContactManager::Roster::onContactBlockingBlockedContactsChanged( const HandleIdentifierMap &added, const HandleIdentifierMap &removed) { if (!gotContactBlockingInitialBlockedContacts) { return; } ConnectionPtr conn(contactManager->connection()); conn->lowlevel()->injectContactIds(added); conn->lowlevel()->injectContactIds(removed); contactListBlockedContactsChangedQueue.enqueue( BlockedContactsChangedInfo(added, removed)); contactListChangesQueue.enqueue( &ContactManager::Roster::processContactListBlockedContactsChanged); processContactListChanges(); } void ContactManager::Roster::gotContactListProperties(PendingOperation *op) { if (op->isError()) { // We may have been in state Failure and then Success, and FeatureRoster is already ready if (introspectPendingOp) { introspectPendingOp->setFinishedWithError( op->errorName(), op->errorMessage()); introspectPendingOp = 0; } return; } debug() << "Got ContactList properties"; PendingVariantMap *pvm = qobject_cast(op); QVariantMap props = pvm->result(); canChangeContactList = qdbus_cast(props[QLatin1String("CanChangeContactList")]); contactListRequestUsesMessage = qdbus_cast(props[QLatin1String("RequestUsesMessage")]); // only update the status if we did not get it from ContactListStateChanged if (pendingContactListState == (uint) -1) { uint state = qdbus_cast(props[QLatin1String("ContactListState")]); onContactListStateChanged(state); } } void ContactManager::Roster::gotContactListContacts(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (watcher->isError()) { warning() << "Failed introspecting ContactList contacts"; contactListState = ContactListStateFailure; debug() << "Setting state to failure"; emit contactManager->stateChanged((Tp::ContactListState) contactListState); // We may have been in state Failure and then Success, and FeatureRoster is already ready if (introspectPendingOp) { introspectPendingOp->setFinishedWithError( reply.error()); introspectPendingOp = 0; } return; } debug() << "Got initial ContactList contacts"; gotContactListInitialContacts = true; ConnectionPtr conn(contactManager->connection()); ContactAttributesMap attrsMap = reply.value(); ContactAttributesMap::const_iterator begin = attrsMap.constBegin(); ContactAttributesMap::const_iterator end = attrsMap.constEnd(); for (ContactAttributesMap::const_iterator i = begin; i != end; ++i) { uint bareHandle = i.key(); QVariantMap attrs = i.value(); ContactPtr contact = contactManager->ensureContact(ReferencedHandles(conn, HandleTypeContact, UIntList() << bareHandle), conn->contactFactory()->features(), attrs); cachedAllKnownContacts.insert(contact); contactListContacts.insert(contact); } if (contactManager->connection()->requestedFeatures().contains( Connection::FeatureRosterGroups)) { groupsSetSuccess = true; } // We may have been in state Failure and then Success, and FeatureRoster is already ready // In any case, if we're going to reintrospect Groups, we only advance to state success once // that is finished. We connect to the op finishing already here to catch all the failure finish // cases as well. if (introspectPendingOp) { if (!groupsSetSuccess) { // Will emit stateChanged() signal when the op is finished in idle // callback. This is to ensure FeatureRoster (and Groups) is marked ready. connect(introspectPendingOp, SIGNAL(finished(Tp::PendingOperation *)), SLOT(setStateSuccess())); } introspectPendingOp->setFinished(); introspectPendingOp = 0; } else if (!groupsSetSuccess) { setStateSuccess(); } else { // Verify that Groups is actually going to set the state // As far as I can see, this will always be the case. Q_ASSERT(groupsReintrospectionRequired); } if (groupsReintrospectionRequired) { introspectGroups(); } } void ContactManager::Roster::setStateSuccess() { if (contactManager->connection()->isValid()) { debug() << "State is now success"; contactListState = ContactListStateSuccess; emit contactManager->stateChanged((Tp::ContactListState) contactListState); } } void ContactManager::Roster::onContactListStateChanged(uint state) { if (pendingContactListState == state) { // ignore redundant state changes return; } pendingContactListState = state; if (state == ContactListStateSuccess) { introspectContactListContacts(); return; } contactListState = state; if (state == ContactListStateFailure) { debug() << "State changed to failure, finishing roster introspection"; } emit contactManager->stateChanged((Tp::ContactListState) state); if (state == ContactListStateFailure) { // Consider it done here as the state may go from Failure to Success afterwards, in which // case the contacts will appear. Q_ASSERT(introspectPendingOp); introspectPendingOp->setFinished(); introspectPendingOp = 0; } } void ContactManager::Roster::onContactListContactsChangedWithId(const Tp::ContactSubscriptionMap &changes, const Tp::HandleIdentifierMap &ids, const Tp::HandleIdentifierMap &removals) { debug() << "Got ContactList.ContactsChangedWithID with" << changes.size() << "changes and" << removals.size() << "removals"; gotContactListContactsChangedWithId = true; if (!gotContactListInitialContacts) { debug() << "Ignoring ContactList changes until initial contacts are retrieved"; return; } ConnectionPtr conn(contactManager->connection()); conn->lowlevel()->injectContactIds(ids); contactListUpdatesQueue.enqueue(UpdateInfo(changes, ids, removals)); contactListChangesQueue.enqueue(&ContactManager::Roster::processContactListUpdates); processContactListChanges(); } void ContactManager::Roster::onContactListContactsChanged(const Tp::ContactSubscriptionMap &changes, const Tp::UIntList &removals) { if (gotContactListContactsChangedWithId) { return; } debug() << "Got ContactList.ContactsChanged with" << changes.size() << "changes and" << removals.size() << "removals"; if (!gotContactListInitialContacts) { debug() << "Ignoring ContactList changes until initial contacts are retrieved"; return; } HandleIdentifierMap removalsMap; foreach (uint handle, removals) { removalsMap.insert(handle, QString()); } contactListUpdatesQueue.enqueue(UpdateInfo(changes, HandleIdentifierMap(), removalsMap)); contactListChangesQueue.enqueue(&ContactManager::Roster::processContactListUpdates); processContactListChanges(); } void ContactManager::Roster::onContactListBlockedContactsConstructed(Tp::PendingOperation *op) { BlockedContactsChangedInfo info = contactListBlockedContactsChangedQueue.dequeue(); if (op->isError()) { if (info.continueIntrospectionWhenFinished) { introspectContactList(); } processingContactListChanges = false; processContactListChanges(); return; } Contacts newBlockedContacts; Contacts unblockedContacts; HandleIdentifierMap::const_iterator begin = info.added.constBegin(); HandleIdentifierMap::const_iterator end = info.added.constEnd(); for (HandleIdentifierMap::const_iterator i = begin; i != end; ++i) { uint bareHandle = i.key(); ContactPtr contact = contactManager->lookupContactByHandle(bareHandle); if (!contact) { warning() << "Unable to construct contact for handle" << bareHandle; continue; } debug() << "Contact" << contact->id() << "is now blocked"; blockedContacts.insert(contact); newBlockedContacts.insert(contact); contact->setBlocked(true); } begin = info.removed.constBegin(); end = info.removed.constEnd(); for (HandleIdentifierMap::const_iterator i = begin; i != end; ++i) { uint bareHandle = i.key(); ContactPtr contact = contactManager->lookupContactByHandle(bareHandle); if (!contact) { warning() << "Unable to construct contact for handle" << bareHandle; continue; } debug() << "Contact" << contact->id() << "is now unblocked"; blockedContacts.remove(contact); unblockedContacts.insert(contact); contact->setBlocked(false); } // Perform the needed computation for allKnownContactsChanged computeKnownContactsChanges(newBlockedContacts, Contacts(), Contacts(), unblockedContacts, Channel::GroupMemberChangeDetails()); if (info.continueIntrospectionWhenFinished) { introspectContactList(); } processingContactListChanges = false; processContactListChanges(); } void ContactManager::Roster::onContactListNewContactsConstructed(Tp::PendingOperation *op) { if (op->isError()) { contactListUpdatesQueue.dequeue(); processingContactListChanges = false; processContactListChanges(); return; } UpdateInfo info = contactListUpdatesQueue.dequeue(); Tp::Contacts added; Tp::Contacts removed; Tp::Contacts publishRequested; ContactSubscriptionMap::const_iterator begin = info.changes.constBegin(); ContactSubscriptionMap::const_iterator end = info.changes.constEnd(); for (ContactSubscriptionMap::const_iterator i = begin; i != end; ++i) { uint bareHandle = i.key(); ContactSubscriptions subscriptions = i.value(); ContactPtr contact = contactManager->lookupContactByHandle(bareHandle); if (!contact) { warning() << "Unable to construct contact for handle" << bareHandle; continue; } contactListContacts.insert(contact); added << contact; Contact::PresenceState oldContactPublishState = contact->publishState(); QString oldContactPublishStateMessage = contact->publishStateMessage(); contact->setSubscriptionState((SubscriptionState) subscriptions.subscribe); contact->setPublishState((SubscriptionState) subscriptions.publish, subscriptions.publishRequest); if (subscriptions.publish == SubscriptionStateAsk && (oldContactPublishState != Contact::PresenceStateAsk || oldContactPublishStateMessage != contact->publishStateMessage())) { Channel::GroupMemberChangeDetails publishRequestDetails; QVariantMap detailsMap; detailsMap.insert(QLatin1String("message"), subscriptions.publishRequest); publishRequestDetails = Channel::GroupMemberChangeDetails(ContactPtr(), detailsMap); publishRequested.insert(contact); } } if (!publishRequested.empty()) { emit contactManager->presencePublicationRequested(publishRequested); } foreach (uint bareHandle, info.removals.keys()) { ContactPtr contact = contactManager->lookupContactByHandle(bareHandle); if (!contact) { warning() << "Unable to find removed contact with handle" << bareHandle; continue; } if (!contactListContacts.contains(contact)) { warning() << "Contact" << contact->id() << "removed from ContactList " "but it wasn't present, ignoring."; continue; } contactListContacts.remove(contact); removed << contact; } computeKnownContactsChanges(added, Contacts(), Contacts(), removed, Channel::GroupMemberChangeDetails()); foreach (const Tp::ContactPtr &contact, removed) { contact->setSubscriptionState(SubscriptionStateNo); contact->setPublishState(SubscriptionStateNo); } processingContactListChanges = false; processContactListChanges(); } void ContactManager::Roster::onContactListGroupsChanged(const Tp::UIntList &contacts, const QStringList &added, const QStringList &removed) { Q_ASSERT(usingFallbackContactList == false); if (!contactListGroupPropertiesReceived) { return; } contactListGroupsUpdatesQueue.enqueue(GroupsUpdateInfo(contacts, added, removed)); contactListChangesQueue.enqueue(&ContactManager::Roster::processContactListGroupsUpdates); processContactListChanges(); } void ContactManager::Roster::onContactListGroupsCreated(const QStringList &names) { Q_ASSERT(usingFallbackContactList == false); if (!contactListGroupPropertiesReceived) { return; } contactListGroupsCreatedQueue.enqueue(names); contactListChangesQueue.enqueue(&ContactManager::Roster::processContactListGroupsCreated); processContactListChanges(); } void ContactManager::Roster::onContactListGroupRenamed(const QString &oldName, const QString &newName) { Q_ASSERT(usingFallbackContactList == false); if (!contactListGroupPropertiesReceived) { return; } contactListGroupRenamedQueue.enqueue(GroupRenamedInfo(oldName, newName)); contactListChangesQueue.enqueue(&ContactManager::Roster::processContactListGroupRenamed); processContactListChanges(); } void ContactManager::Roster::onContactListGroupsRemoved(const QStringList &names) { Q_ASSERT(usingFallbackContactList == false); if (!contactListGroupPropertiesReceived) { return; } contactListGroupsRemovedQueue.enqueue(names); contactListChangesQueue.enqueue(&ContactManager::Roster::processContactListGroupsRemoved); processContactListChanges(); } void ContactManager::Roster::onModifyFinished(Tp::PendingOperation *op) { ModifyFinishOp *returned = returnedModifyOps.take(op); // Finished twice, or we didn't add the returned op at all? Q_ASSERT(returned); if (op->isError()) { returned->setError(op->errorName(), op->errorMessage()); } modifyFinishQueue.enqueue(returned); contactListChangesQueue.enqueue(&ContactManager::Roster::processFinishedModify); processContactListChanges(); } void ContactManager::Roster::gotContactListChannelHandle(PendingOperation *op) { PendingHandles *ph = qobject_cast(op); Q_ASSERT(ph->namesRequested().size() == 1); QString channelId = ph->namesRequested().first(); uint type = ChannelInfo::typeForIdentifier(channelId); if (op->isError()) { // let's not fail, because the contact lists are not supported debug() << "Unable to retrieve handle for" << channelId << "channel, ignoring"; contactListChannels.remove(type); onContactListChannelReady(); return; } if (ph->invalidNames().size() == 1) { // let's not fail, because the contact lists are not supported debug() << "Unable to retrieve handle for" << channelId << "channel, ignoring"; contactListChannels.remove(type); onContactListChannelReady(); return; } Q_ASSERT(ph->handles().size() == 1); debug() << "Got handle for" << channelId << "channel"; if (!usingFallbackContactList) { Q_ASSERT(type == ChannelInfo::TypeDeny); } else { Q_ASSERT(type != (uint) -1 && type < ChannelInfo::LastType); } ReferencedHandles handle = ph->handles(); contactListChannels[type].handle = handle; debug() << "Requesting channel for" << channelId << "channel"; QVariantMap request; request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType"), TP_QT_IFACE_CHANNEL_TYPE_CONTACT_LIST); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType"), (uint) HandleTypeList); request.insert(TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandle"), handle[0]); ConnectionPtr conn(contactManager->connection()); /* Request the channel passing INT_MAX as timeout (meaning no timeout), as * some CMs may take too long to return from ensureChannel when still * loading the contact list */ connect(conn->lowlevel()->ensureChannel(request, INT_MAX), SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotContactListChannel(Tp::PendingOperation*))); } void ContactManager::Roster::gotContactListChannel(PendingOperation *op) { if (op->isError()) { debug() << "Unable to create channel, ignoring"; onContactListChannelReady(); return; } PendingChannel *pc = qobject_cast(op); ChannelPtr channel = pc->channel(); Q_ASSERT(channel); uint handle = pc->targetHandle(); Q_ASSERT(handle); for (uint i = 0; i < ChannelInfo::LastType; ++i) { if (contactListChannels.contains(i) && contactListChannels[i].handle.size() > 0 && contactListChannels[i].handle[0] == handle) { Q_ASSERT(!contactListChannels[i].channel); contactListChannels[i].channel = channel; // deref connection refcount here as connection will keep a ref to channel and we don't // want a contact list channel keeping a ref of connection, otherwise connection will // leak, thus the channels. channel->connection()->deref(); connect(channel->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactListChannelReady())); } } } void ContactManager::Roster::onContactListChannelReady() { if (!usingFallbackContactList) { setContactListChannelsReady(); updateContactsBlockState(); if (denyChannel) { cachedAllKnownContacts.unite(denyChannel->groupContacts()); } introspectContactList(); } else if (++contactListChannelsReady == ChannelInfo::LastType) { if (contactListChannels.isEmpty()) { contactListState = ContactListStateFailure; debug() << "State is failure, roster not supported"; emit contactManager->stateChanged((Tp::ContactListState) contactListState); Q_ASSERT(introspectPendingOp); introspectPendingOp->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Roster not supported")); introspectPendingOp = 0; return; } setContactListChannelsReady(); updateContactsBlockState(); // Refresh the cache for the current known contacts foreach (const ChannelInfo &contactListChannel, contactListChannels) { ChannelPtr channel = contactListChannel.channel; if (!channel) { continue; } cachedAllKnownContacts.unite(channel->groupContacts()); cachedAllKnownContacts.unite(channel->groupLocalPendingContacts()); cachedAllKnownContacts.unite(channel->groupRemotePendingContacts()); } updateContactsPresenceState(); Q_ASSERT(introspectPendingOp); if (!contactManager->connection()->requestedFeatures().contains( Connection::FeatureRosterGroups)) { // Will emit stateChanged() signal when the op is finished in idle // callback. This is to ensure FeatureRoster is marked ready. connect(introspectPendingOp, SIGNAL(finished(Tp::PendingOperation *)), SLOT(setStateSuccess())); } else { Q_ASSERT(!groupsSetSuccess); groupsSetSuccess = true; } introspectPendingOp->setFinished(); introspectPendingOp = 0; } } void ContactManager::Roster::gotContactListGroupsProperties(PendingOperation *op) { Q_ASSERT(introspectGroupsPendingOp != NULL); if (groupsSetSuccess) { // Connect here, so we catch the following and the other failure cases connect(introspectGroupsPendingOp, SIGNAL(finished(Tp::PendingOperation *)), SLOT(setStateSuccess())); } if (op->isError()) { warning() << "Getting contact list groups properties failed:" << op->errorName() << '-' << op->errorMessage(); introspectGroupsPendingOp->setFinishedWithError( op->errorName(), op->errorMessage()); introspectGroupsPendingOp = 0; return; } debug() << "Got contact list groups properties"; PendingVariantMap *pvm = qobject_cast(op); QVariantMap props = pvm->result(); cachedAllKnownGroups = qdbus_cast(props[QLatin1String("Groups")]).toSet(); contactListGroupPropertiesReceived = true; processingContactListChanges = true; PendingContacts *pc = contactManager->upgradeContacts( contactManager->allKnownContacts().toList(), Contact::FeatureRosterGroups); connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactListContactsUpgraded(Tp::PendingOperation*))); } void ContactManager::Roster::onContactListContactsUpgraded(PendingOperation *op) { Q_ASSERT(processingContactListChanges); processingContactListChanges = false; Q_ASSERT(introspectGroupsPendingOp != NULL); if (op->isError()) { warning() << "Upgrading contacts with group membership failed:" << op->errorName() << '-' << op->errorMessage(); introspectGroupsPendingOp->setFinishedWithError( op->errorName(), op->errorMessage()); introspectGroupsPendingOp = 0; processContactListChanges(); return; } introspectGroupsPendingOp->setFinished(); introspectGroupsPendingOp = 0; processContactListChanges(); } void ContactManager::Roster::onNewChannels(const Tp::ChannelDetailsList &channelDetailsList) { ConnectionPtr conn(contactManager->connection()); QString channelType; uint handleType; foreach (const ChannelDetails &channelDetails, channelDetailsList) { channelType = channelDetails.properties.value( TP_QT_IFACE_CHANNEL + QLatin1String(".ChannelType")).toString(); if (channelType != TP_QT_IFACE_CHANNEL_TYPE_CONTACT_LIST) { continue; } handleType = channelDetails.properties.value( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetHandleType")).toUInt(); if (handleType != Tp::HandleTypeGroup) { continue; } ++featureContactListGroupsTodo; // decremented in onContactListGroupChannelReady ChannelPtr channel = Channel::create(conn, channelDetails.channel.path(), channelDetails.properties); pendingContactListGroupChannels.append(channel); // deref connection refcount here as connection will keep a ref to channel and we don't // want a contact list group channel keeping a ref of connection, otherwise connection will // leak, thus the channels. channel->connection()->deref(); connect(channel->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactListGroupChannelReady(Tp::PendingOperation*))); } } void ContactManager::Roster::onContactListGroupChannelReady(PendingOperation *op) { --featureContactListGroupsTodo; // incremented in onNewChannels ConnectionPtr conn(contactManager->connection()); if (introspectGroupsPendingOp) { checkContactListGroupsReady(); } else { PendingReady *pr = qobject_cast(op); ChannelPtr channel = ChannelPtr::qObjectCast(pr->proxy()); QString id = addContactListGroupChannel(channel); emit contactManager->groupAdded(id); pendingContactListGroupChannels.removeOne(channel); } } void ContactManager::Roster::gotChannels(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; if (!reply.isError()) { debug() << "Got channels"; onNewChannels(qdbus_cast(reply.value())); } else { warning().nospace() << "Getting channels failed with " << reply.error().name() << ":" << reply.error().message(); } --featureContactListGroupsTodo; // incremented in introspectRosterGroups checkContactListGroupsReady(); watcher->deleteLater(); } void ContactManager::Roster::onStoredChannelMembersChanged( const Contacts &groupMembersAdded, const Contacts &groupLocalPendingMembersAdded, const Contacts &groupRemotePendingMembersAdded, const Contacts &groupMembersRemoved, const Channel::GroupMemberChangeDetails &details) { if (!groupLocalPendingMembersAdded.isEmpty()) { warning() << "Found local pending contacts on stored list"; } if (!groupRemotePendingMembersAdded.isEmpty()) { warning() << "Found remote pending contacts on stored list"; } foreach (ContactPtr contact, groupMembersAdded) { debug() << "Contact" << contact->id() << "on stored list"; } foreach (ContactPtr contact, groupMembersRemoved) { debug() << "Contact" << contact->id() << "removed from stored list"; } // Perform the needed computation for allKnownContactsChanged computeKnownContactsChanges(groupMembersAdded, groupLocalPendingMembersAdded, groupRemotePendingMembersAdded, groupMembersRemoved, details); } void ContactManager::Roster::onSubscribeChannelMembersChanged( const Contacts &groupMembersAdded, const Contacts &groupLocalPendingMembersAdded, const Contacts &groupRemotePendingMembersAdded, const Contacts &groupMembersRemoved, const Channel::GroupMemberChangeDetails &details) { if (!groupLocalPendingMembersAdded.isEmpty()) { warning() << "Found local pending contacts on subscribe list"; } foreach (ContactPtr contact, groupMembersAdded) { debug() << "Contact" << contact->id() << "on subscribe list"; contact->setSubscriptionState(SubscriptionStateYes); } foreach (ContactPtr contact, groupRemotePendingMembersAdded) { debug() << "Contact" << contact->id() << "added to subscribe list"; contact->setSubscriptionState(SubscriptionStateAsk); } foreach (ContactPtr contact, groupMembersRemoved) { debug() << "Contact" << contact->id() << "removed from subscribe list"; contact->setSubscriptionState(SubscriptionStateNo); } // Perform the needed computation for allKnownContactsChanged computeKnownContactsChanges(groupMembersAdded, groupLocalPendingMembersAdded, groupRemotePendingMembersAdded, groupMembersRemoved, details); } void ContactManager::Roster::onPublishChannelMembersChanged( const Contacts &groupMembersAdded, const Contacts &groupLocalPendingMembersAdded, const Contacts &groupRemotePendingMembersAdded, const Contacts &groupMembersRemoved, const Channel::GroupMemberChangeDetails &details) { if (!groupRemotePendingMembersAdded.isEmpty()) { warning() << "Found remote pending contacts on publish list"; } foreach (ContactPtr contact, groupMembersAdded) { debug() << "Contact" << contact->id() << "on publish list"; contact->setPublishState(SubscriptionStateYes); } foreach (ContactPtr contact, groupLocalPendingMembersAdded) { debug() << "Contact" << contact->id() << "added to publish list"; contact->setPublishState(SubscriptionStateAsk, details.message()); } foreach (ContactPtr contact, groupMembersRemoved) { debug() << "Contact" << contact->id() << "removed from publish list"; contact->setPublishState(SubscriptionStateNo); } if (!groupLocalPendingMembersAdded.isEmpty()) { emit contactManager->presencePublicationRequested(groupLocalPendingMembersAdded); } // Perform the needed computation for allKnownContactsChanged computeKnownContactsChanges(groupMembersAdded, groupLocalPendingMembersAdded, groupRemotePendingMembersAdded, groupMembersRemoved, details); } void ContactManager::Roster::onDenyChannelMembersChanged( const Contacts &groupMembersAdded, const Contacts &groupLocalPendingMembersAdded, const Contacts &groupRemotePendingMembersAdded, const Contacts &groupMembersRemoved, const Channel::GroupMemberChangeDetails &details) { if (!groupLocalPendingMembersAdded.isEmpty()) { warning() << "Found local pending contacts on deny list"; } if (!groupRemotePendingMembersAdded.isEmpty()) { warning() << "Found remote pending contacts on deny list"; } foreach (ContactPtr contact, groupMembersAdded) { debug() << "Contact" << contact->id() << "added to deny list"; contact->setBlocked(true); } foreach (ContactPtr contact, groupMembersRemoved) { debug() << "Contact" << contact->id() << "removed from deny list"; contact->setBlocked(false); } // Perform the needed computation for allKnownContactsChanged computeKnownContactsChanges(groupMembersAdded, Contacts(), Contacts(), groupMembersRemoved, details); } void ContactManager::Roster::onContactListGroupMembersChanged( const Tp::Contacts &groupMembersAdded, const Tp::Contacts &groupLocalPendingMembersAdded, const Tp::Contacts &groupRemotePendingMembersAdded, const Tp::Contacts &groupMembersRemoved, const Tp::Channel::GroupMemberChangeDetails &details) { ChannelPtr contactListGroupChannel = ChannelPtr( qobject_cast(sender())); QString id = contactListGroupChannel->immutableProperties().value( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")).toString(); foreach (const ContactPtr &contact, groupMembersAdded) { contact->setAddedToGroup(id); } foreach (const ContactPtr &contact, groupMembersRemoved) { contact->setRemovedFromGroup(id); } emit contactManager->groupMembersChanged(id, groupMembersAdded, groupMembersRemoved, details); } void ContactManager::Roster::onContactListGroupRemoved(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { Q_UNUSED(errorName); Q_UNUSED(errorMessage); // Is it correct to assume that if an user-defined contact list // gets invalidated it means it was removed? Spec states that if a // user-defined contact list gets closed it was removed, and Channel // invalidates itself when it gets closed. ChannelPtr contactListGroupChannel = ChannelPtr(qobject_cast(proxy)); QString id = contactListGroupChannel->immutableProperties().value( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")).toString(); contactListGroupChannels.remove(id); removedContactListGroupChannels.append(contactListGroupChannel); disconnect(contactListGroupChannel.data(), 0, 0, 0); emit contactManager->groupRemoved(id); } void ContactManager::Roster::introspectContactBlocking() { debug() << "Requesting ContactBlockingCapabilities property"; ConnectionPtr conn(contactManager->connection()); Client::ConnectionInterfaceContactBlockingInterface *iface = conn->interface(); PendingVariant *pv = iface->requestPropertyContactBlockingCapabilities(); connect(pv, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotContactBlockingCapabilities(Tp::PendingOperation*))); } void ContactManager::Roster::introspectContactBlockingBlockedContacts() { ConnectionPtr conn(contactManager->connection()); Client::ConnectionInterfaceContactBlockingInterface *iface = conn->interface(); Q_ASSERT(iface); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( iface->RequestBlockedContacts(), contactManager); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotContactBlockingBlockedContacts(QDBusPendingCallWatcher*))); connect(iface, SIGNAL(BlockedContactsChanged(Tp::HandleIdentifierMap,Tp::HandleIdentifierMap)), SLOT(onContactBlockingBlockedContactsChanged(Tp::HandleIdentifierMap,Tp::HandleIdentifierMap))); } void ContactManager::Roster::introspectContactList() { debug() << "Requesting ContactList properties"; ConnectionPtr conn(contactManager->connection()); Client::ConnectionInterfaceContactListInterface *iface = conn->interface(); connect(iface, SIGNAL(ContactListStateChanged(uint)), SLOT(onContactListStateChanged(uint))); connect(iface, SIGNAL(ContactsChangedWithID(Tp::ContactSubscriptionMap,Tp::HandleIdentifierMap,Tp::HandleIdentifierMap)), SLOT(onContactListContactsChangedWithId(Tp::ContactSubscriptionMap,Tp::HandleIdentifierMap,Tp::HandleIdentifierMap))); connect(iface, SIGNAL(ContactsChanged(Tp::ContactSubscriptionMap,Tp::UIntList)), SLOT(onContactListContactsChanged(Tp::ContactSubscriptionMap,Tp::UIntList))); PendingVariantMap *pvm = iface->requestAllProperties(); connect(pvm, SIGNAL(finished(Tp::PendingOperation*)), SLOT(gotContactListProperties(Tp::PendingOperation*))); } void ContactManager::Roster::introspectContactListContacts() { ConnectionPtr conn(contactManager->connection()); Client::ConnectionInterfaceContactListInterface *iface = conn->interface(); Features features(conn->contactFactory()->features()); Features supportedFeatures(contactManager->supportedFeatures()); QSet interfaces; foreach (const Feature &feature, features) { contactManager->ensureTracking(feature); if (supportedFeatures.contains(feature)) { // Only query interfaces which are reported as supported to not get an error interfaces.insert(contactManager->featureToInterface(feature)); } } interfaces.insert(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( iface->GetContactListAttributes(interfaces.toList(), true), contactManager); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotContactListContacts(QDBusPendingCallWatcher*))); } void ContactManager::Roster::processContactListChanges() { if (processingContactListChanges || contactListChangesQueue.isEmpty()) { return; } processingContactListChanges = true; (this->*(contactListChangesQueue.dequeue()))(); } void ContactManager::Roster::processContactListBlockedContactsChanged() { BlockedContactsChangedInfo info = contactListBlockedContactsChangedQueue.head(); UIntList contacts; HandleIdentifierMap::const_iterator begin = info.added.constBegin(); HandleIdentifierMap::const_iterator end = info.added.constEnd(); for (HandleIdentifierMap::const_iterator i = begin; i != end; ++i) { uint bareHandle = i.key(); contacts << bareHandle; } begin = info.removed.constBegin(); end = info.removed.constEnd(); for (HandleIdentifierMap::const_iterator i = begin; i != end; ++i) { uint bareHandle = i.key(); contacts << bareHandle; } Features features; if (contactManager->connection()->isReady(Connection::FeatureRosterGroups)) { features << Contact::FeatureRosterGroups; } PendingContacts *pc = contactManager->contactsForHandles(contacts, features); connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactListBlockedContactsConstructed(Tp::PendingOperation*))); } void ContactManager::Roster::processContactListUpdates() { UpdateInfo info = contactListUpdatesQueue.head(); // construct Contact objects for all contacts in added to the contact list UIntList contacts; ContactSubscriptionMap::const_iterator begin = info.changes.constBegin(); ContactSubscriptionMap::const_iterator end = info.changes.constEnd(); for (ContactSubscriptionMap::const_iterator i = begin; i != end; ++i) { uint bareHandle = i.key(); contacts << bareHandle; } Features features; if (contactManager->connection()->isReady(Connection::FeatureRosterGroups)) { features << Contact::FeatureRosterGroups; } PendingContacts *pc = contactManager->contactsForHandles(contacts, features); connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactListNewContactsConstructed(Tp::PendingOperation*))); } void ContactManager::Roster::processContactListGroupsUpdates() { GroupsUpdateInfo info = contactListGroupsUpdatesQueue.dequeue(); foreach (const QString &group, info.groupsAdded) { Contacts contacts; foreach (uint bareHandle, info.contacts) { ContactPtr contact = contactManager->lookupContactByHandle(bareHandle); if (!contact) { warning() << "contact with handle" << bareHandle << "was added to a group but " "never added to the contact list, ignoring"; continue; } contacts << contact; contact->setAddedToGroup(group); } emit contactManager->groupMembersChanged(group, contacts, Contacts(), Channel::GroupMemberChangeDetails()); } foreach (const QString &group, info.groupsRemoved) { Contacts contacts; foreach (uint bareHandle, info.contacts) { ContactPtr contact = contactManager->lookupContactByHandle(bareHandle); if (!contact) { warning() << "contact with handle" << bareHandle << "was removed from a group but " "never added to the contact list, ignoring"; continue; } contacts << contact; contact->setRemovedFromGroup(group); } emit contactManager->groupMembersChanged(group, Contacts(), contacts, Channel::GroupMemberChangeDetails()); } processingContactListChanges = false; processContactListChanges(); } void ContactManager::Roster::processContactListGroupsCreated() { QStringList names = contactListGroupsCreatedQueue.dequeue(); foreach (const QString &name, names) { cachedAllKnownGroups.insert(name); emit contactManager->groupAdded(name); } processingContactListChanges = false; processContactListChanges(); } void ContactManager::Roster::processContactListGroupRenamed() { GroupRenamedInfo info = contactListGroupRenamedQueue.dequeue(); cachedAllKnownGroups.remove(info.oldName); cachedAllKnownGroups.insert(info.newName); emit contactManager->groupRenamed(info.oldName, info.newName); processingContactListChanges = false; processContactListChanges(); } void ContactManager::Roster::processContactListGroupsRemoved() { QStringList names = contactListGroupsRemovedQueue.dequeue(); foreach (const QString &name, names) { cachedAllKnownGroups.remove(name); emit contactManager->groupRemoved(name); } processingContactListChanges = false; processContactListChanges(); } void ContactManager::Roster::processFinishedModify() { ModifyFinishOp *op = modifyFinishQueue.dequeue(); // Only continue processing changes (and thus, emitting change signals) when the op has signaled // finish (it'll only do this after we've returned to the mainloop) connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onModifyFinishSignaled())); op->finish(); } PendingOperation *ContactManager::Roster::queuedFinishVoid(const QDBusPendingCall &call) { PendingOperation *actual = new PendingVoid(call, contactManager->connection()); connect(actual, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onModifyFinished(Tp::PendingOperation*))); ModifyFinishOp *toReturn = new ModifyFinishOp(contactManager->connection()); returnedModifyOps.insert(actual, toReturn); return toReturn; } void ContactManager::Roster::onModifyFinishSignaled() { processingContactListChanges = false; processContactListChanges(); } void ContactManager::Roster::setContactListChannelsReady() { if (!usingFallbackContactList) { Q_ASSERT(!contactListChannels.contains(ChannelInfo::TypeSubscribe)); Q_ASSERT(!contactListChannels.contains(ChannelInfo::TypePublish)); Q_ASSERT(!contactListChannels.contains(ChannelInfo::TypeStored)); } if (contactListChannels.contains(ChannelInfo::TypeSubscribe)) { subscribeChannel = contactListChannels[ChannelInfo::TypeSubscribe].channel; } if (contactListChannels.contains(ChannelInfo::TypePublish)) { publishChannel = contactListChannels[ChannelInfo::TypePublish].channel; } if (contactListChannels.contains(ChannelInfo::TypeStored)) { storedChannel = contactListChannels[ChannelInfo::TypeStored].channel; } if (contactListChannels.contains(ChannelInfo::TypeDeny)) { denyChannel = contactListChannels[ChannelInfo::TypeDeny].channel; } uint type; ChannelPtr channel; const char *method; for (QHash::const_iterator i = contactListChannels.constBegin(); i != contactListChannels.constEnd(); ++i) { type = i.key(); channel = i.value().channel; if (!channel) { continue; } if (type == ChannelInfo::TypeStored) { method = SLOT(onStoredChannelMembersChanged( Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)); } else if (type == ChannelInfo::TypeSubscribe) { method = SLOT(onSubscribeChannelMembersChanged( Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)); } else if (type == ChannelInfo::TypePublish) { method = SLOT(onPublishChannelMembersChanged( Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)); } else if (type == ChannelInfo::TypeDeny) { method = SLOT(onDenyChannelMembersChanged( Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)); } else { continue; } connect(channel.data(), SIGNAL(groupMembersChanged( Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)), method); } } void ContactManager::Roster::updateContactsBlockState() { Q_ASSERT(!hasContactBlockingInterface); if (!denyChannel) { return; } Contacts denyContacts = denyChannel->groupContacts(); foreach (const ContactPtr &contact, denyContacts) { contact->setBlocked(true); } } void ContactManager::Roster::updateContactsPresenceState() { if (!subscribeChannel && !publishChannel) { return; } Contacts subscribeContacts; Contacts subscribeContactsRP; if (subscribeChannel) { subscribeContacts = subscribeChannel->groupContacts(); subscribeContactsRP = subscribeChannel->groupRemotePendingContacts(); } Contacts publishContacts; Contacts publishContactsLP; if (publishChannel) { publishContacts = publishChannel->groupContacts(); publishContactsLP = publishChannel->groupLocalPendingContacts(); } Contacts contacts = cachedAllKnownContacts; foreach (ContactPtr contact, contacts) { if (subscribeChannel) { // not in "subscribe" -> No, in "subscribe" lp -> Ask, in "subscribe" current -> Yes if (subscribeContacts.contains(contact)) { contact->setSubscriptionState(SubscriptionStateYes); } else if (subscribeContactsRP.contains(contact)) { contact->setSubscriptionState(SubscriptionStateAsk); } else { contact->setSubscriptionState(SubscriptionStateNo); } } if (publishChannel) { // not in "publish" -> No, in "subscribe" rp -> Ask, in "publish" current -> Yes if (publishContacts.contains(contact)) { contact->setPublishState(SubscriptionStateYes); } else if (publishContactsLP.contains(contact)) { contact->setPublishState(SubscriptionStateAsk, publishChannel->groupLocalPendingContactChangeInfo(contact).message()); } else { contact->setPublishState(SubscriptionStateNo); } } } } void ContactManager::Roster::computeKnownContactsChanges(const Tp::Contacts& added, const Tp::Contacts& pendingAdded, const Tp::Contacts& remotePendingAdded, const Tp::Contacts& removed, const Channel::GroupMemberChangeDetails &details) { // First of all, compute the real additions/removals based upon our cache Tp::Contacts realAdded; realAdded.unite(added); realAdded.unite(pendingAdded); realAdded.unite(remotePendingAdded); realAdded.subtract(cachedAllKnownContacts); Tp::Contacts realRemoved = removed; realRemoved.intersect(cachedAllKnownContacts); // Check if realRemoved have been _really_ removed from all lists foreach (const ChannelInfo &contactListChannel, contactListChannels) { ChannelPtr channel = contactListChannel.channel; if (!channel) { continue; } realRemoved.subtract(channel->groupContacts()); realRemoved.subtract(channel->groupLocalPendingContacts()); realRemoved.subtract(channel->groupRemotePendingContacts()); } // ...and from the Conn.I.ContactList / Conn.I.ContactBlocking contacts realRemoved.subtract(contactListContacts); realRemoved.subtract(blockedContacts); // Are there any real changes? if (!realAdded.isEmpty() || !realRemoved.isEmpty()) { // Yes, update our "cache" and emit the signal cachedAllKnownContacts.unite(realAdded); cachedAllKnownContacts.subtract(realRemoved); emit contactManager->allKnownContactsChanged(realAdded, realRemoved, details); } } void ContactManager::Roster::checkContactListGroupsReady() { if (featureContactListGroupsTodo != 0) { return; } if (groupsSetSuccess) { Q_ASSERT(contactManager->state() != ContactListStateSuccess); if (introspectGroupsPendingOp) { // Will emit stateChanged() signal when the op is finished in idle // callback. This is to ensure FeatureRosterGroups is marked ready. connect(introspectGroupsPendingOp, SIGNAL(finished(Tp::PendingOperation *)), SLOT(setStateSuccess())); } else { setStateSuccess(); } groupsSetSuccess = false; } setContactListGroupChannelsReady(); if (introspectGroupsPendingOp) { introspectGroupsPendingOp->setFinished(); introspectGroupsPendingOp = 0; } pendingContactListGroupChannels.clear(); } void ContactManager::Roster::setContactListGroupChannelsReady() { Q_ASSERT(usingFallbackContactList == true); Q_ASSERT(contactListGroupChannels.isEmpty()); foreach (const ChannelPtr &contactListGroupChannel, pendingContactListGroupChannels) { addContactListGroupChannel(contactListGroupChannel); } } QString ContactManager::Roster::addContactListGroupChannel(const ChannelPtr &contactListGroupChannel) { QString id = contactListGroupChannel->immutableProperties().value( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")).toString(); contactListGroupChannels.insert(id, contactListGroupChannel); connect(contactListGroupChannel.data(), SIGNAL(groupMembersChanged( Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Channel::GroupMemberChangeDetails)), SLOT(onContactListGroupMembersChanged( Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Contacts, Tp::Channel::GroupMemberChangeDetails))); connect(contactListGroupChannel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onContactListGroupRemoved(Tp::DBusProxy*,QString,QString))); foreach (const ContactPtr &contact, contactListGroupChannel->groupContacts()) { contact->setAddedToGroup(id); } return id; } /**** ContactManager::Roster::ChannelInfo ****/ QString ContactManager::Roster::ChannelInfo::identifierForType(Type type) { static QString identifiers[LastType] = { QLatin1String("subscribe"), QLatin1String("publish"), QLatin1String("stored"), QLatin1String("deny"), }; return identifiers[type]; } uint ContactManager::Roster::ChannelInfo::typeForIdentifier(const QString &identifier) { static QHash types; if (types.isEmpty()) { types.insert(QLatin1String("subscribe"), TypeSubscribe); types.insert(QLatin1String("publish"), TypePublish); types.insert(QLatin1String("stored"), TypeStored); types.insert(QLatin1String("deny"), TypeDeny); } if (types.contains(identifier)) { return types[identifier]; } return (uint) -1; } /**** ContactManager::Roster::ModifyFinishOp ****/ ContactManager::Roster::ModifyFinishOp::ModifyFinishOp(const ConnectionPtr &conn) : PendingOperation(conn) { } void ContactManager::Roster::ModifyFinishOp::setError(const QString &errorName, const QString &errorMessage) { Q_ASSERT(this->errorName.isEmpty()); Q_ASSERT(this->errorMessage.isEmpty()); Q_ASSERT(!errorName.isEmpty()); this->errorName = errorName; this->errorMessage = errorMessage; } void ContactManager::Roster::ModifyFinishOp::finish() { if (errorName.isEmpty()) { setFinished(); } else { setFinishedWithError(errorName, errorMessage); } } /**** ContactManager::Roster::RemoveGroupOp ****/ ContactManager::Roster::RemoveGroupOp::RemoveGroupOp(const ChannelPtr &channel) : PendingOperation(channel) { Contacts contacts = channel->groupContacts(); if (!contacts.isEmpty()) { connect(channel->groupRemoveContacts(contacts.toList()), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactsRemoved(Tp::PendingOperation*))); } else { connect(channel->requestClose(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onChannelClosed(Tp::PendingOperation*))); } } void ContactManager::Roster::RemoveGroupOp::onContactsRemoved(PendingOperation *op) { if (op->isError()) { setFinishedWithError(op->errorName(), op->errorMessage()); return; } // Let's ignore possible errors and try to remove the group ChannelPtr channel = ChannelPtr(qobject_cast((Channel *) object().data())); connect(channel->requestClose(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onChannelClosed(Tp::PendingOperation*))); } void ContactManager::Roster::RemoveGroupOp::onChannelClosed(PendingOperation *op) { if (!op->isError()) { setFinished(); } else { setFinishedWithError(op->errorName(), op->errorMessage()); } } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/ChannelDispatcher0000664000175000017500000000040212470405660020512 0ustar jrjr#ifndef _TelepathyQt_ChannelDispatcher_HEADER_GUARD_ #define _TelepathyQt_ChannelDispatcher_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/channel-request.cpp0000664000175000017500000006715412470405660021033 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2009 Collabora Ltd. * @copyright Copyright (C) 2009 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/_gen/cli-channel-request-body.hpp" #include "TelepathyQt/_gen/cli-channel-request.moc.hpp" #include "TelepathyQt/_gen/channel-request.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include namespace Tp { struct TP_QT_NO_EXPORT ChannelRequest::Private { Private(ChannelRequest *parent, const QVariantMap &immutableProperties, const AccountFactoryConstPtr &, const ConnectionFactoryConstPtr &, const ChannelFactoryConstPtr &, const ContactFactoryConstPtr &); ~Private(); static void introspectMain(Private *self); // \param lastCall Is this the last call to extractMainProps ie. should actions that only must // be done once be done in this call void extractMainProps(const QVariantMap &props, bool lastCall); // Public object ChannelRequest *parent; // Context AccountFactoryConstPtr accFact; ConnectionFactoryConstPtr connFact; ChannelFactoryConstPtr chanFact; ContactFactoryConstPtr contactFact; // Instance of generated interface class Client::ChannelRequestInterface *baseInterface; // Mandatory properties interface proxy Client::DBus::PropertiesInterface *properties; QVariantMap immutableProperties; ReadinessHelper *readinessHelper; // Introspection AccountPtr account; QDateTime userActionTime; QString preferredHandler; QualifiedPropertyValueMapList requests; ChannelRequestHints hints; bool propertiesDone; bool gotSWC; ChannelPtr chan; }; ChannelRequest::Private::Private(ChannelRequest *parent, const QVariantMap &immutableProperties, const AccountFactoryConstPtr &accFact, const ConnectionFactoryConstPtr &connFact, const ChannelFactoryConstPtr &chanFact, const ContactFactoryConstPtr &contactFact) : parent(parent), accFact(accFact), connFact(connFact), chanFact(chanFact), contactFact(contactFact), baseInterface(new Client::ChannelRequestInterface(parent)), properties(parent->interface()), immutableProperties(immutableProperties), readinessHelper(parent->readinessHelper()), propertiesDone(false), gotSWC(false) { debug() << "Creating new ChannelRequest:" << parent->objectPath(); parent->connect(baseInterface, SIGNAL(Failed(QString,QString)), SIGNAL(failed(QString,QString))); parent->connect(baseInterface, SIGNAL(Succeeded()), SLOT(onLegacySucceeded())); parent->connect(baseInterface, SIGNAL(SucceededWithChannel(QDBusObjectPath,QVariantMap,QDBusObjectPath,QVariantMap)), SLOT(onSucceededWithChannel(QDBusObjectPath,QVariantMap,QDBusObjectPath,QVariantMap))); ReadinessHelper::Introspectables introspectables; // As ChannelRequest does not have predefined statuses let's simulate one (0) ReadinessHelper::Introspectable introspectableCore( QSet() << 0, // makesSenseForStatuses Features(), // dependsOnFeatures QStringList(), // dependsOnInterfaces (ReadinessHelper::IntrospectFunc) &Private::introspectMain, this); introspectables[FeatureCore] = introspectableCore; readinessHelper->addIntrospectables(introspectables); // For early access to the immutable properties through the friendly getters - will be called // again with lastCall = true eventually, if/when becomeReady is called, though QVariantMap mainProps; foreach (QString key, immutableProperties.keys()) { // The key.count thing is so that we don't match "org.fdo.Tp.CR.OptionalInterface.Prop" too if (key.startsWith(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".")) && key.count(QLatin1Char('.')) == QString(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".")).count(QLatin1Char('.'))) { QVariant value = immutableProperties.value(key); mainProps.insert(key.remove(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".")), value); } } extractMainProps(mainProps, false); } ChannelRequest::Private::~Private() { } void ChannelRequest::Private::introspectMain(ChannelRequest::Private *self) { QVariantMap props; QString key; bool needIntrospectMainProps = false; const char *propertiesNames[] = { "Account", "UserActionTime", "PreferredHandler", "Requests", "Interfaces", NULL }; for (unsigned i = 0; propertiesNames[i] != NULL; ++i) { key = TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String("."); key += QLatin1String(propertiesNames[i]); if (!self->immutableProperties.contains(key)) { needIntrospectMainProps = true; break; } props.insert(QLatin1String(propertiesNames[i]), self->immutableProperties[key]); } if (needIntrospectMainProps) { debug() << "Calling Properties::GetAll(ChannelRequest)"; QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( self->properties->GetAll(TP_QT_IFACE_CHANNEL_REQUEST), self->parent); // FIXME: This is a Qt bug fixed upstream, should be in the next Qt release. // We should not need to check watcher->isFinished() here, remove the // check when a fixed Qt version is released. if (watcher->isFinished()) { self->parent->gotMainProperties(watcher); } else { self->parent->connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(gotMainProperties(QDBusPendingCallWatcher*))); } } else { self->extractMainProps(props, true); } } void ChannelRequest::Private::extractMainProps(const QVariantMap &props, bool lastCall) { PendingReady *readyOp = 0; if (props.contains(QLatin1String("Account"))) { QDBusObjectPath accountObjectPath = qdbus_cast(props.value(QLatin1String("Account"))); if (!account.isNull()) { if (accountObjectPath.path() == account->objectPath()) { // Most often a no-op, but we want this to guarantee the old behavior in all cases readyOp = account->becomeReady(); } else { warning() << "The account" << accountObjectPath.path() << "was not the expected" << account->objectPath() << "for CR" << parent->objectPath(); // Construct a new one instead account.reset(); } } // We need to check again because we might have dropped the expected account just a sec ago if (account.isNull() && !accountObjectPath.path().isEmpty()) { if (!accFact.isNull()) { readyOp = accFact->proxy( TP_QT_ACCOUNT_MANAGER_BUS_NAME, accountObjectPath.path(), connFact, chanFact, contactFact); account = AccountPtr::qObjectCast(readyOp->proxy()); } else { account = Account::create( TP_QT_ACCOUNT_MANAGER_BUS_NAME, accountObjectPath.path(), connFact, chanFact, contactFact); readyOp = account->becomeReady(); } } } // FIXME See http://bugs.freedesktop.org/show_bug.cgi?id=21690 uint stamp = (uint) qdbus_cast(props.value(QLatin1String("UserActionTime"))); if (stamp != 0) { userActionTime = QDateTime::fromTime_t(stamp); } preferredHandler = qdbus_cast(props.value(QLatin1String("PreferredHandler"))); requests = qdbus_cast(props.value(QLatin1String("Requests"))); parent->setInterfaces(qdbus_cast(props[QLatin1String("Interfaces")])); readinessHelper->setInterfaces(parent->interfaces()); if (props.contains(QLatin1String("Hints"))) { hints = qdbus_cast(props.value(QLatin1String("Hints"))); } if (lastCall) { propertiesDone = true; } if (account) { parent->connect(readyOp, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountReady(Tp::PendingOperation*))); } else if (lastCall) { warning() << "No account for ChannelRequest" << parent->objectPath(); readinessHelper->setIntrospectCompleted(FeatureCore, true); } } /** * \class ChannelRequest * \ingroup clientchannelrequest * \headerfile TelepathyQt/channel-request.h * * \brief The ChannelRequest class represents a Telepathy channel request. * * A channel request is an object in the channel dispatcher representing an * ongoing request for some channels to be created or found. There can be any * number of channel request objects at the same time. * * A channel request can be cancelled by any client (not just the one that * requested it). This means that the channel dispatcher will close the * resulting channel, or refrain from requesting it at all, rather than * dispatching it to a handler. * * See \ref async_model */ /** * Feature representing the core that needs to become ready to make the * ChannelRequest object usable. * * Note that this feature must be enabled in order to use most * ChannelRequest methods. * * When calling isReady(), becomeReady(), this feature is implicitly added * to the requested features. */ const Feature ChannelRequest::FeatureCore = Feature(QLatin1String(ChannelRequest::staticMetaObject.className()), 0, true); /** * Create a new channel request object using the given \a bus and the given factories. * * \param objectPath The channel request object path. * \param immutableProperties The channel request immutable properties. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \return A ChannelRequestPtr object pointing to the newly created ChannelRequest object. */ ChannelRequestPtr ChannelRequest::create(const QDBusConnection &bus, const QString &objectPath, const QVariantMap &immutableProperties, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) { return ChannelRequestPtr(new ChannelRequest(bus, objectPath, immutableProperties, accountFactory, connectionFactory, channelFactory, contactFactory)); } /** * Create a new channel request object for the given \a account. * * The returned instance will use factories from the account. * * \param account The account that the request was made through. * \param objectPath The channel request object path. * \param immutableProperties The channel request immutable properties. * \return A ChannelRequestPtr object pointing to the newly created ChannelRequest object. */ ChannelRequestPtr ChannelRequest::create(const AccountPtr &account, const QString &objectPath, const QVariantMap &immutableProperties) { return ChannelRequestPtr(new ChannelRequest(account, objectPath, immutableProperties)); } /** * Construct a new channel request object using the given \a bus and the given factories. * * \param bus QDBusConnection to use. * \param objectPath The channel request object path. * \param accountFactory The account factory to use. * \param connectionFactory The connection factory to use. * \param channelFactory The channel factory to use. * \param contactFactory The contact factory to use. * \param immutableProperties The immutable properties of the channel request. * \return A ChannelRequestPtr object pointing to the newly created ChannelRequest. */ ChannelRequest::ChannelRequest(const QDBusConnection &bus, const QString &objectPath, const QVariantMap &immutableProperties, const AccountFactoryConstPtr &accountFactory, const ConnectionFactoryConstPtr &connectionFactory, const ChannelFactoryConstPtr &channelFactory, const ContactFactoryConstPtr &contactFactory) : StatefulDBusProxy(bus, TP_QT_IFACE_CHANNEL_DISPATCHER, objectPath, FeatureCore), OptionalInterfaceFactory(this), mPriv(new Private(this, immutableProperties, accountFactory, connectionFactory, channelFactory, contactFactory)) { if (accountFactory->dbusConnection().name() != bus.name()) { warning() << " The D-Bus connection in the account factory is not the proxy connection"; } if (connectionFactory->dbusConnection().name() != bus.name()) { warning() << " The D-Bus connection in the connection factory is not the proxy connection"; } if (channelFactory->dbusConnection().name() != bus.name()) { warning() << " The D-Bus connection in the channel factory is not the proxy connection"; } } /** * Construct a new channel request object using the given \a account. * * The constructed instance will use the factories from the account. * * \param account Account to use. * \param objectPath The channel request object path. * \param immutableProperties The immutable properties of the channel request. * \return A ChannelRequestPtr object pointing to the newly created ChannelRequest. */ ChannelRequest::ChannelRequest(const AccountPtr &account, const QString &objectPath, const QVariantMap &immutableProperties) : StatefulDBusProxy(account->dbusConnection(), TP_QT_IFACE_CHANNEL_DISPATCHER, objectPath, FeatureCore), OptionalInterfaceFactory(this), mPriv(new Private(this, immutableProperties, AccountFactoryPtr(), account->connectionFactory(), account->channelFactory(), account->contactFactory())) { mPriv->account = account; } /** * Class destructor. */ ChannelRequest::~ChannelRequest() { delete mPriv; } /** * Return the account on which this request was made. * * This method can be used even before the ChannelRequest is ready, in which case the account object * corresponding to the immutable properties is returned. In this case, the Account object is not * necessarily ready either. This is useful for eg. matching ChannelRequests from * ClientHandlerInterface::addRequest() with existing accounts in the application: either by object * path, or if account factories are in use, even by object identity. * * If the account is not provided in the immutable properties, this will only return a non-\c NULL * AccountPtr once ChannelRequest::FeatureCore is ready on this object. * * \return A pointer to the Account object. */ AccountPtr ChannelRequest::account() const { return mPriv->account; } /** * Return the time at which the user action occurred, or 0 if this channel * request is for some reason not involving user action. * * Unix developers: this corresponds to the _NET_WM_USER_TIME property in EWMH. * * This property is set when the channel request is created, and can never * change. * * This method can be used even before the ChannelRequest is ready: in this case, the user action * time from the immutable properties, if any, is returned. * * \return The time at which the user action occurred as QDateTime. */ QDateTime ChannelRequest::userActionTime() const { return mPriv->userActionTime; } /** * Return either the well-known bus name (starting with * org.freedesktop.Telepathy.Client.) of the preferred handler for this channel, * or an empty string to indicate that any handler would be acceptable. * * This property is set when the channel request is created, and can never * change. * * This method can be used even before the ChannelRequest is ready: in this case, the preferred * handler from the immutable properties, if any, is returned. * * \return The preferred handler, or an empty string if any handler would be * acceptable. */ QString ChannelRequest::preferredHandler() const { return mPriv->preferredHandler; } /** * Return the desirable properties for the channel or channels to be created, as specified when * placing the request in the first place. * * This property is set when the channel request is created, and can never * change. * * This method can be used even before the ChannelRequest is ready: in this case, the requested * channel properties from the immutable properties, if any, are returned. This is useful for e.g. * matching ChannelRequests from ClientHandlerInterface::addRequest() with existing requests in the * application (by the target ID or handle, most likely). * * \return The requested desirable channel properties as a list of * QualifiedPropertyValueMap objects. */ QualifiedPropertyValueMapList ChannelRequest::requests() const { return mPriv->requests; } /** * Return the dictionary of metadata provided by the channel requester when requesting the channel. * * This property is set when the channel request is created, and can never change. * * This method can be used even before the ChannelRequest is ready: in this case, the requested * channel properties from the immutable properties, if any, are returned. This is useful for e.g. * matching ChannelRequests from ClientHandlerInterface::addRequest() with existing requests in the * application (by the target ID or handle, most likely). * * \sa Account::supportsRequestHints() * \return The hints in the request as a ChannelRequestHints object, if any. */ ChannelRequestHints ChannelRequest::hints() const { return mPriv->hints; } /** * Return all of the immutable properties passed to this object when created. * * This is useful for e.g. getting to domain-specific properties of channel requests. * * \return The immutable properties as QVariantMap. */ QVariantMap ChannelRequest::immutableProperties() const { QVariantMap props = mPriv->immutableProperties; if (!account().isNull()) { props.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Account"), QVariant::fromValue(QDBusObjectPath(account()->objectPath()))); } if (userActionTime().isValid()) { props.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".UserActionTime"), QVariant::fromValue(userActionTime().toTime_t())); } if (!preferredHandler().isNull()) { props.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".PreferredHandler"), preferredHandler()); } if (!requests().isEmpty()) { props.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Requests"), QVariant::fromValue(requests())); } props.insert(TP_QT_IFACE_CHANNEL_REQUEST + QLatin1String(".Interfaces"), QVariant::fromValue(interfaces())); return props; } /** * Cancel the channel request. * * If failed() is emitted in response to this method, the error will be * #TP_QT_ERROR_CANCELLED. * * If the channel has already been dispatched to a handler, then it's too late * to call this method, and the channel request will no longer exist. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *ChannelRequest::cancel() { return new PendingVoid(mPriv->baseInterface->Cancel(), ChannelRequestPtr(this)); } /** * Return the Channel which this request succeeded with, if any. * * This will only ever be populated if Account::requestsSucceedWithChannel() is \c true, and * succeeded() has already been emitted on this ChannelRequest. Note that a PendingChannelRequest * being successfully finished already implies succeeded() has been emitted. * * \return A pointer to the Channel object, or a null ChannelPtr if there isn't any. */ ChannelPtr ChannelRequest::channel() const { return mPriv->chan; } /** * Proceed with the channel request. * * The client that created this object calls this method when it has connected * signal handlers for succeeded() and failed(). Note that this is done * automatically when using PendingChannelRequest. * * \return A PendingOperation which will emit PendingOperation::finished * when the call has finished. */ PendingOperation *ChannelRequest::proceed() { return new PendingVoid(mPriv->baseInterface->Proceed(), ChannelRequestPtr(this)); } /** * Return the ChannelRequestInterface for this ChannelRequest class. This method is * protected since the convenience methods provided by this class should * always be used instead of the interface by users of the class. * * \return A pointer to the existing Client::ChannelRequestInterface object for this * ChannelRequest object. */ Client::ChannelRequestInterface *ChannelRequest::baseInterface() const { return mPriv->baseInterface; } void ChannelRequest::gotMainProperties(QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; QVariantMap props; if (!reply.isError()) { debug() << "Got reply to Properties::GetAll(ChannelRequest)"; props = reply.value(); mPriv->extractMainProps(props, true); } else { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, reply.error()); warning().nospace() << "Properties::GetAll(ChannelRequest) failed with " << reply.error().name() << ": " << reply.error().message(); } watcher->deleteLater(); } void ChannelRequest::onAccountReady(PendingOperation *op) { if (op->isError()) { warning() << "Unable to make ChannelRequest.Account ready"; mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, false, op->errorName(), op->errorMessage()); return; } if (mPriv->propertiesDone && !isReady()) { mPriv->readinessHelper->setIntrospectCompleted(FeatureCore, true); } } void ChannelRequest::onLegacySucceeded() { if (mPriv->gotSWC) { return; } emit succeeded(ChannelPtr()); } void ChannelRequest::onSucceededWithChannel( const QDBusObjectPath &connPath, const QVariantMap &connProps, const QDBusObjectPath &chanPath, const QVariantMap &chanProps) { if (mPriv->gotSWC) { warning().nospace() << "Got SucceededWithChannel again for CR(" << objectPath() << ")!"; return; } mPriv->gotSWC = true; QList readyOps; QString connBusName = connPath.path().mid(1).replace( QLatin1String("/"), QLatin1String(".")); PendingReady *connReady = mPriv->connFact->proxy(connBusName, connPath.path(), mPriv->chanFact, mPriv->contactFact); ConnectionPtr conn = ConnectionPtr::qObjectCast(connReady->proxy()); readyOps.append(connReady); PendingReady *chanReady = mPriv->chanFact->proxy(conn, chanPath.path(), chanProps); mPriv->chan = ChannelPtr::qObjectCast(chanReady->proxy()); readyOps.append(chanReady); connect(new PendingComposite(readyOps, ChannelRequestPtr(this)), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onChanBuilt(Tp::PendingOperation*))); } void ChannelRequest::onChanBuilt(Tp::PendingOperation *op) { if (op->isError()) { warning() << "Failed to build Channel which the ChannelRequest succeeded with," << "succeeding with NULL channel:" << op->errorName() << ',' << op->errorMessage(); mPriv->chan.reset(); } emit succeeded(mPriv->chan); } /** * \fn void ChannelRequest::failed(const QString &errorName, * const QString &errorMessage) * * Emitted when the channel request has failed. No further * methods must not be called on it. * * \param errorName The name of a D-Bus error. * \param errorMessage The error message. * \sa succeeded() */ /** * \fn void ChannelRequest::succeeded(const Tp::ChannelPtr &channel) * * Emitted when the channel request has succeeded. No further * methods must not be called on it. * * The \a channel parameter can be used to observe the channel resulting from the request (e.g. for * it getting closed). The pointer may be NULL if the Channel Dispatcher implementation is too old. * Whether a non-NULL channel can be expected can be checked with * Account::requestsSucceedWithChannel(). * * If there is a channel, it will be of the subclass determined by and made ready (or not) according * to the settings of the ChannelFactory on the Account the request was made through. * * \param channel Pointer to a proxy for the resulting channel, if the Channel Dispatcher reported it. * \sa failed() */ /** * \class ChannelRequestHints * \ingroup clientchannelrequest * \headerfile TelepathyQt/channel-request.h * * \brief The ChannelRequestHints class represents a dictionary of metadata * provided by the channel requester when requesting a channel. */ struct TP_QT_NO_EXPORT ChannelRequestHints::Private : public QSharedData { Private() {} Private(const QVariantMap &hints) : hints(hints) {} QVariantMap hints; }; ChannelRequestHints::ChannelRequestHints() { } ChannelRequestHints::ChannelRequestHints(const QVariantMap &hints) : mPriv(new Private(hints)) { } ChannelRequestHints::ChannelRequestHints(const ChannelRequestHints &crh) : mPriv(crh.mPriv) { } ChannelRequestHints::~ChannelRequestHints() { } ChannelRequestHints &ChannelRequestHints::operator=(const ChannelRequestHints &other) { if (this == &other) { return *this; } this->mPriv = other.mPriv; return *this; } bool ChannelRequestHints::isValid() const { return mPriv.constData() != 0; } bool ChannelRequestHints::hasHint(const QString &reversedDomain, const QString &localName) const { if (!isValid()) { return false; } const QString qualifiedName = reversedDomain + QLatin1Char('.') + localName; return mPriv->hints.contains(qualifiedName); } QVariant ChannelRequestHints::hint(const QString &reversedDomain, const QString &localName) const { if (!isValid()) { return QVariant(); } const QString qualifiedName = reversedDomain + QLatin1Char('.') + localName; return mPriv->hints.value(qualifiedName); } void ChannelRequestHints::setHint(const QString &reversedDomain, const QString &localName, const QVariant &value) { const QString qualifiedName = reversedDomain + QLatin1Char('.') + localName; if (!isValid()) { mPriv = new Private(); } mPriv->hints.insert(qualifiedName, value); } QVariantMap ChannelRequestHints::allHints() const { return isValid() ? mPriv->hints : QVariantMap(); } } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/media-stream-handler.h0000664000175000017500000000337412470405660021357 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_media_stream_handler_h_HEADER_GUARD_ #define _TelepathyQt_media_stream_handler_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif /** * \addtogroup clientsideproxies Client-side proxies * * Proxy objects representing remote service objects accessed via D-Bus. * * In addition to providing direct access to methods, signals and properties * exported by the remote objects, some of these proxies offer features like * automatic inspection of remote object capabilities, property tracking, * backwards compatibility helpers for older services and other utilities. */ /** * \defgroup clientmstrh Media stream handler proxies * \ingroup clientsideproxies * * Proxy objects representing remote Telepathy MediaStreamHandler objects. */ #include #endif telepathy-qt-0.9.6~git1/TelepathyQt/call-stream.xml0000664000175000017500000000046212470405660020144 0ustar jrjr Call Stream interfaces, version 1 telepathy-qt-0.9.6~git1/TelepathyQt/simple-text-observer.h0000664000175000017500000000512012470405660021463 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_simple_text_observer_h_HEADER_GUARD_ #define _TelepathyQt_simple_text_observer_h_HEADER_GUARD_ #include #include #include namespace Tp { class Message; class PendingOperation; class ReceivedMessage; class TP_QT_EXPORT SimpleTextObserver : public QObject, public RefCounted { Q_OBJECT Q_DISABLE_COPY(SimpleTextObserver) public: static SimpleTextObserverPtr create(const AccountPtr &account); static SimpleTextObserverPtr create(const AccountPtr &account, const ContactPtr &contact); static SimpleTextObserverPtr create(const AccountPtr &account, const QString &contactIdentifier); virtual ~SimpleTextObserver(); AccountPtr account() const; QString contactIdentifier() const; QList textChats() const; Q_SIGNALS: void messageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken, const Tp::TextChannelPtr &channel); void messageReceived(const Tp::ReceivedMessage &message, const Tp::TextChannelPtr &channel); private Q_SLOTS: TP_QT_NO_EXPORT void onNewChannels(const QList &channels); TP_QT_NO_EXPORT void onChannelInvalidated(const Tp::ChannelPtr &channel); private: TP_QT_NO_EXPORT static SimpleTextObserverPtr create(const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization); TP_QT_NO_EXPORT SimpleTextObserver(const AccountPtr &account, const QString &contactIdentifier, bool requiresNormalization); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/ConnectionInterfaceCapabilitiesInterface0000664000175000017500000000045012470405660025211 0ustar jrjr#ifndef _TelepathyQt_ConnectionInterfaceCapabilitiesInterface_HEADER_GUARD_ #define _TelepathyQt_ConnectionInterfaceCapabilitiesInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/and-filter.h0000664000175000017500000000445412470405660017421 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2010 Collabora Ltd. * @copyright Copyright (C) 2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_and_filter_h_HEADER_GUARD_ #define _TelepathyQt_and_filter_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include namespace Tp { template class AndFilter : public Filter { public: static SharedPtr > create( const QList > > &filters = QList > >()) { return SharedPtr >(new AndFilter(filters)); } inline virtual ~AndFilter() { } inline virtual bool isValid() const { Q_FOREACH (const SharedPtr > &filter, mFilters) { if (!filter || !filter->isValid()) { return false; } } return true; } inline virtual bool matches(const SharedPtr &t) const { if (!isValid()) { return false; } Q_FOREACH (const SharedPtr > &filter, mFilters) { if (!filter->matches(t)) { return false; } } return true; } inline QList > > filters() const { return mFilters; } private: AndFilter(const QList > > &filters) : Filter(), mFilters(filters) { } QList > > mFilters; }; } // Tp #endif telepathy-qt-0.9.6~git1/TelepathyQt/base-protocol-internal.h0000664000175000017500000001137412470405660021756 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2012 Collabora Ltd. * @copyright Copyright (C) 2012 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "TelepathyQt/_gen/svc-connection-manager.h" #include #include #include #include #include #include #include namespace Tp { class TP_QT_NO_EXPORT BaseProtocol::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QStringList interfaces READ interfaces) Q_PROPERTY(Tp::ParamSpecList parameters READ parameters) Q_PROPERTY(QStringList connectionInterfaces READ connectionInterfaces) Q_PROPERTY(Tp::RequestableChannelClassList requestableChannelClasses READ requestableChannelClasses) Q_PROPERTY(QString vcardField READ vcardField) Q_PROPERTY(QString englishName READ englishName) Q_PROPERTY(QString icon READ icon) Q_PROPERTY(QStringList authenticationTypes READ authenticationTypes) public: Adaptee(const QDBusConnection &dbusConnection, BaseProtocol *protocol); ~Adaptee(); QStringList interfaces() const; QStringList connectionInterfaces() const; ParamSpecList parameters() const; RequestableChannelClassList requestableChannelClasses() const; QString vcardField() const; QString englishName() const; QString icon() const; QStringList authenticationTypes() const; private Q_SLOTS: void identifyAccount(const QVariantMap ¶meters, const Tp::Service::ProtocolAdaptor::IdentifyAccountContextPtr &context); void normalizeContact(const QString &contactId, const Tp::Service::ProtocolAdaptor::NormalizeContactContextPtr &context); public: BaseProtocol *mProtocol; }; class TP_QT_NO_EXPORT BaseProtocolAddressingInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QStringList addressableVCardFields READ addressableVCardFields) Q_PROPERTY(QStringList addressableURISchemes READ addressableURISchemes) public: Adaptee(BaseProtocolAddressingInterface *interface); ~Adaptee(); QStringList addressableVCardFields() const; QStringList addressableURISchemes() const; private Q_SLOTS: void normalizeVCardAddress(const QString &vcardField, const QString &vcardAddress, const Tp::Service::ProtocolInterfaceAddressingAdaptor::NormalizeVCardAddressContextPtr &context); void normalizeContactURI(const QString &uri, const Tp::Service::ProtocolInterfaceAddressingAdaptor::NormalizeContactURIContextPtr &context); public: BaseProtocolAddressingInterface *mInterface; }; class TP_QT_NO_EXPORT BaseProtocolAvatarsInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(QStringList supportedAvatarMIMETypes READ supportedAvatarMIMETypes) Q_PROPERTY(uint minimumAvatarHeight READ minimumAvatarHeight) Q_PROPERTY(uint minimumAvatarWidth READ minimumAvatarWidth) Q_PROPERTY(uint recommendedAvatarHeight READ recommendedAvatarHeight) Q_PROPERTY(uint recommendedAvatarWidth READ recommendedAvatarWidth) Q_PROPERTY(uint maximumAvatarHeight READ maximumAvatarHeight) Q_PROPERTY(uint maximumAvatarWidth READ maximumAvatarWidth) Q_PROPERTY(uint maximumAvatarBytes READ maximumAvatarBytes) public: Adaptee(BaseProtocolAvatarsInterface *interface); ~Adaptee(); QStringList supportedAvatarMIMETypes() const; uint minimumAvatarHeight() const; uint minimumAvatarWidth() const; uint recommendedAvatarHeight() const; uint recommendedAvatarWidth() const; uint maximumAvatarHeight() const; uint maximumAvatarWidth() const; uint maximumAvatarBytes() const; public: BaseProtocolAvatarsInterface *mInterface; }; class TP_QT_NO_EXPORT BaseProtocolPresenceInterface::Adaptee : public QObject { Q_OBJECT Q_PROPERTY(Tp::SimpleStatusSpecMap statuses READ statuses) public: Adaptee(BaseProtocolPresenceInterface *interface); ~Adaptee(); SimpleStatusSpecMap statuses() const; public: BaseProtocolPresenceInterface *mInterface; }; } telepathy-qt-0.9.6~git1/TelepathyQt/ChannelTypeTextInterface0000664000175000017500000000040512470405660022036 0ustar jrjr#ifndef _TelepathyQt_ChannelTypeTextInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelTypeTextInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/main.dox0000664000175000017500000001076712470405660016667 0ustar jrjr/* * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \mainpage Telepathy-Qt * * \section Introduction * * Telepathy-Qt is a Qt high-level binding for \telepathy. * * \telepathy is a \dbus framework for unifying real time communication, including instant * messaging, voice calls and video calls. It abstracts differences between protocols to * provide a unified interface for applications. * * Releases can be found here. * * Development is done in the git repository found here. * * \li All Classes * * \section getting_started Getting Started * \li \subpage installation * * \section examples Examples * * This is the list of examples in Telepathy-Qt's examples directory. * The examples demonstrate Telepathy-Qt features in small, self-contained * programs. They are not all designed to be impressive when you run them, * but their source code is carefully written to show good Telepathy-Qt * programming practices. * * \li \subpage accounts_example * \li \subpage contact_messenger_example * \li \subpage protocols_example * \li \subpage roster_example * * \section developer_resources Further Information * \li \subpage bugreport * \li \subpage mailing_lists * \li \subpage async_model * \li \subpage shared_ptr */ /** * \page installation Installation * * \section installation_from_source Installing from source on Linux * * \subsection installation_from_source_requirements Requirements * * Building Telepathy-Qt requires: * \li Qt, including QtDBus * \li GNU make * \li pkg-config * \li libxslt, xsltproc * \li Python * * For the full set of regression tests to run, you'll also need: * \li telepathy-glib * * and to build the example VoIP call UI (examples/call), you'll need: * \li telepathy-glib * \li telepathy-farstream * * \li GStreamer \n * * Building also requires the cmake build system. * * \subsection installation_from_source_building Building * * After installing all dependencies, run: * * \verbatim $ mkdir build; cd build $ cmake .. $ make $ make install \endverbatim */ /** * \page bugreport How to report a bug * * Before reporting a bug, please check the * Bug Tracker to see if the issue is already known. * * Always include the following information in your bug report: * \li The version of Telepathy-Qt you are using * * Please submit the bug report, feature request or "to-do" item * * here. */ /** * \page mailing_lists Mailing Lists * * General * discussion list\n * This list should be used for general discussion about \telepathy usage, * development. * * * Commits list\n * Subscribe to this list to follow the commits. * * * Bugs list\n * Subscribe to this list to follow the bug reports. */ telepathy-qt-0.9.6~git1/TelepathyQt/ChannelInterfaceSASLAuthenticationInterface0000664000175000017500000000045312470405660025536 0ustar jrjr#ifndef _TelepathyQt_ChannelInterfaceSASLAuthenticationInterface_HEADER_GUARD_ #define _TelepathyQt_ChannelInterfaceSASLAuthenticationInterface_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #define IN_TP_QT_HEADER #endif #include #undef IN_TP_QT_HEADER #endif // vim:set ft=cpp: telepathy-qt-0.9.6~git1/TelepathyQt/key-file.h0000664000175000017500000000445712470405660017104 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008 Collabora Ltd. * @copyright Copyright (C) 2008 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_key_file_h_HEADER_GUARD_ #define _TelepathyQt_key_file_h_HEADER_GUARD_ #include #include #include class QString; class QStringList; #ifndef DOXYGEN_SHOULD_SKIP_THIS namespace Tp { class TP_QT_NO_EXPORT KeyFile { public: enum Status { None = 0, NoError, NotFoundError, AccessError, FormatError, }; KeyFile(); KeyFile(const KeyFile &other); KeyFile(const QString &fileName); ~KeyFile(); KeyFile &operator=(const KeyFile &other); void setFileName(const QString &fileName); QString fileName() const; Status status() const; void setGroup(const QString &group); QString group() const; QStringList allGroups() const; QStringList allKeys() const; QStringList keys() const; bool contains(const QString &key) const; QString rawValue(const QString &key) const; QString value(const QString &key) const; QStringList valueAsStringList(const QString &key) const; static bool unescapeString(const QByteArray &data, int from, int to, QString &result); static bool unescapeStringList(const QByteArray &data, int from, int to, QStringList &result); private: struct Private; friend struct Private; Private *mPriv; }; } Q_DECLARE_METATYPE(Tp::KeyFile); #endif /* DOXYGEN_SHOULD_SKIP_THIS */ #endif telepathy-qt-0.9.6~git1/TelepathyQt/simple-observer.cpp0000664000175000017500000005537312470405660021053 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2011 Collabora Ltd. * @copyright Copyright (C) 2011 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "TelepathyQt/simple-observer-internal.h" #include "TelepathyQt/_gen/simple-observer.moc.hpp" #include "TelepathyQt/_gen/simple-observer-internal.moc.hpp" #include "TelepathyQt/debug-internal.h" #include #include #include #include #include #include #include #include #include namespace Tp { QHash >, WeakPtr > SimpleObserver::Private::observers; uint SimpleObserver::Private::numObservers = 0; SimpleObserver::Private::Private(SimpleObserver *parent, const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QString &contactIdentifier, bool requiresNormalization, const QList &extraChannelFeatures) : parent(parent), account(account), channelFilter(channelFilter), contactIdentifier(contactIdentifier), extraChannelFeatures(extraChannelFeatures) { QSet normalizedChannelFilter = channelFilter.toSet(); QPair > observerUniqueId( account->dbusConnection().baseService(), normalizedChannelFilter); observer = SharedPtr(observers.value(observerUniqueId)); if (!observer) { SharedPtr fakeAccountFactory = FakeAccountFactory::create( account->dbusConnection()); cr = ClientRegistrar::create( AccountFactoryPtr::qObjectCast(fakeAccountFactory), account->connectionFactory(), account->channelFactory(), account->contactFactory()); QString observerName = QString(QLatin1String("TpQtSO_%1_%2")) .arg(account->dbusConnection().baseService() .replace(QLatin1String(":"), QLatin1String("_")) .replace(QLatin1String("."), QLatin1String("_"))) .arg(numObservers++); observer = SharedPtr(new Observer(cr, fakeAccountFactory, normalizedChannelFilter.toList(), observerName)); if (!cr->registerClient(observer, observerName, false)) { warning() << "Unable to register observer" << observerName; observer.reset(); cr.reset(); return; } debug() << "Observer" << observerName << "registered"; observers.insert(observerUniqueId, observer); } else { debug() << "Observer" << observer->observerName() << "already registered and matches filter, using it"; cr = ClientRegistrarPtr(observer->clientRegistrar()); } observer->registerExtraChannelFeatures(extraChannelFeatures); observer->registerAccount(account); if (contactIdentifier.isEmpty() || !requiresNormalization) { normalizedContactIdentifier = contactIdentifier; } else { parent->connect(account.data(), SIGNAL(connectionChanged(Tp::ConnectionPtr)), SLOT(onAccountConnectionChanged(Tp::ConnectionPtr))); } parent->connect(observer.data(), SIGNAL(newChannels(Tp::AccountPtr,QList)), SLOT(onNewChannels(Tp::AccountPtr,QList))); parent->connect(observer.data(), SIGNAL(channelInvalidated(Tp::AccountPtr,Tp::ChannelPtr,QString,QString)), SLOT(onChannelInvalidated(Tp::AccountPtr,Tp::ChannelPtr,QString,QString))); } bool SimpleObserver::Private::filterChannel(const AccountPtr &channelAccount, const ChannelPtr &channel) { if (channelAccount != account) { return false; } if (contactIdentifier.isEmpty()) { return true; } QString targetId = channel->immutableProperties().value( TP_QT_IFACE_CHANNEL + QLatin1String(".TargetID")).toString(); if (targetId != normalizedContactIdentifier) { // we didn't filter per contact, let's filter here return false; } return true; } void SimpleObserver::Private::insertChannels(const AccountPtr &channelsAccount, const QList &newChannels) { QSet match; foreach (const ChannelPtr &channel, newChannels) { if (!channels.contains(channel) && filterChannel(channelsAccount, channel)) { match.insert(channel); } } if (match.isEmpty()) { return; } channels.unite(match); emit parent->newChannels(match.toList()); } void SimpleObserver::Private::removeChannel(const AccountPtr &channelAccount, const ChannelPtr &channel, const QString &errorName, const QString &errorMessage) { if (!channels.contains(channel) || !filterChannel(channelAccount, channel)) { return; } channels.remove(channel); emit parent->channelInvalidated(channel, errorName, errorMessage); } void SimpleObserver::Private::processChannelsQueue() { if (channelsQueue.isEmpty()) { return; } while (!channelsQueue.isEmpty()) { (this->*(channelsQueue.dequeue()))(); } } void SimpleObserver::Private::processNewChannelsQueue() { NewChannelsInfo info = newChannelsQueue.dequeue(); insertChannels(info.channelsAccount, info.channels); } void SimpleObserver::Private::processChannelsInvalidationQueue() { ChannelInvalidationInfo info = channelsInvalidationQueue.dequeue(); removeChannel(info.channelAccount, info.channel, info.errorName, info.errorMessage); } SimpleObserver::Private::Observer::Observer(const WeakPtr &cr, const SharedPtr &fakeAccountFactory, const ChannelClassSpecList &channelFilter, const QString &observerName) : AbstractClient(), QObject(), AbstractClientObserver(channelFilter, true), mCr(cr), mFakeAccountFactory(fakeAccountFactory), mObserverName(observerName) { } SimpleObserver::Private::Observer::~Observer() { // no need to delete channel wrappers here as they have 'this' as parent // no need to delete context infos here as this observer will never be deleted before all // PendingComposites finish (hold reference to this), which will properly delete them // no need to unregister this observer here as the client registrar destructor will // unregister it } void SimpleObserver::Private::Observer::observeChannels( const MethodInvocationContextPtr<> &context, const AccountPtr &account, const ConnectionPtr &connection, const QList &channels, const ChannelDispatchOperationPtr &dispatchOperation, const QList &requestsSatisfied, const ObserverInfo &observerInfo) { if (!mAccounts.contains(account)) { context->setFinished(); return; } QList readyOps; QList newChannels; foreach (const ChannelPtr &channel, channels) { if (mIncompleteChannels.contains(channel) || mChannels.contains(channel)) { // we are already observing this channel continue; } // this shouldn't happen, but in any case if (!channel->isValid()) { warning() << "Channel received to observe is invalid. " "Ignoring channel"; continue; } SimpleObserver::Private::ChannelWrapper *wrapper = new SimpleObserver::Private::ChannelWrapper(account, channel, featuresFor(ChannelClassSpec(channel->immutableProperties())), this); mIncompleteChannels.insert(channel, wrapper); connect(wrapper, SIGNAL(channelInvalidated(Tp::AccountPtr,Tp::ChannelPtr,QString,QString)), SLOT(onChannelInvalidated(Tp::AccountPtr,Tp::ChannelPtr,QString,QString))); newChannels.append(channel); readyOps.append(wrapper->becomeReady()); } if (readyOps.isEmpty()) { context->setFinished(); return; } PendingComposite *pc = new PendingComposite(readyOps, false /* failOnFirstError */, SharedPtr(this)); mObserveChannelsInfo.insert(pc, new ContextInfo(context, account, newChannels)); connect(pc, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onChannelsReady(Tp::PendingOperation*))); } void SimpleObserver::Private::Observer::onChannelInvalidated(const AccountPtr &channelAccount, const ChannelPtr &channel, const QString &errorName, const QString &errorMessage) { if (mIncompleteChannels.contains(channel)) { // we are still handling the channel, wait for onChannelsReady that will properly remove // it from mChannels return; } emit channelInvalidated(channelAccount, channel, errorName, errorMessage); Q_ASSERT(mChannels.contains(channel)); delete mChannels.take(channel); } void SimpleObserver::Private::Observer::onChannelsReady(PendingOperation *op) { ContextInfo *info = mObserveChannelsInfo.value(op); foreach (const ChannelPtr &channel, info->channels) { Q_ASSERT(mIncompleteChannels.contains(channel)); ChannelWrapper *wrapper = mIncompleteChannels.take(channel); mChannels.insert(channel, wrapper); } emit newChannels(info->account, info->channels); foreach (const ChannelPtr &channel, info->channels) { ChannelWrapper *wrapper = mChannels.value(channel); if (!channel->isValid()) { mChannels.remove(channel); emit channelInvalidated(info->account, channel, channel->invalidationReason(), channel->invalidationMessage()); delete wrapper; } } mObserveChannelsInfo.remove(op); info->context->setFinished(); delete info; } Features SimpleObserver::Private::Observer::featuresFor( const ChannelClassSpec &channelClass) const { Features features; foreach (const ChannelClassFeatures &spec, mExtraChannelFeatures) { if (spec.first.isSubsetOf(channelClass)) { features.unite(spec.second); } } return features; } SimpleObserver::Private::ChannelWrapper::ChannelWrapper(const AccountPtr &channelAccount, const ChannelPtr &channel, const Features &extraChannelFeatures, QObject *parent) : QObject(parent), mChannelAccount(channelAccount), mChannel(channel), mExtraChannelFeatures(extraChannelFeatures) { connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString))); } PendingOperation *SimpleObserver::Private::ChannelWrapper::becomeReady() { PendingOperation *op; if (!mChannel->isReady(mExtraChannelFeatures)) { // The channel factory passed to the Account used by SimpleObserver does // not contain the extra features, request them op = mChannel->becomeReady(mExtraChannelFeatures); } else { op = new PendingSuccess(mChannel); } return op; } void SimpleObserver::Private::ChannelWrapper::onChannelInvalidated(DBusProxy *proxy, const QString &errorName, const QString &errorMessage) { Q_ASSERT(proxy == mChannel.data()); emit channelInvalidated(mChannelAccount, mChannel, errorName, errorMessage); } /** * \class SimpleObserver * \ingroup utils * \headerfile TelepathyQt/simple-observer.h * * \brief The SimpleObserver class provides an easy way to track channels * in an account and can be optionally filtered by a contact. */ /** * Create a new SimpleObserver object. * * Events will be signalled for all channels in \a account that match * \a channelFilter for all contacts. * * \param channelFilter A specification of the channels in which this observer * is interested. * \param account The account used to listen to events. * \param extraChannelFeatures Extra channel features to be enabled. All channels emitted in * newChannels() will have the extra features that match their * immutable properties enabled. * \return An SimpleObserverPtr object pointing to the newly created SimpleObserver object. */ SimpleObserverPtr SimpleObserver::create( const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QList &extraChannelFeatures) { return create(account, channelFilter, QString(), false, extraChannelFeatures); } /** * Create a new SimpleObserver object. * * Events will be signalled for all channels in \a account established with * \a contact, if not null, and that match \a channelFilter. * * \param channelFilter A specification of the channels in which this observer * is interested. * \param account The account used to listen to events. * \param contact The contact used to filter events. * \param extraChannelFeatures Extra channel features to be enabled. All channels emitted in * newChannels() will have the extra features that match their * immutable properties enabled. * \return An SimpleObserverPtr object pointing to the newly created SimpleObserver object. */ SimpleObserverPtr SimpleObserver::create( const AccountPtr &account, const ChannelClassSpecList &channelFilter, const ContactPtr &contact, const QList &extraChannelFeatures) { if (contact) { return create(account, channelFilter, contact->id(), false, extraChannelFeatures); } return create(account, channelFilter, QString(), false, extraChannelFeatures); } /** * Create a new SimpleObserver object. * * Events will be signalled for all channels in \a account established * with a contact identified by \a contactIdentifier, if non-empty, and that match * \a channelFilter. * * \param channelFilter A specification of the channels in which this observer * is interested. * \param account The account used to listen to events. * \param contactIdentifier The identifier of the contact used to filter events. * \param extraChannelFeatures Extra channel features to be enabled. All channels emitted in * newChannels() will have the extra features that match their * immutable properties enabled. * \return An SimpleObserverPtr object pointing to the newly created SimpleObserver object. */ SimpleObserverPtr SimpleObserver::create( const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QString &contactIdentifier, const QList &extraChannelFeatures) { return create(account, channelFilter, contactIdentifier, true, extraChannelFeatures); } SimpleObserverPtr SimpleObserver::create( const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QString &contactIdentifier, bool requiresNormalization, const QList &extraChannelFeatures) { return SimpleObserverPtr(new SimpleObserver(account, channelFilter, contactIdentifier, requiresNormalization, extraChannelFeatures)); } /** * Construct a new SimpleObserver object. * * \param cr The ClientRegistrar used to register this observer. * \param channelFilter The channel filter used by this observer. * \param account The account used to listen to events. * \param extraChannelFeatures Extra channel features to be enabled. All channels emitted in * newChannels() will have the extra features that match their * immutable properties enabled. * \return An SimpleObserverPtr object pointing to the newly created SimpleObserver object. */ SimpleObserver::SimpleObserver(const AccountPtr &account, const ChannelClassSpecList &channelFilter, const QString &contactIdentifier, bool requiresNormalization, const QList &extraChannelFeatures) : mPriv(new Private(this, account, channelFilter, contactIdentifier, requiresNormalization, extraChannelFeatures)) { if (mPriv->observer) { // populate our channels list with current observer channels QHash > channels; foreach (const Private::ChannelWrapper *wrapper, mPriv->observer->channels()) { channels[wrapper->channelAccount()].append(wrapper->channel()); } QHash >::const_iterator it = channels.constBegin(); QHash >::const_iterator end = channels.constEnd(); for (; it != end; ++it) { onNewChannels(it.key(), it.value()); } if (requiresNormalization) { debug() << "Contact id requires normalization. " "Queueing events until it is normalized"; onAccountConnectionChanged(account->connection()); } } } /** * Class destructor. */ SimpleObserver::~SimpleObserver() { delete mPriv; } /** * Return the account used to listen to events. * * \return A pointer to the Account object. */ AccountPtr SimpleObserver::account() const { return mPriv->account; } /** * Return a specification of the channels that this observer is interested. * * \return The specification of the channels as a list of ChannelClassSpec objects. */ ChannelClassSpecList SimpleObserver::channelFilter() const { return mPriv->channelFilter; } /** * Return the extra channel features to be enabled based on the channels immutable properties. * * \return The features as a list of ChannelClassFeatures objects. */ QList SimpleObserver::extraChannelFeatures() const { return mPriv->extraChannelFeatures; } /** * Return the channels being observed. * * \return A list of pointers to Channel objects. */ QList SimpleObserver::channels() const { return mPriv->channels.toList(); } /** * Return the identifier of the contact used to filter events, or an empty string if none was * provided at construction. * * \return The identifier of the contact. */ QString SimpleObserver::contactIdentifier() const { return mPriv->contactIdentifier; } void SimpleObserver::onAccountConnectionChanged(const Tp::ConnectionPtr &connection) { if (connection) { connect(connection->becomeReady(Connection::FeatureConnected), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountConnectionConnected())); } } void SimpleObserver::onAccountConnectionConnected() { ConnectionPtr conn = mPriv->account->connection(); // check here again as the account connection may have changed and the op failed if (!conn || conn->status() != ConnectionStatusConnected) { return; } debug() << "Normalizing contact id" << mPriv->contactIdentifier; ContactManagerPtr contactManager = conn->contactManager(); connect(contactManager->contactsForIdentifiers(QStringList() << mPriv->contactIdentifier), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactConstructed(Tp::PendingOperation*))); } void SimpleObserver::onContactConstructed(Tp::PendingOperation *op) { if (op->isError()) { // what should we do here? retry? wait for a new connection? warning() << "Normalizing contact id failed with" << op->errorName() << " : " << op->errorMessage(); return; } PendingContacts *pc = qobject_cast(op); Q_ASSERT((pc->contacts().size() + pc->invalidIdentifiers().size()) == 1); if (!pc->invalidIdentifiers().isEmpty()) { warning() << "Normalizing contact id failed with invalid id" << mPriv->contactIdentifier; return; } ContactPtr contact = pc->contacts().first(); debug() << "Contact id" << mPriv->contactIdentifier << "normalized to" << contact->id(); mPriv->normalizedContactIdentifier = contact->id(); mPriv->processChannelsQueue(); // disconnect all account signals we are handling disconnect(mPriv->account.data(), 0, this, 0); } void SimpleObserver::onNewChannels(const AccountPtr &channelsAccount, const QList &channels) { if (!mPriv->contactIdentifier.isEmpty() && mPriv->normalizedContactIdentifier.isEmpty()) { mPriv->newChannelsQueue.append(Private::NewChannelsInfo(channelsAccount, channels)); mPriv->channelsQueue.append(&SimpleObserver::Private::processNewChannelsQueue); return; } mPriv->insertChannels(channelsAccount, channels); } void SimpleObserver::onChannelInvalidated(const AccountPtr &channelAccount, const ChannelPtr &channel, const QString &errorName, const QString &errorMessage) { if (!mPriv->contactIdentifier.isEmpty() && mPriv->normalizedContactIdentifier.isEmpty()) { mPriv->channelsInvalidationQueue.append(Private::ChannelInvalidationInfo(channelAccount, channel, errorName, errorMessage)); mPriv->channelsQueue.append(&SimpleObserver::Private::processChannelsInvalidationQueue); return; } mPriv->removeChannel(channelAccount, channel, errorName, errorMessage); } /** * \fn void SimpleObserver::newChannels(const QList &channels) * * Emitted whenever new channels that match this observer's criteria are created. * * \param channels The new channels. */ /** * \fn void SimpleObserver::channelInvalidated(const Tp::ChannelPtr &channel, * const QString &errorName, const QString &errorMessage) * * Emitted whenever a channel that is being observed is invalidated. * * \param channel The channel that was invalidated. * \param errorName A D-Bus error name (a string in a subset * of ASCII, prefixed with a reversed domain name). * \param errorMessage A debugging message associated with the error. */ } // Tp telepathy-qt-0.9.6~git1/TelepathyQt/base-channel.h0000664000175000017500000007571012470405660017717 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2013 Matthias Gehre * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_base_channel_h_HEADER_GUARD_ #define _TelepathyQt_base_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include #include class QString; namespace Tp { class TP_QT_EXPORT BaseChannel : public DBusService { Q_OBJECT Q_DISABLE_COPY(BaseChannel) public: static BaseChannelPtr create(BaseConnection* connection, const QString &channelType, uint targetHandle, uint targetHandleType) { return BaseChannelPtr(new BaseChannel(QDBusConnection::sessionBus(), connection, channelType, targetHandle, targetHandleType)); } virtual ~BaseChannel(); QVariantMap immutableProperties() const; bool registerObject(DBusError *error = NULL); virtual QString uniqueName() const; QString channelType() const; QList interfaces() const; AbstractChannelInterfacePtr interface(const QString &interfaceName) const; uint targetHandle() const; QString targetID() const; uint targetHandleType() const; bool requested() const; uint initiatorHandle() const; QString initiatorID() const; Tp::ChannelDetails details() const; void setInitiatorHandle(uint initiatorHandle); void setInitiatorID(const QString &initiatorID); void setTargetID(const QString &targetID); void setRequested(bool requested); void close(); bool plugInterface(const AbstractChannelInterfacePtr &interface); Q_SIGNALS: void closed(); protected: BaseChannel(const QDBusConnection &dbusConnection, BaseConnection* connection, const QString &channelType, uint targetHandle, uint targetHandleType); virtual bool registerObject(const QString &busName, const QString &objectPath, DBusError *error); private: class Adaptee; friend class Adaptee; class Private; friend class Private; Private *mPriv; }; class TP_QT_EXPORT AbstractChannelInterface : public AbstractDBusServiceInterface { Q_OBJECT Q_DISABLE_COPY(AbstractChannelInterface) public: AbstractChannelInterface(const QString &interfaceName); virtual ~AbstractChannelInterface(); private: friend class BaseChannel; class Private; friend class Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelTextType : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelTextType) public: static BaseChannelTextTypePtr create(BaseChannel* channel) { return BaseChannelTextTypePtr(new BaseChannelTextType(channel)); } template static SharedPtr create(BaseChannel* channel) { return SharedPtr( new BaseChannelTextTypeSubclass(channel)); } typedef Callback2 CreateChannelCallback; CreateChannelCallback createChannel; typedef Callback2 EnsureChannelCallback; EnsureChannelCallback ensureChannel; virtual ~BaseChannelTextType(); QVariantMap immutableProperties() const; Tp::RequestableChannelClassList requestableChannelClasses; typedef Callback1 MessageAcknowledgedCallback; void setMessageAcknowledgedCallback(const MessageAcknowledgedCallback &cb); Tp::MessagePartListList pendingMessages(); /* Convenience function */ void addReceivedMessage(const Tp::MessagePartList &message); private Q_SLOTS: void sent(uint timestamp, uint type, QString text); protected: BaseChannelTextType(BaseChannel* channel); void acknowledgePendingMessages(const Tp::UIntList &IDs, DBusError* error); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelMessagesInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelMessagesInterface) public: static BaseChannelMessagesInterfacePtr create(BaseChannelTextType* textTypeInterface, QStringList supportedContentTypes, UIntList messageTypes, uint messagePartSupportFlags, uint deliveryReportingSupport) { return BaseChannelMessagesInterfacePtr(new BaseChannelMessagesInterface(textTypeInterface, supportedContentTypes, messageTypes, messagePartSupportFlags, deliveryReportingSupport)); } template static SharedPtr create() { return SharedPtr( new BaseChannelMessagesInterfaceSubclass()); } virtual ~BaseChannelMessagesInterface(); QVariantMap immutableProperties() const; QStringList supportedContentTypes(); Tp::UIntList messageTypes(); uint messagePartSupportFlags(); uint deliveryReportingSupport(); Tp::MessagePartListList pendingMessages(); void messageSent(const Tp::MessagePartList &content, uint flags, const QString &messageToken); typedef Callback3 SendMessageCallback; void setSendMessageCallback(const SendMessageCallback &cb); protected: QString sendMessage(const Tp::MessagePartList &message, uint flags, DBusError* error); private Q_SLOTS: void pendingMessagesRemoved(const Tp::UIntList &messageIDs); void messageReceived(const Tp::MessagePartList &message); private: BaseChannelMessagesInterface(BaseChannelTextType* textType, QStringList supportedContentTypes, Tp::UIntList messageTypes, uint messagePartSupportFlags, uint deliveryReportingSupport); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelServerAuthenticationType : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelServerAuthenticationType) public: static BaseChannelServerAuthenticationTypePtr create(const QString &authenticationMethod) { return BaseChannelServerAuthenticationTypePtr(new BaseChannelServerAuthenticationType(authenticationMethod)); } template static SharedPtr create(const QString &authenticationMethod) { return SharedPtr( new BaseChannelServerAuthenticationTypeSubclass(authenticationMethod)); } virtual ~BaseChannelServerAuthenticationType(); QVariantMap immutableProperties() const; private Q_SLOTS: private: BaseChannelServerAuthenticationType(const QString &authenticationMethod); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelCaptchaAuthenticationInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelCaptchaAuthenticationInterface) public: static BaseChannelCaptchaAuthenticationInterfacePtr create(bool canRetryCaptcha) { return BaseChannelCaptchaAuthenticationInterfacePtr(new BaseChannelCaptchaAuthenticationInterface(canRetryCaptcha)); } template static SharedPtr create(bool canRetryCaptcha) { return SharedPtr( new BaseChannelCaptchaAuthenticationInterfaceSubclass(canRetryCaptcha)); } virtual ~BaseChannelCaptchaAuthenticationInterface(); QVariantMap immutableProperties() const; typedef Callback4 GetCaptchasCallback; void setGetCaptchasCallback(const GetCaptchasCallback &cb); typedef Callback3 GetCaptchaDataCallback; void setGetCaptchaDataCallback(const GetCaptchaDataCallback &cb); typedef Callback2 AnswerCaptchasCallback; void setAnswerCaptchasCallback(const AnswerCaptchasCallback &cb); typedef Callback3 CancelCaptchaCallback; void setCancelCaptchaCallback(const CancelCaptchaCallback &cb); void setCaptchaStatus(uint status); void setCaptchaError(const QString &busName); void setCaptchaErrorDetails(const QVariantMap &error); private Q_SLOTS: private: BaseChannelCaptchaAuthenticationInterface(bool canRetryCaptcha); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelSASLAuthenticationInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelSASLAuthenticationInterface) public: static BaseChannelSASLAuthenticationInterfacePtr create(const QStringList &availableMechanisms, bool hasInitialData, bool canTryAgain, const QString &authorizationIdentity, const QString &defaultUsername, const QString &defaultRealm, bool maySaveResponse) { return BaseChannelSASLAuthenticationInterfacePtr(new BaseChannelSASLAuthenticationInterface(availableMechanisms, hasInitialData, canTryAgain, authorizationIdentity, defaultUsername, defaultRealm, maySaveResponse)); } template static SharedPtr create(const QStringList &availableMechanisms, bool hasInitialData, bool canTryAgain, const QString &authorizationIdentity, const QString &defaultUsername, const QString &defaultRealm, bool maySaveResponse) { return SharedPtr( new BaseChannelSASLAuthenticationInterfaceSubclass(availableMechanisms, hasInitialData, canTryAgain, authorizationIdentity, defaultUsername, defaultRealm, maySaveResponse)); } virtual ~BaseChannelSASLAuthenticationInterface(); QVariantMap immutableProperties() const; QStringList availableMechanisms() const; bool hasInitialData() const; bool canTryAgain() const; QString authorizationIdentity() const; QString defaultUsername() const; QString defaultRealm() const; bool maySaveResponse() const; uint saslStatus() const; void setSaslStatus(uint status, const QString &reason, const QVariantMap &details); QString saslError() const; void setSaslError(const QString &saslError); QVariantMap saslErrorDetails() const; void setSaslErrorDetails(const QVariantMap &saslErrorDetails); typedef Callback2 StartMechanismCallback; void setStartMechanismCallback(const StartMechanismCallback &cb); void startMechanism(const QString &mechanism, DBusError *error); typedef Callback3 StartMechanismWithDataCallback; void setStartMechanismWithDataCallback(const StartMechanismWithDataCallback &cb); void startMechanismWithData(const QString &mechanism, const QByteArray &initialData, DBusError *error); typedef Callback2 RespondCallback; void setRespondCallback(const RespondCallback &cb); void respond(const QByteArray &responseData, DBusError *error); typedef Callback1 AcceptSASLCallback; void setAcceptSaslCallback(const AcceptSASLCallback &cb); void acceptSasl(DBusError *error); typedef Callback3 AbortSASLCallback; void setAbortSaslCallback(const AbortSASLCallback &cb); void abortSasl(uint reason, const QString &debugMessage, DBusError *error); void newChallenge(const QByteArray &challengeData); protected: BaseChannelSASLAuthenticationInterface(const QStringList &availableMechanisms, bool hasInitialData, bool canTryAgain, const QString &authorizationIdentity, const QString &defaultUsername, const QString &defaultRealm, bool maySaveResponse); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelSecurableInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelSecurableInterface) public: static BaseChannelSecurableInterfacePtr create() { return BaseChannelSecurableInterfacePtr(new BaseChannelSecurableInterface()); } template static SharedPtr create() { return SharedPtr( new BaseChannelSecurableInterfaceSubclass()); } virtual ~BaseChannelSecurableInterface(); QVariantMap immutableProperties() const; bool encrypted() const; void setEncrypted(bool encrypted); bool verified() const; void setVerified(bool verified); protected: BaseChannelSecurableInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelChatStateInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelChatStateInterface) public: static BaseChannelChatStateInterfacePtr create() { return BaseChannelChatStateInterfacePtr(new BaseChannelChatStateInterface()); } template static SharedPtr create() { return SharedPtr( new BaseChannelChatStateInterfaceSubclass()); } virtual ~BaseChannelChatStateInterface(); QVariantMap immutableProperties() const; Tp::ChatStateMap chatStates() const; void setChatStates(const Tp::ChatStateMap &chatStates); typedef Callback2 SetChatStateCallback; void setSetChatStateCallback(const SetChatStateCallback &cb); void setChatState(uint state, DBusError *error); void chatStateChanged(uint contact, uint state); protected: BaseChannelChatStateInterface(); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelGroupInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelGroupInterface) public: static BaseChannelGroupInterfacePtr create(ChannelGroupFlags initialFlags, uint selfHandle) { return BaseChannelGroupInterfacePtr(new BaseChannelGroupInterface(initialFlags, selfHandle)); } template static SharedPtr create(ChannelGroupFlags initialFlags, uint selfHandle) { return SharedPtr( new BaseChannelGroupInterfaceSubclass(initialFlags, selfHandle)); } virtual ~BaseChannelGroupInterface(); QVariantMap immutableProperties() const; typedef Callback3 RemoveMembersCallback; void setRemoveMembersCallback(const RemoveMembersCallback &cb); typedef Callback3 AddMembersCallback; void setAddMembersCallback(const AddMembersCallback &cb); /* Adds a contact to this group. No-op if already in this group */ void addMembers(const Tp::UIntList &handles, const QStringList &identifiers); void removeMembers(const Tp::UIntList &handles); private Q_SLOTS: private: BaseChannelGroupInterface(ChannelGroupFlags initialFlags, uint selfHandle); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelCallType : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelCallType) public: static BaseChannelCallTypePtr create(BaseChannel* channel, bool hardwareStreaming, uint initialTransport, bool initialAudio, bool initialVideo, QString initialAudioName, QString initialVideoName, bool mutableContents = false) { return BaseChannelCallTypePtr(new BaseChannelCallType(channel, hardwareStreaming, initialTransport, initialAudio, initialVideo, initialAudioName, initialVideoName, mutableContents)); } template static SharedPtr create(BaseChannel* channel, bool hardwareStreaming, uint initialTransport, bool initialAudio, bool initialVideo, QString initialAudioName, QString initialVideoName, bool mutableContents = false) { return SharedPtr( new BaseChannelCallTypeSubclass(channel, hardwareStreaming, initialTransport, initialAudio, initialVideo, initialAudioName, initialVideoName, mutableContents)); } typedef Callback2 CreateChannelCallback; CreateChannelCallback createChannel; typedef Callback2 EnsureChannelCallback; EnsureChannelCallback ensureChannel; virtual ~BaseChannelCallType(); QVariantMap immutableProperties() const; Tp::ObjectPathList contents(); QVariantMap callStateDetails(); uint callState(); uint callFlags(); Tp::CallStateReason callStateReason(); bool hardwareStreaming(); Tp::CallMemberMap callMembers(); Tp::HandleIdentifierMap memberIdentifiers(); uint initialTransport(); bool initialAudio(); bool initialVideo(); QString initialAudioName(); QString initialVideoName(); bool mutableContents(); typedef Callback1 AcceptCallback; void setAcceptCallback(const AcceptCallback &cb); typedef Callback4 HangupCallback; void setHangupCallback(const HangupCallback &cb); typedef Callback1 SetRingingCallback; void setSetRingingCallback(const SetRingingCallback &cb); typedef Callback1 SetQueuedCallback; void setSetQueuedCallback(const SetQueuedCallback &cb); typedef Callback4 AddContentCallback; void setAddContentCallback(const AddContentCallback &cb); void setCallState(const Tp::CallState &state, uint flags, const Tp::CallStateReason &stateReason, const QVariantMap &callStateDetails); void setMembersFlags(const Tp::CallMemberMap &flagsChanged, const Tp::HandleIdentifierMap &identifiers, const Tp::UIntList &removed, const Tp::CallStateReason &reason); BaseCallContentPtr addContent(const QString &name, const Tp::MediaStreamType &type, const Tp::MediaStreamDirection &direction); void addContent(BaseCallContentPtr content); Tp::RequestableChannelClassList requestableChannelClasses; protected: BaseChannelCallType(BaseChannel* channel, bool hardwareStreaming, uint initialTransport, bool initialAudio, bool initialVideo, QString initialAudioName, QString initialVideoName, bool mutableContents = false); private: void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelHoldInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelHoldInterface) public: static BaseChannelHoldInterfacePtr create() { return BaseChannelHoldInterfacePtr(new BaseChannelHoldInterface()); } template static SharedPtr create() { return SharedPtr( new BaseChannelHoldInterfaceSubclass()); } virtual ~BaseChannelHoldInterface(); QVariantMap immutableProperties() const; Tp::LocalHoldState getHoldState() const; Tp::LocalHoldStateReason getHoldReason() const; void setHoldState(const Tp::LocalHoldState &state, const Tp::LocalHoldStateReason &reason); typedef Callback3 SetHoldStateCallback; void setSetHoldStateCallback(const SetHoldStateCallback &cb); Q_SIGNALS: void holdStateChanged(const Tp::LocalHoldState &state, const Tp::LocalHoldStateReason &reason); private: BaseChannelHoldInterface(); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelMergeableConferenceInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelMergeableConferenceInterface) public: static BaseChannelMergeableConferenceInterfacePtr create() { return BaseChannelMergeableConferenceInterfacePtr(new BaseChannelMergeableConferenceInterface()); } template static SharedPtr create() { return SharedPtr( new BaseChannelMergeableConferenceInterfaceSubclass()); } virtual ~BaseChannelMergeableConferenceInterface(); QVariantMap immutableProperties() const; void merge(const QDBusObjectPath &channel); typedef Callback2 MergeCallback; void setMergeCallback(const MergeCallback &cb); private: BaseChannelMergeableConferenceInterface(); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelSplittableInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelSplittableInterface) public: static BaseChannelSplittableInterfacePtr create() { return BaseChannelSplittableInterfacePtr(new BaseChannelSplittableInterface()); } template static SharedPtr create() { return SharedPtr( new BaseChannelSplittableInterfaceSubclass()); } virtual ~BaseChannelSplittableInterface(); QVariantMap immutableProperties() const; void split(); typedef Callback1 SplitCallback; void setSplitCallback(const SplitCallback &cb); private: BaseChannelSplittableInterface(); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelConferenceInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelConferenceInterface) public: static BaseChannelConferenceInterfacePtr create(Tp::ObjectPathList initialChannels = Tp::ObjectPathList(), Tp::UIntList initialInviteeHandles = Tp::UIntList(), QStringList initialInviteeIDs = QStringList(), QString invitationMessage = QString(), ChannelOriginatorMap originalChannels = ChannelOriginatorMap()) { return BaseChannelConferenceInterfacePtr(new BaseChannelConferenceInterface(initialChannels, initialInviteeHandles, initialInviteeIDs, invitationMessage, originalChannels)); } template static SharedPtr create(Tp::ObjectPathList initialChannels = Tp::ObjectPathList(), Tp::UIntList initialInviteeHandles = Tp::UIntList(), QStringList initialInviteeIDs = QStringList(), QString invitationMessage = QString(), ChannelOriginatorMap originalChannels = ChannelOriginatorMap()) { return SharedPtr( new BaseChannelConferenceInterfaceSubclass(initialChannels, initialInviteeHandles, initialInviteeIDs, invitationMessage, originalChannels)); } virtual ~BaseChannelConferenceInterface(); QVariantMap immutableProperties() const; Tp::ObjectPathList channels() const; Tp::ObjectPathList initialChannels() const; Tp::UIntList initialInviteeHandles() const; QStringList initialInviteeIDs() const; QString invitationMessage() const; ChannelOriginatorMap originalChannels() const; void mergeChannel(const QDBusObjectPath &channel, uint channelHandle, const QVariantMap &properties); void removeChannel(const QDBusObjectPath &channel, const QVariantMap &details); private: BaseChannelConferenceInterface(Tp::ObjectPathList initialChannels, Tp::UIntList initialInviteeHandles, QStringList initialInviteeIDs, QString invitationMessage, ChannelOriginatorMap originalChannels); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; class TP_QT_EXPORT BaseChannelSMSInterface : public AbstractChannelInterface { Q_OBJECT Q_DISABLE_COPY(BaseChannelSMSInterface) public: static BaseChannelSMSInterfacePtr create(bool flash, bool smsChannel) { return BaseChannelSMSInterfacePtr(new BaseChannelSMSInterface(flash, smsChannel)); } template static SharedPtr create(bool flash, bool smsChannel) { return SharedPtr( new BaseChannelSMSInterfaceSubclass(flash, smsChannel)); } virtual ~BaseChannelSMSInterface(); QVariantMap immutableProperties() const; typedef Callback2 GetSMSLengthCallback; void setGetSMSLengthCallback(const GetSMSLengthCallback &cb); bool flash() const; bool smsChannel() const; Q_SIGNALS: void smsChannelChanged(bool smsChannel); private: BaseChannelSMSInterface(bool flash, bool smsChannel); void createAdaptor(); class Adaptee; friend class Adaptee; struct Private; friend struct Private; Private *mPriv; }; } #endif telepathy-qt-0.9.6~git1/TelepathyQt/pending-channel.h0000664000175000017500000000601212470405660020416 0ustar jrjr/** * This file is part of TelepathyQt * * @copyright Copyright (C) 2008-2010 Collabora Ltd. * @copyright Copyright (C) 2008-2010 Nokia Corporation * @license LGPL 2.1 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _TelepathyQt_pending_channel_h_HEADER_GUARD_ #define _TelepathyQt_pending_channel_h_HEADER_GUARD_ #ifndef IN_TP_QT_HEADER #error IN_TP_QT_HEADER #endif #include #include #include #include #include namespace Tp { class Connection; class HandledChannelNotifier; class TP_QT_EXPORT PendingChannel : public PendingOperation { Q_OBJECT Q_DISABLE_COPY(PendingChannel) public: ~PendingChannel(); ConnectionPtr connection() const; bool yours() const; const QString &channelType() const; uint targetHandleType() const; uint targetHandle() const; QVariantMap immutableProperties() const; ChannelPtr channel() const; HandledChannelNotifier *handledChannelNotifier() const; private Q_SLOTS: TP_QT_NO_EXPORT void onConnectionCreateChannelFinished( QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onConnectionEnsureChannelFinished( QDBusPendingCallWatcher *watcher); TP_QT_NO_EXPORT void onChannelReady(Tp::PendingOperation *op); TP_QT_NO_EXPORT void onHandlerError(const QString &errorName, const QString &errorMessage); TP_QT_NO_EXPORT void onHandlerChannelReceived( const Tp::ChannelPtr &channel); TP_QT_NO_EXPORT void onAccountCreateChannelFinished( Tp::PendingOperation *op); private: friend class Account; friend class ConnectionLowlevel; TP_QT_NO_EXPORT PendingChannel(const ConnectionPtr &connection, const QString &errorName, const QString &errorMessage); TP_QT_NO_EXPORT PendingChannel(const ConnectionPtr &connection, const QVariantMap &request, bool create, int timeout = -1); TP_QT_NO_EXPORT PendingChannel(const AccountPtr &account, const QVariantMap &request, const QDateTime &userActionTime, bool create); TP_QT_NO_EXPORT PendingChannel(const QString &errorName, const QString &errorMessage); struct Private; friend struct Private; Private *mPriv; }; } // Tp #endif