Imported Upstream version 0.0.1 upstream/0.0.1
authorAmarnath Valluri <amarnath.valluri@linux.intel.com>
Mon, 19 Aug 2013 12:41:04 +0000 (15:41 +0300)
committerAmarnath Valluri <amarnath.valluri@linux.intel.com>
Mon, 19 Aug 2013 12:41:04 +0000 (15:41 +0300)
25 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
data/Makefile.am [new file with mode: 0644]
data/com.google.code.AccountsSSO.gSingleSignOnUI.service.in [new file with mode: 0644]
data/singlesignonui-dialog.xml [new file with mode: 0644]
data/singlesignonui.xml [new file with mode: 0644]
dists/rpm/signonui-efl.changes [new file with mode: 0644]
dists/rpm/signonui-efl.spec [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/sso-ui-dialog.c [new file with mode: 0644]
src/sso-ui-dialog.h [new file with mode: 0644]
src/sso-ui.c [new file with mode: 0644]
tests/Makefile.am [new file with mode: 0644]
tests/README.tests [new file with mode: 0644]
tests/run-unit-tests [new file with mode: 0755]
tools/Makefile.am [new file with mode: 0644]
tools/cancel-ui-request [new file with mode: 0755]
tools/query-dialog [new file with mode: 0755]
tools/refresh-dialog [new file with mode: 0755]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..459aa08
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Jussi Kukkonen <jussi.kukkonen@intel.com>
+Amarnath Valluri <amarnath.valluri@linux.intel.com>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..4362b49
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,502 @@
+                  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.
+\f
+  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.
+\f
+                  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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
+\f
+           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!
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..dd34b12
--- /dev/null
@@ -0,0 +1,2 @@
+SUBDIRS = data src tools tests
+CLEANFILES = *~
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..882f6d2
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+Authentication UI for accounts-sso
+
+https://code.google.com/p/accounts-sso/
+
+This is a authentication UI for the Accounts and Single Sign-On
+framework. It includes a D-Bus service. When queryDialog() is 
+called the service will, if needed, show the user a Elementary 
+(EFL) authentication dialog and return the results of this
+authentication when user is ready.
+
+The dialog is a minimal implementation: it does not try to be fancy,
+and has only been 'designed' to the point where all the supported
+options are somewhat available in the UI. Proper user interaction
+design will likely result in a re-implementation of sso-ui-dialog.
+
+This implementation is currently untested with any real sso
+daemon, and the D-Bus API is largely undocumented, so interoperability
+fixes are likely to be needed: As an example, the D-Bus names and paths
+are mostly made up. It does include a small test suite and
+tools to trigger the dialog for manual testing.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..620de9b
--- /dev/null
@@ -0,0 +1 @@
+autoreconf -v -i 
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..fc8c952
--- /dev/null
@@ -0,0 +1,38 @@
+AC_PREREQ(2.60)
+AC_INIT([signonui-efl], [0.0.1], [jussi.kukkonen@intel.com])
+AM_INIT_AUTOMAKE([1.11 -Wall -Werror dist-bzip2])
+AM_SILENT_RULES([yes])
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_INSTALL
+
+PKG_CHECK_MODULES(GLIB,
+                  glib-2.0 >= 2.30
+                  gio-unix-2.0)
+
+PKG_CHECK_MODULES(EFL,
+                  ecore
+                  evas
+                  elementary)
+
+PKG_CHECK_MODULES(GSIGNOND,
+                  gsignond)
+
+AC_ARG_ENABLE(timeout,
+              [--enable-timeout Enable/disable daemon timeout],
+              [enable_timeout=$enableval],
+              [enable_timeout=yes])
+if test "x$enable_timeout" = "xyes" ; then
+    AC_DEFINE(ENABLE_TIMEOUT, [1], [Enable daemon timeout])
+fi
+
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_FILES([
+        Makefile
+        src/Makefile
+        data/Makefile
+        tools/Makefile
+        tests/Makefile
+])
+AC_OUTPUT
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644 (file)
index 0000000..39ba5b0
--- /dev/null
@@ -0,0 +1,14 @@
+
+noinst_DATA = singlesignonui.xml singlesignonui-dialog.xml
+
+servicedir = $(datadir)/dbus-1/services
+service_in_files = com.google.code.AccountsSSO.gSingleSignOnUI.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+
+com.google.code.AccountsSSO.gSingleSignOnUI.service: com.google.code.AccountsSSO.gSingleSignOnUI.service.in Makefile
+       $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
+
+EXTRA_DIST = $(noinst_DATA) \
+             $(service_in_files)
+
+CLEANFILES = $(service_DATA)
diff --git a/data/com.google.code.AccountsSSO.gSingleSignOnUI.service.in b/data/com.google.code.AccountsSSO.gSingleSignOnUI.service.in
new file mode 100644 (file)
index 0000000..818d97c
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=com.google.code.AccountsSSO.gSingleSignOn.UI
+Exec=@libexecdir@/signon-ui
diff --git a/data/singlesignonui-dialog.xml b/data/singlesignonui-dialog.xml
new file mode 100644 (file)
index 0000000..f9afa8e
--- /dev/null
@@ -0,0 +1,19 @@
+<node>
+  <interface name="com.google.code.AccountsSSO.gSingleSignOn.UI.Dialog">
+
+    <method name="queryDialog">
+      <arg direction="in" type="a{sv}" name="parameters"/>
+      <arg direction="out" type="a{sv}" name="return_value"/>
+    </method>
+
+    <method name="refreshDialog">
+      <arg direction="in" type="a{sv}" name="parameters"/>
+    </method>
+
+    <method name="cancelUiRequest">
+      <arg direction="in" type="s" name="request_id"/>
+    </method>
+
+  </interface>
+</node>
+
diff --git a/data/singlesignonui.xml b/data/singlesignonui.xml
new file mode 100644 (file)
index 0000000..c02042c
--- /dev/null
@@ -0,0 +1,8 @@
+<node>
+  <interface name="com.google.code.AccountsSSO.gSingleSignOn.UI">
+    <method name="getBusAddress">
+      <arg direction="out" type="s" name="bus_socket_address"/>
+    </method>
+  </interface>
+</node>
+
diff --git a/dists/rpm/signonui-efl.changes b/dists/rpm/signonui-efl.changes
new file mode 100644 (file)
index 0000000..b2c4c1c
--- /dev/null
@@ -0,0 +1,2 @@
+* Thu Jun 27 2013 Amarnath Valluri <amarnath.valluri@linux.intel.com>
+- Initial RPM packaging
diff --git a/dists/rpm/signonui-efl.spec b/dists/rpm/signonui-efl.spec
new file mode 100644 (file)
index 0000000..0355f35
--- /dev/null
@@ -0,0 +1,42 @@
+Name: signon-ui
+Summary: EFL based Single Sign-On UI
+URL: https://code.google.com/p/accounts-sso/source/checkout?repo=signonui-efl
+Version: 0.0.1
+Release: 1
+Group: Security/Secure Storage
+License: LGPL-2.1+
+Source: %{name}-%{version}.tar.gz
+Requires: dbus-1
+BuildRequires: pkgconfig(dbus-1)
+BuildRequires: pkgconfig(glib-2.0) >= 2.30
+BuildRequires: pkgconfig(gio-unix-2.0)
+BuildRequires: pkgconfig(evas)
+BuildRequires: pkgconfig(elementary)
+BuildRequires: pkgconfig(gsignond)
+Provides: signon-ui
+
+
+%description
+EFL based Single Sign-On UI used by gsignond.
+
+
+%prep
+%setup -q -n %{name}-%{version}
+autoreconf -f -i
+
+
+%build
+%configure
+make %{?_smp_mflags}
+
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+
+%files
+%defattr(-,root,root,-)
+%{_libexecdir}/%{name}
+%{_datadir}/dbus-1/services/*.service
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..19ae08a
--- /dev/null
@@ -0,0 +1,43 @@
+libexec_PROGRAMS = signon-ui
+
+BUILT_SOURCES = \
+    sso-ui-dbus-glue.c \
+    sso-ui-dbus-glue.h \
+    sso-ui-dialog-dbus-glue.c \
+    sso-ui-dialog-dbus-glue.h
+
+sso-ui-dbus-glue.c sso-ui-dbus-glue.h: ../data/singlesignonui.xml
+       $(AM_V_GEN) gdbus-codegen \
+       --interface-prefix com.google.code.AccountsSSO.gSingleSignOn \
+       --generate-c-code sso-ui-dbus-glue \
+    --c-namespace SSO_Dbus \
+       $<
+
+sso-ui-dialog-dbus-glue.c sso-ui-dialog-dbus-glue.h: ../data/singlesignonui-dialog.xml
+       $(AM_V_GEN) gdbus-codegen \
+       --interface-prefix com.google.code.AccountsSSO.gSingleSignOn \
+       --generate-c-code sso-ui-dialog-dbus-glue \
+    --c-namespace SSO_Dbus \
+       $<
+
+signon_ui_SOURCES = \
+       $(BUILT_SOURCES) \
+       sso-ui-dialog.c \
+       sso-ui-dialog.h \
+       sso-ui.c
+
+signon_ui_CFLAGS = \
+       $(GLIB_CFLAGS) \
+       $(EFL_CFLAGS) \
+    $(GSIGNOND_CFLAGS) \
+    -Wall -Werror \
+       -I$(top_srcdir)
+
+signon_ui_LDADD = \
+       $(GLIB_LIBS) \
+       $(EFL_LIBS) \
+    $(GSIGNOND_LIBS)
+
+CLEANFILES = \
+       $(BUILT_SOURCES) \
+       *~
diff --git a/src/sso-ui-dialog.c b/src/sso-ui-dialog.c
new file mode 100644 (file)
index 0000000..2494529
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * This file is part of signonui-efl
+ *
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * Author: Jussi Kukkonen <jussi.kukkonen@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <Elementary.h>
+#include <gsignond/gsignond-signonui.h>
+#include <gsignond/gsignond-signonui-data.h>
+
+#include "sso-ui-dialog.h"
+
+G_DEFINE_TYPE (SSOUIDialog, sso_ui_dialog, G_TYPE_OBJECT)
+
+#define UI_DIALOG_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), SSO_TYPE_UI_DIALOG, SSOUIDialogPrivate))
+
+struct _SSOUIDialogPrivate {
+  GDBusMethodInvocation  *invocation;
+  GSignondSignonuiData *params;
+  const gchar *old_password;
+  const gchar *oauth_final_url;
+
+  int error_code;
+#if 0
+  /* hack for automated testing: contains values that should be sent as reply */
+  char *test_reply;
+#endif
+  gchar *oauth_response;
+
+  Evas_Object *dialog;
+  Evas_Object *message;
+  Evas_Object *username_entry;
+  Evas_Object *password_entry;
+  Evas_Object *password_confirm1_entry;
+  Evas_Object *password_confirm2_entry;
+  Evas_Object *remember_check;
+  Evas_Object *captcha_image;
+  Evas_Object *captcha_entry;
+  Evas_Object *oauth_web;
+
+};
+
+enum {
+  PROP_0,
+  PROP_INVOCATION,
+  PROP_PARAMETERS,
+  PROP_RETURN_VALUE,
+};
+
+enum {
+  CLOSED_SIGNAL,
+  LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+sso_ui_dialog_get_property (GObject    *object,
+                            guint       property_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  SSOUIDialog *self = SSO_UI_DIALOG (object);
+
+  switch (property_id)
+    {
+    case PROP_INVOCATION:
+      g_value_set_object (value, self->priv->invocation);
+      break;
+    case PROP_RETURN_VALUE:
+      g_value_set_boxed (value, sso_ui_dialog_get_return_value (self));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+sso_ui_dialog_set_property (GObject      *object,
+                            guint         property_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  SSOUIDialog *self = SSO_UI_DIALOG (object);
+  switch (property_id)
+    {
+    case PROP_INVOCATION:
+      self->priv->invocation = g_value_get_object (value);
+      break;
+    case PROP_PARAMETERS: {
+      GSignondSignonuiData *params = g_value_get_boxed (value);
+      sso_ui_dialog_set_parameters (self, params);
+      break;
+    }
+    case PROP_RETURN_VALUE:
+      /* not settable */
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+sso_ui_dialog_dispose (GObject *object)
+{
+  SSOUIDialog *self = SSO_UI_DIALOG (object);
+
+  gsignond_signonui_data_unref (self->priv->params);
+  self->priv->params = NULL;
+#if 0
+  g_free (self->priv->test_reply);
+  self->priv->test_reply = NULL;
+#endif
+  g_free (self->priv->oauth_response);
+  self->priv->oauth_response = NULL;
+
+  if (self->priv->dialog) {
+    evas_object_del (self->priv->dialog);
+    self->priv->dialog = NULL;
+  }
+
+  G_OBJECT_CLASS (sso_ui_dialog_parent_class)->dispose (object);
+}
+
+static void
+sso_ui_dialog_class_init (SSOUIDialogClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (SSOUIDialogPrivate));
+
+  object_class->get_property = sso_ui_dialog_get_property;
+  object_class->set_property = sso_ui_dialog_set_property;
+  object_class->dispose = sso_ui_dialog_dispose;
+
+  g_object_class_install_property (object_class, PROP_INVOCATION,
+      g_param_spec_object ("invocation", "Invocation",
+                           "The GDBusMethodInvocation object for this authentication",
+                           G_TYPE_DBUS_METHOD_INVOCATION,
+                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class, PROP_PARAMETERS,
+      g_param_spec_boxed ("parameters", "Parameters",
+                            "The GVariant a{sv} that contains the parameters for this dialog",
+                            GSIGNOND_TYPE_SIGNONUI_DATA, 
+                            G_PARAM_WRITABLE));
+
+  g_object_class_install_property (object_class, PROP_RETURN_VALUE,
+      g_param_spec_boxed ("return-value", "Return value",
+                            "The return value for this dialog. Only defined after closed signal",
+                            GSIGNOND_TYPE_SIGNONUI_DATA,
+                            G_PARAM_READABLE));
+
+  signals[CLOSED_SIGNAL] =
+    g_signal_new ("closed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (SSOUIDialogClass, closed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+}
+
+static void
+sso_ui_dialog_init (SSOUIDialog *self)
+{
+  SSOUIDialogPrivate *priv = UI_DIALOG_PRIVATE (self);
+
+  priv->params = NULL;
+  priv->error_code = SIGNONUI_ERROR_NONE;
+  priv->old_password = NULL;
+  priv->oauth_final_url = NULL;
+  priv->oauth_response = NULL;
+  
+  priv->dialog  = NULL;
+  priv->message = NULL;
+  priv->username_entry = NULL;
+  priv->password_entry = NULL;
+  priv->password_confirm1_entry = NULL;
+  priv->password_confirm2_entry = NULL;
+  priv->remember_check = NULL;
+  priv->captcha_image = NULL;
+  priv->captcha_entry = NULL;
+  priv->oauth_web = NULL;
+
+  self->priv = priv;
+}
+
+static void
+close_dialog (SSOUIDialog *self)
+{
+  g_debug ("Dialog %s closed", gsignond_signonui_data_get_request_id (
+                self->priv->params));
+
+  evas_object_hide (self->priv->dialog);
+  self->priv->dialog = NULL;
+
+  g_signal_emit (self, signals[CLOSED_SIGNAL], 0);
+}
+
+static void
+on_cancel_or_close_clicked (void *data, Evas_Object *obj, void *event_info)
+{
+  SSOUIDialog *self = SSO_UI_DIALOG (data);
+
+  self->priv->error_code = SIGNONUI_ERROR_CANCELED;
+  close_dialog (self);
+}
+
+static void
+on_ok_clicked (void *data, Evas_Object *obj, void *event_info)
+{
+  SSOUIDialog *self = SSO_UI_DIALOG (data);
+  SSOUIDialogPrivate *priv = self->priv;
+  gboolean query_confirm = FALSE;
+
+  gsignond_signonui_data_get_confirm (priv->params, &query_confirm);
+
+  if (query_confirm) {
+    g_assert (priv->old_password);
+
+    if (g_strcmp0 (priv->old_password,
+                   elm_entry_entry_get (priv->password_entry)) != 0) {
+      g_debug ("Old password does not match, not accepting.");
+      return;
+    }
+    if (g_strcmp0 (elm_entry_entry_get (priv->password_confirm1_entry),
+                   elm_entry_entry_get (priv->password_confirm2_entry)) != 0) {
+      g_debug ("New passwords do not match, not accepting.");
+      return;
+    }
+  }
+
+  priv->error_code = SIGNONUI_ERROR_NONE;
+  close_dialog (self);
+}
+
+static void
+on_forgot_clicked (void *data, Evas_Object *obj, void *event_info)
+{
+  SSOUIDialog *self = SSO_UI_DIALOG (data);
+  GError *error = NULL;
+
+  const gchar *forgot_url = 
+        gsignond_signonui_data_get_forgot_password_url (self->priv->params);
+
+  if (!forgot_url) {
+    g_warning ("'forgot password' URL is not set.");
+    return;
+  }
+
+  if (!g_app_info_launch_default_for_uri (forgot_url,
+                                          NULL,
+                                          &error)) {
+    g_warning ("Failed to launch default handler for '%s': %s.",
+               forgot_url, error->message);
+    g_clear_error (&error);
+    return;
+  }
+
+  g_debug ("Launched default handler for 'forgot password' URL %s",
+           forgot_url);
+  self->priv->error_code = SIGNONUI_ERROR_FORGOT_PASSWORD;
+  close_dialog (self);
+}
+
+static void
+on_web_uri_change (void *data, Evas_Object *obj, void *event_info)
+{
+  SSOUIDialog *self = data;
+  const char *uri = event_info;
+
+  if (!self->priv->oauth_final_url ||
+      !g_str_has_prefix (uri, self->priv->oauth_final_url))
+    return;
+
+   g_debug ("FOUND URL : %s", uri);
+   self->priv->oauth_response = g_strdup (uri);
+
+  self->priv->error_code = SIGNONUI_ERROR_NONE;
+  close_dialog (self);
+}
+
+static Evas_Object*
+add_entry (Evas_Object *window, Evas_Object *container, const gchar *label_text)
+{
+  Evas_Object *frame = NULL;
+  Evas_Object *entry = NULL;
+
+  if (label_text) {
+    frame = elm_frame_add(window);
+
+    elm_object_text_set(frame, label_text);
+    evas_object_size_hint_weight_set(frame, 0.0, 0.0);
+    evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
+    elm_box_pack_end(container, frame);
+    evas_object_show(frame);
+  }
+
+  entry = elm_entry_add (window);
+  elm_entry_single_line_set (entry, EINA_TRUE);
+  elm_entry_scrollable_set (entry, EINA_TRUE);
+  evas_object_size_hint_min_set (entry, 150, 80);
+  evas_object_size_hint_align_set (entry,
+                                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+  evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, 0.0);
+  frame ? elm_object_content_set (frame, entry) 
+        : elm_box_pack_end (container, entry);
+
+  return entry;
+}
+
+static gboolean
+build_dialog (SSOUIDialog *self)
+{
+  SSOUIDialogPrivate *priv = self->priv;
+
+  const gchar *str = NULL;
+
+  Evas_Object *bg, *box, *frame, *content_box;
+  Evas_Object *button_frame, *pad_frame, *button_box;
+  Evas_Object *cancel_button, *ok_button;
+
+#if 0
+  priv->test_reply = gsignond_signonui_data_get_test_reply (priv->params);
+#endif
+  /* main window */
+  priv->dialog = elm_win_add (NULL, "dialog", ELM_WIN_BASIC);
+  str = gsignond_signonui_data_get_title(priv->params);
+  elm_win_title_set (priv->dialog, str ? str : "Single Sign-On");
+  elm_win_center (priv->dialog, EINA_TRUE, EINA_TRUE);
+  evas_object_smart_callback_add (priv->dialog, "delete,request",
+                                  on_cancel_or_close_clicked, self);
+
+  /* window background */
+  bg = elm_bg_add (priv->dialog);
+  evas_object_size_hint_weight_set (bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+  evas_object_show (bg);
+  elm_win_resize_object_add (priv->dialog, bg);
+
+  box = elm_box_add (priv->dialog);
+  evas_object_size_hint_min_set (box, 200, 200);
+  evas_object_size_hint_weight_set (box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+  evas_object_show (box);
+  elm_win_resize_object_add (priv->dialog, box);
+
+  frame = elm_frame_add (priv->dialog);
+  elm_object_style_set (frame, "pad_small");
+  evas_object_size_hint_weight_set (frame,
+                                    EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+  evas_object_size_hint_align_set (frame,
+                                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+  evas_object_show (frame);
+  elm_box_pack_start (box, frame);
+
+  content_box = elm_box_add (priv->dialog);
+  elm_box_padding_set (content_box, 0, 3);
+  evas_object_size_hint_weight_set (content_box, 
+                                    EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+  evas_object_size_hint_align_set (content_box, 0.0, 0.0);
+  evas_object_show (content_box);
+  elm_object_part_content_set (frame, NULL, content_box);
+
+  /* Web Dialog for Outh */
+  if ((str = gsignond_signonui_data_get_open_url (priv->params))) {
+    priv->oauth_final_url = gsignond_signonui_data_get_final_url (priv->params);
+    if (elm_need_web ()) {
+      priv->oauth_web = elm_web_add (priv->dialog);
+      if (!elm_web_uri_set(priv->oauth_web, str))
+        g_warning ("Failed to set URI '%s'", str);
+
+      evas_object_size_hint_min_set (priv->oauth_web, 200, 200);
+      evas_object_size_hint_weight_set(priv->oauth_web,
+                                     EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+      evas_object_size_hint_align_set (priv->oauth_web,
+                                     EVAS_HINT_FILL, EVAS_HINT_FILL);
+      evas_object_smart_callback_add (priv->oauth_web, "uri,changed",
+                                    on_web_uri_change, self);
+      elm_box_pack_end (content_box, priv->oauth_web);
+    } else {
+      g_debug ("Web login is disabled: Elementary does not have Ewebkit support");
+      priv->oauth_web = NULL;
+    } 
+  }
+  else {
+    gboolean query_username = FALSE;
+    gboolean remember = FALSE;
+    gboolean confirm = FALSE;
+    /* credentials */
+    if ((str = gsignond_signonui_data_get_caption (priv->params))) {
+      Evas_Object *caption_label = elm_label_add (priv->dialog);
+      elm_object_text_set (caption_label, str);
+      evas_object_size_hint_align_set (caption_label,
+                                   0.0, 0.0);
+      evas_object_show (caption_label);
+      elm_box_pack_end (content_box, caption_label);
+    }
+
+    priv->username_entry = add_entry (priv->dialog, content_box, "Username:");
+    gsignond_signonui_data_get_query_username (priv->params, &query_username);
+    str = gsignond_signonui_data_get_username (priv->params);
+    elm_entry_entry_set (priv->username_entry, str ? str : "");
+    g_debug ("Settin username entry to editable %d", query_username || !str ? EINA_TRUE : EINA_FALSE);
+    elm_entry_editable_set (priv->username_entry, query_username || !str ? EINA_TRUE : EINA_FALSE);
+
+    priv->password_entry = add_entry (priv->dialog, content_box, "Password:");
+    elm_entry_password_set (priv->password_entry, EINA_TRUE);
+    if (gsignond_signonui_data_get_confirm (priv->params, &confirm) && confirm) {
+      priv->old_password = gsignond_signonui_data_get_password (priv->params);
+      elm_entry_entry_set (priv->password_entry, priv->old_password ? priv->old_password : "");
+      elm_entry_editable_set (priv->password_entry, EINA_FALSE);
+        
+      priv->password_confirm1_entry = add_entry (priv->dialog, content_box, "New Password:");
+      elm_entry_password_set (priv->password_confirm1_entry, EINA_TRUE);
+
+      priv->password_confirm2_entry = add_entry (priv->dialog, content_box, "Confirm New Password:");
+      elm_entry_password_set (priv->password_confirm2_entry, EINA_TRUE);
+    }
+    else 
+      elm_entry_editable_set (priv->password_entry, EINA_TRUE);
+
+    /* remember password */
+    priv->remember_check = elm_check_add (priv->dialog);
+    elm_object_text_set (priv->remember_check, "Remember password");
+    evas_object_show (priv->remember_check);
+    gsignond_signonui_data_get_remember_password (priv->params, &remember);
+    elm_check_state_set (priv->remember_check, remember);
+    evas_object_size_hint_align_set (priv->remember_check,
+                                   1.0, EVAS_HINT_FILL);
+    elm_box_pack_end (content_box, priv->remember_check);
+
+    /* Forgot password link */
+    if ((str =gsignond_signonui_data_get_forgot_password_url (priv->params))) {
+      Evas_Object *forgot_button = elm_button_add (priv->dialog);
+      elm_object_text_set (forgot_button, "Forgot password");
+      evas_object_smart_callback_add (forgot_button, "clicked",
+                                  on_forgot_clicked, self);
+      evas_object_size_hint_align_set (forgot_button,
+                                   1.0, EVAS_HINT_FILL);
+      evas_object_size_hint_weight_set (forgot_button, 0.0, 0.0);
+      evas_object_show (forgot_button);
+      elm_box_pack_end (content_box, forgot_button);
+    }
+
+   /* sigh, Elm_Image can't load urls, and ecore can't use temp files sanely*/
+    /* double sigh, ecore_file_download() does not work with file:// ??? */
+    if ((str = gsignond_signonui_data_get_captcha_url (priv->params))) { 
+      priv->captcha_image = elm_image_add (priv->dialog);
+      elm_image_aspect_fixed_set (priv->captcha_image, TRUE);
+      evas_object_size_hint_align_set (priv->captcha_image,
+                                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+      elm_box_pack_end (content_box, priv->captcha_image);
+      priv->captcha_entry = add_entry (priv->dialog, content_box, NULL);
+
+      sso_ui_dialog_refresh_captcha (self, str);
+    }
+
+    if ((str = gsignond_signonui_data_get_message (priv->params))) {
+      priv->message = elm_label_add (priv->dialog);
+      elm_object_text_set (priv->message, str);
+      evas_object_size_hint_align_set (priv->message,
+                                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+      elm_box_pack_end (content_box, priv->message);
+    }
+
+    /* button row */
+
+    button_frame = elm_frame_add (priv->dialog);
+    elm_object_style_set (button_frame, "outdent_bottom");
+    evas_object_size_hint_weight_set (button_frame, 0.0, 0.0);
+    evas_object_size_hint_align_set (button_frame,
+                                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+    evas_object_show (button_frame);
+    elm_box_pack_end (box, button_frame);
+
+    pad_frame = elm_frame_add (priv->dialog);
+    elm_object_style_set (pad_frame, "pad_medium");
+    evas_object_show (pad_frame);
+    elm_object_part_content_set (button_frame, NULL, pad_frame);
+
+    button_box = elm_box_add (priv->dialog);
+    elm_box_horizontal_set (button_box, 1);
+    elm_box_homogeneous_set (button_box, 1);
+    evas_object_show (button_box);
+    elm_object_part_content_set (pad_frame, NULL, button_box);
+
+
+    /* Cancel button */
+    cancel_button = elm_button_add (priv->dialog);
+    elm_object_text_set (cancel_button, "Cancel");
+    evas_object_size_hint_weight_set (cancel_button,
+                                    EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+    evas_object_size_hint_align_set (cancel_button,
+                                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+    evas_object_smart_callback_add (cancel_button, "clicked",
+                                 on_cancel_or_close_clicked, self);
+    evas_object_show (cancel_button);
+    elm_box_pack_end (button_box, cancel_button);
+
+    /* OK button */
+    ok_button = elm_button_add (priv->dialog);
+    elm_object_text_set (ok_button, "OK");
+    evas_object_size_hint_weight_set (ok_button,
+                                    EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+    evas_object_size_hint_align_set (ok_button,
+                                   EVAS_HINT_FILL, EVAS_HINT_FILL);
+    evas_object_smart_callback_add (ok_button, "clicked", on_ok_clicked, self);
+    evas_object_show (ok_button);
+    elm_box_pack_end (button_box, ok_button);
+  }
+
+  return TRUE;
+}
+
+void
+sso_ui_dialog_set_parameters (SSOUIDialog *self,
+                              GSignondSignonuiData *parameters)
+{
+  SSOUIDialogPrivate *priv = self->priv;
+
+  priv->params = gsignond_signonui_data_ref (parameters);
+
+  build_dialog (self);
+}
+
+gboolean
+sso_ui_dialog_refresh_captcha (SSOUIDialog *self, const gchar *url)
+{
+  g_return_val_if_fail (self && SSO_IS_UI_DIALOG (self), FALSE);
+  g_return_val_if_fail (url, FALSE);
+
+  gchar *filename = g_filename_from_uri (url, NULL, NULL);
+
+  g_debug ("Using captcha %s", filename);
+  if (!filename) return FALSE;
+  elm_image_file_set (self->priv->captcha_image, filename, NULL);
+  g_free (filename);
+
+  return TRUE;
+}
+
+GDBusMethodInvocation*
+sso_ui_dialog_get_invocation (SSOUIDialog *self)
+{
+  return self->priv->invocation;
+}
+
+const gchar*
+sso_ui_dialog_get_request_id   (SSOUIDialog *self)
+{
+  return gsignond_signonui_data_get_request_id (self->priv->params);
+}
+
+GSignondSignonuiData*
+sso_ui_dialog_get_return_value (SSOUIDialog *self)
+{
+  SSOUIDialogPrivate *priv = self->priv;
+  GSignondSignonuiData *reply = gsignond_signonui_data_new ();
+
+  gsignond_signonui_data_set_query_error (reply, priv->error_code);
+
+  if (priv->error_code == SIGNONUI_ERROR_NONE) {
+    gboolean query_oauth = gsignond_signonui_data_get_open_url (priv->params) != NULL;
+
+    if (query_oauth) {
+      gsignond_signonui_data_set_url_response (reply, priv->oauth_response);
+    }
+    else {
+      gboolean query_username = FALSE;
+      gboolean query_confirm = FALSE;
+      gsignond_signonui_data_get_query_username (priv->params, &query_username);
+      gsignond_signonui_data_get_confirm (priv->params, &query_confirm);
+
+      gsignond_signonui_data_set_password (reply,
+           elm_entry_entry_get (query_confirm ? 
+               priv->password_confirm1_entry : priv->password_entry)); 
+      if (priv->remember_check) {
+        gsignond_signonui_data_set_remember_password (reply,
+                               elm_check_state_get (priv->remember_check));
+      }
+
+      if (priv->captcha_entry) {
+        gsignond_signonui_data_set_captcha_response (reply,
+            elm_entry_entry_get (priv->captcha_entry));
+      }
+      if (query_username) {
+        gsignond_signonui_data_set_username (reply,
+               elm_entry_entry_get (priv->username_entry));
+      }
+    }
+  }
+
+  return reply;
+}
+#if 0
+static void
+sso_ui_dialog_handle_test_reply (SSOUIDialog *self)
+{
+  char **iter;
+  char **pairs = g_strsplit (self->priv->test_reply, ",", 0);
+  for (iter = pairs; *iter; iter++) {
+    char **pair = g_strsplit (*iter, ":", 2);
+    if (g_strv_length (pair) == 2) {
+      if (g_strcmp0 (pair[0], SSO_UI_KEY_CAPTCHA_RESPONSE) == 0) {
+        if (evas_object_visible_get (self->priv->captcha_entry))
+          elm_entry_entry_set (self->priv->captcha_entry, pair[1]);
+      } else if (g_strcmp0 (pair[0], SSO_UI_KEY_PASSWORD) == 0) {
+        if (evas_object_visible_get (self->priv->password_entry))
+          elm_entry_entry_set (self->priv->password_entry, pair[1]);
+        if (evas_object_visible_get (self->priv->password_confirm1_entry))
+          elm_entry_entry_set (self->priv->password_confirm1_entry, pair[1]);
+      } else if (g_strcmp0 (pair[0], SSO_UI_KEY_QUERY_ERROR_CODE) == 0) {
+        self->priv->error_code = atoi(pair[1]);
+      } else if (g_strcmp0 (pair[0], SSO_UI_KEY_REMEMBER_PASSWORD) == 0) {
+        if (evas_object_visible_get (self->priv->remember_check))
+          elm_check_state_set (self->priv->remember_check, g_strcmp0 (pair[1], "True") == 0);
+      } else if (g_strcmp0 (pair[0], SSO_UI_KEY_URL_RESPONSE) == 0) {
+        if (evas_object_visible_get (self->priv->oauth_web))
+          self->priv->oauth_response = g_strdup (pair[1]);
+      } else if (g_strcmp0 (pair[0], SSO_UI_KEY_USERNAME) == 0) {
+        if (evas_object_visible_get (self->priv->username_entry))
+          elm_entry_entry_set (self->priv->username_entry, pair[1]);
+      }
+    }
+    g_strfreev (pair);
+  }
+  g_strfreev (pairs);
+}
+#endif
+gboolean
+sso_ui_dialog_show (SSOUIDialog *self)
+{
+  SSOUIDialogPrivate *priv = self->priv;
+
+  const gchar *request_id = gsignond_signonui_data_get_request_id (priv->params);
+  gboolean query_oauth = FALSE;
+  gboolean query_username = FALSE;
+  gboolean query_password = FALSE;
+  gboolean query_confirm = FALSE;
+
+  query_oauth = gsignond_signonui_data_get_open_url (priv->params) != NULL;
+  gsignond_signonui_data_get_query_username (priv->params, &query_username);
+  gsignond_signonui_data_get_query_password (priv->params, &query_password);
+  gsignond_signonui_data_get_confirm (priv->params, &query_confirm);
+
+  if (!request_id) {
+    priv->error_code = SIGNONUI_ERROR_BAD_PARAMETERS;
+    return FALSE;
+  } else if (query_oauth) {
+    if (query_username ||
+        query_password ||
+        query_confirm) {
+      priv->error_code = SIGNONUI_ERROR_BAD_PARAMETERS;
+      return FALSE;
+    } 
+    else if (!priv->oauth_final_url) {
+      priv->error_code = SIGNONUI_ERROR_BAD_PARAMETERS;
+      return FALSE;
+    }
+    else if (!priv->oauth_web) {
+      priv->error_code = SIGNONUI_ERROR_NOT_AVAILABLE;
+      return FALSE;
+    }
+  }
+  else if (!query_username &&
+           !query_password &&
+           !query_confirm) {
+    priv->error_code = SIGNONUI_ERROR_BAD_PARAMETERS;
+    return FALSE;
+  } else if (query_confirm &&
+             !priv->old_password) {
+    priv->error_code = SIGNONUI_ERROR_BAD_PARAMETERS;
+    return FALSE;
+  }
+#if 0
+  if (priv->test_reply) {
+    g_debug ("Filling dialog with given test reply values");
+    sso_ui_dialog_handle_test_reply (self);
+    return FALSE;
+  }
+#endif
+  evas_object_show (priv->dialog);
+  g_debug ("Dialog %s shown", request_id);
+
+  return TRUE;
+}
+
+void
+sso_ui_dialog_close (SSOUIDialog *self)
+{
+  /* TODO : is this really considered cancel ? */
+  self->priv->error_code = SIGNONUI_ERROR_CANCELED;
+  close_dialog (self);
+}
+
+SSOUIDialog*
+sso_ui_dialog_new (GSignondSignonuiData *parameters,
+                   GDBusMethodInvocation *invocation)
+{
+  return g_object_new (SSO_TYPE_UI_DIALOG,
+                       "parameters", parameters,
+                       "invocation", invocation,
+                       NULL);
+}
+
diff --git a/src/sso-ui-dialog.h b/src/sso-ui-dialog.h
new file mode 100644 (file)
index 0000000..981cb87
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * This file is part of signonui-efl
+ *
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * Author: Jussi Kukkonen <jussi.kukkonen@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __SSO_UI_DIALOG_H__
+#define __SSO_UI_DIALOG_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gsignond/gsignond-signonui-data.h>
+
+G_BEGIN_DECLS
+
+#define SSO_TYPE_UI_DIALOG sso_ui_dialog_get_type()
+
+#define SSO_UI_DIALOG(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), SSO_TYPE_UI_DIALOG, SSOUIDialog))
+
+#define SSO_UI_DIALOG_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), SSO_TYPE_UI_DIALOG, SSOUIDialogClass))
+
+#define SSO_IS_UI_DIALOG(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SSO_TYPE_UI_DIALOG))
+
+#define SSO_IS_UI_DIALOG_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), SSO_TYPE_UI_DIALOG))
+
+#define SSO_UI_DIALOG_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), SSO_TYPE_UI_DIALOG, SSOUIDialogClass))
+
+typedef struct _SSOUIDialogPrivate SSOUIDialogPrivate;
+
+typedef struct _SSOUIDialog {
+  GObject parent;
+  SSOUIDialogPrivate *priv;
+} SSOUIDialog;
+
+typedef struct _SSOUIDialogClass {
+  GObjectClass parent_class;
+  void (* closed) (SSOUIDialog *dialog);
+} SSOUIDialogClass;
+
+GType sso_ui_dialog_get_type (void) G_GNUC_CONST;
+
+SSOUIDialog*           sso_ui_dialog_new              (GSignondSignonuiData *parameters, GDBusMethodInvocation *invocation);
+
+void                   sso_ui_dialog_set_parameters   (SSOUIDialog *self, GSignondSignonuiData *parameters);
+gboolean               sso_ui_dialog_refresh_captcha  (SSOUIDialog * self, const gchar *url);
+
+GDBusMethodInvocation* sso_ui_dialog_get_invocation   (SSOUIDialog *dialog);
+const gchar*           sso_ui_dialog_get_request_id   (SSOUIDialog *dialog);
+GSignondSignonuiData*  sso_ui_dialog_get_return_value (SSOUIDialog *dialog);
+
+gboolean               sso_ui_dialog_show             (SSOUIDialog *dialog);
+void                   sso_ui_dialog_close            (SSOUIDialog *dialog);
+
+G_END_DECLS
+
+#endif /* __SSO_UI_DIALOG_H__ */
diff --git a/src/sso-ui.c b/src/sso-ui.c
new file mode 100644 (file)
index 0000000..a729ebc
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * This file is part of signonui-efl
+ *
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * Author: Jussi Kukkonen <jussi.kukkonen@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <errno.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib/gstdio.h>
+#include <Ecore.h>
+#include <Elementary.h>
+#include <gsignond/gsignond-signonui-data.h>
+
+#include "sso-ui-dbus-glue.h"
+#include "sso-ui-dialog-dbus-glue.h"
+#include "sso-ui-dialog.h"
+
+#ifndef DAEMON_TIMEOUT
+#   define DAEMON_TIMEOUT (30) // seconds
+#endif
+
+#define SSO_UI_NAME "com.google.code.AccountsSSO.gSingleSignOn.UI"
+
+GDBusServer *bus_server = NULL; /* p2p server */
+GHashTable *dialogs;
+gchar *socket_file_path = NULL; /* p2p file system socket path */
+
+#ifdef ENABLE_TIMEOUT
+Ecore_Timer *exit_timer_id = 0;
+double timeout;
+
+static Eina_Bool 
+exit_sso_ui (gpointer data)
+{
+  g_debug ("Exiting since no calls in a while.");
+
+  elm_exit ();
+
+  if (exit_timer_id) {
+      ecore_timer_del (exit_timer_id);
+      exit_timer_id = 0;
+  }
+
+  return ECORE_CALLBACK_CANCEL;
+}
+#endif
+
+static void
+return_value (SSOUIDialog *dialog, SSODbusUIDialog *dbus_ui_dialog)
+{
+  GSignondSignonuiData *result = NULL;
+  GDBusMethodInvocation *invocation = NULL;
+  GVariant *var = NULL;
+
+  result = sso_ui_dialog_get_return_value (dialog);
+  invocation = sso_ui_dialog_get_invocation (dialog);
+  var = gsignond_signonui_data_to_variant (result);
+  /* consumes floating result GVariant */
+  sso_dbus_uidialog_complete_query_dialog (dbus_ui_dialog,invocation, var);
+  gsignond_signonui_data_unref (result);
+}
+
+static void
+on_dialog_close (SSOUIDialog *dialog,
+                 gpointer     userdata)
+{
+  return_value (dialog, SSO_DBUS_UIDIALOG(userdata));
+  g_hash_table_remove (dialogs, sso_ui_dialog_get_request_id (dialog));
+
+#ifdef ENABLE_TIMEOUT
+  if (g_hash_table_size (dialogs) == 0 && exit_timer_id) {
+    ecore_timer_thaw (exit_timer_id);
+  }
+#endif
+}
+
+static gboolean
+on_query_dialog (SSODbusUIDialog       *ui,
+                 GDBusMethodInvocation *invocation,
+                 GVariant              *var,
+                 gpointer               user_data)
+{
+  SSOUIDialog* dialog;
+  g_debug ("method 'QueryDialog' called");
+
+  GSignondSignonuiData *params = gsignond_signonui_data_new_from_variant (var);
+  dialog = sso_ui_dialog_new (params, invocation);
+  gsignond_signonui_data_unref (params);
+  g_signal_connect (dialog, "closed",
+                    G_CALLBACK (on_dialog_close), user_data);
+
+
+  if (!sso_ui_dialog_show (dialog)) {
+    /* there's an error, return it */
+    return_value (dialog, ui);
+  } else {
+    g_object_set_data (G_OBJECT (user_data), "dialog", dialog);
+    g_hash_table_insert (dialogs,
+                         (gpointer)sso_ui_dialog_get_request_id (dialog),
+                         (gpointer)dialog);
+#ifdef ENABLE_TIMEOUT
+    if (exit_timer_id) ecore_timer_freeze (exit_timer_id);
+#endif
+  }
+
+  return TRUE;
+}
+
+static gboolean
+on_refresh_dialog (SSODbusUIDialog       *ui,
+                   GDBusMethodInvocation *invocation,
+                   GVariant              *var,
+                   gpointer               user_data)
+{
+  SSOUIDialog *old_dialog;
+  GSignondSignonuiData *data = gsignond_signonui_data_new_from_variant (var);
+  const gchar *url = NULL;
+  g_debug ("method 'RefreshDialog' called");
+
+  old_dialog = g_hash_table_lookup (dialogs, 
+    gsignond_signonui_data_get_request_id (data));
+  if (old_dialog && (url = gsignond_signonui_data_get_captcha_url (data)))
+    sso_ui_dialog_refresh_captcha (old_dialog, url);
+
+  gsignond_signonui_data_unref (data);
+
+  g_dbus_method_invocation_return_value (invocation, NULL);
+  return TRUE;
+}
+
+static gboolean
+on_cancel_ui_request (SSODbusUIDialog       *ui,
+                      GDBusMethodInvocation *invocation,
+                      char                  *request_id,
+                      gpointer               user_data)
+{
+  g_debug ("method 'CancelUiRequest' called");
+
+  if (request_id) {
+    SSOUIDialog *dialog;
+    dialog = g_hash_table_lookup (dialogs, request_id);
+    if (dialog)
+      sso_ui_dialog_close (dialog);
+  }
+
+  g_dbus_method_invocation_return_value (invocation, NULL);
+  return TRUE;
+}
+
+static void 
+_on_connection_closed (GDBusConnection *connection,
+                       gboolean         remote_peer_vanished,
+                       GError          *error,
+                       gpointer         user_data)
+{
+    g_debug ("Client Dis-Connected ....");
+
+    g_signal_handlers_disconnect_by_func (connection, _on_connection_closed, user_data);
+
+    g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON(user_data));
+
+    /* close active dialog if any */
+    gpointer *dialog = g_object_get_data (G_OBJECT (user_data), "dialog");
+    if (dialog && SSO_IS_UI_DIALOG (dialog)) {
+        g_object_unref (G_OBJECT (dialog));
+    }
+
+    g_object_unref (G_OBJECT(user_data));
+}
+
+static gboolean
+on_client_connection (GDBusServer *dbus_server,
+                      GDBusConnection *connection,
+                      gpointer userdata)
+{
+  SSODbusUIDialog *dbus_dialog = sso_dbus_uidialog_skeleton_new ();
+
+  g_debug ("Client Connected ....");
+
+  g_signal_connect (dbus_dialog, "handle-query-dialog",
+                    G_CALLBACK (on_query_dialog), dbus_dialog);
+  g_signal_connect (dbus_dialog, "handle-refresh-dialog",
+                    G_CALLBACK (on_refresh_dialog), dbus_dialog);
+  g_signal_connect (dbus_dialog, "handle-cancel-ui-request",
+                    G_CALLBACK (on_cancel_ui_request), dbus_dialog);
+
+  if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (dbus_dialog),
+                                         connection,
+                                         "/Dialog",
+                                         NULL)) {
+    g_warning ("Failed to export interface");
+
+    return FALSE;
+  }
+
+  g_signal_connect (connection, "closed", G_CALLBACK(_on_connection_closed), dbus_dialog);
+
+  return TRUE;
+}
+
+static gboolean
+on_get_bus_address (SSODbusUI     *ui,
+                    GDBusMethodInvocation *invocation,
+                    gpointer       user_data)
+{
+  if (bus_server) {
+    g_debug ("Returning Server address : %s", g_dbus_server_get_client_address (bus_server));
+    sso_dbus_ui_complete_get_bus_address (ui, invocation, 
+            g_dbus_server_get_client_address (bus_server));
+  } else {
+    // FIXME: define dbus errors
+    //   g_dbus_method_invocation_take_error (invocation,
+    //       g_error_new ());
+  }
+
+  return TRUE;
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+                  const gchar     *name,
+                  gpointer         user_data)
+{
+  g_debug ("D-Bus name acquired");
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+              const gchar     *name,
+              gpointer         user_data)
+{
+  g_debug ("D-Bus name lost");
+
+  if (bus_server) {
+    g_object_unref (bus_server);
+    bus_server = NULL;
+  }
+#ifdef ENABLE_TIMEOUT
+  if (exit_timer_id) ecore_timer_del (exit_timer_id);
+  exit_timer_id = 0;
+#endif
+  elm_exit ();
+}
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+                 const gchar     *name,
+                 gpointer         user_data)
+{
+  gchar *address = NULL;
+  gchar *guid = NULL;
+  GError *error = NULL;
+  SSODbusUI *ui = NULL;
+  gchar *base_path = NULL;
+
+  g_debug ("D-Bus bus acquired");
+  
+  base_path = g_strdup_printf("%s/gsignond/", g_get_user_runtime_dir());
+  socket_file_path = tempnam (base_path, "ui-");
+  if (g_file_test(socket_file_path, G_FILE_TEST_EXISTS)) {
+    g_unlink (socket_file_path);
+  }
+  else {
+    if (g_mkdir_with_parents (base_path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
+      g_warning ("Could not create '%s', error: %s", base_path, strerror(errno));
+    }
+  }
+  g_free (base_path);
+
+  address = g_strdup_printf ("unix:path=%s", socket_file_path);
+
+  guid = g_dbus_generate_guid ();
+  bus_server = g_dbus_server_new_sync (address, G_DBUS_SERVER_FLAGS_NONE, guid, NULL, NULL, &error);
+  g_free (guid);
+  g_free (address);
+
+  if (!bus_server) {
+    g_warning ("Could not start dbus server at address '%s' : %s", address, error->message);
+    g_error_free (error);
+
+    g_free (socket_file_path);
+    socket_file_path = NULL;
+
+    elm_exit();
+
+    return ;
+  }
+
+  g_chmod (socket_file_path, S_IRUSR | S_IWUSR);
+
+  g_signal_connect (bus_server, "new-connection", G_CALLBACK (on_client_connection), NULL);
+
+  /* expose interface */
+
+  ui = sso_dbus_ui_skeleton_new ();
+
+  g_signal_connect (ui, "handle-get-bus-address",
+                    G_CALLBACK (on_get_bus_address), NULL);
+
+  if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (ui),
+                                         connection,
+                                         "/",
+                                         &error)) {
+    g_warning ("Failed to export interface: %s", error->message);
+    g_error_free (error);
+
+    elm_exit();
+
+    return ;
+  }
+
+  g_dbus_server_start (bus_server);
+
+  g_debug ("UI Dialog server started at : %s", g_dbus_server_get_client_address (bus_server));
+#ifdef ENABLE_TIMEOUT
+  if (exit_timer_id) ecore_timer_thaw (exit_timer_id);
+#endif
+}
+
+static void 
+_close_server ()
+{
+  if (bus_server) {
+    g_dbus_server_stop (bus_server);
+    g_object_unref (bus_server);
+    bus_server = NULL;
+  }
+
+  if (socket_file_path) {
+    g_unlink (socket_file_path);
+    g_free (socket_file_path);
+    socket_file_path = NULL;
+  }
+}
+
+static Eina_Bool
+_handle_unix_signal (void *data, int type, void *event)
+{
+  (void)data;
+  (void)event;
+
+  g_debug ("Received signal : %d", type);
+
+  elm_exit();
+  return TRUE;
+}
+
+EAPI_MAIN int
+elm_main (int argc, char **argv)
+{
+  guint owner_id = 0;
+  Ecore_Event_Handler *hup_signal_handler = 0;
+  Ecore_Event_Handler *exit_signal_handler = 0;
+  Eina_Bool keep_running, help;
+  static const Ecore_Getopt optdesc = {
+      "gSSO UI daemon",
+      NULL,
+      "0.0",
+      "(C) 2013 Intel Corporation",
+      NULL,
+      "ui dialog service for gsingle signon daemon",
+      0,
+      {
+          ECORE_GETOPT_STORE_TRUE('k', "keep-running", "Do not timeout the daemon"),
+          ECORE_GETOPT_HELP('h', "help"),
+          ECORE_GETOPT_SENTINEL
+      }
+  };
+  Ecore_Getopt_Value values[] = {
+      ECORE_GETOPT_VALUE_BOOL(keep_running),
+      ECORE_GETOPT_VALUE_BOOL(help),
+      ECORE_GETOPT_VALUE_NONE
+  };
+
+#if !GLIB_CHECK_VERSION (2, 36, 0)
+  g_type_init ();
+#endif
+
+  if (ecore_getopt_parse (&optdesc, values, argc, argv) < 0) {
+      fprintf (stderr, "Argument parsing failed\n");
+      return 1;
+  }
+
+  if (help) {
+      return 0;
+  }
+
+#ifdef ENABLE_TIMEOUT
+  if (!keep_running) {
+    const gchar *env_timeout = g_getenv("GSSO_UI_TIMEOUT");
+    if (env_timeout) timeout = atoi (env_timeout);
+    if (!timeout) timeout = DAEMON_TIMEOUT;
+    exit_timer_id = ecore_timer_add (timeout, exit_sso_ui, NULL);
+    /* postpone the timer till DBus setup ready */
+    if (exit_timer_id) 
+        ecore_timer_freeze (exit_timer_id);
+    else {
+        fprintf (stderr, "Could not create Ecore Timer, Ignoring daemon timeout");
+    }
+  }
+#endif
+
+  dialogs = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                   NULL, g_object_unref);
+  owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                             SSO_UI_NAME,
+                             G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE,
+                             on_bus_acquired,
+                             on_name_acquired,
+                             on_name_lost,
+                             NULL,
+                             NULL);
+
+  /* Use the ecore main loop because we intend to use Elm */
+  ecore_main_loop_glib_integrate();
+
+  /* install unix signal handler for clean shutdown */
+  hup_signal_handler = ecore_event_handler_add (ECORE_EVENT_SIGNAL_HUP, _handle_unix_signal, NULL);
+  exit_signal_handler = ecore_event_handler_add (ECORE_EVENT_SIGNAL_EXIT, _handle_unix_signal, NULL);
+
+  elm_run ();
+
+  ecore_event_handler_del (hup_signal_handler);
+  ecore_event_handler_del (exit_signal_handler);
+
+  g_bus_unown_name (owner_id);
+  _close_server ();
+  g_hash_table_unref (dialogs);
+
+  elm_shutdown ();
+  g_debug ("Clean shut down");
+
+  return 0;
+}
+ELM_MAIN()
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644 (file)
index 0000000..c8328b6
--- /dev/null
@@ -0,0 +1,3 @@
+
+TESTS = run-unit-tests
+EXTRA_DIST = $(TESTS)
diff --git a/tests/README.tests b/tests/README.tests
new file mode 100644 (file)
index 0000000..8950cf2
--- /dev/null
@@ -0,0 +1,4 @@
+All tests use the D-Bus api so one of two options needs to be used:
+1. sso-ui binary must be running before tests are run, or
+2. the binary and service file must be installed in a location where
+   the D-Bus service activation will find them
diff --git a/tests/run-unit-tests b/tests/run-unit-tests
new file mode 100755 (executable)
index 0000000..9198acf
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+import dbus, os, unittest, sys;
+import traceback;
+
+bad_params_dict    = dbus.Dictionary({'QueryErrorCode': dbus.UInt32(3)}, signature='sv')
+canceled_dict      = dbus.Dictionary({'QueryErrorCode': dbus.UInt32(4)}, signature='sv')
+not_available_dict = dbus.Dictionary({'QueryErrorCode': dbus.UInt32(5)}, signature='sv')
+
+class TestSequenceFunctions(unittest.TestCase):
+    @classmethod
+    def setUpClass(cls):
+        bus = dbus.SessionBus()
+        try:
+            proxy = bus.get_object('com.google.code.AccountsSSO.gSingleSignOn.UI',
+                                   '/')
+            sso = dbus.Interface(proxy, dbus_interface='com.google.code.AccountsSSO.gSingleSignOn.UI')
+
+            address = sso.getBusAddress();
+
+            print 'server address:' , "'" , str(address) , "'" ;
+            bus_a = dbus.bus.Connection(str(address));
+
+            proxy = bus_a.get_object (object_path='/Dialog');
+
+            cls.sso = dbus.Interface(proxy, dbus_interface='com.google.code.AccountsSSO.gSingleSignOn.UI.Dialog');
+        except :
+            print 'EXCEPTION: ' , sys.exc_info(), traceback.print_exc()
+            raise unittest.SkipTest('could not get a D-Bus proxy for SignonUI')
+
+    def test_no_request_id(self):
+        params = dbus.Dictionary({'QueryPassword':True}, signature='sv')
+        self.assertEqual(self.sso.queryDialog(params), bad_params_dict)
+
+    def test_no_query(self):
+        params = dbus.Dictionary({'RequestId':'test_id'}, signature='sv')
+        self.assertEqual(self.sso.queryDialog(params), bad_params_dict)
+
+    def test_open_url_with_other_query(self):
+        params = dbus.Dictionary({'RequestId':'test_id',
+                                  'QueryPassword':True,
+                                  'OpenUrl':'http://first.invalid/',
+                                  'FinalUrl':'http://second.invalid/'}, signature='sv')
+        self.assertEqual(self.sso.queryDialog(params), bad_params_dict)
+
+    def test_query_password(self):
+        params = dbus.Dictionary({'RequestId':'test_id',
+                                  'QueryPassword':True,
+                                  'TestReplyValues':'Secret:12345'}, signature='sv')
+        expected = dbus.Dictionary({'QueryErrorCode': dbus.UInt32(0),
+                                    'Secret': '12345'}, signature='sv')
+        self.assertEqual(self.sso.queryDialog(params), expected)
+
+    def test_query_remember_password(self):
+        params = dbus.Dictionary({'RequestId':'test_id',
+                                  'QueryPassword':True,
+                                  'RememberPassword': False,
+                                  'TestReplyValues':'Secret:12345,RememberPassword:True'}, signature='sv')
+        expected = dbus.Dictionary({'QueryErrorCode': dbus.UInt32(0),
+                                    'Secret': '12345',
+                                    'RememberPassword': True}, signature='sv')
+        self.assertEqual(self.sso.queryDialog(params), expected)
+
+    def test_query_username_and_password(self):
+        params = dbus.Dictionary({'RequestId':'test_id',
+                                  'QueryPassword':True,
+                                  'QueryUserName':True,
+                                  'TestReplyValues':'Secret:12345,UserName:uname'}, signature='sv')
+        expected = dbus.Dictionary({'QueryErrorCode': dbus.UInt32(0),
+                                    'UserName': 'uname',
+                                    'Secret': '12345'}, signature='sv')
+        self.assertEqual(self.sso.queryDialog(params), expected)
+
+    def test_query_password_and_confirm (self):
+        params = dbus.Dictionary({'RequestId':'test_id',
+                                  'QueryPassword':True,
+                                  'Confirm':True,
+                                  'Secret':'12345',
+                                  'TestReplyValues':'Secret:12345,SecretConfirm:67890'}, signature='sv')
+        expected = dbus.Dictionary({'QueryErrorCode': dbus.UInt32(0),
+                                    'SecretConfirm': '67890',
+                                    'Secret': '12345'}, signature='sv')
+        self.assertEqual(self.sso.queryDialog(params), expected)
+
+    def test_query_captcha(self):
+        params = dbus.Dictionary({'RequestId':'test_id',
+                                  'CaptchaUrl':'file:///usr/share/locale/l10n/us/flag.png',
+                                  'TestReplyValues':'CaptchaResponse:qwerty'}, signature='sv')
+        expected = dbus.Dictionary({'QueryErrorCode': dbus.UInt32(0),
+                                    'CaptchaResponse': 'qwerty'}, signature='sv')
+        self.assertEqual(self.sso.queryDialog(params), expected)
+
+    def test_query_oauth(self):
+        # ugly, this test actually opens the dialog for a moment
+        params = dbus.Dictionary({'RequestId':'test_id',
+                                  'OpenUrl':'file:///?param=val&param2=val2',
+                                  'FinalUrl':'file:///'}, signature='sv')
+        expected = dbus.Dictionary({'QueryErrorCode': dbus.UInt32(0),
+                                    'UrlResponse': 'file:///?param=val&param2=val2'}, signature='sv')
+        retval = self.sso.queryDialog(params)
+        # Elementary might not be compiled with Web, have to accept "not available"
+        self.assertTrue(retval == expected or retval == not_available_dict)
+
+    def test_cancel(self):
+        params = dbus.Dictionary({'RequestId':'test_id',
+                                  'QueryPassword':True,
+                                  'TestReplyValues':'QueryErrorCode:4'}, signature='sv')
+        self.assertEqual(self.sso.queryDialog(params), canceled_dict)
+
+if __name__ == '__main__':
+    unittest.main();
+
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644 (file)
index 0000000..3fe5b6f
--- /dev/null
@@ -0,0 +1,6 @@
+
+noinst_SCRIPTS = query-dialog \
+                 refresh-dialog \
+                 cancel-ui-request
+EXTRA_DIST = $(noinst_SCRIPTS)
+
diff --git a/tools/cancel-ui-request b/tools/cancel-ui-request
new file mode 100755 (executable)
index 0000000..e70f027
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+
+import sys, dbus;
+from pprint import pprint;
+
+bus = dbus.SessionBus()
+proxy = bus.get_object('org.tizen.SSO',
+                       '/org/tizen/SSO/SignonUi')
+sso = dbus.Interface(proxy, dbus_interface='org.tizen.SSO.singlesignonui')
+
+params = dbus.Dictionary({}, signature='sv')
+
+# do some guesswork on the params ...
+
+if (len(sys.argv) < 2):
+  print "Usage: ./cancel-ui-request <request_id>"
+  exit()
+
+sso.cancelUiRequest(sys.argv[1])
diff --git a/tools/query-dialog b/tools/query-dialog
new file mode 100755 (executable)
index 0000000..78a1af6
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+
+'''
+# Examples:
+
+# password query
+./query-dialog QueryPassword True \
+               RequestId "12345" \
+               Caption "Please insert password" \
+               UserName "uname" \
+               Title "Hello"
+
+# password confirm query
+./query-dialog QueryPassword True \
+               RequestId "12345" \
+               Caption "Enter current password and new password twice" \
+               UserName "uname" \
+               Confirm True \
+               Title "Hello"
+
+# captcha query
+./query-dialog CaptchaUrl "file:///usr/share/locale/l10n/us/flag.png" \
+               RequestId "67890" \
+               Caption "Please solve the captcha" \
+               Title "Hello"
+
+# weblogin query
+./query-dialog OpenUrl "http://google.fi/" \
+               FinalUrl "http://xkcd.com/" \
+               RequestId "abcde" \
+               Title "Hello"
+'''
+
+import sys, dbus;
+from pprint import pprint;
+
+def db2p(db):
+    if type(db)==dbus.Dictionary:
+        return dict((db2p(key), db2p(value)) for key, value in db.items())
+    if type(db)==dbus.String:
+        return db+''
+    if type(db)==dbus.Int32:
+        return db+0
+    if type(db)==dbus.Boolean:
+        return db==True
+    return ('type: %s' % type(db), db)
+
+
+bus = dbus.SessionBus()
+proxy = bus.get_object('org.tizen.SSO',
+                       '/org/tizen/SSO/SignonUi')
+sso = dbus.Interface(proxy, dbus_interface='org.tizen.SSO.singlesignonui')
+
+params = dbus.Dictionary({}, signature='sv')
+
+# do some guesswork on the params ...
+args = sys.argv[1:]
+while args:
+    if (args[1].lower() == "true"):
+      val = dbus.Boolean (True)
+    elif (args[1].lower() == "false"):
+      val = dbus.Boolean (False)
+    else:
+      val = dbus.String (args[1])
+    params[args[0]] = val
+    args = args[2:]
+
+pprint(db2p(sso.queryDialog(params, timeout=60*10)))
diff --git a/tools/refresh-dialog b/tools/refresh-dialog
new file mode 100755 (executable)
index 0000000..77207e1
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+
+import sys, dbus;
+from pprint import pprint;
+
+bus = dbus.SessionBus()
+proxy = bus.get_object('org.tizen.SSO',
+                       '/org/tizen/SSO/SignonUi')
+sso = dbus.Interface(proxy, dbus_interface='org.tizen.SSO.singlesignonui')
+
+params = dbus.Dictionary({}, signature='sv')
+
+# do some guesswork on the params ...
+args = sys.argv[1:]
+while args:
+    if (args[1].lower() == "true"):
+      val = dbus.Boolean (True)
+    elif (args[1].lower() == "false"):
+      val = dbus.Boolean (False)
+    else:
+      val = dbus.String (args[1])
+    params[args[0]] = val
+    args = args[2:]
+
+sso.refreshDialog(params)