Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:16.0:Staging:A
accounts-qml-module
accounts-qml-module-0.7git.20231028T182937~05e7...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File accounts-qml-module-0.7git.20231028T182937~05e79eb.obscpio of Package accounts-qml-module
07070100000000000081A4000000000000000000000001653D36F100000098000000000000000000000000000000000000003E00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/.gitignore/coverage-html /coverage.info *.gcda *.gcno *.moc *.o Makefile.* Makefile moc_* /src/qmldir /src/Ubuntu /tests/mock/libsignon-qt5.so* /tests/tst_plugin 07070100000001000081A4000000000000000000000001653D36F10000046A000000000000000000000000000000000000004200000000accounts-qml-module-0.7git.20231028T182937~05e79eb/.gitlab-ci.ymlimage: ubuntu:xenial cache: key: apt-cache paths: - apt-cache/ before_script: - export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR - apt-get update -yq && apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y qt5-qmake qtdeclarative5-dev qtdeclarative5-dev-tools qtchooser pkg-config libaccounts-qt5-dev libsignon-qt5-dev - apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y dbus-test-runner xvfb qtdeclarative5-qtquick2-plugin lcov gcovr build_amd64: stage: build script: - export QT_SELECT=qt5 - mkdir build - cd build - qmake CONFIG+=debug CONFIG+=coverage .. - make -j 4 artifacts: paths: - ./ test_amd64: stage: test script: - cd build - make coverage-html dependencies: - build_amd64 artifacts: paths: - ./ pages: stage: deploy script: - cd build - make install INSTALL_ROOT=out - cd .. - mkdir public - cp -a build/coverage-html public/coverage - cp -a build/out/usr/share/accounts-qml-module/doc/html/* public dependencies: - test_amd64 artifacts: paths: - public 07070100000002000081A4000000000000000000000001653D36F100006742000000000000000000000000000000000000003B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/COPYING GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it! 07070100000003000081A4000000000000000000000001653D36F10000037C000000000000000000000000000000000000003D00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/README.mdQML bindings for libaccounts-qt and libsignon-qt ========================================================== This QML module provides an API to manage the user's online accounts and get their authentication data. It's a tiny wrapper around the Qt-based APIs of [libaccounts-qt][] and [libsignon-qt][]. It is part of the accounts-sso project: https://gitlab.com/groups/accounts-sso Dependencies ------------ The project depends on QtQml, QtTest, [libaccounts-qt][] and [libsignon-qt][]. Licence ------- The library is licensed under the GNU LGPL version 2.1. Resources --------- [API reference documentation](http://accounts-sso.gitlab.io/accounts-qml-module/index.html) [Official source code repository](https://gitlab.com/accounts-sso/accounts-qml-module) [libaccounts-qt]: https://gitlab.com/accounts-sso/libaccounts-qt [libsignon-qt]: https://gitlab.com/accounts-sso/libsignon-qt 07070100000004000081A4000000000000000000000001653D36F10000019E000000000000000000000000000000000000004B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/accounts-qml-module.proinclude(common-vars.pri) include(common-project-config.pri) !CONFIG(no_docs): include(doc/doc.pri) TEMPLATE = subdirs CONFIG += ordered SUBDIRS = \ src \ tests include(common-installs-config.pri) DISTNAME = $${PROJECT_NAME}-$${PROJECT_VERSION} dist.commands = "git archive --format=tar --prefix=$${DISTNAME}/ HEAD | bzip2 -9 > $${DISTNAME}.tar.bz2" dist.depends = distclean QMAKE_EXTRA_TARGETS += dist 07070100000005000081A4000000000000000000000001653D36F100000882000000000000000000000000000000000000004E00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/common-installs-config.pri#----------------------------------------------------------------------------- # Common installation configuration for all projects. #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # setup the installation prefix #----------------------------------------------------------------------------- INSTALL_PREFIX = /usr # default installation prefix # default prefix can be overriden by defining PREFIX when running qmake isEmpty( PREFIX ) { message("====") message("==== NOTE: To override the installation path run: `qmake PREFIX=/custom/path'") message("==== (current installation path is `$${INSTALL_PREFIX}')") } else { INSTALL_PREFIX = $${PREFIX} message("====") message("==== install prefix set to `$${INSTALL_PREFIX}'") } #----------------------------------------------------------------------------- # default installation target for applications #----------------------------------------------------------------------------- contains( TEMPLATE, app ) { target.path = $${INSTALL_PREFIX}/bin INSTALLS += target message("====") message("==== INSTALLS += target") } #----------------------------------------------------------------------------- # default installation target for libraries #----------------------------------------------------------------------------- contains( TEMPLATE, lib ) { target.path = $${INSTALL_PREFIX}/lib INSTALLS += target message("====") message("==== INSTALLS += target") # reset the .pc file's `prefix' variable #include( tools/fix-pc-prefix.pri ) } #----------------------------------------------------------------------------- # target for header files #----------------------------------------------------------------------------- !isEmpty( headers.files ) { headers.path = $${INSTALL_PREFIX}/include/$${TARGET} INSTALLS += headers message("====") message("==== INSTALLS += headers") } else { message("====") message("==== NOTE: Remember to add your API headers into `headers.files' for installation!") } # End of File 07070100000006000081A4000000000000000000000001653D36F100000211000000000000000000000000000000000000004D00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/common-project-config.pri#----------------------------------------------------------------------------- # Common configuration for all projects. #----------------------------------------------------------------------------- # we don't like warnings... QMAKE_CXXFLAGS += -Wno-write-strings # Disable RTTI QMAKE_CXXFLAGS += -fno-exceptions -fno-rtti equals(QT_MAJOR_VERSION, 6) { QMAKE_CXXFLAGS += -std=c++17 } else { QMAKE_CXXFLAGS += -std=c++11 } TOP_SRC_DIR = $$PWD TOP_BUILD_DIR = $${TOP_SRC_DIR}/$${BUILD_DIR} include(coverage.pri) 07070100000007000081A4000000000000000000000001653D36F10000030E000000000000000000000000000000000000004300000000accounts-qml-module-0.7git.20231028T182937~05e79eb/common-vars.pri#----------------------------------------------------------------------------- # Common variables for all projects. #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Project name (used e.g. in include file and doc install path). # remember to update debian/* files if you changes this #----------------------------------------------------------------------------- PROJECT_NAME = accounts-qml-module #----------------------------------------------------------------------------- # Project version # remember to update debian/* files if you changes this #----------------------------------------------------------------------------- PROJECT_VERSION = 0.7 # End of File 07070100000008000081A4000000000000000000000001653D36F10000076D000000000000000000000000000000000000004000000000accounts-qml-module-0.7git.20231028T182937~05e79eb/coverage.pri# Coverage CONFIG(coverage) { OBJECTS_DIR = MOC_DIR = TOP_SRC_DIR = $$PWD LIBS += -lgcov QMAKE_CXXFLAGS += --coverage QMAKE_LDFLAGS += --coverage QMAKE_EXTRA_TARGETS += coverage cov QMAKE_EXTRA_TARGETS += clean-gcno clean-gcda coverage-html \ generate-coverage-html clean-coverage-html coverage-gcovr \ generate-gcovr generate-coverage-gcovr clean-coverage-gcovr clean-gcno.commands = \ "@echo Removing old coverage instrumentation"; \ "find -name '*.gcno' -print | xargs -r rm" clean-gcda.commands = \ "@echo Removing old coverage results"; \ "find -name '*.gcda' -print | xargs -r rm" coverage-html.depends = clean-gcda check generate-coverage-html generate-coverage-html.commands = \ "@echo Collecting coverage data"; \ "lcov --directory $${TOP_SRC_DIR} --capture --output-file coverage.info --no-checksum --compat-libtool"; \ "lcov --extract coverage.info \"*/src/*.cpp\" -o coverage.info"; \ "lcov --remove coverage.info \"moc_*.cpp\" -o coverage.info"; \ "LANG=C genhtml --prefix $${TOP_SRC_DIR} --output-directory coverage-html --title \"Code Coverage\" --legend --show-details coverage.info" clean-coverage-html.depends = clean-gcda clean-coverage-html.commands = \ "lcov --directory $${TOP_SRC_DIR} -z"; \ "rm -rf coverage.info coverage-html" coverage-gcovr.depends = clean-gcda check generate-coverage-gcovr generate-coverage-gcovr.commands = \ "@echo Generating coverage GCOVR report"; \ "gcovr -x -r $${TOP_SRC_DIR} -o $${TOP_SRC_DIR}/coverage.xml -e \".*/moc_.*\" -e \"tests/.*\" -e \".*\\.h\"" clean-coverage-gcovr.depends = clean-gcda clean-coverage-gcovr.commands = \ "rm -rf $${TOP_SRC_DIR}/coverage.xml" QMAKE_CLEAN += *.gcda *.gcno coverage.info coverage.xml } 07070100000009000041ED000000000000000000000002653D36F100000000000000000000000000000000000000000000003700000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc0707010000000A000081A4000000000000000000000001653D36F10000023B000000000000000000000000000000000000005B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/accounts-qml-module-common.qdocconf#include(compat.qdocconf) project = OnlineAccounts QML API description = QML API for using online accounts outputdir = html outputformats = HTML headerdirs = ../src sourcedirs = ../src sources.fileextensions = "*.qml *.qdoc *.cpp" exampledirs = ./examples imagedirs = ./images HTML.templatedir = . HTML.nobreadcrumbs = "true" HTML.stylesheets = qtquick.css HTML.headerstyles = " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/qtquick.css\" />\n" HTML.endheader = "</head>\n" HTML.footer = "<div class=\"footer\">Copyright (C) 2013 Canonical Ltd.</div>\n" 0707010000000B000081A4000000000000000000000001653D36F10000033D000000000000000000000000000000000000005B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/accounts-qml-module-ubuntu.qdocconfinclude(accounts-qml-module-common.qdocconf) include(ubuntu-appdev-site-header.qdocconf) include(ubuntu-appdev-site-footer.qdocconf) HTML.stylesheets = \ doc/css/reset.css \ doc/css/qtquick.css \ doc/css/base.css \ doc/css/scratch.css HTML.headerstyles = \ "<link rel=\"stylesheet\" type=\"text/css\" href=\"http://fonts.googleapis.com/css?family=Ubuntu:400,400italic\">\n" \ "<link rel=\"stylesheet\" type=\"text/css\" href=\"http://fonts.googleapis.com/css?family=Ubuntu+Mono:400\">\n" \ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/reset.css\" />\n" \ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/qtquick.css\" />\n" \ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/base.css\" />\n" \ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/scratch.css\" />\n" 0707010000000C000081A4000000000000000000000001653D36F10000014E000000000000000000000000000000000000005400000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/accounts-qml-module.qdocconfinclude(accounts-qml-module-common.qdocconf) HTML.templatedir = . HTML.nobreadcrumbs = "true" HTML.stylesheets = qtquick.css HTML.headerstyles = " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/qtquick.css\" />\n" HTML.endheader = "</head>\n" HTML.footer = "<div class=\"footer\">Copyright (C) 2013 Canonical Ltd.</div>\n" 0707010000000D000041ED000000000000000000000002653D36F100000000000000000000000000000000000000000000003B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/css0707010000000E000081A4000000000000000000000001653D36F100002E37000000000000000000000000000000000000004400000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/css/base.css/** * Ubuntu Developer base stylesheet * * A base stylesheet containing site-wide styles * * @project Ubuntu Developer * @version 1.0 * @author Canonical Web Team: Steve Edwards * @copyright 2011 Canonical Ltd. */ /** * @section Global */ body { font-family: 'Ubuntu', 'Ubuntu Beta', UbuntuBeta, Ubuntu, 'Bitstream Vera Sans', 'DejaVu Sans', Tahoma, sans-serif; font-size: 13px; line-height: 1.4; color: #333; } a { color: #dd4814; text-decoration: none; outline: 0; } p, dl { margin-bottom: 10px; } strong { font-weight: bold; } em { font-style: italic; } code{ padding: 10px; font-family: 'Ubuntu Mono', 'Consolas', 'Monaco', 'DejaVu Sans Mono', Courier, monospace; background-color: #fdf6f2; display: block; margin-bottom: 10px; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } h1 { font-size: 36px; line-height: 1.1; margin-bottom: 20px; } article h1, h2 { font-size: 24px; line-height: 1.2; margin-bottom: 14px; } h3 { font-size: 16px; line-height: 1.3; margin-bottom: 8px; } h4 { font-weight: bold; } time { color:#999; } /** * @section Structure */ .header-login, .header-navigation div, .header-content div { margin: 0 auto; width: 940px; } .header-content h1{ background-color:#ffffff; display:inline-block; } .header-content h2{ background-color:#ffffff; display:table; } .header-login ul { margin: 4px 0; float: right; } .header-login li { margin-right: 10px; float: left; } .header-login a { color: #333; } .header-navigation { border-top: 2px solid #dd4814; border-bottom: 2px solid #dd4814; background-color: #fff; height: 54px; clear: right; overflow: hidden; } .header-navigation nav ul { border-right: 1px solid #dd4814; float: right; } .header-navigation nav li { border-left: 1px solid #dd4814; float: left; height: 54px; } .header-navigation nav a { padding: 18px 14px 0; font-size: 14px; display: block; height: 36px; } .header-navigation nav a:hover { background-color: #fcece7; } .header-navigation nav .current_page_item a, .header-navigation nav .current_page_parent a, .header-navigation nav .current_page_ancestor a { background-color: #dd4814; color: #fff; } .header-navigation input { margin: 12px 10px 0 10px; padding: 5px; border-top: 1px solid #a1a1a1; border-right: 1px solid #e0e0e0; border-bottom: 1px solid #fff; border-left: 1px solid #e0e0e0; width: 90px; font-style: italic; color: #ccc; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; -moz-box-shadow: inset 0 1px 1px #e0e0e0; -webkit-box-shadow: inset 0 1px 1px #e0e0e0; box-shadow: inset 0 1px 1px #e0e0e0; } .header-navigation h2 { margin: 18px 0 0 6px; text-transform: lowercase; font-size: 22px; color: #dd4814; float: left; } .header-navigation .logo-ubuntu { margin-top: 12px; float: left; } .header-content .header-navigation-secondary { margin-bottom: 40px; padding: 0; position: relative; z-index: 2; } .header-navigation-secondary div { padding: 0; border: 2px solid #dd4814; -moz-border-radius: 0px 0px 4px 4px; -webkit-border-radius: 0px 0px 4px 4px; border-radius: 0px 0px 4px 4px; background: #fff; border-top: 0px; width: 936px; } .header-navigation-secondary nav li { float: left; } .header-navigation-secondary nav li a { color: #333; display: block; height: 25px; padding: 8px 8px 0; } .header-navigation-secondary nav li:hover, .header-navigation-secondary nav .current_page_item a { background: url("../img/sec-nav-hover.gif"); } .header-content { padding-bottom: 30px; border-bottom: 1px solid #e0e0e0; -moz-box-shadow: 0 1px 3px #e0e0e0; -webkit-box-shadow: 0 1px 3px #e0e0e0; box-shadow: 0 1px 3px #e0e0e0; margin-bottom: 3px; position: relative; overflow: hidden; } footer { padding: 10px 10px 40px 10px; position: relative; -moz-border-radius: 0 0 4px 4px; -webkit-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; font-size: 12px; background: url("../img/background-footer.png") repeat scroll 0 0 #f7f6f5; } footer div { margin: 0 auto; padding: 0 10px; width: 940px; } footer a { color: #000; } footer nav ul { margin: 10px 17px 30px 0; width: 172px; display: inline-block; vertical-align: top; height: auto; zoom: 1; *display: inline; } footer nav ul.last { margin-right: 0; } footer nav li { margin-bottom: 8px; } footer nav li:first-child { font-weight: bold; } footer p { margin-bottom: 0; } #content { padding-top: 35px; } .arrow-nav { display: none; position: absolute; top: -1px; z-index: 3; } .shadow { margin: 30px 0 3px 0; border-bottom: 1px solid #e0e0e0; -moz-box-shadow: 0 2px 3px #e0e0e0; -webkit-box-shadow: 0 2px 3px #e0e0e0; box-shadow: 0 2px 3px #e0e0e0; height: 3px; } /** * @section Site-wide */ #content h2{ font-size:24px; } .box-orange { padding: 10px; border: 3px solid #dd4814; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } .box-orange .link-action-small { float: right; margin: 0 0 0 20px; } .link-bug { margin-left: 10px; color: #999; } .link-action { float: left; margin-bottom: 20px; padding: 8px 12px; display: block; background-color: #dd4814; color: #fff; -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; font-size: 16px; line-height: 1.3; border-top: 3px solid #e6633a; border-bottom: 3px solid #c03d14; } .link-action2 { float: left; display: block; color: #fff; font-size: 16px; line-height: 1.3; } .link-action2 span{ display:block; float:left; } .link-action2 .cta-left{ background:url(../img/button-cta-left.png) no-repeat; width:22px; height:48px; } .link-action2 .cta-center{ background:url(../img/button-cta-slice.png) repeat-x; line-height:45px; height:48px; } .link-action2 .cta-right{ background:url(../img/button-cta-right.png) no-repeat; width:22px; height:48px; } .link-action-small { float: left; display: block; color: #fff; font-size: 16px; } .link-action-small span{ display:block; float:left; height:42px; } .link-action-small .cta-left{ background:url(../img/button-cta-left-small.png) no-repeat; width:19px; } .link-action-small .cta-center{ background:url(../img/button-cta-slice-small.png) repeat-x; line-height:42px; } .link-action-small .cta-right{ background:url(../img/button-cta-right-small.png) no-repeat; width:19px; } .link-action:active { position: relative; top: 1px; } .link-action2:active { position: relative; top: 1px; } .link-action-small:active { position: relative; top: 1px; } .list-bullets li { margin-bottom: 10px; list-style: disc; list-style-position: inside; } .box { margin-bottom: 30px; padding: 15px; border: 1px solid #aea79f; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } .box-padded { margin-bottom: 30px; padding: 5px; border: 2px solid #aea79f; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; background: url("../img/pattern-featured.gif") repeat scroll 0 0 #ebe9e7; overflow: hidden; } .box-padded h3 { margin: 5px 0 10px 5px; } .box-padded div { padding: 10px; border: 1px solid #aea79f; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; background-color: #fff; overflow: hidden; } .box-padded li { padding: 0 10px; float: left; width: 211px; border-right: 1px dotted #aea79f; } .box-padded li.first { padding: 0; margin-bottom: 0; } .box-padded li.last { border: 0; width: 217px; } .box-padded img { margin: 0 10px 50px 0; float: left; -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } .box-clear { margin-bottom: 40px; } .box-clear .grid-4.first { margin-right: 15px; padding-right: 15px; } .box-clear .grid-4 { margin-left: 0; margin-right: 10px; padding-right: 10px; width: 298px; } .box-clear time { display: block; border-bottom: 1px dotted #aea79f; padding-bottom: 10px; margin-bottom: 10px; } .box-clear div.first { border-right: 1px dotted #aea79f; } .box-clear a { display: block; } .box-clear .rss { background: url("../img/rss.jpg") no-repeat scroll 0 center; padding-left: 20px; } .box-clear .location { display: block; margin-bottom: 1px; } .box-clear .last { margin: 0; padding-right: 0; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; width: 293px; } /* Widgets */ .ui-state-focus { outline: none; } .ui-accordion { border-bottom: 1px dotted #aea79f; } .ui-accordion a { display: block; } .ui-accordion h3 { margin-bottom: 0; border-top: 1px dotted #aea79f; position: relative; font-size: 13px; font-weight: bold; } .ui-accordion h3 a { padding: 10px 0; color: #333; } .ui-accordion h4 { margin-bottom: 5px; } .ui-accordion div fieldset { padding-bottom: 5px; } .ui-accordion div li, .ui-accordion div input { margin-bottom: 10px; } .ui-accordion .ui-icon { position: absolute; top: 15px; right: 0; display: block; width: 8px; height: 8px; background: url("../img/icon-accordion-inactive.png") 0 0 no-repeat transparent; } .ui-accordion .ui-state-active .ui-icon { background-image: url("../img/icon-accordion-active.png"); } .ui-accordion .current_page_item a { color: #333; } .container-tweet { -moz-border-radius: 4px 4px 4px 4px; -webkit-border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px; padding: 10px 10px 10px; background-color: #f7f7f7; } .container-tweet .tweet-follow { margin-top: 10px; margin-bottom: -10px; padding-left: 55px; padding-bottom: 6px; background: url("../img/tweet-follow.png") 0 5px no-repeat; display: block; } .container-tweet .tweet-follow span { font-size: 16px; font-weight: bold; line-height: 1.2; display: block; } .tweet a { display: inline; } .tweet .tweet_text { padding: 10px; background-color: #fff; -moz-border-radius: 4px 4px 4px 4px; -webkit-border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px; border: 1px solid #dd4814; font-size: 16px; display: block; clear: both; } .tweet.tweet-small .tweet_text { font-size: inherit; } .tweet .tweet_text a { color: #333; } .tweet .tweet_time, .tweet .tweet_user_and_time { padding: 15px 0 10px 0; position: relative; top: -2px; background: url("../img/tweet-arrow.png") no-repeat; display: block; } .tweet .tweet_odd .tweet_time, .tweet .tweet_odd .tweet_user_and_time { background-position: right 0; float: right; } .tweet .tweet_even .tweet_time, .tweet .tweet_even .tweet_user_and_time { background-position: left 0; float: left; } /* Search */ #content .list-search li { list-style-type:none; border:0px; margin-bottom: 15px; padding-top: 15px; } /* Blog */ .blog-article #nav-single { margin-top: 30px; margin-bottom: 30px; } .blog-article #nav-single .nav-next { float: right; } .blog-article article header .entry-meta { margin-bottom: 20px; } .blog-article article .entry-meta { color: #999; } .blog-article #respond form input[type="submit"] { float: left; cursor: pointer; margin-bottom: 20px; padding: 8px 12px; display: block; background-color: #dd4814; color: #fff; -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; font-size: 16px; line-height: 1.3; border-top: 3px solid #e6633a; border-left: 3px solid #e6633a; border-right: 3px solid #e6633a; border-bottom: 3px solid #c03d14; } .blog-article #respond form input[type="submit"]:active { position: relative; top: 1px; } .alignnone{ float:left; margin:10px 20px 10px 0; } .alignleft{ float:left; margin:10px 20px 10px 0; } .alignright{ float:right; margin:10px 0 10px 20px; } .aligncenter{ float:left; margin:10px 20px 10px 0; } .entry-content h2, .entry-content h3{ margin-top:20px; } .entry-content ul li{ list-style-type: circle; margin-left:16px; } .entry-content hr{ border:none; border-top: 1px dotted #AEA79F; } 0707010000000F000081A4000000000000000000000001653D36F1000033E9000000000000000000000000000000000000004700000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/css/qtquick.css@media screen { /* basic elements */ html { color: #000000; background: #FFFFFF; } table { border-collapse: collapse; border-spacing: 0; } fieldset, img { border: 0; max-width:100%; } address, caption, cite, code, dfn, em, strong, th, var, optgroup { font-style: inherit; font-weight: inherit; } del, ins { text-decoration: none; } ol li { list-style: decimal; } ul li { list-style: none; } caption, th { text-align: left; } h1.title { font-weight: bold; font-size: 150%; } h0 { font-weight: bold; font-size: 130%; } h1, h2, h3, h4, h5, h6 { font-size: 100%; } q:before, q:after { content: ''; } abbr, acronym { border: 0; font-variant: normal; } sup, sub { vertical-align: baseline; } tt, .qmlreadonly span, .qmldefault span { word-spacing:0.5em; } legend { color: #000000; } strong { font-weight: bold; } em { font-style: italic; } body { margin: 0 1.5em 0 1.5em; font-family: ubuntu; line-height: normal } a { color: #00732F; text-decoration: none; } hr { background-color: #E6E6E6; border: 1px solid #E6E6E6; height: 1px; width: 100%; text-align: left; margin: 1.5em 0 1.5em 0; } pre { border: 1px solid #DDDDDD; -moz-border-radius: 0.7em 0.7em 0.7em 0.7em; -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em; border-radius: 0.7em 0.7em 0.7em 0.7em; padding: 1em 1em 1em 1em; overflow-x: auto; } table, pre { -moz-border-radius: 0.7em 0.7em 0.7em 0.7em; -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em; border-radius: 0.7em 0.7em 0.7em 0.7em; background-color: #F6F6F6; border: 1px solid #E6E6E6; border-collapse: separate; margin-bottom: 2.5em; } pre { font-size: 90%; display: block; overflow:hidden; } thead { margin-top: 0.5em; font-weight: bold } th { padding: 0.5em 1.5em 0.5em 1em; background-color: #E1E1E1; border-left: 1px solid #E6E6E6; } td { padding: 0.25em 1.5em 0.25em 1em; } td.rightAlign { padding: 0.25em 0.5em 0.25em 1em; } table tr.odd { border-left: 1px solid #E6E6E6; background-color: #F6F6F6; color: black; } table tr.even { border-left: 1px solid #E6E6E6; background-color: #ffffff; color: #202020; } div.float-left { float: left; margin-right: 2em } div.float-right { float: right; margin-left: 2em } span.comment { color: #008B00; } span.string, span.char { color: #000084; } span.number { color: #a46200; } span.operator { color: #202020; } span.keyword { color: #840000; } span.name { color: black } span.type { font-weight: bold } span.type a:visited { color: #0F5300; } span.preprocessor { color: #404040 } /* end basic elements */ /* font style elements */ .heading { font-weight: bold; font-size: 125%; } .subtitle { font-size: 110% } .small-subtitle { font-size: 100% } .red { color:red; } /* end font style elements */ /* global settings*/ .header, .footer { display: block; clear: both; overflow: hidden; } /* end global settings*/ /* header elements */ .header .qtref { color: #00732F; font-weight: bold; font-size: 130%; } .header .content { margin-left: 5px; margin-top: 5px; margin-bottom: 0.5em; } .header .breadcrumb { font-size: 90%; padding: 0.5em 0 0.5em 1em; margin: 0; background-color: #fafafa; height: 1.35em; border-bottom: 1px solid #d1d1d1; } .header .breadcrumb ul { margin: 0; padding: 0; } .header .content { word-wrap: break-word; } .header .breadcrumb ul li { float: left; background: url(../images/breadcrumb.png) no-repeat 0 3px; padding-left: 1.5em; margin-left: 1.5em; } .header .breadcrumb ul li.last { font-weight: normal; } .header .breadcrumb ul li a { color: #00732F; } .header .breadcrumb ul li.first { background-image: none; padding-left: 0; margin-left: 0; } .header .content ol li { background: none; margin-bottom: 1.0em; margin-left: 1.2em; padding-left: 0 } .header .content li { background: url(../images/bullet_sq.png) no-repeat 0 5px; margin-bottom: 1em; padding-left: 1.2em; } /* end header elements */ /* content elements */ .content h1 { font-weight: bold; font-size: 130% } .content h2 { font-weight: bold; font-size: 120%; width: 100%; } .content h3 { font-weight: bold; font-size: 110%; width: 100%; } .content table p { margin: 0 } .content ul { padding-left: 2.5em; } .content li { padding-top: 0.25em; padding-bottom: 0.25em; } .content ul img { vertical-align: middle; } .content a:visited { color: #4c0033; text-decoration: none; } .content a:visited:hover { color: #4c0033; text-decoration: underline; } a:hover { color: #4c0033; text-decoration: underline; } descr p a { text-decoration: underline; } .descr p a:visited { text-decoration: underline; } .alphaChar{ width:95%; background-color:#F6F6F6; border:1px solid #E6E6E6; -moz-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; font-size:12pt; padding-left:10px; margin-top:10px; margin-bottom:10px; } .flowList{ /*vertical-align:top;*/ /*margin:20px auto;*/ column-count:3; -webkit-column-count:3; -moz-column-count:3; /* column-width:100%; -webkit-column-width:200px; -col-column-width:200px; */ column-gap:41px; -webkit-column-gap:41px; -moz-column-gap:41px; column-rule: 1px dashed #ccc; -webkit-column-rule: 1px dashed #ccc; -moz-column-rule: 1px dashed #ccc; } .flowList dl{ } .flowList dd{ /*display:inline-block;*/ margin-left:10px; min-width:250px; line-height: 1.5; min-width:100%; min-height:15px; } .flowList dd a{ } .mainContent { padding-left:5px; } .content .flowList p{ padding:0px; } .content .alignedsummary { margin: 15px; } .qmltype { text-align: center; font-size: 120%; } .qmlreadonly { padding-left: 5px; float: right; color: #254117; } .qmldefault { padding-left: 5px; float: right; color: red; } .qmldoc { } .generic .alphaChar{ margin-top:5px; } .generic .odd .alphaChar{ background-color: #F6F6F6; } .generic .even .alphaChar{ background-color: #FFFFFF; } .memItemRight{ padding: 0.25em 1.5em 0.25em 0; } .highlightedCode { margin: 1.0em; } .annotated td { padding: 0.25em 0.5em 0.25em 0.5em; } .toc { font-size: 80% } .header .content .toc ul { padding-left: 0px; } .content .toc h3 { border-bottom: 0px; margin-top: 0px; } .content .toc h3 a:hover { color: #00732F; text-decoration: none; } .content .toc .level2 { margin-left: 1.5em; } .content .toc .level3 { margin-left: 3.0em; } .content ul li { background: url(../images/bullet_sq.png) no-repeat 0 0.7em; padding-left: 1em } .content .toc li { background: url(../images/bullet_dn.png) no-repeat 0 5px; padding-left: 1em } .relpage { -moz-border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; border: 1px solid #DDDDDD; padding: 25px 25px; clear: both; } .relpage ul { float: none; padding: 1.5em; } h3.fn, span.fn { -moz-border-radius:7px 7px 7px 7px; -webkit-border-radius:7px 7px 7px 7px; border-radius:7px 7px 7px 7px; background-color: #F6F6F6; border-width: 1px; border-style: solid; border-color: #E6E6E6; font-weight: bold; word-spacing:3px; padding:3px 5px; } .functionIndex { font-size:12pt; word-spacing:10px; margin-bottom:10px; background-color: #F6F6F6; border-width: 1px; border-style: solid; border-color: #E6E6E6; -moz-border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; width:100%; } .centerAlign { text-align:center; } .rightAlign { text-align:right; } .leftAlign { text-align:left; } .topAlign{ vertical-align:top } .functionIndex a{ display:inline-block; } /* end content elements */ /* footer elements */ .footer { color: #393735; font-size: 0.75em; text-align: center; padding-top: 1.5em; padding-bottom: 1em; background-color: #E6E7E8; margin: 0; } .footer p { margin: 0.25em } .small { font-size: 0.5em; } /* end footer elements */ .item { float: left; position: relative; width: 100%; overflow: hidden; } .item .primary { margin-right: 220px; position: relative; } .item hr { margin-left: -220px; } .item .secondary { float: right; width: 200px; position: relative; } .item .cols { clear: both; display: block; } .item .cols .col { float: left; margin-left: 1.5%; } .item .cols .col.first { margin-left: 0; } .item .cols.two .col { width: 45%; } .item .box { margin: 0 0 10px 0; } .item .box h3 { margin: 0 0 10px 0; } .cols.unclear { clear:none; } } /* end of screen media */ /* start of print media */ @media print { input, textarea, .header, .footer, .toolbar, .feedback, .wrapper .hd, .wrapper .bd .sidebar, .wrapper .ft, #feedbackBox, #blurpage, .toc, .breadcrumb, .toolbar, .floatingResult { display: none; background: none; } .content { background: none; display: block; width: 100%; margin: 0; float: none; } } /* end of print media */ /* modify the TOC layouts */ div.toc ul { padding-left: 20px; } div.toc li { padding-left: 4px; } /* Remove the border around images*/ a img { border:none; } /*Add styling to the front pages*/ .threecolumn_area { padding-top: 20px; padding-bottom: 20px; } .threecolumn_piece { display: inline-block; margin-left: 78px; margin-top: 8px; padding: 0; vertical-align: top; width: 25.5%; } div.threecolumn_piece ul { list-style-type: none; padding-left: 0px; margin-top: 2px; } div.threecolumn_piece p { margin-bottom: 7px; color: #5C626E; text-decoration: none; font-weight: bold; } div.threecolumn_piece li { padding-left: 0px; margin-bottom: 5px; } div.threecolumn_piece a { font-weight: normal; } /* Add style to guide page*/ .fourcolumn_area { padding-top: 20px; padding-bottom: 20px; } .fourcolumn_piece { display: inline-block; margin-left: 35px; margin-top: 8px; padding: 0; vertical-align: top; width: 21.3%; } div.fourcolumn_piece ul { list-style-type: none; padding-left: 0px; margin-top: 2px; } div.fourcolumn_piece p { margin-bottom: 7px; color: #40444D; text-decoration: none; font-weight: bold; } div.fourcolumn_piece li { padding-left: 0px; margin-bottom: 5px; } div.fourcolumn_piece a { font-weight: normal; } 07070100000010000081A4000000000000000000000001653D36F10000035B000000000000000000000000000000000000004500000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/css/reset.css/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html version: 3.3.0 build: 3167 */ html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}07070100000011000081A4000000000000000000000001653D36F1000002FC000000000000000000000000000000000000004700000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/css/scratch.cssbody { margin: 0; } div.toc ul { padding: 0; } div.toc li { margin-bottom: 3px; } h1.title { font-size: 36px; line-height: 1.1; font-weight: normal; } h0, h2 { font-size: 24px; line-height: 1.2; margin: 14px 0; font-weight: normal; display: block; } a:hover { color: #dd4814; text-decoration: underline; outline: 0; } table, pre { border-radius: 0; } .annotated td { padding: 0.8em 1em 0.3em; } .wrapper { width: 940px; margin: 0 auto; } .main-content { width: 668px; position: relative; left: 270px; } .title { margin-left: -270px; margin-top: 30px; margin-bottom: 50px; } .toc { margin-left: -270px; font-size: 100%; margin-bottom: 40px; padding: 0; z-index: 2; position: absolute; top: 100px; width: 250px; } 07070100000012000081A4000000000000000000000001653D36F100000234000000000000000000000000000000000000003F00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/doc.priinclude(../common-installs-config.pri) QDOC = $$[QT_INSTALL_BINS]/qdoc QMAKE_EXTRA_TARGETS += clean-docs docs-html clean-docs-html CONFIG(ubuntu-docs) { docs-html.commands = \ "$${QDOC} $${PWD}/accounts-qml-module-ubuntu.qdocconf" } else { docs-html.commands = \ "$${QDOC} $${PWD}/accounts-qml-module.qdocconf" } docs.files = $$PWD/html docs.path = $${INSTALL_PREFIX}/share/accounts-qml-module/doc docs.depends = docs-html INSTALLS += docs clean-docs-html.commands = \ "rm -rf $${PWD}/html" clean-docs.depends = clean-docs-html 07070100000013000081ED000000000000000000000001653D36F100000338000000000000000000000000000000000000004800000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/generate_html.sh#!/bin/sh # # Copyright 2012 Canonical Ltd. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # QDOCCONF_FILE=accounts-qml-module.qdocconf QDOC_BIN=/usr/lib/*/qt5/bin/qdoc sed "s|docs/||" < $QDOCCONF_FILE > $QDOCCONF_FILE.tmp $QDOC_BIN $QDOCCONF_FILE.tmp rm $QDOCCONF_FILE.tmp 07070100000014000041ED000000000000000000000002653D36F100000000000000000000000000000000000000000000003C00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/html07070100000015000081A4000000000000000000000001653D36F100000047000000000000000000000000000000000000004700000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/html/.gitignore# Ignore everything in this directory * # Except this file !.gitignore 07070100000016000081A4000000000000000000000001653D36F10000055E000000000000000000000000000000000000004200000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/index.qdoc/* * Copyright (C) 2016 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /*! \page index.html index \title Accounts QML module \brief This module provides QML bindings for Online Accounts The Online Accounts API allows applications to access the user's accounts in order to perform tasks such as OAuth authentication or plain password retrieval. Given the wide variety of environment in which this system has been deployed, with different scopes, UI flows and security policies, it's unpractical to present here a tutorial or a developer guide: for that, the developer is invited to consult the documentation provided by the SDK in use. This pages contain the reference documentation for the \l{Accounts SSO OnlineAccounts}{API} and \l{Manifest files}{manifest files} used by this module. */ 07070100000017000081A4000000000000000000000001653D36F10000331B000000000000000000000000000000000000004B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/manifest-files.qdoc/* * Copyright (C) 2012 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /*! \page manifest-files.html manifest-files \title Manifest files In order to integrate with the Online Accounts framework, one needs to ship a couple of manifest files which describe the online services being used or provided. Account plugins must ship a \l{The provider files}{provider file} which can contain account settings readable by applications. Applications must ship an \l{The application files}{application file} which tells which online services the application is able to use, and \l{The service files}{service files} which describes the online services and their settings. \section1 The provider files A \c .provider file describes an online accounts provider. It's a XML file, typically installed in \c /usr/share/accounts/providers/ or \c ~/.local/share/accounts/providers/ which looks like this: \code <?xml version="1.0" encoding="UTF-8"?> <provider id="facebook"> <name>Facebook</name> <icon>facebook</icon> <translations>account-plugins</translations> <domains>.*facebook\.com</domains> <plugin>generic-oauth</plugin> <single-account>true</single-account> <template> <group name="auth"> <setting name="method">oauth2</setting> <setting name="mechanism">user_agent</setting> <group name="oauth2"> <group name="user_agent"> <setting name="Host">www.facebook.com</setting> <setting name="AuthPath">/dialog/oauth</setting> <setting name="RedirectUri">https://www.facebook.com/connect/login_success.html</setting> <setting name="Display">popup</setting> <setting type="as" name="Scope">['publish_stream','status_update','user_photos']</setting> <setting name="ClientId">412471239412</setting> <setting type="as" name="AllowedSchemes">['https','http']</setting> </group> </group> </group> </template> </provider> \endcode This file name must match the value of the \c id tag in the root \c <provider> element, plus the \c ".provider" suffix. The only mandatory element is \c <name>, and that's the display name of the provider. Other optional elements are: \list \li \c <icon>: an icon for the account provider. \li \c <translations>: a translation domain for the \c <name> element. \li \c <domains>: a regular expression matching the domain(s) where this account is used. \li \c <plugin>: the ID of the account plugin which must be used to create or edit the accounts for this provider. \li \c <single-account>: whether the account editing UI should prevent the user to create multiple accounts for this provider. \li \c <template>: default settings or authentication parameters for the account. This element is described in \l{The template element} section. \endlist \section1 The service files A \c .service file describes an online service. It's a XML file, typically installed in \c /usr/share/accounts/services/ or \c ~/.local/share/accounts/services/ which looks like this: \code <?xml version="1.0" encoding="UTF-8"?> <service id="picasa"> <type>photo-sharing</type> <name>Picasa</name> <icon>icon_picasa</icon> <provider>google</provider> <translations>account-plugins</translations> <template> <group name="auth/oauth2/user_agent"> <setting type="as" name="Scope">["https://picasaweb.google.com/data/"]</setting> </group> <setting type="i" name="max-resolution">2048</setting> </template> </service> \endcode The name of the file must match the contents of the \c id tag in the root \c <service> element, plus the \c ".service" suffix. Despite the complexity of the example above, only two pieces of information are mandatory: \list \li \c <provider>: the ID of the account provider. See the \l{The provider files}{section about provider files} for more. \li \c <type>: the type of service; some applications don't have a fixed set of supported services, but rather can use any service implementing a certain protocol (for example, IMAP for e-mail clients): in such cases, the different services would use a common type here, and applications would refer to them via this type. Otherwise, the type should be set to a unique string which has low chances of conflicting with other types: for instance, a good practice would be to set it to "\a <provider-id>-<service-id>". \endlist Other information which can be embedded in \c .service files: \list \li \c <name>: a display name for the service. \li \c <icon>: an icon name for the service. \li \c <translations>: a translation domain for the \c <name> element. \li \c <template>: default settings or authentication parameters for the service. This element is described in \l{The template element} section. \endlist \section1 The application files An \c .application file describes how an application uses online accounts. It's a XML file, typically installed in \c /usr/share/accounts/applications/ or \c ~/.local/share/accounts/applications/ which looks like this: \code <?xml version="1.0" encoding="UTF-8" ?> <application id="my-photo-manager"> <description>My Photo Manager</description> <desktop-entry>photo-manager.desktop</desktop-entry> <translations>photo-manager</translations> <services> <service id="photo-instagram"> <description>Publish your pictures to Instagram</description> </service> <service id="photo-facebook"> <description>Publish your pictures to Facebook</description> </service> </services> <service-types> <service-type id="photo-sharing"> <description>Publish your pictures to your favorite site</description> </service-type> </service-types> </application> \endcode The name of the file must match the contents of the \c id tag in the root \c <application> element, plus the \c ".application" suffix. None of the elements is mandatory, but in order to be linked to some online accounts there should be at least one valid \c <service> or \c <service-type> element. The XML elements that an \c .application file can contain are: \list \li \c <description>: a description of the application; if missing, this will be read from the \c .desktop file associated with the application. \li \c <desktop-entry>: the ID of the \c .desktop file associated with the application (with or without the \c ".desktop" suffix); if missing, it's assumed to be the same application ID specified in the \c id tag of the root \c <application> element. \li \c <translations>: a translation domain for all the \c <description> elements. \li \c <services>: a container for \c <service> elements, which refer to the IDs of the \l{The service files}{services} which the application can use. \li \c <service-types>: a container for \c <service-type> elements, which refer to the IDs of the service types which the application can use. See the documentation for the \c <type> element in \l{The service files}{service files}. \endlist \section2 The template element Accounts can contain settings which can be useful for applications, for example authentication parameters or server settings (such as the address and port of an IMAP server). These settings are stored in the accounts database, and an application can read them by accessing the \l AccountService::settings property. The \c <template> element in the \c .service or \c .provider files can be used to specify a fallback value for those settings which have not been set in the accounts database. A \c .service file \c <template> element is used when the \c id of the \l AccountService::service object matches its ID. The \c .provider file \c <template> element is instead used when the \c id of the \l AccountService::service object is empty, meaning that the \c AccountService is describing the global account, and not a specific service. \section3 Format of the default settings The \c <template> element describes a dictionary of keys and values, where the key is always a string, and values can be any data type. Keys can contain the "/" character, which can be used to define key groups; for instance: \code <setting name="net/server/address">example.com</setting> <setting name="net/server/port" type="u">2500</setting> <setting name="net/use-ssl" type="b">false</setting> \endcode is equivalent to \code <group name="net"> <group name="server"> <setting name="address">example.com</setting> <setting name="port" type="u">2500</setting> </group> <setting name="use-ssl" type="b">false</setting> </group> \endcode and also to \code <group name="net/server"> <setting name="address">example.com</setting> <setting name="port" type="u">2500</setting> </group> <setting name="net/use-ssl" type="b">false</setting> \endcode Values are always assumed to be strings, unless a \c type attribute is set in the \c <setting> element; the most commonly used types are: \table \header \li Type \li Code \li Example \row \li string \li \c s \li \c <setting... \c type="s">Hello \c world!</setting> \row \li boolean \li \c b \li \c <setting... \c type="b">true</setting> \row \li integer \li \c i \li \c <setting... \c type="i">-12</setting> \row \li unsigned \li \c u \li \c <setting... \c type="u">256</setting> \row \li array of strings \li \c as \li \c <setting... \c type="as">["one","two"]</setting> \endtable \section3 Authentication data The object returned by the \l AccountService::authData property is also built with a similar fallback mechanism as the rest of account settings, but it's a bit more refined to especially address the needs of application developers to override the authentication parameters. A typical example is OAuth 2.0, where the application might need to specify a different \a ClientId and \a ClientSecret than those used by the rest of the system. Another example is that of an account provider offering a REST API with an OAuth 2.0 authentication for publishing pictures, but a basic username/password authentication to access an IMAP mail sever. The authentication data consists of: \list \li the \c CredentialsId key: this is the numeric ID of the account credentials in the local machine. This key is usually never stored in the \c <template> element, as its value becomes known only when the account is created. \li the \c auth/method key: a string defining which authentication plugin needs to be used. Please refer to the \l {http://docs.accounts-sso.googlecode.com/git/libsignon-qt/html/index.html} {libsignon-qt documentation}. \li the \c auth/mechanism key: a string defining which authentication mechanism needs to be used. Each authentication plugin defines its own mechanisms, so please refer to the plugin's documentation. \li all the settings defined under the \c "auth/ \a <method> \c / \a <mechanism> \c " group. Each authentication plugin defines its own parameters, so please refer to the plugin's documentation. \endlist When the \l AccountService represents the global account, then the authentication data obtained by reading the \l AccountService::authData property follows the usual fallback scheme: the parameters stored in the accounts database have precence over the template parameters defined in the \c .provider file. However, if the \l AccountService represent a service within an account, the authentication parameters are read in the following order (higher priority is listed first): \list \li parameters stored in the accounts database, for the specific service; \li parameters stored in the \c <template> element of the \c .service file; \li parameters stored in the accounts database, for the global account; \li parameters stored in the \c <template> element of the \c .provider file. \endlist */ 07070100000018000081A4000000000000000000000001653D36F1000033E9000000000000000000000000000000000000004300000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/qtquick.css@media screen { /* basic elements */ html { color: #000000; background: #FFFFFF; } table { border-collapse: collapse; border-spacing: 0; } fieldset, img { border: 0; max-width:100%; } address, caption, cite, code, dfn, em, strong, th, var, optgroup { font-style: inherit; font-weight: inherit; } del, ins { text-decoration: none; } ol li { list-style: decimal; } ul li { list-style: none; } caption, th { text-align: left; } h1.title { font-weight: bold; font-size: 150%; } h0 { font-weight: bold; font-size: 130%; } h1, h2, h3, h4, h5, h6 { font-size: 100%; } q:before, q:after { content: ''; } abbr, acronym { border: 0; font-variant: normal; } sup, sub { vertical-align: baseline; } tt, .qmlreadonly span, .qmldefault span { word-spacing:0.5em; } legend { color: #000000; } strong { font-weight: bold; } em { font-style: italic; } body { margin: 0 1.5em 0 1.5em; font-family: ubuntu; line-height: normal } a { color: #00732F; text-decoration: none; } hr { background-color: #E6E6E6; border: 1px solid #E6E6E6; height: 1px; width: 100%; text-align: left; margin: 1.5em 0 1.5em 0; } pre { border: 1px solid #DDDDDD; -moz-border-radius: 0.7em 0.7em 0.7em 0.7em; -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em; border-radius: 0.7em 0.7em 0.7em 0.7em; padding: 1em 1em 1em 1em; overflow-x: auto; } table, pre { -moz-border-radius: 0.7em 0.7em 0.7em 0.7em; -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em; border-radius: 0.7em 0.7em 0.7em 0.7em; background-color: #F6F6F6; border: 1px solid #E6E6E6; border-collapse: separate; margin-bottom: 2.5em; } pre { font-size: 90%; display: block; overflow:hidden; } thead { margin-top: 0.5em; font-weight: bold } th { padding: 0.5em 1.5em 0.5em 1em; background-color: #E1E1E1; border-left: 1px solid #E6E6E6; } td { padding: 0.25em 1.5em 0.25em 1em; } td.rightAlign { padding: 0.25em 0.5em 0.25em 1em; } table tr.odd { border-left: 1px solid #E6E6E6; background-color: #F6F6F6; color: black; } table tr.even { border-left: 1px solid #E6E6E6; background-color: #ffffff; color: #202020; } div.float-left { float: left; margin-right: 2em } div.float-right { float: right; margin-left: 2em } span.comment { color: #008B00; } span.string, span.char { color: #000084; } span.number { color: #a46200; } span.operator { color: #202020; } span.keyword { color: #840000; } span.name { color: black } span.type { font-weight: bold } span.type a:visited { color: #0F5300; } span.preprocessor { color: #404040 } /* end basic elements */ /* font style elements */ .heading { font-weight: bold; font-size: 125%; } .subtitle { font-size: 110% } .small-subtitle { font-size: 100% } .red { color:red; } /* end font style elements */ /* global settings*/ .header, .footer { display: block; clear: both; overflow: hidden; } /* end global settings*/ /* header elements */ .header .qtref { color: #00732F; font-weight: bold; font-size: 130%; } .header .content { margin-left: 5px; margin-top: 5px; margin-bottom: 0.5em; } .header .breadcrumb { font-size: 90%; padding: 0.5em 0 0.5em 1em; margin: 0; background-color: #fafafa; height: 1.35em; border-bottom: 1px solid #d1d1d1; } .header .breadcrumb ul { margin: 0; padding: 0; } .header .content { word-wrap: break-word; } .header .breadcrumb ul li { float: left; background: url(../images/breadcrumb.png) no-repeat 0 3px; padding-left: 1.5em; margin-left: 1.5em; } .header .breadcrumb ul li.last { font-weight: normal; } .header .breadcrumb ul li a { color: #00732F; } .header .breadcrumb ul li.first { background-image: none; padding-left: 0; margin-left: 0; } .header .content ol li { background: none; margin-bottom: 1.0em; margin-left: 1.2em; padding-left: 0 } .header .content li { background: url(../images/bullet_sq.png) no-repeat 0 5px; margin-bottom: 1em; padding-left: 1.2em; } /* end header elements */ /* content elements */ .content h1 { font-weight: bold; font-size: 130% } .content h2 { font-weight: bold; font-size: 120%; width: 100%; } .content h3 { font-weight: bold; font-size: 110%; width: 100%; } .content table p { margin: 0 } .content ul { padding-left: 2.5em; } .content li { padding-top: 0.25em; padding-bottom: 0.25em; } .content ul img { vertical-align: middle; } .content a:visited { color: #4c0033; text-decoration: none; } .content a:visited:hover { color: #4c0033; text-decoration: underline; } a:hover { color: #4c0033; text-decoration: underline; } descr p a { text-decoration: underline; } .descr p a:visited { text-decoration: underline; } .alphaChar{ width:95%; background-color:#F6F6F6; border:1px solid #E6E6E6; -moz-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; font-size:12pt; padding-left:10px; margin-top:10px; margin-bottom:10px; } .flowList{ /*vertical-align:top;*/ /*margin:20px auto;*/ column-count:3; -webkit-column-count:3; -moz-column-count:3; /* column-width:100%; -webkit-column-width:200px; -col-column-width:200px; */ column-gap:41px; -webkit-column-gap:41px; -moz-column-gap:41px; column-rule: 1px dashed #ccc; -webkit-column-rule: 1px dashed #ccc; -moz-column-rule: 1px dashed #ccc; } .flowList dl{ } .flowList dd{ /*display:inline-block;*/ margin-left:10px; min-width:250px; line-height: 1.5; min-width:100%; min-height:15px; } .flowList dd a{ } .mainContent { padding-left:5px; } .content .flowList p{ padding:0px; } .content .alignedsummary { margin: 15px; } .qmltype { text-align: center; font-size: 120%; } .qmlreadonly { padding-left: 5px; float: right; color: #254117; } .qmldefault { padding-left: 5px; float: right; color: red; } .qmldoc { } .generic .alphaChar{ margin-top:5px; } .generic .odd .alphaChar{ background-color: #F6F6F6; } .generic .even .alphaChar{ background-color: #FFFFFF; } .memItemRight{ padding: 0.25em 1.5em 0.25em 0; } .highlightedCode { margin: 1.0em; } .annotated td { padding: 0.25em 0.5em 0.25em 0.5em; } .toc { font-size: 80% } .header .content .toc ul { padding-left: 0px; } .content .toc h3 { border-bottom: 0px; margin-top: 0px; } .content .toc h3 a:hover { color: #00732F; text-decoration: none; } .content .toc .level2 { margin-left: 1.5em; } .content .toc .level3 { margin-left: 3.0em; } .content ul li { background: url(../images/bullet_sq.png) no-repeat 0 0.7em; padding-left: 1em } .content .toc li { background: url(../images/bullet_dn.png) no-repeat 0 5px; padding-left: 1em } .relpage { -moz-border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; border: 1px solid #DDDDDD; padding: 25px 25px; clear: both; } .relpage ul { float: none; padding: 1.5em; } h3.fn, span.fn { -moz-border-radius:7px 7px 7px 7px; -webkit-border-radius:7px 7px 7px 7px; border-radius:7px 7px 7px 7px; background-color: #F6F6F6; border-width: 1px; border-style: solid; border-color: #E6E6E6; font-weight: bold; word-spacing:3px; padding:3px 5px; } .functionIndex { font-size:12pt; word-spacing:10px; margin-bottom:10px; background-color: #F6F6F6; border-width: 1px; border-style: solid; border-color: #E6E6E6; -moz-border-radius: 7px 7px 7px 7px; -webkit-border-radius: 7px 7px 7px 7px; border-radius: 7px 7px 7px 7px; width:100%; } .centerAlign { text-align:center; } .rightAlign { text-align:right; } .leftAlign { text-align:left; } .topAlign{ vertical-align:top } .functionIndex a{ display:inline-block; } /* end content elements */ /* footer elements */ .footer { color: #393735; font-size: 0.75em; text-align: center; padding-top: 1.5em; padding-bottom: 1em; background-color: #E6E7E8; margin: 0; } .footer p { margin: 0.25em } .small { font-size: 0.5em; } /* end footer elements */ .item { float: left; position: relative; width: 100%; overflow: hidden; } .item .primary { margin-right: 220px; position: relative; } .item hr { margin-left: -220px; } .item .secondary { float: right; width: 200px; position: relative; } .item .cols { clear: both; display: block; } .item .cols .col { float: left; margin-left: 1.5%; } .item .cols .col.first { margin-left: 0; } .item .cols.two .col { width: 45%; } .item .box { margin: 0 0 10px 0; } .item .box h3 { margin: 0 0 10px 0; } .cols.unclear { clear:none; } } /* end of screen media */ /* start of print media */ @media print { input, textarea, .header, .footer, .toolbar, .feedback, .wrapper .hd, .wrapper .bd .sidebar, .wrapper .ft, #feedbackBox, #blurpage, .toc, .breadcrumb, .toolbar, .floatingResult { display: none; background: none; } .content { background: none; display: block; width: 100%; margin: 0; float: none; } } /* end of print media */ /* modify the TOC layouts */ div.toc ul { padding-left: 20px; } div.toc li { padding-left: 4px; } /* Remove the border around images*/ a img { border:none; } /*Add styling to the front pages*/ .threecolumn_area { padding-top: 20px; padding-bottom: 20px; } .threecolumn_piece { display: inline-block; margin-left: 78px; margin-top: 8px; padding: 0; vertical-align: top; width: 25.5%; } div.threecolumn_piece ul { list-style-type: none; padding-left: 0px; margin-top: 2px; } div.threecolumn_piece p { margin-bottom: 7px; color: #5C626E; text-decoration: none; font-weight: bold; } div.threecolumn_piece li { padding-left: 0px; margin-bottom: 5px; } div.threecolumn_piece a { font-weight: normal; } /* Add style to guide page*/ .fourcolumn_area { padding-top: 20px; padding-bottom: 20px; } .fourcolumn_piece { display: inline-block; margin-left: 35px; margin-top: 8px; padding: 0; vertical-align: top; width: 21.3%; } div.fourcolumn_piece ul { list-style-type: none; padding-left: 0px; margin-top: 2px; } div.fourcolumn_piece p { margin-bottom: 7px; color: #40444D; text-decoration: none; font-weight: bold; } div.fourcolumn_piece li { padding-left: 0px; margin-bottom: 5px; } div.fourcolumn_piece a { font-weight: normal; } 07070100000019000081A4000000000000000000000001653D36F100000F58000000000000000000000000000000000000005A00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/ubuntu-appdev-site-footer.qdocconfHTML.footer = \ "</div></div>\n" \ "<div class=\"shadow\"></div>\n" \ "<footer>\n" \ " <div>\n" \ " <nav role=\"navigation\" class=\"clearfix\">\n" \ " <ul>\n" \ " <li><a href=\"/get-started\">Get started</a></li>\n" \ " <li class=\"page_item page-item-16\"><a href=\"http://developer.ubuntu.com/get-started/quickly-workflow/\">Quickly workflow</a></li>\n" \ "<li class=\"page_item page-item-18\"><a href=\"http://developer.ubuntu.com/get-started/qt-creator/\">Qt Creator</a></li>\n" \ "<li class=\"page_item page-item-20\"><a href=\"http://developer.ubuntu.com/get-started/eclipse/\">Eclipse</a></li>\n" \ "<li class=\"page_item page-item-22\"><a href=\"http://developer.ubuntu.com/get-started/monodevelop/\">MonoDevelop</a></li>\n" \ " </ul>\n" \ " <ul>\n" \ " <li><a href=\"/resources\">Resources</a></li>\n" \ " <li><a href=\"/resources/tools/quickly\">Quickly</a></li>\n" \ " <li><a href=\"/resources/platform/api\">API</a></li>\n" \ " <li><a href=\"/resources/platform/documentation/platform-diagram\">Platform overview</a></li>\n" \ " </ul>\n" \ " <ul>\n" \ " <li><a href=\"/publish\">Publish</a></li>\n" \ " <li class=\"page_item page-item-24\"><a href=\"http://developer.ubuntu.com/publish/commercial-software-faqs/\">Commercial software FAQs</a></li>\n" \ "<li class=\"page_item page-item-34\"><a href=\"http://developer.ubuntu.com/publish/application-states/\">Application states</a></li>\n" \ "<li class=\"page_item page-item-577\"><a href=\"http://developer.ubuntu.com/publish/my-apps-packages/\">Uploading your app</a></li>\n" \ "<li class=\"page_item page-item-404\"><a href=\"http://developer.ubuntu.com/publish/ubuntu-software-centre/\">Ubuntu Software Centre</a></li>\n" \ "<li class=\"page_item page-item-427\"><a href=\"http://developer.ubuntu.com/publish/licence-key-infrastructure/\">Licence key infrastructure</a></li>\n" \ "<li class=\"page_item page-item-1230\"><a href=\"http://developer.ubuntu.com/publish/updating-your-app/\">Updating your app</a></li>\n" \ " </ul>\n" \ " <ul>\n" \ " <li><a href=\"/community\">Community</a></li>\n" \ " <li class=\"page_item page-item-28\"><a href=\"http://developer.ubuntu.com/community/app-developer-blog/\">App Developer Blog</a></li>\n" \ "<li class=\"page_item page-item-30\"><a href=\"http://developer.ubuntu.com/community/submit-a-tutorial/\">Submit a tutorial</a></li>\n" \ "<li class=\"page_item page-item-32\"><a href=\"http://developer.ubuntu.com/community/app-review-board-charter/\">App Review Board charter</a></li>\n" \ "<li class=\"page_item page-item-2987\"><a href=\"http://developer.ubuntu.com/community/on-air/\">On air</a>\n" \ "<ul class='children'>\n" \ " <li class=\"page_item page-item-3066\"><a href=\"http://developer.ubuntu.com/community/on-air/recordings/\">Recordings</a></li>\n" \ "</ul>\n" \ "</li>\n" \ " </ul>\n" \ " <ul class=\"last\">\n" \ " <li><a href=\"https://myapps.developer.ubuntu.com/dev\">My Apps</a></li>\n" \ " <li><a href=\"https://myapps.developer.ubuntu.com/openid/login/?next=/dev\">Sign in or register</a></li>\n" \ " <li><a href=\"https://myapps.developer.ubuntu.com/dev/account\">My account</a></li>\n" \ " </ul>\n" \ " </nav>\n" \ " <p>© 2013 Canonical Ltd. Ubuntu and Canonical are registered trademarks of Canonical Ltd. <a class=\"link-bug\" href=\"https://bugs.launchpad.net/ubuntudeveloperportal/+filebug\">Report a bug on this site</a></p>\n" \ " </div>\n" \ "</footer>\n" \ "<script type=\"text/javascript\" src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js\"></script>\n" \ "<script type=\"text/javascript\" src=\"http://developer.ubuntu.com/wp-content/themes/wordpress-theme-ubuntudeveloper/js/base.js\"></script>\n" 0707010000001A000081A4000000000000000000000001653D36F100000700000000000000000000000000000000000000005A00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/doc/ubuntu-appdev-site-header.qdocconfHTML.postheader = \ "<header>\n" \ " <div class=\"header-login\">\n" \ " <ul>\n" \ " <li><a href=\"https://myapps.developer.ubuntu.com/openid/login/?next\=/dev\">Sign in or register</a></li>\n" \ " </ul>\n" \ " </div>\n" \ " <div class=\"header-navigation\">\n" \ " <div>\n" \ " <nav role=\"navigation\">\n" \ " <ul>\n" \ " <li class=\"page_item page-item-5\"><a href=\"http://developer.ubuntu.com/\">Home</a></li>\n" \ " <li class=\"page_item page-item-7\"><a href=\"http://developer.ubuntu.com/get-started/\">Get started</a></li>\n" \ " <li class=\"page_item page-item-9\"><a href=\"http://developer.ubuntu.com/resources/\">Resources</a></li>\n" \ " <li class=\"page_item page-item-11\"><a href=\"http://developer.ubuntu.com/publish/\">Publish</a></li>\n" \ " <li class=\"page_item page-item-13\"><a href=\"http://developer.ubuntu.com/community/\">Community</a></li>\n" \ " <li><a href=\"https://myapps.developer.ubuntu.com/dev\">My Apps</a></li>\n" \ " <li>\n" \ " <form id=\"form-search\" method=\"get\" action=\"/\">\n" \ " <fieldset>\n" \ " <input id=\"input-search\" type=\"text\" name=\"s\" value=\"Search\" />\n" \ " </fieldset>\n" \ " </form>\n" \ " </li>\n" \ " </ul>\n" \ " </nav>\n" \ " <a class=\"logo-ubuntu\" href=\"/\"><img src=\"http://developer.ubuntu.com/wp-content/themes/wordpress-theme-ubuntudeveloper/img/logo-ubuntu.png\" width=\"119\" height=\"27\" alt=\"Ubuntu logo\" /></a>\n" \ " <h2><a href=\"/\">App Developer</a></h2>\n" \ " </div>\n" \ " </div>\n" \ " \n" \ " </header>\n" \ " <div class=\"wrapper\">\n" \ " <div class=\"main-content\">\n" 0707010000001B000041ED000000000000000000000002653D36F100000000000000000000000000000000000000000000003C00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/examples0707010000001C000081A4000000000000000000000001653D36F100000919000000000000000000000000000000000000004F00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/examples/create-account.qml/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import QtQuick 2.0 import SSO.OnlineAccounts 0.1 Rectangle { width: 400 height: 300 ListView { id: listView anchors.fill: parent focus: true model: ProviderModel {} spacing: 3 delegate: Item { width: parent.width height: 60 Account { id: account objectHandle: Manager.createAccount(model.providerId) } AccountService { id: globalAccountSettings objectHandle: account.accountServiceHandle credentials: Credentials { id: creds userName: "my name" secret: "password you'll never guess" caption: account.provider.id acl: ["*"] } } Rectangle { anchors.fill: parent radius: 10 color: "lightsteelblue" Text { font.bold: true text: model.displayName } MouseArea { anchors.fill: parent /* Uncomment this to test the account creation. WARNING: this will create a real account on your system, with dummy data! */ // onClicked: writeAccount() } } function writeAccount() { account.updateDisplayName("Delete me"); account.updateEnabled(false); creds.sync(); } } } } 0707010000001D000081A4000000000000000000000001653D36F10000092E000000000000000000000000000000000000004C00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/examples/simple-view.qml/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import QtQuick 2.0 import SSO.OnlineAccounts 0.1 Rectangle { width: 400 height: 300 AccountServiceModel { id: accounts serviceType: "microblogging" includeDisabled: true } ListView { id: listView width: parent.width height: parent.height anchors.fill: parent focus: true model: accounts spacing: 3 delegate: Item { width: parent.width height: 60 AccountService { id: accts objectHandle: accountServiceHandle onAuthenticated: { console.log("Access token is " + reply.AccessToken) } onAuthenticationError: { console.log("Authentication failed, code " + error.code) } onEnabledChanged: { console.log ("ENABLED CHANGED"); } } Rectangle { anchors.fill: parent radius: 10 color: accts.enabled ? "lightsteelblue" : "#777" Column { anchors.fill: parent anchors.margins: 5 Text { font.bold: true text: providerName } Text { text: displayName } } MouseArea { anchors.fill: parent onClicked: accts.authenticate(null) } } } } } 0707010000001E000081A4000000000000000000000001653D36F100000AB7000000000000000000000000000000000000005000000000accounts-qml-module-0.7git.20231028T182937~05e79eb/examples/ubuntu-sdk-view.qml/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import QtQuick 2.0 import Lomiri.Components 0.1 import Lomiri.Components.ListItems 0.1 as ListItem import SSO.OnlineAccounts 0.1 MainView { width: units.gu(60) height: units.gu(80) Behavior on x { SequentialAnimation{ PropertyAction { property: "x"; value: main.width } PropertyAnimation { duration: 200 } } } AccountServiceModel { id: accounts serviceType: "microblogging" //serviceType: "IM" includeDisabled: true Component.onCompleted: { set_model()} } function set_model () { listView.model = accounts; console.log ("MODEL READY: " + listView.count); } ListView { id: listView width: parent.width height: parent.height anchors.fill: parent focus: true delegate: Item { width: parent.width height: childrenRect.height AccountService { id: accts objectHandle: accountServiceHandle onAuthenticated: { console.log("Access token is " + reply.AccessToken) } onAuthenticationError: { console.log("Authentication failed, code " + error.code) } Component.onCompleted: { sw.checked = accts.enabled; } onEnabledChanged: { console.log ("ENABLED CHANGED"); sw.checked = accts.enabled; } } ListItem.Standard { text: displayName icon: "image://gicon/"+accts.provider.iconName control { Switch { id: sw checked: false } } onClicked: accts.authenticate(null) } } populate: Transition { NumberAnimation { properties: "x,y"; duration: 1000 } } } } 0707010000001F000041ED000000000000000000000002653D36F100000000000000000000000000000000000000000000003700000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src07070100000020000081A4000000000000000000000001653D36F1000061A0000000000000000000000000000000000000005100000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/account-service-model.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "account-service-model.h" #include "debug.h" #include "manager.h" #include <algorithm> #include <Accounts/Account> #include <Accounts/AccountService> #include <Accounts/Application> #include <Accounts/Manager> #include <QPointer> #include <QQmlEngine> using namespace OnlineAccounts; static const QLatin1String globalService("global"); static bool sortByProviderAndDisplayName(const Accounts::AccountService *as1, const Accounts::AccountService *as2) { const Accounts::Account *a1 = as1->account(); const Accounts::Account *a2 = as2->account(); int diff = QString::compare(a1->providerName(), a2->providerName()); if (diff < 0) return true; if (diff > 0) return false; diff = QString::compare(a1->displayName(), a2->displayName()); if (diff < 0) return true; if (diff > 0) return false; // last, sort by service return as1->service().name() < as2->service().name(); } namespace OnlineAccounts { typedef QList<Accounts::AccountService *> AccountServices; class AccountServiceModelPrivate: public QObject { Q_OBJECT Q_DECLARE_PUBLIC(AccountServiceModel) public: AccountServiceModelPrivate(AccountServiceModel *model); ~AccountServiceModelPrivate(); void queueUpdate(); AccountServices listAccountServices(Accounts::Account *account) const; AccountServices watchAccount(Accounts::Account *account); void addServicesFromAccount(Accounts::Account *account); void watchItems(const AccountServices &items); void addItems(const AccountServices &added); void removeItems(const AccountServices &removed); void sortItems(); public Q_SLOTS: void update(); void onAccountCreated(Accounts::AccountId id); void onAccountRemoved(Accounts::AccountId id); void onAccountDisplayNameChanged(); void onAccountServiceEnabled(bool enabled); private: mutable AccountServiceModel *q_ptr; QHash<int, QByteArray> roleNames; bool componentCompleted; bool updateQueued; bool accountIdChanged; bool accountChanged; bool applicationIdChanged; bool providerChanged; bool serviceTypeChanged; bool serviceChanged; bool includeDisabled; Accounts::AccountId accountId; QPointer<Accounts::Account> account; Accounts::Application application; QString providerId; QString serviceTypeId; QString serviceId; QSharedPointer<Accounts::Manager> manager; AccountServices allItems; AccountServices modelItems; bool (*sortFunction)(const Accounts::AccountService *as1, const Accounts::AccountService *as2); }; }; // namespace AccountServiceModelPrivate::AccountServiceModelPrivate(AccountServiceModel *model): QObject(model), q_ptr(model), componentCompleted(false), updateQueued(true), accountIdChanged(false), accountChanged(false), providerChanged(false), serviceTypeChanged(false), serviceChanged(false), includeDisabled(false), accountId(0), sortFunction(sortByProviderAndDisplayName) { } AccountServiceModelPrivate::~AccountServiceModelPrivate() { qDeleteAll(allItems); } void AccountServiceModelPrivate::queueUpdate() { if (updateQueued) return; updateQueued = true; QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); } AccountServices AccountServiceModelPrivate::listAccountServices(Accounts::Account *account) const { AccountServices ret; if (Q_UNLIKELY(account == 0)) return ret; if (!providerId.isEmpty() && account->providerName() != providerId) return ret; if (serviceId == globalService) { ret.append(new Accounts::AccountService(account, Accounts::Service())); } else { foreach (Accounts::Service service, account->services()) { if (!serviceId.isEmpty() && service.name() != serviceId) continue; if (application.isValid() && application.serviceUsage(service).isEmpty()) continue; ret.append(new Accounts::AccountService(account, service)); } } return ret; } AccountServices AccountServiceModelPrivate::watchAccount(Accounts::Account *account) { AccountServices accountServices = listAccountServices(account); watchItems(accountServices); QObject::connect(account, SIGNAL(displayNameChanged(const QString &)), this, SLOT(onAccountDisplayNameChanged()), Qt::UniqueConnection); return accountServices; } void AccountServiceModelPrivate::addServicesFromAccount(Accounts::Account *account) { AccountServices accountServices = watchAccount(account); AccountServices newModelItems; foreach (Accounts::AccountService *accountService, accountServices) { if (includeDisabled || accountService->enabled()) newModelItems.append(accountService); } std::sort(newModelItems.begin(), newModelItems.end(), sortFunction); addItems(newModelItems); } void AccountServiceModelPrivate::watchItems(const AccountServices &items) { foreach (Accounts::AccountService *accountService, items) { QObject::connect(accountService, SIGNAL(enabled(bool)), this, SLOT(onAccountServiceEnabled(bool))); } allItems.append(items); } /* * NOTE: @added must be already sorted! */ void AccountServiceModelPrivate::addItems(const AccountServices &added) { Q_Q(AccountServiceModel); AccountServices newModelItems = modelItems; QModelIndex root; QMap<int,int> addedIndexes; foreach (Accounts::AccountService *accountService, added) { // Find where the item should be inserted AccountServices::iterator i = std::lower_bound(modelItems.begin(), modelItems.end(), accountService, sortFunction); int index = i - modelItems.begin(); addedIndexes[index]++; } // update the list int inserted = 0; for (QMap<int,int>::const_iterator i = addedIndexes.constBegin(); i != addedIndexes.constEnd(); i++) { int start = i.key(); int count = i.value(); q->beginInsertRows(root, start + inserted, start + inserted + count - 1); for (int j = 0; j < count; j++) { Accounts::AccountService *accountService = added.at(inserted + j); modelItems.insert(start + inserted + j, accountService); } q->endInsertRows(); inserted += count; } } void AccountServiceModelPrivate::removeItems(const AccountServices &removed) { Q_Q(AccountServiceModel); QModelIndex root; QList<int> removedIndexes; foreach (Accounts::AccountService *accountService, removed) { int index = modelItems.indexOf(accountService); if (Q_UNLIKELY(index < 0)) { qWarning() << "Item already deleted!" << accountService; continue; } removedIndexes.append(index); } // sort the indexes from highest to lower, and start updating the list std::sort(removedIndexes.begin(), removedIndexes.end(), std::greater<int>()); int first = -1; int last = -1; foreach (int index, removedIndexes) { // Check whether the indexes are contiguous if (index != first - 1) { // if we have a valid range, update the list for that range if (first != -1) { q->beginRemoveRows(root, first, last); for (int i = last; i >= first; i--) modelItems.removeAt(i); q->endRemoveRows(); } // a new range starts last = index; } first = index; } if (first != -1) { q->beginRemoveRows(root, first, last); for (int i = last; i >= first; i--) modelItems.removeAt(i); q->endRemoveRows(); } } void AccountServiceModelPrivate::sortItems() { std::sort(modelItems.begin(), modelItems.end(), sortFunction); } void AccountServiceModelPrivate::update() { Q_Q(AccountServiceModel); updateQueued = false; DEBUG(); if (!modelItems.isEmpty()) { q->beginRemoveRows(QModelIndex(), 0, modelItems.count() - 1); modelItems.clear(); q->endRemoveRows(); } qDeleteAll(allItems); allItems.clear(); if (serviceTypeChanged) { if (!manager.isNull()) { QObject::disconnect(manager.data(), 0, this, 0); manager.clear(); } } /* Instantiate a manager, if needed. If the account property is set to a * valid account, we don't need a manager object. */ if (manager.isNull() && account == 0) { if (serviceTypeId.isEmpty()) { manager = SharedManager::instance(); } else { manager = QSharedPointer<Accounts::Manager>( new Accounts::Manager(serviceTypeId)); } QObject::connect(manager.data(), SIGNAL(accountCreated(Accounts::AccountId)), this, SLOT(onAccountCreated(Accounts::AccountId))); QObject::connect(manager.data(), SIGNAL(accountRemoved(Accounts::AccountId)), this, SLOT(onAccountRemoved(Accounts::AccountId))); } QList<Accounts::Account *> accounts; if (account != 0) { accounts.append(account); } else if (accountId != 0) { Accounts::Account *account = manager->account(accountId); accounts.append(account); } else { foreach (Accounts::AccountId accountId, manager->accountList()) { Accounts::Account *account = manager->account(accountId); accounts.append(account); } } foreach (Accounts::Account *account, accounts) { watchAccount(account); } AccountServices newModelItems; if (includeDisabled) { newModelItems = allItems; } else { foreach (Accounts::AccountService *accountService, allItems) { if (accountService->enabled()) newModelItems.append(accountService); } } if (!newModelItems.isEmpty()) { q->beginInsertRows(QModelIndex(), 0, newModelItems.count() - 1); modelItems = newModelItems; sortItems(); q->endInsertRows(); } accountIdChanged = false; providerChanged = false; serviceTypeChanged = false; serviceChanged = false; } void AccountServiceModelPrivate::onAccountCreated(Accounts::AccountId id) { DEBUG() << id; Accounts::Account *account = manager->account(id); addServicesFromAccount(account); } void AccountServiceModelPrivate::onAccountRemoved(Accounts::AccountId id) { DEBUG() << id; AccountServices removed; foreach (Accounts::AccountService *accountService, allItems) { if (accountService->account()->id() == id) { removed.append(accountService); } } /* Remove the items from the model */ removeItems(removed); /* Last, delete the items */ foreach (Accounts::AccountService *accountService, removed) { allItems.removeOne(accountService); delete accountService; } } void AccountServiceModelPrivate::onAccountDisplayNameChanged() { Q_Q(AccountServiceModel); Accounts::Account *account = qobject_cast<Accounts::Account *>(sender()); for (int row = 0; row < modelItems.count(); row++) { Accounts::AccountService *accountService = modelItems[row]; if (accountService->account() == account) { QModelIndex index = q->index(row); q->dataChanged(index, index); } } } void AccountServiceModelPrivate::onAccountServiceEnabled(bool enabled) { Q_Q(AccountServiceModel); Accounts::AccountService *accountService = qobject_cast<Accounts::AccountService *>(sender()); DEBUG() << enabled; int row = modelItems.indexOf(accountService); if (row > 0) { QModelIndex index = q->index(row); q->dataChanged(index, index); } if (!includeDisabled) { /* The item might need to be added or removed from the model */ AccountServices accountServices; accountServices.append(accountService); if (row < 0 && enabled) { addItems(accountServices); } else if (row >= 0 && !enabled) { removeItems(accountServices); } } } /*! * \qmltype AccountServiceModel * \inqmlmodule SSO.OnlineAccounts 0.1 * \ingroup Ubuntu * * \brief A model of the user's Online Accounts * * The AccountServiceModel is a model representing the user's Online Accounts * services. * Please note that an Online Account can offer several different services * (chat, e-mail, micro-blogging, etc.); these are the items represented by * this model, and not the user accounts as a whole. * Since most applications are interested on a small subset of the user's * accounts, AccountServiceModel offers some filtering functionalities: it is * possible to restrict it to only one account provider, to a specific service * type (for instance, an e-mail application will probably be interested in * only those accounts which offer an e-mail service), or to a specific service * (e.g., picasa; this is often equivalent to filtering by provider and by * service-type, because it's rare for a provider to offer two different * services of the same type). * By default, only enabled accounts are returned. Use the \l includeDisabled * property to list also disabled accounts; keep in mind, though, that an * application should never use an account which has been disabled by the user. * * The model defines the following roles: * \list * \li \c displayName is the name of the account (usually the user's login) * \li \c providerName is the name of the account provider (e.g., "Google") * \li \c serviceName is the name of the service (e.g., "Picasa") * \li \c enabled * \li \c accountServiceHandle is a handle to the underlying Qt object which * can be used to instantiate an \l AccountService from QML * \li \c accountId is the numeric ID of the account * \li \c accountHandle is a handle to the underlying Qt object which can be * used to instantiate an \l Account from QML * \endlist * * Examples of use: * * 1. Model of all enabled microblogging accounts: * \qml * Item { * AccountServiceModel { * id: accounts * serviceType: "microblogging" * } * * ListView { * model: accounts * delegate: Text { text: model.displayName + " by " + model.providerName } * } * } * \endqml * * 2. List all Facebook account services: * \qml * Item { * AccountServiceModel { * id: accounts * provider: "facebook" * includeDisabled: true * } * * ListView { * model: accounts * delegate: Text { text: model.serviceName + " on " + model.displayName } * } * } * \endqml * * 3. List all Flickr accounts enabled for uploading: * \qml * Item { * AccountServiceModel { * id: accounts * service: "flickr-sharing" * } * * ListView { * model: accounts * delegate: Rectangle { * id: rect * * Text { text: rect.model.displayName } * * AccountService { * id: accountService * objectHandle: rect.model.accountServiceHandle * * onAuthenticated: { console.log("Access token is " + reply.AccessToken) } * onAuthenticationError: { console.log("Authentication failed, code " + error.code) } * } * * MouseArea { * anchors.fill: parent * onClicked: accountService.authenticate() * } * } * } * } * \endqml * * 4. List all the online accounts, without their services: * \qml * Item { * AccountServiceModel { * id: accounts * service: "global" * } * * ListView { * model: accounts * delegate: Rectangle { * id: rect * * Text { text: account.displayName } * * Account { * id: account * objectHandle: rect.model.accountHandle * } * } * } * } * \endqml */ AccountServiceModel::AccountServiceModel(QObject *parent): QAbstractListModel(parent), d_ptr(new AccountServiceModelPrivate(this)) { Q_D(AccountServiceModel); d->roleNames[DisplayNameRole] = "displayName"; d->roleNames[ProviderNameRole] = "providerName"; d->roleNames[ServiceNameRole] = "serviceName"; d->roleNames[EnabledRole] = "enabled"; d->roleNames[AccountServiceHandleRole] = "accountServiceHandle"; d->roleNames[AccountServiceRole] = "accountService"; d->roleNames[AccountIdRole] = "accountId"; d->roleNames[AccountHandleRole] = "accountHandle"; d->roleNames[AccountRole] = "account"; QObject::connect(this, SIGNAL(rowsInserted(const QModelIndex &,int,int)), this, SIGNAL(countChanged())); QObject::connect(this, SIGNAL(rowsRemoved(const QModelIndex &,int,int)), this, SIGNAL(countChanged())); } AccountServiceModel::~AccountServiceModel() { delete d_ptr; } void AccountServiceModel::classBegin() { } void AccountServiceModel::componentComplete() { Q_D(AccountServiceModel); d->componentCompleted = true; d->update(); } /*! * \qmlproperty quint32 AccountServiceModel::accountId * If set, the model will list only those accounts services available in the * given account. */ void AccountServiceModel::setAccountId(quint32 accountId) { Q_D(AccountServiceModel); if (accountId == d->accountId) return; d->accountId = accountId; d->accountIdChanged = true; d->queueUpdate(); Q_EMIT accountIdChanged(); } quint32 AccountServiceModel::accountId() const { Q_D(const AccountServiceModel); return d->accountId; } /*! * \qmlproperty Account AccountServiceModel::account * If set, the model will list only those accounts services available in the * given account. */ void AccountServiceModel::setAccount(QObject *object) { Q_D(AccountServiceModel); Accounts::Account *account = qobject_cast<Accounts::Account*>(object); if (account == d->account) return; d->account = account; d->accountChanged = true; d->queueUpdate(); Q_EMIT accountChanged(); } QObject *AccountServiceModel::account() const { Q_D(const AccountServiceModel); return d->account; } /*! * \qmlproperty string AccountServiceModel::applicationId * If set, the model will only show those account services which are relevant * for the given \a applicationId. This means that an account service will only * be shown if it can be used by the application, as described in the * application's manifest file. */ void AccountServiceModel::setApplicationId(const QString &applicationId) { Q_D(AccountServiceModel); if (applicationId == d->application.name()) return; if (applicationId.isEmpty()) { d->application = Accounts::Application(); } else { d->application = SharedManager::instance()->application(applicationId); } d->applicationIdChanged = true; d->queueUpdate(); Q_EMIT applicationIdChanged(); } QString AccountServiceModel::applicationId() const { Q_D(const AccountServiceModel); return d->application.name(); } /*! * \qmlproperty string AccountServiceModel::provider * If set, the model will list only those accounts services provided by this provider. */ void AccountServiceModel::setProvider(const QString &providerId) { Q_D(AccountServiceModel); if (providerId == d->providerId) return; d->providerId = providerId; d->providerChanged = true; d->queueUpdate(); Q_EMIT providerChanged(); } QString AccountServiceModel::provider() const { Q_D(const AccountServiceModel); return d->providerId; } /*! * \qmlproperty string AccountServiceModel::serviceType * If set, the model will list only those accounts services supporting this * service type. Each provider-specific service is an instance of a generic * service type (such as "e-mail", "IM", etc.) which identifies the main * functionality provided by the service. */ void AccountServiceModel::setServiceType(const QString &serviceTypeId) { Q_D(AccountServiceModel); if (serviceTypeId == d->serviceTypeId) return; d->serviceTypeId = serviceTypeId; d->serviceTypeChanged = true; d->queueUpdate(); Q_EMIT serviceTypeChanged(); } QString AccountServiceModel::serviceType() const { Q_D(const AccountServiceModel); return d->serviceTypeId; } /*! * \qmlproperty string AccountServiceModel::service * If set, the model will list only those accounts services for this * specific service. */ void AccountServiceModel::setService(const QString &serviceId) { Q_D(AccountServiceModel); if (serviceId == d->serviceId) return; d->serviceId = serviceId; d->serviceChanged = true; d->queueUpdate(); Q_EMIT serviceChanged(); } QString AccountServiceModel::service() const { Q_D(const AccountServiceModel); return d->serviceId; } /*! * \qmlproperty bool AccountServiceModel::includeDisabled * If true, even disabled account services will be listed. Note that an * application should never use a disabled account. * * By default, this property is false. */ void AccountServiceModel::setIncludeDisabled(bool includeDisabled) { Q_D(AccountServiceModel); if (includeDisabled == d->includeDisabled) return; d->includeDisabled = includeDisabled; d->queueUpdate(); Q_EMIT includeDisabledChanged(); } bool AccountServiceModel::includeDisabled() const { Q_D(const AccountServiceModel); return d->includeDisabled; } /*! * \qmlmethod variant AccountServiceModel::get(int row, string roleName) * * Returns the data at \a row for the role \a roleName. */ QVariant AccountServiceModel::get(int row, const QString &roleName) const { int role = roleNames().key(roleName.toLatin1(), -1); return data(index(row), role); } int AccountServiceModel::rowCount(const QModelIndex &parent) const { Q_D(const AccountServiceModel); Q_UNUSED(parent); return d->modelItems.count(); } QVariant AccountServiceModel::data(const QModelIndex &index, int role) const { Q_D(const AccountServiceModel); if (index.row() >= d->modelItems.count()) return QVariant(); Accounts::AccountService *accountService = d->modelItems.at(index.row()); QVariant ret; QObject *object = 0; switch (role) { case Qt::DisplayRole: ret = QString("%1 - %2"). arg(accountService->account()->displayName()). arg(accountService->service().displayName()); break; case DisplayNameRole: ret = accountService->account()->displayName(); break; case ProviderNameRole: { Accounts::Provider provider = accountService->account()->provider(); ret = provider.displayName(); } break; case ServiceNameRole: ret = accountService->service().displayName(); break; case EnabledRole: ret = accountService->enabled(); break; case AccountServiceRole: qWarning() << "accountService role is deprecated, use accountServiceHandle"; /* FALLTHRU */ case AccountServiceHandleRole: object = accountService; break; case AccountIdRole: ret = accountService->account()->id(); break; case AccountRole: qWarning() << "account role is deprecated, use accountHandle"; /* FALLTHRU */ case AccountHandleRole: object = accountService->account(); break; } if (object) { QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); ret = QVariant::fromValue<QObject*>(object); } return ret; } QHash<int, QByteArray> AccountServiceModel::roleNames() const { Q_D(const AccountServiceModel); return d->roleNames; } #include "account-service-model.moc" 07070100000021000081A4000000000000000000000001653D36F100000E49000000000000000000000000000000000000004F00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/account-service-model.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_ACCOUNT_SERVICE_MODEL_H #define ONLINE_ACCOUNTS_ACCOUNT_SERVICE_MODEL_H #include <QAbstractListModel> #include <QQmlParserStatus> #include <QString> namespace OnlineAccounts { class AccountServiceModelPrivate; class AccountServiceModel: public QAbstractListModel, public QQmlParserStatus { Q_OBJECT Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(int count READ rowCount NOTIFY countChanged) Q_PROPERTY(bool includeDisabled READ includeDisabled \ WRITE setIncludeDisabled NOTIFY includeDisabledChanged) Q_PROPERTY(quint32 accountId READ accountId WRITE setAccountId \ NOTIFY accountIdChanged) Q_PROPERTY(QObject *account READ account WRITE setAccount \ NOTIFY accountChanged) Q_PROPERTY(QString applicationId READ applicationId \ WRITE setApplicationId NOTIFY applicationIdChanged) Q_PROPERTY(QString provider READ provider WRITE setProvider \ NOTIFY providerChanged) Q_PROPERTY(QString serviceType READ serviceType WRITE setServiceType \ NOTIFY serviceTypeChanged) Q_PROPERTY(QString service READ service WRITE setService \ NOTIFY serviceChanged) public: AccountServiceModel(QObject *parent = 0); ~AccountServiceModel(); enum Roles { DisplayNameRole = Qt::UserRole + 1, ProviderNameRole, ServiceNameRole, EnabledRole, AccountServiceHandleRole, AccountServiceRole, // deprecated AccountIdRole, AccountHandleRole, AccountRole, // deprecated }; void setIncludeDisabled(bool includeDisabled); bool includeDisabled() const; void setAccountId(quint32 accountId); quint32 accountId() const; void setAccount(QObject *account); QObject *account() const; void setApplicationId(const QString &applicationId); QString applicationId() const; void setProvider(const QString &providerId); QString provider() const; void setServiceType(const QString &serviceTypeId); QString serviceType() const; void setService(const QString &serviceId); QString service() const; Q_INVOKABLE QVariant get(int row, const QString &roleName) const; // reimplemented virtual methods int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QHash<int, QByteArray> roleNames() const; void classBegin(); void componentComplete(); Q_SIGNALS: void countChanged(); void includeDisabledChanged(); void accountIdChanged(); void accountChanged(); void applicationIdChanged(); void providerChanged(); void serviceTypeChanged(); void serviceChanged(); private: AccountServiceModelPrivate *d_ptr; Q_DECLARE_PRIVATE(AccountServiceModel) }; }; // namespace #endif // ONLINE_ACCOUNTS_ACCOUNT_SERVICE_MODEL_H 07070100000022000081A4000000000000000000000001653D36F10000472F000000000000000000000000000000000000004B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/account-service.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "account-service.h" #include "credentials.h" #include "debug.h" #include <Accounts/AccountService> #include <Accounts/Manager> #include <Accounts/Provider> #include <SignOn/AuthSession> #include <SignOn/Identity> using namespace OnlineAccounts; static QVariantMap mergeMaps(const QVariantMap &map1, const QVariantMap &map2) { if (map1.isEmpty()) return map2; if (map2.isEmpty()) return map1; QVariantMap map = map1; //map2 values will overwrite map1 values for the same keys. QMapIterator<QString, QVariant> it(map2); while (it.hasNext()) { it.next(); map.insert(it.key(), it.value()); } return map; } AccountService::ErrorCode errorCodeFromSignOn(int type) { if (type <= 0) return AccountService::NoError; switch (type) { case SignOn::Error::SessionCanceled: case SignOn::Error::TOSNotAccepted: return AccountService::UserCanceledError; case SignOn::Error::PermissionDenied: case SignOn::Error::InvalidCredentials: case SignOn::Error::NotAuthorized: case SignOn::Error::MethodOrMechanismNotAllowed: return AccountService::PermissionDeniedError; case SignOn::Error::NoConnection: case SignOn::Error::Network: return AccountService::NetworkError; case SignOn::Error::Ssl: return AccountService::SslError; case SignOn::Error::UserInteraction: return AccountService::InteractionRequiredError; default: return AccountService::NoAccountError; } } void AccountService::syncIfDesired() { if (m_autoSync) { Accounts::Account *account = accountService->account(); if (Q_UNLIKELY(account == 0)) return; /* If needed, we could optimize this to call account->sync() when * re-entering the main loop, in order to reduce the number or writes. * But this would be better done in the Account class itself (and even * better, in libaccounts-glib). */ account->sync(); } } /*! * \qmltype AccountService * \inqmlmodule SSO.OnlineAccounts 0.1 * \ingroup Ubuntu * * \brief Represents an instance of a service in an Online Accounts * * The AccountService element represents a service within an existing online account. * It can be used to obtain an authentication token to use the service it refers to. * * Currently, an AccountService is valid only if its \a objectHandle property * is set to a value obtained from an AccountServiceModel or an Account. * * See AccountServiceModel's documentation for usage examples. */ AccountService::AccountService(QObject *parent): QObject(parent), accountService(0), identity(0), m_credentials(0), constructed(false), m_autoSync(true) { } AccountService::~AccountService() { } /*! * \qmlproperty object AccountService::objectHandle * An opaque handle to the underlying C++ object. Until the property is set, * the AccountService element is uninitialized. Similarly, if the C++ object is * destroyed (for instance, because the AccountServiceModel which owns it is * destroyed or if the account is deleted), expect the AccountService to become * invalid. */ void AccountService::setObjectHandle(QObject *object) { DEBUG() << object; Accounts::AccountService *as = qobject_cast<Accounts::AccountService*>(object); if (Q_UNLIKELY(as == 0)) return; if (as == accountService) return; accountService = as; QObject::connect(accountService, SIGNAL(changed()), this, SIGNAL(settingsChanged())); QObject::connect(accountService, SIGNAL(enabled(bool)), this, SIGNAL(enabledChanged())); delete identity; identity = 0; Q_EMIT objectHandleChanged(); /* Emit the changed signals for all other properties, to make sure * that all bindings are updated. */ Q_EMIT enabledChanged(); Q_EMIT displayNameChanged(); Q_EMIT settingsChanged(); } QObject *AccountService::objectHandle() const { return accountService; } /*! * \qmlproperty bool AccountService::enabled * This read-only property tells whether the AccountService is enabled. An * application shouldn't use an AccountService which is disabled. */ bool AccountService::enabled() const { if (Q_UNLIKELY(accountService == 0)) return false; return accountService->enabled(); } /*! * \qmlproperty bool AccountService::serviceEnabled * This read-only property tells whether the service is enabled within the * account. This property differs from the \l enabled property in that the * \l enabled property also considers whether the account is enabled, while * this one only reflects the status of the service. Applications shouldn't * rely on the value on this property to decide whether to use the account or * not. * * \sa enabled */ bool AccountService::serviceEnabled() const { if (Q_UNLIKELY(accountService == 0)) return false; return accountService->value("enabled").toBool(); } /*! * \qmlproperty jsobject AccountService::provider * An immutable object representing the provider which provides the account. * The returned object will have at least these members: * \list * \li \c id is the unique identifier for this provider * \li \c displayName * \li \c iconName * \li \c isSingleAccount, \a true if this provider supports creating one * account at most * \li \c translations, the localization domain for translating the provider's * display name * \endlist */ QVariantMap AccountService::provider() const { QVariantMap map; if (Q_UNLIKELY(accountService == 0)) return map; Accounts::Account *account = accountService->account(); if (account == 0) return map; Accounts::Provider provider = account->provider(); map.insert("id", provider.name()); map.insert("displayName", provider.displayName()); map.insert("iconName", provider.iconName()); map.insert("isSingleAccount", provider.isSingleAccount()); map.insert("translations", provider.trCatalog()); return map; } /*! * \qmlproperty jsobject AccountService::service * An immutable object representing the service which this AccountService * instantiates. * The returned object will have at least these members: * \list * \li \c id is the unique identified for this service * \li \c displayName * \li \c iconName * \li \c serviceTypeId identifies the provided service type * \li \c translations, the localization domain for translating the provider's * display name * \endlist */ QVariantMap AccountService::service() const { QVariantMap map; if (Q_UNLIKELY(accountService == 0)) return map; Accounts::Service service = accountService->service(); map.insert("id", service.name()); map.insert("displayName", service.displayName()); map.insert("iconName", service.iconName()); map.insert("serviceTypeId", service.serviceType()); map.insert("translations", service.trCatalog()); return map; } /*! * \qmlproperty string AccountService::displayName * The account's display name (usually the user's login or ID); note that all * AccountService objects which work on the same online account will share the * same display name. */ QString AccountService::displayName() const { if (Q_UNLIKELY(accountService == 0)) return QString(); return accountService->account()->displayName(); } /*! * \qmlproperty string AccountService::accountId * The account's numeric ID; note that all AccountService objects which work on * the same online account will have the same ID. */ uint AccountService::accountId() const { if (Q_UNLIKELY(accountService == 0)) return 0; return accountService->account()->id(); } /*! * \qmlproperty jsobject AccountService::settings * A dictionary of all the account service's settings. This does not * include the authentication settings, which are available from the * AccountService::authData property. */ QVariantMap AccountService::settings() const { QVariantMap map; if (Q_UNLIKELY(accountService == 0)) return map; foreach (const QString &key, accountService->allKeys()) { if (key.startsWith("auth") || key == "enabled") continue; map.insert(key, accountService->value(key)); } return map; } /*! * \qmlproperty jsobject AccountService::authData * An object providing information about the authentication. * The returned object will have at least these members: * \list * \li \c method is the authentication method * \li \c mechanism is the authentication mechanism (a sub-specification of the * method) * \li \c parameters is a dictionary of authentication parameters * \li \c credentialsId is the numeric identified of the credentials in the * secrets storage. See the \l Credentials element for more info. * \endlist */ QVariantMap AccountService::authData() const { QVariantMap map; if (Q_UNLIKELY(accountService == 0)) return map; Accounts::AuthData data = accountService->authData(); map.insert("method", data.method()); map.insert("mechanism", data.mechanism()); map.insert("credentialsId", data.credentialsId()); map.insert("parameters", data.parameters()); return map; } /*! * \qmlproperty bool AccountService::autoSync * This property tells whether the AccountService should invoke the * Account::sync() method whenever updateSettings(), updateDisplayName() or * updateServiceEnabled() are called. * By default, this property is true. */ void AccountService::setAutoSync(bool autoSync) { if (autoSync == m_autoSync) return; m_autoSync = autoSync; Q_EMIT autoSyncChanged(); } bool AccountService::autoSync() const { return m_autoSync; } /*! * \qmlproperty Credentials AccountService::credentials * The credentials used by this account service. This property is meant to be * used only when creating or editing the account, and serves to bind a * credentials record to the account: when the value of the \l * Credentials::credentialsId changes, an update of \l * {authData}{authData.credentialsId} will be queued (and immediately executed * if \l autoSync is \c true). * By default, reading this property returns a null object. */ void AccountService::setCredentials(QObject *credentials) { if (credentials == m_credentials) return; m_credentials = credentials; if (m_credentials != 0) { credentialsIdProperty = QQmlProperty(m_credentials, "credentialsId"); credentialsIdProperty.connectNotifySignal(this, SLOT(onCredentialsIdChanged())); onCredentialsIdChanged(); } else { credentialsIdProperty = QQmlProperty(); } Q_EMIT credentialsChanged(); } QObject *AccountService::credentials() const { return m_credentials; } /*! * \qmlmethod void AccountService::updateServiceEnabled(bool enabled) * * Enables or disables the service within the account configuration. * Since the \l enabled property is the combination of the global account's * enabledness status and the specific service's status, its value might not * change after this method is called. * * \sa enabled, serviceEnabled, autoSync */ void AccountService::updateServiceEnabled(bool enabled) { if (Q_UNLIKELY(accountService == 0)) return; Accounts::Account *account = accountService->account(); if (Q_UNLIKELY(account == 0)) return; account->selectService(accountService->service()); account->setEnabled(enabled); syncIfDesired(); } /*! * \qmlmethod void AccountService::updateSettings(jsobject settings) * * Change some settings. Only the settings which are present in the \a settings * dictionary will be changed; all others settings will not be affected. * To remove a settings, set its value to null. * * \sa autoSync */ void AccountService::updateSettings(const QVariantMap &settings) { if (Q_UNLIKELY(accountService == 0)) return; QMapIterator<QString, QVariant> it(settings); while (it.hasNext()) { it.next(); if (it.value().isNull()) { accountService->remove(it.key()); } else { accountService->setValue(it.key(), it.value()); } } syncIfDesired(); } /*! * \qmlmethod void AccountService::authenticate(jsobject sessionData) * * Perform the authentication on this account, by the method and mechanism * specified in the \l authData dictionary of this account. * The \a sessionData dictionary is optional and if not given the value of * \l {authData}{authData::parameters} will be used. * * Each call to this method will cause either of \l authenticated or * \l authenticationError signals to be emitted at some time later. Note that * the authentication might involve interactions with the network or with the * end-user, so don't expect these signals to be emitted immediately. * * \sa authenticated, authenticationError */ void AccountService::authenticate(const QVariantMap &sessionData) { authenticate(QString(), QString(), sessionData); } /*! * \qmlmethod void AccountService::authenticate(string method, string mechanism, jsobject sessionData) * * Perform the authentication on this account. * The \a sessionData dictionary is optional and if not given the value of * \l {authData}{authData::parameters} will be used. * * Each call to this method will cause either of \l authenticated or * \l authenticationError signals to be emitted at some time later. Note that * the authentication might involve interactions with the network or with the * end-user, so don't expect these signals to be emitted immediately. * * \sa authenticated, authenticationError */ void AccountService::authenticate(const QString &method, const QString &mechanism, const QVariantMap &sessionData) { DEBUG() << sessionData; if (Q_UNLIKELY(accountService == 0)) { QVariantMap error; error.insert("code", NoAccountError); error.insert("message", QLatin1String("Invalid AccountService")); Q_EMIT authenticationError(error); return; } Accounts::AuthData authData = accountService->authData(); QString usedMethod = method.isEmpty() ? authData.method() : method; QString usedMechanism = mechanism.isEmpty() ? authData.mechanism() : mechanism; /* Due to https://gitlab.com/accounts-sso/signond/issues/2 we cannot freely * get new authSessions out of the same Identity object: createSession() * returns 0 if a session already exists for the requested method. * There are two possible workarounds: * 1) Keep a map or methods : authSessions * 2) Destroy the identity and get a new one * The latter seems simpler and less wasteful of memory resources, so * that's our choice here. */ if (authSession && usedMethod != authSession->name()) { delete identity; identity = 0; } if (identity == 0) { quint32 credentialsId = credentialsIdProperty.read().toUInt(); if (credentialsId == 0) credentialsId = authData.credentialsId(); identity = SignOn::Identity::existingIdentity(credentialsId, this); } if (authSession == 0) { authSession = identity->createSession(usedMethod); QObject::connect(authSession, SIGNAL(response(const SignOn::SessionData&)), this, SLOT(onAuthSessionResponse(const SignOn::SessionData&))); QObject::connect(authSession, SIGNAL(error(const SignOn::Error&)), this, SLOT(onAuthSessionError(const SignOn::Error&))); } QVariantMap allSessionData = mergeMaps(authData.parameters(), sessionData); authSession->process(allSessionData, usedMechanism); } /*! * \qmlmethod void AccountService::cancelAuthentication() * * Cancel an ongoing authentication on this account. This method does nothing * if there isn't any authentication process going on. * * \sa authenticate */ void AccountService::cancelAuthentication() { DEBUG(); if (authSession != 0) { authSession->cancel(); } } /*! * \qmlsignal AccountService::authenticated(jsobject reply) * * Emitted when the authentication has been successfully completed. The \a * reply object will contain the authentication data, which depends on the * authentication method used. */ /*! * \qmlsignal AccountService::authenticationError(jsobject error) * * Emitted when the authentication fails. The \a error object will contain the * following fields: * \list * \li \c code is a numeric error code (see Signon::Error for the meaning) * \li \c message is a textual description of the error, not meant for the end-user * \endlist */ void AccountService::classBegin() { } void AccountService::componentComplete() { constructed = true; } void AccountService::onAuthSessionResponse(const SignOn::SessionData &sessionData) { Q_EMIT authenticated(sessionData.toMap()); } void AccountService::onAuthSessionError(const SignOn::Error &error) { QVariantMap e; e.insert("code", errorCodeFromSignOn(error.type())); e.insert("message", error.message()); Q_EMIT authenticationError(e); } void AccountService::onCredentialsIdChanged() { if (accountService) { QVariant value = credentialsIdProperty.read(); accountService->setValue("CredentialsId", value); syncIfDesired(); } } 07070100000023000081A4000000000000000000000001653D36F1000011CD000000000000000000000000000000000000004900000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/account-service.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_ACCOUNT_SERVICE_H #define ONLINE_ACCOUNTS_ACCOUNT_SERVICE_H #include <QObject> #include <QPointer> #include <QQmlParserStatus> #include <QQmlProperty> #include <QVariantMap> namespace Accounts { class AccountService; }; namespace SignOn { class AuthSession; class Error; class Identity; class SessionData; }; namespace OnlineAccounts { class AccountService: public QObject, public QQmlParserStatus { Q_OBJECT Q_INTERFACES(QQmlParserStatus) Q_ENUMS(ErrorCode UiPolicy) Q_PROPERTY(QObject *objectHandle READ objectHandle \ WRITE setObjectHandle NOTIFY objectHandleChanged) Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged) Q_PROPERTY(bool serviceEnabled READ serviceEnabled NOTIFY settingsChanged) Q_PROPERTY(QVariantMap provider READ provider NOTIFY objectHandleChanged) Q_PROPERTY(QVariantMap service READ service NOTIFY objectHandleChanged) Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged) Q_PROPERTY(uint accountId READ accountId NOTIFY objectHandleChanged) Q_PROPERTY(QVariantMap settings READ settings NOTIFY settingsChanged) Q_PROPERTY(QVariantMap authData READ authData NOTIFY settingsChanged) Q_PROPERTY(bool autoSync READ autoSync WRITE setAutoSync \ NOTIFY autoSyncChanged) Q_PROPERTY(QObject *credentials READ credentials WRITE setCredentials \ NOTIFY credentialsChanged) public: enum ErrorCode { NoError = 0, NoAccountError, UserCanceledError, PermissionDeniedError, NetworkError, SslError, InteractionRequiredError, }; enum UiPolicy { /* Keep these in sync with those defined in SignOn/SessionData */ DefaultPolicy = 0, RequestPasswordPolicy, NoUserInteractionPolicy, ValidationPolicy, }; AccountService(QObject *parent = 0); ~AccountService(); void setObjectHandle(QObject *object); QObject *objectHandle() const; bool enabled() const; bool serviceEnabled() const; QVariantMap provider() const; QVariantMap service() const; QString displayName() const; uint accountId() const; QVariantMap settings() const; QVariantMap authData() const; void setAutoSync(bool autoSync); bool autoSync() const; void setCredentials(QObject *credentials); QObject *credentials() const; Q_INVOKABLE void authenticate(const QVariantMap &sessionData = QVariantMap()); Q_INVOKABLE void authenticate(const QString &method, const QString &mechanism, const QVariantMap &sessionData = QVariantMap()); Q_INVOKABLE void cancelAuthentication(); Q_INVOKABLE void updateServiceEnabled(bool enabled); Q_INVOKABLE void updateSettings(const QVariantMap &settings); // reimplemented virtual methods void classBegin(); void componentComplete(); Q_SIGNALS: void objectHandleChanged(); void enabledChanged(); void displayNameChanged(); void settingsChanged(); void autoSyncChanged(); void credentialsChanged(); void authenticated(const QVariantMap &reply); void authenticationError(const QVariantMap &error); private Q_SLOTS: void onAuthSessionResponse(const SignOn::SessionData &sessionData); void onAuthSessionError(const SignOn::Error &error); void onCredentialsIdChanged(); private: void syncIfDesired(); private: QPointer<Accounts::AccountService> accountService; SignOn::Identity *identity; QPointer<SignOn::AuthSession> authSession; QPointer<QObject> m_credentials; QQmlProperty credentialsIdProperty; bool constructed; bool m_autoSync; }; }; // namespace #endif // ONLINE_ACCOUNTS_ACCOUNT_SERVICE_H 07070100000024000081A4000000000000000000000001653D36F100001E82000000000000000000000000000000000000004300000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/account.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "account.h" #include "debug.h" #include <Accounts/Account> #include <Accounts/AccountService> #include <Accounts/Provider> #include <SignOn/Identity> using namespace OnlineAccounts; /*! * \qmltype Account * \inqmlmodule SSO.OnlineAccounts 0.1 * \ingroup Ubuntu * * \brief Represents an instance of an online account. * * The Account element represents an online account. It is functional only if * its \a objectHandle property is set to a valid account, which can be * obtained with Manager.loadAccount() or Manager.createAccount(). */ Account::Account(QObject *parent): QObject(parent), account(0), accountService(0) { } Account::~Account() { } /*! * \qmlproperty object Account::objectHandle * An opaque handle to the underlying C++ object. Until the property is set, * the Account element is uninitialized. Similarly, if the C++ object is * destroyed, expect the Account to become invalid. */ void Account::setObjectHandle(QObject *object) { DEBUG() << object; Accounts::Account *a = qobject_cast<Accounts::Account*>(object); if (Q_UNLIKELY(a == 0)) return; if (a == account) return; account = a; QObject::connect(account, SIGNAL(displayNameChanged(const QString &)), this, SIGNAL(displayNameChanged())); QObject::connect(account, SIGNAL(synced()), this, SIGNAL(synced())); QObject::connect(account, SIGNAL(removed()), this, SLOT(onRemoved())); /* Setup an AccountService object to monitor the settings of the global * account. */ delete accountService; accountService = new Accounts::AccountService(account, Accounts::Service(), account); QObject::connect(accountService, SIGNAL(enabled(bool)), this, SIGNAL(enabledChanged())); Q_EMIT objectHandleChanged(); /* Emit the changed signals for all other properties, to make sure * that all bindings are updated. */ Q_EMIT accountIdChanged(); Q_EMIT enabledChanged(); Q_EMIT displayNameChanged(); } QObject *Account::objectHandle() const { return account; } /*! * \qmlproperty bool Account::enabled * This read-only property tells whether the Account is enabled. An * application shouldn't use an Account which is disabled. */ bool Account::enabled() const { if (Q_UNLIKELY(accountService == 0)) return false; return accountService->enabled(); } /*! * \qmlproperty jsobject Account::provider * An immutable object representing the provider which provides the account. * The returned object will have at least these members: * \list * \li \c id is the unique identified for this provider * \li \c displayName * \li \c iconName * \endlist */ QVariantMap Account::provider() const { QVariantMap map; if (Q_UNLIKELY(account == 0)) return map; Accounts::Provider provider = account->provider(); map.insert("id", provider.name()); map.insert("displayName", provider.displayName()); map.insert("iconName", provider.iconName()); return map; } /*! * \qmlproperty string Account::displayName * The account's display name (usually the user's login or ID). */ QString Account::displayName() const { if (Q_UNLIKELY(account == 0)) return QString(); return account->displayName(); } /*! * \qmlproperty string Account::accountId * The account's numeric ID. This is 0 until the account has been stored into the DB. */ uint Account::accountId() const { if (Q_UNLIKELY(account == 0)) return 0; return account->id(); } /*! * \qmlproperty object Account::accountServiceHandle * A C++ object which can be used to instantiate an AccountService by setting * it as the value for the \l AccountService::objectHandle property. */ QObject *Account::accountServiceHandle() const { return accountService; } /*! * \qmlmethod void Account::updateDisplayName(string displayName) * * Changes the display name of the account. * * \sa sync() */ void Account::updateDisplayName(const QString &displayName) { if (Q_UNLIKELY(account == 0)) return; account->setDisplayName(displayName); } /*! * \qmlmethod void Account::updateEnabled(bool enabled) * * Enables or disables the account. * * \sa sync() */ void Account::updateEnabled(bool enabled) { if (Q_UNLIKELY(account == 0)) return; account->selectService(); account->setEnabled(enabled); } /*! * \qmlmethod void Account::sync() * * Writes the changes to the permanent account storage. */ void Account::sync() { if (Q_UNLIKELY(account == 0)) return; account->sync(); } /*! * \qmlmethod void Account::remove() * * Deletes the account from the permanent storage. This method accepts an * optional parameter, which tells whether the credentials associated with * the account should also be removed: * \list * \li \c Account.RemoveAccountOnly * \li \c Account.RemoveCredentials - the default * \endlist */ void Account::remove(RemovalOptions options) { if (Q_UNLIKELY(account == 0)) return; if (options & RemoveCredentials) { /* Get all the IDs of the credentials used by this account */ QList<uint> credentialIds; account->selectService(); uint credentialsId = account->value("CredentialsId").toUInt(); if (credentialsId != 0) credentialIds.append(credentialsId); Q_FOREACH (const Accounts::Service &service, account->services()) { account->selectService(service); credentialsId = account->value("CredentialsId").toUInt(); if (credentialsId != 0) credentialIds.append(credentialsId); } /* Instantiate an Identity object for each of them */ Q_FOREACH (uint credentialsId, credentialIds) { SignOn::Identity *identity = SignOn::Identity::existingIdentity(credentialsId, this); QObject::connect(identity, SIGNAL(removed()), this, SLOT(onIdentityRemoved())); /* Since we don't do any error handling in case the removal of the * identity failed, we connect to the same slot. */ QObject::connect(identity, SIGNAL(error(const SignOn::Error&)), this, SLOT(onIdentityRemoved())); identities.append(identity); } } account->remove(); account->sync(); } /*! * \qmlsignal Account::synced() * * Emitted when the account changes have been stored into the permanent storage. */ void Account::onRemoved() { Q_FOREACH (SignOn::Identity *identity, identities) { /* Remove the associated credentials */ identity->remove(); } /* Don't emit the removed() signal until all associated Identity objects * have been removed */ if (identities.isEmpty()) { Q_EMIT removed(); } } void Account::onIdentityRemoved() { SignOn::Identity *identity = qobject_cast<SignOn::Identity *>(sender()); identities.removeAll(identity); identity->deleteLater(); if (identities.isEmpty()) { Q_EMIT removed(); } } 07070100000025000081A4000000000000000000000001653D36F100000B04000000000000000000000000000000000000004100000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/account.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_ACCOUNT_H #define ONLINE_ACCOUNTS_ACCOUNT_H #include <QList> #include <QObject> #include <QPointer> #include <QVariantMap> namespace Accounts { class Account; class AccountService; }; namespace SignOn { class Identity; }; namespace OnlineAccounts { class Account: public QObject { Q_OBJECT Q_PROPERTY(QObject *objectHandle READ objectHandle \ WRITE setObjectHandle NOTIFY objectHandleChanged) Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged) Q_PROPERTY(QVariantMap provider READ provider NOTIFY objectHandleChanged) Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged) Q_PROPERTY(uint accountId READ accountId NOTIFY accountIdChanged) Q_PROPERTY(QObject *accountServiceHandle READ accountServiceHandle \ NOTIFY objectHandleChanged) public: enum RemovalOption { RemoveAccountOnly = 0x0, RemoveCredentials = 0x1, }; Q_DECLARE_FLAGS(RemovalOptions, RemovalOption) Q_FLAGS(RemovalOption RemovalOptions) Account(QObject *parent = 0); ~Account(); void setObjectHandle(QObject *object); QObject *objectHandle() const; bool enabled() const; QVariantMap provider() const; QString displayName() const; uint accountId() const; QObject *accountServiceHandle() const; Q_INVOKABLE void updateDisplayName(const QString &displayName); Q_INVOKABLE void updateEnabled(bool enabled); Q_INVOKABLE void sync(); Q_INVOKABLE void remove(RemovalOptions options = RemoveCredentials); Q_SIGNALS: void objectHandleChanged(); void accountIdChanged(); void enabledChanged(); void displayNameChanged(); void synced(); void removed(); private Q_SLOTS: void onRemoved(); void onIdentityRemoved(); private: QPointer<Accounts::Account> account; QPointer<Accounts::AccountService> accountService; QList<SignOn::Identity *> identities; }; }; // namespace Q_DECLARE_OPERATORS_FOR_FLAGS(OnlineAccounts::Account::RemovalOptions) #endif // ONLINE_ACCOUNTS_ACCOUNT_H 07070100000026000081A4000000000000000000000001653D36F1000002D3000000000000000000000000000000000000004500000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/accounts.qdoc/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /*! \qmlmodule SSO.OnlineAccounts 0.1 \title SSO.OnlineAccounts */ 07070100000027000081A4000000000000000000000001653D36F100001281000000000000000000000000000000000000004D00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/application-model.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "debug.h" #include "application-model.h" #include "application.h" #include <Accounts/Manager> #include <QQmlEngine> using namespace OnlineAccounts; /*! * \qmltype ApplicationModel * \inqmlmodule SSO.OnlineAccounts 0.1 * \ingroup Ubuntu * * \brief A model of the applications using online accounts. * * The ApplicationModel is a model representing the applications using online * accounts installed on the system. * * In the current implementation, the model is valid only if its \l * ApplicationModel::service property is set to a valid service ID. * * The model defines the following roles: * \list * \li \c applicationId is the unique identifier of the application * \li \c displayName is the application display name * \li \c iconName is the name of the application icon * \li \c serviceUsage is a description of how the application uses the * service; this is set to a valid value only if the \l * ApplicationModel::service property is set to a valid service ID. * \li \c application is the Application object * \li \c translations, the localization domain for translating the * \c serviceUsage field * \endlist */ ApplicationModel::ApplicationModel(QObject *parent): QAbstractListModel(parent), manager(SharedManager::instance()) { } ApplicationModel::~ApplicationModel() { } /*! * \qmlproperty int ApplicationModel::count * The number of items in the model. */ int ApplicationModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return applications.count(); } /*! * \qmlproperty string ApplicationModel::service * If set, the model will list only those applications which can use this * specific service. */ void ApplicationModel::setService(const QString &serviceId) { if (serviceId == m_service.name()) return; m_service = manager->service(serviceId); beginResetModel(); qDeleteAll(applications); applications.clear(); computeApplicationList(); endResetModel(); Q_EMIT serviceChanged(); } QString ApplicationModel::service() const { return m_service.name(); } /*! * \qmlmethod variant ApplicationModel::get(int row, string roleName) * * Returns the data at \a row for the role \a roleName. */ QVariant ApplicationModel::get(int row, const QString &roleName) const { int role = roleNames().key(roleName.toLatin1(), -1); return data(index(row), role); } QVariant ApplicationModel::data(const QModelIndex &index, int role) const { if (index.row() < 0 || index.row() >= applications.count()) return QVariant(); Application *application = applications.at(index.row()); QVariant ret; switch (role) { case Qt::DisplayRole: case ApplicationIdRole: ret = application->name(); break; case DisplayNameRole: ret = application->displayName(); break; case IconNameRole: ret = application->iconName(); break; case ServiceUsageRole: ret = application->serviceUsage(m_service); break; case ApplicationRole: QQmlEngine::setObjectOwnership(application, QQmlEngine::CppOwnership); ret = QVariant::fromValue<QObject*>(application); break; case TranslationsRole: ret = application->trCatalog(); break; } return ret; } QHash<int, QByteArray> ApplicationModel::roleNames() const { static QHash<int, QByteArray> roles; if (roles.isEmpty()) { roles[ApplicationIdRole] = "applicationId"; roles[DisplayNameRole] = "displayName"; roles[IconNameRole] = "iconName"; roles[ServiceUsageRole] = "serviceUsage"; roles[ApplicationRole] = "application"; roles[TranslationsRole] = "translations"; } return roles; } void ApplicationModel::computeApplicationList() { if (!m_service.isValid()) return; Q_FOREACH(const Accounts::Application &app, manager->applicationList(m_service)) { applications.append(new Application(app, this)); } } 07070100000028000081A4000000000000000000000001653D36F100000873000000000000000000000000000000000000004B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/application-model.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_APPLICATION_MODEL_H #define ONLINE_ACCOUNTS_APPLICATION_MODEL_H #include "manager.h" #include <Accounts/Service> #include <QAbstractListModel> #include <QList> #include <QSharedPointer> namespace OnlineAccounts { class Application; class ApplicationModel: public QAbstractListModel { Q_OBJECT Q_PROPERTY(int count READ rowCount NOTIFY countChanged) Q_PROPERTY(QString service READ service WRITE setService \ NOTIFY serviceChanged) public: ApplicationModel(QObject *parent = 0); ~ApplicationModel(); enum Roles { ApplicationIdRole = Qt::UserRole + 1, DisplayNameRole, IconNameRole, ServiceUsageRole, ApplicationRole, TranslationsRole, }; void setService(const QString &serviceId); QString service() const; Q_INVOKABLE QVariant get(int row, const QString &roleName) const; // reimplemented virtual methods int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QHash<int, QByteArray> roleNames() const; Q_SIGNALS: void countChanged(); void serviceChanged(); private: void computeApplicationList(); private: QSharedPointer<Accounts::Manager> manager; QList<Application*> applications; Accounts::Service m_service; }; }; // namespace #endif // ONLINE_ACCOUNTS_APPLICATION_MODEL_H 07070100000029000081A4000000000000000000000001653D36F100000740000000000000000000000000000000000000004700000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/application.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "application.h" #include "debug.h" using namespace OnlineAccounts; /*! * \qmltype Application * \inqmlmodule SSO.OnlineAccounts 0.1 * \ingroup Ubuntu * * \brief Represents a client application of Online Accounts. * * The Application element represents an application using online accounts. * Currently, instances of this object cannot be created directly, but are * instantiated by the \l ApplicationModel element. */ Application::Application(const Accounts::Application &application, QObject *parent): QObject(parent), Accounts::Application(application) { } Application::~Application() { } /*! * \qmlproperty string Application::applicationId * Unique identifier for this application. */ /*! * \qmlproperty string Application::description * Description of the application. */ /*! * \qmlmethod string Application::serviceUsage(Service service) * * Returns a textual description of how the application can make use of \a * service. */ QString Application::serviceUsage(const Accounts::Service &service) { return Accounts::Application::serviceUsage(service); } 0707010000002A000081A4000000000000000000000001653D36F10000052A000000000000000000000000000000000000004500000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/application.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_APPLICATION_H #define ONLINE_ACCOUNTS_APPLICATION_H #include <QObject> #include <Accounts/Application> namespace OnlineAccounts { class Application: public QObject, public Accounts::Application { Q_OBJECT Q_PROPERTY(QString applicationId READ name CONSTANT) Q_PROPERTY(QString description READ description CONSTANT) public: Application(const Accounts::Application &application, QObject *parent = 0); ~Application(); Q_INVOKABLE QString serviceUsage(const Accounts::Service &service); }; }; // namespace #endif // ONLINE_ACCOUNTS_APPLICATION_H 0707010000002B000081A4000000000000000000000001653D36F100001E76000000000000000000000000000000000000004700000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/credentials.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "credentials.h" #include "debug.h" using namespace OnlineAccounts; /*! * \qmltype Credentials * \inqmlmodule SSO.OnlineAccounts 0.1 * \ingroup Ubuntu * * \brief Holds the account's credentials * * The Credentials element contains the information about an account's * credentials. Informations like user name and password are stored into the * account's secret storage via this object. * If the \l credentialsId property is set to a valid credentials ID (which can * be obtained via the AccountService's \l * {AccountService::authData}{authData.credentialsId} property) the Credentials * element will load the informations stored in the secrets database, with the * notable exception of the \l secret field, which cannot be read back via this * interface (but only via the \l AccountService::authenticate method); if the * \l credentialsId field is not set, then this interface can be used to create * a new record in the secrets storage, by calling the \l sync() method once * all the desired fields have been set. */ Credentials::Credentials(QObject *parent): QObject(parent), m_credentialsId(0), identity(0) { } Credentials::~Credentials() { } /*! * \qmlproperty quint32 Credentials::credentialsId * Numeric identifier of the credentials record in the secret storage database. * A value of \a 0 means that this object has not been stored into the database * yet. * \sa sync */ void Credentials::setCredentialsId(quint32 credentialsId) { if (credentialsId == m_credentialsId) return; delete identity; if (credentialsId != 0) { identity = SignOn::Identity::existingIdentity(credentialsId, this); if (identity != 0) { setupIdentity(); identity->queryInfo(); } } else { identity = 0; /* We'll instantiate it if/when needed */ } m_credentialsId = credentialsId; Q_EMIT credentialsIdChanged(); } quint32 Credentials::credentialsId() const { return m_credentialsId; } /*! * \qmlproperty string Credentials::caption * A description of the credentials. This could be set to the name of the * account provider, for instance. */ void Credentials::setCaption(const QString &caption) { if (caption == info.caption()) return; info.setCaption(caption); Q_EMIT captionChanged(); } QString Credentials::caption() const { return info.caption(); } /*! * \qmlproperty string Credentials::userName * The user name. */ void Credentials::setUserName(const QString &userName) { if (userName == info.userName()) return; info.setUserName(userName); Q_EMIT userNameChanged(); } QString Credentials::userName() const { return info.userName(); } /*! * \qmlproperty string Credentials::secret * The secret information for this credentials; usually this is the user's password. * Note that when retrieving a Credentials object from the secrets database, * this field will not be retrieved. See the detailed description of the * Credentials element for a full explanation of this. * * \sa credentialsId */ void Credentials::setSecret(const QString &secret) { info.setSecret(secret); Q_EMIT secretChanged(); } QString Credentials::secret() const { return info.secret(); } /*! * \qmlproperty bool Credentials::storeSecret * Whether the secret should be stored in the secrets storage. */ void Credentials::setStoreSecret(bool storeSecret) { if (storeSecret == info.isStoringSecret()) return; info.setStoreSecret(storeSecret); Q_EMIT storeSecretChanged(); } bool Credentials::storeSecret() const { return info.isStoringSecret(); } /*! * \qmlproperty list<string> Credentials::acl * The ACL (Access Control List) for the credentials. The string \a "*" should * be used when no access control needs to be performed. */ void Credentials::setAcl(const QStringList &acl) { info.setAccessControlList(acl); Q_EMIT aclChanged(); } QStringList Credentials::acl() const { return info.accessControlList(); } /*! * \qmlproperty jsobject Credentials::methods * A dictionary describing the authentication methods and mechanisms which are * allowed on the credentials. The keys of the dictionary should be the * authentication methods, and the values should be lists of mechanisms. * \qml * Credentials { * methods: { "oauth2": [ "web_server", "user_agent"], "password": [ "password" ] } * } * \endqml */ void Credentials::setMethods(const QVariantMap &methods) { /* To keep things simple, always delete all existing methods, and then add * the new ones. */ Q_FOREACH (const QString &method, info.methods()) { info.removeMethod(method); } QMapIterator<QString, QVariant> it(methods); while (it.hasNext()) { it.next(); info.setMethod(it.key(), it.value().toStringList()); } } QVariantMap Credentials::methods() const { QVariantMap methods; Q_FOREACH (const QString &method, info.methods()) { QStringList mechanisms = info.mechanisms(method); methods.insert(method, mechanisms); } return methods; } /*! * \qmlmethod void Credentials::sync() * * Writes the changes to the secrets storage. * * \sa synced */ void Credentials::sync() { ensureIdentity(); identity->storeCredentials(info); } /*! * \qmlmethod void Credentials::remove() * * Deletes the credentials from the secrets storage. * * \sa removed */ void Credentials::remove() { /* If we don't have an identity object, this means that this object was * never stored; we have nothing to do in this case. */ if (Q_UNLIKELY(identity == 0)) return; identity->remove(); } /*! * \qmlsignal Credentials::synced() * * Emitted when the changes have been stored into the permanent secrets storage. */ /*! * \qmlsignal Credentials::removed() * * Emitted when the credentials have been deleted from the secrets storage. */ void Credentials::ensureIdentity() { if (identity == 0) { identity = SignOn::Identity::newIdentity(info, this); setupIdentity(); } } void Credentials::setupIdentity() { QObject::connect(identity, SIGNAL(info(const SignOn::IdentityInfo&)), this, SLOT(onInfo(const SignOn::IdentityInfo&))); QObject::connect(identity, SIGNAL(credentialsStored(const quint32)), this, SLOT(onStored(const quint32))); QObject::connect(identity, SIGNAL(removed()), this, SIGNAL(removed())); } void Credentials::onInfo(const SignOn::IdentityInfo &info) { this->info = info; /* Emit the notification signals for all the properties; if this turns out * to be an issue, we could just emit the signals for those properties * whose value actually changed. */ Q_EMIT credentialsIdChanged(); Q_EMIT captionChanged(); Q_EMIT userNameChanged(); Q_EMIT secretChanged(); Q_EMIT storeSecretChanged(); Q_EMIT aclChanged(); Q_EMIT methodsChanged(); Q_EMIT synced(); } void Credentials::onStored(const quint32 id) { m_credentialsId = id; identity->queryInfo(); } 0707010000002C000081A4000000000000000000000001653D36F100000B6A000000000000000000000000000000000000004500000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/credentials.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_CREDENTIALS_H #define ONLINE_ACCOUNTS_CREDENTIALS_H #include <QObject> #include <QPointer> #include <QStringList> #include <QVariantMap> #include <SignOn/Identity> namespace OnlineAccounts { class Credentials: public QObject { Q_OBJECT Q_PROPERTY(quint32 credentialsId READ credentialsId WRITE setCredentialsId \ NOTIFY credentialsIdChanged) Q_PROPERTY(QString caption READ caption WRITE setCaption \ NOTIFY captionChanged) Q_PROPERTY(QString userName READ userName WRITE setUserName \ NOTIFY userNameChanged) Q_PROPERTY(QString secret READ secret WRITE setSecret NOTIFY secretChanged) Q_PROPERTY(bool storeSecret READ storeSecret WRITE setStoreSecret \ NOTIFY storeSecretChanged) Q_PROPERTY(QStringList acl READ acl WRITE setAcl NOTIFY aclChanged) Q_PROPERTY(QVariantMap methods READ methods WRITE setMethods NOTIFY methodsChanged) public: Credentials(QObject *parent = 0); ~Credentials(); void setCredentialsId(quint32 credentialsId); quint32 credentialsId() const; void setCaption(const QString &caption); QString caption() const; void setUserName(const QString &userName); QString userName() const; void setSecret(const QString &secret); QString secret() const; void setStoreSecret(bool storeSecret); bool storeSecret() const; void setAcl(const QStringList &acl); QStringList acl() const; void setMethods(const QVariantMap &methods); QVariantMap methods() const; Q_INVOKABLE void sync(); Q_INVOKABLE void remove(); Q_SIGNALS: void credentialsIdChanged(); void captionChanged(); void userNameChanged(); void secretChanged(); void storeSecretChanged(); void aclChanged(); void methodsChanged(); void synced(); void removed(); private: void ensureIdentity(); void setupIdentity(); private Q_SLOTS: void onInfo(const SignOn::IdentityInfo &info); void onStored(const quint32 id); private: quint32 m_credentialsId; SignOn::Identity *identity; SignOn::IdentityInfo info; }; }; // namespace #endif // ONLINE_ACCOUNTS_CREDENTIALS_H 0707010000002D000081A4000000000000000000000001653D36F100000385000000000000000000000000000000000000004100000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/debug.cpp/* * Copyright (C) 2015-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "debug.h" int accounts_qml_module_logging_level = 1; namespace OnlineAccounts { void setLoggingLevel(int level) { accounts_qml_module_logging_level = level; } } 0707010000002E000081A4000000000000000000000001653D36F100000561000000000000000000000000000000000000003F00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/debug.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_DEBUG_H #define ONLINE_ACCOUNTS_DEBUG_H #include <QDebug> #ifdef DEBUG_ENABLED extern int accounts_qml_module_logging_level; static inline bool debugEnabled() { return accounts_qml_module_logging_level >= 2; } static inline bool criticalsEnabled() { return accounts_qml_module_logging_level >= 1; } #define DEBUG() \ if (debugEnabled()) qDebug() #define BLAME() \ if (criticalsEnabled()) qCritical() #else // DEBUG_ENABLED #define DEBUG() while (0) qDebug() #define WARNING() while (0) qDebug() #endif namespace OnlineAccounts { void setLoggingLevel(int level); } #endif // ONLINE_ACCOUNTS_DEBUG_H 0707010000002F000081A4000000000000000000000001653D36F10000089A000000000000000000000000000000000000004300000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/manager.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "manager.h" #include "debug.h" #include <Accounts/Manager> #include <QWeakPointer> using namespace OnlineAccounts; static QWeakPointer<Accounts::Manager> sharedManager; QSharedPointer<Accounts::Manager> SharedManager::instance() { QSharedPointer<Accounts::Manager> manager = sharedManager.toStrongRef(); if (manager.isNull()) { manager = QSharedPointer<Accounts::Manager>(new Accounts::Manager); sharedManager = manager; } return manager; } /*! * \qmltype Manager * \inqmlmodule SSO.OnlineAccounts 0.1 * \ingroup Ubuntu * * \brief The account manager * * The Manager element is a singleton class which can be used to create new * online accounts or load existing ones. */ Manager::Manager(QObject *parent): QObject(parent), manager(SharedManager::instance()) { } Manager::~Manager() { } /*! * \qmlmethod object Manager::loadAccount(uint accountId) * * Loads the account identified by \a accountId. The returned object can be * used to instantiate an \l Account. * * \sa createAccount() */ QObject *Manager::loadAccount(uint accountId) { DEBUG() << accountId; return manager->account(accountId); } /*! * \qmlmethod object Manager::createAccount(string providerName) * * Create a new account interfacing to the provider identified by \a * providerName. * * \sa loadAccount() */ QObject *Manager::createAccount(const QString &providerName) { return manager->createAccount(providerName); } 07070100000030000081A4000000000000000000000001653D36F10000053F000000000000000000000000000000000000004100000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/manager.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_MANAGER_H #define ONLINE_ACCOUNTS_MANAGER_H #include <QObject> #include <QSharedPointer> namespace Accounts { class Manager; }; namespace OnlineAccounts { class SharedManager { public: static QSharedPointer<Accounts::Manager> instance(); }; class Manager: public QObject { Q_OBJECT public: Manager(QObject *parent = 0); ~Manager(); Q_INVOKABLE QObject *loadAccount(uint accountId); Q_INVOKABLE QObject *createAccount(const QString &providerName); private: QSharedPointer<Accounts::Manager> manager; }; }; // namespace #endif // ONLINE_ACCOUNTS_MANAGER_H 07070100000031000081A4000000000000000000000001653D36F100000763000000000000000000000000000000000000004200000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/plugin.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "account-service-model.h" #include "account-service.h" #include "account.h" #include "application-model.h" #include "credentials.h" #include "debug.h" #include "manager.h" #include "plugin.h" #include "provider-model.h" #include <QDebug> #include <QQmlComponent> using namespace OnlineAccounts; static QObject *createManager(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine); Q_UNUSED(scriptEngine); return new Manager(); } void Plugin::registerTypes(const char *uri) { QByteArray loggingLevelVar = qgetenv("OAQ_LOGGING_LEVEL"); if (!loggingLevelVar.isEmpty()) { setLoggingLevel(loggingLevelVar.toInt()); } DEBUG() << Q_FUNC_INFO << uri; qmlRegisterType<AccountServiceModel>(uri, 0, 1, "AccountServiceModel"); qmlRegisterType<AccountService>(uri, 0, 1, "AccountService"); qmlRegisterType<Account>(uri, 0, 1, "Account"); qmlRegisterType<ApplicationModel>(uri, 0, 1, "ApplicationModel"); qmlRegisterType<Credentials>(uri, 0, 1, "Credentials"); qmlRegisterType<ProviderModel>(uri, 0, 1, "ProviderModel"); qmlRegisterSingletonType<Manager>(uri, 0, 1, "Manager", createManager); } 07070100000032000081A4000000000000000000000001653D36F10000043A000000000000000000000000000000000000004000000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/plugin.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_PLUGIN_H #define ONLINE_ACCOUNTS_PLUGIN_H #include <QQmlExtensionPlugin> namespace OnlineAccounts { class Plugin: public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") public: void registerTypes(const char *uri); }; }; // namespace #endif // ONLINE_ACCOUNTS_PLUGIN_H 07070100000033000081A4000000000000000000000001653D36F10000154A000000000000000000000000000000000000004A00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/provider-model.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "debug.h" #include "provider-model.h" #include <Accounts/Application> #include <Accounts/Manager> #include <Accounts/Provider> #include <Accounts/Service> using namespace OnlineAccounts; /*! * \qmltype ProviderModel * \inqmlmodule SSO.OnlineAccounts 0.1 * \ingroup Ubuntu * * \brief A model of the account providers * * The ProviderModel is a model representing the account providers installed on * the system. * * The model defines the following roles: * \list * \li \c displayName, the user-visible name of this provider * \li \c providerId, the unique identifier of the account provider * \li \c iconName, the name of the icon representing this provider * \li \c isSingleAccount, \a true if this provider supports creating one * account at most * \li \c translations, the localization domain for translating the provider's * display name * \endlist */ ProviderModel::ProviderModel(QObject *parent): QAbstractListModel(parent), manager(SharedManager::instance()), m_componentCompleted(false) { QObject::connect(this, SIGNAL(modelReset()), this, SIGNAL(countChanged())); } ProviderModel::~ProviderModel() { } /*! * \qmlproperty string ProviderModel::applicationId * If set, the model will only show those providers which are relevant for the * given \a applicationId. This means that a provider will only be shown if at * least one of its services can be used by the application, as described in * the application's manifest file. */ void ProviderModel::setApplicationId(const QString &applicationId) { if (m_applicationId == applicationId) return; m_applicationId = applicationId; if (m_componentCompleted) update(); Q_EMIT applicationIdChanged(); } QString ProviderModel::applicationId() const { return m_applicationId; } /*! * \qmlproperty int ProviderModel::count * The number of items in the model. */ int ProviderModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return providers.count(); } /*! * \qmlmethod variant ProviderModel::get(int row, string roleName) * * Returns the data at \a row for the role \a roleName. */ QVariant ProviderModel::get(int row, const QString &roleName) const { int role = roleNames().key(roleName.toLatin1(), -1); return data(index(row), role); } QVariant ProviderModel::data(const QModelIndex &index, int role) const { if (index.row() < 0 || index.row() >= providers.count()) return QVariant(); const Accounts::Provider &provider = providers.at(index.row()); QVariant ret; switch (role) { case Qt::DisplayRole: ret = provider.displayName(); break; case ProviderIdRole: ret = provider.name(); break; case IconNameRole: ret = provider.iconName(); break; case IsSingleAccountRole: ret = provider.isSingleAccount(); break; case TranslationsRole: ret = provider.trCatalog(); break; } return ret; } QHash<int, QByteArray> ProviderModel::roleNames() const { static QHash<int, QByteArray> roles; if (roles.isEmpty()) { roles[Qt::DisplayRole] = "displayName"; roles[ProviderIdRole] = "providerId"; roles[IconNameRole] = "iconName"; roles[IsSingleAccountRole] = "isSingleAccount"; roles[TranslationsRole] = "translations"; } return roles; } void ProviderModel::classBegin() { } void ProviderModel::componentComplete() { update(); m_componentCompleted = true; } void ProviderModel::update() { beginResetModel(); Accounts::ProviderList allProviders = manager->providerList(); if (m_applicationId.isEmpty()) { providers = allProviders; } else { providers.clear(); /* This will be slightly simpler once * http://code.google.com/p/accounts-sso/issues/detail?id=214 is fixed. */ Accounts::Application application = manager->application(m_applicationId); Accounts::ServiceList supportedServices; Q_FOREACH(const Accounts::Service &service, manager->serviceList()) { if (!application.serviceUsage(service).isEmpty()) { supportedServices.append(service); } } Q_FOREACH(const Accounts::Provider &provider, allProviders) { bool hasSupportedServices = false; Q_FOREACH(const Accounts::Service &service, supportedServices) { if (service.provider() == provider.name()) { hasSupportedServices = true; break; } } if (hasSupportedServices) { providers.append(provider); } } } endResetModel(); } 07070100000034000081A4000000000000000000000001653D36F1000008DC000000000000000000000000000000000000004800000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/provider-model.h/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ONLINE_ACCOUNTS_PROVIDER_MODEL_H #define ONLINE_ACCOUNTS_PROVIDER_MODEL_H #include "manager.h" #include <QAbstractListModel> #include <QList> #include <QQmlParserStatus> namespace Accounts { class Provider; }; namespace OnlineAccounts { class ProviderModel: public QAbstractListModel, public QQmlParserStatus { Q_OBJECT Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QString applicationId READ applicationId \ WRITE setApplicationId NOTIFY applicationIdChanged) Q_PROPERTY(int count READ rowCount NOTIFY countChanged) public: ProviderModel(QObject *parent = 0); ~ProviderModel(); enum Roles { ProviderIdRole = Qt::UserRole + 1, IconNameRole, IsSingleAccountRole, TranslationsRole, }; void setApplicationId(const QString &applicationId); QString applicationId() const; Q_INVOKABLE QVariant get(int row, const QString &roleName) const; // reimplemented virtual methods int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QHash<int, QByteArray> roleNames() const; void classBegin(); void componentComplete(); Q_SIGNALS: void applicationIdChanged(); void countChanged(); private: void update(); private: QSharedPointer<Accounts::Manager> manager; QList<Accounts::Provider> providers; QString m_applicationId; bool m_componentCompleted; }; }; // namespace #endif // ONLINE_ACCOUNTS_PROVIDER_MODEL_H 07070100000035000081A4000000000000000000000001653D36F10000003E000000000000000000000000000000000000004100000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/qmldir.inmodule $${API_URI} plugin $${TARGET} typeinfo plugin.qmltypes 07070100000036000081A4000000000000000000000001653D36F10000065B000000000000000000000000000000000000003F00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/src/src.proinclude(../common-project-config.pri) TEMPLATE = lib TARGET = Accounts API_URI = "SSO.OnlineAccounts" DESTDIR = $$replace(API_URI, \\., /) CONFIG += \ link_pkgconfig \ plugin \ qt QT += qml # Error on undefined symbols QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF PKGCONFIG += \ accounts-qt$$QT_MAJOR_VERSION \ libsignon-qt$$QT_MAJOR_VERSION CONFIG(debug) { DEFINES += \ DEBUG_ENABLED } SOURCES += \ account-service-model.cpp \ account-service.cpp \ account.cpp \ application-model.cpp \ application.cpp \ credentials.cpp \ debug.cpp \ manager.cpp \ plugin.cpp \ provider-model.cpp HEADERS += \ account-service-model.h \ account-service.h \ account.h \ application-model.h \ application.h \ credentials.h \ debug.h \ manager.h \ plugin.h \ provider-model.h DEFINES += API_URI=\\\"$${API_URI}\\\" qmldir_gen.input = qmldir.in qmldir_gen.output = $${DESTDIR}/qmldir QMAKE_SUBSTITUTES += qmldir_gen OTHER_FILES += qmldir.in PLUGIN_INSTALL_BASE = $$[QT_INSTALL_QML]/$$replace(API_URI, \\., /) target.path = $${PLUGIN_INSTALL_BASE} INSTALLS += target qmldir.files = $${DESTDIR}/qmldir qmldir.path = $${PLUGIN_INSTALL_BASE} INSTALLS += qmldir QML_PLUGINS += $${DESTDIR}/lib$${TARGET}.so qmltypes_gen.commands = env LD_PRELOAD=$${QML_PLUGINS} $$[QT_INSTALL_BINS]/qmlplugindump -notrelocatable $${API_URI} 0.1 . > $(INSTALL_ROOT)$${PLUGIN_INSTALL_BASE}/plugin.qmltypes qmltypes_gen.path = $${PLUGIN_INSTALL_BASE} qmltypes_gen.depends = $${QML_PLUGINS} QMAKE_EXTRA_TARGETS += qmltypes_gen INSTALLS += qmltypes_gen 07070100000037000041ED000000000000000000000002653D36F100000000000000000000000000000000000000000000003900000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests07070100000038000041ED000000000000000000000002653D36F100000000000000000000000000000000000000000000003E00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data07070100000039000041ED000000000000000000000002653D36F100000000000000000000000000000000000000000000004B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/applications0707010000003A000081A4000000000000000000000001653D36F1000000A3000000000000000000000000000000000000005A00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/applications/mailer.desktop[Desktop Entry] Name=Easy Mailer Comment=Send and receive mail Exec=/bin/sh Icon=mailer-icon Terminal=false Type=Application Categories=Application;Network;Email; 0707010000003B000081A4000000000000000000000001653D36F100000086000000000000000000000000000000000000004B00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/bad.provider<?xml version="1.0" encoding="UTF-8" ?> <provider id="bad"> <name>Bad provider</name> <icon>general_myprovider</icon> </provider> 0707010000003C000081A4000000000000000000000001653D36F1000000B4000000000000000000000000000000000000004E00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/badmail.service<?xml version="1.0" encoding="UTF-8" ?> <service id="badmail"> <type>e-mail</type> <name>Bad Mail</name> <icon>general_myservice</icon> <provider>bad</provider> </service> 0707010000003D000081A4000000000000000000000001653D36F1000000BA000000000000000000000000000000000000004F00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/badshare.service<?xml version="1.0" encoding="UTF-8" ?> <service id="badshare"> <type>sharing</type> <name>Bad Share</name> <icon>general_otherservice</icon> <provider>bad</provider> </service> 0707010000003E000081A4000000000000000000000001653D36F1000000D9000000000000000000000000000000000000004C00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/cool.provider<?xml version="1.0" encoding="UTF-8" ?> <provider id="cool"> <name>Cool provider</name> <icon>general_myprovider</icon> <single-account>true</single-account> <translations>somewhere</translations> </provider> 0707010000003F000081A4000000000000000000000001653D36F10000024F000000000000000000000000000000000000004F00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/coolmail.service<?xml version="1.0" encoding="UTF-8" ?> <service id="coolmail"> <type>e-mail</type> <name>Cool Mail</name> <icon>general_myservice</icon> <provider>cool</provider> <translations>here</translations> <template> <group name="auth"> <setting name="method">oauth2</setting> <setting name="mechanism">user_agent</setting> <group name="oauth2/user_agent"> <setting name="host">coolmail.ex</setting> </group> </group> <setting name="color">green</setting> <setting name="auto-explode-after" type="u">10</setting> </template> </service> 07070100000040000081A4000000000000000000000001653D36F100000141000000000000000000000000000000000000005800000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/coolpublisher.application<?xml version="1.0" encoding="UTF-8" ?> <application id="coolpublisher"> <description>Cool publisher</description> <translations>mailer-catalog</translations> <services> <service id="coolshare"> <description>Publish stuff into your Cool account</description> </service> </services> </application> 07070100000041000081A4000000000000000000000001653D36F1000000BD000000000000000000000000000000000000005000000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/coolshare.service<?xml version="1.0" encoding="UTF-8" ?> <service id="coolshare"> <type>sharing</type> <name>Cool Share</name> <icon>general_otherservice</icon> <provider>cool</provider> </service> 07070100000042000081A4000000000000000000000001653D36F1000000BC000000000000000000000000000000000000005200000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/e-mail.service-type<?xml version="1.0" encoding="UTF-8" ?> <service-type id="e-mail"> <translations>translation_file</translations> <name>Electronic mail</name> <icon>email_icon</icon> </service-type> 07070100000043000081A4000000000000000000000001653D36F10000017B000000000000000000000000000000000000005100000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/mailer.application<?xml version="1.0" encoding="UTF-8" ?> <application id="mailer"> <description>Mailer application</description> <translations>mailer-catalog</translations> <desktop-entry>mailer.desktop</desktop-entry> <service-types> <service-type id="e-mail"> <description>Mailer can retrieve your e-mails</description> </service-type> </service-types> </application> 07070100000044000081A4000000000000000000000001653D36F1000000BC000000000000000000000000000000000000005300000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/data/sharing.service-type<?xml version="1.0" encoding="UTF-8" ?> <service-type id="sharing"> <translations>translation_file</translations> <name>File sharing</name> <icon>sharing_icon</icon> </service-type> 07070100000045000041ED000000000000000000000002653D36F100000000000000000000000000000000000000000000003E00000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/mock07070100000046000081A4000000000000000000000001653D36F100000104000000000000000000000000000000000000004700000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/mock/mock.proinclude(../../common-project-config.pri) TARGET = signon-qt$$QT_MAJOR_VERSION TEMPLATE = lib CONFIG += \ debug QT += \ core # Error on undefined symbols QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF SOURCES += \ signon.cpp HEADERS += \ signon.h 07070100000047000081A4000000000000000000000001653D36F100001C55000000000000000000000000000000000000004900000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/mock/signon.cpp/* * Copyright (C) 2013 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "signon.h" #include <QDebug> #include <QStringList> using namespace SignOn; namespace SignOn { class IdentityInfoImpl { private: friend class IdentityInfo; QVariantMap fields; }; QHash<quint32,IdentityInfo> storedIdentities; }; // namespace IdentityInfo::IdentityInfo(): impl(new IdentityInfoImpl) { } IdentityInfo::IdentityInfo(const IdentityInfo &other): impl(new IdentityInfoImpl) { impl->fields = other.impl->fields; } IdentityInfo &IdentityInfo::operator=(const IdentityInfo &other) { impl->fields = other.impl->fields; return *this; } IdentityInfo::~IdentityInfo() { delete impl; } void IdentityInfo::setId(const quint32 id) { impl->fields["id"] = id; } quint32 IdentityInfo::id() const { return impl->fields.value("id", 0).toUInt(); } void IdentityInfo::setSecret(const QString &secret, const bool storeSecret) { impl->fields["secret"] = secret; setStoreSecret(storeSecret); } QString IdentityInfo::secret() const { return impl->fields.value("secret").toString(); } bool IdentityInfo::isStoringSecret() const { return impl->fields.value("storeSecret").toBool(); } void IdentityInfo::setStoreSecret(const bool storeSecret) { impl->fields["storeSecret"] = storeSecret; } void IdentityInfo::setUserName(const QString &userName) { impl->fields["userName"] = userName; } const QString IdentityInfo::userName() const { return impl->fields.value("userName").toString(); } void IdentityInfo::setCaption(const QString &caption) { impl->fields["caption"] = caption; } const QString IdentityInfo::caption() const { return impl->fields.value("caption").toString(); } void IdentityInfo::setRealms(const QStringList &realms) { impl->fields["realms"] = realms; } QStringList IdentityInfo::realms() const { return impl->fields.value("realms").toStringList(); } void IdentityInfo::setOwner(const QString &ownerToken) { impl->fields["owner"] = ownerToken; } QString IdentityInfo::owner() const { return impl->fields.value("owner").toString(); } void IdentityInfo::setAccessControlList(const QStringList &accessControlList) { impl->fields["accessControlList"] = accessControlList; } QStringList IdentityInfo::accessControlList() const { return impl->fields.value("accessControlList").toStringList(); } void IdentityInfo::setMethod(const MethodName &method, const MechanismsList &mechanismsList) { QVariantMap methods = impl->fields["methods"].toMap(); methods[method] = mechanismsList; impl->fields["methods"] = methods; } void IdentityInfo::removeMethod(const MethodName &method) { QVariantMap methods = impl->fields["methods"].toMap(); methods.remove(method); impl->fields["methods"] = methods; } QList<MethodName> IdentityInfo::methods() const { QVariantMap methods = impl->fields["methods"].toMap(); return methods.keys(); } MechanismsList IdentityInfo::mechanisms(const MethodName &method) const { QVariantMap methods = impl->fields["methods"].toMap(); return methods[method].toStringList(); } void IdentityInfo::setType(CredentialsType type) { impl->fields["type"] = type; } IdentityInfo::CredentialsType IdentityInfo::type() const { return CredentialsType(impl->fields["type"].toInt()); } quint32 Identity::lastId = 1; Identity::Identity(const quint32 id, QObject *parent): QObject(parent), m_id(id) { m_storeTimer.setSingleShot(true); m_storeTimer.setInterval(50); QObject::connect(&m_storeTimer, SIGNAL(timeout()), this, SLOT(emitCredentialsStored())); m_infoTimer.setSingleShot(true); m_infoTimer.setInterval(20); QObject::connect(&m_infoTimer, SIGNAL(timeout()), this, SLOT(emitInfo())); m_removeTimer.setSingleShot(true); m_removeTimer.setInterval(40); QObject::connect(&m_removeTimer, SIGNAL(timeout()), this, SLOT(emitRemoved())); } Identity::~Identity() { } Identity *Identity::newIdentity(const IdentityInfo &info, QObject *parent) { Identity *identity = new Identity(0, parent); identity->m_info = info; return identity; } Identity *Identity::existingIdentity(const quint32 id, QObject *parent) { if (id != 0 && !storedIdentities.contains(id)) return 0; Identity *identity = new Identity(id, parent); identity->m_info = storedIdentities.value(id); return identity; } AuthSessionP Identity::createSession(const QString &methodName) { return new AuthSession(m_id, methodName, this); } void Identity::storeCredentials(const IdentityInfo &info) { if (m_id == 0) { m_id = lastId++; } m_info = info; m_info.setId(m_id); storedIdentities.insert(m_id, m_info); m_storeTimer.start(); } void Identity::remove() { m_removeTimer.start(); } void Identity::queryInfo() { m_infoTimer.start(); } void Identity::emitCredentialsStored() { Q_EMIT credentialsStored(m_id); } void Identity::emitInfo() { Q_EMIT info(m_info); } void Identity::emitRemoved() { if (m_id != 0 && !storedIdentities.contains(m_id)) { Q_EMIT error(Error(Error::RemoveFailed, "Identity was not stored")); return; } storedIdentities.remove(m_id); Q_EMIT removed(); } AuthSession::AuthSession(quint32 id, const QString &methodName, QObject *parent): QObject(parent), m_id(id), m_method(methodName) { responseTimer.setSingleShot(true); responseTimer.setInterval(10); QObject::connect(&responseTimer, SIGNAL(timeout()), this, SLOT(respond())); } AuthSession::~AuthSession() { } const QString AuthSession::name() const { return m_method; } void AuthSession::process(const SessionData &sessionData, const QString &mechanism) { m_mechanism = mechanism; m_sessionData = sessionData.toMap(); m_sessionData.insert("credentialsId", m_id); m_sessionData.insert("method", m_method); m_sessionData.insert("mechanism", mechanism); responseTimer.start(); } void AuthSession::cancel() { m_sessionData.insert("errorCode", Error::SessionCanceled); m_sessionData.insert("errorMessage", QStringLiteral("Session canceled")); } void AuthSession::respond() { if (m_sessionData.contains("errorCode")) { Error err(m_sessionData["errorCode"].toInt(), m_sessionData["errorMessage"].toString()); Q_EMIT error(err); } else { Q_EMIT response(m_sessionData); } } 07070100000048000081A4000000000000000000000001653D36F1000024EC000000000000000000000000000000000000004700000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/mock/signon.h/* * Copyright (C) 2013 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef MOCK_SIGNON_H #define MOCK_SIGNON_H #include <QObject> #include <QPointer> #include <QTimer> #include <QVariantMap> namespace SignOn { class AuthSession; typedef QPointer<AuthSession> AuthSessionP; class Error { public: enum ErrorType { Unknown = 1, /**< Catch-all for errors not distinguished by another code. */ InternalServer = 2, /**< Signon Daemon internal error. */ InternalCommunication = 3, /**< Communication with Signon Daemon error. */ PermissionDenied = 4, /**< The operation cannot be performed due to insufficient client permissions. */ EncryptionFailure, /**< Failure during data encryption/decryption. */ AuthServiceErr = 100, /* Placeholder to rearrange enumeration - AuthService specific */ MethodNotKnown, /**< The method with this name is not found. */ ServiceNotAvailable, /**< The service is temporarily unavailable. */ InvalidQuery, /**< Parameters for the query are invalid. */ IdentityErr = 200, /* Placeholder to rearrange enumeration - Identity specific */ MethodNotAvailable, /**< The requested method is not available. */ IdentityNotFound, /**< The identity matching this Identity object was not found on the service. */ StoreFailed, /**< Storing credentials failed. */ RemoveFailed, /**< Removing credentials failed. */ SignOutFailed, /**< SignOut failed. */ IdentityOperationCanceled, /**< Identity operation was canceled by user. */ CredentialsNotAvailable, /**< Query failed. */ ReferenceNotFound, /**< Trying to remove nonexistent reference. */ AuthSessionErr = 300, /* Placeholder to rearrange enumeration - AuthSession/AuthPluginInterface specific */ MechanismNotAvailable, /**< The requested mechanism is not available. */ MissingData, /**< The SessionData object does not contain necessary information. */ InvalidCredentials, /**< The supplied credentials are invalid for the mechanism implementation. */ NotAuthorized, /**< Authorization failed. */ WrongState, /**< An operation method has been called in a wrong state. */ OperationNotSupported, /**< The operation is not supported by the mechanism implementation. */ NoConnection, /**< No Network connetion. */ Network, /**< Network connetion failed. */ Ssl, /**< Ssl connection failed. */ Runtime, /**< Casting SessionData into subclass failed */ SessionCanceled, /**< Challenge was cancelled. */ TimedOut, /**< Challenge was timed out. */ UserInteraction, /**< User interaction dialog failed */ OperationFailed, /**< Temporary failure in authentication. */ EncryptionFailed, /**< @deprecated Failure during data encryption/decryption. */ TOSNotAccepted, /**< User declined Terms of Service. */ ForgotPassword, /**< User requested reset password sequence. */ MethodOrMechanismNotAllowed, /**< Method or mechanism not allowed for this identity. */ IncorrectDate, /**< Date time incorrect on device. */ UserErr = 400 /* Placeholder to rearrange enumeration - User space specific */ }; Error() : m_type((int)Unknown), m_message(QString()) {} Error(const Error &src) : m_type(src.type()), m_message(src.message()) {} Error(int type, const QString &message = QString()): m_type(type), m_message(message) {} Error &operator=(const Error &src) { m_type = src.type(); m_message = src.message(); return *this; } virtual ~Error() {} void setType(int type) { m_type = type; } void setMessage(const QString &message) { m_message = message; } int type() const { return m_type; } QString message() const { return m_message; } private: int m_type; QString m_message; }; class SessionData { public: SessionData(const QVariantMap &data = QVariantMap()) { m_data = data; } SessionData(const SessionData &other) { m_data = other.m_data; } SessionData &operator=(const SessionData &other) { m_data = other.m_data; return *this; } QVariantMap toMap() const { return m_data; } protected: QVariantMap m_data; }; typedef QString MethodName; typedef QStringList MechanismsList; class IdentityInfoImpl; class IdentityInfo { public: enum CredentialsType { Other = 0, Application = 1 << 0, Web = 1 << 1, Network = 1 << 2 }; public: IdentityInfo(); IdentityInfo(const IdentityInfo &other); IdentityInfo &operator=(const IdentityInfo &other); ~IdentityInfo(); void setId(const quint32 id); quint32 id() const; void setSecret(const QString &secret, const bool storeSecret = true); QString secret() const; bool isStoringSecret() const; void setStoreSecret(const bool storeSecret); void setUserName(const QString &userName); const QString userName() const; void setCaption(const QString &caption); const QString caption() const; void setRealms(const QStringList &realms); QStringList realms() const; void setOwner(const QString &ownerToken); QString owner() const; void setAccessControlList(const QStringList &accessControlList); QStringList accessControlList() const; void setMethod(const MethodName &method, const MechanismsList &mechanismsList); void removeMethod(const MethodName &method); void setType(CredentialsType type); CredentialsType type() const; QList<MethodName> methods() const; MechanismsList mechanisms(const MethodName &method) const; private: class IdentityInfoImpl *impl; }; class Identity: public QObject { Q_OBJECT Q_DISABLE_COPY(Identity) protected: Identity(const quint32 id = 0, QObject *parent = 0); public: static Identity *newIdentity(const IdentityInfo &info = IdentityInfo(), QObject *parent = 0); static Identity *existingIdentity(const quint32 id, QObject *parent = 0); virtual ~Identity(); AuthSessionP createSession(const QString &methodName); void storeCredentials(const IdentityInfo &info = IdentityInfo()); void remove(); void queryInfo(); Q_SIGNALS: void error(const SignOn::Error &err); void credentialsStored(const quint32 id); void info(const SignOn::IdentityInfo &info); void removed(); private Q_SLOTS: void emitCredentialsStored(); void emitInfo(); void emitRemoved(); private: static quint32 lastId; quint32 m_id; IdentityInfo m_info; QTimer m_storeTimer; QTimer m_infoTimer; QTimer m_removeTimer; }; class AuthSession: public QObject { Q_OBJECT friend class Identity; protected: AuthSession(quint32 id, const QString &methodName, QObject *parent = 0); ~AuthSession(); public: const QString name() const; void process(const SessionData &sessionData, const QString &mechanism = QString()); void cancel(); Q_SIGNALS: void error(const SignOn::Error &err); void response(const SignOn::SessionData &sessionData); private Q_SLOTS: void respond(); private: quint32 m_id; QString m_method; QString m_mechanism; QVariantMap m_sessionData; QTimer responseTimer; }; }; // namespace Q_DECLARE_METATYPE(SignOn::Error) Q_DECLARE_METATYPE(SignOn::IdentityInfo) Q_DECLARE_METATYPE(SignOn::SessionData) #endif // MOCK_SIGNON_H 07070100000049000081A4000000000000000000000001653D36F10000004F000000000000000000000000000000000000004300000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/tests.proTEMPLATE = subdirs CONFIG += ordered SUBDIRS = \ mock \ tst_plugin.pro 0707010000004A000081A4000000000000000000000001653D36F100010FB7000000000000000000000000000000000000004800000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/tst_plugin.cpp/* * Copyright (C) 2013-2016 Canonical Ltd. * * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <Accounts/AccountService> #include <Accounts/Manager> #include <QAbstractListModel> #include <QDebug> #include <QDir> #include <QQmlComponent> #include <QQmlContext> #include <QQmlEngine> #include <QSignalSpy> #include <QTest> #include <SignOn/SessionData> using namespace Accounts; static bool mapIsSubset(const QVariantMap &set, const QVariantMap &test) { QMapIterator<QString, QVariant> it(set); while (it.hasNext()) { it.next(); if (QMetaType::Type(it.value().type()) == QMetaType::QVariantMap) { if (!mapIsSubset(it.value().toMap(), test.value(it.key()).toMap())) { return false; } } else if (test.value(it.key()) != it.value()) { qDebug() << "Maps differ: expected" << it.value() << "but found" << test.value(it.key()); return false; } } return true; } class PluginTest: public QObject { Q_OBJECT public: PluginTest(); private Q_SLOTS: void initTestCase(); void testLoadPlugin(); void testEmptyModel(); void testModel(); void testModelSignals(); void testModelDisplayName(); void testProviderModel(); void testProviderModelWithApplication(); void testAccountService(); void testAccountServiceUpdate(); void testAuthentication_data(); void testAuthentication(); void testAuthenticationErrors_data(); void testAuthenticationErrors(); void testAuthenticationDeleted(); void testAuthenticationCancel(); void testAuthenticationWithCredentials(); void testAuthenticationMethods(); void testManagerCreate(); void testManagerLoad(); void testAccountInvalid(); void testAccount(); void testCredentials(); void testAccountCredentialsRemoval_data(); void testAccountCredentialsRemoval(); void testAccountServiceCredentials(); void testApplicationModel(); void testUiPolicy_data(); void testUiPolicy(); private: void clearDb(); QVariant get(const QAbstractListModel *model, int row, QString roleName); }; PluginTest::PluginTest(): QObject(0) { } void PluginTest::clearDb() { QDir dbroot(QString::fromLatin1(qgetenv("ACCOUNTS"))); dbroot.remove("accounts.db"); } QVariant PluginTest::get(const QAbstractListModel *model, int row, QString roleName) { QHash<int, QByteArray> roleNames = model->roleNames(); int role = roleNames.key(roleName.toLatin1(), -1); return model->data(model->index(row), role); } void PluginTest::initTestCase() { qputenv("QML2_IMPORT_PATH", "../src"); qputenv("ACCOUNTS", "/tmp/"); qputenv("AG_APPLICATIONS", TEST_DATA_DIR); qputenv("AG_SERVICES", TEST_DATA_DIR); qputenv("AG_SERVICE_TYPES", TEST_DATA_DIR); qputenv("AG_PROVIDERS", TEST_DATA_DIR); qputenv("XDG_DATA_HOME", TEST_DATA_DIR); clearDb(); } void PluginTest::testLoadPlugin() { QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountServiceModel {}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); delete object; } void PluginTest::testEmptyModel() { clearDb(); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountServiceModel {}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast<QAbstractListModel*>(object); QVERIFY(model != 0); QCOMPARE(model->rowCount(), 0); /* We'll now add some accounts but set the service type filter so that they * should not appear in the model. */ model->setProperty("serviceType", QString("e-mail")); QCOMPARE(model->property("serviceType").toString(), QString("e-mail")); /* Create some disabled accounts */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Service badMail = manager->service("badmail"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(false); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->syncAndBlock(); Account *account2 = manager->createAccount("bad"); QVERIFY(account2 != 0); account2->setEnabled(true); account2->setDisplayName("BadAccount"); account2->selectService(badMail); account2->setEnabled(false); account2->syncAndBlock(); QTest::qWait(10); QCOMPARE(model->rowCount(), 0); delete manager; delete object; } void PluginTest::testModel() { clearDb(); /* Create some accounts */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Service coolShare = manager->service("coolshare"); Service badMail = manager->service("badmail"); Service badShare = manager->service("badshare"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->selectService(coolShare); account1->setEnabled(false); account1->syncAndBlock(); Account *account2 = manager->createAccount("bad"); QVERIFY(account2 != 0); account2->setEnabled(true); account2->setDisplayName("BadAccount"); account2->selectService(badMail); account2->setEnabled(true); account2->selectService(badShare); account2->setEnabled(true); account2->syncAndBlock(); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountServiceModel {}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast<QAbstractListModel*>(object); QVERIFY(model != 0); QCOMPARE(model->rowCount(), 3); QCOMPARE(model->property("count").toInt(), 3); QCOMPARE(get(model, 0, "displayName").toString(), QString("BadAccount")); QCOMPARE(get(model, 0, "providerName").toString(), QString("Bad provider")); QCOMPARE(get(model, 0, "accountId").toUInt(), account2->id()); QObject *accountHandle = get(model, 0, "accountHandle").value<QObject*>(); Account *tmpAccount = qobject_cast<Account*>(accountHandle); QVERIFY(tmpAccount != 0); QCOMPARE(tmpAccount->id(), account2->id()); // Same value, but using the deprecated role name QCOMPARE(get(model, 0, "account").value<QObject*>(), accountHandle); QCOMPARE(get(model, 1, "displayName").toString(), QString("BadAccount")); QCOMPARE(get(model, 1, "providerName").toString(), QString("Bad provider")); QCOMPARE(get(model, 2, "displayName").toString(), QString("CoolAccount")); QCOMPARE(get(model, 2, "providerName").toString(), QString("Cool provider")); QCOMPARE(get(model, 2, "accountId").toUInt(), account1->id()); QVariant value; QVERIFY(QMetaObject::invokeMethod(model, "get", Q_RETURN_ARG(QVariant, value), Q_ARG(int, 2), Q_ARG(QString, "providerName"))); QCOMPARE(value.toString(), QString("Cool provider")); QObject *accountServiceHandle = get(model, 2, "accountServiceHandle").value<QObject*>(); QVERIFY(accountServiceHandle != 0); QCOMPARE(accountServiceHandle->metaObject()->className(), "Accounts::AccountService"); // Same value, but using the deprecated role name QCOMPARE(get(model, 2, "accountService").value<QObject*>(), accountServiceHandle); model->setProperty("includeDisabled", true); QCOMPARE(model->property("includeDisabled").toBool(), true); QTest::qWait(10); QCOMPARE(model->rowCount(), 4); QCOMPARE(get(model, 0, "enabled").toBool(), true); QCOMPARE(get(model, 1, "enabled").toBool(), true); QCOMPARE(get(model, 2, "enabled").toBool(), true); QCOMPARE(get(model, 3, "enabled").toBool(), false); /* Test the accountId filter */ model->setProperty("accountId", account1->id()); QCOMPARE(model->property("accountId").toUInt(), account1->id()); QTest::qWait(10); QCOMPARE(model->rowCount(), 2); QCOMPARE(get(model, 0, "accountId").toUInt(), account1->id()); QCOMPARE(get(model, 1, "accountId").toUInt(), account1->id()); model->setProperty("accountId", 0); /* Test the account filter */ model->setProperty("account", QVariant::fromValue<QObject*>(account2)); QCOMPARE(model->property("account").value<QObject*>(), account2); QTest::qWait(10); QCOMPARE(model->rowCount(), 2); QCOMPARE(get(model, 0, "accountId").toUInt(), account2->id()); QCOMPARE(get(model, 1, "accountId").toUInt(), account2->id()); model->setProperty("account", QVariant::fromValue<QObject*>(account2)); QCOMPARE(model->property("account").value<QObject*>(), account2); model->setProperty("account", QVariant::fromValue<QObject*>(0)); /* Test the application filter */ model->setProperty("applicationId", QString("mailer")); QCOMPARE(model->property("applicationId").toString(), QString("mailer")); QTest::qWait(10); QCOMPARE(model->rowCount(), 2); QSet<QString> services; services.insert(get(model, 0, "serviceName").toString()); services.insert(get(model, 1, "serviceName").toString()); QSet<QString> expectedServices; expectedServices.insert("Cool Mail"); expectedServices.insert("Bad Mail"); QCOMPARE(services, expectedServices); /* Reset the application filter */ model->setProperty("applicationId", QString()); /* Test the provider filter */ model->setProperty("provider", QString("bad")); QCOMPARE(model->property("provider").toString(), QString("bad")); QTest::qWait(10); QCOMPARE(model->rowCount(), 2); QCOMPARE(get(model, 0, "providerName").toString(), QString("Bad provider")); QCOMPARE(get(model, 1, "providerName").toString(), QString("Bad provider")); /* Test the service filter */ model->setProperty("service", QString("coolmail")); QCOMPARE(model->property("service").toString(), QString("coolmail")); QTest::qWait(10); QCOMPARE(model->rowCount(), 0); /* Reset the provider, to get some results */ model->setProperty("provider", QString()); QTest::qWait(10); QCOMPARE(model->rowCount(), 1); QCOMPARE(get(model, 0, "providerName").toString(), QString("Cool provider")); QCOMPARE(get(model, 0, "serviceName").toString(), QString("Cool Mail")); QCOMPARE(get(model, 0, "enabled").toBool(), true); /* Retrieve global accounts */ model->setProperty("service", QString("global")); QCOMPARE(model->property("service").toString(), QString("global")); QTest::qWait(10); QCOMPARE(model->rowCount(), 2); QCOMPARE(get(model, 0, "providerName").toString(), QString("Bad provider")); QCOMPARE(get(model, 1, "providerName").toString(), QString("Cool provider")); /* The AccountService objects should refer to a null Service */ for (int i = 0; i < 2; i++) { QObject *tmp = get(model, i, "accountServiceHandle").value<QObject*>(); AccountService *accountService1 = qobject_cast<AccountService*>(tmp); QVERIFY(accountService1 != 0); QVERIFY(!accountService1->service().isValid()); } /* Test the service-type filter */ model->setProperty("serviceType", QString("sharing")); QCOMPARE(model->property("serviceType").toString(), QString("sharing")); /* Reset the service, to get some results */ model->setProperty("service", QString()); QTest::qWait(10); QCOMPARE(model->rowCount(), 2); QCOMPARE(get(model, 0, "serviceName").toString(), QString("Bad Share")); QCOMPARE(get(model, 1, "serviceName").toString(), QString("Cool Share")); delete manager; delete object; } void PluginTest::testModelSignals() { clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Service coolShare = manager->service("coolshare"); Service badMail = manager->service("badmail"); Service badShare = manager->service("badshare"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->selectService(coolShare); account1->setEnabled(false); account1->syncAndBlock(); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountServiceModel {}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast<QAbstractListModel*>(object); QVERIFY(model != 0); QCOMPARE(model->rowCount(), 1); QCOMPARE(model->property("count").toInt(), 1); QCOMPARE(get(model, 0, "displayName").toString(), QString("CoolAccount")); QCOMPARE(get(model, 0, "providerName").toString(), QString("Cool provider")); QCOMPARE(get(model, 0, "serviceName").toString(), QString("Cool Mail")); /* Enable the cool share service, and verify that it appears in the model */ QSignalSpy countChanged(model, SIGNAL(countChanged())); QSignalSpy rowsInserted(model, SIGNAL(rowsInserted(const QModelIndex&,int,int))); account1->selectService(coolShare); account1->setEnabled(true); account1->syncAndBlock(); QTest::qWait(50); QCOMPARE(model->rowCount(), 2); QCOMPARE(rowsInserted.count(), 1); QCOMPARE(countChanged.count(), 1); rowsInserted.clear(); /* Disable the cool mail service, and verify that it gets removed */ QSignalSpy rowsRemoved(model, SIGNAL(rowsRemoved(const QModelIndex&,int,int))); account1->selectService(coolMail); account1->setEnabled(false); account1->syncAndBlock(); QTest::qWait(50); QCOMPARE(model->rowCount(), 1); QCOMPARE(rowsInserted.count(), 0); QCOMPARE(rowsRemoved.count(), 1); rowsRemoved.clear(); /* Create a second account */ Account *account2 = manager->createAccount("bad"); QVERIFY(account2 != 0); account2->setEnabled(false); account2->setDisplayName("BadAccount"); account2->selectService(badMail); account2->setEnabled(true); account2->selectService(badShare); account2->setEnabled(true); account2->syncAndBlock(); QTest::qWait(50); /* It's disabled, so nothing should have changed */ QCOMPARE(model->rowCount(), 1); QCOMPARE(rowsInserted.count(), 0); QCOMPARE(rowsRemoved.count(), 0); /* Enable it */ account2->selectService(); account2->setEnabled(true); account2->syncAndBlock(); QTest::qWait(50); QCOMPARE(model->rowCount(), 3); QCOMPARE(rowsInserted.count(), 2); QCOMPARE(rowsRemoved.count(), 0); rowsInserted.clear(); /* Include disabled */ model->setProperty("includeDisabled", true); QTest::qWait(50); QCOMPARE(model->rowCount(), 4); /* The model is being reset: all rows are deleted and then re-added */ QCOMPARE(rowsInserted.count(), 1); QCOMPARE(rowsRemoved.count(), 1); rowsInserted.clear(); rowsRemoved.clear(); QCOMPARE(get(model, 0, "enabled").toBool(), true); QCOMPARE(get(model, 1, "enabled").toBool(), true); QCOMPARE(get(model, 2, "enabled").toBool(), false); QCOMPARE(get(model, 3, "enabled").toBool(), true); /* Enable cool mail, and check for the dataChanged signal */ QSignalSpy dataChanged(model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))); account1->selectService(coolMail); account1->setEnabled(true); account1->syncAndBlock(); QTest::qWait(50); QCOMPARE(dataChanged.count(), 1); QModelIndex index = qvariant_cast<QModelIndex>(dataChanged.at(0).at(0)); QCOMPARE(index.row(), 2); QCOMPARE(rowsInserted.count(), 0); QCOMPARE(rowsRemoved.count(), 0); dataChanged.clear(); QCOMPARE(get(model, 2, "enabled").toBool(), true); /* Delete the first account */ account1->remove(); account1->syncAndBlock(); QTest::qWait(50); QCOMPARE(model->rowCount(), 2); QCOMPARE(rowsInserted.count(), 0); /* We expect one single signal carrying two rows */ QCOMPARE(rowsRemoved.count(), 1); QCOMPARE(rowsRemoved.at(0).at(1).toInt(), 2); QCOMPARE(rowsRemoved.at(0).at(2).toInt(), 3); rowsRemoved.clear(); /* Create a third account */ Account *account3 = manager->createAccount("bad"); QVERIFY(account3 != 0); account3->setEnabled(true); account3->setDisplayName("Second BadAccount"); account3->selectService(badMail); account3->setEnabled(true); account3->selectService(badShare); account3->setEnabled(false); account3->syncAndBlock(); QTest::qWait(50); QCOMPARE(model->rowCount(), 4); /* We expect one single signal carrying two rows */ QCOMPARE(rowsInserted.count(), 1); QCOMPARE(rowsInserted.at(0).at(1).toInt(), 2); QCOMPARE(rowsInserted.at(0).at(2).toInt(), 3); QCOMPARE(rowsRemoved.count(), 0); rowsInserted.clear(); delete manager; delete object; } void PluginTest::testModelDisplayName() { clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Service coolShare = manager->service("coolshare"); Service badMail = manager->service("badmail"); Service badShare = manager->service("badshare"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->selectService(coolShare); account1->setEnabled(false); account1->syncAndBlock(); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountServiceModel {\n" " includeDisabled: true\n" "}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast<QAbstractListModel*>(object); QVERIFY(model != 0); QCOMPARE(model->property("count").toInt(), 2); /* Create a second account */ Account *account2 = manager->createAccount("bad"); QVERIFY(account2 != 0); account2->setEnabled(false); account2->setDisplayName("BadAccount"); account2->selectService(badMail); account2->setEnabled(true); account2->selectService(badShare); account2->setEnabled(false); account2->syncAndBlock(); QSignalSpy countChanged(model, SIGNAL(countChanged())); countChanged.wait(); QCOMPARE(model->property("count").toInt(), 4); QCOMPARE(get(model, 0, "displayName").toString(), QString("BadAccount")); QCOMPARE(get(model, 1, "displayName").toString(), QString("BadAccount")); QCOMPARE(get(model, 2, "displayName").toString(), QString("CoolAccount")); QCOMPARE(get(model, 3, "displayName").toString(), QString("CoolAccount")); /* Change the displayName, and verify that the dataChanged() signal is * emitted */ QSignalSpy dataChanged(model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))); account1->setDisplayName("ColdAccount"); account1->syncAndBlock(); dataChanged.wait(); /* This is actually an implementation detail: instead of a single signal * carrying the index range in its parameters, we currently get N separate * signals. */ QCOMPARE(dataChanged.count(), 2); QModelIndex index = qvariant_cast<QModelIndex>(dataChanged.at(0).at(0)); QCOMPARE(index.row(), 2); index = qvariant_cast<QModelIndex>(dataChanged.at(1).at(0)); QCOMPARE(index.row(), 3); QCOMPARE(get(model, 0, "displayName").toString(), QString("BadAccount")); QCOMPARE(get(model, 1, "displayName").toString(), QString("BadAccount")); QCOMPARE(get(model, 2, "displayName").toString(), QString("ColdAccount")); QCOMPARE(get(model, 3, "displayName").toString(), QString("ColdAccount")); delete manager; delete object; } void PluginTest::testProviderModel() { /* Create some accounts */ Manager *manager = new Manager(this); ProviderList providers = manager->providerList(); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "ProviderModel {}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast<QAbstractListModel*>(object); QVERIFY(model != 0); QCOMPARE(model->rowCount(), providers.count()); QCOMPARE(model->property("count").toInt(), providers.count()); QCOMPARE(model->property("applicationId").toString(), QString()); for (int i = 0; i < providers.count(); i++) { QCOMPARE(get(model, i, "displayName").toString(), providers[i].displayName()); QCOMPARE(get(model, i, "providerId").toString(), providers[i].name()); QCOMPARE(get(model, i, "iconName").toString(), providers[i].iconName()); QCOMPARE(get(model, i, "isSingleAccount").toBool(), providers[i].isSingleAccount()); QCOMPARE(get(model, i, "translations").toString(), providers[i].trCatalog()); } QCOMPARE(get(model, 100, "iconName"), QVariant()); QVariant value; QVERIFY(QMetaObject::invokeMethod(model, "get", Q_RETURN_ARG(QVariant, value), Q_ARG(int, 1), Q_ARG(QString, "providerId"))); QCOMPARE(value.toString(), providers[1].name()); delete manager; delete object; } void PluginTest::testProviderModelWithApplication() { /* Create some accounts */ Manager *manager = new Manager(this); ProviderList providers = manager->providerList(); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "ProviderModel {\n" " applicationId: \"mailer\"\n" "}", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QAbstractListModel *model = qobject_cast<QAbstractListModel*>(object); QVERIFY(model != 0); QCOMPARE(model->rowCount(), providers.count()); QCOMPARE(model->property("count").toInt(), providers.count()); QCOMPARE(model->property("applicationId").toString(), QString("mailer")); /* Now set an application which supports only "coolservice" and verify that * only the "cool" provider is there */ QSignalSpy countSignal(model, SIGNAL(countChanged())); model->setProperty("applicationId", QString("coolpublisher")); QCOMPARE(model->property("applicationId").toString(), QString("coolpublisher")); QCOMPARE(countSignal.count(), 1); QCOMPARE(model->property("count").toInt(), 1); /* Do it twice, just to improve branch coverage */ model->setProperty("applicationId", QString("coolpublisher")); QCOMPARE(get(model, 0, "providerId").toString(), QString("cool")); delete manager; delete object; } void PluginTest::testAccountService() { clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Service coolShare = manager->service("coolshare"); Service badMail = manager->service("badmail"); Service badShare = manager->service("badshare"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->selectService(coolShare); account1->setEnabled(false); account1->syncAndBlock(); AccountService *accountService1 = new AccountService(account1, coolMail); QVERIFY(accountService1 != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("accountService1", accountService1); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService { objectHandle: accountService1 }", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QCOMPARE(qmlObject->property("objectHandle").value<AccountService*>(), accountService1); QCOMPARE(qmlObject->property("enabled").toBool(), true); QCOMPARE(qmlObject->property("serviceEnabled").toBool(), true); QCOMPARE(qmlObject->property("displayName").toString(), QString("CoolAccount")); QCOMPARE(qmlObject->property("accountId").toUInt(), account1->id()); QVariantMap provider = qmlObject->property("provider").toMap(); QVERIFY(!provider.isEmpty()); QCOMPARE(provider["id"].toString(), QString("cool")); QCOMPARE(provider["displayName"].toString(), QString("Cool provider")); QCOMPARE(provider["iconName"].toString(), QString("general_myprovider")); QCOMPARE(provider["isSingleAccount"].toBool(), true); QCOMPARE(provider["translations"].toString(), QString("somewhere")); QVariantMap service = qmlObject->property("service").toMap(); QVERIFY(!service.isEmpty()); QCOMPARE(service["id"].toString(), QString("coolmail")); QCOMPARE(service["displayName"].toString(), QString("Cool Mail")); QCOMPARE(service["iconName"].toString(), QString("general_myservice")); QCOMPARE(service["serviceTypeId"].toString(), QString("e-mail")); QCOMPARE(service["translations"].toString(), QString("here")); QVariantMap settings = qmlObject->property("settings").toMap(); QVERIFY(!settings.isEmpty()); QCOMPARE(settings["color"].toString(), QString("green")); QCOMPARE(settings["auto-explode-after"].toUInt(), uint(10)); QCOMPARE(settings.count(), 2); QVariantMap authData = qmlObject->property("authData").toMap(); QVERIFY(!authData.isEmpty()); QCOMPARE(authData["method"].toString(), QString("oauth2")); QCOMPARE(authData["mechanism"].toString(), QString("user_agent")); QVariantMap parameters = authData["parameters"].toMap(); QVERIFY(!parameters.isEmpty()); QCOMPARE(parameters["host"].toString(), QString("coolmail.ex")); /* Delete the account service, and check that the QML object survives */ delete accountService1; QCOMPARE(qmlObject->property("objectHandle").value<AccountService*>(), (AccountService*)0); QCOMPARE(qmlObject->property("enabled").toBool(), false); QCOMPARE(qmlObject->property("serviceEnabled").toBool(), false); QCOMPARE(qmlObject->property("displayName").toString(), QString()); QCOMPARE(qmlObject->property("accountId").toUInt(), uint(0)); provider = qmlObject->property("provider").toMap(); QVERIFY(provider.isEmpty()); service = qmlObject->property("service").toMap(); QVERIFY(service.isEmpty()); settings = qmlObject->property("settings").toMap(); QVERIFY(settings.isEmpty()); authData = qmlObject->property("authData").toMap(); QVERIFY(authData.isEmpty()); QVariantMap newSettings; newSettings.insert("color", QString("red")); bool ok; ok = QMetaObject::invokeMethod(qmlObject, "updateSettings", Q_ARG(QVariantMap, newSettings)); QVERIFY(ok); ok = QMetaObject::invokeMethod(qmlObject, "updateServiceEnabled", Q_ARG(bool, true)); QVERIFY(ok); delete manager; delete qmlObject; } void PluginTest::testAccountServiceUpdate() { clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Account *account = manager->createAccount("cool"); QVERIFY(account != 0); account->setEnabled(true); account->setDisplayName("CoolAccount"); account->selectService(coolMail); account->setEnabled(true); account->syncAndBlock(); AccountService *accountService = new AccountService(account, coolMail); QVERIFY(accountService != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("accountService", accountService); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService { objectHandle: accountService }", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QCOMPARE(qmlObject->property("objectHandle").value<AccountService*>(), accountService); QCOMPARE(qmlObject->property("autoSync").toBool(), true); /* Set it to the same value, just to increase coverage */ QVERIFY(qmlObject->setProperty("autoSync", true)); QCOMPARE(qmlObject->property("autoSync").toBool(), true); QVariantMap settings = qmlObject->property("settings").toMap(); QVERIFY(!settings.isEmpty()); QCOMPARE(settings["color"].toString(), QString("green")); QCOMPARE(settings["auto-explode-after"].toUInt(), uint(10)); QCOMPARE(settings.count(), 2); QSignalSpy settingsChanged(qmlObject, SIGNAL(settingsChanged())); /* Update a couple of settings */ QVariantMap newSettings; newSettings.insert("color", QString("red")); newSettings.insert("verified", true); QMetaObject::invokeMethod(qmlObject, "updateSettings", Q_ARG(QVariantMap, newSettings)); QTest::qWait(50); QCOMPARE(settingsChanged.count(), 1); settingsChanged.clear(); settings = qmlObject->property("settings").toMap(); QCOMPARE(settings["color"].toString(), QString("red")); QCOMPARE(settings["auto-explode-after"].toUInt(), uint(10)); QCOMPARE(settings["verified"].toBool(), true); QCOMPARE(settings.count(), 3); /* Disable the service */ QSignalSpy enabledChanged(qmlObject, SIGNAL(enabledChanged())); QMetaObject::invokeMethod(qmlObject, "updateServiceEnabled", Q_ARG(bool, false)); QTest::qWait(50); QCOMPARE(enabledChanged.count(), 1); enabledChanged.clear(); QCOMPARE(qmlObject->property("enabled").toBool(), false); QCOMPARE(settingsChanged.count(), 1); settingsChanged.clear(); QCOMPARE(qmlObject->property("serviceEnabled").toBool(), false); /* Disable autoSync, and change something else */ qmlObject->setProperty("autoSync", false); QCOMPARE(qmlObject->property("autoSync").toBool(), false); newSettings.clear(); newSettings.insert("verified", false); newSettings.insert("color", QVariant()); QMetaObject::invokeMethod(qmlObject, "updateSettings", Q_ARG(QVariantMap, newSettings)); QTest::qWait(50); /* Nothing should have been changed yet */ QCOMPARE(settingsChanged.count(), 0); settings = qmlObject->property("settings").toMap(); QCOMPARE(settings["verified"].toBool(), true); /* Manually store the settings */ account->sync(); QTest::qWait(50); QCOMPARE(settingsChanged.count(), 1); settingsChanged.clear(); settings = qmlObject->property("settings").toMap(); QCOMPARE(settings["verified"].toBool(), false); QCOMPARE(settings["color"].toString(), QString("green")); delete accountService; delete manager; delete qmlObject; } void PluginTest::testAuthentication_data() { QTest::addColumn<QString>("params"); QTest::addColumn<QVariantMap>("expectedReply"); QVariantMap reply; reply.insert("test", QString("OK")); reply.insert("host", QString("coolmail.ex")); QTest::newRow("success with params") << "{ \"test\": \"OK\" }" << reply; reply.clear(); reply.insert("host", QString("coolmail.ex")); QTest::newRow("success without params") << "" << reply; reply.clear(); reply.insert("method", QString("a method")); reply.insert("mechanism", QString("a mechanism")); reply.insert("data", QString("value")); QTest::newRow("w/ method+mechanism") << "'a method', 'a mechanism', {'data':'value'}" << reply; reply.clear(); } void PluginTest::testAuthentication() { QFETCH(QString, params); QFETCH(QVariantMap, expectedReply); clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Service coolShare = manager->service("coolshare"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->selectService(coolShare); account1->setEnabled(false); account1->syncAndBlock(); AccountService *accountService1 = new AccountService(account1, coolMail); QVERIFY(accountService1 != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("accountService1", accountService1); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService {\n" " objectHandle: accountService1\n" " function go() {\n" " authenticate(" + params.toUtf8() + ")\n" " }\n" "}", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QSignalSpy authenticated(qmlObject, SIGNAL(authenticated(const QVariantMap &))); QSignalSpy authenticationError(qmlObject, SIGNAL(authenticationError(const QVariantMap &))); QMetaObject::invokeMethod(qmlObject, "go"); QTRY_COMPARE(authenticated.count(), 1); QCOMPARE(authenticationError.count(), 0); QVariantMap reply = authenticated.at(0).at(0).toMap(); QVERIFY(mapIsSubset(expectedReply, reply)); delete accountService1; delete manager; delete qmlObject; } void PluginTest::testAuthenticationErrors_data() { QTest::addColumn<QString>("params"); QTest::addColumn<QString>("codeName"); QTest::addColumn<QString>("expectedMessage"); QTest::newRow("Signon::UserCanceled") << "{ \"errorCode\": 311, \"errorMessage\": \"Failed!\" }" << "UserCanceledError" << "Failed!"; QTest::newRow("Signon::InvalidQuery") << "{ \"errorCode\": 103, \"errorMessage\": \"Weird\" }" << "NoAccountError" << "Weird"; QTest::newRow("Signon::PermissionDenied") << "{ \"errorCode\": 4, \"errorMessage\": \"Failed!\" }" << "PermissionDeniedError" << "Failed!"; QTest::newRow("Signon::NoConnection") << "{ \"errorCode\": 307, \"errorMessage\": \"Failed!\" }" << "NetworkError" << "Failed!"; } void PluginTest::testAuthenticationErrors() { QFETCH(QString, params); QFETCH(QString, codeName); QFETCH(QString, expectedMessage); clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Service coolShare = manager->service("coolshare"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->selectService(coolShare); account1->setEnabled(false); account1->syncAndBlock(); AccountService *accountService1 = new AccountService(account1, coolMail); QVERIFY(accountService1 != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("accountService1", accountService1); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService {\n" " objectHandle: accountService1\n" " function go() {\n" " authenticate(" + params.toUtf8() + ")\n" " }\n" "}", QUrl()); QObject *qmlObject = component.create(); qDebug() << component.errors(); QVERIFY(qmlObject != 0); QSignalSpy authenticationError(qmlObject, SIGNAL(authenticationError(const QVariantMap &))); QMetaObject::invokeMethod(qmlObject, "go"); QTRY_COMPARE(authenticationError.count(), 1); QVariantMap reply = authenticationError.at(0).at(0).toMap(); int code = reply.value("code").toInt(); QString message = reply.value("message").toString(); QCOMPARE(message, expectedMessage); const QMetaObject *mo = qmlObject->metaObject(); const QMetaEnum errorEnum = mo->enumerator(mo->indexOfEnumerator("ErrorCode")); QCOMPARE(code, errorEnum.keyToValue(codeName.toUtf8().constData())); delete accountService1; delete manager; delete qmlObject; } void PluginTest::testAuthenticationDeleted() { clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Service coolShare = manager->service("coolshare"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->selectService(coolShare); account1->setEnabled(false); account1->syncAndBlock(); AccountService *accountService1 = new AccountService(account1, coolMail); QVERIFY(accountService1 != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("accountService1", accountService1); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService { objectHandle: accountService1 }", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QSignalSpy authenticated(qmlObject, SIGNAL(authenticated(const QVariantMap &))); QSignalSpy authenticationError(qmlObject, SIGNAL(authenticationError(const QVariantMap &))); QVariantMap sessionData; QVariantMap error; /* Delete the account service, and check that the QML object survives */ delete accountService1; QCOMPARE(qmlObject->property("objectHandle").value<AccountService*>(), (AccountService*)0); /* Authenticate now: we should get an error */ sessionData.clear(); sessionData.insert("test", QString("OK")); QMetaObject::invokeMethod(qmlObject, "authenticate", Q_ARG(QVariantMap, sessionData)); QTest::qWait(50); QCOMPARE(authenticationError.count(), 1); QCOMPARE(authenticated.count(), 0); error = authenticationError.at(0).at(0).toMap(); QVERIFY(!error.isEmpty()); QCOMPARE(error["message"].toString(), QString("Invalid AccountService")); authenticationError.clear(); delete manager; delete qmlObject; } void PluginTest::testAuthenticationCancel() { clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->syncAndBlock(); AccountService *accountService1 = new AccountService(account1, coolMail); QVERIFY(accountService1 != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("accountService1", accountService1); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService { objectHandle: accountService1 }", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QSignalSpy authenticated(qmlObject, SIGNAL(authenticated(const QVariantMap &))); QSignalSpy authenticationError(qmlObject, SIGNAL(authenticationError(const QVariantMap &))); /* First, check that calling cancelAuthentication() on an idle object * doesn't do anything. */ bool ok = QMetaObject::invokeMethod(qmlObject, "cancelAuthentication"); QVERIFY(ok); QTest::qWait(50); QCOMPARE(authenticated.count(), 0); QCOMPARE(authenticationError.count(), 0); /* Now, try canceling a session. */ QVariantMap sessionData; sessionData.insert("test", QString("OK")); QMetaObject::invokeMethod(qmlObject, "authenticate", Q_ARG(QVariantMap, sessionData)); QTest::qWait(2); QCOMPARE(authenticated.count(), 0); QCOMPARE(authenticationError.count(), 0); ok = QMetaObject::invokeMethod(qmlObject, "cancelAuthentication"); QVERIFY(ok); QTest::qWait(50); QCOMPARE(authenticated.count(), 0); QCOMPARE(authenticationError.count(), 1); QVariantMap error = authenticationError.at(0).at(0).toMap(); QVERIFY(!error.isEmpty()); const QMetaObject *mo = qmlObject->metaObject(); const QMetaEnum errorEnum = mo->enumerator(mo->indexOfEnumerator("ErrorCode")); QCOMPARE(error["code"].toInt(), errorEnum.keyToValue("UserCanceledError")); authenticationError.clear(); delete accountService1; delete manager; delete qmlObject; } void PluginTest::testAuthenticationWithCredentials() { /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Account *account = manager->createAccount("cool"); QVERIFY(account != 0); AccountService *accountService = new AccountService(account, coolMail); QVERIFY(accountService != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("accountService", accountService); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService {\n" " id: account\n" " autoSync: false\n" " objectHandle: accountService\n" " credentials: Credentials {\n" " objectName: \"creds\"\n" " userName: \"Happy user\"\n" " caption: account.provider.displayName\n" " }\n" "}", QUrl()); QObject *qmlAccount = component.create(); QVERIFY(qmlAccount != 0); QSignalSpy authenticated(qmlAccount, SIGNAL(authenticated(const QVariantMap &))); QSignalSpy authenticationError(qmlAccount, SIGNAL(authenticationError(const QVariantMap &))); QObject *qmlCredentials = qmlAccount->findChild<QObject*>("creds"); QVERIFY(qmlCredentials != 0); /* Store the credentials */ QSignalSpy synced(qmlCredentials, SIGNAL(synced())); bool ok; ok = QMetaObject::invokeMethod(qmlCredentials, "sync"); QVERIFY(ok); /* Wait for the operation to finish, and verify it succeeded */ QTest::qWait(100); QCOMPARE(synced.count(), 1); synced.clear(); uint credentialsId = qmlCredentials->property("credentialsId").toUInt(); QVERIFY(credentialsId != 0); QVariantMap sessionData; sessionData.insert("test", QString("OK")); QMetaObject::invokeMethod(qmlAccount, "authenticate", Q_ARG(QVariantMap, sessionData)); QTest::qWait(50); QCOMPARE(authenticationError.count(), 0); QCOMPARE(authenticated.count(), 1); QVariantMap reply = authenticated.at(0).at(0).toMap(); QVERIFY(!reply.isEmpty()); QCOMPARE(reply["test"].toString(), QString("OK")); QCOMPARE(reply["host"].toString(), QString("coolmail.ex")); /* Check that the newly created credentials were used */ QCOMPARE(reply["credentialsId"].toUInt(), credentialsId); authenticated.clear(); delete manager; delete qmlAccount; } void PluginTest::testAuthenticationMethods() { clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Service coolShare = manager->service("coolshare"); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->setEnabled(true); account1->setDisplayName("CoolAccount"); account1->selectService(coolMail); account1->setEnabled(true); account1->selectService(coolShare); account1->setEnabled(false); account1->syncAndBlock(); AccountService *accountService1 = new AccountService(account1, coolMail); QVERIFY(accountService1 != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("accountService1", accountService1); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService {\n" " objectHandle: accountService1\n" "}", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QSignalSpy authenticated(qmlObject, SIGNAL(authenticated(const QVariantMap &))); QString method = "first"; QString mechanism = "1"; QVariantMap sessionData { { "port", 22 }, }; QMetaObject::invokeMethod(qmlObject, "authenticate", Q_ARG(QString, method), Q_ARG(QString, mechanism), Q_ARG(QVariantMap, sessionData)); QTRY_COMPARE(authenticated.count(), 1); QVariantMap reply = authenticated.at(0).at(0).toMap(); authenticated.clear(); QVariantMap expectedReply { { "port", 22 }, { "method", "first" }, { "mechanism", "1" }, }; QVERIFY(mapIsSubset(expectedReply, reply)); // Authenticate with same method, different mechanism mechanism = "2"; sessionData = QVariantMap { { "host", "example.com" }, }; QMetaObject::invokeMethod(qmlObject, "authenticate", Q_ARG(QString, method), Q_ARG(QString, mechanism), Q_ARG(QVariantMap, sessionData)); QTRY_COMPARE(authenticated.count(), 1); reply = authenticated.at(0).at(0).toMap(); authenticated.clear(); expectedReply = QVariantMap { { "host", "example.com" }, { "method", "first" }, { "mechanism", "2" }, }; QVERIFY(mapIsSubset(expectedReply, reply)); // Authenticate with different method method = "second"; mechanism = "1"; sessionData = QVariantMap { { "true", true }, }; QMetaObject::invokeMethod(qmlObject, "authenticate", Q_ARG(QString, method), Q_ARG(QString, mechanism), Q_ARG(QVariantMap, sessionData)); QTRY_COMPARE(authenticated.count(), 1); reply = authenticated.at(0).at(0).toMap(); authenticated.clear(); expectedReply = QVariantMap { { "true", true }, { "method", "second" }, { "mechanism", "1" }, }; QVERIFY(mapIsSubset(expectedReply, reply)); // And back to the initial method method = "first"; mechanism = "1"; sessionData = QVariantMap { { "false", false }, }; QMetaObject::invokeMethod(qmlObject, "authenticate", Q_ARG(QString, method), Q_ARG(QString, mechanism), Q_ARG(QVariantMap, sessionData)); QTRY_COMPARE(authenticated.count(), 1); reply = authenticated.at(0).at(0).toMap(); authenticated.clear(); expectedReply = QVariantMap { { "false", false }, { "method", "first" }, { "mechanism", "1" }, }; QVERIFY(mapIsSubset(expectedReply, reply)); delete accountService1; delete manager; delete qmlObject; } void PluginTest::testManagerCreate() { QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "Account { objectHandle: Manager.createAccount(\"cool\") }", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QVariantMap provider = qmlObject->property("provider").toMap(); QVERIFY(!provider.isEmpty()); QCOMPARE(provider["id"].toString(), QString("cool")); QCOMPARE(provider["displayName"].toString(), QString("Cool provider")); QCOMPARE(provider["iconName"].toString(), QString("general_myprovider")); delete qmlObject; } void PluginTest::testManagerLoad() { clearDb(); /* Create one account */ Manager *manager = new Manager(this); Account *account1 = manager->createAccount("cool"); QVERIFY(account1 != 0); account1->syncAndBlock(); QVERIFY(account1->id() != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("account1id", uint(account1->id())); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "Account { objectHandle: Manager.loadAccount(account1id) }", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QCOMPARE(qmlObject->property("accountId").toUInt(), account1->id()); QVariantMap provider = qmlObject->property("provider").toMap(); QVERIFY(!provider.isEmpty()); QCOMPARE(provider["id"].toString(), QString("cool")); QCOMPARE(provider["displayName"].toString(), QString("Cool provider")); QCOMPARE(provider["iconName"].toString(), QString("general_myprovider")); delete manager; delete qmlObject; } void PluginTest::testAccountInvalid() { QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "Account {}", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QVERIFY(qmlObject->property("objectHandle").value<QObject*>() == 0); QCOMPARE(qmlObject->property("enabled").toBool(), false); QCOMPARE(qmlObject->property("displayName").toString(), QString()); QCOMPARE(qmlObject->property("accountId").toUInt(), uint(0)); QVariantMap provider = qmlObject->property("provider").toMap(); QVERIFY(provider.isEmpty()); qmlObject->setProperty("objectHandle", QVariant::fromValue<QObject*>(0)); QVERIFY(qmlObject->property("objectHandle").value<QObject*>() == 0); bool ok; ok = QMetaObject::invokeMethod(qmlObject, "updateDisplayName", Q_ARG(QString, "dummy")); QVERIFY(ok); ok = QMetaObject::invokeMethod(qmlObject, "updateEnabled", Q_ARG(bool, "true")); QVERIFY(ok); ok = QMetaObject::invokeMethod(qmlObject, "sync"); QVERIFY(ok); ok = QMetaObject::invokeMethod(qmlObject, "remove"); QVERIFY(ok); delete qmlObject; } void PluginTest::testAccount() { clearDb(); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "Account { objectHandle: Manager.createAccount(\"cool\") }", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QObject *objectHandle = qmlObject->property("objectHandle").value<QObject*>(); Account *account = qobject_cast<Account*>(objectHandle); QVERIFY(account != 0); QVERIFY(account->id() == 0); QVariantMap provider = qmlObject->property("provider").toMap(); QVERIFY(!provider.isEmpty()); QCOMPARE(provider["id"].toString(), QString("cool")); bool ok; ok = QMetaObject::invokeMethod(qmlObject, "updateDisplayName", Q_ARG(QString, "new name")); QVERIFY(ok); ok = QMetaObject::invokeMethod(qmlObject, "updateEnabled", Q_ARG(bool, "true")); QVERIFY(ok); ok = QMetaObject::invokeMethod(qmlObject, "sync"); QVERIFY(ok); QTest::qWait(50); /* Check that the changes have been recorded */ QVERIFY(account->id() != 0); AccountId accountId = account->id(); QCOMPARE(qmlObject->property("accountId").toUInt(), uint(account->id())); QCOMPARE(qmlObject->property("displayName").toString(), QString("new name")); QCOMPARE(qmlObject->property("enabled").toBool(), true); objectHandle = qmlObject->property("accountServiceHandle").value<QObject*>(); AccountService *accountService = qobject_cast<AccountService*>(objectHandle); QVERIFY(accountService != 0); /* Set the same account instance on the account; just to improve coverage * of branches. */ ok = qmlObject->setProperty("objectHandle", QVariant::fromValue<QObject*>(account)); QVERIFY(ok); /* Delete the account */ ok = QMetaObject::invokeMethod(qmlObject, "remove"); QVERIFY(ok); QTest::qWait(50); /* Check that the account has effectively been removed */ Manager *manager = new Manager(this); Account *account1 = manager->account(accountId); QVERIFY(account1 == 0); delete qmlObject; } void PluginTest::testCredentials() { QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "Credentials {" " userName: \"Smart User\"\n" " secret: \"Valuable password\"\n" " storeSecret: true\n" " caption: \"Service One\"\n" " acl: [ \"Me\", \"You\" ]\n" " methods: {\n" " \"oauth\": [ \"one\", \"two\" ]," " \"sasl\": [ \"plain\" ]" " }\n" "}", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QCOMPARE(qmlObject->property("userName").toString(), QString("Smart User")); QCOMPARE(qmlObject->property("secret").toString(), QString("Valuable password")); QCOMPARE(qmlObject->property("storeSecret").toBool(), true); QCOMPARE(qmlObject->property("caption").toString(), QString("Service One")); QStringList acl; acl << "Me" << "You"; QCOMPARE(qmlObject->property("acl").toStringList(), acl); QVariantMap methods; methods.insert("oauth", QStringList() << "one" << "two"); methods.insert("sasl", QStringList() << "plain"); QCOMPARE(qmlObject->property("methods").toMap(), methods); QCOMPARE(qmlObject->property("credentialsId").toUInt(), uint(0)); /* Set a few fields to the same values, just to increase coverage of * branches */ qmlObject->setProperty("credentialsId", uint(0)); qmlObject->setProperty("userName", "Smart User"); qmlObject->setProperty("secret", "Valuable password"); qmlObject->setProperty("storeSecret", true); qmlObject->setProperty("caption", "Service One"); qmlObject->setProperty("methods", methods); qmlObject->setProperty("acl", acl); /* Remove the credentials; this won't do anything now */ bool ok; ok = QMetaObject::invokeMethod(qmlObject, "remove"); QVERIFY(ok); /* Store the credentials */ QSignalSpy synced(qmlObject, SIGNAL(synced())); QSignalSpy credentialsIdChanged(qmlObject, SIGNAL(credentialsIdChanged())); ok = QMetaObject::invokeMethod(qmlObject, "sync"); QVERIFY(ok); QTest::qWait(100); QCOMPARE(synced.count(), 1); synced.clear(); QCOMPARE(credentialsIdChanged.count(), 1); credentialsIdChanged.clear(); uint credentialsId = qmlObject->property("credentialsId").toUInt(); QVERIFY(credentialsId != 0); engine.rootContext()->setContextProperty("credsId", credentialsId); component.setData("import SSO.OnlineAccounts 0.1\n" "Credentials { credentialsId: credsId }", QUrl()); QObject *qmlObject2 = component.create(); QVERIFY(qmlObject2 != 0); QCOMPARE(qmlObject2->property("credentialsId").toUInt(), credentialsId); /* After some time, we should get the synced() signal and all fields should * be loaded at that point */ QSignalSpy synced2(qmlObject2, SIGNAL(synced())); QTest::qWait(100); QCOMPARE(synced2.count(), 1); synced2.clear(); QCOMPARE(qmlObject2->property("userName").toString(), QString("Smart User")); /* Set the credentialsId to 0, everything should continue to work */ qmlObject2->setProperty("credentialsId", uint(0)); QTest::qWait(100); QCOMPARE(qmlObject2->property("userName").toString(), QString("Smart User")); /* test removal of the credentials */ QSignalSpy removed(qmlObject, SIGNAL(removed())); ok = QMetaObject::invokeMethod(qmlObject, "remove"); QVERIFY(ok); QTest::qWait(100); QCOMPARE(removed.count(), 1); removed.clear(); delete qmlObject2; delete qmlObject; } void PluginTest::testAccountCredentialsRemoval_data() { QTest::addColumn<bool>("removeCredentials"); QTest::addColumn<QString>("expectedUserName"); QTest::newRow("With credentials removal") << true << QString(); QTest::newRow("Without credentials removal") << false << QString("Happy user"); } void PluginTest::testAccountCredentialsRemoval() { QFETCH(bool, removeCredentials); QFETCH(QString, expectedUserName); clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Account *account = manager->createAccount("cool"); QVERIFY(account != 0); account->setEnabled(true); account->setDisplayName("CoolAccount"); account->selectService(coolMail); account->setEnabled(true); account->syncAndBlock(); quint32 accountId = account->id(); QVERIFY(accountId != 0); AccountService *globalService = new AccountService(account, Service()); QVERIFY(globalService != 0); AccountService *mailService = new AccountService(account, coolMail); QVERIFY(mailService != 0); QList<AccountService*> services; services.append(globalService); services.append(mailService); QQmlEngine engine; Q_FOREACH (AccountService *accountService, services) { engine.rootContext()->setContextProperty("accountService", accountService); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService {\n" " id: account\n" " objectHandle: accountService\n" " credentials: Credentials {\n" " objectName: \"creds\"\n" " userName: \"Happy user\"\n" " caption: account.provider.displayName\n" " }\n" "}", QUrl()); QObject *qmlAccount = component.create(); QVERIFY(qmlAccount != 0); QObject *qmlCredentials = qmlAccount->findChild<QObject*>("creds"); QVERIFY(qmlCredentials != 0); /* Store the credentials */ bool ok; ok = QMetaObject::invokeMethod(qmlCredentials, "sync"); QVERIFY(ok); QTest::qWait(100); } /* And check that the credentialsId have now been written to the account*/ uint globalCredentialsId = globalService->value("CredentialsId").toUInt(); QVERIFY(globalCredentialsId != 0); uint mailCredentialsId = mailService->value("CredentialsId").toUInt(); QVERIFY(mailCredentialsId != 0); QVERIFY(mailCredentialsId != globalCredentialsId); delete globalService; delete mailService; delete manager; QQmlComponent accountComponent(&engine); engine.rootContext()->setContextProperty("aid", accountId); accountComponent.setData("import SSO.OnlineAccounts 0.1\n" "Account {\n" " objectHandle: Manager.loadAccount(aid)\n" " function removeAccount1() {\n" " remove(Account.RemoveAccountOnly)\n" " }\n" " function removeAccount2() {\n" " remove(Account.RemoveCredentials)\n" " }\n" "}", QUrl()); QObject *qmlAccount = accountComponent.create(); QVERIFY(qmlAccount != 0); /* test removal of the credentials */ QSignalSpy removed(qmlAccount, SIGNAL(removed())); const char *removeFunction = removeCredentials ? "removeAccount2" : "removeAccount1"; bool ok = QMetaObject::invokeMethod(qmlAccount, removeFunction); QVERIFY(ok); QTest::qWait(200); QCOMPARE(removed.count(), 1); removed.clear(); delete qmlAccount; /* Verify that the credentials have actually been removed if * removeCredentials was true, or retained if it was false. */ QList<uint> credentials; credentials.append(globalCredentialsId); credentials.append(mailCredentialsId); Q_FOREACH (uint credentialsId, credentials) { engine.rootContext()->setContextProperty("credsId", credentialsId); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "Credentials { credentialsId: credsId }", QUrl()); QObject *qmlCredentials = component.create(); QVERIFY(qmlCredentials != 0); QTest::qWait(100); QCOMPARE(qmlCredentials->property("userName").toString(), expectedUserName); } } void PluginTest::testAccountServiceCredentials() { clearDb(); /* Create one account */ Manager *manager = new Manager(this); Service coolMail = manager->service("coolmail"); Account *account = manager->createAccount("cool"); QVERIFY(account != 0); account->setEnabled(true); account->setDisplayName("CoolAccount"); account->selectService(coolMail); account->setEnabled(true); account->syncAndBlock(); AccountService *accountService = new AccountService(account, coolMail); QVERIFY(accountService != 0); QQmlEngine engine; engine.rootContext()->setContextProperty("accountService", accountService); QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService {\n" " id: account\n" " objectHandle: accountService\n" " credentials: Credentials {\n" " objectName: \"creds\"\n" " userName: \"Happy user\"\n" " caption: account.provider.displayName\n" " }\n" "}", QUrl()); QObject *qmlAccount = component.create(); QVERIFY(qmlAccount != 0); QObject *qmlCredentials = qmlAccount->findChild<QObject*>("creds"); QVERIFY(qmlCredentials != 0); /* Sanity check */ QCOMPARE(qmlAccount->property("credentials").value<QObject*>(), qmlCredentials); QCOMPARE(qmlCredentials->property("userName").toString(), QString("Happy user")); QCOMPARE(qmlCredentials->property("caption").toString(), QString("Cool provider")); /* Store the credentials */ QSignalSpy synced(qmlCredentials, SIGNAL(synced())); bool ok; ok = QMetaObject::invokeMethod(qmlCredentials, "sync"); QVERIFY(ok); /* Wait for the operation to finish, and verify it succeeded */ QTest::qWait(100); QCOMPARE(synced.count(), 1); synced.clear(); uint credentialsId = qmlCredentials->property("credentialsId").toUInt(); QVERIFY(credentialsId != 0); /* Verify that autoSync is true (it should always be true by default */ QCOMPARE(qmlAccount->property("autoSync").toBool(), true); /* And check that the credentialsId have now been written to the account*/ QVariantMap authData = qmlAccount->property("authData").toMap(); QVERIFY(!authData.isEmpty()); QCOMPARE(authData["credentialsId"].toUInt(), credentialsId); /* Just to increase coverage */ qmlAccount->setProperty("credentials", QVariant::fromValue<QObject*>(qmlCredentials)); qmlAccount->setProperty("credentials", QVariant::fromValue<QObject*>(0)); QVERIFY(qmlAccount->property("credentials").value<QObject*>() == 0); delete qmlAccount; delete accountService; } void PluginTest::testApplicationModel() { QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "ApplicationModel {}", QUrl()); QObject *qmlModel = component.create(); QVERIFY(qmlModel != 0); QAbstractListModel *model = qobject_cast<QAbstractListModel*>(qmlModel); QVERIFY(model != 0); QCOMPARE(model->rowCount(), 0); /* Retrieve a couple of invalid indexes */ QVERIFY(!get(model, 0, "applicationId").isValid()); QVERIFY(!get(model, -1, "applicationId").isValid()); /* Set a valid service on the model */ qmlModel->setProperty("service", QString("badmail")); QCOMPARE(model->property("service").toString(), QString("badmail")); QCOMPARE(model->rowCount(), 1); QCOMPARE(model->property("count").toInt(), 1); QCOMPARE(get(model, 0, "applicationId").toString(), QString("mailer")); QCOMPARE(get(model, 0, "displayName").toString(), QString("Easy Mailer")); QCOMPARE(get(model, 0, "iconName").toString(), QString("mailer-icon")); QCOMPARE(get(model, 0, "serviceUsage").toString(), QString("Mailer can retrieve your e-mails")); QVariant value; QVERIFY(QMetaObject::invokeMethod(model, "get", Q_RETURN_ARG(QVariant, value), Q_ARG(int, 0), Q_ARG(QString, "applicationId"))); QCOMPARE(value.toString(), QString("mailer")); /* Get an Application from the model */ QObject *application = get(model, 0, "application").value<QObject*>(); QCOMPARE(application->metaObject()->className(), "OnlineAccounts::Application"); /* Reset the model to an invalid service */ qmlModel->setProperty("service", QString()); QCOMPARE(model->rowCount(), 0); delete qmlModel; } void PluginTest::testUiPolicy_data() { QTest::addColumn<QString>("name"); QTest::addColumn<int>("expectedValue"); QTest::newRow("default") << "AccountService.DefaultPolicy" << int(SignOn::DefaultPolicy); QTest::newRow("request pw") << "AccountService.RequestPasswordPolicy" << int(SignOn::RequestPasswordPolicy); QTest::newRow("no UI") << "AccountService.NoUserInteractionPolicy" << int(SignOn::NoUserInteractionPolicy); QTest::newRow("validation") << "AccountService.ValidationPolicy" << int(SignOn::ValidationPolicy); } void PluginTest::testUiPolicy() { QFETCH(QString, name); QFETCH(int, expectedValue); QQmlEngine engine; QQmlComponent component(&engine); component.setData("import SSO.OnlineAccounts 0.1\n" "AccountService {\n" " property var value: " + name.toUtf8() + "\n" "}", QUrl()); QObject *qmlObject = component.create(); QVERIFY(qmlObject != 0); QCOMPARE(qmlObject->property("value").toInt(), expectedValue); delete qmlObject; } QTEST_MAIN(PluginTest); #include "tst_plugin.moc" 0707010000004B000081A4000000000000000000000001653D36F100000293000000000000000000000000000000000000004800000000accounts-qml-module-0.7git.20231028T182937~05e79eb/tests/tst_plugin.proinclude(../common-project-config.pri) include($${TOP_SRC_DIR}/common-vars.pri) include($${TOP_SRC_DIR}/common-installs-config.pri) TARGET = tst_plugin CONFIG += \ debug \ link_pkgconfig QT += \ core \ qml \ testlib PKGCONFIG += \ accounts-qt$$QT_MAJOR_VERSION \ libsignon-qt$$QT_MAJOR_VERSION SOURCES += \ tst_plugin.cpp INCLUDEPATH += \ $$TOP_SRC_DIR/src DATA_PATH = $${TOP_SRC_DIR}/tests/data/ DEFINES += \ TEST_DATA_DIR=\\\"$$DATA_PATH\\\" check.commands = "LD_LIBRARY_PATH=mock:${LD_LIBRARY_PATH} xvfb-run -a dbus-test-runner -m 120 -t ./$${TARGET}" check.depends = $${TARGET} QMAKE_EXTRA_TARGETS += check 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!608 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor