Freeciv-3.2: /fast/freeciv/nightly/S3_2/tools/fcmp/download.c Source File

Freeciv-3.2

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,
47 dl_msg_callback mcb,
48 dl_pb_callback pbcb,
49 int recursion);
50
51/**********************************************************************/
54 static void nf_cb(const char *msg, void *data)
55{
56 dl_msg_callback mcb = (dl_msg_callback) data;
57
58 if (mcb != NULL) {
59 mcb(msg);
60 }
61}
62
63/**********************************************************************/
66 const char *download_modpack(const char *URL,
67 const struct fcmp_params *fcmp,
68 dl_msg_callback mcb,
69 dl_pb_callback pbcb)
70{
71 return download_modpack_recursive(URL, fcmp, mcb, pbcb, 0);
72}
73
74/**********************************************************************/
77 static const char *download_modpack_recursive(const char *URL,
78 const struct fcmp_params *fcmp,
79 dl_msg_callback mcb,
80 dl_pb_callback pbcb,
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;
94 bool partial_failure = FALSE;
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),
109 MODPACKDL_SUFFIX)) {
110 return _("This does not look like modpack URL");
111 }
112
113 for (start_idx = strlen(URL) - strlen(MODPACKDL_SUFFIX);
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
149 if (!has_capabilities(MODPACK_CAPSTR, control_capstr)) {
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");
169 type = modpack_type_by_name(typestr, fc_strcasecmp);
170 if (!modpack_type_is_valid(type)) {
171 return _("Illegal modpack type");
172 }
173
174 if (type == MPT_SCENARIO) {
175 fc_snprintf(local_dir, sizeof(local_dir),
176 "%s" DIR_SEPARATOR "scenarios", fcmp->inst_prefix);
177 } else {
178 fc_snprintf(local_dir, sizeof(local_dir),
179 "%s" DIR_SEPARATOR DATASUBDIR, fcmp->inst_prefix);
180 }
181
182 dep = 0;
183 do {
184 dep_name = secfile_lookup_str_default(control, NULL,
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;
190 enum modpack_type dep_type;
191 bool needed = TRUE;
192
193 dep_URL = secfile_lookup_str_default(control, NULL,
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);
201 dep_type = modpack_type_by_name(dep_typestr, fc_strcasecmp);
202 if (!modpack_type_is_valid(dep_type)) {
203 return _("Illegal dependency modpack type");
204 }
205
206 inst_ver = mpdb_installed_version(dep_name, type);
207
208 if (inst_ver != NULL) {
209 const char *dep_ver;
210
211 dep_ver = secfile_lookup_str_default(control, NULL,
212 "dependencies.list%d.version", dep);
213
214 if (dep_ver != NULL && cvercmp_max(dep_ver, inst_ver)) {
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 {
237 sz_strlcpy(dep_URL_full, dep_URL);
238 }
239
240 msg = download_modpack_recursive(dep_URL_full, fcmp, mcb, pbcb, recursion + 1);
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 {
265 src_name = secfile_lookup_str_default(control, NULL,
266 "%s.list%d.src",
267 sec_name, total_files);
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 {
297 sz_strlcpy(baseURL, baseURLpart);
298 }
299
300 /* Remove potential ending '/' as one will get added later. */
301 URL_len = strlen(baseURL);
302 if (baseURL[URL_len - 1] == '/') {
303 baseURL[URL_len - 1] = '\0';
304 }
305
306 for (j = 0;
307 (src_name = secfile_lookup_str_default(control, NULL,
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
321 dest_name = secfile_lookup_str_default(control, NULL,
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 */
326 dest_name = src_name;
327 }
328
329#ifndef DIR_SEPARATOR_IS_DEFAULT
330 dest_name_copy = fc_malloc(strlen(dest_name) + 1);
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 }
342 partial_failure = TRUE;
343 illegal_filename = TRUE;
344 }
345
346#ifndef DIR_SEPARATOR_IS_DEFAULT
347 if (dest_name[k] == '/') {
348 dest_name_copy[k] = DIR_SEPARATOR_CHAR;
349 } else {
350 dest_name_copy[k] = dest_name[k];
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
362 fc_snprintf(local_name, sizeof(local_name),
363 "%s" DIR_SEPARATOR "%s", local_dir, dest_name_copy);
364
365#ifndef DIR_SEPARATOR_IS_DEFAULT
366 free(dest_name_copy);
367#endif /* DIR_SEPARATOR_IS_DEFAULT */
368
369 if (!make_dir_for_file(local_name)) {
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);
383 if (!netfile_download_file(fileURL, local_name, nf_cb, mcb)) {
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 }
391 partial_failure = TRUE;
392 }
393 } else {
394#ifndef DIR_SEPARATOR_IS_DEFAULT
395 free(dest_name_copy);
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
409 section_list_destroy(sec);
410
411 if (partial_failure) {
412 secfile_destroy(control);
413
414 return _("Some parts of the modpack failed to install.");
415 }
416
417 mpdb_update_modpack(mpname, type, mpver);
418
419 secfile_destroy(control);
420
421 return NULL;
422}
423
424/**********************************************************************/
427 const char *download_modpack_list(const struct fcmp_params *fcmp,
428 modpack_list_setup_cb cb,
429 dl_msg_callback mcb)
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
438 list_file = netfile_get_section_file(fcmp->list_url, nf_cb, mcb);
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) {
456 secfile_destroy(list_file);
457 return _("Modpack list has no capability string");
458 }
459
460 if (!has_capabilities(MODLIST_CAPSTR, list_capstr)) {
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
465 secfile_destroy(list_file);
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
485 mp_name = secfile_lookup_str_default(list_file, NULL,
486 "modpacks.list%d.name", modpack_count);
487 mpver = secfile_lookup_str_default(list_file, NULL,
488 "modpacks.list%d.version",
489 modpack_count);
490 mplic = secfile_lookup_str_default(list_file, NULL,
491 "modpacks.list%d.license",
492 modpack_count);
493 mp_type_str = secfile_lookup_str_default(list_file, NULL,
494 "modpacks.list%d.type",
495 modpack_count);
496 mp_subtype = secfile_lookup_str_default(list_file, NULL,
497 "modpacks.list%d.subtype",
498 modpack_count);
499 mpURL = secfile_lookup_str_default(list_file, NULL,
500 "modpacks.list%d.URL", modpack_count);
501 mp_notes = secfile_lookup_str_default(list_file, NULL,
502 "modpacks.list%d.notes", modpack_count);
503
504 if (mp_name != NULL && mpURL != NULL) {
505 char mpURL_full[2048];
506 enum modpack_type type = modpack_type_by_name(mp_type_str, fc_strcasecmp);
507
508 if (!modpack_type_is_valid(type)) {
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
521 strncpy(URLstart, fcmp->list_url, start_idx - 1);
522 URLstart[start_idx - 1] = '\0';
523 fc_snprintf(mpURL_full, sizeof(mpURL_full), "%s%s",
524 URLstart, mpURL + 1);
525 } else {
526 sz_strlcpy(mpURL_full, mpURL);
527 }
528
529 cb(mp_name, mpURL_full, mpver, mplic, type, _(mp_subtype), mp_notes);
530 }
531 modpack_count++;
532 } while (mp_name != NULL);
533
534 return NULL;
535}
has_capabilities
bool has_capabilities(const char *us, const char *them)
Definition capability.c:86
capability.h
incite_cost
char * incite_cost
Definition comments.c:74
download_modpack_recursive
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
download_modpack
const char * download_modpack(const char *URL, const struct fcmp_params *fcmp, dl_msg_callback mcb, dl_pb_callback pbcb)
Definition download.c:66
nf_cb
static void nf_cb(const char *msg, void *data)
Definition download.c:54
download_modpack_list
const char * download_modpack_list(const struct fcmp_params *fcmp, modpack_list_setup_cb cb, dl_msg_callback mcb)
Definition download.c:427
download.h
MODLIST_CAPSTR
#define MODLIST_CAPSTR
Definition download.h:26
modpack_list_setup_cb
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
dl_msg_callback
void(* dl_msg_callback)(const char *msg)
Definition download.h:30
dl_pb_callback
void(* dl_pb_callback)(int downloaded, int max)
Definition download.h:31
MODPACKDL_SUFFIX
#define MODPACKDL_SUFFIX
Definition download.h:23
fc_prehdrs.h
fcintl.h
_
#define _(String)
Definition fcintl.h:67
type
GType type
Definition repodlgs.c:1313
log.h
log_debug
#define log_debug(message,...)
Definition log.h:115
log_normal
#define log_normal(message,...)
Definition log.h:107
log_error
#define log_error(message,...)
Definition log.h:103
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
MODPACK_CAPSTR
#define MODPACK_CAPSTR
Definition modpack.h:20
fcmp
struct fcmp_params fcmp
Definition mpcli.c:37
mpdb_installed_version
const char * mpdb_installed_version(const char *name, enum modpack_type type)
Definition mpdb.c:253
mpdb_update_modpack
bool mpdb_update_modpack(const char *name, enum modpack_type type, const char *version)
Definition mpdb.c:213
mpdb.h
netfile_get_section_file
struct section_file * netfile_get_section_file(const char *URL, nf_errmsg cb, void *data)
Definition netfile.c:146
netfile_download_file
bool netfile_download_file(const char *URL, const char *filename, nf_errmsg cb, void *data)
Definition netfile.c:168
netfile.h
registry.h
section_name
const char * section_name(const struct section *psection)
Definition section_file.c:65
secfile_destroy
void secfile_destroy(struct section_file *secfile)
Definition section_file.c:95
secfile_sections_by_name_prefix
struct section_list * secfile_sections_by_name_prefix(const struct section_file *secfile, const char *prefix)
Definition registry_ini.c:2871
secfile_lookup_str
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:2175
secfile_lookup_str_default
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Definition registry_ini.c:2205
make_dir_for_file
bool make_dir_for_file(char *filename)
Definition shared.c:1858
DIR_SEPARATOR
#define DIR_SEPARATOR
Definition shared.h:127
DIR_SEPARATOR_CHAR
#define DIR_SEPARATOR_CHAR
Definition shared.h:128
recursion
static int recursion[AIT_LAST]
Definition srv_log.c:45
fcmp_params
Definition modinst.h:17
fcmp_params::inst_prefix
const char * inst_prefix
Definition modinst.h:19
fcmp_params::list_url
const char * list_url
Definition modinst.h:18
section_file
Definition section_file.h:36
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47