Freeciv-3.3
Loading...
Searching...
No Matches
download.c
Go to the documentation of this file.
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.
7
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***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include "fc_prehdrs.h"
19
20#ifdef FREECIV_HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_SOCKET_H
24#include <sys/socket.h>
25#endif
26#include <unistd.h>
27#include <errno.h>
28
29/* dependencies */
30#include "cvercmp.h"
31
32/* utility */
33#include "capability.h"
34#include "fcintl.h"
35#include "log.h"
36#include "mem.h"
37#include "netfile.h"
38#include "registry.h"
39
40/* tools */
41#include "mpdb.h"
42
43#include "download.h"
44
45static const char *download_modpack_recursive(const char *URL,
46 const struct fcmp_params *fcmp,
49 int recursion);
50
51/**********************************************************************/
54static void nf_cb(const char *msg, void *data)
55{
57
58 if (mcb != NULL) {
59 mcb(msg);
60 }
61}
62
63/**********************************************************************/
66const char *download_modpack(const char *URL,
67 const struct fcmp_params *fcmp,
70{
71 return download_modpack_recursive(URL, fcmp, mcb, pbcb, 0);
72}
73
74/**********************************************************************/
77static const char *download_modpack_recursive(const char *URL,
78 const struct fcmp_params *fcmp,
81 int recursion)
82{
83 char local_dir[2048];
84 char local_name[2048];
85 int start_idx;
86 int total_files;
87 struct section_file *control;
88 const char *control_capstr;
89 enum modpack_type type;
90 const char *typestr;
91 const char *mpname;
92 const char *mpver;
93 const char *src_name;
95 int dep;
96 const char *dep_name;
97 struct section_list *sec;
98
99 if (recursion > 5) {
100 return _("Recursive dependencies too deep");
101 }
102
103 if (URL == NULL || URL[0] == '\0') {
104 return _("No URL given");
105 }
106
107 if (strlen(URL) < strlen(MODPACKDL_SUFFIX)
108 || strcmp(URL + strlen(URL) - strlen(MODPACKDL_SUFFIX),
110 return _("This does not look like modpack URL");
111 }
112
114 start_idx > 0 && URL[start_idx - 1] != '/';
115 start_idx--) {
116 /* Nothing */
117 }
118
119 if (start_idx <= 0) {
120 return _("This does not look like modpack URL");
121 }
122
123 log_normal(_("Installing modpack %s from %s"), URL + start_idx, URL);
124
125 if (fcmp->inst_prefix == NULL) {
126 return _("Cannot install to given directory hierarchy");
127 }
128
129 if (mcb != NULL) {
130 char buf[2048];
131
132 /* TRANS: %s is a filename with suffix '.mpdl' */
133 fc_snprintf(buf, sizeof(buf), _("Downloading \"%s\" control file."), URL + start_idx);
134 mcb(buf);
135 }
136
137 control = netfile_get_section_file(URL, nf_cb, mcb);
138
139 if (control == NULL) {
140 return _("Failed to get and parse modpack control file");
141 }
142
143 control_capstr = secfile_lookup_str(control, "info.options");
144 if (control_capstr == NULL) {
145 secfile_destroy(control);
146 return _("Modpack control file has no capability string");
147 }
148
150 log_error("Incompatible control file:");
151 log_error(" control file options: %s", control_capstr);
152 log_error(" supported options: %s", MODPACK_CAPSTR);
153
154 secfile_destroy(control);
155
156 return _("Modpack control file is incompatible");
157 }
158
159 mpname = secfile_lookup_str(control, "info.name");
160 if (mpname == NULL) {
161 return _("Modpack name not defined in control file");
162 }
163 mpver = secfile_lookup_str(control, "info.version");
164 if (mpver == NULL) {
165 return _("Modpack version not defined in control file");
166 }
167
168 typestr = secfile_lookup_str(control, "info.type");
171 return _("Illegal modpack type");
172 }
173
174 if (type == MPT_SCENARIO) {
176 "%s" DIR_SEPARATOR "scenarios", fcmp->inst_prefix);
177 } else {
180 }
181
182 dep = 0;
183 do {
185 "dependencies.list%d.modpack", dep);
186 if (dep_name != NULL) {
187 const char *dep_URL;
188 const char *inst_ver;
189 const char *dep_typestr;
191 bool needed = TRUE;
192
194 "dependencies.list%d.URL", dep);
195
196 if (dep_URL == NULL) {
197 return _("Dependency has no download URL");
198 }
199
200 dep_typestr = secfile_lookup_str(control, "dependencies.list%d.type", dep);
203 return _("Illegal dependency modpack type");
204 }
205
207
208 if (inst_ver != NULL) {
209 const char *dep_ver;
210
212 "dependencies.list%d.version", dep);
213
215 needed = FALSE;
216 }
217 }
218
219 if (needed) {
220 const char *msg;
221 char dep_URL_full[2048];
222
223 log_debug("Dependency modpack \"%s\" needed.", dep_name);
224
225 if (mcb != NULL) {
226 mcb(_("Download dependency modpack"));
227 }
228
229 if (dep_URL[0] == '.') {
230 char URLstart[start_idx];
231
232 strncpy(URLstart, URL, start_idx - 1);
233 URLstart[start_idx - 1] = '\0';
234 fc_snprintf(dep_URL_full, sizeof(dep_URL_full), "%s%s",
235 URLstart, dep_URL + 1);
236 } else {
238 }
239
241
242 if (msg != NULL) {
243 return msg;
244 }
245 }
246 }
247
248 dep++;
249
250 } while (dep_name != NULL);
251
252
253 total_files = 0;
254 sec = secfile_sections_by_name_prefix(control, "files_");
255
256 if (sec != NULL) {
257 size_t sec_count = section_list_size(sec);
258 size_t i;
259 int filenbr = 0;
260
261 for (i = 0; i < sec_count; i++) {
262 const char *sec_name = section_name(section_list_get(sec, i));
263
264 do {
266 "%s.list%d.src",
268
269 if (src_name != NULL) {
270 total_files++;
271 }
272 } while (src_name != NULL);
273 }
274
275 if (pbcb != NULL) {
276 /* Control file already downloaded */
277 pbcb(1, total_files + 1);
278 }
279
280 for (i = 0; i < sec_count; i++) {
281 const char *sec_name = section_name(section_list_get(sec, i));
282 const char *baseURLpart;
283 int URL_len;
284 char baseURL[2048];
285 int j;
286
287 baseURLpart = secfile_lookup_str(control, "%s.baseURL", sec_name);
288
289 if (baseURLpart[0] == '.') {
290 char URLstart[start_idx];
291
292 strncpy(URLstart, URL, start_idx - 1);
293 URLstart[start_idx - 1] = '\0';
294 fc_snprintf(baseURL, sizeof(baseURL), "%s%s",
295 URLstart, baseURLpart + 1);
296 } else {
298 }
299
300 /* Remove potential ending '/' as one will get added later. */
302 if (baseURL[URL_len - 1] == '/') {
303 baseURL[URL_len - 1] = '\0';
304 }
305
306 for (j = 0;
308 "%s.list%d.src", sec_name, j)) != NULL;
309 j++) {
310 const char *dest_name;
311
312#ifndef DIR_SEPARATOR_IS_DEFAULT
313 char *dest_name_copy;
314#else /* DIR_SEPARATOR_IS_DEFAULT */
315#define dest_name_copy dest_name
316#endif /* DIR_SEPARATOR_IS_DEFAULT */
317
318 int k;
319 bool illegal_filename = FALSE;
320
322 "%s.list%d.dest", sec_name, j);
323
324 if (dest_name == NULL || dest_name[0] == '\0') {
325 /* Missing dest name is ok, we just default to src_name */
327 }
328
329#ifndef DIR_SEPARATOR_IS_DEFAULT
331#endif /* DIR_SEPARATOR_IS_DEFAULT */
332
333 for (k = 0; dest_name[k] != '\0'; k++) {
334 if (dest_name[k] == '.' && dest_name[k + 1] == '.') {
335 if (mcb != NULL) {
336 char buf[2048];
337
338 fc_snprintf(buf, sizeof(buf), _("Illegal path for %s"),
339 dest_name);
340 mcb(buf);
341 }
344 }
345
346#ifndef DIR_SEPARATOR_IS_DEFAULT
347 if (dest_name[k] == '/') {
349 } else {
351 }
352#endif /* DIR_SEPARATOR_IS_DEFAULT */
353 }
354
355#ifndef DIR_SEPARATOR_IS_DEFAULT
356 dest_name_copy[k] = '\0';
357#endif /* DIR_SEPARATOR_IS_DEFAULT */
358
359 if (!illegal_filename) {
360 char fileURL[2048];
361
364
365#ifndef DIR_SEPARATOR_IS_DEFAULT
367#endif /* DIR_SEPARATOR_IS_DEFAULT */
368
370 secfile_destroy(control);
371 return _("Cannot create required directories");
372 }
373
374 if (mcb != NULL) {
375 char buf[2048];
376
377 fc_snprintf(buf, sizeof(buf), _("Downloading %s"), src_name);
378 mcb(buf);
379 }
380
381 fc_snprintf(fileURL, sizeof(fileURL), "%s/%s", baseURL, src_name);
382 log_debug("Download \"%s\" as \"%s\".", fileURL, local_name);
384 if (mcb != NULL) {
385 char buf[2048];
386
387 fc_snprintf(buf, sizeof(buf), _("Failed to download %s"),
388 src_name);
389 mcb(buf);
390 }
392 }
393 } else {
394#ifndef DIR_SEPARATOR_IS_DEFAULT
396#endif /* DIR_SEPARATOR_IS_DEFAULT */
397 }
398
399 filenbr++;
400
401 if (pbcb != NULL) {
402 /* Count download of control file also */
403 pbcb(filenbr + 1, total_files + 1);
404 }
405 }
406 }
407 }
408
410
411 if (partial_failure) {
412 secfile_destroy(control);
413
414 return _("Some parts of the modpack failed to install.");
415 }
416
418
419 secfile_destroy(control);
420
421 return NULL;
422}
423
424/**********************************************************************/
427const char *download_modpack_list(const struct fcmp_params *fcmp,
430{
431 struct section_file *list_file;
432 const char *list_capstr;
433 int modpack_count;
434 const char *msg;
435 const char *mp_name;
436 int start_idx;
437
439
440 if (list_file == NULL) {
441 return _("Cannot fetch and parse modpack list");
442 }
443
444 for (start_idx = strlen(fcmp->list_url);
445 start_idx > 0 && fcmp->list_url[start_idx - 1] != '/';
446 start_idx--) {
447 /* Nothing */
448 }
449
450 if (start_idx <= 0) {
451 return _("Invalid modpack list URL");
452 }
453
454 list_capstr = secfile_lookup_str(list_file, "info.options");
455 if (list_capstr == NULL) {
457 return _("Modpack list has no capability string");
458 }
459
461 log_error("Incompatible modpack list file:");
462 log_error(" list file options: %s", list_capstr);
463 log_error(" supported options: %s", MODLIST_CAPSTR);
464
466
467 return _("Modpack list is incompatible");
468 }
469
470 msg = secfile_lookup_str_default(list_file, NULL, "info.message");
471
472 if (msg != NULL) {
473 mcb(msg);
474 }
475
476 modpack_count = 0;
477 do {
478 const char *mpURL;
479 const char *mpver;
480 const char *mplic;
481 const char *mp_type_str;
482 const char *mp_subtype;
483 const char *mp_notes;
484
486 "modpacks.list%d.name", modpack_count);
488 "modpacks.list%d.version",
491 "modpacks.list%d.license",
494 "modpacks.list%d.type",
497 "modpacks.list%d.subtype",
500 "modpacks.list%d.URL", modpack_count);
502 "modpacks.list%d.notes", modpack_count);
503
504 if (mp_name != NULL && mpURL != NULL) {
505 char mpURL_full[2048];
507
509 log_error("Illegal modpack type \"%s\"", mp_type_str ? mp_type_str : "NULL");
510 }
511 if (mpver == NULL) {
512 mpver = "-";
513 }
514 if (mp_subtype == NULL) {
515 mp_subtype = "-";
516 }
517
518 if (mpURL[0] == '.') {
519 char URLstart[start_idx];
520
522 URLstart[start_idx - 1] = '\0';
523 fc_snprintf(mpURL_full, sizeof(mpURL_full), "%s%s",
524 URLstart, mpURL + 1);
525 } else {
527 }
528
530 }
532 } while (mp_name != NULL);
533
534 return NULL;
535}
bool has_capabilities(const char *us, const char *them)
Definition capability.c:88
char * incite_cost
Definition comments.c:76
static const char * download_modpack_recursive(const char *URL, const struct fcmp_params *fcmp, dl_msg_callback mcb, dl_pb_callback pbcb, int recursion)
Definition download.c:77
const char * download_modpack(const char *URL, const struct fcmp_params *fcmp, dl_msg_callback mcb, dl_pb_callback pbcb)
Definition download.c:66
static void nf_cb(const char *msg, void *data)
Definition download.c:54
const char * download_modpack_list(const struct fcmp_params *fcmp, modpack_list_setup_cb cb, dl_msg_callback mcb)
Definition download.c:427
#define MODLIST_CAPSTR
Definition download.h:26
void(* modpack_list_setup_cb)(const char *name, const char *URL, const char *version, const char *license, enum modpack_type type, const char *subtype, const char *notes)
Definition download.h:38
void(* dl_msg_callback)(const char *msg)
Definition download.h:30
void(* dl_pb_callback)(int downloaded, int max)
Definition download.h:31
#define MODPACKDL_SUFFIX
Definition download.h:23
#define _(String)
Definition fcintl.h:67
GType type
Definition repodlgs.c:1313
#define log_debug(message,...)
Definition log.h:116
#define log_normal(message,...)
Definition log.h:108
#define log_error(message,...)
Definition log.h:104
#define fc_malloc(sz)
Definition mem.h:34
#define MODPACK_CAPSTR
Definition modpack.h:20
struct fcmp_params fcmp
Definition mpcli.c:37
const char * mpdb_installed_version(const char *name, enum modpack_type type)
Definition mpdb.c:253
bool mpdb_update_modpack(const char *name, enum modpack_type type, const char *version)
Definition mpdb.c:213
struct section_file * netfile_get_section_file(const char *URL, nf_errmsg cb, void *data)
Definition netfile.c:148
bool netfile_download_file(const char *URL, const char *filename, nf_errmsg cb, void *data)
Definition netfile.c:170
const char * section_name(const struct section *psection)
void secfile_destroy(struct section_file *secfile)
struct section_list * secfile_sections_by_name_prefix(const struct section_file *secfile, const char *prefix)
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
bool make_dir_for_file(char *filename)
Definition shared.c:1862
#define DIR_SEPARATOR
Definition shared.h:127
#define DIR_SEPARATOR_CHAR
Definition shared.h:128
static int recursion[AIT_LAST]
Definition srv_log.c:45
const char * inst_prefix
Definition modinst.h:19
const char * list_url
Definition modinst.h:18
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
#define sz_strlcpy(dest, src)
Definition support.h:195
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47