Rework README.ruleset_civ2civ3 defense bonus description.
[freeciv.git] / tools / download.c
blob1971b8d076d8b8cab3cd9af22c270ee8fb83e75e
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 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #endif
21 #ifdef HAVE_SYS_SOCKET_H
22 #include <sys/socket.h>
23 #endif
24 #include <unistd.h>
25 #include <errno.h>
27 /* utility */
28 #include "capability.h"
29 #include "fcintl.h"
30 #include "log.h"
31 #include "netintf.h"
32 #include "netfile.h"
33 #include "registry.h"
35 /* modinst */
36 #include "download.h"
38 /**************************************************************************
39 Message callback called by netfile module when downloading files.
40 **************************************************************************/
41 static void nf_cb(const char *msg, void *data)
43 dl_msg_callback mcb = (dl_msg_callback) data;
45 if (mcb != NULL) {
46 mcb(msg);
50 /**************************************************************************
51 Download modpack from a given URL
52 **************************************************************************/
53 const char *download_modpack(const char *URL,
54 const struct fcmp_params *fcmp,
55 dl_msg_callback mcb,
56 dl_pb_callback pbcb)
58 char local_dir[2048];
59 char local_name[2048];
60 int start_idx;
61 int filenbr, total_files;
62 struct section_file *control;
63 const char *control_capstr;
64 const char *baseURL;
65 enum modpack_type type;
66 const char *typestr;
67 const char *mpname;
68 const char *mpver;
69 char fileURL[2048];
70 const char *src_name;
71 bool partial_failure = FALSE;
73 if (URL == NULL || URL[0] == '\0') {
74 return _("No URL given");
77 if (strlen(URL) < strlen(MODPACK_SUFFIX)
78 || strcmp(URL + strlen(URL) - strlen(MODPACK_SUFFIX), MODPACK_SUFFIX)) {
79 return _("This does not look like modpack URL");
82 for (start_idx = strlen(URL) - strlen(MODPACK_SUFFIX);
83 start_idx > 0 && URL[start_idx - 1] != '/';
84 start_idx--) {
85 /* Nothing */
88 log_normal(_("Installing modpack %s from %s"), URL + start_idx, URL);
90 if (fcmp->inst_prefix == NULL) {
91 return _("Cannot install to given directory hierarchy");
94 if (mcb != NULL) {
95 mcb(_("Downloading modpack control file."));
98 control = netfile_get_section_file(URL, nf_cb, mcb);
100 if (control == NULL) {
101 return _("Failed to get and parse modpack control file");
104 control_capstr = secfile_lookup_str(control, "info.options");
105 if (control_capstr == NULL) {
106 secfile_destroy(control);
107 return _("Modpack control file has no capability string");
110 if (!has_capabilities(MODPACK_CAPSTR, control_capstr)) {
111 log_error("Incompatible control file:");
112 log_error(" control file options: %s", control_capstr);
113 log_error(" supported options: %s", MODPACK_CAPSTR);
115 secfile_destroy(control);
117 return _("Modpack control file is incompatible");
120 mpname = secfile_lookup_str(control, "info.name");
121 if (mpname == NULL) {
122 return _("Modpack name not defined in control file");
124 mpver = secfile_lookup_str(control, "info.version");
125 if (mpver == NULL) {
126 return _("Modpack version not defined in control file");
129 typestr = secfile_lookup_str(control, "info.type");
130 type = modpack_type_by_name(typestr, fc_strcasecmp);
131 if (!modpack_type_is_valid(type)) {
132 return _("Illegal modpack type");
135 if (type == MPT_SCENARIO) {
136 fc_snprintf(local_dir, sizeof(local_dir),
137 "%s/scenarios", fcmp->inst_prefix);
138 } else {
139 fc_snprintf(local_dir, sizeof(local_dir),
140 "%s/" DATASUBDIR, fcmp->inst_prefix);
143 baseURL = secfile_lookup_str(control, "info.baseURL");
145 total_files = 0;
146 do {
147 src_name = secfile_lookup_str_default(control, NULL,
148 "files.list%d.src", total_files);
150 if (src_name != NULL) {
151 total_files++;
153 } while (src_name != NULL);
155 if (pbcb != NULL) {
156 /* Control file already downloaded */
157 pbcb(1, total_files + 1);
160 filenbr = 0;
161 for (filenbr = 0; filenbr < total_files; filenbr++) {
162 const char *dest_name;
163 int i;
164 bool illegal_filename = FALSE;
166 src_name = secfile_lookup_str_default(control, NULL,
167 "files.list%d.src", filenbr);
169 dest_name = secfile_lookup_str_default(control, NULL,
170 "files.list%d.dest", filenbr);
172 if (dest_name == NULL || dest_name[0] == '\0') {
173 /* Missing dest name is ok, we just default to src_name */
174 dest_name = src_name;
177 for (i = 0; dest_name[i] != '\0'; i++) {
178 if (dest_name[i] == '.' && dest_name[i+1] == '.') {
179 if (mcb != NULL) {
180 char buf[2048];
182 fc_snprintf(buf, sizeof(buf), _("Illegal path for %s"),
183 dest_name);
184 mcb(buf);
186 partial_failure = TRUE;
187 illegal_filename = TRUE;
191 if (!illegal_filename) {
192 fc_snprintf(local_name, sizeof(local_name),
193 "%s/%s", local_dir, dest_name);
194 for (i = strlen(local_name) - 1 ; local_name[i] != '/' ; i--) {
195 /* Nothing */
197 local_name[i] = '\0';
198 if (!make_dir(local_name)) {
199 secfile_destroy(control);
200 return _("Cannot create required directories");
202 local_name[i] = '/';
204 if (mcb != NULL) {
205 char buf[2048];
207 fc_snprintf(buf, sizeof(buf), _("Downloading %s"), src_name);
208 mcb(buf);
211 fc_snprintf(fileURL, sizeof(fileURL), "%s/%s", baseURL, src_name);
212 if (!netfile_download_file(fileURL, local_name, nf_cb, mcb)) {
213 if (mcb != NULL) {
214 char buf[2048];
216 fc_snprintf(buf, sizeof(buf), _("Failed to download %s"),
217 src_name);
218 mcb(buf);
220 partial_failure = TRUE;
224 if (pbcb != NULL) {
225 /* Count download of control file also */
226 pbcb(filenbr + 2, total_files + 1);
230 if (partial_failure) {
231 secfile_destroy(control);
233 return _("Some parts of the modpack failed to install.");
236 update_install_info_lists(mpname, type, mpver);
238 secfile_destroy(control);
240 return NULL;
243 /**************************************************************************
244 Download modpack list
245 **************************************************************************/
246 const char *download_modpack_list(const struct fcmp_params *fcmp,
247 modpack_list_setup_cb cb,
248 dl_msg_callback mcb)
250 struct section_file *list_file;
251 const char *list_capstr;
252 int modpack_count;
253 const char *msg;
254 const char *mp_name;
256 list_file = netfile_get_section_file(fcmp->list_url, nf_cb, mcb);
258 if (list_file == NULL) {
259 return _("Cannot fetch and parse modpack list");
262 list_capstr = secfile_lookup_str(list_file, "info.options");
263 if (list_capstr == NULL) {
264 secfile_destroy(list_file);
265 return _("Modpack list has no capability string");
268 if (!has_capabilities(MODLIST_CAPSTR, list_capstr)) {
269 log_error("Incompatible modpack list file:");
270 log_error(" list file options: %s", list_capstr);
271 log_error(" supported options: %s", MODLIST_CAPSTR);
273 secfile_destroy(list_file);
275 return _("Modpack list is incompatible");
278 msg = secfile_lookup_str_default(list_file, NULL, "info.message");
280 if (msg != NULL) {
281 mcb(msg);
284 modpack_count = 0;
285 do {
286 const char *mpURL;
287 const char *mpver;
288 const char *mplic;
289 const char *mp_type_str;
290 const char *mp_subtype;
291 const char *mp_notes;
293 mp_name = secfile_lookup_str_default(list_file, NULL,
294 "modpacks.list%d.name", modpack_count);
295 mpver = secfile_lookup_str_default(list_file, NULL,
296 "modpacks.list%d.version",
297 modpack_count);
298 mplic = secfile_lookup_str_default(list_file, NULL,
299 "modpacks.list%d.license",
300 modpack_count);
301 mp_type_str = secfile_lookup_str_default(list_file, NULL,
302 "modpacks.list%d.type",
303 modpack_count);
304 mp_subtype = secfile_lookup_str_default(list_file, NULL,
305 "modpacks.list%d.subtype",
306 modpack_count);
307 mpURL = secfile_lookup_str_default(list_file, NULL,
308 "modpacks.list%d.URL", modpack_count);
309 mp_notes = secfile_lookup_str_default(list_file, NULL,
310 "modpacks.list%d.notes", modpack_count);
312 if (mp_name != NULL && mpURL != NULL) {
313 enum modpack_type type = modpack_type_by_name(mp_type_str, fc_strcasecmp);
314 if (!modpack_type_is_valid(type)) {
315 log_error("Illegal modpack type \"%s\"", mp_type_str ? mp_type_str : "NULL");
317 if (mpver == NULL) {
318 mpver = "-";
320 if (mp_subtype == NULL) {
321 mp_subtype = "-";
323 cb(mp_name, mpURL, mpver, mplic, type, mp_subtype, mp_notes);
325 modpack_count++;
326 } while (mp_name != NULL);
328 return NULL;