From 91aee2a805d70c9f7a5f0d089139fbfc710939c1 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Thu, 25 Apr 2013 12:30:11 -0400 Subject: Add a gravatar module. This is a new EPhotoSource that obtains images from gravatar.com. --- modules/gravatar/Makefile.am | 30 +++ modules/gravatar/e-gravatar-photo-source.c | 281 +++++++++++++++++++++++ modules/gravatar/e-gravatar-photo-source.h | 68 ++++++ modules/gravatar/e-photo-cache-gravatar-loader.c | 88 +++++++ modules/gravatar/e-photo-cache-gravatar-loader.h | 66 ++++++ modules/gravatar/evolution-module-gravatar.c | 40 ++++ 6 files changed, 573 insertions(+) create mode 100644 modules/gravatar/Makefile.am create mode 100644 modules/gravatar/e-gravatar-photo-source.c create mode 100644 modules/gravatar/e-gravatar-photo-source.h create mode 100644 modules/gravatar/e-photo-cache-gravatar-loader.c create mode 100644 modules/gravatar/e-photo-cache-gravatar-loader.h create mode 100644 modules/gravatar/evolution-module-gravatar.c (limited to 'modules/gravatar') diff --git a/modules/gravatar/Makefile.am b/modules/gravatar/Makefile.am new file mode 100644 index 0000000000..47c9e6570b --- /dev/null +++ b/modules/gravatar/Makefile.am @@ -0,0 +1,30 @@ +module_LTLIBRARIES = module-gravatar.la + +module_gravatar_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -DG_LOG_DOMAIN=\"evolution-gravatar\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) \ + $(GTKHTML_CFLAGS) \ + $(NULL) + +module_gravatar_la_SOURCES = \ + evolution-module-gravatar.c \ + e-gravatar-photo-source.c \ + e-gravatar-photo-source.h \ + e-photo-cache-gravatar-loader.c \ + e-photo-cache-gravatar-loader.h \ + $(NULL) + +module_gravatar_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) \ + $(GTKHTML_LIBS) \ + $(NULL) + +module_gravatar_la_LDFLAGS = \ + -module -avoid-version $(NO_UNDEFINED) + +-include $(top_srcdir)/git.mk diff --git a/modules/gravatar/e-gravatar-photo-source.c b/modules/gravatar/e-gravatar-photo-source.c new file mode 100644 index 0000000000..eb6e653130 --- /dev/null +++ b/modules/gravatar/e-gravatar-photo-source.c @@ -0,0 +1,281 @@ +/* + * e-gravatar-photo-source.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#include "e-gravatar-photo-source.h" + +#include +#include +#include + +#define E_GRAVATAR_PHOTO_SOURCE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_GRAVATAR_PHOTO_SOURCE, EGravatarPhotoSourcePrivate)) + +#define AVATAR_BASE_URI "http://www.gravatar.com/avatar/" + +typedef struct _AsyncContext AsyncContext; + +struct _EGravatarPhotoSourcePrivate { + SoupSession *soup_session; +}; + +struct _AsyncContext { + gchar *email_address; + GInputStream *stream; +}; + +/* Forward Declarations */ +static void e_gravatar_photo_source_interface_init + (EPhotoSourceInterface *interface); + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EGravatarPhotoSource, + e_gravatar_photo_source, + G_TYPE_OBJECT, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_PHOTO_SOURCE, + e_gravatar_photo_source_interface_init)) + +static void +async_context_free (AsyncContext *async_context) +{ + g_free (async_context->email_address); + g_clear_object (&async_context->stream); + + g_slice_free (AsyncContext, async_context); +} + +static void +gravatar_photo_source_get_photo_thread (GSimpleAsyncResult *simple, + GObject *source_object, + GCancellable *cancellable) +{ + EGravatarPhotoSourcePrivate *priv; + AsyncContext *async_context; + SoupRequester *requester; + SoupRequest *request; + GInputStream *stream = NULL; + gchar *hash; + gchar *uri; + GError *local_error = NULL; + + priv = E_GRAVATAR_PHOTO_SOURCE_GET_PRIVATE (source_object); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + hash = e_gravatar_get_hash (async_context->email_address); + uri = g_strdup_printf ("%s%s?d=404", AVATAR_BASE_URI, hash); + + g_debug ("Requesting avatar for %s", async_context->email_address); + g_debug ("%s", uri); + + requester = (SoupRequester *) soup_session_get_feature ( + priv->soup_session, SOUP_TYPE_REQUESTER); + + /* We control the URI so there should be no error. */ + request = soup_requester_request (requester, uri, NULL); + g_return_if_fail (request != NULL); + + stream = soup_request_send (request, cancellable, &local_error); + + /* Sanity check. */ + g_return_if_fail ( + ((stream != NULL) && (local_error == NULL)) || + ((stream == NULL) && (local_error != NULL))); + + /* XXX soup_request_send() returns a stream on HTTP errors. + * We need to check the status code on the SoupMessage + * to make sure the we're not getting an error message. */ + if (stream != NULL) { + SoupMessage *message; + + message = soup_request_http_get_message ( + SOUP_REQUEST_HTTP (request)); + + if (SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) { + async_context->stream = g_object_ref (stream); + + } else if (message->status_code != SOUP_STATUS_NOT_FOUND) { + local_error = g_error_new_literal ( + SOUP_HTTP_ERROR, + message->status_code, + message->reason_phrase); + } + + g_object_unref (message); + g_object_unref (stream); + } + + if (local_error != NULL) { + const gchar *domain; + + domain = g_quark_to_string (local_error->domain); + g_debug ("Error: %s (%s)", local_error->message, domain); + g_simple_async_result_take_error (simple, local_error); + } + + g_debug ("Request complete"); + + g_clear_object (&request); + + g_free (hash); + g_free (uri); +} + +static void +gravatar_photo_source_dispose (GObject *object) +{ + EGravatarPhotoSourcePrivate *priv; + + priv = E_GRAVATAR_PHOTO_SOURCE_GET_PRIVATE (object); + + g_clear_object (&priv->soup_session); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_gravatar_photo_source_parent_class)-> + dispose (object); +} + +static void +gravatar_photo_source_get_photo (EPhotoSource *photo_source, + const gchar *email_address, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + async_context = g_slice_new0 (AsyncContext); + async_context->email_address = g_strdup (email_address); + + simple = g_simple_async_result_new ( + G_OBJECT (photo_source), callback, + user_data, gravatar_photo_source_get_photo); + + g_simple_async_result_set_check_cancellable (simple, cancellable); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, gravatar_photo_source_get_photo_thread, + G_PRIORITY_DEFAULT, cancellable); + + g_object_unref (simple); +} + +static gboolean +gravatar_photo_source_get_photo_finish (EPhotoSource *photo_source, + GAsyncResult *result, + GInputStream **out_stream, + gint *out_priority, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (photo_source), + gravatar_photo_source_get_photo), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + if (async_context->stream != NULL) { + *out_stream = g_object_ref (async_context->stream); + if (out_priority != NULL) + *out_priority = G_PRIORITY_DEFAULT; + } else { + *out_stream = NULL; + } + + return TRUE; +} + +static void +e_gravatar_photo_source_class_init (EGravatarPhotoSourceClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EGravatarPhotoSourcePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->dispose = gravatar_photo_source_dispose; +} + +static void +e_gravatar_photo_source_class_finalize (EGravatarPhotoSourceClass *class) +{ +} + +static void +e_gravatar_photo_source_interface_init (EPhotoSourceInterface *interface) +{ + interface->get_photo = gravatar_photo_source_get_photo; + interface->get_photo_finish = gravatar_photo_source_get_photo_finish; +} + +static void +e_gravatar_photo_source_init (EGravatarPhotoSource *photo_source) +{ + photo_source->priv = + E_GRAVATAR_PHOTO_SOURCE_GET_PRIVATE (photo_source); + + photo_source->priv->soup_session = soup_session_sync_new (); + + soup_session_add_feature_by_type ( + photo_source->priv->soup_session, + SOUP_TYPE_REQUESTER); +} + +void +e_gravatar_photo_source_type_register (GTypeModule *type_module) +{ + /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration + * function, so we have to wrap it with a public function in + * order to register types from a separate compilation unit. */ + e_gravatar_photo_source_register_type (type_module); +} + +EPhotoSource * +e_gravatar_photo_source_new (void) +{ + return g_object_new (E_TYPE_GRAVATAR_PHOTO_SOURCE, NULL); +} + +gchar * +e_gravatar_get_hash (const gchar *email_address) +{ + gchar *string; + gchar *hash; + + g_return_val_if_fail (email_address != NULL, NULL); + g_return_val_if_fail (g_utf8_validate (email_address, -1, NULL), NULL); + + string = g_strstrip (g_utf8_strdown (email_address, -1)); + hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, string, -1); + g_free (string); + + return hash; +} + diff --git a/modules/gravatar/e-gravatar-photo-source.h b/modules/gravatar/e-gravatar-photo-source.h new file mode 100644 index 0000000000..de409d9031 --- /dev/null +++ b/modules/gravatar/e-gravatar-photo-source.h @@ -0,0 +1,68 @@ +/* + * e-gravatar-photo-source.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#ifndef E_GRAVATAR_PHOTO_SOURCE_H +#define E_GRAVATAR_PHOTO_SOURCE_H + +#include + +/* Standard GObject macros */ +#define E_TYPE_GRAVATAR_PHOTO_SOURCE \ + (e_gravatar_photo_source_get_type ()) +#define E_GRAVATAR_PHOTO_SOURCE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_GRAVATAR_PHOTO_SOURCE, EGravatarPhotoSource)) +#define E_GRAVATAR_PHOTO_SOURCE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_GRAVATAR_PHOTO_SOURCE, EGravatarPhotoSourceClass)) +#define E_IS_GRAVATAR_PHOTO_SOURCE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_GRAVATAR_PHOTO_SOURCE)) +#define E_IS_GRAVATAR_PHOTO_SOURCE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_GRAVATAR_PHOTO_SOURCE)) +#define E_GRAVATAR_PHOTO_SOURCE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_GRAVATAR_PHOTO_SOURCE, EGravatarPhotoSourceClass)) + +G_BEGIN_DECLS + +typedef struct _EGravatarPhotoSource EGravatarPhotoSource; +typedef struct _EGravatarPhotoSourceClass EGravatarPhotoSourceClass; +typedef struct _EGravatarPhotoSourcePrivate EGravatarPhotoSourcePrivate; + +struct _EGravatarPhotoSource { + GObject parent; + EGravatarPhotoSourcePrivate *priv; +}; + +struct _EGravatarPhotoSourceClass { + GObjectClass parent_class; +}; + +GType e_gravatar_photo_source_get_type + (void) G_GNUC_CONST; +void e_gravatar_photo_source_type_register + (GTypeModule *type_module); +EPhotoSource * e_gravatar_photo_source_new (void); +gchar * e_gravatar_get_hash (const gchar *email_address); + +G_END_DECLS + +#endif /* E_GRAVATAR_PHOTO_SOURCE_H */ + diff --git a/modules/gravatar/e-photo-cache-gravatar-loader.c b/modules/gravatar/e-photo-cache-gravatar-loader.c new file mode 100644 index 0000000000..33dd39b471 --- /dev/null +++ b/modules/gravatar/e-photo-cache-gravatar-loader.c @@ -0,0 +1,88 @@ +/* + * e-photo-cache-gravatar-loader.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#include "e-photo-cache-gravatar-loader.h" + +#include "e-gravatar-photo-source.h" + +G_DEFINE_DYNAMIC_TYPE ( + EPhotoCacheGravatarLoader, + e_photo_cache_gravatar_loader, + E_TYPE_EXTENSION) + +static EPhotoCache * +photo_cache_gravatar_loader_get_photo_cache (EPhotoCacheGravatarLoader *loader) +{ + EExtensible *extensible; + + extensible = e_extension_get_extensible (E_EXTENSION (loader)); + + return E_PHOTO_CACHE (extensible); +} + +static void +photo_cache_gravatar_loader_constructed (GObject *object) +{ + EPhotoCacheGravatarLoader *loader; + EPhotoCache *photo_cache; + EPhotoSource *photo_source; + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_photo_cache_gravatar_loader_parent_class)-> + constructed (object); + + loader = E_PHOTO_CACHE_GRAVATAR_LOADER (object); + photo_cache = photo_cache_gravatar_loader_get_photo_cache (loader); + + photo_source = e_gravatar_photo_source_new (); + e_photo_cache_add_photo_source (photo_cache, photo_source); + g_object_unref (photo_source); +} + +static void +e_photo_cache_gravatar_loader_class_init (EPhotoCacheGravatarLoaderClass *class) +{ + GObjectClass *object_class; + EExtensionClass *extension_class; + + object_class = G_OBJECT_CLASS (class); + object_class->constructed = photo_cache_gravatar_loader_constructed; + + extension_class = E_EXTENSION_CLASS (class); + extension_class->extensible_type = E_TYPE_PHOTO_CACHE; +} + +static void +e_photo_cache_gravatar_loader_class_finalize (EPhotoCacheGravatarLoaderClass *class) +{ +} + +static void +e_photo_cache_gravatar_loader_init (EPhotoCacheGravatarLoader *loader) +{ +} + +void +e_photo_cache_gravatar_loader_type_register (GTypeModule *type_module) +{ + /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration + * function, so we have to wrap it with a public function in + * order to register types from a separate compilation unit. */ + e_photo_cache_gravatar_loader_register_type (type_module); +} + diff --git a/modules/gravatar/e-photo-cache-gravatar-loader.h b/modules/gravatar/e-photo-cache-gravatar-loader.h new file mode 100644 index 0000000000..13b0d1d0dd --- /dev/null +++ b/modules/gravatar/e-photo-cache-gravatar-loader.h @@ -0,0 +1,66 @@ +/* + * e-photo-cache-gravatar-loader.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#ifndef E_PHOTO_CACHE_GRAVATAR_LOADER_H +#define E_PHOTO_CACHE_GRAVATAR_LOADER_H + +#include + +/* Standard GObject macros */ +#define E_TYPE_PHOTO_CACHE_GRAVATAR_LOADER \ + (e_photo_cache_gravatar_loader_get_type ()) +#define E_PHOTO_CACHE_GRAVATAR_LOADER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_PHOTO_CACHE_GRAVATAR_LOADER, EPhotoCacheGravatarLoader)) +#define E_PHOTO_CACHE_GRAVATAR_LOADER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_PHOTO_CACHE_GRAVATAR_LOADER, EPhotoCacheGravatarLoaderClass)) +#define E_IS_PHOTO_CACHE_GRAVATAR_LOADER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_PHOTO_CACHE_GRAVATAR_LOADER)) +#define E_IS_PHOTO_CACHE_GRAVATAR_LOADER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_PHOTO_CACHE_GRAVATAR_LOADER)) +#define E_PHOTO_CACHE_GRAVATAR_LOADER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_PHOTO_CACHE_GRAVATAR_LOADER, EPhotoCacheGravatarLoaderClass)) + +G_BEGIN_DECLS + +typedef struct _EPhotoCacheGravatarLoader EPhotoCacheGravatarLoader; +typedef struct _EPhotoCacheGravatarLoaderClass EPhotoCacheGravatarLoaderClass; +typedef struct _EPhotoCacheGravatarLoaderPrivate EPhotoCacheGravatarLoaderPrivate; + +struct _EPhotoCacheGravatarLoader { + EExtension parent; + EPhotoCacheGravatarLoaderPrivate *priv; +}; + +struct _EPhotoCacheGravatarLoaderClass { + EExtensionClass parent_class; +}; + +GType e_photo_cache_gravatar_loader_get_type + (void) G_GNUC_CONST; +void e_photo_cache_gravatar_loader_type_register + (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_PHOTO_CACHE_GRAVATAR_LOADER_H */ + diff --git a/modules/gravatar/evolution-module-gravatar.c b/modules/gravatar/evolution-module-gravatar.c new file mode 100644 index 0000000000..0f452babfd --- /dev/null +++ b/modules/gravatar/evolution-module-gravatar.c @@ -0,0 +1,40 @@ +/* + * evolution-module-gravatar.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#include +#include + +#include "e-gravatar-photo-source.h" +#include "e-photo-cache-gravatar-loader.h" + +/* Module Entry Points */ +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + e_gravatar_photo_source_type_register (type_module); + e_photo_cache_gravatar_loader_type_register (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} + -- cgit v1.2.3