libaccounts-glib-1.15+14.04.20131126.2/0000755000015000001560000000000012245171012017344 5ustar pbuserpbgroup00000000000000libaccounts-glib-1.15+14.04.20131126.2/accounts.conf.in0000644000015000001560000000115312245170671022451 0ustar pbuserpbgroup00000000000000 nokia Accounts backup-scripts backup-scripts /usr/share/accounts/accounts-backup /usr/share/accounts/accounts-restore $HOME/@DATABASE_DIR@/accounts.db.bak libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib.pc.in0000644000015000001560000000105312245170671023527 0ustar pbuserpbgroup00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ applicationfilesdir=${prefix}/share/@APPLICATION_FILES_DIR@ servicefilesdir=${prefix}/share/@SERVICE_FILES_DIR@ servicetypefilesdir=${prefix}/share/@SERVICE_TYPE_FILES_DIR@ providerfilesdir=${prefix}/share/@PROVIDER_FILES_DIR@ Name: libaccounts-glib Description: A low-level library for managing accounts settings. Requires: glib-2.0 gobject-2.0 gio-unix-2.0 Require.private: libxml-2.0 sqlite3 Version: @VERSION@ Libs: -L${libdir} -laccounts-glib Cflags: -I${includedir} libaccounts-glib-1.15+14.04.20131126.2/.gitignore0000644000015000001560000000115712245170671021352 0ustar pbuserpbgroup00000000000000.* Makefile Makefile.in accounts.conf aclocal.m4 autom4te.cache /build-aux /configure /config.* /coverage.info /coveragereport debian/ gtk-doc.make /INSTALL libtool m4/gtk-doc.m4 m4/libtool.m4 m4/lt*.m4 patches stamp-h1 *~ *.core *.gcda *.gcno *.gir *.la *.lo *.o *.pc *.stamp *.typelib *.tar.* /docs/reference/ag-backup.1 /docs/reference/ag-tool.1 /docs/reference/html/ /docs/reference/libaccounts-glib*txt /docs/reference/libaccounts-glib.* !/docs/reference/libaccounts-glib-sections.txt /docs/reference/tmpl/ /docs/reference/version.xml /docs/reference/xml/ /libaccounts-glib/ag-marshal.c /libaccounts-glib/ag-marshal.h libaccounts-glib-1.15+14.04.20131126.2/m4/0000755000015000001560000000000012245171012017664 5ustar pbuserpbgroup00000000000000libaccounts-glib-1.15+14.04.20131126.2/m4/gtkdoc_jh_check_xml_catalog.m40000644000015000001560000000113512245170671025603 0ustar pbuserpbgroup00000000000000dnl Checks if a particular URI appears in the XML catalog dnl Usage: dnl JH_CHECK_XML_CATALOG(URI, [FRIENDLY-NAME], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) AC_DEFUN([JH_CHECK_XML_CATALOG], [ AC_REQUIRE([JH_PATH_XML_CATALOG],[JH_PATH_XML_CATALOG(,[:])])dnl AC_MSG_CHECKING([for ifelse([$2],,[$1],[$2]) in XML catalog]) if $jh_found_xmlcatalog && \ AC_RUN_LOG([$XMLCATALOG --noout "$XML_CATALOG_FILE" "$1" >&2]); then AC_MSG_RESULT([found]) ifelse([$3],,,[$3]) else AC_MSG_RESULT([not found]) ifelse([$4],,[AC_MSG_ERROR([could not find ifelse([$2],,[$1],[$2]) in XML catalog])],[$4]) fi ]) libaccounts-glib-1.15+14.04.20131126.2/m4/introspection.m40000644000015000001560000000661412245170671023047 0ustar pbuserpbgroup00000000000000dnl -*- mode: autoconf -*- dnl Copyright 2009 Johan Dahlin dnl dnl This file is free software; the author(s) gives unlimited dnl permission to copy and/or distribute it, with or without dnl modifications, as long as this notice is preserved. dnl # serial 1 m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], [ AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first AC_BEFORE([LT_INIT],[$0])dnl setup libtool first dnl enable/disable introspection m4_if([$2], [require], [dnl enable_introspection=yes ],[dnl AC_ARG_ENABLE(introspection, AS_HELP_STRING([--enable-introspection[=@<:@no/auto/yes@:>@]], [Enable introspection for this build]),, [enable_introspection=auto]) ])dnl AC_MSG_CHECKING([for gobject-introspection]) dnl presence/version checking AS_CASE([$enable_introspection], [no], [dnl found_introspection="no (disabled, use --enable-introspection to enable)" ],dnl [yes],[dnl PKG_CHECK_EXISTS([gobject-introspection-1.0],, AC_MSG_ERROR([gobject-introspection-1.0 is not installed])) PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME])) ],dnl [auto],[dnl PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no) ],dnl [dnl AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/yes@:>@]) ])dnl AC_MSG_RESULT([$found_introspection]) INTROSPECTION_SCANNER= INTROSPECTION_COMPILER= INTROSPECTION_GENERATE= INTROSPECTION_GIRDIR= INTROSPECTION_TYPELIBDIR= if test "x$found_introspection" = "xyes"; then INTROSPECTION_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` INTROSPECTION_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` INTROSPECTION_GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0` INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)" INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` INTROSPECTION_MAKEFILE=`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection fi AC_SUBST(INTROSPECTION_SCANNER) AC_SUBST(INTROSPECTION_COMPILER) AC_SUBST(INTROSPECTION_GENERATE) AC_SUBST(INTROSPECTION_GIRDIR) AC_SUBST(INTROSPECTION_TYPELIBDIR) AC_SUBST(INTROSPECTION_CFLAGS) AC_SUBST(INTROSPECTION_LIBS) AC_SUBST(INTROSPECTION_MAKEFILE) AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes") ]) dnl Usage: dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version]) AC_DEFUN([GOBJECT_INTROSPECTION_CHECK], [ _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1]) ]) dnl Usage: dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version]) AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE], [ _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require]) ]) libaccounts-glib-1.15+14.04.20131126.2/m4/gtkdoc_jh_path_xml_catalog.m40000644000015000001560000000171412245170671025465 0ustar pbuserpbgroup00000000000000dnl Checks the location of the XML Catalog dnl Usage: dnl JH_PATH_XML_CATALOG([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl Defines XMLCATALOG and XML_CATALOG_FILE substitutions AC_DEFUN([JH_PATH_XML_CATALOG], [ dnl check for the presence of the XML catalog AC_ARG_WITH([xml-catalog], AS_HELP_STRING([--with-xml-catalog=CATALOG], [path to xml catalog to use]),, [with_xml_catalog=/etc/xml/catalog]) jh_found_xmlcatalog=true XML_CATALOG_FILE="$with_xml_catalog" AC_SUBST([XML_CATALOG_FILE]) AC_MSG_CHECKING([for XML catalog ($XML_CATALOG_FILE)]) if test -f "$XML_CATALOG_FILE"; then AC_MSG_RESULT([found]) else jh_found_xmlcatalog=false AC_MSG_RESULT([not found]) fi dnl check for the xmlcatalog program AC_PATH_PROG(XMLCATALOG, xmlcatalog, no) if test "x$XMLCATALOG" = xno; then jh_found_xmlcatalog=false fi if $jh_found_xmlcatalog; then ifelse([$1],,[:],[$1]) else ifelse([$2],,[AC_MSG_ERROR([could not find XML catalog])],[$2]) fi ]) libaccounts-glib-1.15+14.04.20131126.2/m4/gcov.m40000644000015000001560000000571612245170671021107 0ustar pbuserpbgroup00000000000000# Copyright 2012 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License version 3, as published # by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR # PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # Checks for existence of coverage tools: # * gcov # * lcov # * genhtml # * gcovr # # Sets ac_cv_check_gcov to yes if tooling is present # and reports the executables to the variables LCOV, GCOVR and GENHTML. AC_DEFUN([AC_TDD_GCOV], [ AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov], [enable coverage testing with gcov]), [use_gcov=yes], [use_gcov=no]) AM_CONDITIONAL(HAVE_GCOV, test "x$use_gcov" = "xyes") if test "x$use_gcov" = "xyes"; then # we need gcc: if test "$GCC" != "yes"; then AC_MSG_ERROR([GCC is required for --enable-gcov]) fi # Check if ccache is being used AC_CHECK_PROG(SHTOOL, shtool, shtool) if test "$SHTOOL"; then AS_CASE([`$SHTOOL path $CC`], [*ccache*], [gcc_ccache=yes], [gcc_ccache=no]) fi if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.]) fi lcov_version_list="1.6 1.7 1.8 1.9" AC_CHECK_PROG(LCOV, lcov, lcov) AC_CHECK_PROG(GENHTML, genhtml, genhtml) if test "$LCOV"; then AC_CACHE_CHECK([for lcov version], glib_cv_lcov_version, [ glib_cv_lcov_version=invalid lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'` for lcov_check_version in $lcov_version_list; do if test "$lcov_version" = "$lcov_check_version"; then glib_cv_lcov_version="$lcov_check_version (ok)" fi done ]) else lcov_msg="To enable code coverage reporting you must have one of the following lcov versions installed: $lcov_version_list" AC_MSG_ERROR([$lcov_msg]) fi case $glib_cv_lcov_version in ""|invalid[)] lcov_msg="You must have one of the following versions of lcov: $lcov_version_list (found: $lcov_version)." AC_MSG_ERROR([$lcov_msg]) LCOV="exit 0;" ;; esac if test -z "$GENHTML"; then AC_MSG_ERROR([Could not find genhtml from the lcov package]) fi # Remove all optimization flags from CFLAGS changequote({,}) CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'` changequote([,]) # Add the special gcc flags COVERAGE_CFLAGS="--coverage -DG_DISABLE_ASSERTS -DG_DISABLE_CHECKS" COVERAGE_CXXFLAGS="--coverage" COVERAGE_LDFLAGS="-lgcov" fi ]) # AC_TDD_GCOV libaccounts-glib-1.15+14.04.20131126.2/README0000644000015000001560000000105112245170671020233 0ustar pbuserpbgroup00000000000000Accounts management library for GLib applications ------------------------------------------------- This project is a library for managing accounts which can be used from GLib applications. It is part of the accounts-sso project: http://code.google.com/p/accounts-sso/ Dependencies ------------ The project depends on GLib (including GIO and GObject), libxml2, sqlite3 and check. Licence ------- The library is licensed under the GNU LGPL version 2.1. Resources --------- http://code.google.com/p/accounts-sso/sources/list?repo=libaccounts-glib libaccounts-glib-1.15+14.04.20131126.2/tools/0000755000015000001560000000000012245171012020504 5ustar pbuserpbgroup00000000000000libaccounts-glib-1.15+14.04.20131126.2/tools/.gitignore0000644000015000001560000000002212245170671022500 0ustar pbuserpbgroup00000000000000ag-backup ag-tool libaccounts-glib-1.15+14.04.20131126.2/tools/backup.c0000644000015000001560000000714312245170671022134 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2011 Nokia Corporation. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ #include #include #include #include #include #include #include static void show_help () { printf ("\nUsage:\n" " %1$s\n" "Backups the accounts from ~/.config/libaccounts-glib/accounts.db\n" "into ~/.config/libaccounts-glib/accounts.db.bak\n\n", g_get_prgname()); } static gboolean write_backup (sqlite3 *src, const gchar *filename) { sqlite3_backup *backup; sqlite3 *dest; gint n_retries; int ret; ret = sqlite3_open (filename, &dest); if (ret != SQLITE_OK) return FALSE; backup = sqlite3_backup_init (dest, "main", src, "main"); if (!backup) { g_warning ("Couldn't start backup"); sqlite3_close (dest); return FALSE; } n_retries = 0; do { ret = sqlite3_backup_step (backup, -1); if (ret == SQLITE_BUSY || ret == SQLITE_LOCKED) sqlite3_sleep(250); n_retries++; } while ((ret == SQLITE_BUSY || ret == SQLITE_LOCKED) && n_retries < 5); sqlite3_backup_finish (backup); sqlite3_close (dest); return ret == SQLITE_OK; } static gboolean backup () { gchar *filename, *filename_bak; sqlite3 *db; gint n_retries; int ret; gboolean success = FALSE;; filename = g_build_filename (g_get_user_config_dir (), DATABASE_DIR, "accounts.db", NULL); filename_bak = g_strdup_printf ("%s.bak", filename); g_debug ("Opening %s", filename); n_retries = 0; do { ret = sqlite3_open (filename, &db); if (ret == SQLITE_BUSY) sched_yield (); n_retries++; } while (ret == SQLITE_BUSY && n_retries < 5); if (G_UNLIKELY (ret != SQLITE_OK)) { g_warning ("Couldn't open accounts DB: %s", sqlite3_errmsg (db)); goto error_open; } n_retries = 0; do { ret = sqlite3_wal_checkpoint (db, NULL); if (ret == SQLITE_BUSY) sched_yield (); n_retries++; } while (ret == SQLITE_BUSY && n_retries < 5); if (G_UNLIKELY (ret != SQLITE_OK)) g_warning ("Checkpoint failed: %s", sqlite3_errmsg (db)); success = write_backup (db, filename_bak); sqlite3_close (db); success = TRUE; error_open: g_free (filename_bak); g_free (filename); return success; } int main (int argc, char **argv) { gboolean success; g_set_prgname (g_path_get_basename (argv[0])); if (argc > 1) { show_help (); return 0; } success = backup (); return success ? EXIT_SUCCESS : EXIT_FAILURE; } libaccounts-glib-1.15+14.04.20131126.2/tools/main.c0000644000015000001560000007553612245170671021626 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ #define AG_DISABLE_DEPRECATION_WARNINGS #include "libaccounts-glib/ag-account.h" #include "libaccounts-glib/ag-manager.h" #include "libaccounts-glib/ag-provider.h" #include "libaccounts-glib/ag-service.h" #include #include #include #if GLIB_CHECK_VERSION (2, 30, 0) #else #define G_VALUE_INIT { 0, { { 0 } } } #endif static gchar *gl_app_name = NULL; enum { ERROR_GENERIC, INVALID_ACC_ID, INVALID_SERVICE_NAME, INVALID_INPUT }; static void show_error (gint err) { switch (err) { case ERROR_GENERIC: printf ("\nUnable to process the request\n\n"); break; case INVALID_ACC_ID: printf ("\nAccount does not exist. Check account ID entered\n\n"); break; case INVALID_SERVICE_NAME: printf ("\nService does not exist. Enter valid service name\n\n"); break; case INVALID_INPUT: printf ("\nRequest is not processed. Check the command parameters\n\n"); break; default: printf ("\nUnknown problem in processing the request\n\n"); break; } } static void show_help () { printf ("\nOptions:\n" " * Creates an account\n" " %1$s create-account [] [] \n\n" " * Updates/Adds key to account and sets a value to key\n" " %1$s update-account (int|uint|bool|string):= \n\n" " * Updates/Adds key to service of an account and sets a value to the key\n" " %1$s update-service \n" " (int|uint|bool|string):= \n\n" " * Enables an account\n" " %1$s enable-account \n\n" " * Enables service of the account\n" " %1$s enable-service \n\n" " * Disables an account\n" " %1$s disable-account \n\n" " * Disables service of an account\n" " %1$s disable-service \n\n" " * Gets the value of a key of an account\n" " %1$s get-account <(int|uint|bool|string):key>\n\n" " * Gets the value of a key of a service\n" " %1$s get-service \n\t\t <(int|uint|bool|string):=\n\n" " * Deletes all accounts is keyword is used or deletes specified account\n" " %1$s delete-account /\n\n" " * Lists all providers\n" " %1$s list-providers\n\n" " * Lists all services or services that can be associated with an account\n" " %1$s list-services []\n\n" " * Lists all accounts\n" " %1$s list-accounts\n\n" " * List all enabled accounts\n" " If account ID is specified lists services enabled on the given account\n" " %1$s list-enabled []\n\n" " * Lists settings associated with account\n" " %1$s list-settings \n", gl_app_name); printf ("\nParameters in square braces '[param]' are optional\n"); } static void show_help_text (gchar *command) { /* TODO: Show individal command help text if needed */ show_help (); } static gchar * get_string_value (const GValue *value) { gchar *str = NULL; if (G_VALUE_HOLDS_STRING (value)) { str = g_value_dup_string (value); } else if (G_VALUE_HOLDS_UINT (value)) { str = g_strdup_printf ("%u", g_value_get_uint (value)); } else if (G_VALUE_HOLDS_INT (value)) { str = g_strdup_printf ("%i", g_value_get_int (value)); } else if (G_VALUE_HOLDS_BOOLEAN (value)) { str = g_strdup (g_value_get_boolean (value) ? "true" : "false"); } else { str = g_strdup_value_contents (value); } return str; } static void get_account (gchar **argv) { AgManager *manager = NULL; AgAccount *account = NULL; GValue value = G_VALUE_INIT; GType type = 0; gchar *str = NULL; gchar **param = NULL; if (argv[2] == NULL || argv[3] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); return; } /* param[0] = type, param[1] = key. Both separated by ':' */ param = g_strsplit (argv[3], ":", 2); if (param[0] == NULL || param[1] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); return; } if (strcmp (param[0], "int") == 0) { g_value_init (&value, G_TYPE_INT); type = G_TYPE_INT; } else if (strcmp (param[0], "uint") == 0) { g_value_init (&value, G_TYPE_UINT); type = G_TYPE_UINT; } else if (strcmp (param[0], "bool") == 0 || strcmp (param[0], "boolean") == 0) { g_value_init (&value, G_TYPE_BOOLEAN); type = G_TYPE_BOOLEAN; } else if (strcmp (param[0], "string") == 0) { g_value_init (&value, G_TYPE_STRING); type = G_TYPE_STRING; } else { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); g_strfreev (param); return; } account = ag_manager_get_account (manager, atoi (argv[2])); if (account == NULL) { show_error (INVALID_ACC_ID); g_strfreev (param); g_object_unref (manager); return; } if (ag_account_get_value (account, param[1], &value) == AG_SETTING_SOURCE_NONE) { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); g_object_unref (account); g_object_unref (manager); return; } switch (type) { case G_TYPE_INT: str = g_strdup_printf ("%i", g_value_get_int (&value)); break; case G_TYPE_UINT: str = g_strdup_printf ("%u", g_value_get_uint (&value)); break; case G_TYPE_BOOLEAN: str = g_strdup_printf ("%i", g_value_get_boolean (&value)); break; case G_TYPE_STRING: str = g_value_dup_string (&value); break; default: break; } if (G_IS_VALUE (&value)) g_value_unset (&value); g_object_unref (account); g_object_unref (manager); printf ("%s = %s\n", param[1], str); g_strfreev (param); g_free(str); } static void list_service_settings (AgAccount *account) { GList *list = NULL; GList *tmp = NULL; AgAccountSettingIter iter; const gchar *key = NULL; const GValue *val = NULL; gchar *str = NULL; list = ag_account_list_services (account); if (list == NULL || g_list_length (list) == 0) { return; } for (tmp = list; tmp != NULL; tmp = g_list_next (tmp)) { printf ("\t\t%s\n", ag_service_get_name (tmp->data)); ag_account_select_service (account, (AgService *) tmp->data); ag_account_settings_iter_init (account, &iter, NULL); while (ag_account_settings_iter_next (&iter, &key, &val)) { str = get_string_value (val); printf ("%s = %s\n", key, str); g_free (str); str = NULL; } } ag_service_list_free (list); } static void list_settings (gchar **argv) { AgManager *manager = NULL; AgAccount *account = NULL; AgAccountSettingIter iter; const gchar *key = NULL; const GValue *val = NULL; gchar *str = NULL; if (argv[2] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } account = ag_manager_get_account (manager, atoi (argv[2])); if (account == NULL) { show_error (INVALID_ACC_ID); g_object_unref (manager); return; } ag_account_settings_iter_init (account, &iter, NULL); while (ag_account_settings_iter_next (&iter, &key, &val)) { str = get_string_value (val); printf ("%s = %s\n", key, str); g_free (str); str = NULL; } list_service_settings (account); g_object_unref (account); g_object_unref (manager); } static void get_service (gchar **argv) { AgManager *manager = NULL; AgService *service = NULL; AgAccount *account = NULL; GValue value = G_VALUE_INIT; GType type = 0; gchar *str = NULL; gchar **param = NULL; if (argv[2] == NULL || argv[3] == NULL || argv[4] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); return; } /* argv[4] = type:key */ param = g_strsplit (argv[4], ":", 2); if (param[0] == NULL || param[1] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); return; } if (strcmp (param[0], "int") == 0) { g_value_init (&value, G_TYPE_INT); type = G_TYPE_INT; } else if (strcmp (param[0], "uint") == 0) { g_value_init (&value, G_TYPE_UINT); type = G_TYPE_UINT; } else if (strcmp (param[0], "bool") == 0 || strcmp (param[0], "boolean") == 0) { g_value_init (&value, G_TYPE_BOOLEAN); type = G_TYPE_BOOLEAN; } else if (strcmp (param[0], "string") == 0) { g_value_init (&value, G_TYPE_STRING); type = G_TYPE_STRING; } else { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); g_strfreev (param); return; } account = ag_manager_get_account (manager, atoi (argv[2])); if (account == NULL) { show_error (INVALID_ACC_ID); g_strfreev (param); g_object_unref (manager); return; } service = ag_manager_get_service (manager, argv[3]); if (service == NULL) { show_error (INVALID_SERVICE_NAME); g_strfreev (param); g_object_unref (account); g_object_unref (manager); return; } ag_account_select_service (account, service); if (ag_account_get_value (account, param[1], &value) == AG_SETTING_SOURCE_NONE) { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); ag_service_unref (service); g_object_unref (account); g_object_unref (manager); return; } switch (type) { case G_TYPE_INT: str = g_strdup_printf ("%i", g_value_get_int (&value)); break; case G_TYPE_UINT: str = g_strdup_printf ("%u", g_value_get_uint (&value)); break; case G_TYPE_BOOLEAN: str = g_strdup_printf ("%i", g_value_get_boolean (&value)); break; case G_TYPE_STRING: str = g_value_dup_string (&value); break; default: break; } if (G_IS_VALUE (&value)) g_value_unset (&value); ag_service_unref (service); g_object_unref (account); g_object_unref (manager); printf ("%s = %s\n", param[1], str); g_strfreev (param); g_free (str); } static void update_service (gchar **argv) { AgManager *manager = NULL; AgAccount *account = NULL; GValue *gvalue = NULL; gchar **param = NULL; gchar **keytype = NULL; AgService *service = NULL; GError *error = NULL; if (argv[2] == NULL || argv[3] == NULL || argv[4] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); return; } param = g_strsplit (argv[4], "=", 2); if (param[0] == NULL || param[1] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); return; } keytype = g_strsplit (param[0], ":", 2); if (keytype[0] == NULL || keytype[1] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); g_strfreev (keytype); return; } gvalue = g_new0 (GValue, 1); if (strcmp (keytype[0], "int") == 0) { g_value_init (gvalue, G_TYPE_INT); g_value_set_int (gvalue, strtol (param[1], NULL, 10)); } else if (strcmp (keytype[0], "uint") == 0) { g_value_init (gvalue, G_TYPE_UINT); g_value_set_uint (gvalue, strtoul (param[1], NULL, 10)); } else if (strcmp (keytype[0], "bool") == 0 || strcmp (keytype[0], "boolean") == 0) { g_value_init (gvalue, G_TYPE_BOOLEAN); g_value_set_boolean (gvalue, atoi (param[1])); } else if (strcmp (keytype[0], "string") == 0) { g_value_init (gvalue, G_TYPE_STRING); g_value_set_string (gvalue, param[1]); } else { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); g_strfreev (keytype); g_value_unset (gvalue); g_free (gvalue); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); g_strfreev (param); g_strfreev (keytype); g_value_unset (gvalue); g_free (gvalue); return; } account = ag_manager_get_account (manager, atoi (argv[2])); if (account == NULL) { show_error (INVALID_ACC_ID); g_strfreev (param); g_strfreev (keytype); g_object_unref (manager); g_value_unset (gvalue); g_free (gvalue); return; } service = ag_manager_get_service (manager, argv[3]); if (service == NULL) { show_error (INVALID_SERVICE_NAME); g_strfreev (param); g_strfreev (keytype); g_object_unref (account); g_object_unref (manager); g_value_unset (gvalue); g_free (gvalue); return; } ag_account_select_service (account, service); ag_account_set_value (account, keytype[1], gvalue); ag_account_store_blocking (account, &error); if (error) { show_error (ERROR_GENERIC); g_error_free (error); } g_strfreev (param); g_strfreev (keytype); g_value_unset (gvalue); g_free (gvalue); ag_service_unref (service); g_object_unref (account); g_object_unref (manager); return; } static void update_account (gchar **argv) { AgManager *manager = NULL; AgAccount *account = NULL; GValue *gvalue = NULL; gchar **param = NULL; gchar **keytype = NULL; GError *error = NULL; /* Input parameter will be argv[2] = * argv[3] = */ if ((argv[2] == NULL) || (argv[3] == NULL)) { show_error (INVALID_INPUT); show_help_text (argv[1]); return; } /* param[0] = , param[1] = value */ param = g_strsplit (argv[3], "=", 2); if (param[0] == NULL || param[1] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); return; } /* keytype[0] = type, keytype[1] = key */ keytype = g_strsplit (param[0], ":", 2); if (keytype[0] == NULL || keytype[1] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); g_strfreev (keytype); return; } gvalue = g_new0 (GValue, 1); if (strcmp (keytype[0], "int") == 0) { g_value_init (gvalue, G_TYPE_INT); g_value_set_int (gvalue, strtol (param[1], NULL, 10)); } else if (strcmp (keytype[0], "uint") == 0) { g_value_init (gvalue, G_TYPE_UINT); g_value_set_uint (gvalue, strtoul (param[1], NULL, 10)); } else if (strcmp (keytype[0], "bool") == 0 || strcmp (keytype[0], "boolean") == 0) { g_value_init (gvalue, G_TYPE_BOOLEAN); g_value_set_boolean (gvalue, atoi (param[1])); } else if (strcmp (keytype[0], "string") == 0) { g_value_init (gvalue, G_TYPE_STRING); g_value_set_string (gvalue, param[1]); } else { show_error (INVALID_INPUT); show_help_text (argv[1]); g_strfreev (param); g_strfreev (keytype); g_free (gvalue); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); g_strfreev (param); g_strfreev (keytype); g_free (gvalue); return; } account = ag_manager_get_account (manager, atoi (argv[2])); if (account == NULL) { show_error (INVALID_ACC_ID); g_strfreev (param); g_strfreev (keytype); g_value_unset (gvalue); g_free (gvalue); g_object_unref (manager); return; } ag_account_set_value (account, keytype[1], gvalue); ag_account_store_blocking (account, &error); if (error) { show_error (ERROR_GENERIC); g_error_free (error); } g_strfreev (param); g_strfreev (keytype); g_value_unset (gvalue); g_free (gvalue); g_object_unref (account); g_object_unref (manager); } static void create_account (gchar **argv) { AgManager *manager = NULL; AgAccount *account = NULL; GError *error = NULL; if (argv[2] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } account = ag_manager_create_account (manager, argv[2]); if (account == NULL) { show_error (ERROR_GENERIC); g_object_unref (manager); return; } if (argv[3] != NULL) ag_account_set_display_name (account, argv[3]); if (argv[4] != NULL) { if (strcmp (argv[4], "enable") == 0) ag_account_set_enabled (account, TRUE); if (strcmp (argv[4], "disable") == 0) ag_account_set_enabled (account, FALSE); } ag_account_store_blocking (account, &error); if (error) { show_error (ERROR_GENERIC); g_error_free (error); } g_object_unref (account); g_object_unref (manager); } static void enable_disable_service (gchar **argv, gboolean enable) { AgManager *manager = NULL; AgService *service = NULL; AgAccount *account = NULL; GError *error = NULL; if ((argv[2] == NULL) || (argv[3] == NULL)) { show_error (INVALID_INPUT); show_help_text (argv[1]); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } account = ag_manager_get_account (manager, atoi (argv[2])); if (account == NULL) { show_error (INVALID_ACC_ID); g_object_unref (manager); return; } service = ag_manager_get_service (manager, argv[3]); if (service == NULL) { show_error (INVALID_SERVICE_NAME); g_object_unref (account); g_object_unref (manager); return; } ag_account_select_service (account, service); ag_account_set_enabled (account, enable); ag_account_store_blocking (account, &error); if (error) { show_error (ERROR_GENERIC); g_error_free (error); } ag_service_unref (service); g_object_unref (account); g_object_unref (manager); } static void delete_account (gchar **argv) { AgManager *manager = NULL; AgAccount *account = NULL; gint id = 0; GList *list = NULL; GList *iter = NULL; GError *error = NULL; if (argv[2] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } if (strcmp (argv[2], "all") == 0) list = ag_manager_list (manager); else list = g_list_prepend (list, GUINT_TO_POINTER (atoi (argv[2]))); for (iter = list; iter != NULL; iter = g_list_next (iter)) { id = GPOINTER_TO_UINT (iter->data); account = ag_manager_get_account (manager, id); if (account == NULL) { show_error (INVALID_ACC_ID); continue; } ag_account_delete (account); ag_account_store_blocking (account, &error); if (error) { show_error (ERROR_GENERIC); g_error_free (error); error = NULL; } g_object_unref (account); account = NULL; } g_object_unref (manager); ag_manager_list_free (list); } static void list_providers () { AgManager *manager = NULL; GList *list = NULL; GList *iter = NULL; const gchar *name = NULL; manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } list = ag_manager_list_providers (manager); if ((list == NULL) || (g_list_length (list) == 0)) { printf ("No providers are available\n"); return; } printf ("\nProvider Name\n-------------\n"); for (iter = list; iter != NULL; iter = g_list_next (iter)) { name = ag_provider_get_name ((AgProvider *) (iter->data)); printf ("%s\n", name); } ag_provider_list_free (list); g_object_unref (manager); } static void list_services (gchar **argv) { AgManager *manager = NULL; GList *list = NULL; GList *iter = NULL; const gchar *name = NULL; AgAccount *account = NULL; const gchar *type = NULL; manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } /* If account Id is not specified, list all services */ if (argv[2] == NULL) list = ag_manager_list_services (manager); else { account = ag_manager_get_account (manager, atoi (argv[2])); if (account == NULL) { show_error (INVALID_ACC_ID); g_object_unref (manager); return; } list = ag_account_list_services (account); } if (list == NULL || g_list_length (list) == 0) { printf ("No services available\n"); if (account) g_object_unref (account); g_object_unref (manager); return; } printf ("%-35s %s\n", "Service type", "Service name"); printf ("%-35s %s\n", "------------", "------------"); for (iter = list; iter != NULL; iter = g_list_next (iter)) { name = ag_service_get_name ((AgService *) (iter->data)); type = ag_service_get_service_type ((AgService *) (iter->data)); printf ("%-35s %s\n", type, name); } ag_service_list_free (list); if (account) g_object_unref (account); g_object_unref (manager); } static void list_accounts () { AgManager *manager = NULL; GList *list = NULL; GList *iter = NULL; const gchar *name = NULL; const gchar *provider = NULL; AgAccount *account = NULL; manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } list = ag_manager_list (manager); if (list == NULL || g_list_length (list) == 0) { printf ("\nNo accounts configured\n"); g_object_unref (manager); return; } printf ("%-10s %-30s %s\n", "ID", "Provider", "Name"); printf ("%-10s %-30s %s\n", "--", "--------", "----"); for (iter = list; iter != NULL; iter = g_list_next (iter)) { printf ("%-10d ", GPOINTER_TO_UINT (iter->data)); account = ag_manager_get_account (manager, GPOINTER_TO_UINT (iter->data)); if (account == NULL) { continue; } provider = ag_account_get_provider_name (account); if (provider != NULL) printf ("%-30s ", provider); else printf ("%-30s ", " "); name = ag_account_get_display_name (account); if (name != NULL) printf ("%s\n", name); else printf ("\n"); g_object_unref (account); account = NULL; } ag_manager_list_free (list); g_object_unref (manager); } static void enable_disable_account (gchar **argv, gboolean enable) { AgManager *manager = NULL; AgAccount *account = NULL; GError *error = NULL; if (argv[2] == NULL) { show_error (INVALID_INPUT); show_help_text (argv[1]); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } account = ag_manager_get_account (manager, atoi (argv[2])); if (account == NULL) { show_error (INVALID_ACC_ID); g_object_unref (manager); return; } ag_account_set_enabled (account, enable); ag_account_store_blocking (account, &error); if (error) { show_error (ERROR_GENERIC); g_error_free (error); } g_object_unref (account); g_object_unref (manager); } static void list_enabled_services (gchar *id) { AgManager *manager = NULL; AgAccount *account = NULL; GList *list = NULL; GList *iter = NULL; const gchar *name = NULL; const gchar *type = NULL; manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } account = ag_manager_get_account (manager, atoi (id)); if (account == NULL) { show_error (INVALID_ACC_ID); g_object_unref (manager); return; } list = ag_account_list_enabled_services (account); if (list == NULL || g_list_length (list) == 0) { printf ("No services enabled for account\n"); g_object_unref (account); g_object_unref (manager); return; } printf ("%-35s%s\n", "Type", "Service Name"); printf ("%-35s%s\n", "----", "------------"); for (iter = list; iter != NULL; iter = g_list_next (iter)) { name = ag_service_get_name ((AgService *) (iter->data)); type = ag_service_get_service_type ((AgService *) (iter->data)); printf ("%-35s", type); printf ("%s\n", name); } ag_service_list_free (list); g_object_unref (account); g_object_unref (manager); } static void list_enabled (gchar **argv) { AgManager *manager = NULL; AgAccount *account = NULL; GList *list = NULL; GList *iter = NULL; const gchar *provider = NULL; const gchar *name = NULL; if (argv[2] != NULL) { list_enabled_services (argv[2]); return; } manager = ag_manager_new (); if (manager == NULL) { show_error (ERROR_GENERIC); return; } list = ag_manager_list_enabled (manager); if (list == NULL || g_list_length (list) == 0) { printf ("No accounts enabled\n"); g_object_unref (manager); return; } printf ("%-10s %-30s %s\n", "ID", "Provider", "Name"); printf ("%-10s %-30s %s\n", "--", "--------", "----"); for (iter = list; iter != NULL; iter = g_list_next (iter)) { printf ("%-10d ", (AgAccountId) GPOINTER_TO_UINT (iter->data)); account = ag_manager_get_account (manager, GPOINTER_TO_UINT (iter->data)); if (account == NULL) { continue; } provider = ag_account_get_provider_name (account); if (provider != NULL) printf ("%-30s ", provider); else printf ("%-30s ", " "); name = ag_account_get_display_name (account); if (name != NULL) printf ("%s\n", name); else printf ("\n"); g_object_unref (account); account = NULL; } ag_manager_list_free (list); g_object_unref (manager); } static int parse (int argc, char **argv) { int i = 0; if (strcmp (argv[1], "create-account") == 0) { create_account (argv); return 0; } else if (strcmp (argv[1], "delete-account") == 0) { delete_account (argv); return 0; } else if (strcmp (argv[1], "list-providers") == 0) { list_providers (); return 0; } else if (strcmp (argv[1], "list-services") == 0) { list_services (argv); return 0; } else if (strcmp (argv[1], "list-accounts") == 0) { list_accounts (); return 0; } else if (strcmp (argv[1], "enable-account") == 0) { enable_disable_account (argv, TRUE); return 0; } else if (strcmp (argv[1], "disable-account") == 0) { enable_disable_account (argv, FALSE); return 0; } else if (strcmp (argv[1], "list-enabled") == 0) { list_enabled (argv); return 0; } else if (strcmp (argv[1], "enable-service") == 0) { enable_disable_service (argv, TRUE); return 0; } else if (strcmp (argv[1], "disable-service") == 0) { enable_disable_service (argv, FALSE); return 0; } else if (strcmp (argv[1], "update-account") == 0) { update_account (argv); return 0; } else if (strcmp (argv[1], "update-service") == 0) { update_service (argv); return 0; } else if (strcmp (argv[1], "get-service") == 0) { get_service (argv); return 0; } else if (strcmp (argv[1], "get-account") == 0) { get_account (argv); return 0; } else if (strcmp (argv[1], "list-settings") == 0) { list_settings (argv); return 0; } return -1; } gint main (int argc, char **argv) { gl_app_name = g_path_get_basename (argv[0]); if (argc < 2) { show_help (); return 0; } if (parse (argc, argv)) show_help (); } libaccounts-glib-1.15+14.04.20131126.2/tools/Makefile.am0000644000015000001560000000071412245170671022554 0ustar pbuserpbgroup00000000000000## Process this file with automake to produce Makefile.in AM_CPPFLAGS = -I$(top_srcdir) $(LIBACCOUNTS_CFLAGS) bin_PROGRAMS = \ ag-backup \ ag-tool ag_tool_SOURCES = main.c ag_tool_CPPFLAGS = \ $(AM_CPPFLAGS) ag_tool_LDADD = \ $(LIBACCOUNTS_LIBS) \ $(top_builddir)/libaccounts-glib/libaccounts-glib.la ag_backup_SOURCES = backup.c ag_backup_CPPFLAGS = \ -I$(top_builddir) \ $(AM_CPPFLAGS) ag_backup_LDADD = \ $(LIBACCOUNTS_LIBS) libaccounts-glib-1.15+14.04.20131126.2/rpm/0000755000015000001560000000000012245171012020142 5ustar pbuserpbgroup00000000000000libaccounts-glib-1.15+14.04.20131126.2/rpm/libaccounts-glib.changes0000644000015000001560000000142412245170671024730 0ustar pbuserpbgroup00000000000000* Mon Oct 25 2010 Alberto Mardegan - 0.58 - Update to 0.58 * Tue Sep 28 2010 Fathi Boudra - 0.52 - Set libaccounts-glib environment variables (AG_SERVICES, AG_SERVICE_TYPES and AG_PROVIDERS) (BMC#7518) * Wed Sep 15 2010 Fathi Boudra - 0.52 - Update to 0.52 (BMC#7258) - Add libaccounts-glib-tests package - Clean up packaging * Mon Aug 02 2010 Bernd Wachter - 0.45 - Update to latest upstream version * Mon Jun 14 2010 Bernd Wachter - 0.39 - Update to latest version * Fri Apr 23 2010 Bernd Wachter - 0.34 - Updated to 0.34 * Wed Feb 03 2010 Helio Castro - 0.26-1 - First release on top of fedora 12 libaccounts-glib-1.15+14.04.20131126.2/rpm/libaccounts-glib.spec0000644000015000001560000000461512245170671024257 0ustar pbuserpbgroup00000000000000Name: libaccounts-glib Version: 0.58 Release: 1 License: LGPLv2.1 Summary: Nokia Maemo Accounts base library Url: http://gitorious.org/accounts-sso/accounts-glib Group: System/Libraries Source0: %{name}-%{version}.tar.gz Source1: libaccounts-glib.sh BuildRequires: automake BuildRequires: gtk-doc BuildRequires: pkgconfig BuildRequires: pkgconfig(check) >= 0.9.4 BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(dbus-glib-1) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(libxml-2.0) BuildRequires: pkgconfig(sqlite3) %description %{summary}. %package devel Summary: Development files for %{name} Group: Development/Libraries Requires: %{name} = %{version} Requires: pkgconfig(glib-2.0) Requires: pkgconfig %description devel The %{name}-devel package contains libraries and header files for developing applications that use %{name}. %package tests Summary: Tests for %{name} Group: Development/Libraries Requires: %{name} = %{version} %description tests This package contains %{name} tests. %prep %setup -q %build gtkdocize autoreconf -vfi %configure --disable-static --disable-gtk-doc make %{?_smp_mflags} %install %make_install install -D -p -m 0644 %{_sourcedir}/%{name}.sh \ %{buildroot}%{_sysconfdir}/profile.d/%{name}.sh %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %defattr(-,root,root,-) %doc README COPYING %config %{_sysconfdir}/profile.d/%{name}.sh %{_libdir}/libaccounts-glib.so.* %{_datadir}/backup-framework/applications/accounts.conf %files devel %defattr(-,root,root,-) %{_includedir}/libaccounts-glib/ag-account.h %{_includedir}/libaccounts-glib/ag-errors.h %{_includedir}/libaccounts-glib/ag-manager.h %{_includedir}/libaccounts-glib/ag-provider.h %{_includedir}/libaccounts-glib/ag-service-type.h %{_includedir}/libaccounts-glib/ag-service.h %{_libdir}/libaccounts-glib.so %{_libdir}/pkgconfig/libaccounts-glib.pc %files tests %defattr(-,root,root,-) %{_bindir}/accounts-glib-test.sh %{_bindir}/accounts-glib-testsuite %{_bindir}/test-process %{_datadir}/libaccounts-glib0-test/e-mail.service-type %{_datadir}/libaccounts-glib0-test/MyProvider.provider %{_datadir}/libaccounts-glib0-test/MyService.service %{_datadir}/libaccounts-glib0-test/OtherService.service %{_datadir}/libaccounts-glib0-test/tests.xml %exclude %{_prefix}/doc/reference libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/0000755000015000001560000000000012245171012022565 5ustar pbuserpbgroup00000000000000libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-manager.h0000644000015000001560000001126212245170671024751 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * Copyright (C) 2012 Intel Corporation. * * Contact: Alberto Mardegan * Contact: Jussi Laako * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_MANAGER_H_ #define _AG_MANAGER_H_ #include #include G_BEGIN_DECLS #define AG_TYPE_MANAGER (ag_manager_get_type ()) #define AG_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AG_TYPE_MANAGER, AgManager)) #define AG_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AG_TYPE_MANAGER, AgManagerClass)) #define AG_IS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AG_TYPE_MANAGER)) #define AG_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AG_TYPE_MANAGER)) #define AG_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), AG_TYPE_MANAGER, AgManagerClass)) typedef struct _AgManagerClass AgManagerClass; typedef struct _AgManagerPrivate AgManagerPrivate; /** * AgManagerClass: * * Use the accessor functions below. */ struct _AgManagerClass { GObjectClass parent_class; void (*account_deleted) (AgManager *manager, AgAccountId id); void (*_ag_reserved2) (void); void (*_ag_reserved3) (void); void (*_ag_reserved4) (void); void (*_ag_reserved5) (void); void (*_ag_reserved6) (void); void (*_ag_reserved7) (void); }; struct _AgManager { GObject parent_instance; /*< private >*/ AgManagerPrivate *priv; }; GType ag_manager_get_type (void) G_GNUC_CONST; AgManager *ag_manager_new (void); AgManager *ag_manager_new_for_service_type (const gchar *service_type); GList *ag_manager_list (AgManager *manager); GList *ag_manager_list_by_service_type (AgManager *manager, const gchar *service_type); void ag_manager_list_free (GList *list); GList *ag_manager_get_account_services (AgManager *manager); GList *ag_manager_get_enabled_account_services (AgManager *manager); AgAccount *ag_manager_get_account (AgManager *manager, AgAccountId account_id); AgAccount *ag_manager_load_account (AgManager *manager, AgAccountId account_id, GError **error); AgAccount *ag_manager_create_account (AgManager *manager, const gchar *provider_name); AgService *ag_manager_get_service (AgManager *manager, const gchar *service_name); GList *ag_manager_list_services (AgManager *manager); GList *ag_manager_list_services_by_type (AgManager *manager, const gchar *service_type); GList *ag_manager_list_enabled (AgManager *manager); GList *ag_manager_list_enabled_by_service_type (AgManager *manager, const gchar *service_type); const gchar *ag_manager_get_service_type (AgManager *manager); AgProvider *ag_manager_get_provider (AgManager *manager, const gchar *provider_name); GList *ag_manager_list_providers (AgManager *manager); void ag_manager_set_db_timeout (AgManager *manager, guint timeout_ms); guint ag_manager_get_db_timeout (AgManager *manager); void ag_manager_set_abort_on_db_timeout (AgManager *manager, gboolean abort); gboolean ag_manager_get_abort_on_db_timeout (AgManager *manager); GList *ag_manager_list_service_types (AgManager *manager); AgServiceType *ag_manager_load_service_type (AgManager *manager, const gchar *service_type); AgApplication *ag_manager_get_application (AgManager *self, const gchar *application_name); GList *ag_manager_list_applications_by_service (AgManager *manager, AgService *service); G_END_DECLS #endif /* _AG_MANAGER_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-account-service.c0000644000015000001560000005441712245170671026435 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2011 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** * SECTION:ag-account-service * @short_description: Account settings for a specific service * @include: libaccounts-glib/ag-account-service.h * * The #AgAccountService object provides access to the account settings for a * specific service type. It is meant to be easier to use than the #AgAccount * class because it hides the complexity of the account structure and gives * access to only the limited subset of account settings which are relevant to * a service. * * To get an #AgAccountService one can use the #AgManager methods * ag_manager_get_account_services() or * ag_manager_get_enabled_account_services(), which both return a #GList of * account services. Note that if the #AgManager was instantiated for a * specific service type, these lists will contain only those account services * matching that service type. * Another way to get an #AgAccountService is to instantiate one using * ag_account_service_new(): this is useful if one already has an #AgAccount * instance. * * This is intended to be a convenient wrapper over the accounts settings * specific for a service; as such, it doesn't offer all the editing * possibilities offered by the #AgAccount class, such as enabling the service * itself: these operations should ideally not be performed by consumer * applications, but by the account editing UI only. * * * Querying available e-mail services * * AgManager *manager; * GList *services, *list; * * // Instantiate an account manager interested in e-mail services only. * manager = ag_manager_new_for_service_type ("e-mail"); * * // Get the list of enabled AgAccountService objects of type e-mail. * services = ag_manager_get_enabled_account_services (manager); * * // Loop through the account services and do something useful with them. * for (list = services; list != NULL; list = list->next) * { * AgAccountService *service = AG_ACCOUNT_SERVICE (list->data); * GVariant *v_server, *v_port, *v_username; * gchar *server = NULL, *username = NULL; * gint port; * AgAccount *account; * * v_server = ag_account_service_get_variant (service, "pop3/hostname", NULL); * if (v_server != NULL) * server = g_variant_dup_string (v_server, NULL); * * v_port = ag_account_service_get_variant (service, "pop3/port", NULL); * if (v_port != NULL) * port = g_variant_get_int16 (&v_port); * * // Suppose that the e-mail address is stored in the global account * // settings; let's get it from there: * account = ag_account_service_get_account (service); * ag_account_select_service (NULL); * v_username = ag_account_get_variant (account, "username", NULL); * if (v_username != NULL) * username = g_variant_dup_string (&v_username); * * ... * * g_free (username); * g_free (server); * } * * * * * * User applications (with the notable exception of the accounts editing * application) should never use account services which are not enabled, and * should stop using an account when the account service becomes disabled. The * latter can be done by connecting to the #AgAccountService::changed signal * and checking if ag_account_service_get_enabled() still returns %TRUE. * Note that if the account gets deleted, it will always get disabled first; * so, there is no need to connect to the #AgAccount::deleted signal; one can * just monitor the #AgAccountService::changed signal. * * */ #define AG_DISABLE_DEPRECATION_WARNINGS #include "ag-account-service.h" #include "ag-errors.h" #include "ag-internals.h" #include "ag-manager.h" #include "ag-service.h" #include "ag-service-type.h" #include "ag-util.h" enum { PROP_0, PROP_ACCOUNT, PROP_SERVICE, PROP_ENABLED, N_PROPERTIES }; static GParamSpec *properties[N_PROPERTIES]; struct _AgAccountServicePrivate { AgAccount *account; AgService *service; gboolean enabled; AgAccountWatch watch; guint account_enabled_id; }; enum { CHANGED, ENABLED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (AgAccountService, ag_account_service, G_TYPE_OBJECT); #define AG_ACCOUNT_SERVICE_PRIV(obj) (AG_ACCOUNT_SERVICE(obj)->priv) static gboolean check_enabled (AgAccountServicePrivate *priv) { gboolean account_enabled; gboolean service_enabled; ag_account_select_service (priv->account, NULL); account_enabled = ag_account_get_enabled (priv->account); if (priv->service) { ag_account_select_service (priv->account, priv->service); service_enabled = ag_account_get_enabled (priv->account); } else service_enabled = TRUE; return service_enabled && account_enabled; } static void account_watch_cb (G_GNUC_UNUSED AgAccount *account, G_GNUC_UNUSED const gchar *key, gpointer user_data) { AgAccountService *self = (AgAccountService *)user_data; g_signal_emit (self, signals[CHANGED], 0); } static void on_account_enabled (G_GNUC_UNUSED AgAccount *account, const gchar *service_name, gboolean service_enabled, AgAccountService *self) { AgAccountServicePrivate *priv = self->priv; gboolean enabled; DEBUG_INFO ("service: %s, enabled: %d", service_name, service_enabled); enabled = check_enabled (priv); if (enabled != priv->enabled) { priv->enabled = enabled; g_signal_emit (self, signals[ENABLED], 0, enabled); g_object_notify_by_pspec ((GObject *)self, properties[PROP_ENABLED]); } } static void ag_account_service_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { AgAccountService *self = AG_ACCOUNT_SERVICE (object); switch (property_id) { case PROP_ACCOUNT: g_value_set_object (value, self->priv->account); break; case PROP_SERVICE: g_value_set_boxed (value, self->priv->service); break; case PROP_ENABLED: g_value_set_boolean (value, self->priv->enabled); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ag_account_service_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { AgAccountServicePrivate *priv = AG_ACCOUNT_SERVICE_PRIV (object); switch (property_id) { case PROP_ACCOUNT: g_assert (priv->account == NULL); priv->account = g_value_dup_object (value); break; case PROP_SERVICE: g_assert (priv->service == NULL); priv->service = g_value_dup_boxed (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ag_account_service_constructed (GObject *object) { AgAccountServicePrivate *priv = AG_ACCOUNT_SERVICE_PRIV (object); if (G_UNLIKELY (!priv->account)) { g_warning ("AgAccountService constructed with no account!"); return; } priv->account_enabled_id = g_signal_connect (priv->account, "enabled", G_CALLBACK (on_account_enabled), object); ag_account_select_service (priv->account, priv->service); priv->watch = ag_account_watch_dir (priv->account, "", account_watch_cb, object); priv->enabled = check_enabled (priv); } static void ag_account_service_dispose (GObject *object) { AgAccountServicePrivate *priv = AG_ACCOUNT_SERVICE_PRIV (object); DEBUG_REFS ("Disposing account-service %p", object); if (priv->account) { ag_account_remove_watch (priv->account, priv->watch); g_signal_handler_disconnect (priv->account, priv->account_enabled_id); g_object_unref (priv->account); priv->account = NULL; } if (priv->service) { ag_service_unref (priv->service); priv->service = NULL; } G_OBJECT_CLASS (ag_account_service_parent_class)->dispose (object); } static void ag_account_service_class_init(AgAccountServiceClass *klass) { GObjectClass* object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (object_class, sizeof (AgAccountServicePrivate)); object_class->constructed = ag_account_service_constructed; object_class->dispose = ag_account_service_dispose; object_class->get_property = ag_account_service_get_property; object_class->set_property = ag_account_service_set_property; /** * AgAccountService:account: * * The #AgAccount used by the account service. * * Since: 1.4 */ properties[PROP_ACCOUNT] = g_param_spec_object ("account", "account", "account", AG_TYPE_ACCOUNT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * AgAccountService:service: * * The #AgService used by the account service. * * Since: 1.4 */ properties[PROP_SERVICE] = g_param_spec_boxed ("service", "service", "service", ag_service_get_type(), G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * AgAccountService:enabled: * * Whether the account service is currently enabled. The value of * this property is %TRUE if and only if the underlying #AgAccount * is enabled and the selected #AgService is enabled on it. If this * property is %FALSE, applications should not try to use this * object. * * Since: 1.4 */ properties[PROP_ENABLED] = g_param_spec_boolean ("enabled", "Enabled", "Whether the account service is enabled", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPERTIES, properties); /** * AgAccountService::changed: * @self: the #AgAccountService. * * Emitted when some setting has changed on the account service. You can * use the ag_account_service_get_changed_fields() method to retrieve the * list of the settings which have changed. */ signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * AgAccountService::enabled: * @self: the #AgAccountService. * @enabled: whether the service is enabled. * * Emitted when the service enabled state changes. */ signals[ENABLED] = g_signal_new ("enabled", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); } static void ag_account_service_init(AgAccountService *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, AG_TYPE_ACCOUNT_SERVICE, AgAccountServicePrivate); } /** * ag_account_service_new: * @account: (transfer full): an #AgAccount. * @service: (transfer full) (allow-none): an #AgService supported by @account. * * Constructor. If @service is %NULL, the returned object will operate on the * global account settings. * * Returns: a new #AgAccountService; call g_object_unref() when you don't need * this object anymore. */ AgAccountService * ag_account_service_new(AgAccount *account, AgService *service) { g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); return g_object_new (AG_TYPE_ACCOUNT_SERVICE, "account", account, "service", service, NULL); } /** * ag_account_service_get_account: * @self: the #AgAccountService. * * Get the #AgAccount associated with @self. * * Returns: (transfer none): the underlying #AgAccount. The reference count on * it is not incremented, so if you need to use it beyond the lifetime of * @self, you need to call g_object_ref() on it yourself. */ AgAccount * ag_account_service_get_account (AgAccountService *self) { g_return_val_if_fail (AG_IS_ACCOUNT_SERVICE (self), NULL); return self->priv->account; } /** * ag_account_service_get_service: * @self: the #AgAccountService. * * Get the #AgService associated with @self. * * Returns: (transfer none): the underlying #AgService. The reference count on * it is not incremented, so if you need to use it beyond the lifetime of * @self, you need to call ag_service_ref() on it yourself. */ AgService * ag_account_service_get_service (AgAccountService *self) { g_return_val_if_fail (AG_IS_ACCOUNT_SERVICE (self), NULL); return self->priv->service; } /** * ag_account_service_get_enabled: * @self: the #AgAccountService. * * Checks whether the underlying #AgAccount is enabled and the selected * #AgService is enabled on it. If this method returns %FALSE, applications * should not try to use this object. * * Returns: %TRUE if the service is enabled, %FALSE otherwise. */ gboolean ag_account_service_get_enabled (AgAccountService *self) { g_return_val_if_fail (AG_IS_ACCOUNT_SERVICE (self), FALSE); return self->priv->enabled; } /** * ag_account_service_get_value: * @self: the #AgAccountService. * @key: the name of the setting to retrieve. * @value: (inout): an initialized #GValue to receive the setting's value. * * Gets the value of the configuration setting @key: @value must be a * #GValue initialized to the type of the setting. * * Returns: one of #AgSettingSource: %AG_SETTING_SOURCE_NONE if * the setting is not present, %AG_SETTING_SOURCE_ACCOUNT if the setting comes * from the account configuration, or %AG_SETTING_SOURCE_PROFILE if the value * comes as predefined in the profile. * * Deprecated: 1.4: Use ag_account_service_get_variant() instead. */ AgSettingSource ag_account_service_get_value (AgAccountService *self, const gchar *key, GValue *value) { AgAccountServicePrivate *priv; g_return_val_if_fail (AG_IS_ACCOUNT_SERVICE (self), AG_SETTING_SOURCE_NONE); priv = self->priv; ag_account_select_service (priv->account, priv->service); return ag_account_get_value (priv->account, key, value); } /** * ag_account_service_set_value: * @self: the #AgAccountService. * @key: the name of the setting to change. * @value: (allow-none): a #GValue holding the new setting's value. * * Sets the value of the configuration setting @key to the value @value. * If @value is %NULL, then the setting is unset. * * Deprecated: 1.4: Use ag_account_service_set_variant() instead. */ void ag_account_service_set_value (AgAccountService *self, const gchar *key, const GValue *value) { AgAccountServicePrivate *priv; g_return_if_fail (AG_IS_ACCOUNT_SERVICE (self)); priv = self->priv; ag_account_select_service (priv->account, priv->service); ag_account_set_value (priv->account, key, value); } /** * ag_account_service_get_variant: * @self: the #AgAccountService. * @key: the name of the setting to retrieve. * @source: (allow-none) (out): a pointer to an * #AgSettingSource variable which will tell whether the setting was * retrieved from the accounts DB or from a service template. * * Gets the value of the configuration setting @key. * * Returns: (transfer none): a #GVariant holding the setting value, or * %NULL. The returned #GVariant is owned by the account, and no guarantees * are made about its lifetime. If the client wishes to keep it, it should * call g_variant_ref() on it. * * Since: 1.4 */ GVariant * ag_account_service_get_variant (AgAccountService *self, const gchar *key, AgSettingSource *source) { AgAccountServicePrivate *priv; g_return_val_if_fail (AG_IS_ACCOUNT_SERVICE (self), NULL); priv = self->priv; ag_account_select_service (priv->account, priv->service); return ag_account_get_variant (priv->account, key, source); } /** * ag_account_service_set_variant: * @self: the #AgAccountService. * @key: the name of the setting to change. * @value: (allow-none): a #GVariant holding the new setting's value. * * Sets the value of the configuration setting @key to the value @value. * If @value has a floating reference, the @account will take ownership * of it. * If @value is %NULL, then the setting is unset. * * Since: 1.4 */ void ag_account_service_set_variant (AgAccountService *self, const gchar *key, GVariant *value) { AgAccountServicePrivate *priv; g_return_if_fail (AG_IS_ACCOUNT_SERVICE (self)); priv = self->priv; ag_account_select_service (priv->account, priv->service); ag_account_set_variant (priv->account, key, value); } /** * ag_account_service_settings_iter_init: * @self: the #AgAccountService. * @iter: an uninitialized #AgAccountSettingIter structure. * @key_prefix: (allow-none): enumerate only the settings whose key starts with * @key_prefix. * * Initializes @iter to iterate over the account settings. If @key_prefix is * not %NULL, only keys whose names start with @key_prefix will be iterated * over. * After calling this method, one would typically call * ag_account_settings_iter_get_next() to read the settings one by one. */ void ag_account_service_settings_iter_init (AgAccountService *self, AgAccountSettingIter *iter, const gchar *key_prefix) { AgAccountServicePrivate *priv; g_return_if_fail (AG_IS_ACCOUNT_SERVICE (self)); priv = self->priv; ag_account_select_service (priv->account, priv->service); ag_account_settings_iter_init (priv->account, iter, key_prefix); } /** * ag_account_service_get_settings_iter: * @self: the #AgAccountService. * @key_prefix: (allow-none): enumerate only the settings whose key starts with * @key_prefix. * * Creates a new iterator. This method is useful for language bindings only. * * Returns: (transfer full): an #AgAccountSettingIter. */ AgAccountSettingIter * ag_account_service_get_settings_iter (AgAccountService *self, const gchar *key_prefix) { AgAccountSettingIter *iter; AgAccountServicePrivate *priv; g_return_val_if_fail (AG_IS_ACCOUNT_SERVICE (self), NULL); priv = self->priv; ag_account_select_service (priv->account, priv->service); iter = g_slice_new (AgAccountSettingIter); _ag_account_settings_iter_init (priv->account, iter, key_prefix, TRUE); return iter; } /** * ag_account_service_settings_iter_next: * @iter: an initialized #AgAccountSettingIter structure. * @key: (out callee-allocates) (transfer none): a pointer to a string * receiving the key name. * @value: (out callee-allocates) (transfer none): a pointer to a pointer to a * #GValue, to receive the key value. * * Iterates over the account keys. @iter must be an iterator previously * initialized with ag_account_service_settings_iter_init(). * * Returns: %TRUE if @key and @value have been set, %FALSE if we there are no * more account settings to iterate over. * * Deprecated: 1.4: Use ag_account_settings_iter_get_next() instead. */ gboolean ag_account_service_settings_iter_next (AgAccountSettingIter *iter, const gchar **key, const GValue **value) { return ag_account_settings_iter_next (iter, key, value); } /** * ag_account_service_get_auth_data: * @self: the #AgAccountService. * * Reads the authentication data stored in the account (merging the * service-specific settings with the global account settings) and returns an * #AgAuthData structure. * The method and mechanism are read from the "auth/method" and * "auth/mechanism" keys, respectively. The authentication parameters are * found under the "auth/<method>/<mechanism>/" group. * * Returns: (transfer full): a newly allocated #AgAuthData structure. */ AgAuthData * ag_account_service_get_auth_data (AgAccountService *self) { AgAccountServicePrivate *priv; g_return_val_if_fail (AG_IS_ACCOUNT_SERVICE (self), NULL); priv = self->priv; return _ag_auth_data_new (priv->account, priv->service); } /** * ag_account_service_get_changed_fields: * @self: the #AgAccountService. * * This method should be called only in the context of a handler of the * #AgAccountService::changed signal, and can be used to retrieve the set of * changes. * * Returns: (transfer full): a newly allocated array of strings describing the * keys of the fields which have been altered. It must be free'd with * g_strfreev(). */ gchar ** ag_account_service_get_changed_fields (AgAccountService *self) { AgAccountServicePrivate *priv; GHashTable *settings; GList *keys, *list; gchar **fields; gint i; g_return_val_if_fail (AG_IS_ACCOUNT_SERVICE (self), NULL); priv = self->priv; settings = _ag_account_get_service_changes (priv->account, priv->service); keys = g_hash_table_get_keys (settings); fields = g_malloc ((g_hash_table_size (settings) + 1) * sizeof(gchar *)); i = 0; for (list = keys; list != NULL; list = list->next) { fields[i++] = g_strdup ((gchar *)(list->data)); } fields[i] = NULL; g_list_free (keys); return fields; } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/accounts-service.dtd0000644000015000001560000000331112245170671026547 0ustar pbuserpbgroup00000000000000 libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-marshal.list0000644000015000001560000000002512245170671025505 0ustar pbuserpbgroup00000000000000VOID:STRING,BOOLEAN libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/accounts-application.dtd0000644000015000001560000000274512245170671027424 0ustar pbuserpbgroup00000000000000 libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-service.h0000644000015000001560000000415212245170671024777 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * Copyright (C) 2012 Intel Corporation. * * Contact: Alberto Mardegan * Contact: Jussi Laako * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_SERVICE_H_ #define _AG_SERVICE_H_ #include #include #include G_BEGIN_DECLS GType ag_service_get_type (void) G_GNUC_CONST; const gchar *ag_service_get_name (AgService *service); const gchar *ag_service_get_display_name (AgService *service); const gchar *ag_service_get_description (AgService *service); const gchar *ag_service_get_service_type (AgService *service); const gchar *ag_service_get_provider (AgService *service); const gchar *ag_service_get_icon_name (AgService *service); const gchar *ag_service_get_i18n_domain (AgService *service); gboolean ag_service_has_tag (AgService *service, const gchar *tag); GList *ag_service_get_tags (AgService *service); void ag_service_get_file_contents (AgService *service, const gchar **contents, gsize *data_offset); AgService *ag_service_ref (AgService *service); void ag_service_unref (AgService *service); void ag_service_list_free (GList *list); G_END_DECLS #endif /* _AG_SERVICE_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/accounts-service-type.dtd0000644000015000001560000000165512245170671027537 0ustar pbuserpbgroup00000000000000 libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-debug.c0000644000015000001560000000313212245170671024415 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2010 Nokia Corporation. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 "ag-debug.h" static const GDebugKey debug_keys[] = { { "time", AG_DEBUG_TIME }, { "refs", AG_DEBUG_REFS }, { "locks", AG_DEBUG_LOCKS }, { "queries", AG_DEBUG_QUERIES }, { "info", AG_DEBUG_INFO }, }; static AgDebugLevel debug_level = AG_DEBUG_LOCKS; void _ag_debug_init (void) { const gchar *env; static gboolean initialized = FALSE; if (initialized) return; initialized = TRUE; env = g_getenv ("AG_DEBUG"); if (env) { debug_level = g_parse_debug_string (env, debug_keys, G_N_ELEMENTS(debug_keys)); } } AgDebugLevel _ag_debug_get_level (void) { return debug_level; } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-account.h0000644000015000001560000001664712245170671025007 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_ACCOUNT_H_ #define _AG_ACCOUNT_H_ #include #include #include G_BEGIN_DECLS #define AG_TYPE_ACCOUNT (ag_account_get_type ()) #define AG_ACCOUNT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AG_TYPE_ACCOUNT, AgAccount)) #define AG_ACCOUNT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AG_TYPE_ACCOUNT, AgAccountClass)) #define AG_IS_ACCOUNT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AG_TYPE_ACCOUNT)) #define AG_IS_ACCOUNT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AG_TYPE_ACCOUNT)) #define AG_ACCOUNT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), AG_TYPE_ACCOUNT, AgAccountClass)) typedef struct _AgAccountClass AgAccountClass; typedef struct _AgAccountPrivate AgAccountPrivate; /** * AgAccountClass: * * Use the accessor functions below. */ struct _AgAccountClass { GObjectClass parent_class; void (*_ag_reserved1) (void); void (*_ag_reserved2) (void); void (*_ag_reserved3) (void); void (*_ag_reserved4) (void); void (*_ag_reserved5) (void); void (*_ag_reserved6) (void); void (*_ag_reserved7) (void); }; struct _AgAccount { GObject parent_instance; AgAccountId id; /*< private >*/ AgAccountPrivate *priv; }; GType ag_account_get_type (void) G_GNUC_CONST; gboolean ag_account_supports_service (AgAccount *account, const gchar *service_type); GList *ag_account_list_services (AgAccount *account); GList *ag_account_list_services_by_type (AgAccount *account, const gchar *service_type); GList *ag_account_list_enabled_services (AgAccount *account); AgManager *ag_account_get_manager (AgAccount *account); const gchar *ag_account_get_provider_name (AgAccount *account); const gchar *ag_account_get_display_name (AgAccount *account); void ag_account_set_display_name (AgAccount *account, const gchar *display_name); /* Account configuration */ void ag_account_select_service (AgAccount *account, AgService *service); AgService *ag_account_get_selected_service (AgAccount *account); gboolean ag_account_get_enabled (AgAccount *account); void ag_account_set_enabled (AgAccount *account, gboolean enabled); void ag_account_delete (AgAccount *account); /** * AgSettingSource: * @AG_SETTING_SOURCE_NONE: the setting is not present * @AG_SETTING_SOURCE_ACCOUNT: the setting comes from the current account * configuration * @AG_SETTING_SOURCE_PROFILE: the setting comes from the predefined profile * * The source of a setting on a #AgAccount. */ typedef enum { AG_SETTING_SOURCE_NONE = 0, AG_SETTING_SOURCE_ACCOUNT, AG_SETTING_SOURCE_PROFILE, } AgSettingSource; #ifndef AG_DISABLE_DEPRECATED AG_DEPRECATED_FOR(ag_account_get_variant) AgSettingSource ag_account_get_value (AgAccount *account, const gchar *key, GValue *value); AG_DEPRECATED_FOR(ag_account_set_variant) void ag_account_set_value (AgAccount *account, const gchar *key, const GValue *value); #endif GVariant *ag_account_get_variant (AgAccount *account, const gchar *key, AgSettingSource *source); void ag_account_set_variant (AgAccount *account, const gchar *key, GVariant *value); typedef struct _AgAccountSettingIter AgAccountSettingIter; /** * AgAccountSettingIter: * @account: the AgAccount to iterate over * * Iterator for account settings. */ struct _AgAccountSettingIter { AgAccount *account; /*< private >*/ GHashTableIter iter1; gpointer ptr1; gpointer ptr2; gint idx1; gint idx2; }; GType ag_account_settings_iter_get_type (void) G_GNUC_CONST; void ag_account_settings_iter_free (AgAccountSettingIter *iter); void ag_account_settings_iter_init (AgAccount *account, AgAccountSettingIter *iter, const gchar *key_prefix); #ifndef AG_DISABLE_DEPRECATED AG_DEPRECATED_FOR(ag_account_settings_iter_get_next) gboolean ag_account_settings_iter_next (AgAccountSettingIter *iter, const gchar **key, const GValue **value); #endif gboolean ag_account_settings_iter_get_next (AgAccountSettingIter *iter, const gchar **key, GVariant **value); AgAccountSettingIter *ag_account_get_settings_iter (AgAccount *account, const gchar *key_prefix); /** * AgAccountWatch: * * An opaque struct returned from ag_account_watch_dir() and * ag_account_watch_key(). */ typedef struct _AgAccountWatch *AgAccountWatch; typedef void (*AgAccountNotifyCb) (AgAccount *account, const gchar *key, gpointer user_data); AgAccountWatch ag_account_watch_key (AgAccount *account, const gchar *key, AgAccountNotifyCb callback, gpointer user_data); AgAccountWatch ag_account_watch_dir (AgAccount *account, const gchar *key_prefix, AgAccountNotifyCb callback, gpointer user_data); void ag_account_remove_watch (AgAccount *account, AgAccountWatch watch); #ifndef AG_DISABLE_DEPRECATED typedef void (*AgAccountStoreCb) (AgAccount *account, const GError *error, gpointer user_data); AG_DEPRECATED_FOR(ag_account_store_async) void ag_account_store (AgAccount *account, AgAccountStoreCb callback, gpointer user_data); #endif void ag_account_store_async (AgAccount *account, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean ag_account_store_finish (AgAccount *account, GAsyncResult *res, GError **error); gboolean ag_account_store_blocking (AgAccount *account, GError **error); void ag_account_sign (AgAccount *account, const gchar *key, const gchar *token); gboolean ag_account_verify (AgAccount *account, const gchar *key, const gchar **token); gboolean ag_account_verify_with_tokens (AgAccount *account, const gchar *key, const gchar **tokens); /* Signon */ /* TODO: depends on signon-glib */ G_END_DECLS #endif /* _AG_ACCOUNT_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-auth-data.h0000644000015000001560000000347112245170671025212 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2012 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_AUTH_DATA_H_ #define _AG_AUTH_DATA_H_ #include #include G_BEGIN_DECLS GType ag_auth_data_get_type (void) G_GNUC_CONST; AgAuthData *ag_auth_data_ref (AgAuthData *self); void ag_auth_data_unref (AgAuthData *self); guint ag_auth_data_get_credentials_id (AgAuthData *self); const gchar *ag_auth_data_get_method (AgAuthData *self); const gchar *ag_auth_data_get_mechanism (AgAuthData *self); #ifndef AG_DISABLE_DEPRECATED AG_DEPRECATED_FOR(ag_auth_data_get_login_parameters) GHashTable *ag_auth_data_get_parameters (AgAuthData *self); AG_DEPRECATED_FOR(ag_auth_data_get_login_parameters) void ag_auth_data_insert_parameters (AgAuthData *self, GHashTable *parameters); #endif GVariant *ag_auth_data_get_login_parameters (AgAuthData *self, GVariant *extra_parameters); G_END_DECLS #endif /* _AG_AUTH_DATA_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-util.h0000644000015000001560000000554012245170671024316 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * Copyright (C) 2012 Intel Corporation. * * Contact: Alberto Mardegan * Contact: Jussi Laako * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_UTIL_H_ #define _AG_UTIL_H_ #include #include #include #include G_BEGIN_DECLS GString *_ag_string_append_printf (GString *string, const gchar *format, ...) G_GNUC_INTERNAL; G_GNUC_INTERNAL GValue *_ag_value_slice_dup (const GValue *value); G_GNUC_INTERNAL void _ag_value_slice_free (GValue *value); G_GNUC_INTERNAL GVariant *_ag_value_to_variant (const GValue *value); G_GNUC_INTERNAL void _ag_value_from_variant (GValue *value, GVariant *variant); G_GNUC_INTERNAL gchar *_ag_value_to_db (GVariant *value, gboolean type_annotate); G_GNUC_INTERNAL GVariant *_ag_value_from_db (sqlite3_stmt *stmt, gint col_type, gint col_value); G_GNUC_INTERNAL const GVariantType *_ag_type_from_g_type (GType type); G_GNUC_INTERNAL gboolean _ag_xml_get_boolean (xmlTextReaderPtr reader, gboolean *dest_boolean); G_GNUC_INTERNAL gboolean _ag_xml_get_element_data (xmlTextReaderPtr reader, const gchar **dest_ptr); G_GNUC_INTERNAL gboolean _ag_xml_dup_element_data (xmlTextReaderPtr reader, gchar **dest_ptr); G_GNUC_INTERNAL gboolean _ag_xml_parse_settings (xmlTextReaderPtr reader, const gchar *group, GHashTable *settings); G_GNUC_INTERNAL gboolean _ag_xml_parse_element_list (xmlTextReaderPtr reader, const gchar *match, GHashTable **list); G_GNUC_INTERNAL gchar *_ag_dbus_escape_as_identifier (const gchar *name); G_GNUC_INTERNAL gchar *_ag_find_libaccounts_file (const gchar *file_id, const gchar *suffix, const gchar *env_var, const gchar *subdir); G_END_DECLS #endif /* _AG_UTIL_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-provider.h0000644000015000001560000000407512245170671025175 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012-2013 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_PROVIDER_H_ #define _AG_PROVIDER_H_ #include #include #include G_BEGIN_DECLS GType ag_provider_get_type (void) G_GNUC_CONST; const gchar *ag_provider_get_name (AgProvider *provider); const gchar *ag_provider_get_display_name (AgProvider *provider); const gchar *ag_provider_get_description (AgProvider *provider); const gchar *ag_provider_get_i18n_domain (AgProvider *provider); const gchar *ag_provider_get_icon_name (AgProvider *provider); const gchar *ag_provider_get_domains_regex (AgProvider *provider); gboolean ag_provider_match_domain (AgProvider *provider, const gchar *domain); const gchar *ag_provider_get_plugin_name (AgProvider *provider); gboolean ag_provider_get_single_account (AgProvider *provider); void ag_provider_get_file_contents (AgProvider *provider, const gchar **contents); AgProvider *ag_provider_ref (AgProvider *provider); void ag_provider_unref (AgProvider *provider); void ag_provider_list_free (GList *list); G_END_DECLS #endif /* _AG_PROVIDER_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/accounts-glib.h0000644000015000001560000000257512245170671025513 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2011 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _ACCOUNTS_GLIB_H_ #define _ACCOUNTS_GLIB_H_ #include #include #include #include #include #include #include #include #include #endif /* _ACCOUNTS_GLIB_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-types.h0000644000015000001560000000502212245170671024500 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_TYPES_H_ #define _AG_TYPES_H_ G_BEGIN_DECLS /** * AgAccount: * * Opaque structure. Use related accessor functions. */ typedef struct _AgAccount AgAccount; /** * AgManager: * * Opaque structure. Use related accessor functions. */ typedef struct _AgManager AgManager; /** * AgService: * * Opaque structure. Use related accessor functions. */ typedef struct _AgService AgService; /** * AgAccountService: * * Opaque structure. Use related accessor functions. */ typedef struct _AgAccountService AgAccountService; /** * AgProvider: * * Opaque structure. Use related accessor functions. */ typedef struct _AgProvider AgProvider; /** * AgAuthData: * * Opaque structure. Use related accessor functions. */ typedef struct _AgAuthData AgAuthData; /** * AgServiceType: * * Opaque structure. Use related accessor functions. */ typedef struct _AgServiceType AgServiceType; /** * AgApplication: * * Opaque structure. Use related accessor functions. */ typedef struct _AgApplication AgApplication; /** * AgAccountId: * * ID of an account. Often used when retrieving lists of accounts from * #AgManager. */ typedef guint AgAccountId; /* guards to avoid bumping up the GLib dependency */ #ifndef G_DEPRECATED #define G_DEPRECATED G_GNUC_DEPRECATED #define G_DEPRECATED_FOR(x) G_GNUC_DEPRECATED_FOR(x) #endif #ifdef AG_DISABLE_DEPRECATION_WARNINGS #define AG_DEPRECATED #define AG_DEPRECATED_FOR(x) #else #define AG_DEPRECATED G_DEPRECATED #define AG_DEPRECATED_FOR(x) G_DEPRECATED_FOR(x) #endif G_END_DECLS #endif /* _AG_TYPES_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-account-service.h0000644000015000001560000001124012245170671026425 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2011 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_ACCOUNT_SERVICE_H_ #define _AG_ACCOUNT_SERVICE_H_ #include #include #include G_BEGIN_DECLS #define AG_TYPE_ACCOUNT_SERVICE (ag_account_service_get_type ()) #define AG_ACCOUNT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ AG_TYPE_ACCOUNT_SERVICE, AgAccountService)) #define AG_ACCOUNT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ AG_TYPE_ACCOUNT_SERVICE, \ AgAccountServiceClass)) #define AG_IS_ACCOUNT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ AG_TYPE_ACCOUNT_SERVICE)) #define AG_IS_ACCOUNT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \ AG_TYPE_ACCOUNT_SERVICE)) #define AG_ACCOUNT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \ AG_TYPE_ACCOUNT_SERVICE, \ AgAccountServiceClass)) typedef struct _AgAccountServiceClass AgAccountServiceClass; typedef struct _AgAccountServicePrivate AgAccountServicePrivate; /** * AgAccountServiceClass: * * Use the accessor functions below. */ struct _AgAccountServiceClass { GObjectClass parent_class; void (*_ag_reserved1) (void); void (*_ag_reserved2) (void); void (*_ag_reserved3) (void); void (*_ag_reserved4) (void); void (*_ag_reserved5) (void); void (*_ag_reserved6) (void); void (*_ag_reserved7) (void); }; struct _AgAccountService { GObject parent_instance; AgAccountServicePrivate *priv; }; GType ag_account_service_get_type (void) G_GNUC_CONST; AgAccountService *ag_account_service_new (AgAccount *account, AgService *service); AgAccount *ag_account_service_get_account (AgAccountService *self); AgService *ag_account_service_get_service (AgAccountService *self); gboolean ag_account_service_get_enabled (AgAccountService *self); #ifndef AG_DISABLE_DEPRECATED AG_DEPRECATED_FOR(ag_account_service_get_variant) AgSettingSource ag_account_service_get_value (AgAccountService *self, const gchar *key, GValue *value); AG_DEPRECATED_FOR(ag_account_service_set_variant) void ag_account_service_set_value (AgAccountService *self, const gchar *key, const GValue *value); #endif GVariant *ag_account_service_get_variant (AgAccountService *self, const gchar *key, AgSettingSource *source); void ag_account_service_set_variant (AgAccountService *self, const gchar *key, GVariant *value); AgAccountSettingIter * ag_account_service_get_settings_iter (AgAccountService *self, const gchar *key_prefix); void ag_account_service_settings_iter_init (AgAccountService *self, AgAccountSettingIter *iter, const gchar *key_prefix); #ifndef AG_DISABLE_DEPRECATED AG_DEPRECATED_FOR(ag_account_settings_iter_get_next) gboolean ag_account_service_settings_iter_next (AgAccountSettingIter *iter, const gchar **key, const GValue **value); #endif AgAuthData *ag_account_service_get_auth_data (AgAccountService *self); gchar **ag_account_service_get_changed_fields (AgAccountService *self); G_END_DECLS #endif /* _AG_ACCOUNT_SERVICE_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-manager.c0000644000015000001560000022425212245170671024751 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012-2013 Canonical Ltd. * Copyright (C) 2012 Intel Corporation. * * Contact: Alberto Mardegan * Contact: Jussi Laako * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** * SECTION:ag-manager * @short_description: The account manager object * @include: libaccounts-glib/ag-manager.h * * The #AgManager is the main object in this library. Use it to create an * #AgAccount, and to instantiate boxed types such as #AgProvider, * #AgApplication and #AgService. * * #AgManager can be instantiated with a set service type with * ag_manager_new_for_service_type(), which restricts some future operations on * the manager, such as ag_manager_list() or ag_manager_list_services(), to * only affect accounts or services with the set service type. * * Lists of objects instantiated by the manager can be freed with the * corresponding functions, such as ag_manager_list_free() for the #GList of * #AgAccountId returned from ag_manager_list(), or ag_service_list_free() for * the #GList of #AgService returned from ag_manager_list_services(). */ #include "config.h" #include "ag-manager.h" #include "ag-account-service.h" #include "ag-application.h" #include "ag-errors.h" #include "ag-internals.h" #include "ag-service.h" #include "ag-util.h" #include #include #include #include #include #include #include #include #ifndef DATABASE_DIR #define DATABASE_DIR "libaccounts-glib" #endif #ifdef DISABLE_WAL #define JOURNAL_MODE "TRUNCATE" #else #define JOURNAL_MODE "WAL" #endif enum { PROP_0, PROP_SERVICE_TYPE, }; enum { ACCOUNT_CREATED, ACCOUNT_DELETED, ACCOUNT_ENABLED, ACCOUNT_UPDATED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; struct _AgManagerPrivate { sqlite3 *db; sqlite3_stmt *begin_stmt; sqlite3_stmt *commit_stmt; sqlite3_stmt *rollback_stmt; sqlite3_int64 last_service_id; sqlite3_int64 last_account_id; GDBusConnection *dbus_conn; /* Cache for AgService */ GHashTable *services; /* Weak references to loaded accounts */ GHashTable *accounts; /* list of StoreCbData awaiting for exclusive locks */ GList *locks; /* list of EmittedSignalData for the signals emitted by this instance */ GList *emitted_signals; /* list of ProcessedSignalData, to avoid processing signals twice */ GList *processed_signals; /* D-Bus object paths we are listening to */ GPtrArray *object_paths; /* List of GDBus signal subscriptions */ GSList *subscription_ids; GError *last_error; guint db_timeout; guint abort_on_db_timeout : 1; guint is_disposed : 1; gchar *service_type; }; typedef struct { AgManager *manager; AgAccount *account; gchar *sql; AgAccountChanges *changes; guint id; GSimpleAsyncResult *async_result; GCancellable *cancellable; } StoreCbData; typedef struct { struct timespec ts; gboolean must_process; } EmittedSignalData; typedef struct { struct timespec ts; } ProcessedSignalData; G_DEFINE_TYPE (AgManager, ag_manager, G_TYPE_OBJECT); #define AG_MANAGER_PRIV(obj) (AG_MANAGER(obj)->priv) static void store_cb_data_free (StoreCbData *sd); static void account_weak_notify (gpointer userdata, GObject *dead_account); typedef gpointer (*AgDataFileLoadFunc) (AgManager *self, const gchar *base_name); static void add_data_files_from_dir (AgManager *manager, const gchar *dirname, GHashTable *loaded_files, const gchar *suffix, AgDataFileLoadFunc load_file_func) { const gchar *filename; gchar *base_name; gint suffix_length; gpointer loaded_file; GDir *dir; g_return_if_fail (dirname != NULL); dir = g_dir_open (dirname, 0, NULL); if (!dir) return; suffix_length = strlen (suffix); while ((filename = g_dir_read_name (dir)) != NULL) { if (filename[0] == '.') continue; if (!g_str_has_suffix (filename, suffix)) continue; base_name = g_strndup (filename, (strlen (filename) - suffix_length)); /* if there is already a service with the same name in the list, then * we skip this one (we process directories in descending order of * priority) */ if (g_hash_table_lookup (loaded_files, base_name) != NULL) { g_free (base_name); continue; } loaded_file = load_file_func (manager, base_name); if (G_UNLIKELY (!loaded_file)) { g_free (base_name); continue; } g_hash_table_insert (loaded_files, base_name, loaded_file); } g_dir_close (dir); } static GList * list_data_files (AgManager *manager, const gchar *suffix, const gchar *env_var, const gchar *subdir, AgDataFileLoadFunc load_file_func) { GHashTable *loaded_files; GList *file_list; const gchar * const *dirs; const gchar *env_dirname, *datadir; gchar *dirname; loaded_files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); env_dirname = g_getenv (env_var); if (env_dirname) { add_data_files_from_dir (manager, env_dirname, loaded_files, suffix, load_file_func); /* If the environment variable is set, don't look in other places */ goto finish; } datadir = g_get_user_data_dir (); if (G_LIKELY (datadir)) { dirname = g_build_filename (datadir, subdir, NULL); add_data_files_from_dir (manager, dirname, loaded_files, suffix, load_file_func); g_free (dirname); } dirs = g_get_system_data_dirs (); for (datadir = *dirs; datadir != NULL; dirs++, datadir = *dirs) { dirname = g_build_filename (datadir, subdir, NULL); add_data_files_from_dir (manager, dirname, loaded_files, suffix, load_file_func); g_free (dirname); } finish: file_list = g_hash_table_get_values (loaded_files); g_hash_table_unref (loaded_files); return file_list; } /** * ag_manager_get_application: * @self: an #AgManager * @application_name: the name of an application to search for * * Search for @application_name in the list of applications, and return a new * #AgApplication if a matching application was found. * * Returns: a new #AgApplication if one was found, %NULL otherwise */ AgApplication * ag_manager_get_application (AgManager *self, const gchar *application_name) { g_return_val_if_fail (AG_IS_MANAGER (self), NULL); return _ag_application_new_from_file (application_name); } static inline GList * _ag_applications_list (AgManager *self) { return list_data_files (self, ".application", "AG_APPLICATIONS", APPLICATION_FILES_DIR, (AgDataFileLoadFunc)ag_manager_get_application); } static inline GList * _ag_providers_list (AgManager *self) { return list_data_files (self, ".provider", "AG_PROVIDERS", PROVIDER_FILES_DIR, (AgDataFileLoadFunc)ag_manager_get_provider); } static inline GList * _ag_services_list (AgManager *self) { return list_data_files (self, ".service", "AG_SERVICES", SERVICE_FILES_DIR, (AgDataFileLoadFunc)ag_manager_get_service); } static inline GList * _ag_service_types_list (AgManager *self) { return list_data_files (self, ".service-type", "AG_SERVICE_TYPES", SERVICE_TYPE_FILES_DIR, (AgDataFileLoadFunc)ag_manager_load_service_type); } static GList * get_account_services_from_accounts (AgManager *manager, GList *account_ids, gboolean enabled_only) { GList *ret = NULL, *account_list; for (account_list = account_ids; account_list != NULL; account_list = account_list->next) { AgAccount *account; GList *service_ids, *service_elem; account = ag_manager_get_account (manager, (AgAccountId) GPOINTER_TO_UINT(account_list->data)); if (G_UNLIKELY (account == NULL)) continue; service_ids = enabled_only ? ag_account_list_enabled_services (account) : ag_account_list_services (account); for (service_elem = service_ids; service_elem != NULL; service_elem = service_elem->next) { AgService *service = (AgService *) service_elem->data; AgAccountService *account_service; account_service = ag_account_service_new (account, service); if (G_UNLIKELY (account_service == NULL)) continue; ret = g_list_prepend (ret, account_service); } ag_service_list_free (service_ids); g_object_unref (account); } return ret; } static void set_error_from_db (AgManager *manager) { AgManagerPrivate *priv = manager->priv; AgError code; GError *error; switch (sqlite3_errcode (priv->db)) { case SQLITE_DONE: case SQLITE_OK: _ag_manager_take_error (manager, NULL); return; case SQLITE_BUSY: code = AG_ACCOUNTS_ERROR_DB_LOCKED; if (priv->abort_on_db_timeout) g_error ("Accounts DB timeout: causing application to abort."); break; default: code = AG_ACCOUNTS_ERROR_DB; break; } error = g_error_new (AG_ACCOUNTS_ERROR, code, "SQLite error %d: %s", sqlite3_errcode (priv->db), sqlite3_errmsg (priv->db)); _ag_manager_take_error (manager, error); } static gboolean timed_unref_account (gpointer account) { DEBUG_REFS ("Releasing temporary reference on account %u", AG_ACCOUNT (account)->id); g_object_unref (account); return FALSE; } static gboolean ag_manager_must_emit_updated (AgManager *manager, AgAccountChanges *changes) { AgManagerPrivate *priv = manager->priv; /* Don't emit the "updated" signal along with "created" or "deleted" */ if (changes->created || changes->deleted) return FALSE; /* The update-event is emitted whenever any value has been changed on * particular service of account. */ return (priv->service_type != NULL) ? _ag_account_changes_have_service_type (changes, priv->service_type) : FALSE; } static gboolean ag_manager_must_emit_enabled (AgManager *manager, AgAccountChanges *changes) { AgManagerPrivate *priv = manager->priv; /* TODO: the enabled-event is emitted whenever enabled status has changed on * any service or account. This has some possibility for optimization. */ return (priv->service_type != NULL) ? _ag_account_changes_have_enabled (changes) : FALSE; } static void ag_manager_emit_signals (AgManager *manager, AgAccountId account_id, gboolean updated, gboolean enabled, gboolean created, gboolean deleted) { if (updated) g_signal_emit_by_name (manager, "account-updated", account_id); if (enabled) g_signal_emit_by_name (manager, "enabled-event", account_id); if (deleted) g_signal_emit_by_name (manager, "account-deleted", account_id); if (created) g_signal_emit_by_name (manager, "account-created", account_id); } static gboolean check_signal_processed (AgManagerPrivate *priv, struct timespec *ts) { ProcessedSignalData *psd; GList *list; for (list = priv->processed_signals; list != NULL; list = list->next) { psd = list->data; if (psd->ts.tv_sec == ts->tv_sec && psd->ts.tv_nsec == ts->tv_nsec) { DEBUG_INFO ("Signal already processed: %lu-%lu", ts->tv_sec, ts->tv_nsec); return TRUE; } } /* Add the signal to the list of processed ones; this is necessary if the * manager was created for a specific service type, because in that case * we are subscribing for DBus signals on two different object paths (the * one for our service type, and one for the global settings), so we might * get notified about the same signal twice. */ /* Don't keep more than a very few elements in the list */ for (list = g_list_nth (priv->processed_signals, 2); list != NULL; list = g_list_nth (priv->processed_signals, 2)) { priv->processed_signals = g_list_delete_link (priv->processed_signals, list); } psd = g_slice_new (ProcessedSignalData); psd->ts = *ts; priv->processed_signals = g_list_prepend (priv->processed_signals, psd); return FALSE; } /* * checks whether the sender of the message is listed in the object_paths array */ static gboolean object_path_is_interesting (const gchar *msg_object_path, GPtrArray *object_paths) { guint i; /* If the object_paths array is empty, it means that we are * interested in all service types. */ if (object_paths->len == 0) return TRUE; if (G_UNLIKELY (msg_object_path == NULL)) return FALSE; for (i = 0; i < object_paths->len; i++) { const gchar *object_path = g_ptr_array_index (object_paths, i); if (strcmp (msg_object_path, object_path) == 0) return TRUE; } return FALSE; } static void dbus_filter_callback (G_GNUC_UNUSED GDBusConnection *dbus_conn, G_GNUC_UNUSED const gchar *sender_name, const gchar *object_path, G_GNUC_UNUSED const gchar *interface_name, G_GNUC_UNUSED const gchar *signal_name, GVariant *msg, gpointer user_data) { AgManager *manager = AG_MANAGER (user_data); AgManagerPrivate *priv = manager->priv; const gchar *provider_name = NULL; AgAccountId account_id = 0; AgAccount *account; AgAccountChanges *changes; struct timespec ts; gboolean deleted, created; gboolean ours = FALSE; gboolean updated = FALSE; gboolean enabled = FALSE; gboolean must_instantiate = TRUE; GVariant *v_services; GList *list, *node; if (!object_path_is_interesting (object_path, priv->object_paths)) return; memset (&ts, 0, sizeof (struct timespec)); g_variant_get (msg, "(uuubb&s@*)", &ts.tv_sec, &ts.tv_nsec, &account_id, &created, &deleted, &provider_name, &v_services); DEBUG_INFO ("path = %s, time = %lu-%lu (%p)", object_path, ts.tv_sec, ts.tv_nsec, manager); /* Do not process the same signal more than once. */ if (check_signal_processed (priv, &ts)) goto skip_processing; list = priv->emitted_signals; while (list != NULL) { EmittedSignalData *esd = list->data; node = list; list = list->next; if (esd->ts.tv_sec == ts.tv_sec && esd->ts.tv_nsec == ts.tv_nsec) { gboolean must_process = esd->must_process; /* message is ours: we can ignore it, as the changes * were already processed when the DB transaction succeeded. */ ours = TRUE; DEBUG_INFO ("Signal is ours, must_process = %d", esd->must_process); g_slice_free (EmittedSignalData, esd); priv->emitted_signals = g_list_delete_link ( priv->emitted_signals, node); if (!must_process) goto skip_processing; } } /* we must mark our emitted signals for reprocessing, because the current * signal might modify some of the fields that were previously modified by * us. * This ensures that changes coming from different account manager * instances are processed in the right order. */ for (list = priv->emitted_signals; list != NULL; list = list->next) { EmittedSignalData *esd = list->data; DEBUG_INFO ("Marking pending signal for processing"); esd->must_process = TRUE; } changes = _ag_account_changes_from_dbus (manager, v_services, created, deleted); /* check if the account is loaded */ account = g_hash_table_lookup (priv->accounts, GUINT_TO_POINTER (account_id)); if (!account && !created && !deleted) must_instantiate = FALSE; if (ours && (deleted || created)) must_instantiate = FALSE; if (!account && must_instantiate) { /* because of the checks above, this can happen if this is an account * created or deleted from another instance. * We must emit the signals, and cache the newly created account for a * while, because the application is likely to inspect it */ account = g_initable_new (AG_TYPE_ACCOUNT, NULL, NULL, "manager", manager, "provider", provider_name, "id", account_id, "foreign", created, NULL); g_return_if_fail (AG_IS_ACCOUNT (account)); g_object_weak_ref (G_OBJECT (account), account_weak_notify, manager); g_hash_table_insert (priv->accounts, GUINT_TO_POINTER (account_id), account); g_timeout_add_seconds (2, timed_unref_account, account); } if (changes) { updated = ag_manager_must_emit_updated (manager, changes); enabled = ag_manager_must_emit_enabled (manager, changes); if (account) _ag_account_done_changes (account, changes); _ag_account_changes_free (changes); } ag_manager_emit_signals (manager, account_id, updated, enabled, created, deleted); skip_processing: g_variant_unref (v_services); } static void signal_account_changes_on_service_types (AgManager *manager, AgAccountChanges *changes, GVariant *msg) { GPtrArray *service_types; guint i; /* Add a temporary reference to the message parameters, to make * sure that g_dbus_connection_emit_signal() won't steal our * variant. */ g_variant_ref (msg); service_types = _ag_account_changes_get_service_types (changes); for (i = 0; i < service_types->len; i++) { const gchar *service_type; gchar path[256]; gchar *escaped_type; gboolean ret; service_type = g_ptr_array_index(service_types, i); escaped_type = _ag_dbus_escape_as_identifier (service_type); g_snprintf (path, sizeof (path), "%s/%s", AG_DBUS_PATH_SERVICE, escaped_type); g_free (escaped_type); ret = g_dbus_connection_emit_signal (manager->priv->dbus_conn, NULL, path, AG_DBUS_IFACE, AG_DBUS_SIG_CHANGED, msg, NULL); if (G_UNLIKELY (!ret)) g_warning ("Emission of DBus signal failed"); } g_ptr_array_free (service_types, TRUE); g_variant_unref (msg); } static void signal_account_changes (AgManager *manager, AgAccount *account, AgAccountChanges *changes) { AgManagerPrivate *priv = manager->priv; GVariant *msg; EmittedSignalData eds; clock_gettime(CLOCK_MONOTONIC, &eds.ts); msg = _ag_account_build_signal (account, changes, &eds.ts); if (G_UNLIKELY (!msg)) { g_warning ("Creation of D-Bus signal failed"); return; } g_variant_ref_sink (msg); /* emit the signal on all service-types */ signal_account_changes_on_service_types(manager, changes, msg); g_dbus_connection_flush_sync (priv->dbus_conn, NULL, NULL); DEBUG_INFO ("Emitted signal, time: %lu-%lu", eds.ts.tv_sec, eds.ts.tv_nsec); eds.must_process = FALSE; priv->emitted_signals = g_list_prepend (priv->emitted_signals, g_slice_dup (EmittedSignalData, &eds)); g_variant_unref (msg); } static gboolean got_service (sqlite3_stmt *stmt, AgService **p_service) { AgService *service; g_assert (p_service != NULL); service = _ag_service_new (); service->id = sqlite3_column_int (stmt, 0); service->display_name = g_strdup ((gchar *)sqlite3_column_text (stmt, 1)); service->provider = g_strdup ((gchar *)sqlite3_column_text (stmt, 2)); service->type = g_strdup ((gchar *)sqlite3_column_text (stmt, 3)); *p_service = service; return TRUE; } static gboolean got_service_id (sqlite3_stmt *stmt, AgService *service) { g_assert (service != NULL); service->id = sqlite3_column_int (stmt, 0); return TRUE; } static gboolean add_service_to_db (AgManager *manager, AgService *service) { gchar *sql; /* Add the service to the DB */ sql = sqlite3_mprintf ("INSERT INTO Services " "(name, display, provider, type) " "VALUES (%Q, %Q, %Q, %Q);", service->name, service->display_name, service->provider, service->type); _ag_manager_exec_query (manager, NULL, NULL, sql); sqlite3_free (sql); /* The insert statement above might fail in the unlikely case * that in the meantime the same service was inserted by some other * process; so, instead of calling sqlite3_last_insert_rowid(), we * just get the ID with another query. */ sql = sqlite3_mprintf ("SELECT id FROM Services WHERE name = %Q", service->name); _ag_manager_exec_query (manager, (AgQueryCallback)got_service_id, service, sql); sqlite3_free (sql); return service->id != 0; } static gboolean add_id_to_list (sqlite3_stmt *stmt, GList **plist) { gint id; id = sqlite3_column_int (stmt, 0); *plist = g_list_prepend (*plist, GINT_TO_POINTER (id)); return TRUE; } static void account_weak_notify (gpointer userdata, GObject *dead_account) { AgManagerPrivate *priv = AG_MANAGER_PRIV (userdata); GHashTableIter iter; GObject *account; DEBUG_REFS ("called for %p", dead_account); g_hash_table_iter_init (&iter, priv->accounts); while (g_hash_table_iter_next (&iter, NULL, (gpointer)&account)) { if (account == dead_account) { g_hash_table_iter_steal (&iter); break; } } } static void account_weak_unref (GObject *account) { g_object_weak_unref (account, account_weak_notify, ag_account_get_manager (AG_ACCOUNT (account))); } /* * exec_transaction: * * Executes a transaction, assuming that the exclusive lock has been obtained. */ static void exec_transaction (AgManager *manager, AgAccount *account, const gchar *sql, AgAccountChanges *changes, GError **error) { AgManagerPrivate *priv; gchar *err_msg = NULL; int ret; gboolean updated, enabled; DEBUG_LOCKS ("Accounts DB is now locked"); DEBUG_QUERIES ("called: %s", sql); g_return_if_fail (AG_IS_MANAGER (manager)); priv = manager->priv; g_return_if_fail (AG_IS_ACCOUNT (account)); g_return_if_fail (sql != NULL); g_return_if_fail (priv->db != NULL); ret = sqlite3_exec (priv->db, sql, NULL, NULL, &err_msg); if (G_UNLIKELY (ret != SQLITE_OK)) { *error = g_error_new (AG_ACCOUNTS_ERROR, AG_ACCOUNTS_ERROR_DB, "%s", err_msg); if (err_msg) sqlite3_free (err_msg); ret = sqlite3_step (priv->rollback_stmt); if (G_UNLIKELY (ret != SQLITE_OK)) g_warning ("Rollback failed"); sqlite3_reset (priv->rollback_stmt); DEBUG_LOCKS ("Accounts DB is now unlocked"); return; } ret = sqlite3_step (priv->commit_stmt); if (G_UNLIKELY (ret != SQLITE_DONE)) { *error = g_error_new_literal (AG_ACCOUNTS_ERROR, AG_ACCOUNTS_ERROR_DB, sqlite3_errmsg (priv->db)); sqlite3_reset (priv->commit_stmt); return; } sqlite3_reset (priv->commit_stmt); DEBUG_LOCKS ("Accounts DB is now unlocked"); /* everything went well; if this was a new account, we must update the * local data structure */ if (account->id == 0) { account->id = priv->last_account_id; /* insert the account into our cache */ g_object_weak_ref (G_OBJECT (account), account_weak_notify, manager); g_hash_table_insert (priv->accounts, GUINT_TO_POINTER (account->id), account); } /* emit DBus signals to notify other processes */ signal_account_changes (manager, account, changes); updated = ag_manager_must_emit_updated(manager, changes); enabled = ag_manager_must_emit_enabled(manager, changes); _ag_account_done_changes (account, changes); ag_manager_emit_signals (manager, account->id, updated, enabled, changes->created, changes->deleted); } static void store_cb_data_free (StoreCbData *sd) { if (sd->id) g_source_remove (sd->id); g_free (sd->sql); g_slice_free (StoreCbData, sd); } static gboolean exec_transaction_idle (StoreCbData *sd) { AgManager *manager = sd->manager; AgAccount *account = sd->account; AgManagerPrivate *priv; GError *error = NULL; int ret; g_return_val_if_fail (AG_IS_MANAGER (manager), FALSE); priv = manager->priv; g_object_ref (manager); g_object_ref (account); /* If the operation was cancelled, abort it. */ if (sd->cancellable != NULL) { g_cancellable_set_error_if_cancelled (sd->cancellable, &error); if (error != NULL) goto finish; } g_return_val_if_fail (priv->begin_stmt != NULL, FALSE); ret = sqlite3_step (priv->begin_stmt); if (ret == SQLITE_BUSY) { sched_yield (); g_object_unref (account); g_object_unref (manager); return TRUE; /* call this callback again */ } if (ret == SQLITE_DONE) { exec_transaction (manager, account, sd->sql, sd->changes, &error); } else { error = g_error_new_literal (AG_ACCOUNTS_ERROR, AG_ACCOUNTS_ERROR_DB, "Generic error"); } finish: if (error != NULL) { g_simple_async_result_take_error (sd->async_result, error); } _ag_account_store_completed (account, sd->changes); priv->locks = g_list_remove (priv->locks, sd); sd->id = 0; store_cb_data_free (sd); g_object_unref (account); g_object_unref (manager); return FALSE; } static int prepare_transaction_statements (AgManagerPrivate *priv) { int ret; if (G_UNLIKELY (!priv->begin_stmt)) { ret = sqlite3_prepare_v2 (priv->db, "BEGIN EXCLUSIVE;", -1, &priv->begin_stmt, NULL); if (ret != SQLITE_OK) return ret; } else sqlite3_reset (priv->begin_stmt); if (G_UNLIKELY (!priv->commit_stmt)) { ret = sqlite3_prepare_v2 (priv->db, "COMMIT;", -1, &priv->commit_stmt, NULL); if (ret != SQLITE_OK) return ret; } else sqlite3_reset (priv->commit_stmt); if (G_UNLIKELY (!priv->rollback_stmt)) { ret = sqlite3_prepare_v2 (priv->db, "ROLLBACK;", -1, &priv->rollback_stmt, NULL); if (ret != SQLITE_OK) return ret; } else sqlite3_reset (priv->rollback_stmt); return SQLITE_OK; } static void set_last_rowid_as_account_id (sqlite3_context *ctx, G_GNUC_UNUSED int argc, G_GNUC_UNUSED sqlite3_value **argv) { AgManagerPrivate *priv; priv = sqlite3_user_data (ctx); priv->last_account_id = sqlite3_last_insert_rowid (priv->db); sqlite3_result_null (ctx); } static void get_account_id (sqlite3_context *ctx, G_GNUC_UNUSED int argc, G_GNUC_UNUSED sqlite3_value **argv) { AgManagerPrivate *priv; priv = sqlite3_user_data (ctx); sqlite3_result_int64 (ctx, priv->last_account_id); } static void create_functions (AgManagerPrivate *priv) { sqlite3_create_function (priv->db, "set_last_rowid_as_account_id", 0, SQLITE_ANY, priv, set_last_rowid_as_account_id, NULL, NULL); sqlite3_create_function (priv->db, "account_id", 0, SQLITE_ANY, priv, get_account_id, NULL, NULL); } static void setup_db_options (sqlite3 *db) { gchar *error; int ret; error = NULL; ret = sqlite3_exec (db, "PRAGMA synchronous = 1", NULL, NULL, &error); if (ret != SQLITE_OK) { g_warning ("%s: couldn't set synchronous mode (%s)", G_STRFUNC, error); sqlite3_free (error); } error = NULL; ret = sqlite3_exec (db, "PRAGMA journal_mode = " JOURNAL_MODE, NULL, NULL, &error); if (ret != SQLITE_OK) { g_warning ("%s: couldn't set journal mode to " JOURNAL_MODE " (%s)", G_STRFUNC, error); sqlite3_free (error); } } static gint get_db_version (sqlite3 *db) { sqlite3_stmt *stmt; gint version = 0, ret; ret = sqlite3_prepare(db, "PRAGMA user_version", -1, &stmt, NULL); if (G_UNLIKELY(ret != SQLITE_OK)) return 0; ret = sqlite3_step(stmt); if (G_LIKELY(ret == SQLITE_ROW)) version = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); return version; } static gboolean create_db (sqlite3 *db) { const gchar *sql; gchar *error; int ret; sql = "" "CREATE TABLE IF NOT EXISTS Accounts (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "name TEXT," "provider TEXT," "enabled INTEGER);" "CREATE TABLE IF NOT EXISTS Services (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "name TEXT NOT NULL UNIQUE," "display TEXT NOT NULL," /* following fields are included for performance reasons */ "provider TEXT," "type TEXT);" "CREATE INDEX IF NOT EXISTS idx_service ON Services(name);" "CREATE TABLE IF NOT EXISTS Settings (" "account INTEGER NOT NULL," "service INTEGER," "key TEXT NOT NULL," "type TEXT NOT NULL," "value BLOB);" "CREATE UNIQUE INDEX IF NOT EXISTS idx_setting ON Settings " "(account, service, key);" "CREATE TRIGGER IF NOT EXISTS tg_delete_account " "BEFORE DELETE ON Accounts FOR EACH ROW BEGIN " "DELETE FROM Settings WHERE account = OLD.id; " "END;" "CREATE TABLE IF NOT EXISTS Signatures (" "account INTEGER NOT NULL," "service INTEGER," "key TEXT NOT NULL," "signature TEXT NOT NULL," "token TEXT NOT NULL);" "CREATE UNIQUE INDEX IF NOT EXISTS idx_signatures ON Signatures " "(account, service, key);" "PRAGMA user_version = 1;"; error = NULL; ret = sqlite3_exec (db, sql, NULL, NULL, &error); if (ret == SQLITE_BUSY) { guint t; for (t = 5; t < MAX_SQLITE_BUSY_LOOP_TIME_MS; t *= 2) { DEBUG_LOCKS ("Database locked, retrying..."); sched_yield (); g_assert(error != NULL); sqlite3_free (error); ret = sqlite3_exec (db, sql, NULL, NULL, &error); if (ret != SQLITE_BUSY) break; usleep(t * 1000); } } if (ret != SQLITE_OK) { g_warning ("Error initializing DB: %s", error); sqlite3_free (error); return FALSE; } return TRUE; } static inline gboolean file_is_read_only (const gchar *filename) { int fd; /* FIXME: Here we could just use access(); however, because of bug * https://bugs.launchpad.net/bugs/1220713, if the access is blocked by * apparmor the access() call would still report that the file is * writeable. */ fd = open (filename, O_RDWR); if (fd == -1) { if (errno == EACCES || errno == EROFS) return TRUE; } else { close (fd); } return FALSE; } static gboolean open_db (AgManager *manager) { AgManagerPrivate *priv = manager->priv; const gchar *basedir; gchar *filename, *pathname; gint version; gboolean ok = TRUE; int ret, flags; basedir = g_getenv ("ACCOUNTS"); if (G_LIKELY (!basedir)) { basedir = g_get_user_config_dir (); pathname = g_build_path (G_DIR_SEPARATOR_S, basedir, DATABASE_DIR, NULL); if (G_UNLIKELY (g_mkdir_with_parents(pathname, 0755))) g_warning ("Cannot create directory: %s", pathname); filename = g_build_filename (pathname, "accounts.db", NULL); g_free (pathname); } else { filename = g_build_filename (basedir, "accounts.db", NULL); } /* First, check if the file exists and is writeable */ if (file_is_read_only (filename)) { DEBUG_INFO ("Opening DB in read-only mode"); flags = SQLITE_OPEN_READONLY; } else { flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; } ret = sqlite3_open_v2 (filename, &priv->db, flags, NULL); g_free (filename); if (ret != SQLITE_OK) { if (priv->db) { g_warning ("Error opening accounts DB: %s", sqlite3_errmsg (priv->db)); sqlite3_close (priv->db); priv->db = NULL; } return FALSE; } /* TODO: busy handler */ version = get_db_version(priv->db); DEBUG_INFO ("DB version: %d", version); if (version < 1) ok = create_db(priv->db); /* insert here code to upgrade the DB from older versions... */ if (G_UNLIKELY (!ok)) { sqlite3_close (priv->db); priv->db = NULL; return FALSE; } setup_db_options (priv->db); create_functions (priv); return TRUE; } static inline void add_matches (AgManager *manager) { AgManagerPrivate *priv = manager->priv; guint i; for (i = 0; i < priv->object_paths->len; i++) { const gchar *path = g_ptr_array_index(priv->object_paths, i); guint id; id = g_dbus_connection_signal_subscribe (priv->dbus_conn, NULL, AG_DBUS_IFACE, AG_DBUS_SIG_CHANGED, path, NULL, G_DBUS_SIGNAL_FLAGS_NONE, dbus_filter_callback, manager, NULL); priv->subscription_ids = g_slist_prepend (priv->subscription_ids, GUINT_TO_POINTER (id)); } } static inline void add_typeless_match (AgManager *manager) { AgManagerPrivate *priv = manager->priv; guint id; id = g_dbus_connection_signal_subscribe (priv->dbus_conn, NULL, AG_DBUS_IFACE, AG_DBUS_SIG_CHANGED, NULL, NULL, G_DBUS_SIGNAL_FLAGS_NONE, dbus_filter_callback, manager, NULL); priv->subscription_ids = g_slist_prepend (priv->subscription_ids, GUINT_TO_POINTER (id)); } static gboolean setup_dbus (AgManager *manager) { AgManagerPrivate *priv = manager->priv; GError *error = NULL; priv->dbus_conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (G_UNLIKELY (error != NULL)) { g_warning ("Failed to get D-Bus connection (%s)", error->message); g_error_free (error); return FALSE; } if (priv->service_type == NULL) { /* listen to all changes */ add_typeless_match (manager); } else { gchar *escaped_type, *path; /* listen for changes on our service type only */ escaped_type = _ag_dbus_escape_as_identifier (priv->service_type); path = g_strdup_printf (AG_DBUS_PATH_SERVICE "/%s", escaped_type); g_free (escaped_type); g_ptr_array_add (priv->object_paths, path); /* add also the global service type */ g_ptr_array_add (priv->object_paths, g_strdup (AG_DBUS_PATH_SERVICE_GLOBAL)); add_matches (manager); } return TRUE; } static void ag_manager_init (AgManager *manager) { AgManagerPrivate *priv; manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, AG_TYPE_MANAGER, AgManagerPrivate); priv = manager->priv; priv->services = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)ag_service_unref); priv->accounts = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)account_weak_unref); priv->db_timeout = MAX_SQLITE_BUSY_LOOP_TIME_MS; /* 5 seconds */ priv->object_paths = g_ptr_array_new_with_free_func (g_free); } static GObject * ag_manager_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObjectClass *object_class = (GObjectClass *)ag_manager_parent_class; AgManager *manager; GObject *object; object = object_class->constructor (type, n_params, params); g_return_val_if_fail (object != NULL, NULL); manager = AG_MANAGER (object); if (G_UNLIKELY (!open_db (manager) || !setup_dbus (manager))) { g_object_unref (object); return NULL; } return object; } static void ag_manager_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { AgManager *manager = AG_MANAGER (object); AgManagerPrivate *priv = manager->priv; switch (property_id) { case PROP_SERVICE_TYPE: g_value_set_string (value, priv->service_type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ag_manager_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { AgManager *manager = AG_MANAGER (object); AgManagerPrivate *priv = manager->priv; switch (property_id) { case PROP_SERVICE_TYPE: g_assert (priv->service_type == NULL); priv->service_type = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ag_manager_dispose (GObject *object) { AgManagerPrivate *priv = AG_MANAGER_PRIV (object); if (priv->is_disposed) return; priv->is_disposed = TRUE; DEBUG_REFS ("Disposing manager %p", object); while (priv->locks) { store_cb_data_free (priv->locks->data); priv->locks = g_list_delete_link (priv->locks, priv->locks); } if (priv->dbus_conn) { while (priv->subscription_ids) { guint id = GPOINTER_TO_UINT (priv->subscription_ids->data); g_dbus_connection_signal_unsubscribe (priv->dbus_conn, id); priv->subscription_ids = g_slist_delete_link (priv->subscription_ids, priv->subscription_ids); } g_object_unref (priv->dbus_conn); priv->dbus_conn = NULL; } G_OBJECT_CLASS (ag_manager_parent_class)->finalize (object); } static void ag_manager_finalize (GObject *object) { AgManagerPrivate *priv = AG_MANAGER_PRIV (object); g_ptr_array_free (priv->object_paths, TRUE); while (priv->emitted_signals) { g_slice_free (EmittedSignalData, priv->emitted_signals->data); priv->emitted_signals = g_list_delete_link (priv->emitted_signals, priv->emitted_signals); } while (priv->processed_signals) { g_slice_free (ProcessedSignalData, priv->processed_signals->data); priv->processed_signals = g_list_delete_link (priv->processed_signals, priv->processed_signals); } if (priv->begin_stmt) sqlite3_finalize (priv->begin_stmt); if (priv->commit_stmt) sqlite3_finalize (priv->commit_stmt); if (priv->rollback_stmt) sqlite3_finalize (priv->rollback_stmt); if (priv->services) g_hash_table_unref (priv->services); if (priv->accounts) g_hash_table_unref (priv->accounts); if (priv->db) { if (sqlite3_close (priv->db) != SQLITE_OK) g_warning ("Failed to close database: %s", sqlite3_errmsg (priv->db)); priv->db = NULL; } g_free (priv->service_type); if (priv->last_error) g_error_free (priv->last_error); G_OBJECT_CLASS (ag_manager_parent_class)->finalize (object); } static void ag_manager_account_deleted (AgManager *manager, AgAccountId id) { g_return_if_fail (AG_IS_MANAGER (manager)); /* The weak reference is removed automatically when the account is removed * from the hash table */ g_hash_table_remove (manager->priv->accounts, GUINT_TO_POINTER (id)); } static void ag_manager_class_init (AgManagerClass *klass) { GObjectClass* object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (object_class, sizeof (AgManagerPrivate)); klass->account_deleted = ag_manager_account_deleted; object_class->constructor = ag_manager_constructor; object_class->dispose = ag_manager_dispose; object_class->get_property = ag_manager_get_property; object_class->set_property = ag_manager_set_property; object_class->finalize = ag_manager_finalize; /** * AgManager:service-type: * * If the service type is set, certain operations on the #AgManager, such * as ag_manager_list() and ag_manager_list_services(), will be restricted * to only affect accounts or services with that service type. */ g_object_class_install_property (object_class, PROP_SERVICE_TYPE, g_param_spec_string ("service-type", "service type", "Set service type", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); /** * AgManager::account-created: * @manager: the #AgManager. * @account_id: the #AgAccountId of the account that has been created. * * Emitted when a new account has been created; note that the account must * have been stored in the database: the signal is not emitted just in * response to ag_manager_create_account(). */ signals[ACCOUNT_CREATED] = g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); /** * AgManager::enabled-event: * @manager: the #AgManager. * @account_id: the #AgAccountId of the account that has been enabled. * * If the manager has been created with ag_manager_new_for_service_type(), * this signal will be emitted when an account (identified by @account_id) * has been modified in such a way that the application might be interested * to start or stop using it: the "enabled" flag on the account or in some * service supported by the account and matching the * #AgManager:service-type have changed. * In practice, this signal might be emitted more often than when strictly * needed; applications must call ag_account_list_enabled_services() or * ag_manager_list_enabled() to get the current state. */ signals[ACCOUNT_ENABLED] = g_signal_new ("enabled-event", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); /** * AgManager::account-deleted: * @manager: the #AgManager. * @account_id: the #AgAccountId of the account that has been deleted. * * Emitted when an account has been deleted. * This signal is redundant with #AgAccount::deleted, but it is convenient * to provide full change notification with #AgManager. */ signals[ACCOUNT_DELETED] = g_signal_new ("account-deleted", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (AgManagerClass, account_deleted), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); /** * AgManager::account-updated: * @manager: the #AgManager. * @account_id: the #AgAccountId of the account that has been update. * * Emitted when particular service of an account has been updated. * This signal is redundant with #AgAccount::deleted, but it is convenient * to provide full change notification with #AgManager. */ signals[ACCOUNT_UPDATED] = g_signal_new ("account-updated", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); _ag_debug_init(); } /** * ag_manager_new: * * Create a new #AgManager. * * Returns: an instance of an #AgManager. */ AgManager * ag_manager_new () { return g_object_new (AG_TYPE_MANAGER, NULL); } GList * _ag_manager_list_all (AgManager *manager) { GList *list = NULL; const gchar *sql; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); sql = "SELECT id FROM Accounts;"; _ag_manager_exec_query (manager, (AgQueryCallback)add_id_to_list, &list, sql); return list; } void _ag_manager_take_error (AgManager *manager, GError *error) { AgManagerPrivate *priv; g_return_if_fail (AG_IS_MANAGER (manager)); priv = manager->priv; if (priv->last_error) g_error_free (priv->last_error); priv->last_error = error; } const GError * _ag_manager_get_last_error (AgManager *manager) { g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); return manager->priv->last_error; } /** * ag_manager_list: * @manager: the #AgManager. * * Lists the accounts. If the #AgManager is created with a specified * #AgManager:service-type, it will return only the accounts supporting this * service type. * * Returns: (transfer full) (element-type AgAccountId): a #GList of * #AgAccountId representing the accounts. Must be free'd with * ag_manager_list_free() when no longer required. */ GList * ag_manager_list (AgManager *manager) { AgManagerPrivate *priv; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); priv = manager->priv; if (priv->service_type) return ag_manager_list_by_service_type (manager, priv->service_type); return _ag_manager_list_all (manager); } /** * ag_manager_list_by_service_type: * @manager: the #AgManager. * @service_type: the name of the service type to check for. * * Lists the accounts supporting the given service type. * * Returns: (transfer full) (element-type AgAccountId): a #GList of * #AgAccountId representing the accounts. Must be free'd with * ag_manager_list_free() when no longer required. */ GList * ag_manager_list_by_service_type (AgManager *manager, const gchar *service_type) { GList *list = NULL; char sql[512]; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); sqlite3_snprintf (sizeof (sql), sql, "SELECT id FROM Accounts WHERE provider IN (" "SELECT provider FROM Services WHERE type = %Q);", service_type); _ag_manager_exec_query (manager, (AgQueryCallback)add_id_to_list, &list, sql); return list; } /** * ag_manager_list_enabled: * @manager: the #AgManager. * * Lists the enabled accounts. * * Returns: (transfer full) (element-type AgAccountId): a #GList of the enabled * #AgAccountId representing the accounts. Must be free'd with * ag_manager_list_free() when no longer required. */ GList * ag_manager_list_enabled (AgManager *manager) { GList *list = NULL; char sql[512]; AgManagerPrivate *priv; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); priv = manager->priv; if (priv->service_type == NULL) { sqlite3_snprintf (sizeof (sql), sql, "SELECT id FROM Accounts WHERE enabled=1;"); _ag_manager_exec_query (manager, (AgQueryCallback)add_id_to_list, &list, sql); } else { list = ag_manager_list_enabled_by_service_type(manager, priv->service_type); } return list; } /** * ag_manager_list_enabled_by_service_type: * @manager: the #AgManager. * @service_type: the name of the service type to check for. * * Lists the enabled accounts supporting the given service type. * * Returns: (transfer full) (element-type AgAccountId): a #GList of the enabled * #AgAccountId representing the accounts. Must be free'd with * ag_manager_list_free() when no longer required. */ GList * ag_manager_list_enabled_by_service_type (AgManager *manager, const gchar *service_type) { GList *list = NULL; char sql[512]; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); g_return_val_if_fail (service_type != NULL, NULL); sqlite3_snprintf (sizeof (sql), sql, "SELECT Settings.account FROM Settings " "INNER JOIN Services ON Settings.service = Services.id " "WHERE Settings.key='enabled' AND Settings.value='true' " "AND Services.type = %Q AND Settings.account IN " "(SELECT id FROM Accounts WHERE enabled=1);", service_type); _ag_manager_exec_query (manager, (AgQueryCallback)add_id_to_list, &list, sql); return list; } /** * ag_manager_list_free: * @list: (element-type AgAccountId): a #GList returned from a #AgManager * method which returns account IDs. * * Frees the memory taken by a #GList of #AgAccountId allocated by #AgManager, * such as by ag_manager_list(), ag_manager_list_enabled() or * ag_manager_list_enabled_by_service_type(). */ void ag_manager_list_free (GList *list) { g_list_free (list); } /** * ag_manager_get_enabled_account_services: * @manager: the #AgManager. * * Gets all the enabled account services. If the @manager was created for a * specific service type, only services with that type will be returned. * * * This method causes the loading of all the service settings for all the * returned accounts (unless they have been loaded previously). If you are * interested in a specific account/service, consider using * ag_manager_load_account() to first load the the account, and then create * the AgAccountService for that account only. * * * * Returns: (transfer full) (element-type AgAccountService): a list of * #AgAccountService objects. When done with it, call g_object_unref() on the * list elements, and g_list_free() on the container. */ GList * ag_manager_get_enabled_account_services (AgManager *manager) { GList *account_ids, *account_services; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); account_ids = ag_manager_list_enabled (manager); account_services = get_account_services_from_accounts (manager, account_ids, TRUE); ag_manager_list_free (account_ids); return account_services; } /** * ag_manager_get_account_services: * @manager: the #AgManager. * * Gets all the account services. If the @manager was created for a * specific service type, only services with that type will be returned. * * * This method causes the loading of all the service settings for all the * returned accounts (unless they have been loaded previously). If you are * interested in a specific account/service, consider using * ag_manager_load_account() to first load the the account, and then create * the AgAccountService for that account only. * * * * Returns: (transfer full) (element-type AgAccountService): a list of * #AgAccountService objects. When done with it, call g_object_unref() on the * list elements, and g_list_free() on the container. */ GList * ag_manager_get_account_services (AgManager *manager) { GList *account_ids, *account_services; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); account_ids = ag_manager_list (manager); account_services = get_account_services_from_accounts (manager, account_ids, FALSE); ag_manager_list_free (account_ids); return account_services; } /** * ag_manager_get_account: * @manager: the #AgManager. * @account_id: the #AgAccountId of the account. * * Instantiates the object representing the account identified by * @account_id. * * Returns: (transfer full): an #AgAccount, on which the client must call * g_object_unref() when it is no longer required, or %NULL if an error occurs. */ AgAccount * ag_manager_get_account (AgManager *manager, AgAccountId account_id) { return ag_manager_load_account (manager, account_id, NULL); } /** * ag_manager_load_account: * @manager: the #AgManager. * @account_id: the #AgAccountId of the account. * @error: pointer to a #GError, or %NULL. * * Instantiates the object representing the account identified by * @account_id. * * Returns: (transfer full): an #AgAccount, on which the client must call * g_object_unref() when it is no longer required, or %NULL if an error occurs. */ AgAccount * ag_manager_load_account (AgManager *manager, AgAccountId account_id, GError **error) { AgManagerPrivate *priv; AgAccount *account; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); g_return_val_if_fail (account_id != 0, NULL); priv = manager->priv; account = g_hash_table_lookup (priv->accounts, GUINT_TO_POINTER (account_id)); if (account) return g_object_ref (account); /* the account is not loaded; do it now */ account = g_initable_new (AG_TYPE_ACCOUNT, NULL, error, "manager", manager, "id", account_id, NULL); if (G_LIKELY (account)) { g_object_weak_ref (G_OBJECT (account), account_weak_notify, manager); g_hash_table_insert (priv->accounts, GUINT_TO_POINTER (account_id), account); } return account; } /** * ag_manager_create_account: * @manager: the #AgManager. * @provider_name: name of the provider of the account. * * Create a new account. The account is not stored in the database until * ag_account_store() has successfully returned; the @id field in the * #AgAccount structure is also not meant to be valid until the account has * been stored. * * Returns: (transfer full): a new #AgAccount, or %NULL. */ AgAccount * ag_manager_create_account (AgManager *manager, const gchar *provider_name) { AgAccount *account; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); account = g_initable_new (AG_TYPE_ACCOUNT, NULL, NULL, "manager", manager, "provider", provider_name, NULL); return account; } /* This is called when creating AgService objects from inside the DBus * handler: we don't want to access the Db from there */ AgService * _ag_manager_get_service_lazy (AgManager *manager, const gchar *service_name, const gchar *service_type, const gint service_id) { AgManagerPrivate *priv; AgService *service; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); g_return_val_if_fail (service_name != NULL, NULL); priv = manager->priv; service = g_hash_table_lookup (priv->services, service_name); if (service) { if (service->id == 0) service->id = service_id; return ag_service_ref (service); } service = _ag_service_new_from_memory (service_name, service_type, service_id); g_hash_table_insert (priv->services, service->name, service); return ag_service_ref (service); } /** * ag_manager_get_service: * @manager: the #AgManager. * @service_name: the name of the service. * * Loads the service identified by @service_name. * * Returns: an #AgService, which must be free'd with ag_service_unref() when no * longer required. */ AgService * ag_manager_get_service (AgManager *manager, const gchar *service_name) { AgManagerPrivate *priv; AgService *service; gchar *sql; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); g_return_val_if_fail (service_name != NULL, NULL); priv = manager->priv; service = g_hash_table_lookup (priv->services, service_name); if (service) return ag_service_ref (service); /* First, check if the service is in the DB */ sql = sqlite3_mprintf ("SELECT id, display, provider, type " "FROM Services WHERE name = %Q", service_name); _ag_manager_exec_query (manager, (AgQueryCallback)got_service, &service, sql); sqlite3_free (sql); if (service) { /* the basic server data have been loaded from the DB; the service name * is still missing, though */ service->name = g_strdup (service_name); } else { /* The service is not in the DB: it must be loaded */ service = _ag_service_new_from_file (service_name); if (service && !add_service_to_db (manager, service)) { g_warning ("Error in adding service %s to DB!", service_name); ag_service_unref (service); service = NULL; } } if (G_UNLIKELY (!service)) return NULL; g_hash_table_insert (priv->services, service->name, service); return ag_service_ref (service); } guint _ag_manager_get_service_id (AgManager *manager, AgService *service) { g_return_val_if_fail (AG_IS_MANAGER (manager), 0); if (service == NULL) return 0; /* global service */ if (service->id == 0) { gchar *sql; gint rows; /* We got this service name from another process; load the id from the * DB - it must already exist */ sql = sqlite3_mprintf ("SELECT id FROM Services WHERE name = %Q", service->name); rows = _ag_manager_exec_query (manager, (AgQueryCallback)got_service_id, service, sql); sqlite3_free (sql); if (G_UNLIKELY (rows != 1)) { g_warning ("%s: got %d rows when asking for service %s", G_STRFUNC, rows, service->name); } } return service->id; } /** * ag_manager_list_services: * @manager: the #AgManager. * * Gets a list of all the installed services. * If the #AgManager was created with a specified #AgManager:service_type * it will return only the installed services supporting that service type. * * Returns: (transfer full) (element-type AgService): a list of #AgService, * which must be free'd with ag_service_list_free() when no longer required. */ GList * ag_manager_list_services (AgManager *manager) { AgManagerPrivate *priv; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); priv = manager->priv; if (priv->service_type) return ag_manager_list_services_by_type (manager, priv->service_type); return _ag_services_list (manager); } /** * ag_manager_list_services_by_type: * @manager: the #AgManager. * @service_type: the type of the service. * * Gets a list of all the installed services where the service type name is * @service_type. * * Returns: (transfer full) (element-type AgService): a list of #AgService, * which must be free'd with ag_service_list_free() when no longer required. */ GList * ag_manager_list_services_by_type (AgManager *manager, const gchar *service_type) { GList *all_services, *list; GList *services = NULL; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); g_return_val_if_fail (service_type != NULL, NULL); /* if we kept the DB Service table always up-to-date with all known * services, then we could just run a query over it. But while we are not, * it's simpler to implement the function by reusing the output from * _ag_services_list(manager). */ all_services = _ag_services_list (manager); for (list = all_services; list != NULL; list = list->next) { AgService *service = list->data; const gchar *serviceType = ag_service_get_service_type (service); if (serviceType && strcmp (serviceType, service_type) == 0) { services = g_list_prepend (services, service); } else ag_service_unref (service); } g_list_free (all_services); return services; } static GError * sqlite_error_to_gerror (int db_error, sqlite3 *db) { AgAccountsError code = (db_error == SQLITE_READONLY) ? AG_ACCOUNTS_ERROR_READONLY : AG_ACCOUNTS_ERROR_DB; return g_error_new (AG_ACCOUNTS_ERROR, code, "Got error: %s (%d)", sqlite3_errmsg (db), db_error); } void _ag_manager_exec_transaction (AgManager *manager, const gchar *sql, AgAccountChanges *changes, AgAccount *account, GSimpleAsyncResult *async_result, GCancellable *cancellable) { AgManagerPrivate *priv = manager->priv; GError *error = NULL; int ret; ret = prepare_transaction_statements (priv); if (G_UNLIKELY (ret != SQLITE_OK)) { error = sqlite_error_to_gerror (ret, priv->db); goto finish; } ret = sqlite3_step (priv->begin_stmt); if (ret == SQLITE_BUSY) { StoreCbData *sd; sd = g_slice_new (StoreCbData); sd->manager = manager; sd->account = account; sd->changes = changes; sd->async_result = async_result; sd->cancellable = cancellable; sd->sql = g_strdup (sql); sd->id = g_idle_add ((GSourceFunc)exec_transaction_idle, sd); priv->locks = g_list_prepend (priv->locks, sd); return; } if (ret != SQLITE_DONE) { error = sqlite_error_to_gerror (ret, priv->db); goto finish; } exec_transaction (manager, account, sql, changes, &error); finish: if (error != NULL) { g_simple_async_result_take_error (async_result, error); } _ag_account_store_completed (account, changes); } void _ag_manager_exec_transaction_blocking (AgManager *manager, const gchar *sql, AgAccountChanges *changes, AgAccount *account, GError **error) { AgManagerPrivate *priv = manager->priv; gint sleep_ms = 200; int ret; ret = prepare_transaction_statements (priv); if (G_UNLIKELY (ret != SQLITE_OK)) { *error = sqlite_error_to_gerror (ret, priv->db); return; } ret = sqlite3_step (priv->begin_stmt); while (ret == SQLITE_BUSY) { /* TODO: instead of this loop, use a semaphore or some other non * polling mechanism */ if (sleep_ms > 30000) { DEBUG_LOCKS ("Database locked for more than 30 seconds; " "giving up!"); break; } DEBUG_LOCKS ("Database locked, sleeping for %ums", sleep_ms); g_usleep (sleep_ms * 1000); sleep_ms *= 2; ret = sqlite3_step (priv->begin_stmt); } if (ret != SQLITE_DONE) { *error = sqlite_error_to_gerror (ret, priv->db); return; } exec_transaction (manager, account, sql, changes, error); } static guint timespec_diff_ms(struct timespec *ts1, struct timespec *ts0) { return (ts1->tv_sec - ts0->tv_sec) * 1000 + (ts1->tv_nsec - ts0->tv_nsec) / 1000000; } /* Executes an SQL statement, and optionally calls * the callback for every row of the result. * Returns the number of rows fetched. */ gint _ag_manager_exec_query (AgManager *manager, AgQueryCallback callback, gpointer user_data, const gchar *sql) { sqlite3 *db; int ret; sqlite3_stmt *stmt; struct timespec ts0, ts1; gint rows = 0; g_return_val_if_fail (AG_IS_MANAGER (manager), 0); db = manager->priv->db; g_return_val_if_fail (db != NULL, 0); ret = sqlite3_prepare_v2 (db, sql, -1, &stmt, NULL); if (ret != SQLITE_OK) { g_warning ("%s: can't compile SQL statement \"%s\": %s", G_STRFUNC, sql, sqlite3_errmsg (db)); return 0; } DEBUG_QUERIES ("about to run:\n%s", sql); /* get the current time, to abort the operation in case the DB is locked * for longer than db_timeout. */ clock_gettime(CLOCK_MONOTONIC, &ts0); do { ret = sqlite3_step (stmt); switch (ret) { case SQLITE_DONE: break; case SQLITE_ROW: if (callback == NULL || callback (stmt, user_data)) { rows++; } break; case SQLITE_BUSY: clock_gettime(CLOCK_MONOTONIC, &ts1); if (timespec_diff_ms(&ts1, &ts0) < manager->priv->db_timeout) { /* If timeout was specified and table is locked, * wait instead of executing default runtime * error action. Otherwise, fall through to it. */ sched_yield (); break; } default: set_error_from_db (manager); g_warning ("%s: runtime error while executing \"%s\": %s", G_STRFUNC, sql, sqlite3_errmsg (db)); sqlite3_finalize (stmt); return rows; } } while (ret != SQLITE_DONE); sqlite3_finalize (stmt); return rows; } /** * ag_manager_get_provider: * @manager: the #AgManager. * @provider_name: the name of the provider. * * Loads the provider identified by @provider_name. * * Returns: an #AgProvider, which must be free'd with ag_provider_unref() when * no longer required. */ AgProvider * ag_manager_get_provider (AgManager *manager, const gchar *provider_name) { g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); g_return_val_if_fail (provider_name != NULL, NULL); /* We don't implement any caching mechanism for AgProvider structures: they * shouldn't be loaded that often. */ return _ag_provider_new_from_file (provider_name); } /** * ag_manager_list_providers: * @manager: the #AgManager. * * Gets a list of all the installed providers. * * Returns: (transfer full) (element-type AgProvider): a list of #AgProvider, * which must be then free'd with ag_provider_list_free(). */ GList * ag_manager_list_providers (AgManager *manager) { g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); return _ag_providers_list (manager); } /** * ag_manager_new_for_service_type: * @service_type: the name of a service type * * Create a new #AgManager with the service type with the name @service_type. * * Returns: an #AgManager instance with the specified service type. */ AgManager * ag_manager_new_for_service_type (const gchar *service_type) { AgManager *manager; g_return_val_if_fail (service_type != NULL, NULL); manager = g_object_new (AG_TYPE_MANAGER, "service-type", service_type, NULL); g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); return manager; } /** * ag_manager_get_service_type: * @manager: the #AgManager. * * Get the service type for @manager. * * Returns: the name of the service type for the supplied @manager. */ const gchar * ag_manager_get_service_type (AgManager *manager) { g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); return manager->priv->service_type; } /** * ag_manager_set_db_timeout: * @manager: the #AgManager. * @timeout_ms: the new timeout, in milliseconds. * * Sets the timeout for database operations. This tells the library how long * it is allowed to block while waiting for a locked DB to become accessible. * Higher values mean a higher chance of successful reads, but also mean that * the execution might be blocked for a longer time. * The default is 5 seconds. */ void ag_manager_set_db_timeout (AgManager *manager, guint timeout_ms) { g_return_if_fail (AG_IS_MANAGER (manager)); manager->priv->db_timeout = timeout_ms; } /** * ag_manager_get_db_timeout: * @manager: the #AgManager. * * Get the timeout of database operations for @manager, in milliseconds. * * Returns: the timeout (in milliseconds) for database operations. */ guint ag_manager_get_db_timeout (AgManager *manager) { g_return_val_if_fail (AG_IS_MANAGER (manager), 0); return manager->priv->db_timeout; } /** * ag_manager_set_abort_on_db_timeout: * @manager: the #AgManager. * @abort: whether to abort when a DB timeout occurs. * * Tells libaccounts whether it should make the client application abort when * a timeout error occurs. The default is %FALSE. */ void ag_manager_set_abort_on_db_timeout (AgManager *manager, gboolean abort) { g_return_if_fail (AG_IS_MANAGER (manager)); manager->priv->abort_on_db_timeout = abort; } /** * ag_manager_get_abort_on_db_timeout: * @manager: the #AgManager. * * Get whether the library will abort when a timeout error occurs. * * Returns: %TRUE is the library will abort when a timeout error occurs, %FALSE * otherwise. */ gboolean ag_manager_get_abort_on_db_timeout (AgManager *manager) { g_return_val_if_fail (AG_IS_MANAGER (manager), FALSE); return manager->priv->abort_on_db_timeout; } /** * ag_manager_list_service_types: * @manager: the #AgManager. * * Gets a list of all the installed service types. * * Returns: (transfer full) (element-type AgServiceType): a list of * #AgServiceType, which must be free'd with ag_service_type_list_free() when * no longer required. */ GList * ag_manager_list_service_types (AgManager *manager) { g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); return _ag_service_types_list (manager); } /** * ag_manager_load_service_type: * @manager: the #AgManager. * @service_type: the name of the service type. * * Instantiate the service type with the name @service_type. * * Returns: (transfer full): an #AgServiceType, which must be free'd with * ag_service_type_unref() when no longer required. */ AgServiceType * ag_manager_load_service_type (AgManager *manager, const gchar *service_type) { g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); /* Given the small size of the service type file, and the unlikely need to * load them more than once, we don't cache them in the manager. But this * might change in the future. */ return _ag_service_type_new_from_file (service_type); } /** * ag_manager_list_applications_by_service: * @manager: the #AgManager. * @service: the #AgService for which we want to get the applications list. * * Lists the registered applications which support the given service. * * Returns: (transfer full) (element-type AgApplication): a #GList of all the * applications which have declared support for the given service or for its * service type. */ GList * ag_manager_list_applications_by_service (AgManager *manager, AgService *service) { GList *applications = NULL; GList *all_applications, *list; g_return_val_if_fail (AG_IS_MANAGER (manager), NULL); g_return_val_if_fail (service != NULL, NULL); all_applications = _ag_applications_list (manager); for (list = all_applications; list != NULL; list = list->next) { AgApplication *application = list->data; if (_ag_application_supports_service (application, service)) { applications = g_list_prepend (applications, application); } else { ag_application_unref (application); } } g_list_free (all_applications); return applications; } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-errors.h0000644000015000001560000000510012245170671024645 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012-2013 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_ERRORS_H_ #define _AG_ERRORS_H_ #include G_BEGIN_DECLS GQuark ag_errors_quark (void); GQuark ag_accounts_error_quark (void); #define AG_ERRORS ag_errors_quark () /** * AG_ACCOUNTS_ERROR: * * Error domain for libaccounts-glib errors. Errors in this domain will be from * the AgAccountsError enumeration. */ #define AG_ACCOUNTS_ERROR AG_ERRORS typedef enum { AG_ERROR_DB, AG_ERROR_DISPOSED, AG_ERROR_DELETED, AG_ERROR_DB_LOCKED, AG_ERROR_ACCOUNT_NOT_FOUND, } AgError; /** * AgAccountsError: * @AG_ACCOUNTS_ERROR_DB: there was an error accessing the accounts database * @AG_ACCOUNTS_ERROR_DISPOSED: the account was in the process of being * disposed * @AG_ACCOUNTS_ERROR_DELETED: the account was in the process of being deleted * @AG_ACCOUNTS_ERROR_DB_LOCKED: the database was locked * @AG_ACCOUNTS_ERROR_ACCOUNT_NOT_FOUND: the requested account was not found * @AG_ACCOUNTS_ERROR_STORE_IN_PROGRESS: an asynchronous store operation is * already in progress. Since 1.4 * @AG_ACCOUNTS_ERROR_READONLY: the accounts DB is in read-only mode. Since 1.4 * * These identify the various errors that can occur with methods in * libaccounts-glib that return a #GError. */ typedef enum { AG_ACCOUNTS_ERROR_DB = AG_ERROR_DB, AG_ACCOUNTS_ERROR_DISPOSED = AG_ERROR_DISPOSED, AG_ACCOUNTS_ERROR_DELETED = AG_ERROR_DELETED, AG_ACCOUNTS_ERROR_DB_LOCKED = AG_ERROR_DB_LOCKED, AG_ACCOUNTS_ERROR_ACCOUNT_NOT_FOUND = AG_ERROR_ACCOUNT_NOT_FOUND, AG_ACCOUNTS_ERROR_STORE_IN_PROGRESS, AG_ACCOUNTS_ERROR_READONLY, } AgAccountsError; G_END_DECLS #endif /* _AG_ERRORS_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-service-type.h0000644000015000001560000000426612245170671025764 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * Copyright (C) 2012 Intel Corporation. * * Contact: Alberto Mardegan * Contact: Jussi Laako * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_SERVICE_TYPE_H_ #define _AG_SERVICE_TYPE_H_ #include #include #include G_BEGIN_DECLS GType ag_service_type_get_type (void) G_GNUC_CONST; const gchar *ag_service_type_get_name (AgServiceType *service_type); const gchar *ag_service_type_get_i18n_domain (AgServiceType *service_type); const gchar *ag_service_type_get_display_name (AgServiceType *service_type); const gchar *ag_service_type_get_description (AgServiceType *service_type); const gchar *ag_service_type_get_icon_name (AgServiceType *service_type); gboolean ag_service_type_has_tag (AgServiceType *service_type, const gchar *tag); GList *ag_service_type_get_tags (AgServiceType *service_type); void ag_service_type_get_file_contents (AgServiceType *service_type, const gchar **contents, gsize *len); AgServiceType *ag_service_type_ref (AgServiceType *service_type); void ag_service_type_unref (AgServiceType *service_type); void ag_service_type_list_free (GList *list); G_END_DECLS #endif /* _AG_SERVICE_TYPE_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-service.c0000644000015000001560000004073112245170671024775 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * Copyright (C) 2012 Intel Corporation. * * Contact: Alberto Mardegan * Contact: Jussi Laako * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** * SECTION:ag-service * @short_description: A representation of a service. * @include: libaccounts-glib/ag-service.h * * The #AgService structure represents a service. The structure is not directly * exposed to applications, but its fields are accessible via getter methods. * It is instantiated by #AgManager, with ag_manager_get_service(), * ag_manager_list_services() or ag_manager_list_services_by_type(). * The structure is reference counted. One must use ag_service_unref() when * done with it. */ #include "config.h" #include "ag-service.h" #include "ag-service-type.h" #include "ag-internals.h" #include "ag-util.h" #include #include G_DEFINE_BOXED_TYPE (AgService, ag_service, (GBoxedCopyFunc)ag_service_ref, (GBoxedFreeFunc)ag_service_unref); static gboolean parse_template (xmlTextReaderPtr reader, AgService *service) { GHashTable *settings; gboolean ok; g_return_val_if_fail (service->default_settings == NULL, FALSE); settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); ok = _ag_xml_parse_settings (reader, "", settings); if (G_UNLIKELY (!ok)) { g_hash_table_destroy (settings); return FALSE; } service->default_settings = settings; return TRUE; } static gboolean parse_preview (G_GNUC_UNUSED xmlTextReaderPtr reader, G_GNUC_UNUSED AgService *service) { /* TODO: implement */ return TRUE; } static gboolean parse_service (xmlTextReaderPtr reader, AgService *service) { const gchar *name; int ret, type; if (!service->name) { xmlChar *_name = xmlTextReaderGetAttribute (reader, (xmlChar *) "id"); service->name = g_strdup ((const gchar *)_name); if (_name) xmlFree(_name); } ret = xmlTextReaderRead (reader); while (ret == 1) { name = (const gchar *)xmlTextReaderConstName (reader); if (G_UNLIKELY (!name)) return FALSE; type = xmlTextReaderNodeType (reader); if (type == XML_READER_TYPE_END_ELEMENT && strcmp (name, "service") == 0) break; if (type == XML_READER_TYPE_ELEMENT) { gboolean ok; if (strcmp (name, "type") == 0 && !service->type) { ok = _ag_xml_dup_element_data (reader, &service->type); } else if (strcmp (name, "name") == 0 && !service->display_name) { ok = _ag_xml_dup_element_data (reader, &service->display_name); } else if (strcmp (name, "description") == 0) { ok = _ag_xml_dup_element_data (reader, &service->description); } else if (strcmp (name, "provider") == 0 && !service->provider) { ok = _ag_xml_dup_element_data (reader, &service->provider); } else if (strcmp (name, "icon") == 0) { ok = _ag_xml_dup_element_data (reader, &service->icon_name); } else if (strcmp (name, "translations") == 0) { ok = _ag_xml_dup_element_data (reader, &service->i18n_domain); } else if (strcmp (name, "template") == 0) { ok = parse_template (reader, service); } else if (strcmp (name, "preview") == 0) { ok = parse_preview (reader, service); } else if (strcmp (name, "type_data") == 0) { static const gchar element[] = " 0) { if (strncmp (service->file_data + offset, element, sizeof (element)) == 0) { service->type_data_offset = offset; break; } offset--; } /* this element is placed after all the elements we are * interested in: we can stop the parsing now */ return TRUE; } else if (strcmp (name, "tags") == 0) { ok = _ag_xml_parse_element_list (reader, "tag", &service->tags); } else ok = TRUE; if (G_UNLIKELY (!ok)) return FALSE; } ret = xmlTextReaderNext (reader); } return TRUE; } static gboolean read_service_file (xmlTextReaderPtr reader, AgService *service) { const xmlChar *name; int ret; ret = xmlTextReaderRead (reader); while (ret == 1) { name = xmlTextReaderConstName (reader); if (G_LIKELY (name && strcmp ((const gchar *)name, "service") == 0)) { return parse_service (reader, service); } ret = xmlTextReaderNext (reader); } return FALSE; } static void copy_tags_from_type (AgService *service) { AgServiceType *type; GList *type_tags, *tag_list; service->tags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); type = _ag_service_type_new_from_file (service->type); if (G_UNLIKELY (type == NULL)) return; type_tags = ag_service_type_get_tags (type); for (tag_list = type_tags; tag_list != NULL; tag_list = tag_list->next) g_hash_table_insert (service->tags, g_strdup (tag_list->data), NULL); g_list_free (type_tags); ag_service_type_unref (type); } AgService * _ag_service_new (void) { AgService *service; service = g_slice_new0 (AgService); service->ref_count = 1; return service; } static gboolean _ag_service_load_from_file (AgService *service) { xmlTextReaderPtr reader; gchar *filepath; gboolean ret; GError *error = NULL; gsize len; g_return_val_if_fail (service->name != NULL, FALSE); DEBUG_REFS ("Loading service %s", service->name); filepath = _ag_find_libaccounts_file (service->name, ".service", "AG_SERVICES", SERVICE_FILES_DIR); if (G_UNLIKELY (!filepath)) return FALSE; g_file_get_contents (filepath, &service->file_data, &len, &error); if (G_UNLIKELY (error)) { g_warning ("Error reading %s: %s", filepath, error->message); g_error_free (error); g_free (filepath); return FALSE; } /* TODO: cache the xmlReader */ reader = xmlReaderForMemory (service->file_data, len, filepath, NULL, 0); g_free (filepath); if (G_UNLIKELY (reader == NULL)) return FALSE; ret = read_service_file (reader, service); xmlFreeTextReader (reader); return ret; } AgService * _ag_service_new_from_file (const gchar *service_name) { AgService *service; service = _ag_service_new (); service->name = g_strdup (service_name); if (!_ag_service_load_from_file (service)) { ag_service_unref (service); service = NULL; } return service; } AgService * _ag_service_new_from_memory (const gchar *service_name, const gchar *service_type, const gint service_id) { AgService *service; service = _ag_service_new (); service->name = g_strdup (service_name); service->type = g_strdup (service_type); service->id = service_id; return service; } GHashTable * _ag_service_load_default_settings (AgService *service) { g_return_val_if_fail (service != NULL, NULL); if (!service->default_settings) { /* This can happen if the service was created by the AccountManager by * loading the record from the DB. * Now we must reload the service from its XML file. */ if (!_ag_service_load_from_file (service)) { g_warning ("Loading service %s file failed", service->name); return NULL; } } return service->default_settings; } GVariant * _ag_service_get_default_setting (AgService *service, const gchar *key) { GHashTable *settings; g_return_val_if_fail (key != NULL, NULL); settings = _ag_service_load_default_settings (service); if (G_UNLIKELY (!settings)) return NULL; return g_hash_table_lookup (settings, key); } /** * ag_service_get_name: * @service: the #AgService. * * Gets the name of the #AgService. * * Returns: the name of @service. */ const gchar * ag_service_get_name (AgService *service) { g_return_val_if_fail (service != NULL, NULL); return service->name; } /** * ag_service_get_display_name: * @service: the #AgService. * * Gets the display name of the #AgService. * * Returns: the display name of @service. */ const gchar * ag_service_get_display_name (AgService *service) { g_return_val_if_fail (service != NULL, NULL); if (service->display_name == NULL && !service->file_data) _ag_service_load_from_file (service); return service->display_name; } /** * ag_service_get_description: * @service: the #AgService. * * Gets the description of the #AgService. * * Returns: the description of @service, or %NULL upon failure. * * Since: 1.2 */ const gchar * ag_service_get_description (AgService *service) { g_return_val_if_fail (service != NULL, NULL); if (service->description == NULL && !service->file_data) _ag_service_load_from_file (service); return service->description; } /** * ag_service_get_service_type: * @service: the #AgService. * * Gets the service type of the #AgService. * * Returns: the type of @service. */ const gchar * ag_service_get_service_type (AgService *service) { g_return_val_if_fail (service != NULL, NULL); if (service->type == NULL && !service->file_data) _ag_service_load_from_file (service); return service->type; } /** * ag_service_get_provider: * @service: the #AgService. * * Gets the provider name of the #AgService. * * Returns: the name of the provider of @service. */ const gchar * ag_service_get_provider (AgService *service) { g_return_val_if_fail (service != NULL, NULL); if (service->provider == NULL && !service->file_data) _ag_service_load_from_file (service); return service->provider; } /** * ag_service_get_icon_name: * @service: the #AgService. * * Gets the icon name of the #AgService. * * Returns: the name of the icon of @service. */ const gchar * ag_service_get_icon_name (AgService *service) { g_return_val_if_fail (service != NULL, NULL); if (!service->file_data) _ag_service_load_from_file (service); return service->icon_name; } /** * ag_service_get_i18n_domain: * @service: the #AgService. * * Gets the translation domain of the #AgService. * * Returns: the name of the translation catalog. */ const gchar * ag_service_get_i18n_domain (AgService *service) { g_return_val_if_fail (service != NULL, NULL); if (!service->file_data) _ag_service_load_from_file (service); return service->i18n_domain; } /** * ag_service_has_tag: * @service: the #AgService. * @tag: tag to check for. * * Checks if the #AgService has the requested tag. * * Returns: TRUE if #AgService has the tag, FALSE otherwise */ gboolean ag_service_has_tag (AgService *service, const gchar *tag) { g_return_val_if_fail (service != NULL, FALSE); if (!service->file_data) _ag_service_load_from_file (service); if (service->tags == NULL) copy_tags_from_type (service); return g_hash_table_lookup_extended (service->tags, tag, NULL, NULL); } /** * ag_service_get_tags: * @service: the #AgService. * * Get list of tags specified for the #AgService. If the service has not * defined tags, tags from the service type will be returned. * * Returns: (transfer container) (element-type utf8): #GList of tags for * @service. The list must be freed with g_list_free(). Entries are owned by * the #AgService type and must not be free'd. */ GList *ag_service_get_tags (AgService *service) { g_return_val_if_fail (service != NULL, NULL); if (!service->file_data) _ag_service_load_from_file (service); if (service->tags == NULL) copy_tags_from_type (service); return g_hash_table_get_keys (service->tags); } /** * ag_service_get_file_contents: * @service: the #AgService. * @contents: location to receive the pointer to the file contents. * @data_offset: pointer to receive the offset of the type data. * * Gets the contents of the XML service file. The buffer returned in @contents * should not be modified or freed, and is guaranteed to be valid as long as * @service is referenced. If @data_offset is not %NULL, it is set to the * offset where the <type_data> element can be found. * If some error occurs, @contents is set to %NULL. */ void ag_service_get_file_contents (AgService *service, const gchar **contents, gsize *data_offset) { g_return_if_fail (service != NULL); g_return_if_fail (contents != NULL); if (service->file_data == NULL) { /* This can happen if the service was created by the AccountManager by * loading the record from the DB. * Now we must reload the service from its XML file. */ if (!_ag_service_load_from_file (service)) g_warning ("Loading service %s file failed", service->name); } *contents = service->file_data; if (data_offset) *data_offset = service->type_data_offset; } /** * ag_service_ref: * @service: the #AgService. * * Adds a reference to @service. * * Returns: @service. */ AgService * ag_service_ref (AgService *service) { g_return_val_if_fail (service != NULL, NULL); g_return_val_if_fail (service->ref_count > 0, NULL); DEBUG_REFS ("Referencing service %s (%d)", service->name, service->ref_count); service->ref_count++; return service; } /** * ag_service_unref: * @service: the #AgService. * * Used to unreference the #AgService structure. */ void ag_service_unref (AgService *service) { g_return_if_fail (service != NULL); g_return_if_fail (service->ref_count > 0); DEBUG_REFS ("Unreferencing service %s (%d)", service->name, service->ref_count); service->ref_count--; if (service->ref_count == 0) { g_free (service->name); g_free (service->display_name); g_free (service->description); g_free (service->icon_name); g_free (service->i18n_domain); g_free (service->type); g_free (service->provider); g_free (service->file_data); if (service->default_settings) g_hash_table_unref (service->default_settings); if (service->tags) g_hash_table_destroy (service->tags); g_slice_free (AgService, service); } } /** * ag_service_list_free: * @list: (element-type AgService): a #GList of services returned by some * function of this library. * * Frees the list @list. */ void ag_service_list_free (GList *list) { g_list_foreach (list, (GFunc)ag_service_unref, NULL); g_list_free (list); } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-auth-data.c0000644000015000001560000002513312245170671025204 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2012 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** * SECTION:ag-auth-data * @short_description: information for account authentication. * @include: libaccounts-glib/ag-auth-data.h * * The #AgAuthData structure holds information on the authentication * parameters used by an account. It is created by * ag_account_service_get_auth_data(), and can be destroyed with * ag_auth_data_unref(). */ #define AG_DISABLE_DEPRECATION_WARNINGS #include "ag-auth-data.h" #include "ag-internals.h" #include "ag-util.h" struct _AgAuthData { /*< private >*/ gint ref_count; guint credentials_id; gchar *method; gchar *mechanism; GHashTable *parameters; /* For compatibility with the deprecated API */ GHashTable *parameters_compat; }; G_DEFINE_BOXED_TYPE (AgAuthData, ag_auth_data, (GBoxedCopyFunc)ag_auth_data_ref, (GBoxedFreeFunc)ag_auth_data_unref); static GVariant * get_value_with_fallback (AgAccount *account, AgService *service, const gchar *key) { GVariant *value; ag_account_select_service (account, service); value = ag_account_get_variant (account, key, NULL); if (value == NULL && service != NULL) { /* fallback to the global account */ ag_account_select_service (account, NULL); value = ag_account_get_variant (account, key, NULL); } return value; } static gchar * get_string_with_fallback (AgAccount *account, AgService *service, const gchar *key) { GVariant *value; value = get_value_with_fallback (account, service, key); if (value == NULL) return NULL; return g_variant_dup_string (value, NULL); } static guint32 get_uint_with_fallback (AgAccount *account, AgService *service, const gchar *key) { GVariant *value; value = get_value_with_fallback (account, service, key); if (value == NULL) return 0; return g_variant_get_uint32 (value); } static void read_auth_settings (AgAccount *account, const gchar *key_prefix, GHashTable *out) { AgAccountSettingIter iter; const gchar *key; GVariant *value; ag_account_settings_iter_init (account, &iter, key_prefix); while (ag_account_settings_iter_get_next (&iter, &key, &value)) { g_hash_table_insert (out, g_strdup (key), g_variant_ref (value)); } } AgAuthData * _ag_auth_data_new (AgAccount *account, AgService *service) { guint32 credentials_id; gchar *method, *mechanism; gchar *key_prefix; GHashTable *parameters; AgAuthData *data = NULL; g_return_val_if_fail (account != NULL, NULL); credentials_id = get_uint_with_fallback (account, service, "CredentialsId"); method = get_string_with_fallback (account, service, "auth/method"); mechanism = get_string_with_fallback (account, service, "auth/mechanism"); parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); key_prefix = g_strdup_printf ("auth/%s/%s/", method, mechanism); /* first, take the values from the global account */ ag_account_select_service (account, NULL); read_auth_settings (account, key_prefix, parameters); /* next, the service-specific authentication settings */ if (service != NULL) { ag_account_select_service (account, service); read_auth_settings (account, key_prefix, parameters); } g_free (key_prefix); data = g_slice_new (AgAuthData); data->credentials_id = credentials_id; data->method = method; data->mechanism = mechanism; data->parameters = parameters; data->parameters_compat = NULL; return data; } /** * ag_auth_data_ref: * @self: the #AgAuthData. * * Increment the reference count of @self. * * Returns: @self. */ AgAuthData * ag_auth_data_ref (AgAuthData *self) { g_return_val_if_fail (self != NULL, NULL); g_atomic_int_inc (&self->ref_count); return self; } /** * ag_auth_data_unref: * @self: the #AgAuthData. * * Decrements the reference count of @self. The item is destroyed when the * count gets to 0. */ void ag_auth_data_unref (AgAuthData *self) { g_return_if_fail (self != NULL); if (g_atomic_int_dec_and_test (&self->ref_count)) { g_free (self->method); g_free (self->mechanism); g_hash_table_unref (self->parameters); if (self->parameters_compat != NULL) g_hash_table_unref (self->parameters_compat); g_slice_free (AgAuthData, self); } } /** * ag_auth_data_get_credentials_id: * @self: the #AgAuthData. * * Gets the ID of the credentials associated with this account. * * Returns: the credentials ID. * * Since: 1.1 */ guint ag_auth_data_get_credentials_id (AgAuthData *self) { g_return_val_if_fail (self != NULL, 0); return self->credentials_id; } /** * ag_auth_data_get_method: * @self: the #AgAuthData. * * Gets the authentication method. * * Returns: the authentication method. */ const gchar * ag_auth_data_get_method (AgAuthData *self) { g_return_val_if_fail (self != NULL, NULL); return self->method; } /** * ag_auth_data_get_mechanism: * @self: the #AgAuthData. * * Gets the authentication mechanism. * * Returns: the authentication mechanism. */ const gchar * ag_auth_data_get_mechanism (AgAuthData *self) { g_return_val_if_fail (self != NULL, NULL); return self->mechanism; } /** * ag_auth_data_get_parameters: * @self: the #AgAuthData. * * Gets the authentication parameters. * * Returns: (transfer none) (element-type utf8 GValue): a #GHashTable * containing all the authentication parameters. * * Deprecated: 1.4: use ag_auth_data_get_login_parameters() instead. */ GHashTable * ag_auth_data_get_parameters (AgAuthData *self) { g_return_val_if_fail (self != NULL, NULL); if (self->parameters_compat == NULL) { GHashTableIter iter; const gchar *key; GVariant *variant; self->parameters_compat = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)_ag_value_slice_free); /* Convert the GVariants into GValues */ g_hash_table_iter_init (&iter, self->parameters); while (g_hash_table_iter_next (&iter, (gpointer)&key, (gpointer)&variant)) { GValue *value = g_slice_new0 (GValue); _ag_value_from_variant (value, variant); g_hash_table_insert (self->parameters_compat, g_strdup (key), value); } } return self->parameters_compat; } /** * ag_auth_data_insert_parameters: * @self: the #AgAuthData. * @parameters: (transfer none) (element-type utf8 GValue): a #GHashTable * containing the authentication parameters to be added. * * Insert the given authentication parameters into the authentication data. If * some parameters were already present, the parameters passed with this method * take precedence. * * Deprecated: 1.4: use ag_auth_data_get_login_parameters() instead. */ void ag_auth_data_insert_parameters (AgAuthData *self, GHashTable *parameters) { GHashTable *self_parameters; GHashTableIter iter; const gchar *key; const GValue *value; g_return_if_fail (self != NULL); g_return_if_fail (parameters != NULL); self_parameters = ag_auth_data_get_parameters (self); g_hash_table_iter_init (&iter, parameters); while (g_hash_table_iter_next (&iter, (gpointer)&key, (gpointer)&value)) { g_hash_table_insert (self_parameters, g_strdup (key), _ag_value_slice_dup (value)); } } /** * ag_auth_data_get_login_parameters: * @self: the #AgAuthData. * @extra_parameters: (transfer floating): a #GVariant containing * client-specific authentication parameters to be added to the returned * dictionary. * * Gets the authentication parameters. * * Returns: (transfer none): a floating #GVariant of type * %G_VARIANT_TYPE_VARDICT containing all the authentication parameters. * * Since: 1.4 */ GVariant * ag_auth_data_get_login_parameters (AgAuthData *self, GVariant *extra_parameters) { GVariantBuilder builder; GHashTableIter iter; gchar *key; GVariant *value; GSList *skip_keys = NULL; g_return_val_if_fail (self != NULL, NULL); g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); /* Put the parameters from the client. */ if (extra_parameters != NULL) { GVariantIter i_extra; g_variant_ref_sink (extra_parameters); g_variant_iter_init (&i_extra, extra_parameters); while (g_variant_iter_next (&i_extra, "{&sv}", &key, &value)) { g_variant_builder_add (&builder, "{sv}", key, value); /* Make sure we are not going to add the same key later */ if (g_hash_table_lookup (self->parameters, key)) skip_keys = g_slist_prepend (skip_keys, g_strdup (key)); } g_variant_unref (extra_parameters); } /* Put the parameters from the account first. */ g_hash_table_iter_init (&iter, self->parameters); while (g_hash_table_iter_next (&iter, (gpointer)&key, (gpointer)&value)) { /* If the key is also present in extra_parameters, then don't add it */ if (!g_slist_find_custom (skip_keys, key, (GCompareFunc)g_strcmp0)) g_variant_builder_add (&builder, "{sv}", key, value); } /* Free the skip_keys list */ while (skip_keys != NULL) { g_free (skip_keys->data); skip_keys = g_slist_delete_link (skip_keys, skip_keys); } return g_variant_builder_end (&builder); } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/accounts-provider.dtd0000644000015000001560000000365212245170671026751 0ustar pbuserpbgroup00000000000000 libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-debug.h0000644000015000001560000000534212245170671024427 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_DEBUG_H_ #define _AG_DEBUG_H_ #include #include G_BEGIN_DECLS G_GNUC_INTERNAL void _ag_debug_init (void); typedef enum { AG_DEBUG_TIME = 1 << 0, AG_DEBUG_REFS = 1 << 1, AG_DEBUG_LOCKS = 1 << 2, AG_DEBUG_QUERIES = 1 << 3, AG_DEBUG_INFO = 1 << 4, AG_DEBUG_ALL = 0xffffffff } AgDebugLevel; G_GNUC_INTERNAL AgDebugLevel _ag_debug_get_level (void); #ifdef ENABLE_DEBUG #define DEBUG(level, format, ...) G_STMT_START { \ if (_ag_debug_get_level() & level) \ g_debug("%s: " format, G_STRFUNC, ##__VA_ARGS__); \ } G_STMT_END /* Macros for profiling */ #define TIME_START() \ struct timespec tm0, tm1; \ struct timespec tt0, tt1; \ long ms_mdiff; \ long ms_tdiff; \ clock_gettime(CLOCK_MONOTONIC, &tm0); \ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tt0) #define TIME_STOP() \ clock_gettime(CLOCK_MONOTONIC, &tm1); \ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tt1); \ ms_mdiff = (tm1.tv_sec - tm0.tv_sec) * 1000 + \ (tm1.tv_nsec - tm0.tv_nsec) / 1000000; \ ms_tdiff = (tt1.tv_sec - tt0.tv_sec) * 1000 + \ (tt1.tv_nsec - tt0.tv_nsec) / 1000000; \ DEBUG_TIME("%s, total %ld ms, thread %ld ms", G_STRLOC, ms_mdiff, ms_tdiff) #else /* !ENABLE_DEBUG */ #define DEBUG(level, format, ...) #define TIME_START() #define TIME_STOP() #endif #define DEBUG_TIME(format, ...) DEBUG(AG_DEBUG_TIME, format, ##__VA_ARGS__) #define DEBUG_REFS(format, ...) DEBUG(AG_DEBUG_REFS, format, ##__VA_ARGS__) #define DEBUG_LOCKS(format, ...) DEBUG(AG_DEBUG_LOCKS, format, ##__VA_ARGS__) #define DEBUG_QUERIES(format, ...) \ DEBUG(AG_DEBUG_QUERIES, format, ##__VA_ARGS__) #define DEBUG_INFO(format, ...) DEBUG(AG_DEBUG_INFO, format, ##__VA_ARGS__) G_END_DECLS #endif /* _AG_DEBUG_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/libaccounts-glib.vapi0000644000015000001560000002564512245170671026715 0ustar pbuserpbgroup00000000000000/* accounts.vapi generated by vapigen, do not modify. */ [CCode (cprefix = "Ag", gir_namespace = "Accounts", gir_version = "1.0", lower_case_cprefix = "ag_")] namespace Ag { [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", type_id = "ag_account_get_type ()")] public class Account : GLib.Object { [CCode (has_construct_function = false)] protected Account (); public void @delete (); public unowned string get_display_name (); public bool get_enabled (); public unowned Ag.Manager get_manager (); public unowned string get_provider_name (); public Ag.Service get_selected_service (); public Ag.AccountSettingIter get_settings_iter (string? key_prefix); [Deprecated (replacement = "get_variant", since = "1.4")] public Ag.SettingSource get_value (string key, ref GLib.Value value); public GLib.Variant get_variant (string key, out Ag.SettingSource? source); public GLib.List list_enabled_services (); public GLib.List list_services (); public GLib.List list_services_by_type (string service_type); public void remove_watch (Ag.AccountWatch watch); public void select_service (Ag.Service? service); public void set_display_name (string display_name); public void set_enabled (bool enabled); [Deprecated (replacement = "set_variant", since = "1.4")] public void set_value (string key, GLib.Value? value); public void set_variant (string key, GLib.Variant? value); public void settings_iter_init (Ag.AccountSettingIter iter, string? key_prefix); public void sign (string key, string token); [Deprecated (replacement = "store_async", since="1.4")] public void store (Ag.AccountStoreCb callback); public async void store_async (GLib.Cancellable? cancellable = null) throws Ag.AccountsError; public bool store_blocking () throws Ag.AccountsError; public bool supports_service (string service_type); public bool verify (string key, string token); public bool verify_with_tokens (string key, string tokens); public unowned Ag.AccountWatch watch_dir (string key_prefix, Ag.AccountNotifyCb callback); public unowned Ag.AccountWatch watch_key (string key, Ag.AccountNotifyCb callback); public string display_name { get; } /* FIXME: Same name as a signal, so ignore for the moment. public bool enabled { get; } */ public bool foreign { construct; } [NoAccessorMethod] public uint id { get; construct; } public Ag.Manager manager { get; construct; } public string provider { get; construct; } public signal void deleted (); public signal void display_name_changed (); public signal void enabled (string service, bool enabled); } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", type_id = "ag_account_service_get_type ()")] public class AccountService : GLib.Object { [CCode (has_construct_function = false)] public AccountService (owned Ag.Account account, owned Ag.Service? service); public unowned Ag.Account get_account (); public Ag.AuthData get_auth_data (); [CCode (array_length = false, array_null_terminated = true)] public string[] get_changed_fields (); public bool get_enabled (); public unowned Ag.Service get_service (); public Ag.AccountSettingIter get_settings_iter (string? key_prefix); [Deprecated (replacement = "get_variant", since = "1.4")] public Ag.SettingSource get_value (string key, ref GLib.Value value); public GLib.Variant get_variant (string key, out Ag.SettingSource? source); [Deprecated (replacement = "set_variant", since = "1.4")] public void set_value (string key, GLib.Value? value); public void set_variant (string key, GLib.Variant? value); public void settings_iter_init (Ag.AccountSettingIter iter, string? key_prefix); [Deprecated (since = "1.4")] public static bool settings_iter_next (Ag.AccountSettingIter iter, out unowned string key, out GLib.Value value); public Ag.Account account { construct; } /* FIXME: Same name as a signal, so ignore for the moment. public bool enabled { get; } */ public Ag.Service service { construct; } public signal void changed (); public signal void enabled (bool enabled); } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", lower_case_csuffix = "account_settings_iter", type_id = "ag_account_settings_iter_get_type ()")] [Compact] public class AccountSettingIter { public weak Ag.Account account; public void free (); public bool next (out unowned string key, out GLib.Value value); } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h")] [Compact] public class AccountWatch { } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "ag_application_get_type ()")] [Compact] public class Application { public unowned string get_description (); public GLib.DesktopAppInfo get_desktop_app_info (); public unowned string get_i18n_domain (); public unowned string get_name (); public unowned string get_service_usage (Ag.Service service); public Ag.Application @ref (); public void unref (); } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "ag_auth_data_get_type ()")] [Compact] public class AuthData { public uint get_credentials_id (); public unowned string get_mechanism (); public unowned string get_method (); public unowned GLib.Variant get_login_parameters (GLib.Variant variant); [Deprecated (replacement = "get_login_parameters", since = "1.4")] public unowned GLib.HashTable get_parameters (); [Deprecated (replacement = "get_login_parameters", since = "1.4")] public void insert_parameters (GLib.HashTable parameters); public Ag.AuthData @ref (); public void unref (); } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", type_id = "ag_manager_get_type ()")] public class Manager : GLib.Object { [CCode (has_construct_function = false)] public Manager (); public Ag.Account create_account (string provider_name); [CCode (has_construct_function = false)] public Manager.for_service_type (string service_type); public bool get_abort_on_db_timeout (); public Ag.Account get_account (Ag.AccountId account_id); public GLib.List get_account_services (); public Ag.Application get_application (string application_name); public uint get_db_timeout (); public GLib.List get_enabled_account_services (); public Ag.Provider get_provider (string provider_name); public Ag.Service get_service (string service_name); public unowned string get_service_type (); public GLib.List list (); public GLib.List list_applications_by_service (Ag.Service service); public GLib.List list_by_service_type (string service_type); public GLib.List list_enabled (); public GLib.List list_enabled_by_service_type (string service_type); public static void list_free (GLib.List list); public GLib.List list_providers (); public GLib.List list_service_types (); public GLib.List list_services (); public GLib.List list_services_by_type (string service_type); public Ag.Account load_account (Ag.AccountId account_id) throws Ag.AccountsError; public Ag.ServiceType load_service_type (string service_type); public void set_abort_on_db_timeout (bool abort); public void set_db_timeout (uint timeout_ms); public string service_type { get; construct; } public signal void account_created (uint account_id); public virtual signal void account_deleted (uint id); public signal void account_updated (uint account_id); public signal void enabled_event (uint account_id); } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "ag_provider_get_type ()")] [Compact] public class Provider { public unowned string get_display_name (); public unowned string get_description (); public unowned string get_domains_regex (); public void get_file_contents (string contents); public unowned string get_i18n_domain (); public unowned string get_icon_name (); public unowned string get_name (); public unowned string get_plugin_name (); public static void list_free (GLib.List list); public bool match_domain (string domain); public Ag.Provider @ref (); public void unref (); } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "ag_service_get_type ()")] [Compact] public class Service { public unowned string get_display_name (); public unowned string get_description (); public void get_file_contents (string contents, size_t data_offset); public unowned string get_i18n_domain (); public unowned string get_icon_name (); public unowned string get_name (); public unowned string get_provider (); public unowned string get_service_type (); public GLib.List get_tags (); public bool has_tag (string tag); public static void list_free (GLib.List list); public Ag.Service @ref (); public void unref (); } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "ag_service_type_get_type ()")] [Compact] public class ServiceType { public unowned string get_display_name (); public unowned string get_description (); public void get_file_contents (string contents, size_t len); public unowned string get_i18n_domain (); public unowned string get_icon_name (); public unowned string get_name (); public GLib.List get_tags (); public bool has_tag (string tag); public static void list_free (GLib.List list); public Ag.ServiceType @ref (); public void unref (); } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h")] [SimpleType] public struct AccountId : uint { } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", cprefix = "AG_ACCOUNTS_ERROR_")] public errordomain AccountsError { DB, DISPOSED, DELETED, DB_LOCKED, ACCOUNT_NOT_FOUND, STORE_IN_PROGRESS } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", cprefix = "AG_SETTING_SOURCE_")] public enum SettingSource { NONE, ACCOUNT, PROFILE } [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", instance_pos = 2.9)] public delegate void AccountNotifyCb (Ag.Account account, string key); [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", instance_pos = 2.9)] public delegate void AccountServiceNotifyCb (Ag.AccountService self, string key); [Deprecated (since = "1.4")] [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h", instance_pos = 2.9)] public delegate void AccountStoreCb (Ag.Account account, GLib.Error error); [CCode (cheader_filename = "libaccounts-glib/accounts-glib.h")] public static GLib.Quark errors_quark (); } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-account.c0000644000015000001560000023215012245170671024767 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** * SECTION:ag-account * @short_description: A representation of an account. * @include: libaccounts-glib/ag-account.h * * An #AgAccount is an object which represents an account. It provides a * method for enabling/disabling the account and methods for editing the * account settings. * * Accounts are created by #AgManager with ag_manager_create_account(), and * deleted by #AgAccount with ag_account_delete(). These operations, and any * other operations which modify the account settings, must be followed by * ag_account_store() before the changes are committed to the database. * * Creating a new <structname>AgAccount</structname> * * GMainLoop *main_loop = NULL; * * gboolean account_cleanup_idle (gpointer user_data) * { * AgManager *manager; * AgAccount *account = AG_ACCOUNT (user_data); * manager = ag_account_get_manager (account); * * g_object_unref (account); * g_object_unref (manager); * * g_main_loop_quit (main_loop); * * return FALSE; * } * * void account_stored_cb (AgAccount *account, * const GError *error, * gpointer user_data) * { * AgManager *manager = AG_MANAGER (user_data); * * if (error != NULL) * { * g_warning ("Account with ID '%u' failed to store, with error: %s", * account->id, * error->message); * } * else * { * g_print ("Account stored with ID: %u", account->id); * } * * /* Clean up in an idle callback. */ * g_idle_add (account_cleanup_idle, account); * g_main_loop_run (main_loop); * } * * void store_account (void) * { * AgManager *manager; * GList *providers; * const gchar *provider_name; * AgAccount *account; * * main_loop = g_main_loop_new (NULL, FALSE); * manager = ag_manager_new (); * providers = ag_manager_list_providers (manager); * g_assert (providers != NULL); * provider_name = ag_provider_get_name ((AgProvider *) providers->data); * account = ag_manager_create_account (manager, provider_name); * * ag_provider_list_free (providers); * * /* The account is not valid until it has been stored. */ * ag_account_store (account, account_stored_cb, (gpointer) manager); * } * * */ #include "ag-manager.h" #include "ag-account.h" #include "ag-errors.h" #include "ag-internals.h" #include "ag-marshal.h" #include "ag-provider.h" #include "ag-service.h" #include "ag-util.h" #include "config.h" #include #define SERVICE_GLOBAL "global" enum { PROP_0, PROP_ID, PROP_MANAGER, PROP_PROVIDER, PROP_FOREIGN, PROP_ENABLED, PROP_DISPLAY_NAME, N_PROPERTIES }; static GParamSpec *properties[N_PROPERTIES]; enum { ENABLED, DISPLAY_NAME_CHANGED, DELETED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; typedef struct _AgServiceChanges { AgService *service; /* this is set only if the change came from this instance */ gchar *service_type; GHashTable *settings; GHashTable *signatures; } AgServiceChanges; typedef struct _AgServiceSettings { AgService *service; GHashTable *settings; } AgServiceSettings; struct _AgAccountPrivate { AgManager *manager; /* selected service */ AgService *service; AgProvider *provider; gchar *provider_name; gchar *display_name; /* cached settings: keys are service names, values are AgServiceSettings * structures. * It may be that not all services are loaded in this hash table. But if a * service is present, then all of its settings are. */ GHashTable *services; AgAccountChanges *changes; /* Watches: it's a GHashTable whose keys are pointers to AgService * elements, and values are GHashTables whose keys and values are * AgAccountWatch-es. */ GHashTable *watches; /* Temporary pointer to the services table of the AgAccountChanges * structure, to be used while invoking the watches in case some handlers * want to retrieve the list of changes (AgAccountService does this). */ GHashTable *changes_for_watches; /* GSimpleAsyncResult for the ag_account_store_async operation. */ GSimpleAsyncResult *store_async_result; /* The "foreign" flag means that the account has been created by another * instance and we got informed about it from D-Bus. In this case, all the * informations that we get via D-Bus will be cached in the * AgServiceSetting structures. */ guint foreign : 1; guint enabled : 1; guint deleted : 1; }; struct _AgAccountWatch { AgService *service; gchar *key; gchar *prefix; AgAccountNotifyCb callback; gpointer user_data; }; /* Same size and member types as AgAccountSettingIter */ typedef struct { AgAccount *account; GHashTableIter iter; gchar *key_prefix; /* The next field is used by ag_account_settings_iter_next() only */ GValue *last_gvalue; gint stage; gint must_free_prefix; } RealIter; typedef struct _AgSignature { gchar *signature; gchar *token; } AgSignature; typedef struct { AgAccountStoreCb callback; gpointer user_data; } AsyncReadyCbWrapperData; #define AG_ITER_STAGE_UNSET 0 #define AG_ITER_STAGE_ACCOUNT 1 #define AG_ITER_STAGE_SERVICE 2 static void ag_account_initable_iface_init(gpointer g_iface, gpointer iface_data); G_DEFINE_TYPE_WITH_CODE (AgAccount, ag_account, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, ag_account_initable_iface_init)); #define AG_ACCOUNT_PRIV(obj) (AG_ACCOUNT(obj)->priv) static inline gboolean ensure_has_provider (AgAccountPrivate *priv) { if (priv->provider == NULL && priv->provider_name != NULL) { priv->provider = ag_manager_get_provider (priv->manager, priv->provider_name); } return priv->provider != NULL; } static void async_ready_cb_wrapper (GObject *object, GAsyncResult *res, gpointer user_data) { AsyncReadyCbWrapperData *cb_data = user_data; AgAccount *account = AG_ACCOUNT (object); GError *error = NULL; ag_account_store_finish (account, res, &error); if (cb_data->callback != NULL) { cb_data->callback (account, error, cb_data->user_data); } g_clear_error (&error); g_slice_free (AsyncReadyCbWrapperData, cb_data); } static void ag_variant_safe_unref (gpointer variant) { if (variant != NULL) g_variant_unref ((GVariant *)variant); } GVariant * _ag_account_build_signal (AgAccount *account, AgAccountChanges *changes, const struct timespec *ts) { GVariantBuilder builder; const gchar *provider_name; g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); provider_name = account->priv->provider_name; if (!provider_name) provider_name = ""; g_variant_builder_add (&builder, "u", ts->tv_sec); g_variant_builder_add (&builder, "u", ts->tv_nsec); g_variant_builder_add (&builder, "u", account->id); g_variant_builder_add (&builder, "b", changes->created); g_variant_builder_add (&builder, "b", changes->deleted); g_variant_builder_add (&builder, "s", provider_name); /* Append the settings */ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(ssua{sv}as)")); if (changes->services) { GHashTableIter iter; AgServiceChanges *sc; gchar *service_name; g_hash_table_iter_init (&iter, changes->services); while (g_hash_table_iter_next (&iter, (gpointer)&service_name, (gpointer)&sc)) { GSList *removed_keys = NULL; GHashTableIter si; gchar *key; GVariant *value; guint service_id; g_variant_builder_open (&builder, G_VARIANT_TYPE ("(ssua{sv}as)")); /* Append the service name */ g_variant_builder_add (&builder, "s", service_name); /* Append the service type */ g_variant_builder_add (&builder, "s", sc->service_type); /* Append the service id */ if (sc->service == NULL) service_id = 0; else service_id = sc->service->id; g_variant_builder_add (&builder, "u", service_id); /* Append the dictionary of service settings */ g_variant_builder_open (&builder, G_VARIANT_TYPE_VARDICT); g_hash_table_iter_init (&si, sc->settings); while (g_hash_table_iter_next (&si, (gpointer)&key, (gpointer)&value)) { if (value) g_variant_builder_add (&builder, "{sv}", key, value); else removed_keys = g_slist_prepend (removed_keys, key); } g_variant_builder_close (&builder); /* append the list of removed keys */ g_variant_builder_open (&builder, G_VARIANT_TYPE_STRING_ARRAY); while (removed_keys) { g_variant_builder_add (&builder, "s", removed_keys->data); removed_keys = g_slist_delete_link (removed_keys, removed_keys); } g_variant_builder_close (&builder); /* Close the service entry builder */ g_variant_builder_close (&builder); } } g_variant_builder_close (&builder); return g_variant_builder_end (&builder); } static void ag_account_watch_free (AgAccountWatch watch) { g_return_if_fail (watch != NULL); g_free (watch->key); g_free (watch->prefix); g_slice_free (struct _AgAccountWatch, watch); } static AgService * ag_service_ref_null (AgService *service) { if (service) ag_service_ref (service); return service; } static void ag_service_unref_null (AgService *service) { if (service) ag_service_unref (service); } static AgAccountWatch ag_account_watch_int (AgAccount *account, gchar *key, gchar *prefix, AgAccountNotifyCb callback, gpointer user_data) { AgAccountPrivate *priv = account->priv; AgAccountWatch watch; GHashTable *service_watches; if (!priv->watches) { priv->watches = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify)ag_service_unref_null, (GDestroyNotify)g_hash_table_destroy); } service_watches = g_hash_table_lookup (priv->watches, priv->service); if (!service_watches) { service_watches = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)ag_account_watch_free); g_hash_table_insert (priv->watches, ag_service_ref_null (priv->service), service_watches); } watch = g_slice_new (struct _AgAccountWatch); watch->service = priv->service; watch->key = key; watch->prefix = prefix; watch->callback = callback; watch->user_data = user_data; g_hash_table_insert (service_watches, watch, watch); return watch; } static gboolean got_account_setting (sqlite3_stmt *stmt, GHashTable *settings) { gchar *key; GVariant *value; key = g_strdup ((gchar *)sqlite3_column_text (stmt, 0)); g_return_val_if_fail (key != NULL, FALSE); value = _ag_value_from_db (stmt, 1, 2); g_hash_table_insert (settings, key, value); return TRUE; } static void ag_service_settings_free (AgServiceSettings *ss) { if (ss->service) ag_service_unref (ss->service); g_hash_table_unref (ss->settings); g_slice_free (AgServiceSettings, ss); } static AgServiceSettings * get_service_settings (AgAccountPrivate *priv, AgService *service, gboolean create) { AgServiceSettings *ss; const gchar *service_name; if (G_UNLIKELY (!priv->services)) { priv->services = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) ag_service_settings_free); } service_name = service ? service->name : SERVICE_GLOBAL; ss = g_hash_table_lookup (priv->services, service_name); if (!ss && create) { ss = g_slice_new (AgServiceSettings); ss->service = service ? ag_service_ref (service) : NULL; ss->settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, ag_variant_safe_unref); g_hash_table_insert (priv->services, (gchar *)service_name, ss); } return ss; } static gboolean ag_account_changes_get_enabled (AgAccountChanges *changes, gboolean *enabled) { AgServiceChanges *sc; GVariant *value; sc = g_hash_table_lookup (changes->services, SERVICE_GLOBAL); if (sc) { value = g_hash_table_lookup (sc->settings, "enabled"); if (value) { *enabled = g_variant_get_boolean (value); return TRUE; } } *enabled = FALSE; return FALSE; } static gboolean ag_account_changes_get_display_name (AgAccountChanges *changes, const gchar **display_name) { AgServiceChanges *sc; GVariant *value; sc = g_hash_table_lookup (changes->services, SERVICE_GLOBAL); if (sc) { value = g_hash_table_lookup (sc->settings, "name"); if (value) { *display_name = g_variant_get_string (value, NULL); return TRUE; } } *display_name = NULL; return FALSE; } static void ag_service_changes_free (AgServiceChanges *sc) { g_free (sc->service_type); if (sc->settings) g_hash_table_unref (sc->settings); if (sc->signatures) g_hash_table_unref (sc->signatures); g_slice_free (AgServiceChanges, sc); } void _ag_account_changes_free (AgAccountChanges *changes) { if (G_LIKELY (changes)) { g_hash_table_unref (changes->services); g_slice_free (AgAccountChanges, changes); } } static GList * match_watch_with_key (GHashTable *watches, const gchar *key, GList *watch_list) { GHashTableIter iter; AgAccountWatch watch; g_hash_table_iter_init (&iter, watches); while (g_hash_table_iter_next (&iter, NULL, (gpointer)&watch)) { if (watch->key) { if (strcmp (key, watch->key) == 0) { watch_list = g_list_prepend (watch_list, watch); } } else /* match on the prefix */ { if (g_str_has_prefix (key, watch->prefix)) { /* before addind the watch to the list, make sure it's not * already there */ if (!g_list_find (watch_list, watch)) watch_list = g_list_prepend (watch_list, watch); } } } return watch_list; } static void update_settings (AgAccount *account, GHashTable *services) { AgAccountPrivate *priv = account->priv; GHashTableIter iter; AgServiceChanges *sc; gchar *service_name; GList *watch_list = NULL; g_hash_table_iter_init (&iter, services); while (g_hash_table_iter_next (&iter, (gpointer)&service_name, (gpointer)&sc)) { AgServiceSettings *ss; GHashTableIter si; gchar *key; GVariant *value; GHashTable *watches = NULL; if (priv->foreign) { /* If the account has been created from another instance * (which might be in another process), the "changes" structure * contains all the account settings for all services. * * Instead of discarding this precious information, we store all * the settings in memory, to minimize future disk accesses. */ ss = get_service_settings (priv, sc->service, TRUE); } else { /* if the changed service doesn't have a AgServiceSettings entry it * means that the service was never selected on this account, so we * don't need to update its settings. */ if (!priv->services) continue; ss = g_hash_table_lookup (priv->services, service_name); } /* get the watches associated to this service */ if (ss != NULL && priv->watches != NULL) watches = g_hash_table_lookup (priv->watches, ss->service); g_hash_table_iter_init (&si, sc->settings); while (g_hash_table_iter_next (&si, (gpointer)&key, (gpointer)&value)) { if (ss != NULL) { if (ss->service == NULL) { if (strcmp (key, "name") == 0) { g_free (priv->display_name); priv->display_name = value ? g_variant_dup_string (value, NULL) : NULL; g_signal_emit (account, signals[DISPLAY_NAME_CHANGED], 0); g_object_notify_by_pspec ((GObject *)account, properties[PROP_DISPLAY_NAME]); continue; } else if (strcmp (key, "enabled") == 0) { priv->enabled = value ? g_variant_get_boolean (value) : FALSE; g_signal_emit (account, signals[ENABLED], 0, NULL, priv->enabled); g_object_notify_by_pspec ((GObject *)account, properties[PROP_ENABLED]); continue; } } if (value) g_hash_table_replace (ss->settings, g_strdup (key), g_variant_ref (value)); else g_hash_table_remove (ss->settings, key); /* check for installed watches to be invoked */ if (watches) watch_list = match_watch_with_key (watches, key, watch_list); } if (strcmp (key, "enabled") == 0) { gboolean enabled = value ? g_variant_get_boolean (value) : FALSE; g_signal_emit (account, signals[ENABLED], 0, service_name, enabled); } } } /* Invoke all watches * While whatches are running, let the receivers retrieve the changes * table with _ag_account_get_service_changes(): set it into the * changes_for_watches field. */ priv->changes_for_watches = services; while (watch_list) { AgAccountWatch watch = watch_list->data; if (watch->key) watch->callback (account, watch->key, watch->user_data); else watch->callback (account, watch->prefix, watch->user_data); watch_list = g_list_delete_link (watch_list, watch_list); } priv->changes_for_watches = NULL; } void _ag_account_store_completed (AgAccount *account, AgAccountChanges *changes) { AgAccountPrivate *priv = account->priv; g_simple_async_result_complete_in_idle (priv->store_async_result); g_clear_object (&priv->store_async_result); _ag_account_changes_free (changes); } /* * _ag_account_done_changes: * * This function is called after a successful execution of a transaction, and * must update the account data as with the contents of the AgAccountChanges * structure. */ void _ag_account_done_changes (AgAccount *account, AgAccountChanges *changes) { AgAccountPrivate *priv = account->priv; g_return_if_fail (changes != NULL); if (changes->services) update_settings (account, changes->services); if (changes->deleted) { priv->deleted = TRUE; priv->enabled = FALSE; g_signal_emit (account, signals[ENABLED], 0, NULL, FALSE); g_object_notify_by_pspec ((GObject *)account, properties[PROP_ENABLED]); g_signal_emit (account, signals[DELETED], 0); } } static AgAccountChanges * account_changes_get (AgAccountPrivate *priv) { if (!priv->changes) { priv->changes = g_slice_new0 (AgAccountChanges); priv->changes->services = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)ag_service_changes_free); } return priv->changes; } static void _ag_signatures_slice_free (AgSignature *sgn) { g_free (sgn->signature); g_free (sgn->token); g_slice_free (AgSignature, sgn); } static AgServiceChanges* account_service_changes_get (AgAccountPrivate *priv, AgService *service, gboolean create_signatures) { AgAccountChanges *changes; AgServiceChanges *sc; gchar *service_name; gchar *service_type; changes = account_changes_get (priv); service_name = service ? service->name : SERVICE_GLOBAL; service_type = service ? service->type : SERVICE_GLOBAL_TYPE; sc = g_hash_table_lookup (changes->services, service_name); if (!sc) { sc = g_slice_new0 (AgServiceChanges); sc->service = service; sc->service_type = g_strdup (service_type); sc->settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, ag_variant_safe_unref); g_hash_table_insert (changes->services, service_name, sc); } if (create_signatures && !sc->signatures) sc->signatures = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)_ag_signatures_slice_free); return sc; } GHashTable * _ag_account_get_service_changes (AgAccount *account, AgService *service) { GHashTable *services; AgServiceChanges *sc; services = account->priv->changes_for_watches; if (!services) return NULL; sc = g_hash_table_lookup (services, service ? service->name : SERVICE_GLOBAL); if (!sc) return NULL; return sc->settings; } static void change_service_value (AgAccountPrivate *priv, AgService *service, const gchar *key, GVariant *value) { AgServiceChanges *sc; sc = account_service_changes_get (priv, service, FALSE); g_hash_table_insert (sc->settings, g_strdup (key), value ? g_variant_ref_sink (value) : NULL); } static inline void change_selected_service_value (AgAccountPrivate *priv, const gchar *key, GVariant *value) { change_service_value(priv, priv->service, key, value); } static void ag_account_init (AgAccount *account) { account->priv = G_TYPE_INSTANCE_GET_PRIVATE (account, AG_TYPE_ACCOUNT, AgAccountPrivate); } static gboolean got_account (sqlite3_stmt *stmt, AgAccountPrivate *priv) { g_assert (priv->display_name == NULL); g_assert (priv->provider_name == NULL); priv->display_name = g_strdup ((gchar *)sqlite3_column_text (stmt, 0)); priv->provider_name = g_strdup ((gchar *)sqlite3_column_text (stmt, 1)); priv->enabled = sqlite3_column_int (stmt, 2); return TRUE; } static gboolean ag_account_load (AgAccount *account, GError **error) { AgAccountPrivate *priv = account->priv; gchar sql[128]; gint rows; g_snprintf (sql, sizeof (sql), "SELECT name, provider, enabled " "FROM Accounts WHERE id = %u", account->id); rows = _ag_manager_exec_query (priv->manager, (AgQueryCallback)got_account, priv, sql); /* if the query succeeded but we didn't get a row, we must set the * NOT_FOUND error */ if (rows != 1) { g_set_error (error, AG_ACCOUNTS_ERROR, AG_ACCOUNTS_ERROR_ACCOUNT_NOT_FOUND, "Account %u not found in DB", account->id); } return rows == 1; } static gboolean ag_account_initable_init (GInitable *initable, G_GNUC_UNUSED GCancellable *cancellable, GError **error) { AgAccount *account = AG_ACCOUNT (initable); if (account->id) { if (account->priv->changes && account->priv->changes->created) { /* this is a new account and we should not load it */ _ag_account_changes_free (account->priv->changes); account->priv->changes = NULL; } else if (!ag_account_load (account, error)) { g_warning ("Unable to load account %u", account->id); return FALSE; } } if (!account->priv->foreign) ag_account_select_service (account, NULL); return TRUE; } static void ag_account_initable_iface_init (gpointer g_iface, G_GNUC_UNUSED gpointer iface_data) { GInitableIface *iface = (GInitableIface *)g_iface; iface->init = ag_account_initable_init; } static void ag_account_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { AgAccount *account = AG_ACCOUNT (object); switch (property_id) { case PROP_ID: g_value_set_uint (value, account->id); break; case PROP_MANAGER: g_value_set_object (value, account->priv->manager); break; case PROP_PROVIDER: g_value_set_string (value, account->priv->provider_name); break; case PROP_ENABLED: g_value_set_boolean (value, account->priv->enabled); break; case PROP_DISPLAY_NAME: g_value_set_string (value, account->priv->display_name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ag_account_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { AgAccount *account = AG_ACCOUNT (object); AgAccountPrivate *priv = account->priv; switch (property_id) { case PROP_ID: g_assert (account->id == 0); account->id = g_value_get_uint (value); break; case PROP_MANAGER: g_assert (priv->manager == NULL); priv->manager = g_value_dup_object (value); break; case PROP_PROVIDER: g_assert (priv->provider_name == NULL); priv->provider_name = g_value_dup_string (value); /* if this property is given, it means we are creating a new account */ if (priv->provider_name) { AgAccountChanges *changes = account_changes_get (priv); changes->created = TRUE; } break; case PROP_FOREIGN: priv->foreign = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ag_account_dispose (GObject *object) { AgAccount *account = AG_ACCOUNT (object); AgAccountPrivate *priv = account->priv; DEBUG_REFS ("Disposing account %p", object); if (priv->watches) { g_hash_table_destroy (priv->watches); priv->watches = NULL; } if (priv->provider) { ag_provider_unref (priv->provider); priv->provider = NULL; } if (priv->manager) { g_object_unref (priv->manager); priv->manager = NULL; } G_OBJECT_CLASS (ag_account_parent_class)->dispose (object); } static void ag_account_finalize (GObject *object) { AgAccountPrivate *priv = AG_ACCOUNT_PRIV (object); g_free (priv->provider_name); g_free (priv->display_name); if (priv->services) g_hash_table_unref (priv->services); if (priv->changes) { DEBUG_INFO ("Finalizing account with uncommitted changes!"); _ag_account_changes_free (priv->changes); } G_OBJECT_CLASS (ag_account_parent_class)->finalize (object); } static void ag_account_class_init (AgAccountClass *klass) { GObjectClass* object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (object_class, sizeof (AgAccountPrivate)); object_class->get_property = ag_account_get_property; object_class->set_property = ag_account_set_property; object_class->dispose = ag_account_dispose; object_class->finalize = ag_account_finalize; /** * AgAccount:id: * * The AgAccountId for the account. */ properties[PROP_ID] = g_param_spec_uint ("id", "Account ID", "The AgAccountId of the account", 0, G_MAXUINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * AgAccount:manager: * * The #AgManager from which the account was instantiated. * * Since: 1.4 */ properties[PROP_MANAGER] = g_param_spec_object ("manager", "manager", "manager", AG_TYPE_MANAGER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); /** * AgAccount:provider: * * The ID of the provider for the account. * * Since: 1.4 */ properties[PROP_PROVIDER] = g_param_spec_string ("provider", "provider", "provider", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); properties[PROP_FOREIGN] = g_param_spec_boolean ("foreign", "foreign", "foreign", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); /** * AgAccount:enabled: * * Whether the account is currently enabled. * * Since: 1.4 */ properties[PROP_ENABLED] = g_param_spec_boolean ("enabled", "Enabled", "Whether the account is enabled", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * AgAccount:display-name: * * The display name of the account. * * Since: 1.4 */ properties[PROP_DISPLAY_NAME] = g_param_spec_string ("display-name", "Display name", "The display name of the account", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPERTIES, properties); /** * AgAccount::enabled: * @account: the #AgAccount. * @service: the service which was enabled/disabled, or %NULL if the global * enabledness of the account changed. * @enabled: the new state of the @account. * * Emitted when the account "enabled" status was changed for one of its * services, or for the account globally. */ signals[ENABLED] = g_signal_new ("enabled", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, ag_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN); /** * AgAccount::display-name-changed: * @account: the #AgAccount. * * Emitted when the account display name has changed. */ signals[DISPLAY_NAME_CHANGED] = g_signal_new ("display-name-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * AgAccount::deleted: * @account: the #AgAccount. * * Emitted when the account has been deleted. */ signals[DELETED] = g_signal_new ("deleted", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } AgAccountChanges * _ag_account_changes_from_dbus (AgManager *manager, GVariant *v_services, gboolean created, gboolean deleted) { AgAccountChanges *changes; AgServiceChanges *sc; GVariantIter i_serv, i_dict, i_list; GVariant *changed_keys, *removed_keys; gchar *service_name; gchar *service_type; gint service_id; changes = g_slice_new0 (AgAccountChanges); changes->created = created; changes->deleted = deleted; changes->services = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)ag_service_changes_free); /* parse the settings */ g_variant_iter_init (&i_serv, v_services); /* iterate the array, each element holds one service */ while (g_variant_iter_next (&i_serv, "(ssu@a{sv}@as)", &service_name, &service_type, &service_id, &changed_keys, &removed_keys)) { GVariant *variant; gchar *key; sc = g_slice_new0 (AgServiceChanges); if (service_name != NULL && strcmp (service_name, SERVICE_GLOBAL) == 0) sc->service = NULL; else sc->service = _ag_manager_get_service_lazy (manager, service_name, service_type, service_id); sc->service_type = service_type; sc->settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, ag_variant_safe_unref); g_hash_table_insert (changes->services, service_name, sc); /* iterate the "a{sv}" of settings */ g_variant_iter_init (&i_dict, changed_keys); while (g_variant_iter_next (&i_dict, "{sv}", &key, &variant)) { g_hash_table_insert (sc->settings, key, variant); } g_variant_unref (changed_keys); /* iterate the "as" of removed settings */ g_variant_iter_init (&i_list, removed_keys); while (g_variant_iter_next (&i_list, "s", &key)) { g_hash_table_insert (sc->settings, key, NULL); } g_variant_unref (removed_keys); } return changes; } static void add_service_type (GPtrArray *types, const gchar *service_type) { gboolean found = FALSE; guint i; /* if the service type is not yet in the list, add it */ for (i = 0; i < types->len; i++) { if (strcmp (service_type, g_ptr_array_index (types, i)) == 0) { found = TRUE; break; } } if (!found) g_ptr_array_add (types, (gchar *)service_type); } /** * _ag_account_changes_get_service_types: * @changes: the #AgAccountChanges structure. * * Gets the list of service types involved in the change. The list does not * contain duplicates. * * Returns: a newly-allocated GPtrArray (this must be freed, but not the * strings it holds!). */ GPtrArray * _ag_account_changes_get_service_types (AgAccountChanges *changes) { GPtrArray *ret = g_ptr_array_sized_new (8); if (changes->services) { GHashTableIter iter; AgServiceChanges *sc; g_hash_table_iter_init (&iter, changes->services); while (g_hash_table_iter_next (&iter, NULL, (gpointer)&sc)) { if (!sc->service_type) continue; add_service_type (ret, sc->service_type); } } /* if the account has been created or deleted, make sure that the global * service type is in the list */ if (changes->created || changes->deleted) add_service_type (ret, SERVICE_GLOBAL_TYPE); return ret; } gboolean _ag_account_changes_have_service_type (AgAccountChanges *changes, gchar *service_type) { if (changes->services) { GHashTableIter iter; AgServiceChanges *sc; g_hash_table_iter_init (&iter, changes->services); while (g_hash_table_iter_next (&iter, NULL, (gpointer)&sc)) { if (g_strcmp0(sc->service_type, service_type) == 0) return TRUE; } } return FALSE; } gboolean _ag_account_changes_have_enabled (AgAccountChanges *changes) { if (changes->services) { GHashTableIter iter; AgServiceChanges *sc; g_hash_table_iter_init (&iter, changes->services); while (g_hash_table_iter_next (&iter, NULL, (gpointer)&sc)) { const gchar *key = "enabled"; if (g_hash_table_lookup (sc->settings, (gpointer)key)) return TRUE; } } return FALSE; } static void ag_account_store_signature (AgAccount *account, AgServiceChanges *sc, GString *sql) { AgAccountId account_id; GHashTableIter i_signatures; gint service_id; gpointer ht_key, ht_value; account_id = account->id; service_id = (sc->service != NULL) ? sc->service->id : 0; g_hash_table_iter_init (&i_signatures, sc->signatures); while (g_hash_table_iter_next (&i_signatures, &ht_key, &ht_value)) { const gchar *key = ht_key; AgSignature *sgn = ht_value; if (sgn) { _ag_string_append_printf (sql, "INSERT OR REPLACE INTO Signatures" "(account, service, key, signature, token)" "VALUES (%d, %d, %Q, %Q, %Q);", account_id, service_id, key, sgn->signature, sgn->token); } } } static gchar * ag_account_get_store_sql (AgAccount *account, GError **error) { AgAccountPrivate *priv; AgAccountChanges *changes; GString *sql; gchar account_id_buffer[16]; const gchar *account_id_str; priv = account->priv; if (G_UNLIKELY (priv->deleted)) { *error = g_error_new (AG_ACCOUNTS_ERROR, AG_ACCOUNTS_ERROR_DELETED, "Account %s (id = %d) has been deleted", priv->display_name, account->id); return NULL; } changes = priv->changes; if (G_UNLIKELY (!changes)) { /* Nothing to do: return no SQL, and no error */ return NULL; } sql = g_string_sized_new (512); if (changes->deleted) { if (account->id != 0) { _ag_string_append_printf (sql, "DELETE FROM Accounts WHERE id = %d;", account->id); _ag_string_append_printf (sql, "DELETE FROM Settings WHERE account = %d;", account->id); } account_id_str = NULL; /* make the compiler happy */ } else if (account->id == 0) { gboolean enabled; const gchar *display_name; ag_account_changes_get_enabled (changes, &enabled); ag_account_changes_get_display_name (changes, &display_name); _ag_string_append_printf (sql, "INSERT INTO Accounts (name, provider, enabled) " "VALUES (%Q, %Q, %d);", display_name, priv->provider_name, enabled); g_string_append (sql, "SELECT set_last_rowid_as_account_id();"); account_id_str = "account_id()"; } else { gboolean enabled, enabled_changed, display_name_changed; const gchar *display_name; g_snprintf (account_id_buffer, sizeof (account_id_buffer), "%u", account->id); account_id_str = account_id_buffer; enabled_changed = ag_account_changes_get_enabled (changes, &enabled); display_name_changed = ag_account_changes_get_display_name (changes, &display_name); if (display_name_changed || enabled_changed) { gboolean comma = FALSE; g_string_append (sql, "UPDATE Accounts SET "); if (display_name_changed) { _ag_string_append_printf (sql, "name = %Q", display_name); comma = TRUE; } if (enabled_changed) { _ag_string_append_printf (sql, "%cenabled = %d", comma ? ',' : ' ', enabled); } _ag_string_append_printf (sql, " WHERE id = %d;", account->id); } } if (!changes->deleted) { GHashTableIter i_services; gpointer ht_key, ht_value; g_hash_table_iter_init (&i_services, changes->services); while (g_hash_table_iter_next (&i_services, &ht_key, &ht_value)) { AgServiceChanges *sc = ht_value; GHashTableIter i_settings; const gchar *service_id_str; gchar service_id_buffer[16]; if (sc->service) { g_snprintf (service_id_buffer, sizeof (service_id_buffer), "%d", sc->service->id); service_id_str = service_id_buffer; } else service_id_str = "0"; g_hash_table_iter_init (&i_settings, sc->settings); while (g_hash_table_iter_next (&i_settings, &ht_key, &ht_value)) { const gchar *key = ht_key; GVariant *value = ht_value; if (value) { const GVariantType *type_str; gchar *value_str; value_str = _ag_value_to_db (value, FALSE); type_str = g_variant_get_type (value); _ag_string_append_printf (sql, "INSERT OR REPLACE INTO Settings (account, service," "key, type, value) " "VALUES (%s, %s, %Q, %Q, %Q);", account_id_str, service_id_str, key, (const gchar *)type_str, value_str); g_free (value_str); } else if (account->id != 0) { _ag_string_append_printf (sql, "DELETE FROM Settings WHERE " "account = %d AND " "service = %Q AND " "key = %Q;", account->id, service_id_str, key); } } if (sc->signatures) ag_account_store_signature (account, sc, sql); } } return g_string_free (sql, FALSE); } /** * ag_account_supports_service: * @account: the #AgAccount. * @service_type: the name of the service type to check for * * Get whether @service_type is supported on @account. * * Returns: %TRUE if @account supports the service type @service_type, %FALSE * otherwise. */ gboolean ag_account_supports_service (AgAccount *account, const gchar *service_type) { GList *services; gboolean ret = FALSE; services = ag_account_list_services_by_type (account, service_type); if (services) { ag_service_list_free (services); ret = TRUE; } return ret; } /** * ag_account_list_services: * @account: the #AgAccount. * * Get the list of services for @account. If the #AgManager was created with * specified service_type this will return only services with this service_type. * * Returns: (transfer full) (element-type AgService): a #GList of #AgService * items representing all the services supported by this account. Must be * free'd with ag_service_list_free(). */ GList * ag_account_list_services (AgAccount *account) { AgAccountPrivate *priv; GList *all_services, *list; GList *services = NULL; g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); priv = account->priv; if (!priv->provider_name) return NULL; all_services = ag_manager_list_services (priv->manager); for (list = all_services; list != NULL; list = list->next) { AgService *service = list->data; const gchar *provider = ag_service_get_provider (service); if (provider && strcmp (provider, priv->provider_name) == 0) { services = g_list_prepend (services, service); } else ag_service_unref (service); } g_list_free (all_services); return services; } /** * ag_account_list_services_by_type: * @account: the #AgAccount. * @service_type: the service type which all the returned services should * provide. * * Get the list of services supported by @account, filtered by @service_type. * * Returns: (transfer full) (element-type AgService): a #GList of #AgService * items representing all the services supported by this account which provide * @service_type. Must be free'd with ag_service_list_free(). */ GList * ag_account_list_services_by_type (AgAccount *account, const gchar *service_type) { AgAccountPrivate *priv; GList *all_services, *list; GList *services = NULL; g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); g_return_val_if_fail (service_type != NULL, NULL); priv = account->priv; if (!priv->provider_name) return NULL; all_services = ag_manager_list_services_by_type (priv->manager, service_type); for (list = all_services; list != NULL; list = list->next) { AgService *service = list->data; const gchar *provider = ag_service_get_provider (service); if (provider && strcmp (provider, priv->provider_name) == 0) { services = g_list_prepend (services, service); } else ag_service_unref (service); } g_list_free (all_services); return services; } static gboolean add_name_to_list (sqlite3_stmt *stmt, GList **plist) { gchar *name; name = g_strdup ((gchar *)sqlite3_column_text (stmt, 0)); *plist = g_list_prepend(*plist, name); return TRUE; } static inline GList * list_enabled_services_from_memory (AgAccountPrivate *priv, const gchar *service_type) { GHashTableIter iter; AgServiceSettings *ss; GList *list = NULL; g_hash_table_iter_init (&iter, priv->services); while (g_hash_table_iter_next (&iter, NULL, (gpointer)&ss)) { GVariant *value; if (ss->service == NULL) continue; if (service_type != NULL && g_strcmp0 (ag_service_get_service_type (ss->service), service_type) != 0) continue; value = g_hash_table_lookup (ss->settings, "enabled"); if (value != NULL && g_variant_get_boolean (value)) list = g_list_prepend (list, ag_service_ref(ss->service)); } return list; } static AgAccountSettingIter * ag_account_settings_iter_copy(const AgAccountSettingIter *orig) { RealIter *copy; copy = (RealIter *)g_slice_dup (AgAccountSettingIter, orig); copy->last_gvalue = NULL; return (AgAccountSettingIter *)copy; } G_DEFINE_BOXED_TYPE (AgAccountSettingIter, ag_account_settings_iter, (GBoxedCopyFunc)ag_account_settings_iter_copy, (GBoxedFreeFunc)ag_account_settings_iter_free); void _ag_account_settings_iter_init (AgAccount *account, AgAccountSettingIter *iter, const gchar *key_prefix, gboolean copy_string) { AgAccountPrivate *priv; AgServiceSettings *ss; RealIter *ri = (RealIter *)iter; g_return_if_fail (AG_IS_ACCOUNT (account)); g_return_if_fail (iter != NULL); priv = account->priv; ri->account = account; if (copy_string) { ri->key_prefix = g_strdup (key_prefix); ri->must_free_prefix = TRUE; } else { ri->key_prefix = (gchar *)key_prefix; ri->must_free_prefix = FALSE; } ri->stage = AG_ITER_STAGE_UNSET; ss = get_service_settings (priv, priv->service, FALSE); if (ss) { g_hash_table_iter_init (&ri->iter, ss->settings); ri->stage = AG_ITER_STAGE_ACCOUNT; } ri->last_gvalue = NULL; } /** * ag_account_list_enabled_services: * @account: the #AgAccount. * * Gets a list of services that are enabled for @account. * * Returns: (transfer full) (element-type AgService): a #GList of #AgService * items representing all the services which are enabled. Must be free'd with * ag_service_list_free(). */ GList * ag_account_list_enabled_services (AgAccount *account) { AgAccountPrivate *priv; GList *list = NULL; GList *iter; GList *services = NULL; const gchar *service_type; char sql[512]; g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); priv = account->priv; service_type = ag_manager_get_service_type (priv->manager); /* avoid accessing the DB, if possible */ if (priv->foreign) return list_enabled_services_from_memory (priv, service_type); if (service_type != NULL) sqlite3_snprintf (sizeof (sql), sql, "SELECT DISTINCT Services.name FROM Services " "JOIN Settings ON Settings.service = Services.id " "WHERE Settings.key='enabled' " "AND Settings.value='true' " "AND Settings.account='%d' " "AND Services.type = '%s';", account->id, service_type); else sqlite3_snprintf (sizeof (sql), sql, "SELECT DISTINCT Services.name FROM Services " "JOIN Settings ON Settings.service = Services.id " "WHERE Settings.key='enabled' " "AND Settings.value='true' " "AND Settings.account='%d';", account->id); _ag_manager_exec_query (priv->manager, (AgQueryCallback)add_name_to_list, &list, sql); for (iter = list; iter != NULL; iter = iter->next) { gchar *service_name; AgService *service; service_name = (gchar*)iter->data; service = ag_manager_get_service (priv->manager, service_name); services = g_list_prepend (services, service); g_free (service_name); } g_list_free (list); return services; } /** * ag_account_get_manager: * @account: the #AgAccount. * * Get the #AgManager for @account. * * Returns: (transfer none): the #AgManager. */ AgManager * ag_account_get_manager (AgAccount *account) { g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); return account->priv->manager; } /** * ag_account_get_provider_name: * @account: the #AgAccount. * * Get the name of the provider of @account. * * Returns: the name of the provider. */ const gchar * ag_account_get_provider_name (AgAccount *account) { g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); return account->priv->provider_name; } /** * ag_account_get_display_name: * @account: the #AgAccount. * * Get the display name of @account. * * Returns: the display name. */ const gchar * ag_account_get_display_name (AgAccount *account) { g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); return account->priv->display_name; } /** * ag_account_set_display_name: * @account: the #AgAccount. * @display_name: the display name to set. * * Changes the display name for @account to @display_name. */ void ag_account_set_display_name (AgAccount *account, const gchar *display_name) { g_return_if_fail (AG_IS_ACCOUNT (account)); change_service_value (account->priv, NULL, "name", g_variant_new_string (display_name)); } /** * ag_account_select_service: * @account: the #AgAccount. * @service: (allow-none): the #AgService to select. * * Selects the configuration of service @service: from now on, all the * subsequent calls on the #AgAccount configuration will act on the @service. * If @service is %NULL, the global account configuration is selected. * * Note that if @account is being shared with other code one must take special * care to make sure the desired service is always selected. */ void ag_account_select_service (AgAccount *account, AgService *service) { AgAccountPrivate *priv; gboolean load_settings = FALSE; AgServiceSettings *ss; g_return_if_fail (AG_IS_ACCOUNT (account)); priv = account->priv; priv->service = service; if (account->id != 0 && !get_service_settings (priv, service, FALSE)) { /* the settings for this service are not yet loaded: do it now */ load_settings = TRUE; } ss = get_service_settings (priv, service, TRUE); if (load_settings) { guint service_id; gchar sql[128]; service_id = _ag_manager_get_service_id (priv->manager, service); g_snprintf (sql, sizeof (sql), "SELECT key, type, value FROM Settings " "WHERE account = %u AND service = %u", account->id, service_id); _ag_manager_exec_query (priv->manager, (AgQueryCallback)got_account_setting, ss->settings, sql); } } /** * ag_account_get_selected_service: * @account: the #AgAccount. * * Gets the selected #AgService for @account. * * Returns: the selected service, or %NULL if no service is selected. */ AgService * ag_account_get_selected_service (AgAccount *account) { g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); return account->priv->service; } /** * ag_account_get_enabled: * @account: the #AgAccount. * * Gets whether the selected service is enabled for @account. * * Returns: %TRUE if the selected service for @account is enabled, %FALSE * otherwise. */ gboolean ag_account_get_enabled (AgAccount *account) { AgAccountPrivate *priv; gboolean ret = FALSE; AgServiceSettings *ss; GVariant *val; g_return_val_if_fail (AG_IS_ACCOUNT (account), FALSE); priv = account->priv; if (priv->service == NULL) { ret = priv->enabled; } else { ss = get_service_settings (priv, priv->service, FALSE); if (ss) { val = g_hash_table_lookup (ss->settings, "enabled"); ret = val ? g_variant_get_boolean (val) : FALSE; } } return ret; } /** * ag_account_set_enabled: * @account: the #AgAccount. * @enabled: whether @account should be enabled. * * Sets the "enabled" flag on the selected service for @account. */ void ag_account_set_enabled (AgAccount *account, gboolean enabled) { g_return_if_fail (AG_IS_ACCOUNT (account)); change_selected_service_value (account->priv, "enabled", g_variant_new_boolean (enabled)); } /** * ag_account_delete: * @account: the #AgAccount. * * Deletes the account. Call ag_account_store() in order to record the change * in the storage. */ void ag_account_delete (AgAccount *account) { AgAccountChanges *changes; g_return_if_fail (AG_IS_ACCOUNT (account)); changes = account_changes_get (account->priv); changes->deleted = TRUE; } /** * ag_account_get_value: * @account: the #AgAccount. * @key: the name of the setting to retrieve. * @value: (inout): an initialized #GValue to receive the setting's value. * * Gets the value of the configuration setting @key: @value must be a * #GValue initialized to the type of the setting. * * Returns: one of #AgSettingSource: %AG_SETTING_SOURCE_NONE if the setting is * not present, %AG_SETTING_SOURCE_ACCOUNT if the setting comes from the * account configuration, or %AG_SETTING_SOURCE_PROFILE if the value comes as * predefined in the profile. * * Deprecated: 1.4: Use ag_account_get_variant() instead. */ AgSettingSource ag_account_get_value (AgAccount *account, const gchar *key, GValue *value) { AgSettingSource source; GValue val = G_VALUE_INIT; GVariant *variant; g_return_val_if_fail (AG_IS_ACCOUNT (account), AG_SETTING_SOURCE_NONE); variant = ag_account_get_variant (account, key, &source); if (variant != NULL) { _ag_value_from_variant (&val, variant); if (G_VALUE_TYPE (&val) == G_VALUE_TYPE (value)) g_value_copy (&val, value); else g_value_transform (&val, value); g_value_unset (&val); return source; } return AG_SETTING_SOURCE_NONE; } /** * ag_account_set_value: * @account: the #AgAccount. * @key: the name of the setting to change. * @value: (allow-none): a #GValue holding the new setting's value. * * Sets the value of the configuration setting @key to the value @value. * If @value is %NULL, then the setting is unset. * * Deprecated: 1.4: Use ag_account_set_variant() instead. */ void ag_account_set_value (AgAccount *account, const gchar *key, const GValue *value) { AgAccountPrivate *priv; GVariant *variant; g_return_if_fail (AG_IS_ACCOUNT (account)); priv = account->priv; if (value != NULL) { variant = _ag_value_to_variant (value); g_return_if_fail (variant != NULL); } else { variant = NULL; } change_selected_service_value (priv, key, variant); } /** * ag_account_get_variant: * @account: the #AgAccount. * @key: the name of the setting to retrieve. * @source: (allow-none) (out): a pointer to an * #AgSettingSource variable which will tell whether the setting was * retrieved from the accounts DB or from a service template. * * Gets the value of the configuration setting @key. * * Returns: (transfer none): a #GVariant holding the setting value, or * %NULL. The returned #GVariant is owned by the account, and no guarantees * are made about its lifetime. If the client wishes to keep it, it should * call g_variant_ref() on it. * * Since: 1.4 */ GVariant * ag_account_get_variant (AgAccount *account, const gchar *key, AgSettingSource *source) { AgAccountPrivate *priv; AgServiceSettings *ss; GVariant *value = NULL; g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); priv = account->priv; ss = get_service_settings (priv, priv->service, FALSE); if (ss) { value = g_hash_table_lookup (ss->settings, key); if (value != NULL) { if (source) *source = AG_SETTING_SOURCE_ACCOUNT; return value; } } if (priv->service) { value = _ag_service_get_default_setting (priv->service, key); } else if (ensure_has_provider (priv)) { value = _ag_provider_get_default_setting (priv->provider, key); } if (value != NULL) { if (source) *source = AG_SETTING_SOURCE_PROFILE; return value; } if (source) *source = AG_SETTING_SOURCE_NONE; return NULL; } /** * ag_account_set_variant: * @account: the #AgAccount. * @key: the name of the setting to change. * @value: (allow-none): a #GVariant holding the new setting's value. * * Sets the value of the configuration setting @key to the value @value. * If @value has a floating reference, the @account will take ownership * of it. * If @value is %NULL, then the setting is unset. * * Since: 1.4 */ void ag_account_set_variant (AgAccount *account, const gchar *key, GVariant *value) { AgAccountPrivate *priv; g_return_if_fail (AG_IS_ACCOUNT (account)); priv = account->priv; change_selected_service_value (priv, key, value); } /** * ag_account_get_settings_iter: * @account: the #AgAccount. * @key_prefix: (allow-none): enumerate only the settings whose key starts with * @key_prefix. * * Creates a new iterator. This method is useful for language bindings only. * * Returns: (transfer full): an #AgAccountSettingIter. */ AgAccountSettingIter * ag_account_get_settings_iter (AgAccount *account, const gchar *key_prefix) { AgAccountSettingIter *iter = g_slice_new (AgAccountSettingIter); _ag_account_settings_iter_init (account, iter, key_prefix, TRUE); return iter; } /** * ag_account_settings_iter_free: * @iter: a #AgAccountSettingIter. * * Frees the memory associated with an #AgAccountSettingIter. */ void ag_account_settings_iter_free (AgAccountSettingIter *iter) { if (iter == NULL) return; RealIter *ri = (RealIter *)iter; if (ri->must_free_prefix) g_free (ri->key_prefix); if (ri->last_gvalue != NULL) _ag_value_slice_free (ri->last_gvalue); g_slice_free (AgAccountSettingIter, iter); } /** * ag_account_settings_iter_init: * @account: the #AgAccount. * @iter: an uninitialized #AgAccountSettingIter structure. * @key_prefix: (allow-none): enumerate only the settings whose key starts with * @key_prefix. * * Initializes @iter to iterate over the account settings. If @key_prefix is * not %NULL, only keys whose names start with @key_prefix will be iterated * over. */ void ag_account_settings_iter_init (AgAccount *account, AgAccountSettingIter *iter, const gchar *key_prefix) { _ag_account_settings_iter_init (account, iter, key_prefix, FALSE); } /** * ag_account_settings_iter_next: * @iter: an initialized #AgAccountSettingIter structure. * @key: (out callee-allocates) (transfer none): a pointer to a string * receiving the key name. * @value: (out callee-allocates) (transfer none): a pointer to a pointer to a * #GValue, to receive the key value. * * Iterates over the account keys. @iter must be an iterator previously * initialized with ag_account_settings_iter_init(). * * Returns: %TRUE if @key and @value have been set, %FALSE if we there are no * more account settings to iterate over. * * Deprecated: 1.4: Use ag_account_settings_iter_get_next() instead. */ gboolean ag_account_settings_iter_next (AgAccountSettingIter *iter, const gchar **key, const GValue **value) { RealIter *ri = (RealIter *)iter; GVariant *variant; GValue *val; gboolean ok; /* Since AgAccount internally operates with GVariants, we need to * allocate a new GValue. The client, however, won't free it, so we * free it ourselves the next time that this function is called, or * when the iterator is freed. * NOTE: It's still possible that the GValue is leaked if the * AgAccountSettingIter was allocated on the stack and the loop was * interrupted before ag_account_settings_iter_next() returned * FALSE; however, this is not common (and we hope that clients * will soon migrate to the new GVariant API. */ if (ri->last_gvalue != NULL) { _ag_value_slice_free (ri->last_gvalue); ri->last_gvalue = NULL; } ok = ag_account_settings_iter_get_next (iter, key, &variant); if (!ok) { *value = NULL; return FALSE; } val = g_slice_new0 (GValue); _ag_value_from_variant (val, variant); ri->last_gvalue = val; *value = val; return TRUE; } /** * ag_account_settings_iter_get_next: * @iter: an initialized #AgAccountSettingIter structure. * @key: (out callee-allocates) (transfer none): a pointer to a string * receiving the key name. * @value: (out callee-allocates) (transfer none): a pointer to a pointer to a * #GVariant, to receive the key value. * * Iterates over the account keys. @iter must be an iterator previously * initialized with ag_account_settings_iter_init(). * * Returns: %TRUE if @key and @value have been set, %FALSE if we there are no * more account settings to iterate over. * * Since: 1.4 */ gboolean ag_account_settings_iter_get_next (AgAccountSettingIter *iter, const gchar **key, GVariant **value) { RealIter *ri = (RealIter *)iter; AgServiceSettings *ss; AgAccountPrivate *priv; gint prefix_length; g_return_val_if_fail (iter != NULL, FALSE); g_return_val_if_fail (AG_IS_ACCOUNT (iter->account), FALSE); g_return_val_if_fail (key != NULL && value != NULL, FALSE); priv = iter->account->priv; prefix_length = ri->key_prefix ? strlen(ri->key_prefix) : 0; if (ri->stage == AG_ITER_STAGE_ACCOUNT) { while (g_hash_table_iter_next (&ri->iter, (gpointer *)key, (gpointer *)value)) { if (ri->key_prefix && !g_str_has_prefix (*key, ri->key_prefix)) continue; *key = *key + prefix_length; return TRUE; } ri->stage = AG_ITER_STAGE_UNSET; } if (ri->stage == AG_ITER_STAGE_UNSET) { GHashTable *settings = NULL; if (priv->service != NULL) { settings = _ag_service_load_default_settings (priv->service); } else if (ensure_has_provider (priv)) { settings = _ag_provider_load_default_settings (priv->provider); } if (!settings) goto finish; g_hash_table_iter_init (&ri->iter, settings); ri->stage = AG_ITER_STAGE_SERVICE; } ss = get_service_settings (priv, priv->service, FALSE); while (g_hash_table_iter_next (&ri->iter, (gpointer *)key, (gpointer *)value)) { if (ri->key_prefix && !g_str_has_prefix (*key, ri->key_prefix)) continue; /* if the setting is also on the account, it is overriden and we must * not return it here */ if (ss && g_hash_table_lookup (ss->settings, *key) != NULL) continue; *key = *key + prefix_length; return TRUE; } finish: *key = NULL; *value = NULL; return FALSE; } /** * AgAccountNotifyCb: * @account: the #AgAccount. * @key: the name of the key whose value has changed. * @user_data: the user data that was passed when installing this callback. * * This callback is invoked when the value of an account configuration setting * changes. If the callback was installed with ag_account_watch_key() then @key * is the name of the configuration setting which changed; if it was installed * with ag_account_watch_dir() then @key is the same key prefix that was used * when installing this callback. */ /** * ag_account_watch_key: * @account: the #AgAccount. * @key: the name of the key to watch. * @callback: (scope async): a #AgAccountNotifyCb callback to be called. * @user_data: pointer to user data, to be passed to @callback. * * Installs a watch on @key: @callback will be invoked whenever the value of * @key changes (or the key is removed). * * Returns: (transfer none): a #AgAccountWatch, which can then be used to * remove this watch. */ AgAccountWatch ag_account_watch_key (AgAccount *account, const gchar *key, AgAccountNotifyCb callback, gpointer user_data) { g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); g_return_val_if_fail (key != NULL, NULL); g_return_val_if_fail (callback != NULL, NULL); return ag_account_watch_int (account, g_strdup (key), NULL, callback, user_data); } /** * ag_account_watch_dir: * @account: the #AgAccount. * @key_prefix: the prefix of the keys to watch. * @callback: (scope async): a #AgAccountNotifyCb callback to be called. * @user_data: pointer to user data, to be passed to @callback. * * Installs a watch on all the keys under @key_prefix: @callback will be * invoked whenever the value of any of these keys changes (or a key is * removed). * * Returns: (transfer none): a #AgAccountWatch, which can then be used to * remove this watch. */ AgAccountWatch ag_account_watch_dir (AgAccount *account, const gchar *key_prefix, AgAccountNotifyCb callback, gpointer user_data) { g_return_val_if_fail (AG_IS_ACCOUNT (account), NULL); g_return_val_if_fail (key_prefix != NULL, NULL); g_return_val_if_fail (callback != NULL, NULL); return ag_account_watch_int (account, NULL, g_strdup (key_prefix), callback, user_data); } /** * ag_account_remove_watch: * @account: the #AgAccount. * @watch: the watch to remove. * * Removes the notification callback identified by @watch. */ void ag_account_remove_watch (AgAccount *account, AgAccountWatch watch) { AgAccountPrivate *priv; GHashTable *service_watches; g_return_if_fail (AG_IS_ACCOUNT (account)); g_return_if_fail (watch != NULL); priv = account->priv; if (G_LIKELY (priv->watches)) { service_watches = g_hash_table_lookup (priv->watches, watch->service); if (G_LIKELY (service_watches && g_hash_table_remove (service_watches, watch))) return; /* success */ } g_warning ("Watch %p not found", watch); } /** * AgAccountStoreCb: * @account: the #AgAccount. * @error: a #GError, or %NULL. * @user_data: the user data that was passed to ag_account_store(). * * This callback is invoked when storing the account settings is completed. If * @error is not %NULL, then some error occurred and the data has most likely * not been written. */ /** * ag_account_store: * @account: the #AgAccount. * @callback: (scope async): function to be called when the settings have been * written. * @user_data: pointer to user data, to be passed to @callback. * * Commit the changed account settings to the account database, and invoke * @callback when the operation has been completed. * * Deprecated: 1.4: Use ag_account_store_async() instead. */ void ag_account_store (AgAccount *account, AgAccountStoreCb callback, gpointer user_data) { AsyncReadyCbWrapperData *cb_data; g_return_if_fail (AG_IS_ACCOUNT (account)); cb_data = g_slice_new (AsyncReadyCbWrapperData); cb_data->callback = callback; cb_data->user_data = user_data; ag_account_store_async (account, NULL, async_ready_cb_wrapper, cb_data); } /** * ag_account_store_async: * @account: the #AgAccount. * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @callback: (scope async): function to be called when the settings have been * written. * @user_data: pointer to user data, to be passed to @callback. * * Commit the changed account settings to the account database, and invoke * @callback when the operation has been completed. * * Since: 1.4 */ void ag_account_store_async (AgAccount *account, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { AgAccountPrivate *priv; AgAccountChanges *changes; GError *error = NULL; gchar *sql; g_return_if_fail (AG_IS_ACCOUNT (account)); priv = account->priv; if (G_UNLIKELY (priv->store_async_result != NULL)) { g_critical ("ag_account_store_async called again before completion"); g_simple_async_report_error_in_idle ((GObject *)account, callback, user_data, AG_ACCOUNTS_ERROR, AG_ACCOUNTS_ERROR_STORE_IN_PROGRESS, "Store operation already " "in progress"); return; } priv->store_async_result = g_simple_async_result_new ((GObject *)account, callback, user_data, ag_account_store_async); g_simple_async_result_set_check_cancellable (priv->store_async_result, cancellable); sql = ag_account_get_store_sql (account, &error); if (G_UNLIKELY (error)) { g_simple_async_result_take_error (priv->store_async_result, error); g_simple_async_result_complete_in_idle (priv->store_async_result); g_clear_object (&priv->store_async_result); return; } changes = priv->changes; priv->changes = NULL; if (G_UNLIKELY (!sql)) { /* Nothing to do: invoke the callback immediately */ g_simple_async_result_complete_in_idle (priv->store_async_result); g_clear_object (&priv->store_async_result); return; } _ag_manager_exec_transaction (priv->manager, sql, changes, account, priv->store_async_result, cancellable); g_free (sql); } /** * ag_account_store_finish: * @account: the #AgAccount. * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to * ag_account_store_async(). * @error: return location for error, or %NULL. * * Finishes the store operation started by ag_account_store_async(). * * Returns: %TRUE on success, %FALSE otherwise. * * Since: 1.4 */ gboolean ag_account_store_finish (AgAccount *account, GAsyncResult *res, GError **error) { GSimpleAsyncResult *async_result; g_return_val_if_fail (AG_IS_ACCOUNT (account), FALSE); async_result = (GSimpleAsyncResult *)res; return !g_simple_async_result_propagate_error (async_result, error); } /** * ag_account_store_blocking: * @account: the #AgAccount. * @error: pointer to receive the #GError, or %NULL. * * Commit the changed account settings to the account database, and invoke * @callback when the operation has been completed. * * Returns: %TRUE on success, %FALSE on failure. */ gboolean ag_account_store_blocking (AgAccount *account, GError **error) { AgAccountPrivate *priv; AgAccountChanges *changes; GError *error_int = NULL; gchar *sql; g_return_val_if_fail (AG_IS_ACCOUNT (account), FALSE); priv = account->priv; sql = ag_account_get_store_sql (account, &error_int); if (G_UNLIKELY (error_int)) { g_warning ("%s: %s", G_STRFUNC, error_int->message); g_propagate_error (error, error_int); return FALSE; } changes = priv->changes; priv->changes = NULL; if (G_UNLIKELY (!sql)) { /* Nothing to do: return immediately */ return TRUE; } _ag_manager_exec_transaction_blocking (priv->manager, sql, changes, account, &error_int); g_free (sql); _ag_account_changes_free (changes); if (G_UNLIKELY (error_int)) { g_warning ("%s: %s", G_STRFUNC, error_int->message); g_propagate_error (error, error_int); return FALSE; } return TRUE; } /** * ag_account_sign: * @account: the #AgAccount. * @key: the name of the key or prefix of the keys to be signed. * @token: a signing token (%NULL-terminated string) for creating the * signature. The application must possess (request) the token. * * Creates signature of the @key with given @token. The account must be * stored prior to calling this function. */ void ag_account_sign (G_GNUC_UNUSED AgAccount *account, G_GNUC_UNUSED const gchar *key, G_GNUC_UNUSED const gchar *token) { g_warning ("ag_account_sign: no encryptor supported."); } /** * ag_account_verify: * @account: the #AgAccount. * @key: the name of the key or prefix of the keys to be verified. * @token: location to receive the pointer to aegis token. * * Verify if the key is signed and the signature matches the value * and provides the aegis token which was used for signing the @key. * * Returns: %TRUE if the key is signed and the signature matches the value, * %FALSE otherwise. */ gboolean ag_account_verify (G_GNUC_UNUSED AgAccount *account, G_GNUC_UNUSED const gchar *key, G_GNUC_UNUSED const gchar **token) { g_warning ("ag_account_verify: no encryptor supported."); return FALSE; } /** * ag_account_verify_with_tokens: * @account: the #AgAccount. * @key: the name of the key or prefix of the keys to be verified. * @tokens: array of aegis tokens. * * Verify if the @key is signed with any of the tokens from the @tokens * and the signature is valid. * * Returns: %TRUE if the key is signed with any of the given tokens and the * signature is valid, %FALSE otherwise. */ gboolean ag_account_verify_with_tokens (AgAccount *account, const gchar *key, const gchar **tokens) { g_return_val_if_fail (AG_IS_ACCOUNT (account), FALSE); const gchar *tmp_token = NULL; g_return_val_if_fail (tokens != NULL, FALSE); if (ag_account_verify (account, key, &tmp_token)) { g_return_val_if_fail (tmp_token != NULL, FALSE); while (*tokens != NULL) { if (strcmp (tmp_token, *tokens) == 0) { return TRUE; } tokens++; } } return FALSE; } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-util.c0000644000015000001560000003732712245170671024321 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * Copyright (C) 2012 Intel Corporation. * * Contact: Alberto Mardegan * Contact: Jussi Laako * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 "ag-util.h" #include "ag-debug.h" #include "ag-errors.h" #include #include #include #include #include GString * _ag_string_append_printf (GString *string, const gchar *format, ...) { va_list ap; char *sql; va_start (ap, format); sql = sqlite3_vmprintf (format, ap); va_end (ap); if (sql) { g_string_append (string, sql); sqlite3_free (sql); } return string; } GValue * _ag_value_slice_dup (const GValue *value) { GValue *copy; if (!value) return NULL; copy = g_slice_new0 (GValue); g_value_init (copy, G_VALUE_TYPE (value)); g_value_copy (value, copy); return copy; } void _ag_value_slice_free (GValue *value) { if (!value) return; g_value_unset (value); g_slice_free (GValue, value); } GVariant * _ag_value_to_variant (const GValue *in_value) { const GVariantType *type; GValue transformed_value = G_VALUE_INIT; const GValue *value; g_return_val_if_fail (in_value != NULL, NULL); /* transform some GValues which g_dbus_gvalue_to_gvariant() cannot handle */ if (G_VALUE_TYPE (in_value) == G_TYPE_CHAR) { g_value_init (&transformed_value, G_TYPE_INT); if (G_UNLIKELY (!g_value_transform (in_value, &transformed_value))) { g_warning ("%s: could not transform %s to %s", G_STRFUNC, G_VALUE_TYPE_NAME (in_value), G_VALUE_TYPE_NAME (&transformed_value)); return NULL; } value = &transformed_value; } else { value = in_value; } type = _ag_type_from_g_type (G_VALUE_TYPE (value)); return g_dbus_gvalue_to_gvariant (value, type); } gchar * _ag_value_to_db (GVariant *value, gboolean type_annotate) { return g_variant_print (value, type_annotate); } const GVariantType * _ag_type_from_g_type (GType type) { switch (type) { case G_TYPE_STRING: return G_VARIANT_TYPE_STRING; case G_TYPE_INT: case G_TYPE_CHAR: return G_VARIANT_TYPE_INT32; case G_TYPE_UINT: return G_VARIANT_TYPE_UINT32; case G_TYPE_BOOLEAN: return G_VARIANT_TYPE_BOOLEAN; case G_TYPE_UCHAR: return G_VARIANT_TYPE_BYTE; case G_TYPE_INT64: return G_VARIANT_TYPE_INT64; case G_TYPE_UINT64: return G_VARIANT_TYPE_UINT64; default: /* handle dynamic types here */ if (type == G_TYPE_STRV) return G_VARIANT_TYPE_STRING_ARRAY; g_warning ("%s: unsupported type ``%s''", G_STRFUNC, g_type_name (type)); return NULL; } } void _ag_value_from_variant (GValue *value, GVariant *variant) { g_dbus_gvariant_to_gvalue (variant, value); } static GVariant * _ag_value_from_string (const gchar *type, const gchar *string) { GVariant *variant; GError *error = NULL; if (G_UNLIKELY (!string)) return NULL; /* g_variant_parse() expects all strings to be enclosed in quotes, which we * wouldn't like to enforce in the XML files. So, if we know that we are * reading a string, just build the GValue right away */ if (type != NULL && type[0] == 's' && type[1] == '\0' && string[0] != '"' && string[0] != '\'') { return g_variant_new_string (string); } variant = g_variant_parse ((GVariantType *)type, string, NULL, NULL, &error); if (error != 0) { g_warning ("%s: error parsing type \"%s\" ``%s'': %s", G_STRFUNC, type, string, error->message); g_error_free (error); return NULL; } return variant; } GVariant * _ag_value_from_db (sqlite3_stmt *stmt, gint col_type, gint col_value) { gchar *string_value; gchar *type; type = (gchar *)sqlite3_column_text (stmt, col_type); string_value = (gchar *)sqlite3_column_text (stmt, col_value); return _ag_value_from_string (type, string_value); } /** * ag_errors_quark: * * Return the libaccounts-glib error domain. * * Returns: the libaccounts-glib error domain. */ GQuark ag_errors_quark (void) { static gsize quark = 0; if (g_once_init_enter (&quark)) { GQuark domain = g_quark_from_static_string ("ag_errors"); g_assert (sizeof (GQuark) <= sizeof (gsize)); g_once_init_leave (&quark, domain); } return (GQuark) quark; } /** * ag_accounts_error_quark: * * Return the libaccounts-glib error domain. * * Returns: the libaccounts-glib error domain. */ GQuark ag_accounts_error_quark (void) { return ag_errors_quark (); } gboolean _ag_xml_get_element_data (xmlTextReaderPtr reader, const gchar **dest_ptr) { gint node_type; if (dest_ptr) *dest_ptr = NULL; if (xmlTextReaderIsEmptyElement (reader)) return TRUE; if (xmlTextReaderRead (reader) != 1) return FALSE; node_type = xmlTextReaderNodeType (reader); if (node_type != XML_READER_TYPE_TEXT) return (node_type == XML_READER_TYPE_END_ELEMENT) ? TRUE : FALSE; if (dest_ptr) *dest_ptr = (const gchar *)xmlTextReaderConstValue (reader); return TRUE; } static gboolean close_element (xmlTextReaderPtr reader) { if (xmlTextReaderRead (reader) != 1 || xmlTextReaderNodeType (reader) != XML_READER_TYPE_END_ELEMENT) return FALSE; return TRUE; } gboolean _ag_xml_dup_element_data (xmlTextReaderPtr reader, gchar **dest_ptr) { const gchar *data; gboolean ret; ret = _ag_xml_get_element_data (reader, &data); if (dest_ptr) *dest_ptr = g_strdup (data); close_element (reader); return ret; } gboolean _ag_xml_get_boolean (xmlTextReaderPtr reader, gboolean *dest_boolean) { GVariant *variant; const gchar *data; gboolean ok; ok = _ag_xml_get_element_data (reader, &data); if (G_UNLIKELY (!ok)) return FALSE; variant = _ag_value_from_string ("b", data); if (G_UNLIKELY (variant == NULL)) return FALSE; *dest_boolean = g_variant_get_boolean (variant); ok = close_element (reader); return ok; } static gboolean parse_param (xmlTextReaderPtr reader, GVariant **value) { const gchar *str_value; xmlChar *str_type = NULL; gboolean ok; const gchar *type; str_type = xmlTextReaderGetAttribute (reader, (xmlChar *) "type"); if (!str_type) type = "s"; else { type = (const gchar*)str_type; } ok = _ag_xml_get_element_data (reader, &str_value); if (G_UNLIKELY (!ok)) goto error; /* Empty value is not an error, but simply ignored */ if (G_UNLIKELY (!str_value)) goto finish; *value = _ag_value_from_string (type, str_value); ok = close_element (reader); if (G_UNLIKELY (!ok)) goto error; finish: ok = TRUE; error: if (str_type != NULL) xmlFree(str_type); return TRUE; } gboolean _ag_xml_parse_settings (xmlTextReaderPtr reader, const gchar *group, GHashTable *settings) { const gchar *name; int ret, type; ret = xmlTextReaderRead (reader); while (ret == 1) { name = (const gchar *)xmlTextReaderConstName (reader); if (G_UNLIKELY (!name)) return FALSE; type = xmlTextReaderNodeType (reader); if (type == XML_READER_TYPE_END_ELEMENT) break; if (type == XML_READER_TYPE_ELEMENT) { gboolean ok; DEBUG_INFO ("found name %s", name); if (strcmp (name, "setting") == 0) { GVariant *value = NULL; xmlChar *key_name; gchar *key; key_name = xmlTextReaderGetAttribute (reader, (xmlChar *)"name"); key = g_strdup_printf ("%s%s", group, (const gchar*)key_name); if (key_name) xmlFree (key_name); ok = parse_param (reader, &value); if (ok && value != NULL) { g_variant_ref_sink (value); g_hash_table_insert (settings, key, value); } else g_free (key); } else if (strcmp (name, "group") == 0 && xmlTextReaderHasAttributes (reader)) { /* it's a subgroup */ if (!xmlTextReaderIsEmptyElement (reader)) { xmlChar *group_name; gchar *subgroup; group_name = xmlTextReaderGetAttribute (reader, (xmlChar *)"name"); subgroup = g_strdup_printf ("%s%s/", group, (const gchar *)group_name); if (group_name) xmlFree (group_name); ok = _ag_xml_parse_settings (reader, subgroup, settings); g_free (subgroup); } else ok = TRUE; } else { g_warning ("%s: using wrong XML for groups; " "please change to ", xmlTextReaderConstBaseUri (reader), name); /* it's a subgroup */ if (!xmlTextReaderIsEmptyElement (reader)) { gchar *subgroup; subgroup = g_strdup_printf ("%s%s/", group, name); ok = _ag_xml_parse_settings (reader, subgroup, settings); g_free (subgroup); } else ok = TRUE; } if (G_UNLIKELY (!ok)) return FALSE; } ret = xmlTextReaderNext (reader); } return TRUE; } gboolean _ag_xml_parse_element_list (xmlTextReaderPtr reader, const gchar *match, GHashTable **list) { gboolean ok = FALSE; const gchar *ename; gchar *data; int res, etype; *list = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); res = xmlTextReaderRead (reader); while (res == 1) { ename = (const gchar *) xmlTextReaderConstName (reader); if (G_UNLIKELY (!ename)) return FALSE; etype = xmlTextReaderNodeType (reader); if (etype == XML_READER_TYPE_END_ELEMENT) break; if (etype == XML_READER_TYPE_ELEMENT) { if (strcmp (ename, match) == 0) { if (_ag_xml_dup_element_data (reader, &data)) { g_hash_table_insert (*list, data, NULL); ok = TRUE; } else return FALSE; } } res = xmlTextReaderNext (reader); } return ok; } static inline gboolean _esc_ident_bad (gchar c, gboolean is_first) { return ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9' || is_first)); } /** * _ag_dbus_escape_as_identifier: * @name: The string to be escaped * * Taken from telepathy-glib's tp_escape_as_identifier(). * * Escape an arbitrary string so it follows the rules for a C identifier, * and hence an object path component, interface element component, * bus name component or member name in D-Bus. * * Unlike g_strcanon this is a reversible encoding, so it preserves * distinctness. * * The escaping consists of replacing all non-alphanumerics, and the first * character if it's a digit, with an underscore and two lower-case hex * digits: * * "0123abc_xyz\x01\xff" -> _30123abc_5fxyz_01_ff * * i.e. similar to URI encoding, but with _ taking the role of %, and a * smaller allowed set. As a special case, "" is escaped to "_" (just for * completeness, really). * * Returns: the escaped string, which must be freed by the caller with #g_free */ gchar * _ag_dbus_escape_as_identifier (const gchar *name) { gboolean bad = FALSE; size_t len = 0; GString *op; const gchar *ptr, *first_ok; g_return_val_if_fail (name != NULL, NULL); /* fast path for empty name */ if (name[0] == '\0') return g_strdup ("_"); for (ptr = name; *ptr; ptr++) { if (_esc_ident_bad (*ptr, ptr == name)) { bad = TRUE; len += 3; } else len++; } /* fast path if it's clean */ if (!bad) return g_strdup (name); /* If strictly less than ptr, first_ok is the first uncopied safe * character. */ first_ok = name; op = g_string_sized_new (len); for (ptr = name; *ptr; ptr++) { if (_esc_ident_bad (*ptr, ptr == name)) { /* copy preceding safe characters if any */ if (first_ok < ptr) { g_string_append_len (op, first_ok, ptr - first_ok); } /* escape the unsafe character */ g_string_append_printf (op, "_%02x", (unsigned char)(*ptr)); /* restart after it */ first_ok = ptr + 1; } } /* copy trailing safe characters if any */ if (first_ok < ptr) { g_string_append_len (op, first_ok, ptr - first_ok); } return g_string_free (op, FALSE); } /** * _ag_find_libaccounts_file: * @file_id: the base name of the file, without suffix. * @suffix: the file suffix. * @env_var: name of the environment variable which could specify an override * path. * @subdir: file will be searched in $XDG_DATA_DIRS// * * Search for the libaccounts file @file_id. * * Returns: the path of the file, if found, %NULL otherwise. */ gchar * _ag_find_libaccounts_file (const gchar *file_id, const gchar *suffix, const gchar *env_var, const gchar *subdir) { const gchar * const *dirs; const gchar *dirname; const gchar *env_dirname; gchar *filename, *filepath; filename = g_strconcat (file_id, suffix, NULL); env_dirname = g_getenv (env_var); if (env_dirname) { filepath = g_build_filename (env_dirname, filename, NULL); if (g_file_test (filepath, G_FILE_TEST_IS_REGULAR)) goto found; g_free (filepath); } dirname = g_get_user_data_dir (); if (G_LIKELY (dirname)) { filepath = g_build_filename (dirname, subdir, filename, NULL); if (g_file_test (filepath, G_FILE_TEST_IS_REGULAR)) goto found; g_free (filepath); } dirs = g_get_system_data_dirs (); for (dirname = *dirs; dirname != NULL; dirs++, dirname = *dirs) { filepath = g_build_filename (dirname, subdir, filename, NULL); if (g_file_test (filepath, G_FILE_TEST_IS_REGULAR)) goto found; g_free (filepath); } filepath = NULL; found: g_free (filename); return filepath; } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-provider.c0000644000015000001560000003453512245170671025174 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012-2013 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** * SECTION:ag-provider * @short_description: A representation of a provider. * @include: libaccounts-glib/ag-provider.h * * The #AgProvider structure represents an account provider. The structure is * not directly exposed to applications, but its fields are accessible via * getter methods. It can be instantiated by #AgManager with * ag_manager_get_provider() or ag_manager_list_providers(). * The structure is reference counted. One must use ag_provider_unref() when * done with it. * * See the example of creating a * new AgAccount to see how #AgProvider can be * used. */ #include "config.h" #include "ag-provider.h" #include "ag-internals.h" #include "ag-util.h" #include #include G_DEFINE_BOXED_TYPE (AgProvider, ag_provider, (GBoxedCopyFunc)ag_provider_ref, (GBoxedFreeFunc)ag_provider_unref); static gboolean parse_template (xmlTextReaderPtr reader, AgProvider *provider) { GHashTable *settings; gboolean ok; g_return_val_if_fail (provider->default_settings == NULL, FALSE); settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); ok = _ag_xml_parse_settings (reader, "", settings); if (G_UNLIKELY (!ok)) { g_hash_table_destroy (settings); return FALSE; } provider->default_settings = settings; return TRUE; } static gboolean parse_provider (xmlTextReaderPtr reader, AgProvider *provider) { const gchar *name; int ret, type; if (!provider->name) { xmlChar *_name = xmlTextReaderGetAttribute (reader, (xmlChar *) "id"); provider->name = g_strdup((const gchar *)_name); if (_name) xmlFree(_name); } ret = xmlTextReaderRead (reader); while (ret == 1) { name = (const gchar *)xmlTextReaderConstName (reader); if (G_UNLIKELY (!name)) return FALSE; type = xmlTextReaderNodeType (reader); if (type == XML_READER_TYPE_END_ELEMENT && strcmp (name, "provider") == 0) break; if (type == XML_READER_TYPE_ELEMENT) { gboolean ok; if (strcmp (name, "name") == 0 && !provider->display_name) { ok = _ag_xml_dup_element_data (reader, &provider->display_name); /* that's the only thing we are interested of: we can stop the * parsing now. */ } else if (strcmp (name, "description") == 0) { ok = _ag_xml_dup_element_data (reader, &provider->description); } else if (strcmp (name, "translations") == 0) { ok = _ag_xml_dup_element_data (reader, &provider->i18n_domain); } else if (strcmp (name, "icon") == 0) { ok = _ag_xml_dup_element_data (reader, &provider->icon_name); } else if (strcmp (name, "domains") == 0) { ok = _ag_xml_dup_element_data (reader, &provider->domains); } else if (strcmp (name, "plugin") == 0) { ok = _ag_xml_dup_element_data (reader, &provider->plugin_name); } else if (strcmp (name, "single-account") == 0) { ok = _ag_xml_get_boolean (reader, &provider->single_account); } else if (strcmp (name, "template") == 0) { ok = parse_template (reader, provider); } else ok = TRUE; if (G_UNLIKELY (!ok)) return FALSE; } ret = xmlTextReaderNext (reader); } return TRUE; } static gboolean read_provider_file (xmlTextReaderPtr reader, AgProvider *provider) { const xmlChar *name; int ret, type; ret = xmlTextReaderRead (reader); while (ret == 1) { type = xmlTextReaderNodeType (reader); if (type == XML_READER_TYPE_ELEMENT) { name = xmlTextReaderConstName (reader); if (G_LIKELY (name && strcmp ((const gchar *)name, "provider") == 0)) { return parse_provider (reader, provider); } } ret = xmlTextReaderNext (reader); } return FALSE; } static AgProvider * _ag_provider_new (void) { AgProvider *provider; provider = g_slice_new0 (AgProvider); provider->ref_count = 1; return provider; } static gboolean _ag_provider_load_from_file (AgProvider *provider) { xmlTextReaderPtr reader; gchar *filepath; gboolean ret; GError *error = NULL; gsize len; g_return_val_if_fail (provider->name != NULL, FALSE); DEBUG_REFS ("Loading provider %s", provider->name); filepath = _ag_find_libaccounts_file (provider->name, ".provider", "AG_PROVIDERS", PROVIDER_FILES_DIR); if (G_UNLIKELY (!filepath)) return FALSE; g_file_get_contents (filepath, &provider->file_data, &len, &error); if (G_UNLIKELY (error)) { g_warning ("Error reading %s: %s", filepath, error->message); g_error_free (error); g_free (filepath); return FALSE; } g_free (filepath); /* TODO: cache the xmlReader */ reader = xmlReaderForMemory (provider->file_data, len, NULL, NULL, 0); if (G_UNLIKELY (reader == NULL)) return FALSE; ret = read_provider_file (reader, provider); xmlFreeTextReader (reader); return ret; } AgProvider * _ag_provider_new_from_file (const gchar *provider_name) { AgProvider *provider; provider = _ag_provider_new (); provider->name = g_strdup (provider_name); if (!_ag_provider_load_from_file (provider)) { ag_provider_unref (provider); provider = NULL; } return provider; } GHashTable * _ag_provider_load_default_settings (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); if (!provider->default_settings) { /* This can happen if the provider was created by the AccountManager by * loading the record from the DB. * Now we must reload the provider from its XML file. */ if (!_ag_provider_load_from_file (provider)) { g_warning ("Loading provider %s file failed", provider->name); return NULL; } } return provider->default_settings; } GVariant * _ag_provider_get_default_setting (AgProvider *provider, const gchar *key) { GHashTable *settings; g_return_val_if_fail (key != NULL, NULL); settings = _ag_provider_load_default_settings (provider); if (G_UNLIKELY (!settings)) return NULL; return g_hash_table_lookup (settings, key); } /** * ag_provider_get_name: * @provider: the #AgProvider. * * Get the name of the #AgProvider. * * Returns: the name of @provider. */ const gchar * ag_provider_get_name (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); return provider->name; } /** * ag_provider_get_i18n_domain: * @provider: the #AgProvider. * * Get the translation domain of the #AgProvider. * * Returns: the translation domain. */ const gchar * ag_provider_get_i18n_domain (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); return provider->i18n_domain; } /** * ag_provider_get_icon_name: * @provider: the #AgProvider. * * Get the icon name of the #AgProvider. * * Returns: the icon_name. */ const gchar * ag_provider_get_icon_name (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); return provider->icon_name; } /** * ag_provider_get_display_name: * @provider: the #AgProvider. * * Get the display name of the #AgProvider. * * Returns: the display name of @provider. */ const gchar * ag_provider_get_display_name (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); return provider->display_name; } /** * ag_provider_get_description: * @provider: the #AgProvider. * * Get the description of the #AgProvider. * * Returns: the description of @provider, or %NULL upon failure. * * Since: 1.2 */ const gchar * ag_provider_get_description (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); return provider->description; } /** * ag_provider_get_domains_regex: * @provider: the #AgProvider. * * Get a regular expression matching all domains where this provider's accounts * can be used. * * Returns: a regular expression matching the domain names. * * Since: 1.1 */ const gchar * ag_provider_get_domains_regex (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); return provider->domains; } /** * ag_provider_match_domain: * @provider: the #AgProvider. * @domain: a domain name. * * Check whether @domain is supported by this provider, by matching it with the * regex returned by ag_provider_get_domains_regex(). * If the provider does not define a regular expression to match the supported * domains, this function will return %FALSE. * * Returns: %TRUE if the given domain is supported, %FALSE otherwise. * * Since: 1.2 */ gboolean ag_provider_match_domain (AgProvider *provider, const gchar *domain) { g_return_val_if_fail (provider != NULL, FALSE); g_return_val_if_fail (domain != NULL, FALSE); if (provider->domains == NULL) return FALSE; return g_regex_match_simple (provider->domains, domain, 0, 0); } /** * ag_provider_get_plugin_name: * @provider: the #AgProvider. * * Get the name of the account plugin which manages all accounts created from * this #AgProvider. * Some platforms might find it useful to store plugin names in the provider * XML files, especially when the same plugin can work for different providers. * * Returns: the plugin name for @provider, or %NULL if a plugin name is not * defined. * * Since: 1.5 */ const gchar * ag_provider_get_plugin_name (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); return provider->plugin_name; } /** * ag_provider_get_single_account: * @provider: the #AgProvider. * * Tell whether the provider doesn't support creating more than one account. * Note that libaccounts itself does not enforce preventing the creation of * multiple accounts when this flag is set: the flag is only informative, and * its implementation is left to the client. * * Returns: %FALSE if multiple accounts can be created from this provider, * %TRUE otherwise. * * Since: 1.14 */ gboolean ag_provider_get_single_account (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); return provider->single_account; } /** * ag_provider_get_file_contents: * @provider: the #AgProvider. * @contents: location to receive the pointer to the file contents. * * Gets the contents of the XML provider file. The buffer returned in @contents * should not be modified or freed, and is guaranteed to be valid as long as * @provider is referenced. * If some error occurs, @contents is set to %NULL. */ void ag_provider_get_file_contents (AgProvider *provider, const gchar **contents) { g_return_if_fail (provider != NULL); g_return_if_fail (contents != NULL); if (provider->file_data == NULL) { /* This can happen if the provider was created by the AccountManager by * loading the record from the DB. * Now we must reload the provider from its XML file. */ if (!_ag_provider_load_from_file (provider)) g_warning ("Loading provider %s file failed", provider->name); } *contents = provider->file_data; } /** * ag_provider_ref: * @provider: the #AgProvider. * * Adds a reference to @provider. * * Returns: @provider. */ AgProvider * ag_provider_ref (AgProvider *provider) { g_return_val_if_fail (provider != NULL, NULL); g_return_val_if_fail (provider->ref_count > 0, NULL); DEBUG_REFS ("Referencing provider %s (%d)", provider->name, provider->ref_count); provider->ref_count++; return provider; } /** * ag_provider_unref: * @provider: the #AgProvider. * * Used to unreference the #AgProvider structure. */ void ag_provider_unref (AgProvider *provider) { g_return_if_fail (provider != NULL); g_return_if_fail (provider->ref_count > 0); DEBUG_REFS ("Unreferencing provider %s (%d)", provider->name, provider->ref_count); provider->ref_count--; if (provider->ref_count == 0) { g_free (provider->name); g_free (provider->i18n_domain); g_free (provider->icon_name); g_free (provider->description); g_free (provider->display_name); g_free (provider->domains); g_free (provider->file_data); g_slice_free (AgProvider, provider); } } /** * ag_provider_list_free: * @list: (element-type AgProvider): a #GList of providers returned by some * function of this library. * * Frees the list @list. */ void ag_provider_list_free (GList *list) { g_list_foreach (list, (GFunc)ag_provider_unref, NULL); g_list_free (list); } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-service-type.c0000644000015000001560000003014312245170671025750 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2010 Nokia Corporation. * Copyright (C) 2012 Canonical Ltd. * Copyright (C) 2012 Intel Corporation. * * Contact: Alberto Mardegan * Contact: Jussi Laako * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** * SECTION:ag-service-type * @short_description: A description of a service type. * @include: libaccounts-glib/ag-service-type.h * * The #AgServiceType structure represents a service type. The structure is * not directly exposed to applications, but its fields are accessible via * getter methods. * It is instantiated by #AgManager with ag_manager_list_service_types() or * ag_manager_load_service_type(). Additonally, #AgManager can be instantiated * with a set service type with ag_manager_new_for_service_type(), which * restricts some future operations on the manager, such as ag_manager_list() * or ag_manager_list_services(), to only affect accounts or services with the * set service type. * The structure is reference counted. One must use ag_service_type_unref() * when done with it. */ #include "config.h" #include "ag-service-type.h" #include "ag-internals.h" #include "ag-util.h" #include #include struct _AgServiceType { /*< private >*/ gint ref_count; gchar *name; gchar *i18n_domain; gchar *display_name; gchar *description; gchar *icon_name; gchar *file_data; gsize file_data_len; GHashTable *tags; }; G_DEFINE_BOXED_TYPE (AgServiceType, ag_service_type, (GBoxedCopyFunc)ag_service_type_ref, (GBoxedFreeFunc)ag_service_type_unref); static gboolean parse_service_type (xmlTextReaderPtr reader, AgServiceType *service_type) { const gchar *name; int ret, type; if (!service_type->name) { xmlChar *_name = xmlTextReaderGetAttribute (reader, (xmlChar *) "id"); service_type->name = g_strdup ((const gchar *)_name); if (_name) xmlFree(_name); } ret = xmlTextReaderRead (reader); while (ret == 1) { name = (const gchar *)xmlTextReaderConstName (reader); if (G_UNLIKELY (!name)) return FALSE; type = xmlTextReaderNodeType (reader); if (type == XML_READER_TYPE_END_ELEMENT && strcmp (name, "service-type") == 0) break; if (type == XML_READER_TYPE_ELEMENT) { gboolean ok; if (strcmp (name, "name") == 0 && !service_type->display_name) { ok = _ag_xml_dup_element_data (reader, &service_type->display_name); } else if (strcmp (name, "description") == 0) { ok = _ag_xml_dup_element_data (reader, &service_type->description); } else if (strcmp (name, "icon") == 0) { ok = _ag_xml_dup_element_data (reader, &service_type->icon_name); } else if (strcmp (name, "translations") == 0) { ok = _ag_xml_dup_element_data (reader, &service_type->i18n_domain); } else if (strcmp (name, "tags") == 0) { ok = _ag_xml_parse_element_list (reader, "tag", &service_type->tags); } else ok = TRUE; if (G_UNLIKELY (!ok)) return FALSE; } ret = xmlTextReaderNext (reader); } return TRUE; } static gboolean read_service_type_file (xmlTextReaderPtr reader, AgServiceType *service_type) { const xmlChar *name; int ret; ret = xmlTextReaderRead (reader); while (ret == 1) { name = xmlTextReaderConstName (reader); if (G_LIKELY (name && strcmp ((const gchar *)name, "service-type") == 0)) { return parse_service_type (reader, service_type); } ret = xmlTextReaderNext (reader); } return FALSE; } static AgServiceType * _ag_service_type_new (void) { AgServiceType *service_type; service_type = g_slice_new0 (AgServiceType); service_type->ref_count = 1; return service_type; } static gboolean _ag_service_type_load_from_file (AgServiceType *service_type) { xmlTextReaderPtr reader; gchar *filepath; gboolean ret; GError *error = NULL; g_return_val_if_fail (service_type->name != NULL, FALSE); DEBUG_REFS ("Loading service_type %s", service_type->name); filepath = _ag_find_libaccounts_file (service_type->name, ".service-type", "AG_SERVICE_TYPES", SERVICE_TYPE_FILES_DIR); if (G_UNLIKELY (!filepath)) return FALSE; g_file_get_contents (filepath, &service_type->file_data, &service_type->file_data_len, &error); if (G_UNLIKELY (error)) { g_warning ("Error reading %s: %s", filepath, error->message); g_error_free (error); g_free (filepath); return FALSE; } /* TODO: cache the xmlReader */ reader = xmlReaderForMemory (service_type->file_data, service_type->file_data_len, filepath, NULL, 0); g_free (filepath); if (G_UNLIKELY (reader == NULL)) return FALSE; ret = read_service_type_file (reader, service_type); xmlFreeTextReader (reader); return ret; } AgServiceType * _ag_service_type_new_from_file (const gchar *service_type_name) { AgServiceType *service_type; service_type = _ag_service_type_new (); service_type->name = g_strdup (service_type_name); if (!_ag_service_type_load_from_file (service_type)) { ag_service_type_unref (service_type); service_type = NULL; } return service_type; } /** * ag_service_type_get_name: * @service_type: the #AgServiceType. * * Get the name of the #AgServiceType. * * Returns: the name of @service_type. */ const gchar * ag_service_type_get_name (AgServiceType *service_type) { g_return_val_if_fail (service_type != NULL, NULL); return service_type->name; } /** * ag_service_type_get_i18n_domain: * @service_type: the #AgServiceType. * * Get the translation domain of the #AgServiceType. * * Returns: the translation domain. */ const gchar * ag_service_type_get_i18n_domain (AgServiceType *service_type) { g_return_val_if_fail (service_type != NULL, NULL); return service_type->i18n_domain; } /** * ag_service_type_get_display_name: * @service_type: the #AgServiceType. * * Get the display name of the #AgServiceType. * * Returns: the display name of @service_type. */ const gchar * ag_service_type_get_display_name (AgServiceType *service_type) { g_return_val_if_fail (service_type != NULL, NULL); return service_type->display_name; } /** * ag_service_type_get_description: * @service_type: the #AgServiceType. * * Get the description of the #AgServiceType. * * Returns: the description of @service_type, or %NULL upon failure. * * Since: 1.2 */ const gchar * ag_service_type_get_description (AgServiceType *service_type) { g_return_val_if_fail (service_type != NULL, NULL); return service_type->description; } /** * ag_service_type_get_icon_name: * @service_type: the #AgServiceType. * * Get the icon name of the #AgServiceType. * * Returns: the name of the icon of @service_type. */ const gchar * ag_service_type_get_icon_name (AgServiceType *service_type) { g_return_val_if_fail (service_type != NULL, NULL); return service_type->icon_name; } /** * ag_service_type_has_tag: * @service_type: the #AgServiceType. * @tag: the tag to check for. * * Check if the #AgServiceType has the requested tag. * * Returns: TRUE if the #AgServiceType has the tag, FALSE otherwise */ gboolean ag_service_type_has_tag (AgServiceType *service_type, const gchar *tag) { g_return_val_if_fail (service_type != NULL, FALSE); if (service_type->tags == NULL) return FALSE; return g_hash_table_lookup_extended (service_type->tags, tag, NULL, NULL); } /** * ag_service_type_get_tags: * @service_type: the #AgServiceType. * * Get list of tags specified for the #AgServiceType. * * Returns: (transfer container) (element-type utf8): #GList of tags for * @service_type. * The list must be freed with g_list_free(). Entries are owned by the * #AgServiceType type and must not be free'd. */ GList *ag_service_type_get_tags (AgServiceType *service_type) { g_return_val_if_fail (service_type != NULL, NULL); if (service_type->tags == NULL) return NULL; return g_hash_table_get_keys (service_type->tags); } /** * ag_service_type_get_file_contents: * @service_type: the #AgServiceType. * @contents: location to receive the pointer to the file contents. * @len: location to receive the length of the file, in bytes. * * Gets the contents of the XML service type file. The buffer returned in * @contents should not be modified or freed, and is guaranteed to be valid as * long as @service_type is referenced. * If some error occurs, @contents is set to %NULL. */ void ag_service_type_get_file_contents (AgServiceType *service_type, const gchar **contents, gsize *len) { g_return_if_fail (service_type != NULL); g_return_if_fail (contents != NULL); *contents = service_type->file_data; if (len) *len = service_type->file_data_len; } /** * ag_service_type_ref: * @service_type: the #AgServiceType. * * Adds a reference to @service_type. * * Returns: @service_type. */ AgServiceType * ag_service_type_ref (AgServiceType *service_type) { g_return_val_if_fail (service_type != NULL, NULL); g_return_val_if_fail (service_type->ref_count > 0, NULL); DEBUG_REFS ("Referencing service_type %s (%d)", service_type->name, service_type->ref_count); service_type->ref_count++; return service_type; } /** * ag_service_type_unref: * @service_type: the #AgServiceType. * * Used to unreference the #AgServiceType structure. */ void ag_service_type_unref (AgServiceType *service_type) { g_return_if_fail (service_type != NULL); g_return_if_fail (service_type->ref_count > 0); DEBUG_REFS ("Unreferencing service_type %s (%d)", service_type->name, service_type->ref_count); service_type->ref_count--; if (service_type->ref_count == 0) { g_free (service_type->name); g_free (service_type->i18n_domain); g_free (service_type->display_name); g_free (service_type->description); g_free (service_type->icon_name); g_free (service_type->file_data); if (service_type->tags) g_hash_table_destroy (service_type->tags); g_slice_free (AgServiceType, service_type); } } /** * ag_service_type_list_free: * @list: (element-type AgServiceType): a #GList of service types returned by * some function of this library, such as ag_manager_list_service_types(). * * Frees the list @list. */ void ag_service_type_list_free (GList *list) { g_list_foreach (list, (GFunc)ag_service_type_unref, NULL); g_list_free (list); } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/libaccounts-glib.deps0000644000015000001560000000001512245170671026671 0ustar pbuserpbgroup00000000000000gio-unix-2.0 libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-internals.h0000644000015000001560000001604412245170671025341 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2009-2010 Nokia Corporation. * Copyright (C) 2012-2013 Canonical Ltd. * Copyright (C) 2012 Intel Corporation. * * Contact: Alberto Mardegan * Contact: Jussi Laako * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_INTERNALS_H_ #define _AG_INTERNALS_H_ #include "ag-account.h" #include "ag-auth-data.h" #include "ag-debug.h" #include "ag-manager.h" #include #include G_BEGIN_DECLS #define AG_DBUS_PATH_SERVICE "/ServiceType" #define AG_DBUS_IFACE "com.google.code.AccountsSSO.Accounts" #define AG_DBUS_SIG_CHANGED "AccountChanged" #define SERVICE_GLOBAL_TYPE "global" #define AG_DBUS_PATH_SERVICE_GLOBAL \ AG_DBUS_PATH_SERVICE "/" SERVICE_GLOBAL_TYPE #define MAX_SQLITE_BUSY_LOOP_TIME 5 #define MAX_SQLITE_BUSY_LOOP_TIME_MS (MAX_SQLITE_BUSY_LOOP_TIME * 1000) #if GLIB_CHECK_VERSION (2, 30, 0) #else #define G_VALUE_INIT { 0, { { 0 } } } #endif typedef struct _AgAccountChanges AgAccountChanges; struct _AgAccountChanges { gboolean deleted; gboolean created; /* The keys of the table are service names, and the values are * AgServiceChanges structures */ GHashTable *services; }; G_GNUC_INTERNAL void _ag_account_store_completed (AgAccount *account, AgAccountChanges *changes); G_GNUC_INTERNAL void _ag_account_done_changes (AgAccount *account, AgAccountChanges *changes); G_GNUC_INTERNAL GVariant *_ag_account_build_signal (AgAccount *account, AgAccountChanges *changes, const struct timespec *ts); G_GNUC_INTERNAL AgAccountChanges *_ag_account_changes_from_dbus (AgManager *manager, GVariant *v_services, gboolean created, gboolean deleted); G_GNUC_INTERNAL GHashTable *_ag_account_get_service_changes (AgAccount *account, AgService *service); G_GNUC_INTERNAL void _ag_manager_exec_transaction (AgManager *manager, const gchar *sql, AgAccountChanges *changes, AgAccount *account, GSimpleAsyncResult *async_result, GCancellable *cancellable); typedef gboolean (*AgQueryCallback) (sqlite3_stmt *stmt, gpointer user_data); G_GNUC_INTERNAL void _ag_manager_exec_transaction_blocking (AgManager *manager, const gchar *sql, AgAccountChanges *changes, AgAccount *account, GError **error); G_GNUC_INTERNAL gint _ag_manager_exec_query (AgManager *manager, AgQueryCallback callback, gpointer user_data, const gchar *sql); G_GNUC_INTERNAL void _ag_manager_take_error (AgManager *manager, GError *error); G_GNUC_INTERNAL const GError *_ag_manager_get_last_error (AgManager *manager); G_GNUC_INTERNAL AgService *_ag_manager_get_service_lazy (AgManager *manager, const gchar *service_name, const gchar *service_type, const gint service_id); G_GNUC_INTERNAL guint _ag_manager_get_service_id (AgManager *manager, AgService *service); struct _AgService { /*< private >*/ gint ref_count; gchar *name; gchar *display_name; gchar *description; gchar *type; gchar *provider; gchar *icon_name; gchar *i18n_domain; gchar *file_data; gsize type_data_offset; gint id; GHashTable *default_settings; GHashTable *tags; }; G_GNUC_INTERNAL AgService *_ag_service_new_from_file (const gchar *service_name); G_GNUC_INTERNAL AgService *_ag_service_new_from_memory (const gchar *service_name, const gchar *service_type, const gint service_id); G_GNUC_INTERNAL GHashTable *_ag_service_load_default_settings (AgService *service); G_GNUC_INTERNAL GVariant *_ag_service_get_default_setting (AgService *service, const gchar *key); G_GNUC_INTERNAL AgService *_ag_service_new (void); struct _AgProvider { /*< private >*/ gint ref_count; gchar *i18n_domain; gchar *icon_name; gchar *name; gchar *display_name; gchar *description; gchar *domains; gchar *plugin_name; gchar *file_data; gboolean single_account; GHashTable *default_settings; }; G_GNUC_INTERNAL AgProvider *_ag_provider_new_from_file (const gchar *provider_name); G_GNUC_INTERNAL GHashTable *_ag_provider_load_default_settings (AgProvider *provider); G_GNUC_INTERNAL GVariant *_ag_provider_get_default_setting (AgProvider *provider, const gchar *key); G_GNUC_INTERNAL GPtrArray *_ag_account_changes_get_service_types (AgAccountChanges *changes); G_GNUC_INTERNAL gboolean _ag_account_changes_have_service_type (AgAccountChanges *changes, gchar *service_type); G_GNUC_INTERNAL gboolean _ag_account_changes_have_enabled (AgAccountChanges *changes); G_GNUC_INTERNAL GList *_ag_manager_list_all (AgManager *manager); G_GNUC_INTERNAL void _ag_account_changes_free (AgAccountChanges *change); G_GNUC_INTERNAL void _ag_account_settings_iter_init (AgAccount *account, AgAccountSettingIter *iter, const gchar *key_prefix, gboolean copy_string); /* Service type functions */ G_GNUC_INTERNAL AgServiceType *_ag_service_type_new_from_file (const gchar *service_type_name); /* AgAuthData functions */ G_GNUC_INTERNAL AgAuthData *_ag_auth_data_new (AgAccount *account, AgService *service); /* Application functions */ G_GNUC_INTERNAL AgApplication *_ag_application_new_from_file (const gchar *application_name); /* Application functions */ G_GNUC_INTERNAL gboolean _ag_application_supports_service (AgApplication *self, AgService *service); #endif /* _AG_INTERNALS_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-application.c0000644000015000001560000003444512245170671025645 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2012 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** * SECTION:ag-application * @short_description: information on the client applications of libaccounts. * @include: libaccounts-glib/ag-application.h * * The #AgApplication structure holds information on the client applications * registered with libaccounts. * It is instantiated by #AgManager with ag_manager_get_application() and * ag_manager_list_applications_by_service(), and destroyed with * ag_application_unref(). * * * Querying application names for an * <structname>AgService</structname> * * AgManager *manager; * GList *services, *applications; * AgService *service; * * manager = ag_manager_new (); * services = ag_manager_list_services (manager); * g_assert (services != NULL); * service = (AgService *) services->data; * applications = ag_manager_list_applications_by_service (manager, service); * * g_print ("Service type: %s\n", ag_service_get_name (service)); * for (applications; applications != NULL; applications = applications->next) * { * const gchar *application_name = ag_application_get_name ((AgApplication *) applications->data); * g_print (" Application name: %s\n", application_name); * } * * */ #include "config.h" #include "ag-application.h" #include "ag-internals.h" #include "ag-service.h" #include "ag-util.h" #include #include struct _AgApplication { /*< private >*/ gint ref_count; gchar *name; gchar *desktop_entry; gchar *description; gchar *i18n_domain; GDesktopAppInfo *desktop_app_info; gboolean desktop_app_info_loaded; /* the values of these hash tables are AgApplicationItem elements */ GHashTable *services; GHashTable *service_types; }; typedef struct { gchar *description; /* more fields could be added later on (for instance, supported features) */ } AgApplicationItem; G_DEFINE_BOXED_TYPE (AgApplication, ag_application, (GBoxedCopyFunc)ag_application_ref, (GBoxedFreeFunc)ag_application_unref); static void _ag_application_item_free (AgApplicationItem *item) { g_free (item->description); g_slice_free (AgApplicationItem, item); } static AgApplicationItem * _ag_application_get_service_item (AgApplication *self, AgService *service) { AgApplicationItem *item = NULL; if (self->services != NULL) item = g_hash_table_lookup (self->services, service->name); if (item == NULL && self->service_types != NULL) { item = g_hash_table_lookup (self->service_types, ag_service_get_service_type (service)); } return item; } static inline void _ag_application_ensure_desktop_app_info (AgApplication *self) { if (!self->desktop_app_info_loaded) { const char *filename = self->desktop_entry != NULL ? self->desktop_entry : self->name; gchar *filename_tmp = NULL; if (!g_str_has_suffix (filename, ".desktop")) { filename_tmp = g_strconcat (filename, ".desktop", NULL); filename = filename_tmp; } self->desktop_app_info = g_desktop_app_info_new (filename); self->desktop_app_info_loaded = TRUE; g_free (filename_tmp); } } static gboolean parse_item (xmlTextReaderPtr reader, GHashTable *hash_table, const gchar *item_tag) { AgApplicationItem *item; xmlChar *xml_item_id; gchar *item_id; int ret, type; xml_item_id = xmlTextReaderGetAttribute (reader, (xmlChar *)"id"); if (G_UNLIKELY (xml_item_id == NULL)) { g_warning ("Found element %s with no \"id\" attribute", item_tag); return FALSE; } item_id = g_strdup ((const gchar*)xml_item_id); xmlFree (xml_item_id); item = g_slice_new0 (AgApplicationItem); g_hash_table_insert (hash_table, item_id, item); ret = xmlTextReaderRead (reader); while (ret == 1) { const gchar *name = (const gchar *)xmlTextReaderConstName (reader); if (G_UNLIKELY (!name)) return FALSE; type = xmlTextReaderNodeType (reader); if (type == XML_READER_TYPE_END_ELEMENT && strcmp (name, item_tag) == 0) break; if (type == XML_READER_TYPE_ELEMENT) { gboolean ok; if (strcmp (name, "description") == 0) { ok = _ag_xml_dup_element_data (reader, &item->description); } else ok = TRUE; if (G_UNLIKELY (!ok)) return FALSE; } ret = xmlTextReaderNext (reader); } return TRUE; } static gboolean parse_items (xmlTextReaderPtr reader, GHashTable **hash_table, const gchar *item_tag) { const gchar *name; if (*hash_table == NULL) { *hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)_ag_application_item_free); } int ret, type; ret = xmlTextReaderRead (reader); while (ret == 1) { name = (const gchar *)xmlTextReaderConstName (reader); if (G_UNLIKELY (!name)) return FALSE; type = xmlTextReaderNodeType (reader); if (type == XML_READER_TYPE_END_ELEMENT) break; if (type == XML_READER_TYPE_ELEMENT) { gboolean ok; if (strcmp (name, item_tag) == 0) { ok = parse_item (reader, *hash_table, item_tag); } else { /* ignore unrecognized elements */ ok = TRUE; } if (G_UNLIKELY (!ok)) return FALSE; } ret = xmlTextReaderNext (reader); } return TRUE; } static gboolean parse_application (xmlTextReaderPtr reader, AgApplication *application) { const gchar *name; int ret, type; if (!application->name) { xmlChar *_name = xmlTextReaderGetAttribute (reader, (xmlChar *) "id"); application->name = g_strdup ((const gchar *)_name); if (_name) xmlFree(_name); } ret = xmlTextReaderRead (reader); while (ret == 1) { name = (const gchar *)xmlTextReaderConstName (reader); if (G_UNLIKELY (!name)) return FALSE; type = xmlTextReaderNodeType (reader); if (type == XML_READER_TYPE_END_ELEMENT && strcmp (name, "application") == 0) break; if (type == XML_READER_TYPE_ELEMENT) { gboolean ok; if (strcmp (name, "desktop-entry") == 0) { ok = _ag_xml_dup_element_data (reader, &application->desktop_entry); } else if (strcmp (name, "description") == 0) { ok = _ag_xml_dup_element_data (reader, &application->description); } else if (strcmp (name, "translations") == 0) { ok = _ag_xml_dup_element_data (reader, &application->i18n_domain); } else if (strcmp (name, "services") == 0) { ok = parse_items (reader, &application->services, "service"); } else if (strcmp (name, "service-types") == 0) { ok = parse_items (reader, &application->service_types, "service-type"); } else ok = TRUE; if (G_UNLIKELY (!ok)) return FALSE; } ret = xmlTextReaderNext (reader); } return TRUE; } static gboolean read_application_file (xmlTextReaderPtr reader, AgApplication *application) { const xmlChar *name; int ret; ret = xmlTextReaderRead (reader); while (ret == 1) { name = xmlTextReaderConstName (reader); if (G_LIKELY (name && strcmp ((const gchar *)name, "application") == 0)) { return parse_application (reader, application); } ret = xmlTextReaderNext (reader); } return FALSE; } static gboolean _ag_application_load_from_file (AgApplication *application) { xmlTextReaderPtr reader; gchar *filepath; gboolean ret = FALSE; GError *error = NULL; gchar *file_data; gsize file_data_len; g_return_val_if_fail (application->name != NULL, FALSE); DEBUG_REFS ("Loading application %s", application->name); filepath = _ag_find_libaccounts_file (application->name, ".application", "AG_APPLICATIONS", APPLICATION_FILES_DIR); if (G_UNLIKELY (!filepath)) return FALSE; g_file_get_contents (filepath, &file_data, &file_data_len, &error); if (G_UNLIKELY (error)) { g_warning ("Error reading %s: %s", filepath, error->message); g_error_free (error); g_free (filepath); return FALSE; } reader = xmlReaderForMemory (file_data, file_data_len, filepath, NULL, 0); g_free (filepath); if (G_UNLIKELY (reader == NULL)) goto err_reader; ret = read_application_file (reader, application); xmlFreeTextReader (reader); err_reader: g_free (file_data); return ret; } AgApplication * _ag_application_new_from_file (const gchar *application_name) { AgApplication *application; application = g_slice_new0 (AgApplication); application->ref_count = 1; application->name = g_strdup (application_name); if (!_ag_application_load_from_file (application)) { ag_application_unref (application); application = NULL; } return application; } gboolean _ag_application_supports_service (AgApplication *self, AgService *service) { return _ag_application_get_service_item (self, service) != NULL; } /** * ag_application_get_name: * @self: the #AgApplication. * * Get the name of the #AgApplication. * * Returns: the name of @self. */ const gchar * ag_application_get_name (AgApplication *self) { g_return_val_if_fail (self != NULL, NULL); return self->name; } /** * ag_application_get_description: * @self: the #AgApplication. * * Get the description of the #AgApplication. * * Returns: the description of @self. */ const gchar * ag_application_get_description (AgApplication *self) { g_return_val_if_fail (self != NULL, NULL); if (self->description == NULL) { _ag_application_ensure_desktop_app_info (self); if (self->desktop_app_info != NULL) { return g_app_info_get_description (G_APP_INFO (self->desktop_app_info)); } } return self->description; } /** * ag_application_get_i18n_domain: * @self: the #AgApplication. * * Get the translation domain of the #AgApplication. * * Returns: the translation domain. */ const gchar * ag_application_get_i18n_domain (AgApplication *self) { g_return_val_if_fail (self != NULL, NULL); return self->i18n_domain; } /** * ag_application_get_desktop_app_info: * @self: the #AgApplication. * * Get the #GDesktopAppInfo of the application. * * Returns: (transfer full): the #GDesktopAppInfo for @self, or %NULL if * failed. */ GDesktopAppInfo * ag_application_get_desktop_app_info (AgApplication *self) { g_return_val_if_fail (self != NULL, NULL); _ag_application_ensure_desktop_app_info (self); return self->desktop_app_info != NULL ? g_object_ref (self->desktop_app_info) : NULL; } /** * ag_application_get_service_usage: * @self: the #AgApplication. * @service: an #AgService. * * Get the description from the application XML file, for the specified * service; if not found, get the service-type description instead. * * Returns: usage description of the service. */ const gchar * ag_application_get_service_usage(AgApplication *self, AgService *service) { AgApplicationItem *item; g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (service != NULL, NULL); item = _ag_application_get_service_item (self, service); return (item != NULL) ? item->description : NULL; } /** * ag_application_ref: * @self: the #AgApplication. * * Increment the reference count of @self. * * Returns: @self. */ AgApplication * ag_application_ref (AgApplication *self) { g_return_val_if_fail (self != NULL, NULL); g_atomic_int_inc (&self->ref_count); return self; } /** * ag_application_unref: * @self: the #AgApplication. * * Decrements the reference count of @self. The item is destroyed when the * count gets to 0. */ void ag_application_unref (AgApplication *self) { g_return_if_fail (self != NULL); if (g_atomic_int_dec_and_test (&self->ref_count)) { g_free (self->name); g_free (self->desktop_entry); g_free (self->description); g_free (self->i18n_domain); if (self->desktop_app_info != NULL) g_object_unref (self->desktop_app_info); if (self->services != NULL) g_hash_table_unref (self->services); if (self->service_types != NULL) g_hash_table_unref (self->service_types); g_slice_free (AgApplication, self); } } libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/ag-application.h0000644000015000001560000000325712245170671025647 0ustar pbuserpbgroup00000000000000/* vi: set et sw=4 ts=4 cino=t0,(0: */ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of libaccounts-glib * * Copyright (C) 2012 Canonical Ltd. * * Contact: Alberto Mardegan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * 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 _AG_APPLICATION_H_ #define _AG_APPLICATION_H_ #include #include #include G_BEGIN_DECLS GType ag_application_get_type (void) G_GNUC_CONST; const gchar *ag_application_get_name (AgApplication *self); const gchar *ag_application_get_description (AgApplication *self); const gchar *ag_application_get_i18n_domain (AgApplication *self); GDesktopAppInfo *ag_application_get_desktop_app_info (AgApplication *self); const gchar *ag_application_get_service_usage(AgApplication *self, AgService *service); AgApplication *ag_application_ref (AgApplication *self); void ag_application_unref (AgApplication *self); G_END_DECLS #endif /* _AG_APPLICATION_H_ */ libaccounts-glib-1.15+14.04.20131126.2/libaccounts-glib/Makefile.am0000644000015000001560000000564412245170671024644 0ustar pbuserpbgroup00000000000000lib_LTLIBRARIES = \ libaccounts-glib.la libaccounts_glib_la_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_builddir) \ -I$(builddir) \ -DG_LOG_DOMAIN=\"accounts-glib\" libaccounts_glib_la_CFLAGS = \ $(LIBACCOUNTS_CFLAGS) \ $(COVERAGE_CFLAGS) \ -Wall -Werror libaccounts_glib_la_LIBADD = \ $(LIBACCOUNTS_LIBS) libaccounts_glib_la_LDFLAGS = \ $(COVERAGE_LDFLAGS) \ -version-info 1:3:1 \ --no-allow-shlib-undefined \ -export-symbols-regex '^ag_' BUILT_SOURCES = \ ag-marshal.c \ ag-marshal.h CLEANFILES = $(BUILT_SOURCES) libaccounts_glib_la_SOURCES = \ ag-account.h \ ag-account.c \ ag-account-service.c \ ag-application.h \ ag-application.c \ ag-auth-data.c \ ag-debug.h \ ag-debug.c \ ag-errors.h \ ag-internals.h \ ag-manager.h \ ag-manager.c \ ag-provider.h \ ag-provider.c \ ag-service.h \ ag-service.c \ ag-service-type.h \ ag-service-type.c \ ag-types.h \ ag-util.h \ ag-util.c nodist_libaccounts_glib_la_SOURCES = \ $(BUILT_SOURCES) libaccounts_glib_includedir = $(includedir)/libaccounts-glib libaccounts_glib_include_HEADERS = \ accounts-glib.h \ ag-account.h \ ag-account-service.h \ ag-application.h \ ag-auth-data.h \ ag-errors.h \ ag-manager.h \ ag-provider.h \ ag-service.h \ ag-service-type.h \ ag-types.h ag-marshal.h: ag-marshal.list Makefile $(AM_V_GEN)glib-genmarshal --header --prefix=ag_marshal $< > $@ ag-marshal.c: ag-marshal.list Makefile $(AM_V_GEN)glib-genmarshal --body --prefix=ag_marshal $< > $@ dist_noinst_DATA = ag-marshal.list -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_GIRS = INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) if HAVE_INTROSPECTION introspection_sources = \ ag-account.c \ ag-account.h \ ag-account-service.c \ ag-account-service.h \ ag-application.c \ ag-application.h \ ag-auth-data.c \ ag-auth-data.h \ ag-errors.h \ ag-manager.c \ ag-manager.h \ ag-provider.c \ ag-provider.h \ ag-service.c \ ag-service.h \ ag-service-type.c \ ag-service-type.h \ ag-types.h Accounts-1.0.gir: libaccounts-glib.la Accounts_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 Accounts_1_0_gir_SCANNERFLAGS = \ --identifier-prefix=Ag \ --symbol-prefix=ag \ --c-include="libaccounts-glib/accounts-glib.h" \ --warn-all Accounts_1_0_gir_CFLAGS = \ $(LIBACCOUNTS_CFLAGS) \ -I$(top_srcdir) Accounts_1_0_gir_LIBS = libaccounts-glib.la Accounts_1_0_gir_FILES = $(introspection_sources) INTROSPECTION_GIRS += Accounts-1.0.gir girdir = $(datadir)/gir-1.0 gir_DATA = $(INTROSPECTION_GIRS) typelibdir = $(libdir)/girepository-1.0 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES += $(gir_DATA) $(typelib_DATA) endif # XML DTDs dtddir = $(datadir)/xml/accounts/schema/dtd dist_dtd_DATA = \ accounts-application.dtd \ accounts-provider.dtd \ accounts-service.dtd \ accounts-service-type.dtd # Vala bindings vapidir = $(datadir)/vala/vapi dist_vapi_DATA = \ libaccounts-glib.deps \ libaccounts-glib.vapi libaccounts-glib-1.15+14.04.20131126.2/NEWS0000644000015000001560000001177712245170671020072 0ustar pbuserpbgroup00000000000000libaccounts-glib NEWS Version 1.15 ------------ * Fix SQL query for ag_manager_list_by_service_type() Fixes: http://code.google.com/p/accounts-sso/issues/detail?id=208 Version 1.14 ------------ * Add ag_provider_get_single_account Fixes: http://code.google.com/p/accounts-sso/issues/detail?id=202 * Add coverage reporting using lcov * Tests: increase test coverage * Tests: increase tolerance on blocking time Version 1.13 ------------ * Allow disabling WAL journaling mode at configuration time; this is needed in order to support accessing the DB in read-only mode * Tests: make test_signals_other_manager() more stable Fixes: http://code.google.com/p/accounts-sso/issues/detail?id=200 Version 1.12 ------------ * Allow opening the DB in read-only mode Fixes: http://code.google.com/p/accounts-sso/issues/detail?id=199 * Application: do not require ".desktop" suffix Fixes: http://code.google.com/p/accounts-sso/issues/detail?id=193 * Account: emit "enabled" signal also on non-selected services * AgAccount: implement the GInitable interface * Tests: revert "don't run tests in parallel", disable gtkdoc tests Version 1.11 ------------ * Tests: don't run tests in parallel Version 1.10 ------------ * Vala: rename .vapi and .deps files Fixes: http://code.google.com/p/accounts-sso/issues/detail?id=176 * Tests: don't fail on critical warnings * AgService: load the XML file before returning tags * Removed deprecated g_type_init and bumped GObject dependency Version 1.9 ----------- * Fix compilation with GCC 4.8 * Install tests * Add installcheck target for installed tests Version 1.8 ----------- * Account::enabled(): use NULL for global account Fixes: http://code.google.com/p/accounts-sso/issues/detail?id=157 * Do never return a NULL AgAuthData pointer Version 1.7 ----------- * Link with rt only when necessary. * Remove AEGIS dead code. * Update VAPI file. * Allow creating AuthData for a global account. Version 1.6 ----------- * Fix the check for pyoverridesdir for python3 * Also support Python 2.7 Version 1.5 ----------- * Allow provider XML files to specify which plugin manages the accounts of the provider * Include ag-auth-data.h in accounts-glib.h Fixes: http://code.google.com/p/accounts-sso/issues/detail?id=136 Version 1.4 ----------- * Port to GDBus; drop the dependencies on libdbus and libdbus-glib. * Added support for the