Freeciv-3.4
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 != nullptr) {
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 == nullptr || 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 == nullptr) {
126 return _("Cannot install to given directory hierarchy");
127 }
128
129 if (mcb != nullptr) {
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 == nullptr) {
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 == nullptr) {
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 == nullptr) {
161 return _("Modpack name not defined in control file");
162 }
163 mpver = secfile_lookup_str(control, "info.version");
164 if (mpver == nullptr) {
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 {
184 dep_name = secfile_lookup_str_default(control, nullptr,
185 "dependencies.list%d.modpack", dep);
186 if (dep_name != nullptr) {
187 const char *dep_URL;
188 const char *inst_ver;
189 const char *dep_typestr;
191 bool needed = TRUE;
192
193 dep_URL = secfile_lookup_str_default(control, nullptr,
194 "dependencies.list%d.URL", dep);
195
196 if (dep_URL == nullptr) {
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 != nullptr) {
209 const char *dep_ver;
210
211 dep_ver = secfile_lookup_str_default(control, nullptr,
212 "dependencies.list%d.version", dep);
213
214 if (dep_ver != nullptr && 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 != nullptr) {
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 != nullptr) {
243 return msg;
244 }
245 }
246 }
247
248 dep++;
249
250 } while (dep_name != nullptr);
251
252
253 total_files = 0;
254 sec = secfile_sections_by_name_prefix(control, "files_");
255
256 if (sec != nullptr) {
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, nullptr,
266 "%s.list%d.src",
268
269 if (src_name != nullptr) {
270 total_files++;
271 }
272 } while (src_name != nullptr);
273 }
274
275 if (pbcb != nullptr) {
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;
307 (src_name = secfile_lookup_str_default(control, nullptr,
308 "%s.list%d.src", sec_name, j))
309 != nullptr;
310 j++) {
311 const char *dest_name;
312
313#ifndef DIR_SEPARATOR_IS_DEFAULT
314 char *dest_name_copy;
315#else /* DIR_SEPARATOR_IS_DEFAULT */
316#define dest_name_copy dest_name
317#endif /* DIR_SEPARATOR_IS_DEFAULT */
318
319 int k;
320 bool illegal_filename = FALSE;
321
322 dest_name = secfile_lookup_str_default(control, nullptr,
323 "%s.list%d.dest", sec_name, j);
324
325 if (dest_name == nullptr || dest_name[0] == '\0') {
326 /* Missing dest name is ok, we just default to src_name */
328 }
329
330#ifndef DIR_SEPARATOR_IS_DEFAULT
332#endif /* DIR_SEPARATOR_IS_DEFAULT */
333
334 for (k = 0; dest_name[k] != '\0'; k++) {
335 if (dest_name[k] == '.' && dest_name[k + 1] == '.') {
336 if (mcb != nullptr) {
337 char buf[2048];
338
339 fc_snprintf(buf, sizeof(buf), _("Illegal path for %s"),
340 dest_name);
341 mcb(buf);
342 }
345 }
346
347#ifndef DIR_SEPARATOR_IS_DEFAULT
348 if (dest_name[k] == '/') {
350 } else {
352 }
353#endif /* DIR_SEPARATOR_IS_DEFAULT */
354 }
355
356#ifndef DIR_SEPARATOR_IS_DEFAULT
357 dest_name_copy[k] = '\0';
358#endif /* DIR_SEPARATOR_IS_DEFAULT */
359
360 if (!illegal_filename) {
361 char fileURL[2048];
362
365
366#ifndef DIR_SEPARATOR_IS_DEFAULT
368#endif /* DIR_SEPARATOR_IS_DEFAULT */
369
371 secfile_destroy(control);
372 return _("Cannot create required directories");
373 }
374
375 if (mcb != nullptr) {
376 char buf[2048];
377
378 fc_snprintf(buf, sizeof(buf), _("Downloading %s"), src_name);
379 mcb(buf);
380 }
381
382 fc_snprintf(fileURL, sizeof(fileURL), "%s/%s", baseURL, src_name);
383 log_debug("Download \"%s\" as \"%s\".", fileURL, local_name);
385 if (mcb != nullptr) {
386 char buf[2048];
387
388 fc_snprintf(buf, sizeof(buf), _("Failed to download %s"),
389 src_name);
390 mcb(buf);
391 }
393 }
394 } else {
395#ifndef DIR_SEPARATOR_IS_DEFAULT
397#endif /* DIR_SEPARATOR_IS_DEFAULT */
398 }
399
400 filenbr++;
401
402 if (pbcb != nullptr) {
403 /* Count download of control file also */
404 pbcb(filenbr + 1, total_files + 1);
405 }
406 }
407 }
408 }
409
411
412 if (partial_failure) {
413 secfile_destroy(control);
414
415 return _("Some parts of the modpack failed to install.");
416 }
417
419
420 secfile_destroy(control);
421
422 return nullptr;
423}
424
425/**********************************************************************/
428const char *download_modpack_list(const struct fcmp_params *fcmp,
431{
432 struct section_file *list_file;
433 const char *list_capstr;
434 int modpack_count;
435 const char *msg;
436 const char *mp_name;
437 int start_idx;
438
440
441 if (list_file == nullptr) {
442 return _("Cannot fetch and parse modpack list");
443 }
444
445 for (start_idx = strlen(fcmp->list_url);
446 start_idx > 0 && fcmp->list_url[start_idx - 1] != '/';
447 start_idx--) {
448 /* Nothing */
449 }
450
451 if (start_idx <= 0) {
452 return _("Invalid modpack list URL");
453 }
454
455 list_capstr = secfile_lookup_str(list_file, "info.options");
456 if (list_capstr == nullptr) {
458 return _("Modpack list has no capability string");
459 }
460
462 log_error("Incompatible modpack list file:");
463 log_error(" list file options: %s", list_capstr);
464 log_error(" supported options: %s", MODLIST_CAPSTR);
465
467
468 return _("Modpack list is incompatible");
469 }
470
471 msg = secfile_lookup_str_default(list_file, nullptr, "info.message");
472
473 if (msg != nullptr) {
474 mcb(msg);
475 }
476
477 modpack_count = 0;
478 do {
479 const char *mpURL;
480 const char *mpver;
481 const char *mplic;
482 const char *mp_type_str;
483 const char *mp_subtype;
484 const char *mp_notes;
485
487 "modpacks.list%d.name", modpack_count);
489 "modpacks.list%d.version",
492 "modpacks.list%d.license",
495 "modpacks.list%d.type",
498 "modpacks.list%d.subtype",
501 "modpacks.list%d.URL", modpack_count);
503 "modpacks.list%d.notes", modpack_count);
504
505 if (mp_name != nullptr && mpURL != nullptr) {
506 char mpURL_full[2048];
508
510 log_error("Illegal modpack type \"%s\"",
511 mp_type_str ? mp_type_str : "nullptr");
512 }
513 if (mpver == nullptr) {
514 mpver = "-";
515 }
516 if (mp_subtype == nullptr) {
517 mp_subtype = "-";
518 }
519
520 if (mpURL[0] == '.') {
521 char URLstart[start_idx];
522
524 URLstart[start_idx - 1] = '\0';
525 fc_snprintf(mpURL_full, sizeof(mpURL_full), "%s%s",
526 URLstart, mpURL + 1);
527 } else {
529 }
530
532 }
534 } while (mp_name != nullptr);
535
536 return nullptr;
537}
bool has_capabilities(const char *us, const char *them)
Definition capability.c:88
char * incite_cost
Definition comments.c:77
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:428
#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:38
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