[PATCH 0/3] Config save/load support (revised)

1 view
Skip to first unread message

Adrian Perez

unread,
Jun 15, 2009, 12:56:26 PM6/15/09
to frogr...@googlegroups.com
Hello!

I have revised my previous patch with the given suggestions, and I am
re-sending it for review. Changes over the previous version of the patch:

* Coding style is more Gtk-ish and follows conventions outlined by Mario.

* FrogrConfig singleton is now created using the standard GObject idiom
(http://library.gnome.org/devel/gobject/unstable/gobject-The-Base-Object-Type.html)

* FrogrConfigAccount was renamed to FrogrAccount (which is a shorter, nicer
name IMHO) and splitted into new frogr-account.{h,c} files.

* Added setter and getter methods for the properties in FrogrAccount.

* Touched frogr-controller.c and main.c to use setter/getter methods and the
changed API, which now needs passing the FrogrConfig instance around.

* Revised type checking to use FROGR_IS_ACCOUNT and FROGR_IS_CONFIG.

* Added underscore in front of private method names and private utility
functions (mostly in frogr-config.c).

I hope that the code is now more suitable for inclusion in Frogr. As always,
comments are welcome.

Best regards,


P.S. And this time I did not forgot adding "--cover-letter" when creating
the patch set with Git ;-)

Adrian Perez (3):
FrogrAccount to save Flickr account information
FrogrConfig class, XML save/load of configuration
Save/load frob and auth token in account config

src/Makefile.am | 4 +
src/frogr-account.c | 371 ++++++++++++++++++++++++++++++++++++++++
src/frogr-account.h | 88 ++++++++++
src/frogr-config.c | 469 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/frogr-config.h | 72 ++++++++
src/frogr-facade.c | 32 +++--
src/main.c | 2 +
7 files changed, 1026 insertions(+), 12 deletions(-)
create mode 100644 src/frogr-account.c
create mode 100644 src/frogr-account.h
create mode 100644 src/frogr-config.c
create mode 100644 src/frogr-config.h

Adrian Perez

unread,
Jun 15, 2009, 12:56:27 PM6/15/09
to frogr...@googlegroups.com
---
src/Makefile.am | 2 +
src/frogr-account.c | 371 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/frogr-account.h | 88 ++++++++++++
3 files changed, 461 insertions(+), 0 deletions(-)

create mode 100644 src/frogr-account.c
create mode 100644 src/frogr-account.h

diff --git a/src/Makefile.am b/src/Makefile.am
index a010107..d09c791 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,4 +42,6 @@ frogr_SOURCES = \
frogr-main-window.h \
frogr-picture.c \
frogr-picture.h \
+ frogr-account.c \
+ frogr-account.h \
main.c
diff --git a/src/frogr-account.c b/src/frogr-account.c
new file mode 100644
index 0000000..a113656
--- /dev/null
+++ b/src/frogr-account.c
@@ -0,0 +1,371 @@
+/*
+ * frogr-config.c -- Configuration system for Frogr.
+ *
+ * Copyright (C) 2009 Adrian Perez
+ * Authors: Adrian Perez <ape...@igalia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 3 of the GNU General Public
+ * License 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 warranty of
+ * MERCHANTABILITY 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "frogr-account.h"
+#include <libxml/parser.h>
+#include <errno.h>
+
+
+#define FROGR_ACCOUNT_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), FROGR_ACCOUNT_TYPE, FrogrAccountPrivate))
+
+G_DEFINE_TYPE (FrogrAccount, frogr_account, G_TYPE_OBJECT);
+
+
+/* Private structure */
+typedef struct _FrogrAccountPrivate FrogrAccountPrivate;
+struct _FrogrAccountPrivate
+{
+ gchar *frob;
+ gchar *token;
+ gchar *username;
+
+ gboolean enabled;
+ gboolean public;
+ gboolean family;
+ gboolean friends;
+};
+
+
+/* Properties */
+enum
+{
+ PROP_0,
+ PROP_FROB,
+ PROP_TOKEN,
+ PROP_USERNAME,
+ PROP_ENABLED,
+ PROP_PUBLIC,
+ PROP_FAMILY,
+ PROP_FRIENDS,
+};
+
+
+
+/* Private API bits */
+
+static void
+_frogr_account_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ FrogrAccountPrivate *priv = FROGR_ACCOUNT_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_FROB:
+ g_free (priv -> frob);
+ priv -> frob = g_value_dup_string (value);
+ break;
+ case PROP_TOKEN:
+ g_free (priv -> token);
+ priv -> token = g_value_dup_string (value);
+ break;
+ case PROP_USERNAME:
+ g_free (priv -> username);
+ priv -> username = g_value_dup_string (value);
+ break;
+ case PROP_ENABLED:
+ priv -> enabled = g_value_get_boolean (value);
+ break;
+ case PROP_PUBLIC:
+ priv -> public = g_value_get_boolean (value);
+ break;
+ case PROP_FAMILY:
+ priv -> family = g_value_get_boolean (value);
+ break;
+ case PROP_FRIENDS:
+ priv -> friends = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+
+static void
+_frogr_account_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ FrogrAccountPrivate *priv = FROGR_ACCOUNT_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_FROB:
+ g_value_set_string (value, priv -> frob);
+ break;
+ case PROP_TOKEN:
+ g_value_set_string (value, priv -> token);
+ break;
+ case PROP_USERNAME:
+ g_value_set_string (value, priv -> username);
+ break;
+ case PROP_ENABLED:
+ g_value_set_boolean (value, priv -> enabled);
+ break;
+ case PROP_PUBLIC:
+ g_value_set_boolean (value, priv -> public);
+ break;
+ case PROP_FAMILY:
+ g_value_set_boolean (value, priv -> family);
+ break;
+ case PROP_FRIENDS:
+ g_value_set_boolean (value, priv -> friends);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+static void
+_frogr_account_finalize (GObject *object)
+{
+ FrogrAccountPrivate *priv = FROGR_ACCOUNT_GET_PRIVATE (object);
+
+ g_free (priv -> frob);
+ g_free (priv -> token);
+ g_free (priv -> username);
+
+ /* Call superclass */
+ G_OBJECT_CLASS (frogr_account_parent_class) -> finalize (object);
+}
+
+
+
+
+static void
+frogr_account_class_init (FrogrAccountClass *klass)
+{
+ GObjectClass *obj_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (FrogrAccountPrivate));
+
+ obj_class -> get_property = _frogr_account_get_property;
+ obj_class -> set_property = _frogr_account_set_property;
+ obj_class -> finalize = _frogr_account_finalize;
+
+ pspec = g_param_spec_string ("frob",
+ "Flickr API authentication frob",
+ "Get/set Flickr frob",
+ "",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (obj_class, PROP_FROB, pspec);
+
+ pspec = g_param_spec_string ("token",
+ "Flickr API authentication token",
+ "Get/set Flickr token",
+ "",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (obj_class, PROP_TOKEN, pspec);
+
+ pspec = g_param_spec_string ("username",
+ "Flickr account user name",
+ "Get/set Flickr user name",
+ "",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (obj_class, PROP_USERNAME, pspec);
+
+ pspec = g_param_spec_boolean ("enabled",
+ "Whether the account is enabled",
+ "Get/set enabled status",
+ TRUE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (obj_class, PROP_ENABLED, pspec);
+
+ pspec = g_param_spec_boolean ("public",
+ "Whether photos are public by default",
+ "Get/set private by default",
+ FALSE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (obj_class, PROP_PUBLIC, pspec);
+
+ pspec = g_param_spec_boolean ("family",
+ "If sharing is private, whether to share with family",
+ "Get/set family sharing",
+ FALSE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (obj_class, PROP_FAMILY, pspec);
+
+ pspec = g_param_spec_boolean ("friends",
+ "If sharing is private, whether to share with friends",
+ "Get/set family sharing",
+ FALSE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (obj_class, PROP_FRIENDS, pspec);
+}
+
+
+static void
+frogr_account_init (FrogrAccount *faccount)
+{
+ FrogrAccountPrivate *priv = FROGR_ACCOUNT_GET_PRIVATE (faccount);
+
+ priv -> frob = NULL;
+ priv -> token = NULL;
+ priv -> username = NULL;
+ priv -> enabled = TRUE;
+ priv -> public = FALSE;
+ priv -> family = FALSE;
+ priv -> friends = FALSE;
+}
+
+
+gchar*
+frogr_account_get_frob (FrogrAccount *faccount)
+{
+ gchar *value;
+ g_return_val_if_fail (FROGR_IS_ACCOUNT (faccount), NULL);
+ g_object_get (faccount, "frob", &value, NULL);
+ return value;
+}
+
+
+void
+frogr_account_set_frob (FrogrAccount *faccount,
+ const gchar *value)
+{
+ g_return_if_fail (FROGR_IS_ACCOUNT (faccount));
+ g_return_if_fail (value != NULL);
+ g_object_set (faccount, "frob", value, NULL);
+}
+
+
+gchar*
+frogr_account_get_token (FrogrAccount *faccount)
+{
+ gchar *value;
+ g_return_val_if_fail (FROGR_IS_ACCOUNT (faccount), NULL);
+ g_object_get (faccount, "token", &value, NULL);
+ return value;
+}
+
+
+void
+frogr_account_set_token (FrogrAccount *faccount,
+ const gchar *value)
+{
+ g_return_if_fail (FROGR_IS_ACCOUNT (faccount));
+ g_return_if_fail (value != NULL);
+ g_object_set (faccount, "token", value, NULL);
+}
+
+
+gchar*
+frogr_account_get_username (FrogrAccount *faccount)
+{
+ gchar *value;
+ g_return_val_if_fail (FROGR_IS_ACCOUNT (faccount), NULL);
+ g_object_get (faccount, "username", &value, NULL);
+ return value;
+}
+
+
+void
+frogr_account_set_username (FrogrAccount *faccount,
+ const gchar *value)
+{
+ g_return_if_fail (FROGR_IS_ACCOUNT (faccount));
+ g_return_if_fail (value != NULL);
+ g_object_set (faccount, "username", value, NULL);
+}
+
+
+gboolean
+frogr_account_get_enabled (FrogrAccount *faccount)
+{
+ gboolean value;
+ g_return_val_if_fail (FROGR_IS_ACCOUNT (faccount), FALSE);
+ g_object_get (faccount, "enabled", &value, NULL);
+ return value;
+}
+
+
+void
+frogr_account_set_enabled (FrogrAccount *faccount,
+ gboolean value)
+{
+ g_return_if_fail (FROGR_IS_ACCOUNT (faccount));
+ g_object_set (faccount, "enabled", value, NULL);
+}
+
+
+gboolean
+frogr_account_get_public (FrogrAccount *faccount)
+{
+ gboolean value;
+ g_return_val_if_fail (FROGR_IS_ACCOUNT (faccount), FALSE);
+ g_object_get (faccount, "public", &value, NULL);
+ return value;
+}
+
+
+void
+frogr_account_set_public (FrogrAccount *faccount,
+ gboolean value)
+{
+ g_return_if_fail (FROGR_IS_ACCOUNT (faccount));
+ g_object_set (faccount, "public", value, NULL);
+}
+
+
+gboolean
+frogr_account_get_family (FrogrAccount *faccount)
+{
+ gboolean value;
+ g_return_val_if_fail (FROGR_IS_ACCOUNT (faccount), FALSE);
+ g_object_get (faccount, "family", &value, NULL);
+ return value;
+}
+
+
+void
+frogr_account_set_family (FrogrAccount *faccount,
+ gboolean value)
+{
+ g_return_if_fail (FROGR_IS_ACCOUNT (faccount));
+ g_object_set (faccount, "family", value, NULL);
+}
+
+
+gboolean
+frogr_account_get_friends (FrogrAccount *faccount)
+{
+ gboolean value;
+ g_return_val_if_fail (FROGR_IS_ACCOUNT (faccount), FALSE);
+ g_object_get (faccount, "friends", &value, NULL);
+ return value;
+}
+
+
+void
+frogr_account_set_friends (FrogrAccount *faccount,
+ gboolean value)
+{
+ g_return_if_fail (FROGR_IS_ACCOUNT (faccount));
+ g_object_set (faccount, "friends", value, NULL);
+}
+
diff --git a/src/frogr-account.h b/src/frogr-account.h
new file mode 100644
index 0000000..d7323a5
--- /dev/null
+++ b/src/frogr-account.h
@@ -0,0 +1,88 @@
+/*
+ * frogr-config.h -- Account class for Frogr.
+ *
+ * Copyright (C) 2009 Adrian Perez
+ * Authors: Adrian Perez <ape...@igalia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 3 of the GNU General Public
+ * License 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 warranty of
+ * MERCHANTABILITY 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _FROGR_ACCOUNT_H
+#define _FROGR_ACCOUNT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define FROGR_ACCOUNT_TYPE (frogr_account_get_type())
+#define FROGR_IS_ACCOUNT(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, FROGR_ACCOUNT_TYPE))
+#define FROGR_IS_ACCOUNT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, FROGR_ACCOUNT_TYPE))
+#define FROGR_ACCOUNT(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, FROGR_ACCOUNT_TYPE, FrogrAccount))
+#define FROGR_ACCOUNT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, FROGR_ACCOUNT_TYPE, FrogrAccountClass))
+#define FROGR_ACCOUNT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, FROGR_ACCOUNT_TYPE, FrogrAccountClass))
+
+typedef struct _FrogrAccount FrogrAccount;
+typedef struct _FrogrAccountClass FrogrAccountClass;
+
+
+struct _FrogrAccount
+{
+ GObject parent_instance;
+};
+
+
+struct _FrogrAccountClass
+{
+ GObjectClass parent_class;
+};
+
+
+GType frogr_account_get_type(void) G_GNUC_CONST;
+
+FrogrAccount* frogr_account_new (const gchar *first_property, ...);
+
+gchar* frogr_account_get_frob (FrogrAccount *faccount);
+void frogr_account_set_frob (FrogrAccount *faccount,
+ const gchar *frob);
+
+gchar* frogr_account_get_token (FrogrAccount *faccount);
+void frogr_account_set_token (FrogrAccount *faccount,
+ const gchar *token);
+
+gchar* frogr_account_get_username (FrogrAccount *faccount);
+void frogr_account_set_username (FrogrAccount *faccount,
+ const gchar *username);
+
+gboolean frogr_account_get_enabled (FrogrAccount *faccount);
+void frogr_account_set_enabled (FrogrAccount *faccount,
+ gboolean value);
+
+gboolean frogr_account_get_public (FrogrAccount *faccount);
+void frogr_account_set_public (FrogrAccount *faccount,
+ gboolean value);
+
+gboolean frogr_account_get_private_family (FrogrAccount *faccount);
+void frogr_account_set_private_family (FrogrAccount *faccount,
+ gboolean value);
+
+gboolean frogr_account_get_private_friends (FrogrAccount *faccount);
+void frogr_account_set_private_friends (FrogrAccount *faccount,
+ gboolean value);
+
+G_END_DECLS
+
+#endif /* !_FROGR_ACCOUNT_H */
+
--
1.6.3.2

Adrian Perez

unread,
Jun 15, 2009, 12:56:28 PM6/15/09
to frogr...@googlegroups.com
* FrogrConfig and FrogrConfigAccount classes.

* Interface based on GObject properties: all configuration can be accessed
as properties of objects. This makes them easy to bind to Gtk UI elements.

* Support for loading/saving ~.config/frogr/accounts.xml

* There is support for handling multiple accounts.
---
src/Makefile.am | 2 +
src/frogr-config.c | 469 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/frogr-config.h | 72 ++++++++
3 files changed, 543 insertions(+), 0 deletions(-)


create mode 100644 src/frogr-config.c
create mode 100644 src/frogr-config.h

diff --git a/src/Makefile.am b/src/Makefile.am
index d09c791..ad3d595 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -44,4 +44,6 @@ frogr_SOURCES = \
frogr-picture.h \
frogr-account.c \
frogr-account.h \
+ frogr-config.c \
+ frogr-config.h \
main.c
diff --git a/src/frogr-config.c b/src/frogr-config.c
new file mode 100644
index 0000000..7aba2f0
--- /dev/null
+++ b/src/frogr-config.c
@@ -0,0 +1,469 @@


+/*
+ * frogr-config.c -- Configuration system for Frogr.
+ *
+ * Copyright (C) 2009 Adrian Perez
+ * Authors: Adrian Perez <ape...@igalia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 3 of the GNU General Public
+ * License 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 warranty of
+ * MERCHANTABILITY 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+

+#include "frogr-config.h"
+#include "frogr-account.h"
+#include <libxml/parser.h>
+#include <string.h>
+#include <errno.h>
+
+
+#define FROGR_CONFIG_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), FROGR_CONFIG_TYPE, FrogrConfigPrivate))
+
+
+G_DEFINE_TYPE (FrogrConfig, frogr_config, G_TYPE_OBJECT);
+
+
+typedef struct _FrogrConfigPrivate FrogrConfigPrivate;
+struct _FrogrConfigPrivate
+{
+ /* List of accounts. */
+ GList *accounts;
+};
+
+
+static gboolean
+_xml_node_to_boolean (const xmlNodePtr node)
+{
+ xmlChar *xstr;
+ gchar *str;
+ gboolean result;
+
+ g_return_val_if_fail (node != NULL, FALSE);
+
+ xstr = xmlNodeGetContent (node);
+ str = (gchar*) xstr;
+
+ while (g_ascii_isspace (*str++)); /* Skip blanks */
+
+ if (g_ascii_isdigit (*str))
+ {
+ long value = strtol (str, NULL, 0);
+ result = (value != 0);
+ }
+ else
+ {
+ result = (g_ascii_strncasecmp ("false", str, 5) != 0);
+ }
+ xmlFree (xstr);
+ return result;
+}
+
+
+static FrogrAccount*
+_frogr_config_account_from_xml (xmlDocPtr xml, xmlNodePtr rootnode)
+{
+ xmlNodePtr node;
+ GObject *faccount = NULL;
+
+ xmlChar *frob = NULL;
+ xmlChar *token = NULL;
+ xmlChar *username = NULL;
+ gboolean enabled = TRUE;
+ gboolean public = FALSE;
+ gboolean family = FALSE;
+ gboolean friends = FALSE;
+
+ g_return_val_if_fail (xml != NULL, NULL);
+ g_return_val_if_fail (rootnode != NULL, NULL);
+
+ /* Traverse child nodes and extract relevant information. */
+ for (node = rootnode->children; node != NULL; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrcmp (node->name, (const xmlChar*) "frob") == 0)
+ frob = xmlNodeGetContent (node);
+ else if (xmlStrcmp (node->name, (const xmlChar*) "token") == 0)
+ token = xmlNodeGetContent (node);
+ else if (xmlStrcmp (node->name, (const xmlChar*) "username") == 0)
+ username = xmlNodeGetContent (node);
+ else if (xmlStrcmp (node->name, (const xmlChar*) "enabled") == 0)
+ enabled = _xml_node_to_boolean (node);
+ else if (xmlStrcmp (node->name, (const xmlChar*) "public") == 0)
+ public = _xml_node_to_boolean (node);
+ else if (xmlStrcmp (node->name, (const xmlChar*) "family") == 0)
+ family = _xml_node_to_boolean (node);
+ else if (xmlStrcmp (node->name, (const xmlChar*) "friends") == 0)
+ friends = _xml_node_to_boolean (node);
+ }
+
+ /*
+ * The account object is created only of some minimum requirements are
+ * met: user name, token and frob.
+ */
+ if (frob != NULL && token != NULL && username != NULL)
+ {
+ faccount = g_object_new (FROGR_ACCOUNT_TYPE,
+ "frob", (const gchar*) frob,
+ "token", (const gchar*) token,
+ "username", (const gchar*) username,
+ "enabled", enabled,
+ "public", public,
+ "family", family,
+ "friends", friends,
+ NULL);
+ }
+
+ if (frob != NULL) xmlFree (frob);
+ if (token != NULL) xmlFree (token);
+ if (username != NULL) xmlFree (username);
+
+ return FROGR_ACCOUNT (faccount);


+}
+
+
+static void

+_frogr_config_load_accounts (FrogrConfig *fconfig, const gchar *config_dir)
+{
+ FrogrConfigPrivate *priv;
+ gchar *xml_path;
+ xmlNodePtr node;
+ xmlDocPtr xml;
+
+ g_return_if_fail (FROGR_IS_CONFIG (fconfig));
+ g_return_if_fail (config_dir != NULL);
+
+ priv = FROGR_CONFIG_GET_PRIVATE (fconfig);
+
+ xml_path = g_build_filename (config_dir, "accounts.xml", NULL);
+ xml = xmlParseFile (xml_path);
+ g_free (xml_path);
+
+ if (xml == NULL)
+ {
+ g_warning ("Could not load '%s/accounts.xml'", config_dir);
+ return;
+ }
+
+ if ((node = xmlDocGetRootElement (xml)) == NULL)
+ {
+ g_warning ("File '%s/accounts.xml' is empty", config_dir);
+ xmlFreeDoc (xml);
+ return;
+ }
+
+ if (node->name == NULL ||
+ xmlStrcmp (node->name, (const xmlChar*) "accounts") != 0)
+ {
+ g_warning ("File '%s/accounts.xml' does not start with "
+ "an <accounts> tag", config_dir);
+ xmlFreeDoc (xml);
+ return;
+ }
+
+ /* Iterate over children nodes and extract accounts. */
+ for (node = node->children; node != NULL; node = node->next)
+ {
+ if (xmlStrcmp (node->name, (const xmlChar*) "account") == 0)
+ {
+ FrogrAccount *account;
+ if ((account = _frogr_config_account_from_xml (xml, node)) == NULL)
+ {
+ g_warning ("Malformed account in '%s/accounts.xml', "
+ "skipping it", config_dir);
+ }
+ else
+ {
+ priv -> accounts = g_list_prepend (priv -> accounts, account);
+ }
+ }
+ }
+
+ xmlFreeDoc (xml);
+ xmlCleanupParser ();


+}
+
+
+static void

+_frogr_config_load (FrogrConfig *fconfig, const gchar *config_dir)
+{
+ g_return_if_fail (FROGR_IS_CONFIG (fconfig));
+ g_return_if_fail (config_dir != NULL);
+ /*
+ * XXX This method is just a placeholder for when we have program
+ * settings. For now, load just the accounts.
+ */
+
+ _frogr_config_load_accounts (fconfig, config_dir);
+}
+
+
+static xmlNodePtr
+_xml_add_string_child (xmlNodePtr parent,
+ const gchar *xml_name,
+ GObject *object,
+ const gchar *prop_name)
+{
+ xmlNodePtr node;
+ xmlChar *enc;
+ gchar *value;
+
+ g_return_val_if_fail (parent != NULL, NULL);
+ g_return_val_if_fail (xml_name != NULL, NULL);
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (prop_name != NULL, NULL);
+
+ g_object_get (object, prop_name, &value, NULL);
+
+ node = xmlNewNode (NULL, (const xmlChar*) xml_name);
+ enc = xmlEncodeEntitiesReentrant (NULL, (const xmlChar*) value);
+ xmlNodeSetContent (node, enc);
+ g_free (value);
+ xmlFree (enc);
+ xmlAddChild (parent, node);
+
+ return node;
+}
+
+
+static xmlNodePtr
+_xml_add_boolean_child (xmlNodePtr parent,
+ const gchar *xml_name,
+ GObject *object,
+ const gchar *prop_name)
+{
+ xmlNodePtr node;
+ gboolean value;
+
+ g_return_val_if_fail (parent != NULL, NULL);
+ g_return_val_if_fail (xml_name != NULL, NULL);
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (prop_name != NULL, NULL);
+
+ g_object_get (object, prop_name, &value, NULL);
+
+ node = xmlNewNode (NULL, (const xmlChar*) xml_name);
+ xmlNodeSetContent (node, (const xmlChar*) ((value) ? "true" : "false"));
+ xmlAddChild (parent, node);
+
+ return node;
+}
+
+
+static gboolean
+_frogr_config_save_accounts (FrogrConfig *fconfig)
+{
+ FrogrConfigPrivate *priv;
+ gboolean retval = TRUE;
+ xmlDocPtr xml;
+ xmlNodePtr node, root;
+ GList *item;
+ GObject *account;
+ gchar *xml_path;
+
+ g_return_val_if_fail (FROGR_IS_CONFIG (fconfig), FALSE);
+
+ priv = FROGR_CONFIG_GET_PRIVATE (fconfig);
+
+ xml = xmlNewDoc ((const xmlChar*) "1.0");
+ root = xmlNewNode (NULL, (const xmlChar*) "accounts");
+ xmlDocSetRootElement (xml, root);
+
+ for (item = g_list_first (priv -> accounts);
+ item != NULL;
+ item = g_list_next (item))
+ {
+ account = G_OBJECT (item->data);
+ node = xmlNewNode (NULL, (const xmlChar*) "account");
+ _xml_add_string_child (node, "frob", account, "frob");
+ _xml_add_string_child (node, "token", account, "token");
+ _xml_add_string_child (node, "username", account, "username");
+ _xml_add_boolean_child (node, "enabled", account, "enabled");
+
+ _xml_add_boolean_child (node, "public", account, "public");
+ _xml_add_boolean_child (node, "family", account, "family");
+ _xml_add_boolean_child (node, "friends", account, "friends");
+
+ xmlAddChild (root, node);
+ }
+
+ xml_path = g_build_filename (g_get_user_config_dir (),
+ "frogr", "accounts.xml", NULL);
+
+ if (xmlSaveFormatFileEnc (xml_path, xml, "UTF-8", 1) == -1) {
+ g_critical ("Unable to open '%s' for saving", xml_path);
+ retval = FALSE;
+ }
+
+ return retval;
+}
+
+
+gboolean
+frogr_config_save (FrogrConfig *fconfig)
+{
+ g_return_val_if_fail (FROGR_IS_CONFIG (fconfig), FALSE);
+
+ /*
+ * XXX This method is just a placeholder for when we have program
+ * settings. For now, save just the accounts.
+ */
+
+ return _frogr_config_save_accounts (fconfig);


+}
+
+
+
+
+static void

+_frogr_config_finalize (GObject *object)
+{
+ FrogrConfigPrivate *priv = FROGR_CONFIG_GET_PRIVATE (object);
+
+ g_list_foreach (priv -> accounts, (GFunc) g_object_unref, NULL);
+ g_list_free (priv -> accounts);


+
+ /* Call superclass */

+ G_OBJECT_CLASS (frogr_config_parent_class) -> finalize (object);
+}
+
+
+static GObject*
+_frogr_config_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params)
+{
+ static GObject *instance = NULL;
+
+ if (instance == NULL)
+ {
+ GObjectClass *klass = g_type_class_peek (FROGR_CONFIG_TYPE);
+ GObjectClass *parent_class = g_type_class_peek_parent (klass);
+ instance = G_OBJECT_CLASS (parent_class) -> constructor (type,
+ n_params,
+ params);
+ }
+ return g_object_ref (instance);


+}
+
+
+static void

+frogr_config_class_init (FrogrConfigClass *klass)


+{
+ GObjectClass *obj_class = G_OBJECT_CLASS (klass);
+

+ g_type_class_add_private (klass, sizeof (FrogrConfigPrivate));
+
+ obj_class -> constructor = _frogr_config_constructor;
+ obj_class -> finalize = _frogr_config_finalize;


+}
+
+
+static void

+frogr_config_init (FrogrConfig *fconfig)
+{
+ FrogrConfigPrivate *priv = FROGR_CONFIG_GET_PRIVATE (fconfig);
+ gchar *config_dir = g_build_filename (g_get_user_config_dir (),
+ g_get_prgname (), NULL);
+
+ priv -> accounts = NULL;
+
+ /* Ensure that we have the config directory in place. */
+ if (g_mkdir_with_parents (config_dir, 0777) != 0)
+ {
+ g_warning ("Could not create config directory '%s' (%s)",
+ config_dir, strerror (errno));
+ }
+
+ _frogr_config_load (fconfig, config_dir);
+
+ g_free (config_dir);


+}
+
+
+
+

+FrogrConfig*
+frogr_config_get_instance (void)
+{
+ static GObject *conf = NULL;
+
+ if (conf == NULL) conf = g_object_new (FROGR_CONFIG_TYPE, NULL);
+
+ return FROGR_CONFIG (g_object_ref (conf));
+}
+
+
+
+FrogrAccount*
+frogr_config_get_default_account (FrogrConfig *fconfig)
+{
+ g_return_val_if_fail (FROGR_IS_CONFIG (fconfig), NULL);
+ return frogr_config_get_account (fconfig, NULL);
+}
+
+
+void
+frogr_config_add_account (FrogrConfig *fconfig,
+ FrogrAccount *faccount)
+{
+ FrogrConfigPrivate *priv;
+
+ g_return_if_fail (FROGR_IS_CONFIG (fconfig));


+ g_return_if_fail (FROGR_IS_ACCOUNT (faccount));
+

+ priv = FROGR_CONFIG_GET_PRIVATE (fconfig);
+
+ priv -> accounts = g_list_prepend (priv -> accounts,
+ g_object_ref (faccount));
+}
+
+
+FrogrAccount*
+frogr_config_get_account (FrogrConfig *fconfig,
+ const gchar *username)
+{
+ FrogrConfigPrivate *priv;
+ GList *item;
+
+ g_return_val_if_fail (FROGR_IS_CONFIG (fconfig), NULL);
+
+ priv = FROGR_CONFIG_GET_PRIVATE (fconfig);
+
+ if (priv -> accounts == NULL)
+ {
+ frogr_config_add_account (fconfig, g_object_new (FROGR_ACCOUNT_TYPE, NULL));
+ }
+
+ if (username == NULL)
+ return FROGR_ACCOUNT (g_list_first (priv -> accounts)->data);
+
+ for (item = g_list_first (priv -> accounts);
+ item != NULL;
+ item = g_list_next (item))
+ {
+ FrogrAccount *faccount = FROGR_ACCOUNT (item -> data);
+ gchar *tmp = frogr_account_get_username (faccount);
+ if (g_str_equal (tmp, username))
+ {
+ g_free (tmp);
+ return faccount;
+ }
+ g_free (tmp);
+ }
+
+ return NULL;
+}
+
+
diff --git a/src/frogr-config.h b/src/frogr-config.h
new file mode 100644
index 0000000..c08dfaf
--- /dev/null
+++ b/src/frogr-config.h
@@ -0,0 +1,72 @@
+/*
+ * frogr-config.h -- Configuration system for Frogr.


+ *
+ * Copyright (C) 2009 Adrian Perez
+ * Authors: Adrian Perez <ape...@igalia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 3 of the GNU General Public
+ * License 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 warranty of
+ * MERCHANTABILITY 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+

+#ifndef _FROGR_CONFIG_H
+#define _FROGR_CONFIG_H
+
+#include "frogr-account.h"


+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+

+#define FROGR_CONFIG_TYPE (frogr_config_get_type())
+#define FROGR_IS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, FROGR_CONFIG_TYPE))
+#define FROGR_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, FROGR_CONFIG_TYPE))
+#define FROGR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, FROGR_CONFIG_TYPE, FrogrConfig))
+#define FROGR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, FROGR_CONFIG_TYPE, FrogrConfigClass))
+#define FROGR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, FROGR_CONFIG_TYPE, FrogrConfigClass))
+
+typedef struct _FrogrConfig FrogrConfig;
+typedef struct _FrogrConfigClass FrogrConfigClass;
+
+
+struct _FrogrConfig


+{
+ GObject parent_instance;
+};
+
+

+struct _FrogrConfigClass


+{
+ GObjectClass parent_class;
+};
+
+
+

+GType frogr_config_get_type (void) G_GNUC_CONST;
+
+FrogrConfig* frogr_config_get_instance (void);
+
+gboolean frogr_config_save (FrogrConfig *fconfig);
+
+FrogrAccount* frogr_config_get_default_account (FrogrConfig *fconfig);
+
+void frogr_config_add_account (FrogrConfig *fconfig,
+ FrogrAccount *faccount);
+
+FrogrAccount* frogr_config_get_account (FrogrConfig *fconfig,


+ const gchar *username);
+

+G_END_DECLS
+
+#endif /* !_FROGR_CONFIG_H */
+
--
1.6.3.2

Adrian Perez

unread,
Jun 15, 2009, 12:56:29 PM6/15/09
to frogr...@googlegroups.com
This is the minimum possible changes needed to save the frob and
authentication token, and load the authentication token to/from the
accounts configuration file. This is done nicely using the API of
the FrogrConfig and FrogrConfigAccount objects.

Fixes to frogr-config wiring
---
src/frogr-facade.c | 32 ++++++++++++++++++++------------
src/main.c | 2 ++
2 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/src/frogr-facade.c b/src/frogr-facade.c
index ad1f788..7f67b51 100644
--- a/src/frogr-facade.c
+++ b/src/frogr-facade.c
@@ -20,10 +20,13 @@
*
*/

+#include <string.h>
#include <flickcurl.h>
#include "frogr-facade.h"
#include "frogr-controller.h"
#include "frogr-picture.h"
+#include "frogr-config.h"
+#include "frogr-account.h"

#define API_KEY "18861766601de84f0921ce6be729f925"
#define SHARED_SECRET "6233fbefd85f733a"
@@ -39,8 +42,6 @@ struct _FrogrFacadePrivate
{
FrogrController *controller;
flickcurl *fcurl;
- gchar *frob;
- gchar *auth_token;
};


@@ -54,8 +55,6 @@ frogr_facade_finalize (GObject* object)
/* Free memory */
g_object_unref (priv -> controller);
flickcurl_free (priv -> fcurl);
- g_free (priv -> frob);
- g_free (priv -> auth_token);

/* Call superclass */
G_OBJECT_CLASS (frogr_facade_parent_class) -> finalize(object);
@@ -74,10 +73,8 @@ static void
frogr_facade_init (FrogrFacade *ffacade)
{
FrogrFacadePrivate *priv = FROGR_FACADE_GET_PRIVATE (ffacade);
-
- /* Set default values */
- priv -> auth_token = NULL;
- priv -> frob = NULL;
+ FrogrConfig *fconfig = frogr_config_get_instance ();
+ gchar *token;

/* Get controller */
priv -> controller = frogr_controller_get_instance ();
@@ -89,6 +86,13 @@ frogr_facade_init (FrogrFacade *ffacade)
/* Set API key and shared secret */
flickcurl_set_api_key(priv -> fcurl, API_KEY);
flickcurl_set_shared_secret(priv -> fcurl, SHARED_SECRET);
+
+ /* If available, set token */
+ if ((token = frogr_account_get_token (frogr_config_get_default_account (fconfig))) != NULL)
+ {
+ flickcurl_set_auth_token (priv->fcurl, token);
+ g_free (token);
+ }
}


@@ -109,6 +113,7 @@ frogr_facade_get_authorization_url (FrogrFacade *ffacade)
gchar *frob = flickcurl_auth_getFrob (priv -> fcurl);
gchar *auth_url = NULL;

+
/* Get auth url */
if (frob)
{
@@ -116,7 +121,8 @@ frogr_facade_get_authorization_url (FrogrFacade *ffacade)
gchar *api_sig;

/* Save frob value */
- priv -> frob = frob;
+ frogr_account_set_frob (frogr_config_get_default_account (frogr_config_get_instance ()),
+ frob);

/* Build the authorization url */
sign_str = g_strdup_printf ("%sapi_key%sfrob%spermswrite",
@@ -138,23 +144,25 @@ frogr_facade_complete_authorization (FrogrFacade *ffacade)
{
g_return_if_fail(FROGR_IS_FACADE (ffacade));

+ FrogrAccount *faccount = frogr_config_get_default_account (frogr_config_get_instance ());
FrogrFacadePrivate *priv = FROGR_FACADE_GET_PRIVATE (ffacade);
gchar *auth_token = NULL;
+ gchar *frob = NULL;

/* Check if frob value is present */
- if (!priv -> frob)
+ if ((frob = frogr_account_get_frob (faccount)) == NULL)
{
g_debug ("No frob defined");
return;
}

/* Get auth token */
- auth_token = flickcurl_auth_getToken (priv -> fcurl, priv -> frob);
+ auth_token = flickcurl_auth_getToken (priv -> fcurl, frob);
if (auth_token)
{
/* Set and save the auth token */
flickcurl_set_auth_token(priv -> fcurl, auth_token);
- priv -> auth_token = auth_token;
+ frogr_account_set_token (faccount, auth_token);
}

return (auth_token != NULL);
diff --git a/src/main.c b/src/main.c
index 267a8a8..df511fc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -23,6 +23,7 @@
#include <config.h>
#include <glib.h>
#include "frogr-controller.h"
+#include "frogr-config.h"

static FrogrController *fcontroller = NULL;

@@ -40,6 +41,7 @@ main (int argc, char **argv)
/* Run app */
fcontroller = frogr_controller_get_instance ();
frogr_controller_run_app (fcontroller);
+ frogr_config_save (frogr_config_get_instance ());

gdk_threads_leave ();

--
1.6.3.2

Mario Sanchez Prada

unread,
Jun 15, 2009, 6:33:06 PM6/15/09
to frogr...@googlegroups.com
Great! Changes pushed to master with a couple of changes afterwards,
just nitpicking about coding style, basically.

Thanks for your superb contribution! Now we have a proper configuration
management system, so this is the "beginning of the end" of the annoying
"authorize" button, which was needed to get pressed every time the app
was run so far :-)

Great!
Mario

Adrian Perez de Castro

unread,
Jun 15, 2009, 6:57:44 PM6/15/09
to frogr...@googlegroups.com
On Mon, 15 Jun 2009 23:33:06 +0100, Mario wrote:

> Great! Changes pushed to master with a couple of changes afterwards,
> just nitpicking about coding style, basically.

I am reviewing what you changed -- just to try not to make the same
mistakes again :)



> Thanks for your superb contribution! Now we have a proper configuration
> management system, so this is the "beginning of the end" of the annoying
> "authorize" button, which was needed to get pressed every time the app
> was run so far :-)

Now that you mention it: nice idea to remove the authorization button
from the main window and trigger the authorization process at the
first start-up... but probably it would be desirable to keep the option
somewhere (in a menu or some other place which is not directly visible)
just in case someone needs to re-authenticate, e.g. if the application
was removed from the list of allowed clients in the Flickr website.

Just sharing my thoughts :)

Best regards, and thanks again for your time while correcting my
patches and providing nice comments on it!

--
Adrian Perez de Castro <ape...@igalia.com>
Igalia - Free Software Engineering

signature.asc

Mario Sanchez Prada

unread,
Jun 16, 2009, 3:11:56 AM6/16/09
to frogr...@googlegroups.com
Adrian Perez de Castro wrote:
> [...]

> Now that you mention it: nice idea to remove the authorization button
> from the main window and trigger the authorization process at the
> first start-up... but probably it would be desirable to keep the option
> somewhere (in a menu or some other place which is not directly visible)
> just in case someone needs to re-authenticate, e.g. if the application
> was removed from the list of allowed clients in the Flickr website.

Sure, that's a mandatory next step as well :-)

> Just sharing my thoughts :)
>
> Best regards, and thanks again for your time while correcting my
> patches and providing nice comments on it!

You're welcome. I'm glad to have found some time for it.

See you!
Mario


Reply all
Reply to author
Forward
0 new messages