webperimental: killstack decides stack protects.
[freeciv.git] / utility / netfile.c
blob6c71641abd1a8b4e430e7b77627897748198c9f9
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <curl/curl.h>
20 #ifdef FREECIV_MSWINDOWS
21 #include <windows.h>
22 #endif
24 /* utility */
25 #include "fcintl.h"
26 #include "ioz.h"
27 #include "mem.h"
28 #include "rand.h"
29 #include "registry.h"
31 #include "netfile.h"
33 struct netfile_post {
34 struct curl_httppost *first;
35 struct curl_httppost *last;
38 typedef size_t (*netfile_write_cb)(char *ptr, size_t size, size_t nmemb, void *userdata);
40 static char error_buf_curl[CURL_ERROR_SIZE];
42 /**********************************************************************
43 Set handle to usable state.
44 ***********************************************************************/
45 static CURL *netfile_init_handle(void)
47 /* Consecutive transfers can use same handle for better performance */
48 static CURL *handle = NULL;
50 if (handle == NULL) {
51 handle = curl_easy_init();
52 } else {
53 curl_easy_reset(handle);
56 error_buf_curl[0] = '\0';
57 curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, error_buf_curl);
59 return handle;
62 /**********************************************************************
63 curl write callback to store received file to memory.
64 ***********************************************************************/
65 static size_t netfile_memwrite_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
67 struct netfile_write_cb_data *data = (struct netfile_write_cb_data *)userdata;
69 if (size > 0) {
70 data->mem = fc_realloc(data->mem, data->size + size * nmemb);
71 memcpy(data->mem + data->size, ptr, size * nmemb);
72 data->size += size * nmemb;
75 return size * nmemb;
78 /**********************************************************************
79 Fetch file from given URL to given file stream. This is core
80 function of netfile module.
81 ***********************************************************************/
82 static bool netfile_download_file_core(const char *URL, FILE *fp,
83 struct netfile_write_cb_data *mem_data,
84 nf_errmsg cb, void *data)
86 CURLcode curlret;
87 struct curl_slist *headers = NULL;
88 static CURL *handle;
89 bool ret = TRUE;
91 handle = netfile_init_handle();
93 headers = curl_slist_append(headers,"User-Agent: Freeciv/" VERSION_STRING);
95 curl_easy_setopt(handle, CURLOPT_URL, URL);
96 if (mem_data != NULL) {
97 mem_data->mem = NULL;
98 mem_data->size = 0;
99 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, netfile_memwrite_cb);
100 curl_easy_setopt(handle, CURLOPT_WRITEDATA, mem_data);
101 } else {
102 curl_easy_setopt(handle, CURLOPT_WRITEDATA, fp);
104 curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
105 curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1);
107 curlret = curl_easy_perform(handle);
109 curl_slist_free_all(headers);
111 if (curlret != CURLE_OK) {
112 if (cb != NULL) {
113 char buf[2048 + CURL_ERROR_SIZE];
115 fc_snprintf(buf, sizeof(buf),
116 /* TRANS: first %s is URL, second is Curl error message
117 * (not in Freeciv translation domain) */
118 _("Failed to fetch %s: %s"), URL,
119 error_buf_curl[0] != '\0' ? error_buf_curl : curl_easy_strerror(curlret));
120 cb(buf, data);
123 ret = FALSE;
126 return ret;
129 /**********************************************************************
130 Fetch section file from net
131 ***********************************************************************/
132 struct section_file *netfile_get_section_file(const char *URL,
133 nf_errmsg cb, void *data)
135 bool success;
136 struct section_file *out = NULL;
137 struct netfile_write_cb_data mem_data;
138 fz_FILE *file;
140 success = netfile_download_file_core(URL, NULL, &mem_data, cb, data);
142 if (success) {
143 file = fz_from_memory(mem_data.mem, mem_data.size, TRUE);
145 out = secfile_from_stream(file, TRUE);
148 return out;
151 /**********************************************************************
152 Fetch file from given URL and save as given filename.
153 ***********************************************************************/
154 bool netfile_download_file(const char *URL, const char *filename,
155 nf_errmsg cb, void *data)
157 bool success;
158 FILE *fp;
160 fp = fc_fopen(filename, "w+b");
162 if (fp == NULL) {
163 if (cb != NULL) {
164 char buf[2048];
166 fc_snprintf(buf, sizeof(buf),
167 _("Could not open %s for writing"), filename);
168 cb(buf, data);
170 return FALSE;
173 success = netfile_download_file_core(URL, fp, NULL, cb, data);
175 fclose(fp);
177 return success;
180 /**********************************************************************
181 Allocate netfile_post
182 ***********************************************************************/
183 struct netfile_post *netfile_start_post(void)
185 return fc_calloc(1, sizeof(struct netfile_post));
188 /**********************************************************************
189 Add one entry to netfile post form
190 ***********************************************************************/
191 void netfile_add_form_str(struct netfile_post *post,
192 const char *name, const char *val)
194 curl_formadd(&post->first, &post->last,
195 CURLFORM_COPYNAME, name,
196 CURLFORM_COPYCONTENTS, val,
197 CURLFORM_END);
200 /**********************************************************************
201 Add one integer entry to netfile post form
202 ***********************************************************************/
203 void netfile_add_form_int(struct netfile_post *post,
204 const char *name, const int val)
206 char buf[50];
208 fc_snprintf(buf, sizeof(buf), "%d", val);
209 netfile_add_form_str(post, name, buf);
212 /**********************************************************************
213 Free netfile_post resources
214 ***********************************************************************/
215 void netfile_close_post(struct netfile_post *post)
217 curl_formfree(post->first);
218 FC_FREE(post);
221 /**********************************************************************
222 Dummy write callback used only to make sure curl's default write
223 function does not get used as we don't want reply to stdout
224 ***********************************************************************/
225 static size_t dummy_write(void *buffer, size_t size, size_t nmemb, void *userp)
227 return size * nmemb;
230 /**********************************************************************
231 Send HTTP POST
232 ***********************************************************************/
233 bool netfile_send_post(const char *URL, struct netfile_post *post,
234 FILE *reply_fp, struct netfile_write_cb_data *mem_data,
235 const char *addr)
237 CURLcode curlret;
238 long http_resp;
239 struct curl_slist *headers = NULL;
240 static CURL *handle;
242 handle = netfile_init_handle();
244 headers = curl_slist_append(headers,"User-Agent: Freeciv/" VERSION_STRING);
246 curl_easy_setopt(handle, CURLOPT_URL, URL);
247 curl_easy_setopt(handle, CURLOPT_HTTPPOST, post->first);
248 if (mem_data != NULL) {
249 mem_data->mem = NULL;
250 mem_data->size = 0;
251 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, netfile_memwrite_cb);
252 curl_easy_setopt(handle, CURLOPT_WRITEDATA, mem_data);
253 } else if (reply_fp == NULL) {
254 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, dummy_write);
255 } else {
256 curl_easy_setopt(handle, CURLOPT_WRITEDATA, reply_fp);
258 if (addr != NULL) {
259 curl_easy_setopt(handle, CURLOPT_INTERFACE, addr);
261 curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
263 curlret = curl_easy_perform(handle);
265 curl_slist_free_all(headers);
267 if (curlret != CURLE_OK) {
268 return FALSE;
271 curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_resp);
273 if (http_resp != 200) {
274 return FALSE;
277 return TRUE;