1 /*
2  * Claws Mail -- A GTK+ based, lightweight, and fast e-mail client
3  * Copyright(C) 2019 the Claws Mail Team
4  *
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.
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write tothe Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  */
17 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 #include <string.h>
23 #include "http.h"
24 
25 #include "utils.h"
26 
27 struct Data {
28   GInputStream *memory;
29   size_t size;
30 };
31 
write_data(char * ptr,size_t size,size_t nmemb,void * data_ptr)32 static size_t write_data(char* ptr, size_t size, size_t nmemb, void* data_ptr) {
33     struct Data* data = (struct Data *) data_ptr;
34     size_t realsize = size * nmemb;
35 
36 		g_memory_input_stream_add_data((GMemoryInputStream *)data->memory,
37 				g_memdup(ptr, realsize), realsize,
38 				g_free);
39 		data->size += realsize;
40 
41     return realsize;
42 }
43 
http()44 http::http()
45 {
46     curl = curl_easy_init();
47     curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
48     curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_GET_TIMEOUT);
49     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
50     curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
51     curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
52     curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
53     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
54     stream = NULL;
55 }
56 
~http()57 http::~http()
58 {
59     curl_easy_cleanup(curl);
60     destroy_giostream();
61 }
62 
destroy_giostream()63 void http::destroy_giostream() {
64     debug_print("destroy_giostream called.\n");
65     if (stream) {
66 	debug_print("Freeing input_stream\n");
67 	g_input_stream_close(stream, NULL, NULL);
68 	g_object_unref(stream);
69     }
70 }
71 
load_url(const gchar * url,GError ** error)72 GInputStream *http::load_url(const gchar *url, GError **error)
73 {
74 	GError* _error = NULL;
75 	CURLcode res = CURLE_OK;
76 	gsize len;
77 	gchar* content;
78 
79 	if (!strncmp(url, "file:///", 8) || g_file_test(url, G_FILE_TEST_EXISTS)) {
80 		gchar* newurl = g_filename_from_uri(url, NULL, NULL);
81 		if (g_file_get_contents(newurl ? newurl : url, &content, &len, &_error)) {
82 			stream = g_memory_input_stream_new_from_data(content, len, g_free);
83 		} else {
84 			debug_print("Got error: %s\n", _error->message);
85 		}
86 		g_free(newurl);
87 	} else {
88 		struct Data data;
89 
90 		if (!curl) return NULL;
91 
92                 data.memory = g_memory_input_stream_new();
93                 data.size = 0;
94 
95 		curl_easy_setopt(curl, CURLOPT_URL, url);
96 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&data);
97 		res = curl_easy_perform(curl);
98 
99 		if (res != CURLE_OK) {
100 			_error = g_error_new_literal(G_FILE_ERROR, res, curl_easy_strerror(res));
101 			g_object_unref(data.memory);
102 		} else {
103 			debug_print("Image size: %d\n", data.size);
104 			stream = data.memory;
105 		}
106 	}
107 
108 	if (error && _error) *error = _error;
109 
110 	return stream;
111 }
112