Freeciv-3.3
Loading...
Searching...
No Matches
connectdlg_common.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2004 - The Freeciv Project
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#include <fcntl.h>
21#include <stdio.h>
22#include <signal.h> /* SIGTERM and kill */
23#include <string.h>
24#include <time.h>
25
26#ifdef FREECIV_MSWINDOWS
27#include <windows.h>
28#endif
29
30#ifdef FREECIV_HAVE_SYS_TYPES_H
31#include <sys/types.h> /* fchmod */
32#endif
33
34#ifdef HAVE_SYS_STAT_H
35#include <sys/stat.h> /* fchmod */
36#endif
37
38#ifdef HAVE_SYS_WAIT_H
39#include <sys/wait.h>
40#endif
41
42/* utility */
43#include "astring.h"
44#include "capability.h"
45#include "deprecations.h"
46#include "fciconv.h"
47#include "fcintl.h"
48#include "ioz.h"
49#include "log.h"
50#include "mem.h"
51#include "netintf.h"
52#include "rand.h"
53#include "registry.h"
54#include "shared.h"
55#include "support.h"
56
57/* client */
58#include "attribute.h"
59#include "client_main.h"
60#include "climisc.h"
61#include "clinet.h" /* connect_to_server() */
62#include <packhand_gen.h> /* <> so looked from the build directory first. */
63
64#include "chatline_common.h"
65#include "connectdlg_g.h"
66#include "connectdlg_common.h"
67#include "tilespec.h"
68
69#define WAIT_BETWEEN_TRIES 100000 /* usecs */
70
71#ifdef FREECIV_PATIENT_CONNECT
72#define NUMBER_OF_TRIES 10000
73#else /* FREECIV_PATIENT_CONNECT */
74#define NUMBER_OF_TRIES 500
75#endif /* FREECIV_PATIENT_CONNECT */
76
77#if defined(HAVE_WORKING_FORK) && !defined(FREECIV_MSWINDOWS)
78/* We are yet to see FREECIV_MSWINDOWS setup where even HAVE_WORKING_FORK would
79 * mean fork() that actually works for us. */
80#define HAVE_USABLE_FORK
81#endif
82
83#ifdef HAVE_USABLE_FORK
84static pid_t server_pid = -1;
85#elif FREECIV_MSWINDOWS
88#endif /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
90
92static bool client_has_hack = FALSE;
93
95
96/**************************************************************************
97 The general chain of events:
98
99 Two distinct paths are taken depending on the choice of mode:
100
101 If the user selects the multi-player mode, then a packet_req_join_game
102 packet is sent to the server. It is either successful or not. The end.
103
104 If the user selects a single-player mode (either a new game or a save game)
105 then:
106 1. the packet_req_join_game is sent.
107 2. on receipt, if we can join, then a challenge packet is sent to the
108 server, so we can get hack level control.
109 3. if we can't get hack, then we get dumped to multi-player mode. If
110 we can, then:
111 a. for a new game, we send a series of packet_generic_message packets
112 with commands to start the game.
113 b. for a saved game, we send the load command with a
114 packet_generic_message, then we send a PACKET_PLAYER_LIST_REQUEST.
115 the response to this request will tell us if the game was loaded or
116 not. if not, then we send another load command. if so, then we send
117 a series of packet_generic_message packets with commands to start
118 the game.
119**************************************************************************/
120
121/**********************************************************************/
125{
126 if (server_quitting) {
127 return FALSE;
128 }
129#ifdef HAVE_USABLE_FORK
130 return (server_pid > 0);
131#elif FREECIV_MSWINDOWS
133#else
134 return FALSE; /* We've been unable to start one! */
135#endif
136}
137
138/**********************************************************************/
142{
143 return client_has_hack;
144}
145
146/**********************************************************************/
154{
155#ifdef HAVE_USABLE_FORK
156 if (server_quitting && server_pid > 0) {
157 /* Already asked to /quit.
158 * If it didn't do that, kill it. */
159 if (waitpid(server_pid, NULL, WUNTRACED) <= 0) {
162 }
163 server_pid = -1;
165 }
166#elif FREECIV_MSWINDOWS
168 /* Already asked to /quit.
169 * If it didn't do that, kill it. */
174 }
178 }
179#endif /* FREECIV_MSWINDOWS || HAVE_USABLE_FORK */
180
181 if (is_server_running()) {
183 /* This does a "soft" shutdown of the server by sending a /quit.
184 *
185 * This is useful when closing the client or disconnecting because it
186 * doesn't kill the server prematurely. In particular, killing the
187 * server in the middle of a save can have disastrous results. This
188 * method tells the server to quit on its own. This is safer from a
189 * game perspective, but more dangerous because if the kill fails the
190 * server will be left running.
191 *
192 * Another potential problem is because this function is called atexit
193 * it could potentially be called when we're connected to an unowned
194 * server. In this case we don't want to kill it. */
195 send_chat("/quit");
197 } else if (force) {
198 /* Either we already disconnected, or we didn't get control of the
199 * server. In either case, the only thing to do is a "hard" kill of
200 * the server. */
201#ifdef HAVE_USABLE_FORK
204 server_pid = -1;
205#elif FREECIV_MSWINDOWS
210 }
213#endif /* FREECIV_MSWINDOWS || HAVE_USABLE_FORK */
215 }
216 }
218}
219
220/**********************************************************************/
225{
226#if !defined(HAVE_USABLE_FORK) && !defined(FREECIV_MSWINDOWS)
227 /* Can't do much without fork */
228 return FALSE;
229#else /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
230 char buf[512];
231 int connect_tries = 0;
234 char *storage;
235 char *ruleset;
236
237#if !defined(HAVE_USABLE_FORK)
238 /* Above also implies that this is FREECIV_MSWINDOWS ->
239 * Windows that can't use fork() */
242
243 char options[1024];
244 char *depr;
245 char rsparam[256];
246#ifdef FREECIV_DEBUG
247 char cmdline1[512];
248#ifndef FREECIV_WEB
249 char cmdline2[512];
250#endif /* FREECIV_WEB */
251#endif /* FREECIV_DEBUG */
252 char cmdline3[512];
253 char cmdline4[512];
254 char logcmdline[512];
255 char scriptcmdline[512];
256 char savefilecmdline[512];
257 char savescmdline[512];
258 char scenscmdline[512];
259#endif /* !HAVE_USABLE_FORK -> FREECIV_MSWINDOWS */
260
261#ifdef FREECIV_IPV6_SUPPORT
263#else
265#endif /* FREECIV_IPV6_SUPPORT */
266
267 /* Only one server (forked from this client) shall be running at a time */
268 /* This also resets client_has_hack. */
270
271 output_window_append(ftc_client, _("Starting local server..."));
272
273 /* Find a free port */
274 /* Mitigate the risk of ending up with the port already
275 * used by standalone server on Windows where this is known to be buggy
276 * by not starting from DEFAULT_SOCK_PORT but from one higher. */
278 DEFAULT_SOCK_PORT + 1 + 10000,
279 family, "localhost", TRUE);
280
281 if (internal_server_port < 0) {
282 output_window_append(ftc_client, _("Couldn't start the server."));
284 _("You'll have to start one manually. Sorry..."));
285 return FALSE;
286 }
287
289 if (storage == NULL) {
290 output_window_append(ftc_client, _("Cannot find freeciv storage directory"));
292 _("You'll have to start server manually. Sorry..."));
293 return FALSE;
294 }
295
297
298#ifdef HAVE_USABLE_FORK
299 {
300 int argc = 0;
301 const int max_nargs = 25;
302 char *argv[max_nargs + 1];
303 char port_buf[32];
304 char dbg_lvl_buf[32]; /* Do not move this inside the block where it gets filled,
305 * it's needed via the argv[x] pointer later on, so must
306 * remain in scope. */
307 bool log_to_dev_null = FALSE;
308
309 /* Set up the command-line parameters. */
311 fc_snprintf(savesdir, sizeof(savesdir), "%s" DIR_SEPARATOR "saves", storage);
312 fc_snprintf(scensdir, sizeof(scensdir), "%s" DIR_SEPARATOR "scenarios", storage);
313#ifdef FREECIV_WEB
314 argv[argc++] = "freeciv-web";
315#else /* FREECIV_WEB */
316 argv[argc++] = "freeciv-server";
317#endif /* FREECIV_WEB */
318 argv[argc++] = "-p";
319 argv[argc++] = port_buf;
320 argv[argc++] = "--bind";
321 argv[argc++] = "localhost";
322 argv[argc++] = "-q";
323 argv[argc++] = "1";
324 argv[argc++] = "-e";
325 argv[argc++] = "--saves";
326 argv[argc++] = savesdir;
327 argv[argc++] = "--scenarios";
328 argv[argc++] = scensdir;
329 argv[argc++] = "-A";
330 argv[argc++] = "none";
331 if (logfile) {
333
334 argv[argc++] = "--debug";
336 argv[argc++] = dbg_lvl_buf;
337 argv[argc++] = "--log";
338 argv[argc++] = logfile;
339 }
340 if (scriptfile) {
341 argv[argc++] = "--read";
342 argv[argc++] = scriptfile;
343 }
344 if (savefile) {
345 argv[argc++] = "--file";
346 argv[argc++] = savefile;
347 }
349 argv[argc++] = "--warnings";
350 }
351 if (ruleset != NULL) {
352 argv[argc++] = "--ruleset";
353 argv[argc++] = ruleset;
354 }
355 argv[argc] = NULL;
357
358 {
360 int i;
361
362 for (i = 1; i < argc; i++) {
363 astr_add(&srv_cmdline_opts, i == 1 ? "%s" : " %s", argv[i]);
364 }
365 log_verbose("Arguments to spawned server: %s",
368 }
369
370 server_pid = fork();
372
373 if (server_pid == 0) {
374 int fd;
375
376 /* Inside the child */
377
378 /* Avoid terminal spam, but still make server output available */
379 fclose(stdout);
380 fclose(stderr);
381
382 if (!logfile) {
384 fd = open("/dev/null", O_WRONLY);
385 } else {
386 /* FIXME: include the port to avoid duplication? */
387 fd = open(logfile, O_WRONLY | O_CREAT | O_APPEND, 0644);
388 }
389
390 if (fd != 1) {
391 dup2(fd, 1);
392 }
393 if (fd != 2) {
394 dup2(fd, 2);
395 }
396 if (!log_to_dev_null) {
397 fchmod(1, 0644);
398 }
399
400 /* If it's still attached to our terminal, things get messed up,
401 but freeciv-server needs *something* */
402 fclose(stdin);
403 fd = open("/dev/null", O_RDONLY);
404 if (fd != 0) {
405 dup2(fd, 0);
406 }
407
408 /* These won't return on success */
409#ifdef FREECIV_APPIMAGE
410 char srvpath[2048];
411
412 fc_snprintf(srvpath, sizeof(srvpath), "%s/usr/bin/freeciv-server",
413 getenv("APPDIR"));
415#else /* FREECIV_APPIMAGE */
416#ifdef FREECIV_DEBUG
417 /* Search under current directory (what ever that happens to be)
418 * only in debug builds. This allows running freeciv directly from build
419 * tree, but could be considered security risk in release builds. */
420#ifdef FREECIV_WEB
421 execvp("./server/freeciv-web", argv);
422#else /* FREECIV_WEB */
423#ifdef MESON_BUILD
424 execvp("./freeciv-server", argv);
425#else /* MESON_BUILD */
426 execvp("./fcser", argv);
427 execvp("./server/freeciv-server", argv);
428#endif /* MESON_BUILD */
429#endif /* FREECIV_WEB */
430#endif /* FREECIV_DEBUG */
431#ifdef FREECIV_WEB
432 execvp(BINDIR "/freeciv-web", argv);
433 execvp("freeciv-web", argv);
434#else /* FREECIV_WEB */
435 execvp(BINDIR "/freeciv-server", argv);
436 execvp("freeciv-server", argv);
437#endif /* FREECIV_WEB */
438#endif /* FREECIV_APPIMAGE */
439
440 /* This line is only reached if freeciv-server cannot be started,
441 * so we kill the forked process.
442 * Calling exit here is dangerous due to X11 problems (async replies) */
443 _exit(1);
444 }
445 }
446#else /* HAVE_USABLE_FORK */
447#ifdef FREECIV_MSWINDOWS
448 if (logfile) {
451 NULL,
452 OPEN_ALWAYS, 0, NULL);
453 }
454
455 ZeroMemory(&si, sizeof(si));
456 si.cb = sizeof(si);
457 si.hStdOutput = loghandle;
458 si.hStdInput = INVALID_HANDLE_VALUE;
459 si.hStdError = loghandle;
460 si.dwFlags = STARTF_USESTDHANDLES;
461
462 /* Set up the command-line parameters. */
463 logcmdline[0] = 0;
464 scriptcmdline[0] = 0;
465 savefilecmdline[0] = 0;
466
467 /* The server expects command line arguments to be in local encoding */
468 if (logfile) {
472
473 fc_snprintf(logcmdline, sizeof(logcmdline), " --debug %s --log %s",
477 }
478 if (scriptfile) {
481
482 fc_snprintf(scriptcmdline, sizeof(scriptcmdline), " --read %s",
485 }
486 if (savefile) {
489
490 fc_snprintf(savefilecmdline, sizeof(savefilecmdline), " --file %s",
493 }
494
495 fc_snprintf(savesdir, sizeof(savesdir), "%s" DIR_SEPARATOR "saves", storage);
497
498 fc_snprintf(scensdir, sizeof(scensdir), "%s" DIR_SEPARATOR "scenarios", storage);
500
502 depr = " --warnings";
503 } else {
504 depr = "";
505 }
506 if (ruleset != NULL) {
507 fc_snprintf(rsparam, sizeof(rsparam), " --ruleset %s", ruleset);
508 } else {
509 rsparam[0] = '\0';
510 }
511
512 fc_snprintf(options, sizeof(options),
513 "-p %d --bind localhost -q 1 -e%s%s%s --saves \"%s\" "
514 "--scenarios \"%s\" -A none %s%s",
517#ifdef FREECIV_DEBUG
518#ifdef FREECIV_WEB
520 "./server/freeciv-web %s", options);
521#else /* FREECIV_WEB */
522 fc_snprintf(cmdline1, sizeof(cmdline1), "./fcser %s", options);
524 "./server/freeciv-server %s", options);
525#endif /* FREECIV_WEB */
526#endif /* FREECIV_DEBUG */
527#ifdef FREECIV_WEB
529 BINDIR "/freeciv-web %s", options);
531 "freeciv-web %s", options);
532#else /* FREECIV_WEB */
534 BINDIR "/freeciv-server %s", options);
536 "freeciv-server %s", options);
537#endif /* FREECIV_WEB */
538
539 if (
543 NULL, NULL, &si, &pi)
547 NULL, NULL, &si, &pi)
548#endif /* FREECIV_WEB */
549 &&
550#endif /* FREECIV_DEBUG */
553 NULL, NULL, &si, &pi)
556 NULL, NULL, &si, &pi)) {
557 log_error("Failed to start server process.");
558#ifdef FREECIV_DEBUG
559 log_verbose("Tried with commandline: '%s'", cmdline1);
560 log_verbose("Tried with commandline: '%s'", cmdline2);
561#endif /* FREECIV_DEBUG */
562 log_verbose("Tried with commandline: '%s'", cmdline3);
563 log_verbose("Tried with commandline: '%s'", cmdline4);
564 output_window_append(ftc_client, _("Couldn't start the server."));
566 _("You'll have to start one manually. Sorry..."));
567 return FALSE;
568 }
569
570 log_verbose("Arguments to spawned server: %s", options);
571
572 server_process = pi.hProcess;
573
574#endif /* FREECIV_MSWINDOWS */
575#endif /* HAVE_USABLE_FORK */
576
577 /* A reasonable number of tries */
579 buf, sizeof(buf)) == -1) {
581#ifdef HAVE_USABLE_FORK
582#ifndef FREECIV_MSWINDOWS
583 if (waitpid(server_pid, NULL, WNOHANG) != 0) {
584 break;
585 }
586#endif /* FREECIV_MSWINDOWS */
587#endif /* HAVE_USABLE_FORK */
589 log_error("Last error from connect attempts: '%s'", buf);
590 break;
591 }
592 }
593
594 /* Weird, but could happen, if server doesn't support new startup stuff
595 * capabilities won't help us here... */
596 if (!client.conn.used) {
597 /* Possible that server is still running. kill it */
599
600 log_error("Failed to connect to spawned server!");
601 output_window_append(ftc_client, _("Couldn't connect to the server."));
603 _("We probably couldn't start it from here."));
605 _("You'll have to start one manually. Sorry..."));
606
607 return FALSE;
608 }
609
610 /* We set the topology to match the view.
611 *
612 * When a typical player launches a game, they want the map orientation
613 * to match the tileset orientation. So if you use an isometric tileset,
614 * you get an iso-map and for a classic tileset you get a classic map.
615 *
616 * This works also with hex maps. A hex map always has
617 * tileset_is_isometric(tileset) return TRUE. An iso-hex map has
618 * tileset_hex_height(tileset) != 0, while a non-iso hex map
619 * has tileset_hex_width(tileset) != 0.
620 *
621 * Setting the option here is a bit of a hack, but so long as the client
622 * has sufficient permissions to do so (it doesn't have HACK access yet) it
623 * is safe enough. Note that if you load a savegame the topology will be
624 * set but then overwritten during the load.
625 *
626 * Don't send it now, it will be sent to the server when receiving the
627 * server setting infos. */
628 {
629 char topobuf[16];
630 bool iso = FALSE;
632
633 if (hh == 0 && tileset_is_isometric(tileset)) {
634 fc_strlcpy(topobuf, "ISO", sizeof(topobuf));
635 iso = TRUE;
636 }
637
638 if (0 < hh || 0 < tileset_hex_width(tileset)) {
639 if (iso) {
640 fc_strlcat(topobuf, "|HEX", sizeof(topobuf));
641 } else {
642 fc_strlcpy(topobuf, "HEX", sizeof(topobuf));
643 }
644 } else if (!iso) {
645 /* Empty value */
646 topobuf[0] = '\0';
647 }
648
650 }
651
652 return TRUE;
653#endif /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
654}
655
656/**********************************************************************/
659static void randomize_string(char *str, size_t n)
660{
661 const char chars[] =
662 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
663 int i;
664
665 for (i = 0; i < n - 1; i++) {
666 str[i] = chars[fc_rand(sizeof(chars) - 1)];
667 }
668 str[i] = '\0';
669}
670
671/**********************************************************************/
679void send_client_wants_hack(const char *filename)
680{
681 if (filename[0] != '\0') {
683 struct section_file *file;
684 const char *sdir = freeciv_storage_dir();
685
686 if (sdir == NULL) {
687 return;
688 }
689
690 if (!is_safe_filename(filename)) {
691 return;
692 }
693
695 log_error("Couldn't create storage directory for token.");
696 return;
697 }
698
700 "%s" DIR_SEPARATOR "%s", sdir, filename);
701
702 /* Generate an authentication token */
703 randomize_string(req.token, sizeof(req.token));
704
705 file = secfile_new(FALSE);
706 secfile_insert_str(file, req.token, "challenge.token");
707 if (!secfile_save(file, challenge_fullname, 0, FZ_PLAIN)) {
708 log_error("Couldn't write token to temporary file: %s",
710 /* FIXME: We need to destroy the secfile, but do we really
711 * want also to send the network packet after this? */
712 }
713 secfile_destroy(file);
714
715 /* Tell the server what we put into the file */
717 }
718}
719
720/**********************************************************************/
723void handle_single_want_hack_reply(bool you_have_hack)
724{
725 /* Remove challenge file */
726 if (challenge_fullname[0] != '\0') {
727 if (fc_remove(challenge_fullname) == -1) {
728 log_error("Couldn't remove temporary file: %s", challenge_fullname);
729 }
730 challenge_fullname[0] = '\0';
731 }
732
733 if (you_have_hack) {
735 _("Established control over the server. "
736 "You have command access level 'hack'."));
738 } else if (is_server_running()) {
739 /* Only output this if we started the server and we NEED hack */
741 _("Failed to obtain the required access "
742 "level to take control of the server. "
743 "Attempting to shut down server."));
745 }
746}
747
748/**********************************************************************/
751void send_save_game(const char *filename)
752{
754
755 if (filename) {
756 send_chat_printf("/save %s", filename);
757 } else {
758 send_chat("/save");
759 }
760}
761
762/**********************************************************************/
766{
767 char *rulesets[packet->ruleset_count];
768 int i;
769 size_t suf_len = strlen(RULESET_SUFFIX);
770
771 for (i = 0; i < packet->ruleset_count; i++) {
772 size_t len = strlen(packet->rulesets[i]);
773
774 rulesets[i] = fc_strdup(packet->rulesets[i]);
775
776 if (len > suf_len
777 && strcmp(rulesets[i] + len - suf_len, RULESET_SUFFIX) == 0) {
778 rulesets[i][len - suf_len] = '\0';
779 }
780 }
781 set_rulesets(packet->ruleset_count, rulesets);
782
783 for (i = 0; i < packet->ruleset_count; i++) {
784 free(rulesets[i]);
785 }
786}
787
788/**********************************************************************/
792void set_ruleset(const char *ruleset)
793{
794 struct packet_ruleset_select packet;
795
796 fc_snprintf(packet.modpack, sizeof(packet.modpack), "%s", ruleset);
797
799}
void astr_free(struct astring *astr)
Definition astring.c:148
void astr_add(struct astring *astr, const char *format,...)
Definition astring.c:271
#define str
Definition astring.c:76
#define n
Definition astring.c:77
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
#define ASTRING_INIT
Definition astring.h:44
void attribute_flush(void)
Definition attribute.c:333
int send_chat_printf(const char *format,...)
int send_chat(const char *message)
void output_window_append(const struct ft_color color, const char *featured_text)
char user_name[512]
char * logfile
struct civclient client
char * scriptfile
char * savefile
int connect_to_server(const char *username, const char *hostname, int port, char *errbuf, int errbufsize)
Definition clinet.c:249
char * incite_cost
Definition comments.c:76
#define NUMBER_OF_TRIES
void handle_ruleset_choices(const struct packet_ruleset_choices *packet)
bool server_quitting
void handle_single_want_hack_reply(bool you_have_hack)
void send_client_wants_hack(const char *filename)
static bool client_has_hack
int internal_server_port
void send_save_game(const char *filename)
static void randomize_string(char *str, size_t n)
#define WAIT_BETWEEN_TRIES
void set_ruleset(const char *ruleset)
bool is_server_running(void)
void client_kill_server(bool force)
bool client_start_server(void)
bool can_client_access_hack(void)
static char challenge_fullname[MAX_LEN_PATH]
bool are_deprecation_warnings_enabled(void)
static char * ruleset
Definition fc_manual.c:163
#define RULESET_SUFFIX
Definition fc_types.h:271
char * internal_to_local_string_buffer(const char *text, char *buf, size_t bufsz)
char * internal_to_local_string_malloc(const char *text)
#define _(String)
Definition fcintl.h:67
const struct ft_color ftc_client
void set_rulesets(int num_rulesets, char **rulesets)
Definition pages.c:3586
@ FZ_PLAIN
Definition ioz.h:38
const char * log_level_name(enum log_level lvl)
Definition log.c:330
enum log_level log_get_level(void)
Definition log.c:322
#define log_verbose(message,...)
Definition log.h:110
#define fc_assert(condition)
Definition log.h:177
log_level
Definition log.h:29
#define log_error(message,...)
Definition log.h:104
#define fc_strdup(str)
Definition mem.h:43
fc_addr_family
Definition net_types.h:61
@ FC_ADDR_IPV4
Definition net_types.h:62
@ FC_ADDR_ANY
Definition net_types.h:64
int find_next_free_port(int starting_port, int highest_port, enum fc_addr_family family, char *net_interface, bool not_avail_ok)
Definition netintf.c:560
void desired_settable_option_update(const char *op_name, const char *op_value, bool allow_replace)
Definition options.c:5859
int send_packet_ruleset_select(struct connection *pc, const struct packet_ruleset_select *packet)
int send_packet_single_want_hack_req(struct connection *pc, const struct packet_single_want_hack_req *packet)
int len
Definition packhand.c:127
#define fc_rand(_size)
Definition rand.h:56
struct section_file * secfile_new(bool allow_duplicates)
void secfile_destroy(struct section_file *secfile)
bool secfile_save(const struct section_file *secfile, const char *filename, int compression_level, enum fz_method compression_method)
#define secfile_insert_str(secfile, string, path,...)
bool make_dir(const char *pathname, int mode)
Definition shared.c:1779
bool is_safe_filename(const char *name)
Definition shared.c:256
char * freeciv_storage_dir(void)
Definition shared.c:671
#define DIR_SEPARATOR
Definition shared.h:127
#define DIRMODE_DEFAULT
Definition shared.h:258
#define MAX_LEN_PATH
Definition shared.h:32
struct connection conn
Definition client_main.h:96
char rulesets[MAX_NUM_RULESETS][MAX_RULESET_NAME_LENGTH]
char modpack[MAX_RULESET_NAME_LENGTH]
char token[MAX_LEN_NAME]
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
void fc_usleep(unsigned long usec)
Definition support.c:639
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:822
int fc_remove(const char *filename)
Definition support.c:555
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
int tileset_hex_width(const struct tileset *t)
Definition tilespec.c:747
bool tileset_is_isometric(const struct tileset *t)
Definition tilespec.c:738
int tileset_hex_height(const struct tileset *t)
Definition tilespec.c:756
char * tileset_what_ruleset(struct tileset *t)
Definition tilespec.c:7783