2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2016 Ricardo Mones and the Claws Mail Team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "claws-features.h"
25 #include <curl/curl.h>
28 #include <common/claws.h>
29 #include <prefs_common.h>
32 #include "libravatar.h"
33 #include "libravatar_prefs.h"
34 #include "libravatar_missing.h"
35 #include "libravatar_image.h"
37 static size_t write_image_data_cb(void *ptr, size_t size, size_t nmemb, void *stream)
39 size_t written = claws_fwrite(ptr, size, nmemb, (FILE *)stream);
40 debug_print("received %zu bytes from avatar server\n", written);
45 static GdkPixbuf *image_pixbuf_from_filename(const gchar *filename)
47 GdkPixbuf *picture = NULL;
51 gdk_pixbuf_get_file_info(filename, &w, &h);
53 if (w != AVATAR_SIZE || h != AVATAR_SIZE)
54 /* server can provide a different size from the requested in URL */
55 picture = gdk_pixbuf_new_from_file_at_scale(
56 filename, AVATAR_SIZE, AVATAR_SIZE, TRUE, &error);
58 picture = gdk_pixbuf_new_from_file(filename, &error);
61 g_warning("failed to load image '%s': %s", filename, error->message);
65 g_warning("failed to load image '%s': no error returned!", filename);
71 static GdkPixbuf *pixbuf_from_url(const gchar *url, const gchar *md5, const gchar *filename) {
72 GdkPixbuf *image = NULL;
77 file = claws_fopen(filename, "wb");
79 g_warning("could not open '%s' for writing", filename);
82 curl = curl_easy_init();
84 g_warning("could not initialize curl to get image from URL");
89 curl_easy_setopt(curl, CURLOPT_URL, url);
90 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_image_data_cb);
91 /* make sure timeout is less than general IO timeout */
92 curl_easy_setopt(curl, CURLOPT_TIMEOUT,
93 (libravatarprefs.timeout == 0
94 || libravatarprefs.timeout
95 > prefs_common_get_prefs()->io_timeout_secs)
96 ? prefs_common_get_prefs()->io_timeout_secs
97 : libravatarprefs.timeout);
98 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
100 if (libravatarprefs.allow_redirects) {
101 long maxredirs = (libravatarprefs.default_mode == DEF_MODE_URL)? 3L
102 : ((libravatarprefs.default_mode == DEF_MODE_MM)? 2L: 1L);
103 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
104 curl_easy_setopt(curl, CURLOPT_MAXREDIRS, maxredirs);
106 curl_easy_setopt(curl, CURLOPT_FILE, file);
107 debug_print("retrieving URL to file: %s -> %s\n", url, filename);
108 curl_easy_perform(curl);
109 filesize = ftell(file);
110 claws_safe_fclose(file);
111 if (filesize < MIN_PNG_SIZE)
112 debug_print("not enough data for an avatar image: %ld bytes\n", filesize);
114 image = image_pixbuf_from_filename(filename);
116 if (!libravatarprefs.cache_icons || filesize == 0) {
117 if (g_unlink(filename) < 0)
118 g_warning("failed to delete cache file '%s'", filename);
122 missing_add_md5(libravatarmisses, md5);
124 curl_easy_cleanup(curl);
129 static void *get_image_thread(void *arg) {
130 AvatarImageFetch *ctx = (AvatarImageFetch *)arg;
133 ctx->pixbuf = pixbuf_from_url(ctx->url, ctx->md5, ctx->filename);
140 GdkPixbuf *libravatar_image_fetch(AvatarImageFetch *ctx)
146 g_return_val_if_fail(ctx != NULL, NULL);
149 if (pthread_create(&pt, NULL, get_image_thread, (void *)ctx) != 0) {
150 debug_print("synchronous image fetching (couldn't create thread)\n");
151 get_image_thread(ctx);
153 debug_print("waiting for thread completion\n");
155 while (!ctx->ready ) {
159 pthread_join(pt, NULL);
160 debug_print("thread completed\n");
163 debug_print("synchronous image fetching (pthreads unavailable)\n");
164 get_image_thread(ctx);
166 if (ctx->pixbuf == NULL) {
167 g_warning("could not get image");