Code cleanup around glib version check (2.28 minimum).
[claws.git] / src / plugins / libravatar / libravatar.c
index abb2d9a5a74f30129865cc0c3e642e3b54cd867e..de5100aa7b0d6905c9b71c7ddea4e4b213299c7d 100644 (file)
@@ -1,7 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2014 Hiroyuki Yamamoto and the Claws Mail Team
- * Copyright (C) 2014 Ricardo Mones
+ * Copyright (C) 2014-2015 Ricardo Mones and the Claws Mail Team
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include "version.h"
 #include "libravatar.h"
 #include "libravatar_prefs.h"
+#include "libravatar_cache.h"
+#include "libravatar_image.h"
 #include "libravatar_missing.h"
+#include "libravatar_federation.h"
 #include "prefs_common.h"
 #include "procheader.h"
 #include "procmsg.h"
@@ -47,8 +49,8 @@ static const char *def_mode[] = {
        "retro"
 };
 
-static guint update_hook_id;
-static guint render_hook_id;
+static gulong update_hook_id = HOOK_NONE;
+static gulong render_hook_id = HOOK_NONE;
 static gchar *cache_dir = NULL; /* dir-separator terminated */
 
 static gboolean libravatar_header_update_hook(gpointer source, gpointer data)
@@ -69,6 +71,7 @@ static gboolean libravatar_header_update_hook(gpointer source, gpointer data)
 
                debug_print("libravatar added '%s'\n", a);
                procmsg_msginfo_add_avatar(acd->msginfo, AVATAR_LIBRAVATAR, a);
+               g_free(a);
        }
 
        return FALSE; /* keep getting */
@@ -76,16 +79,39 @@ static gboolean libravatar_header_update_hook(gpointer source, gpointer data)
 
 static gchar *federated_base_url_from_address(const gchar *address)
 {
-       /*
-          TODO: no federation supported right now
-          Details on http://wiki.libravatar.org/running_your_own/
-        */
+#if defined USE_GNUTLS
+       gchar *base_url = NULL;
+
+       if (!libravatarprefs.allow_federated) {
+               debug_print("federated domains disabled by configuration\n");
+               goto default_url;
+       }
+
+       base_url = federated_url_for_address(address);
+       if (base_url != NULL) {
+               return base_url;
+       }
+
+default_url:
+#endif
        return g_strdup(libravatarprefs.base_url);
 }
 
-static GtkWidget *image_widget_from_filename(const gchar *filename)
+static GtkWidget *image_widget_from_pixbuf(GdkPixbuf *picture)
 {
        GtkWidget *image = NULL;
+
+       if (picture) {
+               image = gtk_image_new_from_pixbuf(picture);
+               g_object_unref(picture);
+       } else
+               g_warning("null picture returns null widget");
+
+       return image;
+}
+
+static GtkWidget *image_widget_from_filename(const gchar *filename)
+{
        GdkPixbuf *picture = NULL;
        GError *error = NULL;
        gint w, h;
@@ -100,17 +126,12 @@ static GtkWidget *image_widget_from_filename(const gchar *filename)
                picture = gdk_pixbuf_new_from_file(filename, &error);
 
        if (error != NULL) {
-               g_warning("Failed to load image '%s': %s\n", filename, error->message);
+               g_warning("failed to load image '%s': %s", filename, error->message);
                g_error_free(error);
-       } else {
-               if (picture) {
-                       image = gtk_image_new_from_pixbuf(picture);
-                       g_object_unref(picture);
-               } else
-                       g_warning("Failed to load image '%s': no error returned!\n", filename);
+               return NULL;
        }
 
-       return image;
+       return image_widget_from_pixbuf(picture);
 }
 
 static gchar *cache_name_for_md5(const gchar *md5)
@@ -136,62 +157,24 @@ static size_t write_image_data_cb(void *ptr, size_t size, size_t nmemb, void *st
 static GtkWidget *image_widget_from_url(const gchar *url, const gchar *md5)
 {
        GtkWidget *image = NULL;
-       gchar *filename;
-       FILE *file;
-       CURL *curl;
-
-       curl = curl_easy_init();
-       if (curl == NULL) {
-               g_warning("could not initialize curl to get image from url\n");
-               return NULL;
-       }
-       curl_easy_setopt(curl, CURLOPT_URL, url);
-       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_image_data_cb);
-       curl_easy_setopt(curl, CURLOPT_TIMEOUT, prefs_common_get_prefs()->io_timeout_secs);
-       curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
-
-       filename = cache_name_for_md5(md5);
-       file = fopen(filename, "wb");
-       if (file != NULL) {
-               long filesize;
-
-               if (libravatarprefs.allow_redirects) {
-                       long maxredirs = (libravatarprefs.default_mode == DEF_MODE_URL)? 3L
-                               : ((libravatarprefs.default_mode == DEF_MODE_MM)? 2L: 1L);
-
-                       curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
-                       curl_easy_setopt(curl, CURLOPT_MAXREDIRS, maxredirs);
-               }
-               curl_easy_setopt(curl, CURLOPT_FILE, file);
-               debug_print("retrieving URL to file: %s -> %s\n", url, filename);
-               curl_easy_perform(curl);
-               filesize = ftell(file);
-               fclose(file);
-
-               if (filesize < MIN_PNG_SIZE)
-                       debug_print("not enough data for an avatar image: %ld bytes\n", filesize);
-               else
-                       image = image_widget_from_filename(filename);
-
-               if (!libravatarprefs.cache_icons || filesize == 0) {
-                       if (g_unlink(filename) < 0)
-                               g_warning("failed to delete cache file %s\n", filename);
-               }
-
-               if (filesize == 0)
-                       missing_add_md5(libravatarmisses, md5);
-       } else {
-               g_warning("could not open '%s' for writting\n", filename);
+       AvatarImageFetch aif;
+
+       aif.url = url;
+       aif.md5 = md5;
+       aif.filename = cache_name_for_md5(md5);
+       libravatar_image_fetch(&aif);
+       if (aif.pixbuf) {
+               image = gtk_image_new_from_pixbuf(aif.pixbuf);
+               g_object_unref(aif.pixbuf);
        }
-       curl_easy_cleanup(curl);
-       g_free(filename);
+       g_free(aif.filename);
 
        return image;
 }
 
 static gboolean is_recent_enough(const gchar *filename)
 {
-       struct stat s;
+       GStatBuf s;
        time_t t;
 
        if (libravatarprefs.cache_icons) {
@@ -235,7 +218,7 @@ static gchar *libravatar_url_for_md5(const gchar *base, const gchar *md5)
                                base, md5, AVATAR_SIZE);
        }
 
-       g_warning("invalid libravatar default mode: %d\n", libravatarprefs.default_mode);
+       g_warning("invalid libravatar default mode: %d", libravatarprefs.default_mode);
        return NULL;
 }
 
@@ -263,10 +246,11 @@ static gboolean libravatar_image_render_hook(gpointer source, gpointer data)
                        if (ar->image) /* previous plugin set one */
                                gtk_widget_destroy(ar->image);
                        ar->image = image;
+                       ar->type  = AVATAR_LIBRAVATAR;
                        return FALSE;
                }
                /* not cached copy: try network */
-               if (prefs_common.work_offline) {
+               if (prefs_common_get_prefs()->work_offline) {
                        debug_print("working off-line: libravatar network retrieval skipped\n");
                        return FALSE;
                }
@@ -279,6 +263,7 @@ static gboolean libravatar_image_render_hook(gpointer source, gpointer data)
                                if (ar->image) /* previous plugin set one */
                                        gtk_widget_destroy(ar->image);
                                ar->image = image;
+                               ar->type  = AVATAR_LIBRAVATAR;
                        }
                }
                g_free(base);
@@ -291,29 +276,8 @@ static gboolean libravatar_image_render_hook(gpointer source, gpointer data)
 
 static gint cache_dir_init()
 {
-       gchar *subdir;
-       int i;
-
-       cache_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
-                               LIBRAVATAR_CACHE_DIR, G_DIR_SEPARATOR_S,
-                               NULL);
-       if (!is_dir_exist(cache_dir)) {
-               if (make_dir(cache_dir) < 0) {
-                       g_free(cache_dir);
-                       return -1;
-               }
-       }
-       for (i = DEF_MODE_MM; i <= DEF_MODE_RETRO; ++i) {
-               subdir = g_strconcat(cache_dir, def_mode[i - 10], NULL);
-               if (!is_dir_exist(subdir)) {
-                       if (make_dir(subdir) < 0) {
-                               g_warning("cannot create directory %s\n", subdir);
-                               g_free(subdir);
-                               return -1;
-                       }
-               }
-               g_free(subdir);
-       }
+       cache_dir = libravatar_cache_init(def_mode, DEF_MODE_MM - 10, DEF_MODE_RETRO - 10);
+       cm_return_val_if_fail (cache_dir != NULL, -1);
 
        return 0;
 }
@@ -347,6 +311,20 @@ static void missing_cache_done()
        }
 }
 
+static void unregister_hooks()
+{
+       if (render_hook_id != HOOK_NONE) {
+               hooks_unregister_hook(AVATAR_IMAGE_RENDER_HOOKLIST,
+                                     render_hook_id);
+               render_hook_id = HOOK_NONE;
+       }
+       if (update_hook_id != HOOK_NONE) {
+               hooks_unregister_hook(AVATAR_HEADER_UPDATE_HOOKLIST,
+                                     update_hook_id);
+               update_hook_id = HOOK_NONE;
+       }
+}
+
 /**
  * Initialize plugin.
  *
@@ -363,7 +341,7 @@ gint plugin_init(gchar **error)
        update_hook_id = hooks_register_hook(AVATAR_HEADER_UPDATE_HOOKLIST,
                                             libravatar_header_update_hook,
                                             NULL);
-       if (update_hook_id == -1) {
+       if (update_hook_id == HOOK_NONE) {
                *error = g_strdup(_("Failed to register avatar header update hook"));
                return -1;
        }
@@ -371,12 +349,14 @@ gint plugin_init(gchar **error)
        render_hook_id = hooks_register_hook(AVATAR_IMAGE_RENDER_HOOKLIST,
                                             libravatar_image_render_hook,
                                             NULL);
-       if (render_hook_id == -1) {
+       if (render_hook_id == HOOK_NONE) {
+               unregister_hooks();
                *error = g_strdup(_("Failed to register avatar image render hook"));
                return -1;
        }
        /* cache dir */
        if (cache_dir_init() == -1) {
+               unregister_hooks();
                *error = g_strdup(_("Failed to create avatar image cache directory"));
                return -1;
        }
@@ -386,6 +366,7 @@ gint plugin_init(gchar **error)
        curl_global_init(CURL_GLOBAL_DEFAULT);
        /* missing cache */
        if (missing_cache_init() == -1) {
+               unregister_hooks();
                *error = g_strdup(_("Failed to load missing items cache"));
                return -1;
        }
@@ -402,16 +383,7 @@ gint plugin_init(gchar **error)
  */
 gboolean plugin_done(void)
 {
-       if (render_hook_id != -1) {
-               hooks_unregister_hook(AVATAR_IMAGE_RENDER_HOOKLIST,
-                                     render_hook_id);
-               render_hook_id = -1;
-       }
-       if (update_hook_id != -1) {
-               hooks_unregister_hook(AVATAR_HEADER_UPDATE_HOOKLIST,
-                                     update_hook_id);
-               update_hook_id = -1;
-       }
+       unregister_hooks();
        libravatar_prefs_done();
        missing_cache_done();
        if (cache_dir != NULL)
@@ -442,7 +414,7 @@ const gchar *plugin_desc(void)
                 "info about libravatar at http://www.libravatar.org/. If you have\n"
                 "a gravatar.com profile but not a libravatar one, those will also\n"
                 "be retrieved (when redirections are allowed in plugin config).\n"
-                "Plugin config page it's available from main window at:\n"
+                "Plugin config page is available from main window at:\n"
                 "/Configuration/Preferences/Plugins/Libravatar.\n\n"
                 "This plugin uses libcurl to retrieve images, so if you're behind a\n"
                 "proxy please refer to curl(1) manpage for details on 'http_proxy'\n"