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
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
* 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
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
> 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
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