summaryrefslogtreecommitdiff
path: root/rest-extras
diff options
context:
space:
mode:
authorRoss Burton <ross@linux.intel.com>2009-10-08 15:30:40 +0100
committerRoss Burton <ross@linux.intel.com>2009-10-08 15:30:40 +0100
commitb7b09e3921c29d2af891382e5c905436984db13e (patch)
treedd250c86bcef049d5cbee3a0907d6833fddf7558 /rest-extras
parentbd0adec30e6f1e73a08c365902268e486529c07d (diff)
Split the Facebook and Flickr backends to librest-extras
Diffstat (limited to 'rest-extras')
-rw-r--r--rest-extras/Makefile.am36
-rw-r--r--rest-extras/facebook-proxy-call.c88
-rw-r--r--rest-extras/facebook-proxy-call.h67
-rw-r--r--rest-extras/facebook-proxy-private.h33
-rw-r--r--rest-extras/facebook-proxy.c354
-rw-r--r--rest-extras/facebook-proxy.h93
-rw-r--r--rest-extras/flickr-proxy-call.c80
-rw-r--r--rest-extras/flickr-proxy-call.h68
-rw-r--r--rest-extras/flickr-proxy-private.h33
-rw-r--r--rest-extras/flickr-proxy.c407
-rw-r--r--rest-extras/flickr-proxy.h94
-rw-r--r--rest-extras/test-runner.c35
12 files changed, 1388 insertions, 0 deletions
diff --git a/rest-extras/Makefile.am b/rest-extras/Makefile.am
new file mode 100644
index 0000000..e59e235
--- /dev/null
+++ b/rest-extras/Makefile.am
@@ -0,0 +1,36 @@
+lib_sources = \
+ flickr-proxy.c \
+ flickr-proxy-call.c \
+ flickr-proxy-private.h \
+ facebook-proxy.c \
+ facebook-proxy-call.c \
+ facebook-proxy-private.h
+lib_headers = \
+ flickr-proxy.h \
+ flickr-proxy-call.h \
+ facebook-proxy.h \
+ facebook-proxy-call.h
+
+
+lib_LTLIBRARIES = librest-extras-@API_VERSION@.la
+librest_extras_@API_VERSION@_la_CFLAGS = $(GLIB_CFLAGS) $(GTHREAD_CFLAGS) \
+ $(SOUP_CFLAGS) $(SOUP_GNOME_CFLAGS) \
+ $(XML_CFLAGS) \
+ -I$(top_srcdir) -Wall -DG_LOG_DOMAIN=\"Rest\"
+librest_extras_@API_VERSION@_la_LIBADD = $(GLIB_LIBS) $(GTHREAD_LIBS) \
+ $(SOUP_LIBS) $(SOUP_GNOME_LIBS) $(XML_LIBS) \
+ $(top_builddir)/rest/librest-@API_VERSION@.la
+librest_extras_@API_VERSION@_la_SOURCES = $(lib_sources) $(lib_headers)
+librest_extras_@API_VERSION@_la_HEADERS = $(lib_headers)
+librest_extras_@API_VERSION@_ladir = $(includedir)/rest-@API_VERSION@/rest-extras
+
+
+# Test suite
+TESTS = test-runner
+check_PROGRAMS = test-runner
+
+test_runner_SOURCES = test-runner.c $(lib_sources) $(lib_headers)
+test_runner_CFLAGS = -DBUILD_TESTS $(librest_extras_@API_VERSION@_la_CFLAGS)
+test_runner_LDFLAGS = $(librest_extras_@API_VERSION@_la_LIBADD)
+
+# TODO: use gtester
diff --git a/rest-extras/facebook-proxy-call.c b/rest-extras/facebook-proxy-call.c
new file mode 100644
index 0000000..353f119
--- /dev/null
+++ b/rest-extras/facebook-proxy-call.c
@@ -0,0 +1,88 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <string.h>
+#include <libsoup/soup.h>
+#include <rest/rest-proxy-call.h>
+#include "facebook-proxy-call.h"
+#include "facebook-proxy-private.h"
+#include "rest/rest-proxy-call-private.h"
+#include "rest/sha1.h"
+
+G_DEFINE_TYPE (FacebookProxyCall, facebook_proxy_call, REST_TYPE_PROXY_CALL)
+
+static gboolean
+_prepare (RestProxyCall *call, GError **error)
+{
+ FacebookProxy *proxy = NULL;
+ FacebookProxyPrivate *priv;
+ RestProxyCallPrivate *call_priv;
+ char *s;
+
+ g_object_get (call, "proxy", &proxy, NULL);
+ priv = PROXY_GET_PRIVATE (proxy);
+ call_priv = call->priv;
+
+ /* First reset the URL because Facebook puts the function in the parameters */
+ g_object_get (proxy, "url-format", &call_priv->url, NULL);
+
+ rest_proxy_call_add_params (call,
+ "method", call_priv->function,
+ "api_key", priv->api_key,
+ "v", "1.0",
+ NULL);
+
+ if (priv->session_key) {
+ GTimeVal time;
+ g_get_current_time (&time);
+ s = g_strdup_printf ("%ld.%ld", time.tv_sec, time.tv_usec);
+ rest_proxy_call_add_param (call, "call_id", s);
+ g_free (s);
+
+ rest_proxy_call_add_param (call, "session_key", priv->session_key);
+ }
+
+ s = facebook_proxy_sign (proxy, call_priv->params);
+ rest_proxy_call_add_param (call, "sig", s);
+ g_free (s);
+
+ g_object_unref (proxy);
+
+ return TRUE;
+}
+
+static void
+facebook_proxy_call_class_init (FacebookProxyCallClass *klass)
+{
+ RestProxyCallClass *call_class = REST_PROXY_CALL_CLASS (klass);
+
+ call_class->prepare = _prepare;
+}
+
+static void
+facebook_proxy_call_init (FacebookProxyCall *self)
+{
+}
+
+#if BUILD_TESTS
+#warning TODO facebook signature test cases
+#endif
diff --git a/rest-extras/facebook-proxy-call.h b/rest-extras/facebook-proxy-call.h
new file mode 100644
index 0000000..9f97ad7
--- /dev/null
+++ b/rest-extras/facebook-proxy-call.h
@@ -0,0 +1,67 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _FACEBOOK_PROXY_CALL
+#define _FACEBOOK_PROXY_CALL
+
+#include <rest/rest-proxy-call.h>
+
+G_BEGIN_DECLS
+
+#define FACEBOOK_TYPE_PROXY_CALL facebook_proxy_call_get_type()
+
+#define FACEBOOK_PROXY_CALL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), FACEBOOK_TYPE_PROXY_CALL, FacebookProxyCall))
+
+#define FACEBOOK_PROXY_CALL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), FACEBOOK_TYPE_PROXY_CALL, FacebookProxyCallClass))
+
+#define FACEBOOK_IS_PROXY_CALL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FACEBOOK_TYPE_PROXY_CALL))
+
+#define FACEBOOK_IS_PROXY_CALL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), FACEBOOK_TYPE_PROXY_CALL))
+
+#define FACEBOOK_PROXY_CALL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), FACEBOOK_TYPE_PROXY_CALL, FacebookProxyCallClass))
+
+/**
+ * FacebookProxyCall:
+ *
+ * #FacebookProxyCall has no publicly available members.
+ */
+typedef struct {
+ RestProxyCall parent;
+} FacebookProxyCall;
+
+typedef struct {
+ RestProxyCallClass parent_class;
+ /*< private >*/
+ /* padding for future expansion */
+ gpointer _padding_dummy[8];
+} FacebookProxyCallClass;
+
+GType facebook_proxy_call_get_type (void);
+
+G_END_DECLS
+
+#endif /* _FACEBOOK_PROXY_CALL */
diff --git a/rest-extras/facebook-proxy-private.h b/rest-extras/facebook-proxy-private.h
new file mode 100644
index 0000000..0f652a6
--- /dev/null
+++ b/rest-extras/facebook-proxy-private.h
@@ -0,0 +1,33 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "facebook-proxy.h"
+
+#define PROXY_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), FACEBOOK_TYPE_PROXY, FacebookProxyPrivate))
+
+struct _FacebookProxyPrivate {
+ char *api_key;
+ char *app_secret;
+ char *session_key;
+};
+
diff --git a/rest-extras/facebook-proxy.c b/rest-extras/facebook-proxy.c
new file mode 100644
index 0000000..2ca5490
--- /dev/null
+++ b/rest-extras/facebook-proxy.c
@@ -0,0 +1,354 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <config.h>
+#include <string.h>
+#include <rest/rest-proxy.h>
+#include <libsoup/soup.h>
+#include "facebook-proxy.h"
+#include "facebook-proxy-private.h"
+#include "facebook-proxy-call.h"
+
+G_DEFINE_TYPE (FacebookProxy, facebook_proxy, REST_TYPE_PROXY)
+
+enum {
+ PROP_0,
+ PROP_API_KEY,
+ PROP_APP_SECRET,
+ PROP_SESSION_KEY,
+};
+
+static RestProxyCall *
+_new_call (RestProxy *proxy)
+{
+ RestProxyCall *call;
+
+ call = g_object_new (FACEBOOK_TYPE_PROXY_CALL,
+ "proxy", proxy,
+ NULL);
+
+ return call;
+}
+
+static void
+facebook_proxy_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ FacebookProxyPrivate *priv = PROXY_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_API_KEY:
+ g_value_set_string (value, priv->api_key);
+ break;
+ case PROP_APP_SECRET:
+ g_value_set_string (value, priv->app_secret);
+ break;
+ case PROP_SESSION_KEY:
+ g_value_set_string (value, priv->session_key);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+facebook_proxy_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ FacebookProxyPrivate *priv = PROXY_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_API_KEY:
+ if (priv->api_key)
+ g_free (priv->api_key);
+ priv->api_key = g_value_dup_string (value);
+ break;
+ case PROP_APP_SECRET:
+ if (priv->app_secret)
+ g_free (priv->app_secret);
+ priv->app_secret = g_value_dup_string (value);
+ break;
+ case PROP_SESSION_KEY:
+ if (priv->session_key);
+ g_free (priv->session_key);
+ priv->session_key = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+facebook_proxy_finalize (GObject *object)
+{
+ FacebookProxyPrivate *priv = PROXY_GET_PRIVATE (object);
+
+ g_free (priv->api_key);
+ g_free (priv->app_secret);
+ g_free (priv->session_key);
+
+ G_OBJECT_CLASS (facebook_proxy_parent_class)->finalize (object);
+}
+
+#ifndef G_PARAM_STATIC_STRINGS
+#define G_PARAM_STATIC_STRINGS (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
+#endif
+
+static void
+facebook_proxy_class_init (FacebookProxyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ RestProxyClass *proxy_class = REST_PROXY_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (FacebookProxyPrivate));
+
+ object_class->get_property = facebook_proxy_get_property;
+ object_class->set_property = facebook_proxy_set_property;
+ object_class->finalize = facebook_proxy_finalize;
+
+ proxy_class->new_call = _new_call;
+
+ pspec = g_param_spec_string ("api-key", "api-key",
+ "The API key", NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class,
+ PROP_API_KEY,
+ pspec);
+
+ pspec = g_param_spec_string ("app-secret", "app-secret",
+ "The application secret", NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class,
+ PROP_APP_SECRET,
+ pspec);
+
+ pspec = g_param_spec_string ("session-key", "session-key",
+ "The session key", NULL,
+ G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class,
+ PROP_SESSION_KEY,
+ pspec);
+}
+
+static void
+facebook_proxy_init (FacebookProxy *self)
+{
+ self->priv = PROXY_GET_PRIVATE (self);
+}
+
+RestProxy *
+facebook_proxy_new (const char *api_key,
+ const char *app_secret)
+{
+ return facebook_proxy_new_with_session (api_key,
+ app_secret,
+ NULL);
+}
+
+RestProxy *
+facebook_proxy_new_with_session (const char *api_key,
+ const char *app_secret,
+ const char *session_key)
+{
+ return g_object_new (FACEBOOK_TYPE_PROXY,
+ "api-key", api_key,
+ "app-secret", app_secret,
+ "session-key", session_key,
+ "url-format", "https://api.facebook.com/restserver.php",
+ "binding-required", FALSE,
+ NULL);
+}
+
+/**
+ * facebook_proxy_get_api_key:
+ * @proxy: an #FacebookProxy
+ *
+ * Get the API key.
+ *
+ * Returns: the API key. This string is owned by #FacebookProxy and should not be
+ * freed.
+ */
+const char *
+facebook_proxy_get_api_key (FacebookProxy *proxy)
+{
+ FacebookProxyPrivate *priv = PROXY_GET_PRIVATE (proxy);
+ return priv->api_key;
+}
+
+/**
+ * facebook_proxy_get_app_secret:
+ * @proxy: an #FacebookProxy
+ *
+ * Get the application secret for authentication.
+ *
+ * Returns: the application secret. This string is owned by #FacebookProxy and should not be
+ * freed.
+ */
+const char *
+facebook_proxy_get_app_secret (FacebookProxy *proxy)
+{
+ FacebookProxyPrivate *priv = PROXY_GET_PRIVATE (proxy);
+ return priv->app_secret;
+}
+
+void
+facebook_proxy_set_app_secret (FacebookProxy *proxy, const char *secret)
+{
+ FacebookProxyPrivate *priv;
+
+ g_return_if_fail (FACEBOOK_IS_PROXY (proxy));
+ priv = PROXY_GET_PRIVATE (proxy);
+
+ if (priv->app_secret)
+ g_free (priv->app_secret);
+
+ priv->app_secret = g_strdup (secret);
+}
+
+/**
+ * facebook_proxy_get_session_key:
+ * @proxy: an #FacebookProxy
+ *
+ * Get the current session key
+ *
+ * Returns: the session key, or %NULL if there is no session yet. This string is owned
+ * by #FacebookProxy and should not be freed.
+ */
+const char *
+facebook_proxy_get_session_key (FacebookProxy *proxy)
+{
+ FacebookProxyPrivate *priv = PROXY_GET_PRIVATE (proxy);
+ return priv->session_key;
+}
+
+/**
+ * facebook_proxy_set_session_key:
+ * @proxy: an #FacebookProxy
+ * @session_key: the session key
+ *
+ * Set the token.
+ */
+void
+facebook_proxy_set_session_key (FacebookProxy *proxy, const char *session_key)
+{
+ FacebookProxyPrivate *priv;
+
+ g_return_if_fail (FACEBOOK_IS_PROXY (proxy));
+ priv = PROXY_GET_PRIVATE (proxy);
+
+ if (priv->session_key)
+ g_free (priv->session_key);
+
+ priv->session_key = g_strdup (session_key);
+}
+
+char *
+facebook_proxy_sign (FacebookProxy *proxy, GHashTable *params)
+{
+ FacebookProxyPrivate *priv;
+ GString *s;
+ GList *keys;
+ char *md5;
+
+ g_return_val_if_fail (FACEBOOK_IS_PROXY (proxy), NULL);
+ g_return_val_if_fail (params, NULL);
+
+ priv = PROXY_GET_PRIVATE (proxy);
+
+ s = g_string_new (NULL);
+
+ keys = g_hash_table_get_keys (params);
+ keys = g_list_sort (keys, (GCompareFunc)strcmp);
+
+ while (keys) {
+ const char *key;
+ const char *value;
+
+ key = keys->data;
+ value = g_hash_table_lookup (params, key);
+
+ g_string_append_printf (s, "%s=%s", key, value);
+
+ keys = keys->next;
+ }
+
+ g_string_append (s, priv->app_secret);
+
+ md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, s->str, s->len);
+
+ g_string_free (s, TRUE);
+
+ return md5;
+}
+
+char *
+facebook_proxy_build_login_url (FacebookProxy *proxy, const char *token)
+{
+ SoupURI *uri;
+ GHashTable *params;
+ char *s;
+
+ g_return_val_if_fail (FACEBOOK_IS_PROXY (proxy), NULL);
+ g_return_val_if_fail (token, NULL);
+
+ uri = soup_uri_new ("http://facebook.com/login.php/");
+ params = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (params, "api_key", proxy->priv->api_key);
+ g_hash_table_insert (params, "v", "1.0");
+ g_hash_table_insert (params, "auth_token", (gpointer)token);
+
+ soup_uri_set_query_from_form (uri, params);
+
+ s = soup_uri_to_string (uri, FALSE);
+
+ g_hash_table_unref (params);
+ soup_uri_free (uri);
+ return s;
+}
+
+char *
+facebook_proxy_build_permission_url (FacebookProxy *proxy, const char *perms)
+{
+ SoupURI *uri;
+ GHashTable *params;
+ char *s;
+
+ g_return_val_if_fail (FACEBOOK_IS_PROXY (proxy), NULL);
+ g_return_val_if_fail (perms, NULL);
+
+ uri = soup_uri_new ("http://facebook.com/authorize.php");
+ params = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (params, "api_key", proxy->priv->api_key);
+ g_hash_table_insert (params, "v", "1.0");
+ g_hash_table_insert (params, "ext_perm", (gpointer)perms);
+
+ soup_uri_set_query_from_form (uri, params);
+
+ s = soup_uri_to_string (uri, FALSE);
+
+ g_hash_table_unref (params);
+ soup_uri_free (uri);
+ return s;
+}
diff --git a/rest-extras/facebook-proxy.h b/rest-extras/facebook-proxy.h
new file mode 100644
index 0000000..cdee905
--- /dev/null
+++ b/rest-extras/facebook-proxy.h
@@ -0,0 +1,93 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _FACEBOOK_PROXY
+#define _FACEBOOK_PROXY
+
+#include <rest/rest-proxy.h>
+
+G_BEGIN_DECLS
+
+#define FACEBOOK_TYPE_PROXY facebook_proxy_get_type()
+
+#define FACEBOOK_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), FACEBOOK_TYPE_PROXY, FacebookProxy))
+
+#define FACEBOOK_PROXY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), FACEBOOK_TYPE_PROXY, FacebookProxyClass))
+
+#define FACEBOOK_IS_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FACEBOOK_TYPE_PROXY))
+
+#define FACEBOOK_IS_PROXY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), FACEBOOK_TYPE_PROXY))
+
+#define FACEBOOK_PROXY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), FACEBOOK_TYPE_PROXY, FacebookProxyClass))
+
+typedef struct _FacebookProxyPrivate FacebookProxyPrivate;
+
+/**
+ * FacebookProxy:
+ *
+ * #FacebookProxy has no publicly available members.
+ */
+typedef struct {
+ RestProxy parent;
+ FacebookProxyPrivate *priv;
+} FacebookProxy;
+
+typedef struct {
+ RestProxyClass parent_class;
+ /*< private >*/
+ /* padding for future expansion */
+ gpointer _padding_dummy[8];
+} FacebookProxyClass;
+
+GType facebook_proxy_get_type (void);
+
+RestProxy* facebook_proxy_new (const char *api_key,
+ const char *app_secret);
+
+RestProxy* facebook_proxy_new_with_session (const char *api_key,
+ const char *app_secret,
+ const char *session_key);
+
+const char * facebook_proxy_get_api_key (FacebookProxy *proxy);
+
+void facebook_proxy_set_app_secret (FacebookProxy *proxy, const char *secret);
+
+const char * facebook_proxy_get_app_secret (FacebookProxy *proxy);
+
+const char * facebook_proxy_get_session_key (FacebookProxy *proxy);
+
+void facebook_proxy_set_session_key (FacebookProxy *proxy, const char *session_key);
+
+char * facebook_proxy_sign (FacebookProxy *proxy, GHashTable *params);
+
+char * facebook_proxy_build_login_url (FacebookProxy *proxy, const char *frob);
+
+char * facebook_proxy_build_permission_url (FacebookProxy *proxy, const char *perms);
+
+G_END_DECLS
+
+#endif /* _FACEBOOK_PROXY */
diff --git a/rest-extras/flickr-proxy-call.c b/rest-extras/flickr-proxy-call.c
new file mode 100644
index 0000000..a408925
--- /dev/null
+++ b/rest-extras/flickr-proxy-call.c
@@ -0,0 +1,80 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <string.h>
+#include <libsoup/soup.h>
+#include <rest/rest-proxy-call.h>
+#include "flickr-proxy-call.h"
+#include "flickr-proxy-private.h"
+#include "rest/rest-proxy-call-private.h"
+#include "rest/sha1.h"
+
+G_DEFINE_TYPE (FlickrProxyCall, flickr_proxy_call, REST_TYPE_PROXY_CALL)
+
+static gboolean
+_prepare (RestProxyCall *call, GError **error)
+{
+ FlickrProxy *proxy = NULL;
+ FlickrProxyPrivate *priv;
+ RestProxyCallPrivate *call_priv;
+ char *s;
+
+ g_object_get (call, "proxy", &proxy, NULL);
+ priv = PROXY_GET_PRIVATE (proxy);
+ call_priv = call->priv;
+
+ /* First reset the URL because Flickr puts the function in the parameters */
+ call_priv->url = g_strdup ("http://api.flickr.com/services/rest/");
+
+ rest_proxy_call_add_params (call,
+ "method", call_priv->function,
+ "api_key", priv->api_key,
+ NULL);
+
+ if (priv->token)
+ rest_proxy_call_add_param (call, "auth_token", priv->token);
+
+ s = flickr_proxy_sign (proxy, call_priv->params);
+ rest_proxy_call_add_param (call, "api_sig", s);
+ g_free (s);
+
+ g_object_unref (proxy);
+
+ return TRUE;
+}
+
+static void
+flickr_proxy_call_class_init (FlickrProxyCallClass *klass)
+{
+ RestProxyCallClass *call_class = REST_PROXY_CALL_CLASS (klass);
+
+ call_class->prepare = _prepare;
+}
+
+static void
+flickr_proxy_call_init (FlickrProxyCall *self)
+{
+}
+
+#if BUILD_TESTS
+#warning TODO flickr signature test cases
+#endif
diff --git a/rest-extras/flickr-proxy-call.h b/rest-extras/flickr-proxy-call.h
new file mode 100644
index 0000000..195886e
--- /dev/null
+++ b/rest-extras/flickr-proxy-call.h
@@ -0,0 +1,68 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _FLICKR_PROXY_CALL
+#define _FLICKR_PROXY_CALL
+
+#include <rest/rest-proxy-call.h>
+
+G_BEGIN_DECLS
+
+#define FLICKR_TYPE_PROXY_CALL flickr_proxy_call_get_type()
+
+#define FLICKR_PROXY_CALL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), FLICKR_TYPE_PROXY_CALL, FlickrProxyCall))
+
+#define FLICKR_PROXY_CALL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), FLICKR_TYPE_PROXY_CALL, FlickrProxyCallClass))
+
+#define FLICKR_IS_PROXY_CALL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FLICKR_TYPE_PROXY_CALL))
+
+#define FLICKR_IS_PROXY_CALL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), FLICKR_TYPE_PROXY_CALL))
+
+#define FLICKR_PROXY_CALL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), FLICKR_TYPE_PROXY_CALL, FlickrProxyCallClass))
+
+/**
+ * FlickrProxyCall:
+ *
+ * #FlickrProxyCall has no publicly available members.
+ */
+typedef struct {
+ RestProxyCall parent;
+} FlickrProxyCall;
+
+typedef struct {
+ RestProxyCallClass parent_class;
+ /*< private >*/
+ /* padding for future expansion */
+ gpointer _padding_dummy[8];
+} FlickrProxyCallClass;
+
+GType flickr_proxy_call_get_type (void);
+
+G_END_DECLS
+
+#endif /* _FLICKR_PROXY_CALL */
+
diff --git a/rest-extras/flickr-proxy-private.h b/rest-extras/flickr-proxy-private.h
new file mode 100644
index 0000000..cbf8533
--- /dev/null
+++ b/rest-extras/flickr-proxy-private.h
@@ -0,0 +1,33 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "flickr-proxy.h"
+
+#define PROXY_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), FLICKR_TYPE_PROXY, FlickrProxyPrivate))
+
+struct _FlickrProxyPrivate {
+ char *api_key;
+ char *shared_secret;
+ char *token;
+};
+
diff --git a/rest-extras/flickr-proxy.c b/rest-extras/flickr-proxy.c
new file mode 100644
index 0000000..38ff330
--- /dev/null
+++ b/rest-extras/flickr-proxy.c
@@ -0,0 +1,407 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/*
+ * TODO:
+ *
+ * Convenience API for authentication so that the user doesn't have to parse the
+ * XML themselves.
+ *
+ * Function to parse a payload and return either a xml document or a GError.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rest/rest-proxy.h>
+#include <libsoup/soup.h>
+#include "flickr-proxy.h"
+#include "flickr-proxy-private.h"
+#include "flickr-proxy-call.h"
+
+G_DEFINE_TYPE (FlickrProxy, flickr_proxy, REST_TYPE_PROXY)
+
+enum {
+ PROP_0,
+ PROP_API_KEY,
+ PROP_SHARED_SECRET,
+ PROP_TOKEN,
+};
+
+GQuark
+flickr_proxy_error_quark (void)
+{
+ return g_quark_from_static_string ("rest-flickr-proxy");
+}
+
+static RestProxyCall *
+_new_call (RestProxy *proxy)
+{
+ RestProxyCall *call;
+
+ call = g_object_new (FLICKR_TYPE_PROXY_CALL,
+ "proxy", proxy,
+ NULL);
+
+ return call;
+}
+
+static void
+flickr_proxy_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ FlickrProxyPrivate *priv = PROXY_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_API_KEY:
+ g_value_set_string (value, priv->api_key);
+ break;
+ case PROP_SHARED_SECRET:
+ g_value_set_string (value, priv->shared_secret);
+ break;
+ case PROP_TOKEN:
+ g_value_set_string (value, priv->token);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+flickr_proxy_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ FlickrProxyPrivate *priv = PROXY_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_API_KEY:
+ if (priv->api_key)
+ g_free (priv->api_key);
+ priv->api_key = g_value_dup_string (value);
+ break;
+ case PROP_SHARED_SECRET:
+ if (priv->shared_secret)
+ g_free (priv->shared_secret);
+ priv->shared_secret = g_value_dup_string (value);
+ break;
+ case PROP_TOKEN:
+ if (priv->token)
+ g_free (priv->token);
+ priv->token = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+flickr_proxy_finalize (GObject *object)
+{
+ FlickrProxyPrivate *priv = PROXY_GET_PRIVATE (object);
+
+ g_free (priv->api_key);
+ g_free (priv->shared_secret);
+ g_free (priv->token);
+
+ G_OBJECT_CLASS (flickr_proxy_parent_class)->finalize (object);
+}
+
+#ifndef G_PARAM_STATIC_STRINGS
+#define G_PARAM_STATIC_STRINGS (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
+#endif
+
+static void
+flickr_proxy_class_init (FlickrProxyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ RestProxyClass *proxy_class = REST_PROXY_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (FlickrProxyPrivate));
+
+ object_class->get_property = flickr_proxy_get_property;
+ object_class->set_property = flickr_proxy_set_property;
+ object_class->finalize = flickr_proxy_finalize;
+
+ proxy_class->new_call = _new_call;
+
+ pspec = g_param_spec_string ("api-key", "api-key",
+ "The API key", NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class,
+ PROP_API_KEY,
+ pspec);
+
+ pspec = g_param_spec_string ("shared-secret", "shared-secret",
+ "The shared secret", NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class,
+ PROP_SHARED_SECRET,
+ pspec);
+
+ pspec = g_param_spec_string ("token", "token",
+ "The request or access token", NULL,
+ G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class,
+ PROP_TOKEN,
+ pspec);
+}
+
+static void
+flickr_proxy_init (FlickrProxy *self)
+{
+ self->priv = PROXY_GET_PRIVATE (self);
+}
+
+RestProxy *
+flickr_proxy_new (const char *api_key,
+ const char *shared_secret)
+{
+ return flickr_proxy_new_with_token (api_key,
+ shared_secret,
+ NULL);
+}
+
+RestProxy *
+flickr_proxy_new_with_token (const char *api_key,
+ const char *shared_secret,
+ const char *token)
+{
+ return g_object_new (FLICKR_TYPE_PROXY,
+ "api-key", api_key,
+ "shared-secret", shared_secret,
+ "token", token,
+ "url-format", "http://api.flickr.com/services/rest/",
+ "binding-required", FALSE,
+ NULL);
+}
+
+/**
+ * flickr_proxy_get_api_key:
+ * @proxy: an #FlickrProxy
+ *
+ * Get the API key.
+ *
+ * Returns: the API key. This string is owned by #FlickrProxy and should not be
+ * freed.
+ */
+const char *
+flickr_proxy_get_api_key (FlickrProxy *proxy)
+{
+ FlickrProxyPrivate *priv = PROXY_GET_PRIVATE (proxy);
+ return priv->api_key;
+}
+
+/**
+ * flickr_proxy_get_shared_secret:
+ * @proxy: an #FlickrProxy
+ *
+ * Get the shared secret for authentication.
+ *
+ * Returns: the shared secret. This string is owned by #FlickrProxy and should not be
+ * freed.
+ */
+const char *
+flickr_proxy_get_shared_secret (FlickrProxy *proxy)
+{
+ FlickrProxyPrivate *priv = PROXY_GET_PRIVATE (proxy);
+ return priv->shared_secret;
+}
+
+/**
+ * flickr_proxy_get_token:
+ * @proxy: an #FlickrProxy
+ *
+ * Get the current token.
+ *
+ * Returns: the token, or %NULL if there is no token yet. This string is owned
+ * by #FlickrProxy and should not be freed.
+ */
+const char *
+flickr_proxy_get_token (FlickrProxy *proxy)
+{
+ FlickrProxyPrivate *priv = PROXY_GET_PRIVATE (proxy);
+ return priv->token;
+}
+
+/**
+ * flickr_proxy_set_token:
+ * @proxy: an #FlickrProxy
+ * @token: the access token
+ *
+ * Set the token.
+ */
+void
+flickr_proxy_set_token (FlickrProxy *proxy, const char *token)
+{
+ FlickrProxyPrivate *priv;
+
+ g_return_if_fail (FLICKR_IS_PROXY (proxy));
+ priv = PROXY_GET_PRIVATE (proxy);
+
+ if (priv->token)
+ g_free (priv->token);
+
+ priv->token = g_strdup (token);
+}
+
+char *
+flickr_proxy_sign (FlickrProxy *proxy, GHashTable *params)
+{
+ FlickrProxyPrivate *priv;
+ GString *s;
+ GList *keys;
+ char *md5;
+
+ g_return_val_if_fail (FLICKR_IS_PROXY (proxy), NULL);
+ g_return_val_if_fail (params, NULL);
+
+ priv = PROXY_GET_PRIVATE (proxy);
+
+ s = g_string_new (priv->shared_secret);
+
+ keys = g_hash_table_get_keys (params);
+ keys = g_list_sort (keys, (GCompareFunc)strcmp);
+
+ while (keys) {
+ const char *key;
+ const char *value;
+
+ key = keys->data;
+ value = g_hash_table_lookup (params, key);
+
+ g_string_append_printf (s, "%s%s", key, value);
+
+ keys = g_list_delete_link (keys, keys);
+ }
+
+ md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, s->str, s->len);
+
+ g_string_free (s, TRUE);
+
+ return md5;
+}
+
+char *
+flickr_proxy_build_login_url (FlickrProxy *proxy, const char *frob)
+{
+ SoupURI *uri;
+ GHashTable *params;
+ char *sig, *s;
+
+ g_return_val_if_fail (FLICKR_IS_PROXY (proxy), NULL);
+
+ uri = soup_uri_new ("http://flickr.com/services/auth/");
+ params = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (params, "api_key", proxy->priv->api_key);
+ /* TODO: parameter */
+ g_hash_table_insert (params, "perms", "read");
+ if (frob)
+ g_hash_table_insert (params, "frob", (gpointer)frob);
+
+ sig = flickr_proxy_sign (proxy, params);
+ g_hash_table_insert (params, "api_sig", sig);
+
+ soup_uri_set_query_from_form (uri, params);
+
+ s = soup_uri_to_string (uri, FALSE);
+
+ g_free (sig);
+ g_hash_table_destroy (params);
+ soup_uri_free (uri);
+
+ return s;
+}
+
+/**
+ * flickr_proxy_is_successful:
+ * @root: The root node of a parsed Flickr response
+ * @error: #GError to set if the response was an error
+ *
+ * Examines the Flickr response and if it not a successful reply, set @error and
+ * return FALSE.
+ *
+ * Returns: %TRUE if this response is successful, %FALSE otherwise.
+ */
+gboolean
+flickr_proxy_is_successful (RestXmlNode *root, GError **error)
+{
+ RestXmlNode *node;
+
+ g_return_val_if_fail (root, FALSE);
+
+ if (strcmp (root->name, "rsp") != 0) {
+ g_set_error (error, FLICKR_PROXY_ERROR, 0,
+ "Unexpected response from Flickr (root node %s)",
+ root->name);
+ return FALSE;
+ }
+
+ if (strcmp (rest_xml_node_get_attr (root, "stat"), "ok") != 0) {
+ node = rest_xml_node_find (root, "err");
+ g_set_error_literal (error,FLICKR_PROXY_ERROR,
+ atoi (rest_xml_node_get_attr (node, "code")),
+ rest_xml_node_get_attr (node, "msg"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#if BUILD_TESTS
+void
+test_flickr_error (void)
+{
+ RestXmlParser *parser;
+ RestXmlNode *root;
+ GError *error;
+ const char test_1[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<rsp stat=\"ok\"><auth></auth></rsp>";
+ const char test_2[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<foobar/>";
+ const char test_3[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<rsp stat=\"fail\"><err code=\"108\" msg=\"Invalid frob\" /></rsp>";
+
+ parser = rest_xml_parser_new ();
+
+ root = rest_xml_parser_parse_from_data (parser, test_1, sizeof (test_1) - 1);
+ error = NULL;
+ flickr_proxy_is_successful (root, &error);
+ g_assert_no_error (error);
+ rest_xml_node_unref (root);
+
+ error = NULL;
+ root = rest_xml_parser_parse_from_data (parser, test_2, sizeof (test_2) - 1);
+ flickr_proxy_is_successful (root, &error);
+ g_assert_error (error, FLICKR_PROXY_ERROR, 0);
+ g_error_free (error);
+ rest_xml_node_unref (root);
+
+ error = NULL;
+ root = rest_xml_parser_parse_from_data (parser, test_3, sizeof (test_3) - 1);
+ flickr_proxy_is_successful (root, &error);
+ g_assert_error (error, FLICKR_PROXY_ERROR, 108);
+ g_error_free (error);
+ rest_xml_node_unref (root);
+}
+#endif
diff --git a/rest-extras/flickr-proxy.h b/rest-extras/flickr-proxy.h
new file mode 100644
index 0000000..736056c
--- /dev/null
+++ b/rest-extras/flickr-proxy.h
@@ -0,0 +1,94 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _FLICKR_PROXY
+#define _FLICKR_PROXY
+
+#include <rest/rest-proxy.h>
+#include <rest/rest-xml-parser.h>
+
+G_BEGIN_DECLS
+
+#define FLICKR_TYPE_PROXY flickr_proxy_get_type()
+
+#define FLICKR_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), FLICKR_TYPE_PROXY, FlickrProxy))
+
+#define FLICKR_PROXY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), FLICKR_TYPE_PROXY, FlickrProxyClass))
+
+#define FLICKR_IS_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FLICKR_TYPE_PROXY))
+
+#define FLICKR_IS_PROXY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), FLICKR_TYPE_PROXY))
+
+#define FLICKR_PROXY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), FLICKR_TYPE_PROXY, FlickrProxyClass))
+
+typedef struct _FlickrProxyPrivate FlickrProxyPrivate;
+
+/**
+ * FlickrProxy:
+ *
+ * #FlickrProxy has no publicly available members.
+ */
+typedef struct {
+ RestProxy parent;
+ FlickrProxyPrivate *priv;
+} FlickrProxy;
+
+typedef struct {
+ RestProxyClass parent_class;
+ /*< private >*/
+ /* padding for future expansion */
+ gpointer _padding_dummy[8];
+} FlickrProxyClass;
+
+#define FLICKR_PROXY_ERROR flickr_proxy_error_quark()
+
+GType flickr_proxy_get_type (void);
+
+RestProxy* flickr_proxy_new (const char *api_key,
+ const char *shared_secret);
+
+RestProxy* flickr_proxy_new_with_token (const char *api_key,
+ const char *shared_secret,
+ const char *token);
+
+const char * flickr_proxy_get_api_key (FlickrProxy *proxy);
+
+const char * flickr_proxy_get_shared_secret (FlickrProxy *proxy);
+
+const char * flickr_proxy_get_token (FlickrProxy *proxy);
+
+void flickr_proxy_set_token (FlickrProxy *proxy, const char *token);
+
+char * flickr_proxy_sign (FlickrProxy *proxy, GHashTable *params);
+
+char * flickr_proxy_build_login_url (FlickrProxy *proxy, const char *frob);
+
+gboolean flickr_proxy_is_successful (RestXmlNode *root, GError **error);
+
+G_END_DECLS
+
+#endif /* _FLICKR_PROXY */
diff --git a/rest-extras/test-runner.c b/rest-extras/test-runner.c
new file mode 100644
index 0000000..acf688a
--- /dev/null
+++ b/rest-extras/test-runner.c
@@ -0,0 +1,35 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (C) 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+#include <glib-object.h>
+
+#define test_add(unit_name, func) G_STMT_START { \
+ extern void func (void); \
+ g_test_add_func (unit_name, func); } G_STMT_END
+
+int
+main (int argc, char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ test_add ("/flickr/error", test_flickr_error);
+
+ return g_test_run ();
+}