Freeciv-3.1
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
86HANDLE server_process = INVALID_HANDLE_VALUE;
87HANDLE loghandle = INVALID_HANDLE_VALUE;
88#endif /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
90
92static bool client_has_hack = FALSE;
93
95
96/**************************************************************************
97The general chain of events:
98
99Two distinct paths are taken depending on the choice of mode:
100
101if the user selects the multi- player mode, then a packet_req_join_game
102packet is sent to the server. It is either successful or not. The end.
103
104If the user selects a single- player mode (either a new game or a save game)
105then:
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
132 return (server_process != INVALID_HANDLE_VALUE);
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/**********************************************************************/
153void client_kill_server(bool force)
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) {
160 kill(server_pid, SIGTERM);
161 waitpid(server_pid, NULL, WUNTRACED);
162 }
163 server_pid = -1;
165 }
166#elif FREECIV_MSWINDOWS
167 if (server_quitting && server_process != INVALID_HANDLE_VALUE) {
168 /* Already asked to /quit.
169 * If it didn't do that, kill it. */
170 TerminateProcess(server_process, 0);
171 CloseHandle(server_process);
172 if (loghandle != INVALID_HANDLE_VALUE) {
173 CloseHandle(loghandle);
174 }
175 server_process = INVALID_HANDLE_VALUE;
176 loghandle = INVALID_HANDLE_VALUE;
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
202 kill(server_pid, SIGTERM);
203 waitpid(server_pid, NULL, WUNTRACED);
204 server_pid = -1;
205#elif FREECIV_MSWINDOWS
206 TerminateProcess(server_process, 0);
207 CloseHandle(server_process);
208 if (loghandle != INVALID_HANDLE_VALUE) {
209 CloseHandle(loghandle);
210 }
211 server_process = INVALID_HANDLE_VALUE;
212 loghandle = INVALID_HANDLE_VALUE;
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;
232 char savesdir[MAX_LEN_PATH];
233 char scensdir[MAX_LEN_PATH];
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() */
240 STARTUPINFO si;
241 PROCESS_INFORMATION pi;
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
262 enum fc_addr_family family = FC_ADDR_ANY;
263#else
264 enum fc_addr_family family = FC_ADDR_IPV4;
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. */
277 internal_server_port = find_next_free_port(DEFAULT_SOCK_PORT + 1,
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
288 storage = freeciv_storage_dir();
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. */
310 fc_snprintf(port_buf, sizeof(port_buf), "%d", internal_server_port);
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) {
332 enum log_level llvl = log_get_level();
333
334 argv[argc++] = "--debug";
335 fc_snprintf(dbg_lvl_buf, sizeof(dbg_lvl_buf), "%s", log_level_name(llvl));
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;
356 fc_assert(argc <= max_nargs);
357
358 {
359 struct astring srv_cmdline_opts = ASTRING_INIT;
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",
366 astr_str(&srv_cmdline_opts));
367 astr_free(&srv_cmdline_opts);
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) {
383 log_to_dev_null = TRUE;
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"));
414 execvp(srvpath, argv);
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) {
449 loghandle = CreateFile(logfile, GENERIC_WRITE,
450 FILE_SHARE_READ | FILE_SHARE_WRITE,
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) {
469 char *logfile_in_local_encoding =
471 enum log_level llvl = log_get_level();
472
473 fc_snprintf(logcmdline, sizeof(logcmdline), " --debug %s --log %s",
474 log_level_name(llvl),
475 logfile_in_local_encoding);
476 free(logfile_in_local_encoding);
477 }
478 if (scriptfile) {
479 char *scriptfile_in_local_encoding =
481
482 fc_snprintf(scriptcmdline, sizeof(scriptcmdline), " --read %s",
483 scriptfile_in_local_encoding);
484 free(scriptfile_in_local_encoding);
485 }
486 if (savefile) {
487 char *savefile_in_local_encoding =
489
490 fc_snprintf(savefilecmdline, sizeof(savefilecmdline), " --file %s",
491 savefile_in_local_encoding);
492 free(savefile_in_local_encoding);
493 }
494
495 fc_snprintf(savesdir, sizeof(savesdir), "%s" DIR_SEPARATOR "saves", storage);
496 internal_to_local_string_buffer(savesdir, savescmdline, sizeof(savescmdline));
497
498 fc_snprintf(scensdir, sizeof(scensdir), "%s" DIR_SEPARATOR "scenarios", storage);
499 internal_to_local_string_buffer(scensdir, scenscmdline, sizeof(scenscmdline));
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",
515 internal_server_port, logcmdline, scriptcmdline, savefilecmdline,
516 savescmdline, scenscmdline, rsparam, depr);
517#ifdef FREECIV_DEBUG
518#ifdef FREECIV_WEB
519 fc_snprintf(cmdline1, sizeof(cmdline1),
520 "./server/freeciv-web %s", options);
521#else /* FREECIV_WEB */
522 fc_snprintf(cmdline1, sizeof(cmdline1), "./fcser %s", options);
523 fc_snprintf(cmdline2, sizeof(cmdline2),
524 "./server/freeciv-server %s", options);
525#endif /* FREECIV_WEB */
526#endif /* FREECIV_DEBUG */
527#ifdef FREECIV_WEB
528 fc_snprintf(cmdline3, sizeof(cmdline2),
529 BINDIR "/freeciv-web %s", options);
530 fc_snprintf(cmdline4, sizeof(cmdline3),
531 "freeciv-web %s", options);
532#else /* FREECIV_WEB */
533 fc_snprintf(cmdline3, sizeof(cmdline3),
534 BINDIR "/freeciv-server %s", options);
535 fc_snprintf(cmdline4, sizeof(cmdline4),
536 "freeciv-server %s", options);
537#endif /* FREECIV_WEB */
538
539 if (
540#ifdef FREECIV_DEBUG
541 !CreateProcess(NULL, cmdline1, NULL, NULL, TRUE,
542 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
543 NULL, NULL, &si, &pi)
544#ifndef FREECIV_WEB
545 && !CreateProcess(NULL, cmdline2, NULL, NULL, TRUE,
546 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
547 NULL, NULL, &si, &pi)
548#endif /* FREECIV_WEB */
549 &&
550#endif /* FREECIV_DEBUG */
551 !CreateProcess(NULL, cmdline3, NULL, NULL, TRUE,
552 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
553 NULL, NULL, &si, &pi)
554 && !CreateProcess(NULL, cmdline4, NULL, NULL, TRUE,
555 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
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 */
588 if (connect_tries++ > NUMBER_OF_TRIES) {
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 * In both cases the map wraps in the X direction by default.
616 *
617 * This works with hex maps too now. A hex map always has
618 * tileset_is_isometric(tileset) return TRUE. An iso-hex map has
619 * tileset_hex_height(tileset) != 0, while a non-iso hex map
620 * has tileset_hex_width(tileset) != 0.
621 *
622 * Setting the option here is a bit of a hack, but so long as the client
623 * has sufficient permissions to do so (it doesn't have HACK access yet) it
624 * is safe enough. Note that if you load a savegame the topology will be
625 * set but then overwritten during the load.
626 *
627 * Don't send it now, it will be sent to the server when receiving the
628 * server setting infos. */
629 {
630 char topobuf[16];
631
632 fc_strlcpy(topobuf, "WRAPX", sizeof(topobuf));
634 fc_strlcat(topobuf, "|ISO", sizeof(topobuf));
635 }
637 fc_strlcat(topobuf, "|HEX", sizeof(topobuf));
638 }
639 desired_settable_option_update("topology", topobuf, FALSE);
640 }
641
642 return TRUE;
643#endif /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
644}
645
646/**********************************************************************/
649static void randomize_string(char *str, size_t n)
650{
651 const char chars[] =
652 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
653 int i;
654
655 for (i = 0; i < n - 1; i++) {
656 str[i] = chars[fc_rand(sizeof(chars) - 1)];
657 }
658 str[i] = '\0';
659}
660
661/**********************************************************************/
669void send_client_wants_hack(const char *filename)
670{
671 if (filename[0] != '\0') {
673 struct section_file *file;
674 const char *sdir = freeciv_storage_dir();
675
676 if (sdir == NULL) {
677 return;
678 }
679
680 if (!is_safe_filename(filename)) {
681 return;
682 }
683
684 if (!make_dir(sdir)) {
685 log_error("Couldn't create storage directory for token.");
686 return;
687 }
688
690 "%s" DIR_SEPARATOR "%s", sdir, filename);
691
692 /* Generate an authentication token */
693 randomize_string(req.token, sizeof(req.token));
694
695 file = secfile_new(FALSE);
696 secfile_insert_str(file, req.token, "challenge.token");
697 if (!secfile_save(file, challenge_fullname, 0, FZ_PLAIN)) {
698 log_error("Couldn't write token to temporary file: %s",
700 /* FIXME: We need to destroy the secfile, but do we really
701 * want also to send the network packet after this? */
702 }
703 secfile_destroy(file);
704
705 /* Tell the server what we put into the file */
707 }
708}
709
710/**********************************************************************/
713void handle_single_want_hack_reply(bool you_have_hack)
714{
715 /* remove challenge file */
716 if (challenge_fullname[0] != '\0') {
717 if (fc_remove(challenge_fullname) == -1) {
718 log_error("Couldn't remove temporary file: %s", challenge_fullname);
719 }
720 challenge_fullname[0] = '\0';
721 }
722
723 if (you_have_hack) {
725 _("Established control over the server. "
726 "You have command access level 'hack'."));
728 } else if (is_server_running()) {
729 /* only output this if we started the server and we NEED hack */
731 _("Failed to obtain the required access "
732 "level to take control of the server. "
733 "Attempting to shut down server."));
735 }
736}
737
738/**********************************************************************/
741void send_save_game(const char *filename)
742{
744
745 if (filename) {
746 send_chat_printf("/save %s", filename);
747 } else {
748 send_chat("/save");
749 }
750}
751
752/**********************************************************************/
756{
757 char *rulesets[packet->ruleset_count];
758 int i;
759 size_t suf_len = strlen(RULESET_SUFFIX);
760
761 for (i = 0; i < packet->ruleset_count; i++) {
762 size_t len = strlen(packet->rulesets[i]);
763
764 rulesets[i] = fc_strdup(packet->rulesets[i]);
765
766 if (len > suf_len
767 && strcmp(rulesets[i] + len - suf_len, RULESET_SUFFIX) == 0) {
768 rulesets[i][len - suf_len] = '\0';
769 }
770 }
771 set_rulesets(packet->ruleset_count, rulesets);
772
773 for (i = 0; i < packet->ruleset_count; i++) {
774 free(rulesets[i]);
775 }
776}
777
778/**********************************************************************/
782void set_ruleset(const char *ruleset)
783{
784 char buf[4096];
785
786 fc_snprintf(buf, sizeof(buf), "/read %s%s", ruleset, RULESET_SUFFIX);
787 log_debug("Executing '%s'", buf);
788 send_chat(buf);
789}
void astr_free(struct astring *astr)
Definition astring.c:153
void astr_add(struct astring *astr, const char *format,...)
Definition astring.c:287
#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:327
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)
static char * ruleset
Definition civmanual.c:206
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:248
#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)
#define RULESET_SUFFIX
Definition fc_types.h:384
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:37
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:109
#define fc_assert(condition)
Definition log.h:176
#define log_debug(message,...)
Definition log.h:115
log_level
Definition log.h:28
#define log_error(message,...)
Definition log.h:103
#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:5599
int send_packet_single_want_hack_req(struct connection *pc, const struct packet_single_want_hack_req *packet)
int len
Definition packhand.c:125
#define fc_rand(_size)
Definition rand.h:34
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)
Definition shared.c:1772
bool is_safe_filename(const char *name)
Definition shared.c:252
char * freeciv_storage_dir(void)
Definition shared.c:672
#define DIR_SEPARATOR
Definition shared.h:127
#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 token[MAX_LEN_NAME]
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:787
void fc_usleep(unsigned long usec)
Definition support.c:640
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:832
int fc_remove(const char *filename)
Definition support.c:556
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
int tileset_hex_width(const struct tileset *t)
Definition tilespec.c:684
bool tileset_is_isometric(const struct tileset *t)
Definition tilespec.c:675
int tileset_hex_height(const struct tileset *t)
Definition tilespec.c:693
char * tileset_what_ruleset(struct tileset *t)
Definition tilespec.c:7243