[Commits] [SCM] claws branch, master, updated. 3.9.3-32-g7593136
mones at claws-mail.org
mones at claws-mail.org
Tue Mar 11 00:35:21 CET 2014
The branch master of project "claws" (Claws Mail) has been updated
via 7593136257a76ae5618fdcaeacd435475deee5e8 (commit)
from c8409a47933b566ff93f2805e91980efd7df1c7d (commit)
- Log -----------------------------------------------------------------
commit 7593136257a76ae5618fdcaeacd435475deee5e8
Author: Ricardo Mones <ricardo at mones.org>
Date: Tue Mar 11 00:33:43 2014 +0100
New libravatar plugin
diff --git a/configure.ac b/configure.ac
index 9bbd9ae..474971f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -964,6 +964,10 @@ AC_ARG_ENABLE(geolocation-plugin,
[ --disable-geolocation-plugin Do not build geolocation plugin],
[enable_geolocation_plugin=$enableval], [enable_geolocation_plugin=auto])
+AC_ARG_ENABLE(libravatar-plugin,
+ [ --disable-libravatar-plugin Do not build libravatar plugin],
+ [enable_libravatar_plugin=$enableval], [enable_libravatar_plugin=auto])
+
AC_ARG_ENABLE(mailmbox-plugin,
[ --disable-mailmbox-plugin Do not build mailmbox plugin],
[enable_mailmbox_plugin=$enableval], [enable_mailmbox_plugin=auto])
@@ -1470,6 +1474,31 @@ else
AC_MSG_RESULT(no)
fi
+AC_MSG_CHECKING([whether to build libravatar plugin])
+if test x"$enable_libravatar_plugin" != xno; then
+ dependencies_missing=""
+
+ if test x"$HAVE_CURL" = xno; then
+ dependencies_missing="libcurl $dependencies_missing"
+ fi
+
+ if test x"$dependencies_missing" = x; then
+ PLUGINS="$PLUGINS libravatar"
+ AC_MSG_RESULT(yes)
+ elif test x"$enable_libravatar_plugin" = xauto; then
+ AC_MSG_RESULT(no)
+ AC_MSG_WARN("Plugin libravatar will not be built; missing $dependencies_missing")
+ enable_rssyl_plugin=no
+ MISSING_DEPS_PLUGINS="$MISSING_DEPS_PLUGINS libravatar"
+ else
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR("Plugin libravatar cannot be built; missing $dependencies_missing")
+ fi
+else
+ DISABLED_PLUGINS="$DISABLED_PLUGINS libravatar"
+ AC_MSG_RESULT(no)
+fi
+
AC_MSG_CHECKING([whether to build mailmbox plugin])
if test x"$enable_mailmbox_plugin" != xno; then
PLUGINS="$PLUGINS mailmbox"
@@ -1830,6 +1859,7 @@ AM_CONDITIONAL(BUILD_FANCY_PLUGIN, test x"$enable_fancy_plugin" != xno)
AM_CONDITIONAL(BUILD_FETCHINFO_PLUGIN, test x"$enable_fetchinfo_plugin" != xno)
AM_CONDITIONAL(BUILD_GDATA_PLUGIN, test x"$enable_gdata_plugin" != xno)
AM_CONDITIONAL(BUILD_GEOLOCATION_PLUGIN, test x"$enable_geolocation_plugin" != xno)
+AM_CONDITIONAL(BUILD_LIBRAVATAR_PLUGIN, test x"$enable_libravatar_plugin" != xno)
AM_CONDITIONAL(BUILD_MAILMBOX_PLUGIN, test x"$enable_mailmbox_plugin" != xno)
AM_CONDITIONAL(BUILD_NEWMAIL_PLUGIN, test x"$enable_newmail_plugin" != xno)
AM_CONDITIONAL(BUILD_NOTIFICATION_PLUGIN, test x"$enable_notification_plugin" != xno)
@@ -1877,6 +1907,7 @@ src/plugins/fancy/Makefile
src/plugins/fetchinfo/Makefile
src/plugins/gdata/Makefile
src/plugins/geolocation/Makefile
+src/plugins/libravatar/Makefile
src/plugins/mailmbox/Makefile
src/plugins/newmail/Makefile
src/plugins/notification/Makefile
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index d440d96..2914aa5 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -12,6 +12,7 @@ SUBDIRS = \
fetchinfo \
gdata \
geolocation \
+ libravatar \
mailmbox \
newmail \
notification \
diff --git a/src/plugins/libravatar/Makefile.am b/src/plugins/libravatar/Makefile.am
new file mode 100644
index 0000000..e49d965
--- /dev/null
+++ b/src/plugins/libravatar/Makefile.am
@@ -0,0 +1,74 @@
+EXTRA_DIST = claws.def plugin.def version.rc
+
+if OS_WIN32
+
+LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RC) \
+ `echo $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) | \
+ sed -e 's/-I/--include-dir /g;s/-D/--define /g'`
+
+%.lo : %.rc
+ $(LTRCCOMPILE) -i $< -o $@
+
+plugin_res = version.lo
+plugin_res_ldflag = -Wl,.libs/version.o
+
+export_symbols = -export-symbols $(srcdir)/plugin.def
+
+plugin_deps = libclaws.a $(plugin_res) plugin.def
+
+libclaws.a: claws.def
+ $(DLLTOOL) --output-lib $@ --def $<
+
+plugin_ldadd = -L. -lclaws
+
+else
+plugin_res =
+plugin_res_ldflag =
+export_symbols =
+plugin_deps =
+plugin_ldadd =
+endif
+
+if PLATFORM_WIN32
+no_undefined = -no-undefined
+else
+no_undefined =
+endif
+
+if CYGWIN
+cygwin_export_lib = -L$(top_builddir)/src -lclaws-mail
+else
+cygwin_export_lib =
+endif
+
+plugindir = $(pkglibdir)/plugins
+
+if BUILD_LIBRAVATAR_PLUGIN
+plugin_LTLIBRARIES = libravatar.la
+endif
+
+libravatar_la_LDFLAGS = \
+ $(plugin_res_ldflag) $(no_undefined) $(export_symbols) \
+ -avoid-version -module \
+ $(GTK_LIBS)
+
+libravatar_la_DEPENDENCIES = $(plugin_deps)
+
+libravatar_la_LIBADD = $(plugin_ldadd) $(cygwin_export_lib) \
+ $(GTK_LIBS)
+
+INCLUDES = \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/common \
+ -I$(top_builddir)/src/common \
+ -I$(top_srcdir)/src/gtk
+
+AM_CPPFLAGS = \
+ $(GLIB_CFLAGS) \
+ $(GTK_CFLAGS)
+
+libravatar_la_SOURCES = \
+ libravatar.c libravatar.h \
+ libravatar_prefs.c libravatar_prefs.h \
+ libravatar_missing.c libravatar_missing.h
+
diff --git a/src/plugins/libravatar/README b/src/plugins/libravatar/README
new file mode 100644
index 0000000..fdd9e71
--- /dev/null
+++ b/src/plugins/libravatar/README
@@ -0,0 +1,39 @@
+Libravatar plugin for Claws Mail
+--------------------------------
+
+This plugin allows showing the profile picture associated to email
+addresses provided by https://www.libravatar.org/. You can read
+more about what is this at http://wiki.libravatar.org/description/.
+
+By default missing profiles in the libravatar site are also searched
+in http://gravatar.com, so it will also show pictures from gravatar
+profiles. This can be turned off by disallowing redirects.
+
+When profile is missing in both sites there's options to use a
+'generated' avatar instead. It's also possible to not generate
+anything. In that case no image will be added and the existing
+Face/X-Face machinery will operate as usual, allowing to show the
+avatar images provided by those headers when no profile picture
+exists in the servers.
+
+This plugin uses libcurl to download images, so proxy support is
+already implemented. You just need to set the âhttp_proxyâ variable
+in your environment before launching Claws Mail (see ENVIRONMENT
+section in curl(1) manpage for details).
+
+This plugin saves retrieved images for later reuse instead of making
+a network request on every message. Cache directory is in
+~/.claws-mail/avatarcache. Does also save the missing ones in a
+special file to avoid filling the cache with empty files. You can
+control how much time will be kept there before trying to download
+them again. Missing items are valid for more time, 7 times your
+configured interval cache time. You can disable the image cache,
+but notice that write access to avatarcache is still required.
+Missing cache cannot be disabled.
+
+The TODO file contains more known issues/enhancements, read it before
+reporting bugs.
+
+--
+Ricardo Mones <ricardo at mones.org>
+
diff --git a/src/plugins/libravatar/TODO b/src/plugins/libravatar/TODO
new file mode 100644
index 0000000..c21ff67
--- /dev/null
+++ b/src/plugins/libravatar/TODO
@@ -0,0 +1,27 @@
+Enhancements, possibilities and random ideas
+--------------------------------------------
+
+- Retrieve federated domain records (!)
+- Support federated IDN domains (??) (Claws Mail itself doesn't support it
+ http://www.thewildbeast.co.uk/claws-mail/bugzilla/show_bug.cgi?id=1670)
+- Domain validation when searching for federated avatars, or at least
+ exclude some domains (eg.: localhost) (???)
+- Check box to enable/disable domain validation (?)
+ http://data.iana.org/TLD/tlds-alpha-by-domain.txt may be useful.
+- Button for checking custom default URL is not 404 (!) check on apply (?)
+- Make it run in cache-less mode if cache dir cannot be created (??)
+- Only cache "mystery man" once for all hashes (what if changes) (?)
+- Cache information label (size on disk/# of avatars/missing cached) (?)
+- Empty avatar/missing cache button(s) (?)
+- Run network retrieval in a separate thread started at header capture
+ hook (??)
+- Alternate proxy support (send avatar requests through a proxy which
+ is not the one in http_proxy environment variable) (??)
+- Limit avatar download size (??) or time (???)
+- Configure missing factor/time separately (??)
+
+As these are already known, please do not request enhancement bugs for any
+of the above unless you have a working patch to be attached to the bug ;-)
+
+Discussion on ML is welcome, specially for items with one or more question
+marks.
diff --git a/src/plugins/libravatar/claws.def b/src/plugins/libravatar/claws.def
new file mode 100644
index 0000000..e7533f6
--- /dev/null
+++ b/src/plugins/libravatar/claws.def
@@ -0,0 +1,25 @@
+LIBRARY CLAWS-MAIL.EXE
+EXPORTS
+get_locale_dir
+check_plugin_version
+conv_codeset_strdup
+conv_get_locale_charset_str_no_utf8
+debug_print_real
+debug_srcname
+get_rc_dir
+hooks_register_hook
+hooks_unregister_hook
+line_has_quote_char
+pref_get_escaped_pref
+pref_get_unescaped_pref
+prefs_common
+prefs_file_close
+prefs_file_close_revert
+prefs_gtk_register_page
+prefs_gtk_unregister_page
+prefs_read_config
+prefs_set_block_label
+prefs_set_default
+prefs_write_open
+prefs_write_param
+prefs_common_get_prefs
diff --git a/src/plugins/libravatar/libravatar.c b/src/plugins/libravatar/libravatar.c
new file mode 100644
index 0000000..9f40a95
--- /dev/null
+++ b/src/plugins/libravatar/libravatar.c
@@ -0,0 +1,480 @@
+/*
+ * 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
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#include "claws-features.h"
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <curl/curl.h>
+
+#include "version.h"
+#include "libravatar.h"
+#include "libravatar_prefs.h"
+#include "libravatar_missing.h"
+#include "prefs_common.h"
+#include "procheader.h"
+#include "procmsg.h"
+#include "utils.h"
+#include "md5.h"
+
+/* indexes of keys are default_mode - 10 if applicable */
+static const char *def_mode[] = {
+ "404", /* not used, only useful in web pages */
+ "mm",
+ "identicon",
+ "monsterid",
+ "wavatar",
+ "retro"
+};
+
+static guint update_hook_id;
+static guint render_hook_id;
+static gchar *cache_dir = NULL; /* dir-separator terminated */
+static GHashTable *misses;
+
+static gboolean libravatar_header_update_hook(gpointer source, gpointer data)
+{
+ AvatarCaptureData *acd = (AvatarCaptureData *)source;
+
+ debug_print("libravatar avatar_header_update invoked\n");
+
+ if (!strcmp(acd->header, "From:")) {
+ gchar *a = g_strdup(acd->content);
+ extract_address(a);
+ debug_print("libravatar added '%s'\n", a);
+ procmsg_msginfo_add_avatar(acd->msginfo, AVATAR_LIBRAVATAR, a);
+ }
+
+ return FALSE; /* keep getting */
+}
+
+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/
+ */
+ return g_strdup(libravatarprefs.base_url);
+}
+
+static GtkWidget *image_widget_from_filename(const gchar *filename)
+{
+ GtkWidget *image = NULL;
+ GdkPixbuf *picture = NULL;
+ GError *error = NULL;
+ gint w, h;
+
+ gdk_pixbuf_get_file_info(filename, &w, &h);
+
+ if (w != AVATAR_SIZE || h != AVATAR_SIZE)
+ /* server can provide a different size from the requested in URL */
+ picture = gdk_pixbuf_new_from_file_at_scale(
+ filename, AVATAR_SIZE, AVATAR_SIZE, TRUE, &error);
+ else /* exact size */
+ picture = gdk_pixbuf_new_from_file(filename, &error);
+
+ if (error != NULL) {
+ g_warning("Failed to load image '%s': %s\n", 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 image;
+}
+
+static gchar *cache_name_for_md5(const gchar *md5)
+{
+ if (libravatarprefs.default_mode >= DEF_MODE_MM
+ && libravatarprefs.default_mode <= DEF_MODE_RETRO) {
+ /* cache dir for generated avatars */
+ return g_strconcat(cache_dir, def_mode[libravatarprefs.default_mode - 10],
+ G_DIR_SEPARATOR_S, md5, NULL);
+ }
+ /* default cache dir */
+ return g_strconcat(cache_dir, md5, NULL);
+}
+
+static size_t write_image_data_cb(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);
+ debug_print("received %zu bytes from avatar server\n", written);
+
+ return written;
+}
+
+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);
+
+ 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_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) {
+ if (g_unlink(filename) < 0)
+ g_warning("failed to delete cache file %s\n", filename);
+ }
+
+ if (filesize == 0)
+ missing_add_md5(misses, md5);
+ } else {
+ g_warning("could not open '%s' for writting\n", filename);
+ }
+ curl_easy_cleanup(curl);
+ g_free(filename);
+
+ return image;
+}
+
+static gboolean is_recent_enough(const gchar *filename)
+{
+ struct stat s;
+ time_t t;
+
+ if (libravatarprefs.cache_icons) {
+ t = time(NULL);
+ if (t != (time_t)-1 && !g_stat(filename, &s)) {
+ if (t - s.st_ctime <= libravatarprefs.cache_interval * 3600)
+ return TRUE;
+ }
+ }
+
+ return FALSE; /* re-download */
+}
+
+static GtkWidget *image_widget_from_cached_md5(const gchar *md5)
+{
+ GtkWidget *image = NULL;
+ gchar *filename;
+
+ filename = cache_name_for_md5(md5);
+ if (is_file_exist(filename) && is_recent_enough(filename)) {
+ debug_print("found cached image for %s\n", md5);
+ image = image_widget_from_filename(filename);
+ }
+ g_free(filename);
+
+ return image;
+}
+
+static gchar *libravatar_url_for_md5(const gchar *base, const gchar *md5)
+{
+ if (libravatarprefs.default_mode >= DEF_MODE_404) {
+ return g_strdup_printf("%s/%s?s=%u&d=%s",
+ base, md5, AVATAR_SIZE,
+ def_mode[libravatarprefs.default_mode - 10]);
+ } else if (libravatarprefs.default_mode == DEF_MODE_URL) {
+ return g_strdup_printf("%s/%s?s=%u&d=%s",
+ base, md5, AVATAR_SIZE,
+ libravatarprefs.default_mode_url);
+ } else if (libravatarprefs.default_mode == DEF_MODE_NONE) {
+ return g_strdup_printf("%s/%s?s=%u",
+ base, md5, AVATAR_SIZE);
+ }
+
+ g_warning("invalid libravatar default mode: %d\n", libravatarprefs.default_mode);
+ return NULL;
+}
+
+static gboolean libravatar_image_render_hook(gpointer source, gpointer data)
+{
+ AvatarRender *ar = (AvatarRender *)source;
+ GtkWidget *image = NULL;
+ gchar *a = NULL, *url = NULL;
+ gchar md5sum[33];
+
+ debug_print("libravatar avatar_image_render invoked\n");
+
+ a = procmsg_msginfo_get_avatar(ar->full_msginfo, AVATAR_LIBRAVATAR);
+ if (a != NULL) {
+ gchar *base;
+
+ md5_hex_digest(md5sum, a);
+ /* try missing cache */
+ if (is_missing_md5(misses, md5sum)) {
+ return FALSE;
+ }
+ /* try disk cache */
+ image = image_widget_from_cached_md5(md5sum);
+ if (image != NULL) {
+ if (ar->image) /* previous plugin set one */
+ gtk_widget_destroy(ar->image);
+ ar->image = image;
+ return FALSE;
+ }
+ /* not cached copy: try network */
+ if (prefs_common.work_offline) {
+ debug_print("working off-line: libravatar network retrieval skipped\n");
+ return FALSE;
+ }
+ base = federated_base_url_from_address(a);
+ url = libravatar_url_for_md5(base, md5sum);
+ if (url != NULL) {
+ image = image_widget_from_url(url, md5sum);
+ g_free(url);
+ if (image != NULL) {
+ if (ar->image) /* previous plugin set one */
+ gtk_widget_destroy(ar->image);
+ ar->image = image;
+ }
+ }
+ g_free(base);
+
+ return TRUE;
+ }
+
+ return FALSE; /* keep rendering */
+}
+
+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);
+ }
+
+ return 0;
+}
+
+static gint missing_cache_init()
+{
+ gchar *cache_file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+ LIBRAVATAR_CACHE_DIR, G_DIR_SEPARATOR_S,
+ LIBRAVATAR_MISSING_FILE, NULL);
+
+ misses = missing_load_from_file(cache_file);
+ g_free(cache_file);
+
+ if (misses == NULL)
+ return -1;
+
+ return 0;
+}
+
+static void missing_cache_done()
+{
+ gchar *cache_file;
+
+ if (misses != NULL) {
+ cache_file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+ LIBRAVATAR_CACHE_DIR, G_DIR_SEPARATOR_S,
+ LIBRAVATAR_MISSING_FILE, NULL);
+ missing_save_to_file(misses, cache_file);
+ g_free(cache_file);
+ g_hash_table_destroy(misses);
+ }
+}
+
+/**
+ * Initialize plugin.
+ *
+ * @param error For storing the returned error message.
+ *
+ * @return 0 if initialization succeeds, -1 on failure.
+ */
+gint plugin_init(gchar **error)
+{
+ if (!check_plugin_version(MAKE_NUMERIC_VERSION(3,9,3,29),
+ VERSION_NUMERIC, _("Libravatar"), error))
+ return -1;
+ /* get info from headers */
+ update_hook_id = hooks_register_hook(AVATAR_HEADER_UPDATE_HOOKLIST,
+ libravatar_header_update_hook,
+ NULL);
+ if (update_hook_id == -1) {
+ *error = g_strdup(_("Failed to register avatar header update hook"));
+ return -1;
+ }
+ /* get image for displaying */
+ render_hook_id = hooks_register_hook(AVATAR_IMAGE_RENDER_HOOKLIST,
+ libravatar_image_render_hook,
+ NULL);
+ if (render_hook_id == -1) {
+ *error = g_strdup(_("Failed to register avatar image render hook"));
+ return -1;
+ }
+ /* cache dir */
+ if (cache_dir_init() == -1) {
+ *error = g_strdup(_("Failed to create avatar image cache directory"));
+ return -1;
+ }
+ /* preferences page */
+ libravatar_prefs_init();
+ /* curl library */
+ curl_global_init(CURL_GLOBAL_DEFAULT);
+ /* missing cache */
+ if (missing_cache_init() == -1) {
+ *error = g_strdup(_("Failed to load missing items cache"));
+ return -1;
+ }
+ debug_print("Libravatar plugin loaded\n");
+
+ return 0;
+}
+
+/**
+ * Destructor for the plugin.
+ * Unregister the callback function and frees matcher.
+ *
+ * @return Always TRUE.
+ */
+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;
+ }
+ libravatar_prefs_done();
+ missing_cache_done();
+ if (cache_dir != NULL)
+ g_free(cache_dir);
+ debug_print("Libravatar plugin unloaded\n");
+
+ return TRUE;
+}
+
+/**
+ * Get the name of the plugin.
+ *
+ * @return The plugin's name, maybe translated.
+ */
+const gchar *plugin_name(void)
+{
+ return _("Libravatar");
+}
+
+/**
+ * Get the description of the plugin.
+ *
+ * @return The plugin's description, maybe translated.
+ */
+const gchar *plugin_desc(void)
+{
+ return _("Get and display libravatar images for mail messages.\n\n"
+ "Info about libravatar at http://www.libravatar.org/\n\n"
+ "Feedback to <ricardo at mones.org> is welcome.\n");
+}
+
+/**
+ * Get the kind of plugin.
+ *
+ * @return The "GTK2" constant.
+ */
+const gchar *plugin_type(void)
+{
+ return "GTK2";
+}
+
+/**
+ * Get the license acronym the plugin is released under.
+ *
+ * @return The "GPL3+" constant.
+ */
+const gchar *plugin_licence(void)
+{
+ return "GPL3+";
+}
+
+/**
+ * Get the version of the plugin.
+ *
+ * @return The current version string.
+ */
+const gchar *plugin_version(void)
+{
+ return VERSION;
+}
+
+/**
+ * Get the features implemented by the plugin.
+ *
+ * @return A constant PluginFeature structure with the features.
+ */
+struct PluginFeature *plugin_provides(void)
+{
+ static struct PluginFeature features[] =
+ { {PLUGIN_OTHER, N_("Libravatar")},
+ {PLUGIN_NOTHING, NULL}};
+
+ return features;
+}
+
diff --git a/src/plugins/libravatar/libravatar.h b/src/plugins/libravatar/libravatar.h
new file mode 100644
index 0000000..9bb3c2e
--- /dev/null
+++ b/src/plugins/libravatar/libravatar.h
@@ -0,0 +1,49 @@
+/*
+ * 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
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBRAVATAR_H
+#define __LIBRAVATAR_H
+
+#include <glib.h>
+
+#include "version.h"
+#include "claws.h"
+#include "plugin.h"
+#include "utils.h"
+#include "hooks.h"
+#include "avatars.h"
+
+#define AVATAR_LIBRAVATAR 3
+#define AVATAR_SIZE 48
+#define LIBRAVATAR_CACHE_DIR "avatarcache"
+/* https://github.com/mathiasbynens/small/pull/19 */
+#define MIN_PNG_SIZE 67L
+#define MAX_URL_LENGTH 1024
+
+gint plugin_init (gchar **error);
+gboolean plugin_done (void);
+const gchar * plugin_name (void);
+const gchar * plugin_desc (void);
+const gchar * plugin_type (void);
+const gchar * plugin_licence (void);
+const gchar * plugin_version (void);
+struct PluginFeature *plugin_provides (void);
+
+#endif
+
diff --git a/src/plugins/libravatar/libravatar_missing.c b/src/plugins/libravatar/libravatar_missing.c
new file mode 100644
index 0000000..6288dc7
--- /dev/null
+++ b/src/plugins/libravatar/libravatar_missing.c
@@ -0,0 +1,182 @@
+/*
+ * 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
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include "libravatar_missing.h"
+#include "libravatar_prefs.h"
+#include "utils.h"
+
+/**
+ * Loads the hash table of md5sum â time from the given filename.
+ *
+ * @param filename Name of the hash table filename.
+ *
+ * @return A hash table with the entries not expired contained in
+ * the given filename or NULL if failed to load.
+ */
+GHashTable *missing_load_from_file(const gchar *filename)
+{
+ FILE *file = fopen(filename, "r");
+ time_t t;
+ long long unsigned seen;
+ gchar md5sum[33];
+ GHashTable *table;
+ int r = 0, a = 0, d = 0;
+
+ if (file == NULL) {
+ if (!is_file_exist(filename)) { /* first run, return an empty table */
+ return g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ }
+ g_warning("Cannot open %s for reading\n", filename);
+ return NULL;
+ }
+ t = time(NULL);
+ if (t == (time_t)-1) {
+ g_warning("Cannot get time!\n");
+ return NULL;
+ }
+
+ table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+ while ((r = fscanf(file, "%s %llu\n", md5sum, &seen)) != EOF) {
+ if (t - (time_t)seen <= LIBRAVATAR_MISSING_TIME) {
+ time_t *value = g_malloc0(sizeof(time_t));
+ if (value == NULL) {
+ g_warning("Cannot allocate memory\n");
+ g_hash_table_destroy(table);
+ return NULL;
+ }
+ *value = (time_t)seen;
+ g_hash_table_insert(table, g_strdup(md5sum), value);
+ } else
+ d++;
+ a++;
+ }
+
+ if (fclose(file) != 0)
+ g_warning("Error closing %s\n", filename);
+
+ debug_print("Read %d missing avatar entries, %d obsolete entries discarded\n", a, d);
+ return table;
+}
+
+/**
+ * Saves a hash table item.
+ *
+ * @param key Hash table key, a md5sum string.
+ * @param vakue Hash table value, a time_t.
+ * @param data User data, a pointer to the open FILE being written.
+ */
+static void missing_save_item(gpointer key, gpointer value, gpointer data)
+{
+ FILE *file = (FILE *)data;
+ gchar *line = g_strdup_printf("%s %llu\n", (gchar *)key, *((long long unsigned *)value));
+ if (fputs(line, file) < 0)
+ g_warning("Error saving missing item\n");
+ g_free(line);
+}
+
+/**
+ * Saves a hash table of md5sum â time to a given file name.
+ *
+ * @param table The table to save.
+ * @param filename The name of the file where table data will be saved.
+ *
+ * @return 0 on success, -1 if there was some problem saving.
+ */
+gint missing_save_to_file(GHashTable *table, const gchar *filename)
+{
+ FILE *file = fopen(filename, "w");
+
+ if (file == NULL) {
+ g_warning("Cannot open %s for writting\n", filename);
+ return -1;
+ }
+
+ g_hash_table_foreach(table, missing_save_item, (gpointer)file);
+ debug_print("Saved %u missing avatar entries\n", g_hash_table_size(table));
+
+ if (fclose(file) != 0) {
+ g_warning("Error closing %s\n", filename);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Adds a md5sum to a md5sum â time hash table.
+ * If the md5sum is already in the table its time is updated.
+ *
+ * @param table The table to use.
+ * @param md5 The md5sum to add or update.
+ */
+void missing_add_md5(GHashTable *table, const gchar *md5)
+{
+ time_t t = time(NULL);
+
+ if (t == (time_t)-1) {
+ g_warning("Cannot get time!\n");
+ return;
+ }
+
+ time_t *seen = g_hash_table_lookup(table, md5);
+ if (seen == NULL) {
+ seen = g_malloc0(sizeof(time_t));
+ if (seen == NULL) {
+ g_warning("Cannot allocate memory\n");
+ return;
+ }
+ *seen = t;
+ g_hash_table_insert(table, g_strdup(md5), seen);
+ debug_print("New md5 %s added with time %llu\n", md5, (long long unsigned)t);
+ } else {
+ *seen = t; /* just update */
+ debug_print("Updated md5 %s with time %llu\n", md5, (long long unsigned)t);
+ }
+}
+
+/**
+ * Check if a md5sum is in hash table and not expired.
+ *
+ * @param table The table to check against.
+ * @param md5 The md5sum to check.
+ *
+ * @return TRUE if the md5sum is in the table and is not expired,
+ FALSE otherwise.
+ */
+gboolean is_missing_md5(GHashTable *table, const gchar *md5)
+{
+ time_t t;
+ time_t *seen = (time_t *)g_hash_table_lookup(table, md5);
+
+ if (seen == NULL)
+ return FALSE;
+
+ t = time(NULL);
+ if (t != (time_t)-1) {
+ if (t - *seen <= LIBRAVATAR_MISSING_TIME) {
+ debug_print("Found missing md5 %s\n", md5);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
diff --git a/src/plugins/libravatar/libravatar_missing.h b/src/plugins/libravatar/libravatar_missing.h
new file mode 100644
index 0000000..191159b
--- /dev/null
+++ b/src/plugins/libravatar/libravatar_missing.h
@@ -0,0 +1,37 @@
+/*
+ * 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
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBRAVATAR_MISSING_H
+#define __LIBRAVATAR_MISSING_H
+
+#include <glib.h>
+
+#define LIBRAVATAR_MISSING_FILE "missing"
+/* multiply cache interval time pref for missing items */
+#define LIBRAVATAR_MISSING_TIME (libravatarprefs.cache_interval * 3600 * 7)
+
+GHashTable *missing_load_from_file (const gchar *filename);
+gint missing_save_to_file (GHashTable *table,
+ const gchar *filename);
+void missing_add_md5 (GHashTable *table,
+ const gchar *md5);
+gboolean is_missing_md5 (GHashTable *table,
+ const gchar *md5);
+
+#endif
diff --git a/src/plugins/libravatar/libravatar_prefs.c b/src/plugins/libravatar/libravatar_prefs.c
new file mode 100644
index 0000000..c14948d
--- /dev/null
+++ b/src/plugins/libravatar/libravatar_prefs.c
@@ -0,0 +1,382 @@
+/*
+ * 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
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#include "claws-features.h"
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "libravatar.h"
+
+#include <gtk/gtk.h>
+#include <gtk/filesel.h>
+
+#include "defs.h"
+#include "libravatar_prefs.h"
+#include "prefs_common.h"
+#include "prefs_gtk.h"
+
+#define PREFS_BLOCK_NAME "Libravatar"
+#define NUM_DEF_BUTTONS 7
+/* cache interval goes from 1 hour to 30 days */
+#define INTERVAL_MIN_H 1.0
+#define INTERVAL_MAX_H 720.0
+
+LibravatarPrefs libravatarprefs;
+
+struct LibravatarPrefsPage
+{
+ PrefsPage page;
+
+ GtkWidget *cache_interval_spin;
+ GtkWidget *cache_icons_check;
+ GtkWidget *defm_radio[NUM_DEF_BUTTONS];
+ GtkWidget *defm_url_text;
+ GtkWidget *allow_redirects_check;
+};
+
+struct LibravatarPrefsPage libravatarprefs_page;
+
+static PrefParam param[] = {
+ { "base_url", "http://cdn.libravatar.org/avatar",
+ &libravatarprefs.base_url,
+ P_STRING, NULL, NULL, NULL },
+ { "cache_interval", "24",
+ &libravatarprefs.cache_interval,
+ P_INT, NULL, NULL, NULL },
+ { "cache_icons", "TRUE",
+ &libravatarprefs.cache_icons,
+ P_BOOL, NULL, NULL, NULL },
+ { "default_mode", "0",
+ &libravatarprefs.default_mode,
+ P_INT, NULL, NULL, NULL },
+ { "default_mode_url", "",
+ &libravatarprefs.default_mode_url,
+ P_STRING, NULL, NULL, NULL },
+ { "allow_redirects", "TRUE",
+ &libravatarprefs.allow_redirects,
+ P_BOOL, NULL, NULL, NULL },
+ {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
+};
+
+static GtkWidget *create_checkbox(gchar *label, gchar *hint)
+{
+ GtkWidget *cb = gtk_check_button_new_with_mnemonic(label);
+ CLAWS_SET_TIP(cb, hint);
+ gtk_widget_show(cb);
+
+ return cb;
+}
+
+static void cache_icons_check_toggled_cb(GtkToggleButton *button, gpointer data)
+{
+ gtk_widget_set_sensitive(libravatarprefs_page.cache_interval_spin,
+ gtk_toggle_button_get_active(button));
+}
+
+static GtkWidget *p_create_frame_cache(struct LibravatarPrefsPage *page)
+{
+ GtkWidget *vbox, *checkbox, *lbl, *lbla, *spinner, *hbox;
+ GtkAdjustment *adj;
+
+ vbox = gtk_vbox_new(FALSE, 6);
+
+ checkbox = create_checkbox(_("_Use cached icons"),
+ _("Keep icons on disk for reusing instead "
+ "of making another network request"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox),
+ libravatarprefs.cache_icons);
+ g_signal_connect(checkbox, "toggled",
+ G_CALLBACK(cache_icons_check_toggled_cb), NULL);
+ page->cache_icons_check = checkbox;
+
+ lbl = gtk_label_new(_("Cache refresh interval"));
+ gtk_widget_show(lbl);
+ lbla = gtk_label_new(_("hours"));
+ gtk_widget_show(lbla);
+ adj = (GtkAdjustment *) gtk_adjustment_new(
+ libravatarprefs.cache_interval,
+ INTERVAL_MIN_H, INTERVAL_MAX_H, 1.0,
+ 0.0, 0.0);
+ spinner = gtk_spin_button_new(adj, 1.0, 0);
+ gtk_widget_show(spinner);
+ gtk_widget_set_sensitive(spinner, libravatarprefs.cache_icons);
+ hbox = gtk_hbox_new(FALSE, 6);
+ gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), lbla, FALSE, FALSE, 0);
+ page->cache_interval_spin = spinner;
+
+ gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+ return vbox;
+}
+
+static void default_mode_radio_button_cb(GtkToggleButton *button, gpointer data)
+{
+ gboolean is_url;
+
+ if (gtk_toggle_button_get_active(button) == TRUE) {
+ is_url = (*((guint *)data) == DEF_MODE_URL)? TRUE: FALSE;
+ gtk_widget_set_sensitive(libravatarprefs_page.defm_url_text, is_url);
+ if (is_url) /* custom URL requires following redirects */
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(libravatarprefs_page.allow_redirects_check),
+ TRUE);
+ /* don't waste time with headers that won't be displayed */
+ prefs_common.enable_avatars = (*((guint *)data) == DEF_MODE_NONE)
+ ? AVATARS_ENABLE_BOTH: AVATARS_DISABLE;
+ }
+}
+
+static const guint radio_value[] = {
+ DEF_MODE_NONE,
+ DEF_MODE_MM,
+ DEF_MODE_IDENTICON,
+ DEF_MODE_MONSTERID,
+ DEF_MODE_WAVATAR,
+ DEF_MODE_RETRO,
+ DEF_MODE_URL
+};
+
+static GtkWidget *p_create_frame_missing(struct LibravatarPrefsPage *page)
+{
+ GtkWidget *vbox, *radio[NUM_DEF_BUTTONS], *hbox, *label, *entry;
+ gboolean enable = FALSE;
+ int i;
+ gchar *radio_label[] = {
+ _("None"),
+ _("Mystery man"),
+ _("Identicon"),
+ _("MonsterID"),
+ _("Wavatar"),
+ _("Retro"),
+ _("Custom URL")
+ };
+ gchar *radio_hint[] = {
+ _("A blank image"),
+ _("The unobtrusive low-contrast greyish silhouette"),
+ _("A generated geometric pattern"),
+ _("A generated full-body monster"),
+ _("A generated almost unique face"),
+ _("A generated 8-bit arcade-style pixelated image"),
+ _("Redirect to a user provided URL")
+ };
+
+ vbox = gtk_vbox_new(FALSE, 6);
+
+ for (i = 0; i < NUM_DEF_BUTTONS; ++i) {
+ enable = (!enable && libravatarprefs.default_mode == radio_value[i])? TRUE: FALSE;
+ radio[i] = gtk_radio_button_new_with_label_from_widget(
+ (i > 0)? GTK_RADIO_BUTTON(radio[i - 1]): NULL, radio_label[i]);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[i]), enable);
+ gtk_box_pack_start(GTK_BOX(vbox), radio[i], FALSE, FALSE, 0);
+ g_signal_connect(radio[i], "toggled",
+ G_CALLBACK(default_mode_radio_button_cb),
+ (gpointer) &(radio_value[i]));
+ CLAWS_SET_TIP(radio[i], radio_hint[i]);
+ gtk_widget_show(radio[i]);
+ page->defm_radio[i] = radio[i];
+ }
+ if (!enable) { /* unknown value, go default */
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[0]), TRUE);
+ libravatarprefs.default_mode = DEF_MODE_NONE;
+ }
+ /* don't waste time with headers that won't be displayed */
+ prefs_common.enable_avatars = (libravatarprefs.default_mode == DEF_MODE_NONE)
+ ? AVATARS_ENABLE_BOTH: AVATARS_DISABLE;
+
+ label = gtk_label_new(_("URL:"));
+ gtk_widget_show(label);
+ entry = gtk_entry_new_with_max_length(MAX_URL_LENGTH);
+ gtk_widget_show(entry);
+ gtk_entry_set_text(GTK_ENTRY(entry), libravatarprefs.default_mode_url);
+
+ hbox = gtk_hbox_new(FALSE, 6);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
+ gtk_widget_set_sensitive(entry,
+ (libravatarprefs.default_mode == DEF_MODE_URL)? TRUE: FALSE);
+ page->defm_url_text = entry;
+
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+ return vbox;
+}
+
+static GtkWidget *p_create_frame_network(struct LibravatarPrefsPage *page)
+{
+ GtkWidget *vbox, *checkbox;
+
+ vbox = gtk_vbox_new(FALSE, 6);
+
+ checkbox = create_checkbox(_("_Allow redirects to other sites"),
+ _("Follow redirect responses received from "
+ "libravatar server to other avatar "
+ "services like gravatar.com"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox),
+ libravatarprefs.allow_redirects);
+ page->allow_redirects_check = checkbox;
+
+ gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0);
+
+ return vbox;
+}
+
+/*
+ ââIcon cacheââââââââââââââââââââââââââââââââââââââââââââ
+ â [â] Use cached icons â
+ â Cache refresh interval [ 24 |â¬] hours â
+ ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ ââDefault missing icon modeâââââââââââââââââââââââââââââ
+ â (â¢) None â
+ â ( ) Mystery man â
+ â ( ) Identicon â
+ â ( ) MonsterID â
+ â ( ) Wavatar â
+ â ( ) Retro â
+ â ( ) Custom URL â
+ â URL: [_________________________________________] â
+ ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ ââNetworkâââââââââââââââââââââââââââââââââââââââââââââââ
+ â [â] Allow redirects â
+ ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
+ */
+static void libravatar_prefs_create_widget_func(PrefsPage * _page,
+ GtkWindow * window,
+ gpointer data)
+{
+ struct LibravatarPrefsPage *page = (struct LibravatarPrefsPage *) _page;
+ GtkWidget *vbox, *vbox1, *vbox2, *vbox3, *frame;
+
+ vbox1 = p_create_frame_cache(page);
+ vbox2 = p_create_frame_missing(page);
+ vbox3 = p_create_frame_network(page);
+
+ vbox = gtk_vbox_new(FALSE, 6);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), VBOX_BORDER);
+
+ PACK_FRAME (vbox, frame, _("Icon cache"));
+ gtk_container_set_border_width(GTK_CONTAINER(vbox1), 6);
+ gtk_container_add(GTK_CONTAINER(frame), vbox1);
+
+ PACK_FRAME (vbox, frame, _("Default missing icon mode"));
+ gtk_container_set_border_width(GTK_CONTAINER(vbox2), 6);
+ gtk_container_add(GTK_CONTAINER(frame), vbox2);
+
+ PACK_FRAME (vbox, frame, _("Network"));
+ gtk_container_set_border_width(GTK_CONTAINER(vbox3), 6);
+ gtk_container_add(GTK_CONTAINER(frame), vbox3);
+
+ gtk_widget_show_all(vbox);
+ page->page.widget = vbox;
+}
+
+static void libravatar_prefs_destroy_widget_func(PrefsPage *_page)
+{
+ /* nothing */
+}
+
+static void libravatar_save_config(void)
+{
+ PrefFile *pfile;
+ gchar *rcpath;
+
+ debug_print("Saving Libravatar Page\n");
+
+ rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
+ pfile = prefs_write_open(rcpath);
+ g_free(rcpath);
+ if (!pfile || (prefs_set_block_label(pfile, PREFS_BLOCK_NAME) < 0))
+ return;
+
+ if (prefs_write_param(param, pfile->fp) < 0) {
+ g_warning("Failed to write Libravatar configuration to file\n");
+ prefs_file_close_revert(pfile);
+ return;
+ }
+ if (fprintf(pfile->fp, "\n") < 0) {
+ FILE_OP_ERROR(rcpath, "fprintf");
+ prefs_file_close_revert(pfile);
+ } else
+ prefs_file_close(pfile);
+}
+
+static void libravatar_prefs_save_func(PrefsPage * _page)
+{
+ struct LibravatarPrefsPage *page = (struct LibravatarPrefsPage *) _page;
+ int i;
+
+ /* cache */
+ libravatarprefs.cache_icons = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(page->cache_icons_check));
+ /* cache interval */
+ libravatarprefs.cache_interval = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(page->cache_interval_spin));
+ /* default mode */
+ for (i = 0; i < NUM_DEF_BUTTONS; ++i) {
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->defm_radio[i]))) {
+ libravatarprefs.default_mode = radio_value[i];
+ break;
+ }
+ }
+ /* custom url */
+ if (libravatarprefs.default_mode_url != NULL) {
+ g_free(libravatarprefs.default_mode_url);
+ }
+ libravatarprefs.default_mode_url = gtk_editable_get_chars(
+ GTK_EDITABLE(page->defm_url_text), 0, -1);
+ /* redirects */
+ libravatarprefs.allow_redirects = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(page->allow_redirects_check));
+
+ libravatar_save_config();
+}
+
+void libravatar_prefs_init(void)
+{
+ static gchar *path[3];
+ gchar *rcpath;
+
+ path[0] = _("Plugins");
+ path[1] = _("Libravatar");
+ path[2] = NULL;
+
+ prefs_set_default(param);
+ rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
+ prefs_read_config(param, PREFS_BLOCK_NAME, rcpath, NULL);
+ g_free(rcpath);
+
+ libravatarprefs_page.page.path = path;
+ libravatarprefs_page.page.create_widget = libravatar_prefs_create_widget_func;
+ libravatarprefs_page.page.destroy_widget = libravatar_prefs_destroy_widget_func;
+ libravatarprefs_page.page.save_page = libravatar_prefs_save_func;
+
+ prefs_gtk_register_page((PrefsPage *) &libravatarprefs_page);
+}
+
+void libravatar_prefs_done(void)
+{
+ prefs_gtk_unregister_page((PrefsPage *) &libravatarprefs_page);
+}
+
diff --git a/src/plugins/libravatar/libravatar_prefs.h b/src/plugins/libravatar/libravatar_prefs.h
new file mode 100644
index 0000000..fe8ed6a
--- /dev/null
+++ b/src/plugins/libravatar/libravatar_prefs.h
@@ -0,0 +1,56 @@
+/*
+ * 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
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBRAVATAR_PREFS_H
+#define __LIBRAVATAR_PREFS_H
+
+#include <glib.h>
+
+typedef struct _LibravatarPrefs LibravatarPrefs;
+
+/* http://wiki.libravatar.org/api/ */
+enum
+{
+ DEF_MODE_NONE = 0,
+ DEF_MODE_URL = 1,
+ DEF_MODE_404 = 10, /* not used, only useful in web pages */
+ DEF_MODE_MM = 11,
+ DEF_MODE_IDENTICON = 12,
+ DEF_MODE_MONSTERID = 13,
+ DEF_MODE_WAVATAR = 14,
+ DEF_MODE_RETRO = 15,
+};
+
+struct _LibravatarPrefs
+{
+ gchar *base_url; /* hidden pref */
+ guint cache_interval;
+ gboolean cache_icons;
+ guint default_mode;
+ gchar *default_mode_url;
+ gboolean allow_redirects;
+};
+
+extern LibravatarPrefs libravatarprefs;
+
+void libravatar_prefs_init(void);
+void libravatar_prefs_done(void);
+
+#endif
+
diff --git a/src/plugins/libravatar/plugin.def b/src/plugins/libravatar/plugin.def
new file mode 100644
index 0000000..8471df1
--- /dev/null
+++ b/src/plugins/libravatar/plugin.def
@@ -0,0 +1,10 @@
+EXPORTS
+ plugin_desc
+ plugin_done
+ plugin_init
+ plugin_licence
+ plugin_name
+ plugin_type
+ plugin_provides
+ plugin_version
+
diff --git a/src/plugins/libravatar/version.rc b/src/plugins/libravatar/version.rc
new file mode 100644
index 0000000..5d93a3d
--- /dev/null
+++ b/src/plugins/libravatar/version.rc
@@ -0,0 +1,36 @@
+1 VERSIONINFO
+ FILEVERSION 0, 0, 0, 0
+ PRODUCTVERSION 0, 0, 0, 0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "FileDescription", "Claws Mail Libravatar Plugin\0"
+ VALUE "FileVersion", "0.0.0.0\0"
+ VALUE "ProductVersion", "0.0.0.0 Win32\0"
+ VALUE "LegalCopyright", "GPL / © 1999-2014 Hiroyuki Yamamoto & The Claws Mail Team\0"
+ VALUE "CompanyName", "GNU / Free Software Foundation\0"
+ VALUE "ProductName", "Claws Mail\0"
+// VALUE "Comments", "\0"
+// VALUE "InternalName", "\0"
+// VALUE "LegalTrademarks", "\0"
+// VALUE "OriginalFilename", "\0"
+// VALUE "PrivateBuild", "\0"
+// VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
-----------------------------------------------------------------------
Summary of changes:
configure.ac | 31 ++
src/plugins/Makefile.am | 1 +
.../{address_keeper => libravatar}/Makefile.am | 19 +-
src/plugins/libravatar/README | 39 ++
src/plugins/libravatar/TODO | 27 ++
src/plugins/{mailmbox => libravatar}/claws.def | 7 +-
src/plugins/libravatar/libravatar.c | 480 ++++++++++++++++++++
.../address_keeper.h => libravatar/libravatar.h} | 25 +-
src/plugins/libravatar/libravatar_missing.c | 182 ++++++++
src/plugins/libravatar/libravatar_missing.h | 37 ++
src/plugins/libravatar/libravatar_prefs.c | 382 ++++++++++++++++
src/plugins/libravatar/libravatar_prefs.h | 56 +++
src/plugins/libravatar/plugin.def | 10 +
src/plugins/{att_remover => libravatar}/version.rc | 4 +-
14 files changed, 1272 insertions(+), 28 deletions(-)
copy src/plugins/{address_keeper => libravatar}/Makefile.am (75%)
create mode 100644 src/plugins/libravatar/README
create mode 100644 src/plugins/libravatar/TODO
copy src/plugins/{mailmbox => libravatar}/claws.def (84%)
create mode 100644 src/plugins/libravatar/libravatar.c
copy src/plugins/{address_keeper/address_keeper.h => libravatar/libravatar.h} (63%)
create mode 100644 src/plugins/libravatar/libravatar_missing.c
create mode 100644 src/plugins/libravatar/libravatar_missing.h
create mode 100644 src/plugins/libravatar/libravatar_prefs.c
create mode 100644 src/plugins/libravatar/libravatar_prefs.h
create mode 100644 src/plugins/libravatar/plugin.def
copy src/plugins/{att_remover => libravatar}/version.rc (87%)
hooks/post-receive
--
Claws Mail
More information about the Commits
mailing list