Freeciv-3.3: /fast/freeciv/nightly/main/server/stdinhand.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
stdinhand.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#include <stdarg.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#ifdef FREECIV_HAVE_LIBREADLINE
26#include <readline/readline.h>
27#endif
28
29/* utility */
30#include "astring.h"
31#include "bitvector.h"
32#include "deprecations.h"
33#include "fc_cmdline.h"
34#include "fciconv.h"
35#include "fcintl.h"
36#include "log.h"
37#include "mem.h"
38#include "rand.h"
39#include "registry.h"
40#include "support.h" /* fc__attribute, bool type, etc. */
41#include "timing.h"
42#include "section_file.h"
43
44/* common */
45#include "capability.h"
46#include "events.h"
47#include "fc_types.h" /* LINE_BREAK */
48#include "featured_text.h"
49#include "game.h"
50#include "map.h"
51#include "mapimg.h"
52#include "modpack.h"
53#include "packets.h"
54#include "player.h"
55#include "research.h"
56#include "rgbcolor.h"
57#include "srvdefs.h"
58#include "unitlist.h"
59#include "version.h"
60
61/* server */
62#include "aiiface.h"
63#include "citytools.h"
64#include "connecthand.h"
65#include "diplhand.h"
66#include "gamehand.h"
67#include "mapgen.h"
68#include "maphand.h"
69#include "meta.h"
70#include "notify.h"
71#include "plrhand.h"
72#include "report.h"
73#include "ruleload.h"
74#include "sanitycheck.h"
75#include "score.h"
76#include "sernet.h"
77#include "settings.h"
78#include "srv_log.h"
79#include "srv_main.h"
80#include "techtools.h"
81#include "voting.h"
82
83/* server/savegame */
84#include "savemain.h"
85
86/* server/scripting */
87#include "script_server.h"
88#include "script_fcdb.h"
89
90/* ai */
91#include "difficulty.h"
92#include "handicaps.h"
93
94#include "stdinhand.h"
95
96#define OPTION_NAME_SPACE 25
97
98 static enum cmdlevel default_access_level = ALLOW_BASIC;
99 static enum cmdlevel first_access_level = ALLOW_BASIC;
100
101static time_t *time_duplicate(const time_t *t);
102
103/* 'struct kick_hash' and related functions. */
104#define SPECHASH_TAG kick
105#define SPECHASH_ASTR_KEY_TYPE
106#define SPECHASH_IDATA_TYPE time_t *
107#define SPECHASH_UDATA_TYPE time_t
108#define SPECHASH_IDATA_COPY time_duplicate
109#define SPECHASH_IDATA_FREE (kick_hash_data_free_fn_t) free
110#define SPECHASH_UDATA_TO_IDATA(t) (&(t))
111#define SPECHASH_IDATA_TO_UDATA(p) (NULL != p ? *p : 0)
112#include "spechash.h"
113
114 const char *script_extension = ".serv";
115
116 static struct kick_hash *kick_table_by_addr = NULL;
117 static struct kick_hash *kick_table_by_user = NULL;
118
119
120static bool cut_client_connection(struct connection *caller, char *name,
121 bool check);
122static bool show_help(struct connection *caller, char *arg);
123static bool show_list(struct connection *caller, char *arg);
124static void show_colors(struct connection *caller);
125static bool set_ai_level_named(struct connection *caller, const char *name,
126 const char *level_name, bool check);
127static bool set_ai_level(struct connection *caller, const char *name,
128 enum ai_level level, bool check);
129static bool away_command(struct connection *caller, bool check);
130static bool show_command(struct connection *caller, char *str, bool check);
131static bool show_settings(struct connection *caller,
132 enum command_id called_as,
133 char *str, bool check);
134static void show_settings_one(struct connection *caller, enum command_id cmd,
135 struct setting *pset);
136static void show_ruleset_info(struct connection *caller, enum command_id cmd,
137 bool check, int read_recursion);
138static void show_mapimg(struct connection *caller, enum command_id cmd);
139static bool set_command(struct connection *caller, char *str, bool check);
140static bool lock_command(struct connection *caller, char *str, bool check);
141static bool unlock_command(struct connection *caller, char *str, bool check);
142
143static bool create_command(struct connection *caller, const char *str,
144 bool check);
145static bool end_command(struct connection *caller, char *str, bool check);
146static bool surrender_command(struct connection *caller, char *str, bool check);
147static bool handle_stdin_input_real(struct connection *caller, char *str,
148 bool check, int read_recursion);
149static bool read_init_script_real(struct connection *caller,
150 const char *script_filename, bool from_cmdline,
151 bool check, int read_recursion);
152static bool reset_command(struct connection *caller, char *arg, bool check,
153 int read_recursion);
154static bool default_command(struct connection *caller, char *arg, bool check);
155static bool lua_command(struct connection *caller, char *arg, bool check,
156 int read_recursion);
157static bool kick_command(struct connection *caller, char *name, bool check);
158static bool delegate_command(struct connection *caller, char *arg,
159 bool check);
160static const char *delegate_player_str(struct player *pplayer, bool observer);
161static bool aicmd_command(struct connection *caller, char *arg, bool check);
162static bool fcdb_command(struct connection *caller, char *arg, bool check);
163static const char *fcdb_accessor(int i);
164static char setting_status(struct connection *caller,
165 const struct setting *pset);
166static bool player_name_check(const char *name, char *buf, size_t buflen);
167static bool playercolor_command(struct connection *caller,
168 char *str, bool check);
169static bool playernation_command(struct connection *caller,
170 char *str, bool check);
171static bool mapimg_command(struct connection *caller, char *arg, bool check);
172static const char *mapimg_accessor(int i);
173
174static void show_delegations(struct connection *caller);
175
176 static const char horiz_line[] =
177"------------------------------------------------------------------------------";
178
179/**********************************************************************/
183 static bool is_restricted(struct connection *caller)
184{
185 return (caller && caller->access_level != ALLOW_HACK);
186}
187
188/**********************************************************************/
192 static bool player_name_check(const char *name, char *buf, size_t buflen)
193{
194 size_t len = strlen(name);
195
196 if (len == 0) {
197 fc_snprintf(buf, buflen, _("Can't use an empty name."));
198 return FALSE;
199 } else if (len > MAX_LEN_NAME-1) {
200 fc_snprintf(buf, buflen, _("That name exceeds the maximum of %d chars."),
201 MAX_LEN_NAME-1);
202 return FALSE;
203 } else if (fc_strcasecmp(name, ANON_PLAYER_NAME) == 0
204 || fc_strcasecmp(name, "Observer") == 0) {
205 fc_snprintf(buf, buflen, _("That name is not allowed."));
206 /* "Observer" used to be illegal and we keep it that way for now. */
207 /* FIXME: This disallows anonymous player name as it appears in English,
208 * but not one in any other language that the user may see. */
209 return FALSE;
210 }
211
212 return TRUE;
213}
214
215/**********************************************************************/
222 static enum command_id command_named(const char *token, bool accept_ambiguity)
223{
224 enum m_pre_result result;
225 int ind;
226
227 result = match_prefix(command_name_by_number, CMD_NUM, 0,
228 fc_strncasecmp, NULL, token, &ind);
229
230 if (result < M_PRE_AMBIGUOUS) {
231 return ind;
232 } else if (result == M_PRE_AMBIGUOUS) {
233 return accept_ambiguity ? ind : CMD_AMBIGUOUS;
234 } else {
235 return CMD_UNRECOGNIZED;
236 }
237}
238
239/**********************************************************************/
242 void stdinhand_init(void)
243{
244 fc_assert(NULL == kick_table_by_addr);
245 kick_table_by_addr = kick_hash_new();
246
247 fc_assert(NULL == kick_table_by_user);
248 kick_table_by_user = kick_hash_new();
249}
250
251/**********************************************************************/
255 void stdinhand_turn(void)
256{
257 /* Nothing at the moment. */
258}
259
260/**********************************************************************/
263 void stdinhand_free(void)
264{
265 fc_assert(NULL != kick_table_by_addr);
266 if (NULL != kick_table_by_addr) {
267 kick_hash_destroy(kick_table_by_addr);
268 kick_table_by_addr = NULL;
269 }
270
271 fc_assert(NULL != kick_table_by_user);
272 if (NULL != kick_table_by_user) {
273 kick_hash_destroy(kick_table_by_user);
274 kick_table_by_user = NULL;
275 }
276}
277
278/**********************************************************************/
282 static bool may_use(struct connection *caller, enum command_id cmd)
283{
284 if (!caller) {
285 return TRUE; /* on the console, everything is allowed */
286 }
287 return (caller->access_level >= command_level(command_by_number(cmd)));
288}
289
290/**********************************************************************/
294 static bool may_use_nothing(struct connection *caller)
295{
296 if (!caller) {
297 return FALSE; /* on the console, everything is allowed */
298 }
299 return (ALLOW_NONE == conn_get_access(caller));
300}
301
302/**********************************************************************/
306 static char setting_status(struct connection *caller,
307 const struct setting *pset)
308{
309 /* First check for a ruleset lock as this is included in
310 * setting_is_changeable() */
311 if (setting_locked(pset)) {
312 /* Setting is locked */
313 return '!';
314 }
315
316 if (setting_is_changeable(pset, caller, NULL, 0)) {
317 /* setting can be changed */
318 return '+';
319 }
320
321 /* setting is fixed */
322 return ' ';
323}
324
325/**********************************************************************/
332 static void cmd_reply_line(enum command_id cmd, struct connection *caller,
333 enum rfc_status rfc_status, const char *prefix,
334 const char *line)
335{
336 const char *cmdname = cmd < CMD_NUM
337 ? command_name_by_number(cmd)
338 : cmd == CMD_AMBIGUOUS
339 /* TRANS: ambiguous command */
340 ? _("(ambiguous)")
341 : cmd == CMD_UNRECOGNIZED
342 /* TRANS: unrecognized command */
343 ? _("(unknown)")
344 : "(?!?)"; /* this case is a bug! */
345
346 if (caller) {
347 notify_conn(caller->self, NULL, E_SETTING, ftc_command,
348 "/%s: %s%s", cmdname, prefix, line);
349 /* cc: to the console - testing has proved it's too verbose - rp
350 con_write(rfc_status, "%s/%s: %s%s", caller->name, cmdname, prefix, line);
351 */
352 } else {
353 con_write(rfc_status, "%s%s", prefix, line);
354 }
355
356 if (rfc_status == C_OK) {
357 struct packet_chat_msg packet;
358
359 package_event(&packet, NULL, E_SETTING, ftc_server, "%s", line);
360 conn_list_iterate(game.est_connections, pconn) {
361 /* Do not tell caller, since they were told above! */
362 if (caller != pconn) {
363 send_packet_chat_msg(pconn, &packet);
364 }
365 } conn_list_iterate_end;
366 event_cache_add_for_all(&packet);
367
368 if (NULL != caller) {
369 /* Echo to the console. */
370 log_normal("%s", line);
371 }
372 }
373}
374
375/**********************************************************************/
379 static void vcmd_reply_prefix(enum command_id cmd, struct connection *caller,
380 enum rfc_status rfc_status, const char *prefix,
381 const char *format, va_list ap)
382{
383 char buf[4096];
384 char *c0, *c1;
385
386 fc_vsnprintf(buf, sizeof(buf), format, ap);
387
388 c0 = buf;
389 while ((c1 = strstr(c0, "\n"))) {
390 *c1 = '\0';
391 cmd_reply_line(cmd, caller, rfc_status, (c0 == buf ? "" : prefix), c0);
392 c0 = c1 + 1;
393 }
394
395 cmd_reply_line(cmd, caller, rfc_status, (c0 == buf ? "" : prefix), c0);
396}
397
398/**********************************************************************/
402 static void cmd_reply_prefix(enum command_id cmd, struct connection *caller,
403 enum rfc_status rfc_status, const char *prefix,
404 const char *format, ...)
405 fc__attribute((__format__ (__printf__, 5, 6)));
406 static void cmd_reply_prefix(enum command_id cmd, struct connection *caller,
407 enum rfc_status rfc_status, const char *prefix,
408 const char *format, ...)
409{
410 va_list ap;
411 va_start(ap, format);
412 vcmd_reply_prefix(cmd, caller, rfc_status, prefix, format, ap);
413 va_end(ap);
414}
415
416/**********************************************************************/
419 void cmd_reply(enum command_id cmd, struct connection *caller,
420 enum rfc_status rfc_status, const char *format, ...)
421{
422 va_list ap;
423 va_start(ap, format);
424 vcmd_reply_prefix(cmd, caller, rfc_status, "", format, ap);
425 va_end(ap);
426}
427
428/**********************************************************************/
432 static void cmd_reply_no_such_player(enum command_id cmd,
433 struct connection *caller,
434 const char *name,
435 enum m_pre_result match_result)
436{
437 switch (match_result) {
438 case M_PRE_EMPTY:
439 cmd_reply(cmd, caller, C_SYNTAX,
440 _("Name is empty, so cannot be a player."));
441 break;
442 case M_PRE_LONG:
443 cmd_reply(cmd, caller, C_SYNTAX,
444 _("Name is too long, so cannot be a player."));
445 break;
446 case M_PRE_AMBIGUOUS:
447 cmd_reply(cmd, caller, C_FAIL,
448 _("Player name prefix '%s' is ambiguous."), name);
449 break;
450 case M_PRE_FAIL:
451 cmd_reply(cmd, caller, C_FAIL,
452 _("No player by the name of '%s'."), name);
453 break;
454 default:
455 cmd_reply(cmd, caller, C_FAIL,
456 _("Unexpected match_result %d (%s) for '%s'."),
457 match_result, _(m_pre_description(match_result)), name);
458 log_error("Unexpected match_result %d (%s) for '%s'.",
459 match_result, m_pre_description(match_result), name);
460 }
461}
462
463/**********************************************************************/
467 static void cmd_reply_no_such_conn(enum command_id cmd,
468 struct connection *caller,
469 const char *name,
470 enum m_pre_result match_result)
471{
472 switch (match_result) {
473 case M_PRE_EMPTY:
474 cmd_reply(cmd, caller, C_SYNTAX,
475 _("Name is empty, so cannot be a connection."));
476 break;
477 case M_PRE_LONG:
478 cmd_reply(cmd, caller, C_SYNTAX,
479 _("Name is too long, so cannot be a connection."));
480 break;
481 case M_PRE_AMBIGUOUS:
482 cmd_reply(cmd, caller, C_FAIL,
483 _("Connection name prefix '%s' is ambiguous."), name);
484 break;
485 case M_PRE_FAIL:
486 cmd_reply(cmd, caller, C_FAIL,
487 _("No connection by the name of '%s'."), name);
488 break;
489 default:
490 cmd_reply(cmd, caller, C_FAIL,
491 _("Unexpected match_result %d (%s) for '%s'."),
492 match_result, _(m_pre_description(match_result)), name);
493 log_error("Unexpected match_result %d (%s) for '%s'.",
494 match_result, m_pre_description(match_result), name);
495 }
496}
497
498/**********************************************************************/
501 static void open_metaserver_connection(struct connection *caller,
502 bool persistent)
503{
504 server_open_meta(persistent);
505 if (send_server_info_to_metaserver(META_INFO)) {
506 cmd_reply(CMD_METACONN, caller, C_OK,
507 _("Open metaserver connection to [%s]."),
508 meta_addr_port());
509 }
510}
511
512/**********************************************************************/
515 static void close_metaserver_connection(struct connection *caller)
516{
517 if (send_server_info_to_metaserver(META_GOODBYE)) {
518 server_close_meta();
519 cmd_reply(CMD_METACONN, caller, C_OK,
520 _("Close metaserver connection to [%s]."),
521 meta_addr_port());
522 }
523}
524
525/**********************************************************************/
528 static bool metaconnection_command(struct connection *caller, char *arg,
529 bool check)
530{
531 bool persistent = FALSE;
532
533 if ((*arg == '\0')
534 || (!strcmp(arg, "?"))) {
535 if (is_metaserver_open()) {
536 cmd_reply(CMD_METACONN, caller, C_COMMENT,
537 _("Metaserver connection is open."));
538 } else {
539 cmd_reply(CMD_METACONN, caller, C_COMMENT,
540 _("Metaserver connection is closed."));
541 }
542 return TRUE;
543 }
544
545 if (!fc_strcasecmp(arg, "p")
546 || !fc_strcasecmp(arg, "persistent")) {
547 persistent = TRUE;
548 }
549
550 if (persistent
551 || !fc_strcasecmp(arg, "u")
552 || !fc_strcasecmp(arg, "up")) {
553 if (!is_metaserver_open()) {
554 if (!check) {
555 open_metaserver_connection(caller, persistent);
556 }
557 } else {
558 cmd_reply(CMD_METACONN, caller, C_METAERROR,
559 _("Metaserver connection is already open."));
560 return FALSE;
561 }
562 } else if (!fc_strcasecmp(arg, "d")
563 || !fc_strcasecmp(arg, "down")) {
564 if (is_metaserver_open()) {
565 if (!check) {
566 close_metaserver_connection(caller);
567 }
568 } else {
569 cmd_reply(CMD_METACONN, caller, C_METAERROR,
570 _("Metaserver connection is already closed."));
571 return FALSE;
572 }
573 } else {
574 cmd_reply(CMD_METACONN, caller, C_METAERROR,
575 _("Argument must be 'u', 'up', 'd', 'down', 'p', 'persistent', or '?'."));
576 return FALSE;
577 }
578 return TRUE;
579}
580
581/**********************************************************************/
584 static bool metapatches_command(struct connection *caller,
585 char *arg, bool check)
586{
587 if (check) {
588 return TRUE;
589 }
590
591 set_meta_patches_string(arg);
592
593 if (is_metaserver_open()) {
594 send_server_info_to_metaserver(META_INFO);
595 cmd_reply(CMD_METAPATCHES, caller, C_OK,
596 _("Metaserver patches string set to '%s'."), arg);
597 } else {
598 cmd_reply(CMD_METAPATCHES, caller, C_OK,
599 _("Metaserver patches string set to '%s', "
600 "not reporting to metaserver."), arg);
601 }
602
603 return TRUE;
604}
605
606/**********************************************************************/
609 static bool metamessage_command(struct connection *caller,
610 char *arg, bool check)
611{
612 struct setting *pset;
613
614 log_deprecation(_("/metamessage command is deprecated. "
615 "Set metamessage setting instead."));
616
617 if (check) {
618 return TRUE;
619 }
620
621 set_user_meta_message_string(arg);
622 if (is_metaserver_open()) {
623 send_server_info_to_metaserver(META_INFO);
624 cmd_reply(CMD_METAMESSAGE, caller, C_OK,
625 _("Metaserver message string set to '%s'."), arg);
626 } else {
627 cmd_reply(CMD_METAMESSAGE, caller, C_OK,
628 _("Metaserver message string set to '%s', "
629 "not reporting to metaserver."), arg);
630 }
631
632 /* Metamessage is also a setting. */
633 pset = setting_by_name("metamessage");
634 setting_changed(pset);
635 send_server_setting(NULL, pset);
636
637 return TRUE;
638}
639
640/**********************************************************************/
643 static bool metaserver_command(struct connection *caller, char *arg,
644 bool check)
645{
646 if (check) {
647 return TRUE;
648 }
649 close_metaserver_connection(caller);
650
651 sz_strlcpy(srvarg.metaserver_addr, arg);
652
653 cmd_reply(CMD_METASERVER, caller, C_OK,
654 _("Metaserver is now [%s]."), meta_addr_port());
655 return TRUE;
656}
657
658/**********************************************************************/
661 static bool show_serverid(struct connection *caller, char *arg)
662{
663 cmd_reply(CMD_SRVID, caller, C_COMMENT, _("Server id: %s"), srvarg.serverid);
664
665 return TRUE;
666}
667
668/**********************************************************************/
672 static bool save_command(struct connection *caller, char *arg, bool check)
673{
674 if (is_restricted(caller)) {
675 cmd_reply(CMD_SAVE, caller, C_FAIL,
676 _("You cannot save games manually on this server."));
677 return FALSE;
678 }
679 if (!check) {
680 save_game(arg, "User request", FALSE);
681 }
682 return TRUE;
683}
684
685/**********************************************************************/
689 static bool scensave_command(struct connection *caller, char *arg, bool check)
690{
691 if (is_restricted(caller)) {
692 cmd_reply(CMD_SAVE, caller, C_FAIL,
693 _("You cannot save games manually on this server."));
694 return FALSE;
695 }
696 if (!check) {
697 save_game(arg, "Scenario", TRUE);
698 }
699 return TRUE;
700}
701
702/**********************************************************************/
705 void toggle_ai_player_direct(struct connection *caller, struct player *pplayer)
706{
707 fc_assert_ret(pplayer != NULL);
708
709 if (is_human(pplayer)) {
710 cmd_reply(CMD_AITOGGLE, caller, C_OK,
711 _("%s is now under AI control."),
712 player_name(pplayer));
713 player_set_to_ai_mode(pplayer,
714 !ai_level_is_valid(pplayer->ai_common.skill_level)
715 ? game.info.skill_level
716 : pplayer->ai_common.skill_level);
717 fc_assert(is_ai(pplayer));
718 } else {
719 cmd_reply(CMD_AITOGGLE, caller, C_OK,
720 _("%s is now under human control."),
721 player_name(pplayer));
722 player_set_under_human_control(pplayer);
723 fc_assert(is_human(pplayer));
724 }
725}
726
727/**********************************************************************/
730 static bool toggle_ai_command(struct connection *caller, char *arg, bool check)
731{
732 enum m_pre_result match_result;
733 struct player *pplayer;
734
735 pplayer = player_by_name_prefix(arg, &match_result);
736
737 if (!pplayer) {
738 cmd_reply_no_such_player(CMD_AITOGGLE, caller, arg, match_result);
739 return FALSE;
740 } else if (!check) {
741 toggle_ai_player_direct(caller, pplayer);
742 send_player_info_c(pplayer, game.est_connections);
743 }
744 return TRUE;
745}
746
747/**********************************************************************/
753 static bool create_command(struct connection *caller, const char *str,
754 bool check)
755{
756 enum rfc_status status;
757 char buf[MAX_LEN_CONSOLE_LINE];
758
759 /* 2 legal arguments, and extra space for stuffing illegal part */
760 char *arg[3];
761 int ntokens;
762 const char *ai_type_name;
763
764 sz_strlcpy(buf, str);
765 ntokens = get_tokens(buf, arg, 3, TOKEN_DELIMITERS);
766
767 if (ntokens == 1) {
768 ai_type_name = default_ai_type_name();
769 } else if (ntokens == 2) {
770 ai_type_name = arg[1];
771 } else {
772 cmd_reply(CMD_CREATE, caller, C_SYNTAX,
773 _("Wrong number of arguments to create command."));
774 free_tokens(arg, ntokens);
775 return FALSE;
776 }
777
778 if (game_was_started()) {
779 status = create_command_newcomer(arg[0], ai_type_name, check,
780 NULL, NULL, buf, sizeof(buf));
781 } else {
782 status = create_command_pregame(arg[0], ai_type_name, check,
783 NULL, buf, sizeof(buf));
784 }
785
786 free_tokens(arg, ntokens);
787
788 if (status != C_OK) {
789 /* No player created. */
790 cmd_reply(CMD_CREATE, caller, status, "%s", buf);
791 return FALSE;
792 }
793
794 if (strlen(buf) > 0) {
795 /* Send a notification. */
796 cmd_reply(CMD_CREATE, caller, C_OK, "%s", buf);
797 }
798
799 return TRUE;
800}
801
802/**********************************************************************/
811 enum rfc_status create_command_newcomer(const char *name,
812 const char *ai,
813 bool check,
814 struct nation_type *pnation,
815 struct player **newplayer,
816 char *buf, size_t buflen)
817{
818 struct player *pplayer = NULL;
819 struct research *presearch;
820 bool new_slot = FALSE;
821
822 /* Check player name. */
823 if (!player_name_check(name, buf, buflen)) {
824 return C_SYNTAX;
825 }
826
827 /* Check first if we can replace a player with
828 * [1a] - the same username. */
829 pplayer = player_by_user(name);
830 if (pplayer && pplayer->is_alive) {
831 fc_snprintf(buf, buflen,
832 _("A living user already exists by that name."));
833 return C_BOUNCE;
834 }
835
836 /* [1b] - the same player name. */
837 pplayer = player_by_name(name);
838 if (pplayer && pplayer->is_alive) {
839 fc_snprintf(buf, buflen,
840 _("A living player already exists by that name."));
841 return C_BOUNCE;
842 }
843
844 if (pnation) {
845 if (!nation_is_in_current_set(pnation)) {
846 fc_snprintf(buf, buflen,
847 _("Can't create player, requested nation %s not in "
848 "current nation set."),
849 nation_plural_translation(pnation));
850 return C_FAIL;
851 }
852 players_iterate(aplayer) {
853 if (0 > nations_match(pnation, nation_of_player(aplayer), FALSE)) {
854 fc_snprintf(buf, buflen,
855 _("Can't create players, nation %s conflicts with %s."),
856 nation_plural_for_player(aplayer),
857 nation_plural_for_player(pplayer));
858 return C_FAIL;
859 }
860 } players_iterate_end;
861 } else {
862 /* Try to find a nation. */
863 pnation = pick_a_nation(NULL, FALSE, TRUE, NOT_A_BARBARIAN);
864 if (pnation == NO_NATION_SELECTED) {
865 fc_snprintf(buf, buflen,
866 _("Can't create players, no nations available."));
867 return C_FAIL;
868 }
869 }
870
871 if (pplayer == NULL) {
872 if (player_count() == player_slot_count()) {
873 bool dead_found = FALSE;
874
875 players_iterate(aplayer) {
876 if (!aplayer->is_alive) {
877 dead_found = TRUE;
878 break;
879 }
880 } players_iterate_end;
881
882 if (!dead_found) {
883 fc_snprintf(buf, buflen,
884 _("Can't create players, no slots available."));
885 return C_FAIL;
886 }
887 } else if (normal_player_count() == game.server.max_players) {
888 fc_snprintf(buf, buflen,
889 _("Maxplayers setting prevents creation of more players."));
890 return C_FAIL;
891 }
892 }
893
894 if (check) {
895 /* All code below will change the game state. */
896
897 /* Return an empty string. */
898 buf[0] = '\0';
899
900 return C_OK;
901 }
902
903 if (pplayer) {
904 /* [1] Replace a player. 'pplayer' was set above. */
905 fc_snprintf(buf, buflen,
906 _("%s is replacing dead player %s as an AI-controlled "
907 "player."), name, player_name(pplayer));
908 /* remove player and thus free a player slot */
909 server_remove_player(pplayer);
910 pplayer = NULL;
911 } else if (player_count() == player_slot_count()) {
912 /* [2] All player slots are used; try to remove a dead player. */
913 bool dead_found = FALSE;
914
915 players_iterate(aplayer) {
916 if (!aplayer->is_alive) {
917 if (!dead_found) {
918 /* Fill the buffer with the name of the first found dead player */
919 fc_snprintf(buf, buflen,
920 _("%s is replacing dead player %s as an AI-controlled "
921 "player."), name, player_name(aplayer));
922 dead_found = TRUE;
923 }
924
925 /* Remove player and thus free a player slot */
926 server_remove_player(aplayer);
927 }
928
929 fc_assert(dead_found);
930 } players_iterate_end;
931 } else {
932 /* [3] An empty player slot must be used for the new player. */
933 new_slot = TRUE;
934 }
935
936 /* Create the new player. */
937 pplayer = server_create_player(-1, ai, NULL, FALSE);
938 if (!pplayer) {
939 fc_snprintf(buf, buflen, _("Failed to create new player %s."), name);
940 return C_FAIL;
941 }
942
943 if (new_slot) {
944 /* 'buf' must be set if a new player slot is used. */
945 fc_snprintf(buf, buflen, _("New player %s created."), name);
946 }
947
948 /* We have a player; now initialise all needed data. */
949 (void) aifill(game.info.aifill);
950
951 /* Initialise player. */
952 server_player_init(pplayer, TRUE, TRUE);
953
954 player_nation_defaults(pplayer, pnation, FALSE);
955 pplayer->government = pplayer->target_government =
956 init_government_of_nation(pnation);
957 /* Find a color for the new player. */
958 assign_player_colors();
959
960 /* TRANS: keep one space at the beginning of the string. */
961 cat_snprintf(buf, buflen, _(" Nation of the new player: %s."),
962 nation_rule_name(pnation));
963
964 presearch = research_get(pplayer);
965 init_tech(presearch, TRUE);
966 give_initial_techs(presearch, 0);
967
968 server_player_set_name(pplayer, name);
969 sz_strlcpy(pplayer->username, _(ANON_USER_NAME));
970 pplayer->unassigned_user = TRUE;
971
972 pplayer->was_created = TRUE; /* must use /remove explicitly to remove */
973 set_as_ai(pplayer);
974 set_ai_level_directer(pplayer, game.info.skill_level);
975
976 CALL_PLR_AI_FUNC(gained_control, pplayer, pplayer);
977
978 send_player_info_c(pplayer, NULL);
979 /* Send updated diplstate information to all players. */
980 send_player_diplstate_c(NULL, NULL);
981 /* Send research info after player info, else the client will complain
982 * about invalid team. */
983 send_research_info(presearch, NULL);
984 (void) send_server_info_to_metaserver(META_INFO);
985
986 if (newplayer != NULL) {
987 *newplayer = pplayer;
988 }
989 return C_OK;
990}
991
992/**********************************************************************/
995 enum rfc_status create_command_pregame(const char *name,
996 const char *ai,
997 bool check,
998 struct player **newplayer,
999 char *buf, size_t buflen)
1000{
1001 char leader_name[MAX_LEN_NAME]; /* Must be in whole function scope */
1002 struct player *pplayer = NULL;
1003 bool rand_name = FALSE;
1004
1005 if (name[0] == '\0') {
1006 int filled = 1;
1007
1008 do {
1009 fc_snprintf(leader_name, sizeof(leader_name), "%s*%d", ai, filled++);
1010 } while (player_by_name(leader_name));
1011
1012 name = leader_name;
1013 rand_name = TRUE;
1014 }
1015
1016 if (!player_name_check(name, buf, buflen)) {
1017 return C_SYNTAX;
1018 }
1019
1020 if (NULL != player_by_name(name)) {
1021 fc_snprintf(buf, buflen,
1022 _("A player already exists by that name."));
1023 return C_BOUNCE;
1024 }
1025 if (NULL != player_by_user(name)) {
1026 fc_snprintf(buf, buflen,
1027 _("A user already exists by that name."));
1028 return C_BOUNCE;
1029 }
1030
1031 /* Search for first uncontrolled player */
1032 pplayer = find_uncontrolled_player();
1033
1034 if (NULL == pplayer) {
1035 /* Check that we are not going over max players setting */
1036 if (normal_player_count() >= game.server.max_players) {
1037 fc_snprintf(buf, buflen,
1038 _("Can't add more players, server is full."));
1039 return C_FAIL;
1040 }
1041 /* Check that we have nations available */
1042 if (normal_player_count() >= server.playable_nations) {
1043 if (nation_set_count() > 1) {
1044 fc_snprintf(buf, buflen,
1045 _("Can't add more players, not enough playable nations "
1046 "in current nation set (see 'nationset' setting)."));
1047 } else {
1048 fc_snprintf(buf, buflen,
1049 _("Can't add more players, not enough playable nations."));
1050 }
1051 return C_FAIL;
1052 }
1053 }
1054
1055 if (pplayer) {
1056 struct ai_type *ait = ai_type_by_name(ai);
1057
1058 if (ait == NULL) {
1059 fc_snprintf(buf, buflen,
1060 _("There is no AI type %s."), ai);
1061 return C_FAIL;
1062 }
1063 }
1064
1065 if (check) {
1066 /* All code below will change the game state. */
1067
1068 /* Return an empty string. */
1069 buf[0] = '\0';
1070
1071 return C_OK;
1072 }
1073
1074 if (pplayer) {
1075 fc_snprintf(buf, buflen,
1076 /* TRANS: <name> replacing <name> ... */
1077 _("%s replacing %s as an AI-controlled player."),
1078 name, player_name(pplayer));
1079
1080 team_remove_player(pplayer);
1081 pplayer->ai = ai_type_by_name(ai);
1082 } else {
1083 /* add new player */
1084 pplayer = server_create_player(-1, ai, NULL, FALSE);
1085 /* pregame so no need to assign_player_colors() */
1086 if (!pplayer) {
1087 fc_snprintf(buf, buflen,
1088 _("Failed to create new player %s."), name);
1089 return C_GENFAIL;
1090 }
1091
1092 fc_snprintf(buf, buflen,
1093 _("%s has been added as an AI-controlled player (%s)."),
1094 name, ai_name(pplayer->ai));
1095 }
1096 server_player_init(pplayer, FALSE, TRUE);
1097
1098 server_player_set_name(pplayer, name);
1099 sz_strlcpy(pplayer->username, _(ANON_USER_NAME));
1100 pplayer->unassigned_user = TRUE;
1101
1102 pplayer->was_created = TRUE; /* must use /remove explicitly to remove */
1103 pplayer->random_name = rand_name;
1104 set_as_ai(pplayer);
1105 set_ai_level_directer(pplayer, game.info.skill_level);
1106 CALL_PLR_AI_FUNC(gained_control, pplayer, pplayer);
1107 send_player_info_c(pplayer, game.est_connections);
1108
1109 (void) aifill(game.info.aifill);
1110 reset_all_start_commands(TRUE);
1111 (void) send_server_info_to_metaserver(META_INFO);
1112
1113 if (newplayer != NULL) {
1114 *newplayer = pplayer;
1115 }
1116 return C_OK;
1117}
1118
1119/**********************************************************************/
1122 static bool remove_player_command(struct connection *caller, char *arg,
1123 bool check)
1124{
1125 enum m_pre_result match_result;
1126 struct player *pplayer;
1127 char name[MAX_LEN_NAME];
1128
1129 pplayer = player_by_name_prefix(arg, &match_result);
1130
1131 if (NULL == pplayer) {
1132 cmd_reply_no_such_player(CMD_REMOVE, caller, arg, match_result);
1133 return FALSE;
1134 }
1135
1136 if (game_was_started() && caller && caller->access_level < ALLOW_ADMIN) {
1137 cmd_reply(CMD_REMOVE, caller, C_FAIL,
1138 _("Command level '%s' or greater needed to remove a player "
1139 "once the game has started."), cmdlevel_name(ALLOW_ADMIN));
1140 return FALSE;
1141 }
1142 if (check) {
1143 return TRUE;
1144 }
1145
1146 sz_strlcpy(name, player_name(pplayer));
1147 server_remove_player(pplayer);
1148 if (!caller || caller->used) { /* may have removed self */
1149 cmd_reply(CMD_REMOVE, caller, C_OK,
1150 _("Removed player %s from the game."), name);
1151 }
1152 (void) aifill(game.info.aifill);
1153 return TRUE;
1154}
1155
1156/**********************************************************************/
1159 static bool read_command(struct connection *caller, char *arg, bool check,
1160 int read_recursion)
1161{
1162 return read_init_script_real(caller, arg, FALSE, check, read_recursion);
1163}
1164
1165/**********************************************************************/
1168 bool read_init_script(struct connection *caller, const char *script_filename,
1169 bool from_cmdline, bool check)
1170{
1171 return read_init_script_real(caller, script_filename, from_cmdline,
1172 check, 0);
1173}
1174
1175/**********************************************************************/
1186 static bool read_init_script_real(struct connection *caller,
1187 const char *script_filename, bool from_cmdline,
1188 bool check, int read_recursion)
1189{
1190 FILE *script_file;
1191 char serv_filename[strlen(script_extension) + strlen(script_filename) + 2];
1192 char tilde_filename[4096];
1193 const char *real_filename;
1194 size_t fnlen;
1195
1196 /* check recursion depth */
1197 if (read_recursion > GAME_MAX_READ_RECURSION) {
1198 log_error("Error: recursive calls to read!");
1199 return FALSE;
1200 }
1201
1202 /* abuse real_filename to find if we already have a .serv extension */
1203 fnlen = strlen(script_filename);
1204 real_filename = script_filename + fnlen
1205 - MIN(strlen(script_extension), fnlen);
1206 if (strcmp(real_filename, script_extension) != 0) {
1207 fc_snprintf(serv_filename, sizeof(serv_filename), "%s%s",
1208 script_filename, script_extension);
1209 } else {
1210 sz_strlcpy(serv_filename, script_filename);
1211 }
1212
1213 if (is_restricted(caller) && !from_cmdline) {
1214 if (!is_safe_filename(serv_filename)) {
1215 cmd_reply(CMD_READ_SCRIPT, caller, C_FAIL,
1216 _("Name \"%s\" disallowed for security reasons."),
1217 serv_filename);
1218 return FALSE;
1219 }
1220 sz_strlcpy(tilde_filename, serv_filename);
1221 } else {
1222 interpret_tilde(tilde_filename, sizeof(tilde_filename), serv_filename);
1223 }
1224
1225 real_filename = fileinfoname(get_data_dirs(), tilde_filename);
1226 if (!real_filename) {
1227 if (is_restricted(caller) && !from_cmdline) {
1228 cmd_reply(CMD_READ_SCRIPT, caller, C_FAIL,
1229 _("No command script found by the name \"%s\"."),
1230 serv_filename);
1231 return FALSE;
1232 }
1233 /* File is outside data directories */
1234 real_filename = tilde_filename;
1235 }
1236
1237 log_testmatic_alt(LOG_NORMAL, _("Loading script file '%s'."), real_filename);
1238
1239 if (is_reg_file_for_access(real_filename, FALSE)
1240 && (script_file = fc_fopen(real_filename, "r"))) {
1241 char buffer[MAX_LEN_CONSOLE_LINE];
1242
1243 /* The size is set as to not overflow buffer in handle_stdin_input */
1244 while (fgets(buffer, MAX_LEN_CONSOLE_LINE - 1, script_file)) {
1245 /* Execute script contents with same permissions as caller */
1246 handle_stdin_input_real(caller, buffer, check, read_recursion + 1);
1247 }
1248 fclose(script_file);
1249
1250 show_ruleset_info(caller, CMD_READ_SCRIPT, check, read_recursion);
1251
1252 return TRUE;
1253 } else {
1254 cmd_reply(CMD_READ_SCRIPT, caller, C_FAIL,
1255 _("Cannot read command line scriptfile '%s'."), real_filename);
1256 if (NULL != caller) {
1257 log_error(_("Could not read script file '%s'."), real_filename);
1258 }
1259 return FALSE;
1260 }
1261}
1262
1263/**********************************************************************/
1269 struct strvec *get_init_script_choices(void)
1270{
1271 return fileinfolist(get_data_dirs(), RULESET_SUFFIX);
1272}
1273
1274/**********************************************************************/
1279 static bool write_init_script(char *script_filename)
1280{
1281 char real_filename[1024], buf[256];
1282 FILE *script_file;
1283
1284 interpret_tilde(real_filename, sizeof(real_filename), script_filename);
1285
1286 if (is_reg_file_for_access(real_filename, TRUE)
1287 && (script_file = fc_fopen(real_filename, "w"))) {
1288 fprintf(script_file,
1289 "#FREECIV SERVER COMMAND FILE, version %s\n", VERSION_STRING);
1290 fputs("# These are server options saved from a running freeciv-server.\n",
1291 script_file);
1292
1293 /* First rulesetdir. Setting rulesetdir resets the settings to their
1294 * default value, so they would be lost if placed before this. */
1295 fprintf(script_file, "rulesetdir %s\n", game.server.rulesetdir);
1296
1297 /* Some state info from commands (we can't save everything) */
1298
1299 fprintf(script_file, "cmdlevel %s new\n",
1300 cmdlevel_name(default_access_level));
1301
1302 fprintf(script_file, "cmdlevel %s first\n",
1303 cmdlevel_name(first_access_level));
1304
1305 fprintf(script_file, "%s\n",
1306 ai_level_cmd(game.info.skill_level));
1307
1308 if (*srvarg.metaserver_addr != '\0'
1309 && ((0 != strcmp(srvarg.metaserver_addr, DEFAULT_META_SERVER_ADDR)))) {
1310 fprintf(script_file, "metaserver %s\n", meta_addr_port());
1311 }
1312
1313 if (0 != strcmp(get_meta_patches_string(), default_meta_patches_string())) {
1314 fprintf(script_file, "metapatches %s\n", get_meta_patches_string());
1315 }
1316 if (0 != strcmp(get_meta_message_string(), default_meta_message_string())) {
1317 fprintf(script_file, "metamessage %s\n", get_meta_message_string());
1318 }
1319
1320 /* Then, the 'set' option settings */
1321
1322 settings_iterate(SSET_ALL, pset) {
1323 fprintf(script_file, "set %s \"%s\"\n", setting_name(pset),
1324 setting_value_name(pset, FALSE, buf, sizeof(buf)));
1325 } settings_iterate_end;
1326
1327 fclose(script_file);
1328
1329 return TRUE;
1330 } else {
1331 log_error(_("Could not write script file '%s'."), real_filename);
1332
1333 return FALSE;
1334 }
1335}
1336
1337/**********************************************************************/
1340 static bool write_command(struct connection *caller, char *arg, bool check)
1341{
1342 if (is_restricted(caller)) {
1343 cmd_reply(CMD_WRITE_SCRIPT, caller, C_FAIL,
1344 _("You cannot use the write command on this server"
1345 " for security reasons."));
1346 return FALSE;
1347 } else if (!check) {
1348 char serv_filename[strlen(script_extension) + strlen(arg) + 2];
1349 const char *real_filename;
1350 size_t arglen = strlen(arg);
1351
1352 /* abuse real_filename to find if we already have a .serv extension */
1353 real_filename = arg + arglen - MIN(strlen(script_extension), arglen);
1354 if (strcmp(real_filename, script_extension) != 0) {
1355 fc_snprintf(serv_filename, sizeof(serv_filename), "%s%s",
1356 arg, script_extension);
1357 } else {
1358 sz_strlcpy(serv_filename, arg);
1359 }
1360
1361 if (!write_init_script(serv_filename)) {
1362 cmd_reply(CMD_WRITE_SCRIPT, caller, C_FAIL,
1363 /* TRANS: Failed to write server script, e.g., 'example.serv' */
1364 _("Failed to write %s."), serv_filename);
1365 return FALSE;
1366 }
1367
1368 cmd_reply(CMD_WRITE_SCRIPT, caller, C_OK,
1369 /* TRANS: Wrote server script, e.g., 'example.serv' */
1370 _("Wrote %s."), serv_filename);
1371 }
1372
1373 return TRUE;
1374}
1375
1376/**********************************************************************/
1379 static bool set_cmdlevel(struct connection *caller,
1380 struct connection *ptarget,
1381 enum cmdlevel level)
1382{
1383 /* Only ever call me for specific connection. */
1384 fc_assert_ret_val(ptarget != NULL, FALSE);
1385
1386 if (caller && ptarget->access_level > caller->access_level) {
1387 /*
1388 * This command is intended to be used at ctrl access level
1389 * and thus this if clause is needed.
1390 * (Imagine a ctrl level access player that wants to change
1391 * access level of a hack level access player)
1392 * At the moment it can be used only by hack access level
1393 * and thus this clause is never used.
1394 */
1395 cmd_reply(CMD_CMDLEVEL, caller, C_FAIL,
1396 _("Cannot decrease command access level '%s' "
1397 "for connection '%s'; you only have '%s'."),
1398 cmdlevel_name(ptarget->access_level),
1399 ptarget->username,
1400 cmdlevel_name(caller->access_level));
1401 return FALSE;
1402 } else {
1403 conn_set_access(ptarget, level, TRUE);
1404 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1405 _("Command access level set to '%s' for connection %s."),
1406 cmdlevel_name(level), ptarget->username);
1407 return TRUE;
1408 }
1409}
1410
1411/**********************************************************************/
1414 static bool a_connection_exists(void)
1415{
1416 return conn_list_size(game.est_connections) > 0;
1417}
1418
1419/**********************************************************************/
1422 static bool is_first_access_level_taken(void)
1423{
1424 conn_list_iterate(game.est_connections, pconn) {
1425 if (pconn->access_level >= first_access_level) {
1426 return TRUE;
1427 }
1428 }
1429 conn_list_iterate_end;
1430 return FALSE;
1431}
1432
1433/**********************************************************************/
1436 enum cmdlevel access_level_for_next_connection(void)
1437{
1438 if ((first_access_level > default_access_level)
1439 && !a_connection_exists()) {
1440 return first_access_level;
1441 } else {
1442 return default_access_level;
1443 }
1444}
1445
1446/**********************************************************************/
1450 void notify_if_first_access_level_is_available(void)
1451{
1452 if (first_access_level > default_access_level
1453 && !is_first_access_level_taken()) {
1454 notify_conn(NULL, NULL, E_SETTING, ftc_any,
1455 _("Anyone can now become game organizer "
1456 "'%s' by issuing the 'first' command."),
1457 cmdlevel_name(first_access_level));
1458 }
1459}
1460
1461/**********************************************************************/
1464 static bool cmdlevel_command(struct connection *caller, char *str, bool check)
1465{
1466 char *arg[2];
1467 int ntokens;
1468 bool ret = FALSE;
1469 enum m_pre_result match_result;
1470 enum cmdlevel level;
1471 struct connection *ptarget;
1472
1473 ntokens = get_tokens(str, arg, 2, TOKEN_DELIMITERS);
1474
1475 if (ntokens == 0) {
1476 /* No argument supplied; list the levels */
1477 cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, horiz_line);
1478 cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT,
1479 _("Command access levels in effect:"));
1480 cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, horiz_line);
1481 conn_list_iterate(game.est_connections, pconn) {
1482 const char *lvl_name = cmdlevel_name(conn_get_access(pconn));
1483
1484 if (lvl_name != NULL) {
1485 cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, "cmdlevel %s %s",
1486 lvl_name, pconn->username);
1487 } else {
1488 fc_assert(lvl_name != NULL); /* Always fails when reached. */
1489 }
1490 } conn_list_iterate_end;
1491 cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT,
1492 _("Command access level for new connections: %s"),
1493 cmdlevel_name(default_access_level));
1494 cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT,
1495 _("Command access level for first player to take it: %s"),
1496 cmdlevel_name(first_access_level));
1497 cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, horiz_line);
1498 return TRUE;
1499 }
1500
1501 /* A level name was supplied; set the level. */
1502 level = cmdlevel_by_name(arg[0], fc_strcasecmp);
1503 if (!cmdlevel_is_valid(level)) {
1504 const char *cmdlevel_names[CMDLEVEL_COUNT];
1505 struct astring astr = ASTRING_INIT;
1506 int i = 0;
1507
1508 for (level = cmdlevel_begin(); level != cmdlevel_end();
1509 level = cmdlevel_next(level)) {
1510 cmdlevel_names[i++] = cmdlevel_name(level);
1511 }
1512 cmd_reply(CMD_CMDLEVEL, caller, C_SYNTAX,
1513 /* TRANS: comma and 'or' separated list of access levels */
1514 _("Command access level must be one of %s."),
1515 astr_build_or_list(&astr, cmdlevel_names, i));
1516 astr_free(&astr);
1517 goto CLEAN_UP;
1518 } else if (caller && level > conn_get_access(caller)) {
1519 cmd_reply(CMD_CMDLEVEL, caller, C_FAIL,
1520 _("Cannot increase command access level to '%s';"
1521 " you only have '%s' yourself."),
1522 arg[0], cmdlevel_name(conn_get_access(caller)));
1523 goto CLEAN_UP;
1524 }
1525
1526 if (check) {
1527 return TRUE; /* looks good */
1528 }
1529
1530 if (ntokens == 1) {
1531 /* No playername supplied: set for all connections */
1532 conn_list_iterate(game.est_connections, pconn) {
1533 if (pconn != caller) {
1534 (void) set_cmdlevel(caller, pconn, level);
1535 }
1536 } conn_list_iterate_end;
1537
1538 /* Set the caller access level at last, because it could make the
1539 * previous operations impossible if set before. */
1540 if (caller) {
1541 (void) set_cmdlevel(caller, caller, level);
1542 }
1543
1544 /* Set default access for new connections. */
1545 default_access_level = level;
1546 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1547 _("Command access level set to '%s' for new players."),
1548 cmdlevel_name(level));
1549 /* Set default access for first connection. */
1550 first_access_level = level;
1551 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1552 _("Command access level set to '%s' "
1553 "for first player to grab it."),
1554 cmdlevel_name(level));
1555
1556 ret = TRUE;
1557
1558 } else if (fc_strcasecmp(arg[1], "new") == 0) {
1559 default_access_level = level;
1560 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1561 _("Command access level set to '%s' for new players."),
1562 cmdlevel_name(level));
1563 if (level > first_access_level) {
1564 first_access_level = level;
1565 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1566 _("Command access level set to '%s' "
1567 "for first player to grab it."),
1568 cmdlevel_name(level));
1569 }
1570
1571 ret = TRUE;
1572
1573 } else if (fc_strcasecmp(arg[1], "first") == 0) {
1574 first_access_level = level;
1575 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1576 _("Command access level set to '%s' "
1577 "for first player to grab it."),
1578 cmdlevel_name(level));
1579 if (level < default_access_level) {
1580 default_access_level = level;
1581 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1582 _("Command access level set to '%s' for new players."),
1583 cmdlevel_name(level));
1584 }
1585
1586 ret = TRUE;
1587
1588 } else if ((ptarget = conn_by_user_prefix(arg[1], &match_result))) {
1589 if (set_cmdlevel(caller, ptarget, level)) {
1590 ret = TRUE;
1591 }
1592 } else {
1593 cmd_reply_no_such_conn(CMD_CMDLEVEL, caller, arg[1], match_result);
1594 }
1595
1596 CLEAN_UP:
1597 free_tokens(arg, ntokens);
1598 return ret;
1599}
1600
1601/**********************************************************************/
1607 static bool firstlevel_command(struct connection *caller, bool check)
1608{
1609 if (!caller) {
1610 cmd_reply(CMD_FIRSTLEVEL, caller, C_FAIL,
1611 _("The 'first' command makes no sense from the server command line."));
1612 return FALSE;
1613 } else if (caller->access_level >= first_access_level) {
1614 cmd_reply(CMD_FIRSTLEVEL, caller, C_FAIL,
1615 _("You already have command access level '%s' or better."),
1616 cmdlevel_name(first_access_level));
1617 return FALSE;
1618 } else if (is_first_access_level_taken()) {
1619 cmd_reply(CMD_FIRSTLEVEL, caller, C_FAIL,
1620 _("Someone else is already game organizer."));
1621 return FALSE;
1622 } else if (!check) {
1623 conn_set_access(caller, first_access_level, FALSE);
1624 cmd_reply(CMD_FIRSTLEVEL, caller, C_OK,
1625 _("Connection %s has opted to become the game organizer."),
1626 caller->username);
1627 }
1628 return TRUE;
1629}
1630
1631/**********************************************************************/
1634 void set_running_game_access_level(void)
1635{
1636 if (default_access_level > ALLOW_BASIC) {
1637 notify_conn(NULL, NULL, E_SETTING, ftc_server,
1638 _("Default cmdlevel lowered to 'basic' on game start."));
1639 default_access_level = ALLOW_BASIC;
1640 }
1641}
1642
1643/**********************************************************************/
1647 static const char *optname_accessor(int i)
1648{
1649 return setting_name(setting_by_number(i));
1650}
1651
1652#ifdef FREECIV_HAVE_LIBREADLINE
1653/**********************************************************************/
1656static const char *olvlname_accessor(int i)
1657{
1658 if (i == 0) {
1659 return "rulesetdir";
1660 } else if (i < OLEVELS_NUM+1) {
1661 return sset_level_name(i-1);
1662 } else {
1663 return optname_accessor(i-OLEVELS_NUM-1);
1664 }
1665}
1666#endif /* FREECIV_HAVE_LIBREADLINE */
1667
1668/**********************************************************************/
1671 static bool timeout_command(struct connection *caller, char *str, bool check)
1672{
1673 char buf[MAX_LEN_CONSOLE_LINE];
1674 char *arg[4];
1675 int i = 0, ntokens;
1676 int *timeouts[4];
1677
1678 timeouts[0] = &game.server.timeoutint;
1679 timeouts[1] = &game.server.timeoutintinc;
1680 timeouts[2] = &game.server.timeoutinc;
1681 timeouts[3] = &game.server.timeoutincmult;
1682
1683 sz_strlcpy(buf, str);
1684 ntokens = get_tokens(buf, arg, 4, TOKEN_DELIMITERS);
1685
1686 for (i = 0; i < ntokens; i++) {
1687 if (!str_to_int(arg[i], timeouts[i])) {
1688 cmd_reply(CMD_TIMEOUT, caller, C_FAIL, _("Invalid argument %d."),
1689 i + 1);
1690 }
1691 free(arg[i]);
1692 }
1693
1694 if (ntokens == 0) {
1695 cmd_reply(CMD_TIMEOUT, caller, C_SYNTAX, _("Usage:\n%s"),
1696 command_synopsis(command_by_number(CMD_TIMEOUT)));
1697 return FALSE;
1698 } else if (check) {
1699 return TRUE;
1700 }
1701
1702 cmd_reply(CMD_TIMEOUT, caller, C_OK, _("Dynamic timeout set to "
1703 "%d %d %d %d"),
1704 game.server.timeoutint, game.server.timeoutintinc,
1705 game.server.timeoutinc, game.server.timeoutincmult);
1706
1707 /* if we set anything here, reset the counter */
1708 game.server.timeoutcounter = 1;
1709 return TRUE;
1710}
1711
1712/**********************************************************************/
1715 static enum sset_level lookup_option_level(const char *name)
1716{
1717 enum sset_level i;
1718
1719 for (i = SSET_ALL; i < OLEVELS_NUM; i++) {
1720 if (0 == fc_strcasecmp(name, sset_level_name(i))) {
1721 return i;
1722 }
1723 }
1724
1725 return SSET_NONE;
1726}
1727
1728/* Special return values of lookup options */
1729#define LOOKUP_OPTION_NO_RESULT (-1)
1730#define LOOKUP_OPTION_AMBIGUOUS (-2)
1731#define LOOKUP_OPTION_LEVEL_NAME (-3)
1732#define LOOKUP_OPTION_RULESETDIR (-4)
1733
1734/**********************************************************************/
1741 static int lookup_option(const char *name)
1742{
1743 enum m_pre_result result;
1744 int ind;
1745
1746 /* Check for option levels, first off */
1747 if (lookup_option_level(name) != SSET_NONE) {
1748 return LOOKUP_OPTION_LEVEL_NAME;
1749 }
1750
1751 result = match_prefix(optname_accessor, settings_number(),
1752 0, fc_strncasecmp, NULL, name, &ind);
1753 if (M_PRE_AMBIGUOUS > result) {
1754 return ind;
1755 } else if (M_PRE_AMBIGUOUS == result) {
1756 return LOOKUP_OPTION_AMBIGUOUS;
1757 } else if ('\0' != name[0]
1758 && 0 == fc_strncasecmp("rulesetdir", name, strlen(name))) {
1759 return LOOKUP_OPTION_RULESETDIR;
1760 } else {
1761 return LOOKUP_OPTION_NO_RESULT;
1762 }
1763}
1764
1765/**********************************************************************/
1770 static void show_help_option(struct connection *caller,
1771 enum command_id help_cmd, int id)
1772{
1773 char val_buf[256], def_buf[256];
1774 struct setting *pset = setting_by_number(id);
1775 const char *sethelp;
1776
1777 if (setting_short_help(pset)) {
1778 cmd_reply(help_cmd, caller, C_COMMENT,
1779 /* TRANS: <untranslated name> - translated short help */
1780 _("Option: %s - %s"), setting_name(pset),
1781 _(setting_short_help(pset)));
1782 } else {
1783 cmd_reply(help_cmd, caller, C_COMMENT,
1784 /* TRANS: <untranslated name> */
1785 _("Option: %s"), setting_name(pset));
1786 }
1787
1788 sethelp = setting_extra_help(pset, FALSE);
1789 if (strlen(sethelp) > 0) {
1790 char *help = fc_strdup(sethelp);
1791
1792 fc_break_lines(help, LINE_BREAK);
1793 cmd_reply(help_cmd, caller, C_COMMENT, _("Description:"));
1794 cmd_reply_prefix(help_cmd, caller, C_COMMENT, " ", " %s", help);
1795 FC_FREE(help);
1796 }
1797 cmd_reply(help_cmd, caller, C_COMMENT,
1798 _("Status: %s"), (setting_is_changeable(pset, NULL, NULL, 0)
1799 ? _("changeable") : _("fixed")));
1800
1801 if (setting_is_visible(pset, caller)) {
1802 setting_value_name(pset, TRUE, val_buf, sizeof(val_buf));
1803 setting_default_name(pset, TRUE, def_buf, sizeof(def_buf));
1804
1805 switch (setting_type(pset)) {
1806 case SST_INT:
1807 cmd_reply(help_cmd, caller, C_COMMENT, "%s %s, %s %d, %s %s, %s %d",
1808 _("Value:"), val_buf,
1809 _("Minimum:"), setting_int_min(pset),
1810 _("Default:"), def_buf,
1811 _("Maximum:"), setting_int_max(pset));
1812 break;
1813 case SST_ENUM:
1814 {
1815 int i;
1816 const char *value;
1817
1818 cmd_reply(help_cmd, caller, C_COMMENT, _("Possible values:"));
1819 for (i = 0; (value = setting_enum_val(pset, i, FALSE)); i++) {
1820 cmd_reply(help_cmd, caller, C_COMMENT, "- %s: \"%s\"",
1821 value, setting_enum_val(pset, i, TRUE));
1822 }
1823 }
1824
1825 fc__fallthrough;
1826 case SST_BOOL:
1827 case SST_STRING:
1828 cmd_reply(help_cmd, caller, C_COMMENT, "%s %s, %s %s",
1829 _("Value:"), val_buf, _("Default:"), def_buf);
1830 break;
1831 case SST_BITWISE:
1832 {
1833 int i;
1834 const char *value;
1835
1836 cmd_reply(help_cmd, caller, C_COMMENT,
1837 _("Possible values (option can take any number of these):"));
1838 for (i = 0; (value = setting_bitwise_bit(pset, i, FALSE)); i++) {
1839 cmd_reply(help_cmd, caller, C_COMMENT, "- %s: \"%s\"",
1840 value, setting_bitwise_bit(pset, i, TRUE));
1841 }
1842 cmd_reply(help_cmd, caller, C_COMMENT, "%s %s",
1843 _("Value:"), val_buf);
1844 cmd_reply(help_cmd, caller, C_COMMENT, "%s %s",
1845 _("Default:"), def_buf);
1846 }
1847 break;
1848 case SST_COUNT:
1849 fc_assert(setting_type(pset) != SST_COUNT);
1850 break;
1851 }
1852 }
1853}
1854
1855/**********************************************************************/
1860 static void show_help_option_list(struct connection *caller,
1861 enum command_id help_cmd)
1862{
1863 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
1864 cmd_reply(help_cmd, caller, C_COMMENT,
1865 _("Explanations are available for the following server options:"));
1866 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
1867 if (!caller && con_get_style()) {
1868 settings_iterate(SSET_ALL, pset) {
1869 cmd_reply(help_cmd, caller, C_COMMENT, "%s", setting_name(pset));
1870 } settings_iterate_end
1871 } else {
1872 char buf[MAX_LEN_CONSOLE_LINE];
1873 int j = 0;
1874 buf[0] = '\0';
1875
1876 settings_iterate(SSET_ALL, pset) {
1877 if (setting_is_visible(pset, caller)) {
1878 cat_snprintf(buf, sizeof(buf), "%-19s", setting_name(pset));
1879 if ((++j % 4) == 0) {
1880 cmd_reply(help_cmd, caller, C_COMMENT, "%s", buf);
1881 buf[0] = '\0';
1882 }
1883 }
1884 } settings_iterate_end;
1885
1886 if (buf[0] != '\0') {
1887 cmd_reply(help_cmd, caller, C_COMMENT, "%s", buf);
1888 }
1889 }
1890 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
1891}
1892
1893/**********************************************************************/
1896 static bool explain_option(struct connection *caller, char *str, bool check)
1897{
1898 int cmd;
1899
1900 remove_leading_trailing_spaces(str);
1901
1902 if (*str != '\0') {
1903 cmd = lookup_option(str);
1904 if (cmd >= 0 && cmd < settings_number()) {
1905 show_help_option(caller, CMD_EXPLAIN, cmd);
1906 } else if (cmd == LOOKUP_OPTION_NO_RESULT
1907 || cmd == LOOKUP_OPTION_LEVEL_NAME
1908 || cmd == LOOKUP_OPTION_RULESETDIR) {
1909 cmd_reply(CMD_EXPLAIN, caller, C_FAIL,
1910 _("No explanation for that yet."));
1911 return FALSE;
1912 } else if (cmd == LOOKUP_OPTION_AMBIGUOUS) {
1913 cmd_reply(CMD_EXPLAIN, caller, C_FAIL, _("Ambiguous option name."));
1914 return FALSE;
1915 } else {
1916 log_error("Unexpected case %d in %s line %d", cmd, __FILE__,
1917 __FC_LINE__);
1918 return FALSE;
1919 }
1920 } else {
1921 show_help_option_list(caller, CMD_EXPLAIN);
1922 }
1923 return TRUE;
1924}
1925
1926/**********************************************************************/
1929 static bool wall(char *str, bool check)
1930{
1931 if (!check) {
1932 notify_conn(NULL, NULL, E_MESSAGE_WALL, ftc_server_prompt,
1933 _("Server Operator: %s"), str);
1934 }
1935 return TRUE;
1936}
1937
1938/**********************************************************************/
1941 static bool connectmsg_command(struct connection *caller, char *str,
1942 bool check)
1943{
1944 unsigned int bufsize = sizeof(game.server.connectmsg);
1945
1946 if (is_restricted(caller)) {
1947 return FALSE;
1948 }
1949 if (!check) {
1950 int i;
1951 int c = 0;
1952
1953 for (i = 0; c < bufsize -1 && str[i] != '\0'; i++) {
1954 if (str[i] == '\\') {
1955 i++;
1956
1957 if (str[i] == 'n') {
1958 game.server.connectmsg[c++] = '\n';
1959 } else {
1960 game.server.connectmsg[c++] = str[i];
1961 }
1962 } else {
1963 game.server.connectmsg[c++] = str[i];
1964 }
1965 }
1966
1967 game.server.connectmsg[c++] = '\0';
1968
1969 if (c == bufsize) {
1970 /* Truncated */
1971 cmd_reply(CMD_CONNECTMSG, caller, C_WARNING,
1972 _("Connectmsg truncated to %u bytes."), bufsize);
1973 }
1974 }
1975 return TRUE;
1976}
1977
1978/**********************************************************************/
1982 static enum command_id cmd_of_level(enum ai_level level)
1983{
1984 switch (level) {
1985 case AI_LEVEL_AWAY : return CMD_AWAY;
1986 case AI_LEVEL_RESTRICTED : return CMD_RESTRICTED;
1987 case AI_LEVEL_NOVICE : return CMD_NOVICE;
1988 case AI_LEVEL_EASY : return CMD_EASY;
1989 case AI_LEVEL_NORMAL : return CMD_NORMAL;
1990 case AI_LEVEL_HARD : return CMD_HARD;
1991 case AI_LEVEL_CHEATING : return CMD_CHEATING;
1992#ifdef FREECIV_DEBUG
1993 case AI_LEVEL_EXPERIMENTAL : return CMD_EXPERIMENTAL;
1994#endif /* FREECIV_DEBUG */
1995 case AI_LEVEL_COUNT : return CMD_NORMAL;
1996 }
1997 log_error("Unknown AI level variant: %d.", level);
1998 return CMD_NORMAL;
1999}
2000
2001/**********************************************************************/
2004 void set_ai_level_direct(struct player *pplayer, enum ai_level level)
2005{
2006 set_ai_level_directer(pplayer, level);
2007 send_player_info_c(pplayer, NULL);
2008 cmd_reply(cmd_of_level(level), NULL, C_OK,
2009 _("Player '%s' now has AI skill level '%s'."),
2010 player_name(pplayer),
2011 ai_level_translated_name(level));
2012
2013}
2014
2015/**********************************************************************/
2018 static bool set_ai_level_named(struct connection *caller, const char *name,
2019 const char *level_name, bool check)
2020{
2021 enum ai_level level = ai_level_by_name(level_name, fc_strcasecmp);
2022
2023 return set_ai_level(caller, name, level, check);
2024}
2025
2026/**********************************************************************/
2029 static bool set_ai_level(struct connection *caller, const char *name,
2030 enum ai_level level, bool check)
2031{
2032 enum m_pre_result match_result;
2033 struct player *pplayer;
2034
2035 fc_assert_ret_val(level >= 0 && level < AI_LEVEL_AWAY, FALSE);
2036
2037 pplayer = player_by_name_prefix(name, &match_result);
2038
2039 if (pplayer) {
2040 if (is_ai(pplayer)) {
2041 if (check) {
2042 return TRUE;
2043 }
2044 set_ai_level_directer(pplayer, level);
2045 send_player_info_c(pplayer, NULL);
2046 cmd_reply(cmd_of_level(level), caller, C_OK,
2047 _("Player '%s' now has AI skill level '%s'."),
2048 player_name(pplayer),
2049 ai_level_translated_name(level));
2050 } else {
2051 cmd_reply(cmd_of_level(level), caller, C_FAIL,
2052 _("%s is not controlled by the AI."),
2053 player_name(pplayer));
2054 return FALSE;
2055 }
2056 } else if (match_result == M_PRE_EMPTY) {
2057 if (check) {
2058 return TRUE;
2059 }
2060 players_iterate(cplayer) {
2061 if (is_ai(cplayer)) {
2062 set_ai_level_directer(cplayer, level);
2063 send_player_info_c(cplayer, NULL);
2064 cmd_reply(cmd_of_level(level), caller, C_OK,
2065 _("Player '%s' now has AI skill level '%s'."),
2066 player_name(cplayer),
2067 ai_level_translated_name(level));
2068 }
2069 } players_iterate_end;
2070 game.info.skill_level = level;
2071 send_game_info(NULL);
2072 cmd_reply(cmd_of_level(level), caller, C_OK,
2073 _("Default AI skill level set to '%s'."),
2074 ai_level_translated_name(level));
2075 } else {
2076 cmd_reply_no_such_player(cmd_of_level(level), caller, name, match_result);
2077 return FALSE;
2078 }
2079 return TRUE;
2080}
2081
2082/**********************************************************************/
2085 static bool away_command(struct connection *caller, bool check)
2086{
2087 struct player *pplayer;
2088
2089 if (caller == NULL) {
2090 cmd_reply(CMD_AWAY, caller, C_FAIL, _("This command is client only."));
2091 return FALSE;
2092 }
2093
2094 if (!conn_controls_player(caller)) {
2095 /* This happens for detached or observer connections. */
2096 cmd_reply(CMD_AWAY, caller, C_FAIL,
2097 _("Only players may use the away command."));
2098 return FALSE;
2099 }
2100
2101 if (check) {
2102 return TRUE;
2103 }
2104
2105 pplayer = conn_get_player(caller);
2106 if (is_human(pplayer)) {
2107 cmd_reply(CMD_AWAY, caller, C_OK,
2108 _("%s set to away mode."), player_name(pplayer));
2109 player_set_to_ai_mode(pplayer, AI_LEVEL_AWAY);
2110 fc_assert(!is_human(pplayer));
2111 } else {
2112 cmd_reply(CMD_AWAY, caller, C_OK,
2113 _("%s returned to game."), player_name(pplayer));
2114 player_set_under_human_control(pplayer);
2115 fc_assert(is_human(pplayer));
2116 }
2117
2118 send_player_info_c(caller->playing, game.est_connections);
2119
2120 return TRUE;
2121}
2122
2123/**********************************************************************/
2126 static void show_ruleset_info(struct connection *caller, enum command_id cmd,
2127 bool check, int read_recursion)
2128{
2129 char *show_arg = "changed";
2130
2131 /* show changed settings only at the top level of recursion */
2132 if (read_recursion != 0) {
2133 return;
2134 }
2135
2136 show_settings(caller, cmd, show_arg, check);
2137
2138 if (game.ruleset_summary != NULL) {
2139 char *translated = fc_strdup(_(game.ruleset_summary));
2140
2141 fc_break_lines(translated, LINE_BREAK);
2142 cmd_reply(cmd, caller, C_COMMENT, "%s", translated);
2143 cmd_reply(cmd, caller, C_COMMENT, horiz_line);
2144 free(translated);
2145 }
2146}
2147
2148/**********************************************************************/
2151 static bool show_command(struct connection *caller, char *str, bool check)
2152{
2153 return show_settings(caller, CMD_SHOW, str, check);
2154}
2155
2156/**********************************************************************/
2161 static bool show_settings(struct connection *caller,
2162 enum command_id called_as,
2163 char *str, bool check)
2164{
2165 int cmd;
2166 enum sset_level level = SSET_ALL;
2167 size_t clen = 0;
2168
2169 remove_leading_trailing_spaces(str);
2170 if (str[0] != '\0') {
2171 /* In "/show forests", figure out that it's the forests option we're
2172 * looking at. */
2173 cmd = lookup_option(str);
2174 if (cmd >= 0) {
2175 /* Ignore levels when a particular option is specified. */
2176 level = SSET_NONE;
2177
2178 if (!setting_is_visible(setting_by_number(cmd), caller)) {
2179 cmd_reply(called_as, caller, C_FAIL,
2180 _("Sorry, you do not have access to view option '%s'."),
2181 str);
2182 return FALSE;
2183 }
2184 }
2185
2186 /* Valid negative values for 'cmd' are defined as LOOKUP_OPTION_*. */
2187 switch (cmd) {
2188 case LOOKUP_OPTION_NO_RESULT:
2189 cmd_reply(called_as, caller, C_FAIL, _("Unknown option '%s'."), str);
2190 return FALSE;
2191 case LOOKUP_OPTION_AMBIGUOUS:
2192 /* Allow ambiguous: show all matching. */
2193 clen = strlen(str);
2194 break;
2195 case LOOKUP_OPTION_LEVEL_NAME:
2196 /* Option level. */
2197 level = lookup_option_level(str);
2198 break;
2199 case LOOKUP_OPTION_RULESETDIR:
2200 /* Ruleset. */
2201 cmd_reply(called_as, caller, C_COMMENT,
2202 _("Current ruleset directory is \"%s\""),
2203 game.server.rulesetdir);
2204 return TRUE;
2205 }
2206 } else {
2207 /* to indicate that no command was specified */
2208 cmd = LOOKUP_OPTION_NO_RESULT;
2209 /* Use vital level by default. */
2210 level = SSET_VITAL;
2211 }
2212
2213 fc_assert_ret_val(cmd >= 0 || cmd == LOOKUP_OPTION_AMBIGUOUS
2214 || cmd == LOOKUP_OPTION_LEVEL_NAME
2215 || cmd == LOOKUP_OPTION_NO_RESULT, FALSE);
2216
2217#define cmd_reply_show(string) \
2218 cmd_reply(called_as, caller, C_COMMENT, "%s", string)
2219
2220 {
2221 const char *heading = NULL;
2222 switch (level) {
2223 case SSET_NONE:
2224 break;
2225 case SSET_CHANGED:
2226 heading = _("All options with non-default values");
2227 break;
2228 case SSET_ALL:
2229 heading = _("All options");
2230 break;
2231 case SSET_VITAL:
2232 heading = _("Vital options");
2233 break;
2234 case SSET_SITUATIONAL:
2235 heading = _("Situational options");
2236 break;
2237 case SSET_RARE:
2238 heading = _("Rarely used options");
2239 break;
2240 case SSET_LOCKED:
2241 heading = _("Options locked by the ruleset");
2242 break;
2243 case OLEVELS_NUM:
2244 /* nothing */
2245 break;
2246 }
2247 if (heading) {
2248 cmd_reply_show(horiz_line);
2249 cmd_reply_show(heading);
2250 }
2251 }
2252 cmd_reply_show(horiz_line);
2253 cmd_reply_show(_("In the column '##' the status of the option is shown:"));
2254 cmd_reply_show(_(" - a '!' means the option is locked by the ruleset."));
2255 cmd_reply_show(_(" - a '+' means you may change the option."));
2256 cmd_reply_show(_(" - a '~' means that option follows default value."));
2257 cmd_reply_show(_(" - a '=' means the value is same as default."));
2258 cmd_reply_show(horiz_line);
2259 cmd_reply(called_as, caller, C_COMMENT, _("%-*s ## value (min, max)"),
2260 OPTION_NAME_SPACE, _("Option"));
2261 cmd_reply_show(horiz_line);
2262
2263 /* Update changed and locked levels. */
2264 settings_list_update();
2265
2266 switch (level) {
2267 case SSET_NONE:
2268 /* Show _one_ setting. */
2269 fc_assert_ret_val(0 <= cmd, FALSE);
2270 {
2271 struct setting *pset = setting_by_number(cmd);
2272
2273 show_settings_one(caller, called_as, pset);
2274 }
2275 break;
2276 case SSET_CHANGED:
2277 case SSET_ALL:
2278 case SSET_VITAL:
2279 case SSET_SITUATIONAL:
2280 case SSET_RARE:
2281 case SSET_LOCKED:
2282 settings_iterate(level, pset) {
2283 if (!setting_is_visible(pset, caller)) {
2284 continue;
2285 }
2286
2287 if (LOOKUP_OPTION_AMBIGUOUS == cmd
2288 && 0 != fc_strncasecmp(setting_name(pset), str, clen)) {
2289 continue;
2290 }
2291
2292 show_settings_one(caller, called_as, pset);
2293 } settings_iterate_end;
2294 break;
2295 case OLEVELS_NUM:
2296 /* nothing */
2297 break;
2298 }
2299
2300 cmd_reply_show(horiz_line);
2301 /* Only emit this additional help for bona fide 'show' command */
2302 if (called_as == CMD_SHOW) {
2303 cmd_reply_show(_("A help text for each option is available via 'help "
2304 "<option>'."));
2305 cmd_reply_show(horiz_line);
2306 if (level == SSET_VITAL) {
2307 cmd_reply_show(_("Try 'show situational' or 'show rare' to show "
2308 "more options.\n"
2309 "Try 'show changed' to show settings with "
2310 "non-default values.\n"
2311 "Try 'show locked' to show settings locked "
2312 "by the ruleset."));
2313 cmd_reply_show(horiz_line);
2314 }
2315 }
2316 return TRUE;
2317#undef cmd_reply_show
2318}
2319
2320/**********************************************************************/
2333 static void show_settings_one(struct connection *caller, enum command_id cmd,
2334 struct setting *pset)
2335{
2336 char buf[MAX_LEN_CONSOLE_LINE] = "", value[MAX_LEN_CONSOLE_LINE] = "";
2337 bool is_changed;
2338 static char prefix[OPTION_NAME_SPACE + 4 + 1] = "";
2339 char defaultness;
2340
2341 fc_assert_ret(pset != NULL);
2342
2343 is_changed = setting_non_default(pset);
2344 setting_value_name(pset, TRUE, value, sizeof(value));
2345
2346 /* Wrap long option values, such as bitwise options */
2347 fc_break_lines(value, LINE_BREAK - (sizeof(prefix)-1));
2348
2349 if (prefix[0] == '\0') {
2350 memset(prefix, ' ', sizeof(prefix)-1);
2351 }
2352
2353 if (is_changed) {
2354 /* Emphasizes the changed option. */
2355 /* Apply tags to each line fragment. */
2356 size_t startpos = 0;
2357 char *nl;
2358 do {
2359 nl = strchr(value + startpos, '\n');
2360 featured_text_apply_tag(value, buf, sizeof(buf), TTT_COLOR,
2361 startpos, nl ? nl - value : FT_OFFSET_UNSET,
2362 ftc_changed);
2363 sz_strlcpy(value, buf);
2364 if (nl) {
2365 char *p = strchr(nl, '\n');
2366 fc_assert_action(p != NULL, break);
2367 startpos = p + 1 - value;
2368 }
2369 } while (nl);
2370 }
2371
2372 if (SST_INT == setting_type(pset)) {
2373 /* Add the range. */
2374 cat_snprintf(value, sizeof(value), " (%d, %d)",
2375 setting_int_min(pset), setting_int_max(pset));
2376 }
2377
2378 if (setting_get_setdef(pset) == SETDEF_INTERNAL) {
2379 defaultness = '~';
2380 } else if (is_changed) {
2381 defaultness = ' ';
2382 } else {
2383 defaultness = '=';
2384 }
2385
2386 cmd_reply_prefix(cmd, caller, C_COMMENT, prefix, "%-*s %c%c %s",
2387 OPTION_NAME_SPACE, setting_name(pset),
2388 setting_status(caller, pset), defaultness,
2389 value);
2390}
2391
2392/**********************************************************************/
2395 static bool team_command(struct connection *caller, char *str, bool check)
2396{
2397 struct player *pplayer;
2398 enum m_pre_result match_result;
2399 char buf[MAX_LEN_CONSOLE_LINE];
2400 char *arg[2];
2401 int ntokens = 0, i;
2402 bool res = FALSE;
2403 struct team_slot *tslot;
2404
2405 if (game_was_started()) {
2406 cmd_reply(CMD_TEAM, caller, C_SYNTAX,
2407 _("Cannot change teams once game has begun."));
2408 return FALSE;
2409 }
2410
2411 if (str != NULL || strlen(str) > 0) {
2412 sz_strlcpy(buf, str);
2413 ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS);
2414 }
2415 if (ntokens != 2) {
2416 cmd_reply(CMD_TEAM, caller, C_SYNTAX,
2417 _("Undefined argument. Usage:\n%s"),
2418 command_synopsis(command_by_number(CMD_TEAM)));
2419 goto cleanup;
2420 }
2421
2422 pplayer = player_by_name_prefix(arg[0], &match_result);
2423 if (pplayer == NULL) {
2424 cmd_reply_no_such_player(CMD_TEAM, caller, arg[0], match_result);
2425 goto cleanup;
2426 }
2427
2428 tslot = team_slot_by_rule_name(arg[1]);
2429 if (NULL == tslot) {
2430 int teamno;
2431
2432 if (str_to_int(arg[1], &teamno)) {
2433 tslot = team_slot_by_number(teamno);
2434 }
2435 }
2436
2437 if (NULL == tslot) {
2438 cmd_reply(CMD_TEAM, caller, C_SYNTAX,
2439 _("No such team %s. Please give a "
2440 "valid team name or number."), arg[1]);
2441 goto cleanup;
2442 }
2443
2444 if (is_barbarian(pplayer)) {
2445 /* This can happen if we change team settings on a loaded game. */
2446 cmd_reply(CMD_TEAM, caller, C_SYNTAX, _("Cannot team a barbarian."));
2447 goto cleanup;
2448 }
2449
2450 if (!check) {
2451 /* Should never fail when slot given is not nullptr */
2452 team_add_player(pplayer, team_new(tslot));
2453 send_player_info_c(pplayer, NULL);
2454 cmd_reply(CMD_TEAM, caller, C_OK, _("Player %s set to team %s."),
2455 player_name(pplayer),
2456 team_slot_name_translation(tslot));
2457 }
2458
2459 res = TRUE;
2460
2461 cleanup:
2462 for (i = 0; i < ntokens; i++) {
2463 free(arg[i]);
2464 }
2465
2466 return res;
2467}
2468
2469/**********************************************************************/
2472 static void show_votes(struct connection *caller)
2473{
2474 int count = 0;
2475 const char *title;
2476
2477 if (vote_list != NULL) {
2478 vote_list_iterate(vote_list, pvote) {
2479 if (NULL != caller && !conn_can_see_vote(caller, pvote)) {
2480 continue;
2481 }
2482 /* TRANS: "Vote" or "Teamvote" is voting-as-a-process. Used as
2483 * part of a sentence. */
2484 title = vote_is_team_only(pvote) ? _("Teamvote") : _("Vote");
2485 cmd_reply(CMD_VOTE, caller, C_COMMENT,
2486 /* TRANS: "[Vote|Teamvote] 3 \"proposed change\" (needs ..." */
2487 _("%s %d \"%s\" (needs %0.0f%%%s): %d for, "
2488 "%d against, and %d abstained out of %d players."),
2489 title, pvote->vote_no, pvote->cmdline,
2490 MIN(100, pvote->need_pc * 100 + 1),
2491 /* TRANS: preserve leading space */
2492 pvote->flags & VCF_NODISSENT ? _(" no dissent") : "",
2493 pvote->yes, pvote->no, pvote->abstain, count_voters(pvote));
2494 count++;
2495 } vote_list_iterate_end;
2496 }
2497
2498 if (count == 0) {
2499 cmd_reply(CMD_VOTE, caller, C_COMMENT,
2500 _("There are no votes going on."));
2501 }
2502}
2503
2504/**********************************************************************/
2507 static const char *const vote_args[] = {
2508 "yes",
2509 "no",
2510 "abstain",
2511 NULL
2512};
2513 static const char *vote_arg_accessor(int i)
2514{
2515 return vote_args[i];
2516}
2517
2518/**********************************************************************/
2521 static bool vote_command(struct connection *caller, char *str,
2522 bool check)
2523{
2524 char buf[MAX_LEN_CONSOLE_LINE];
2525 char *arg[2];
2526 int ntokens = 0, i = 0, which = -1;
2527 enum m_pre_result match_result;
2528 struct vote *pvote = NULL;
2529 bool res = FALSE;
2530
2531 if (check) {
2532 /* This should never happen, since /vote must always be
2533 * set to ALLOW_BASIC or less. But just in case... */
2534 return FALSE;
2535 }
2536
2537 sz_strlcpy(buf, str);
2538 ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS);
2539
2540 if (ntokens == 0) {
2541 show_votes(caller);
2542 goto CLEANUP;
2543 } else if (!conn_can_vote(caller, NULL)) {
2544 cmd_reply(CMD_VOTE, caller, C_FAIL,
2545 _("You are not allowed to use this command."));
2546 goto CLEANUP;
2547 }
2548
2549 match_result = match_prefix(vote_arg_accessor, VOTE_NUM, 0,
2550 fc_strncasecmp, NULL, arg[0], &i);
2551
2552 if (match_result == M_PRE_AMBIGUOUS) {
2553 cmd_reply(CMD_VOTE, caller, C_SYNTAX,
2554 _("The argument \"%s\" is ambiguous."), arg[0]);
2555 goto CLEANUP;
2556 } else if (match_result > M_PRE_AMBIGUOUS) {
2557 /* Failed */
2558 cmd_reply(CMD_VOTE, caller, C_SYNTAX,
2559 _("Undefined argument. Usage:\n%s"),
2560 command_synopsis(command_by_number(CMD_VOTE)));
2561 goto CLEANUP;
2562 }
2563
2564 if (ntokens == 1) {
2565 /* Applies to last vote */
2566 if (vote_number_sequence > 0 && get_vote_by_no(vote_number_sequence)) {
2567 which = vote_number_sequence;
2568 } else {
2569 int num_votes = vote_list_size(vote_list);
2570 if (num_votes == 0) {
2571 cmd_reply(CMD_VOTE, caller, C_FAIL, _("There are no votes running."));
2572 } else {
2573 /* TRANS: "vote" as a process */
2574 cmd_reply(CMD_VOTE, caller, C_FAIL, _("No legal last vote (%d %s)."),
2575 num_votes, PL_("other vote running", "other votes running",
2576 num_votes));
2577 }
2578 goto CLEANUP;
2579 }
2580 } else {
2581 if (!str_to_int(arg[1], &which)) {
2582 cmd_reply(CMD_VOTE, caller, C_SYNTAX, _("Value must be an integer."));
2583 goto CLEANUP;
2584 }
2585 }
2586
2587 if (!(pvote = get_vote_by_no(which))) {
2588 /* TRANS: "vote" as a process */
2589 cmd_reply(CMD_VOTE, caller, C_FAIL, _("No such vote (%d)."), which);
2590 goto CLEANUP;
2591 }
2592
2593 if (!conn_can_vote(caller, pvote)) {
2594 cmd_reply(CMD_VOTE, caller, C_FAIL,
2595 _("You are not allowed to vote on that."));
2596 goto CLEANUP;
2597 }
2598
2599 if (i == VOTE_YES) {
2600 cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted for \"%s\""),
2601 pvote->cmdline);
2602 connection_vote(caller, pvote, VOTE_YES);
2603 } else if (i == VOTE_NO) {
2604 cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted against \"%s\""),
2605 pvote->cmdline);
2606 connection_vote(caller, pvote, VOTE_NO);
2607 } else if (i == VOTE_ABSTAIN) {
2608 cmd_reply(CMD_VOTE, caller, C_COMMENT,
2609 _("You abstained from voting on \"%s\""), pvote->cmdline);
2610 connection_vote(caller, pvote, VOTE_ABSTAIN);
2611 } else {
2612 /* Must never happen. */
2613 fc_assert_action(FALSE, goto CLEANUP);
2614 }
2615
2616 res = TRUE;
2617
2618 CLEANUP:
2619 free_tokens(arg, ntokens);
2620 return res;
2621}
2622
2623/**********************************************************************/
2626 static bool cancelvote_command(struct connection *caller,
2627 char *arg, bool check)
2628{
2629 struct vote *pvote = NULL;
2630 int vote_no;
2631
2632 if (check) {
2633 /* This should never happen anyway, since /cancelvote
2634 * is set to ALLOW_BASIC in both pregame and while the
2635 * game is running. */
2636 return FALSE;
2637 }
2638
2639 remove_leading_trailing_spaces(arg);
2640
2641 if (arg[0] == '\0') {
2642 if (caller == NULL) {
2643 /* Server prompt */
2644 cmd_reply(CMD_CANCELVOTE, caller, C_SYNTAX,
2645 /* TRANS: "vote" as a process */
2646 _("Missing argument <vote number> or "
2647 "the string \"all\"."));
2648 return FALSE;
2649 }
2650 /* The caller is canceling their own vote. */
2651 if (!(pvote = get_vote_by_caller(caller))) {
2652 cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
2653 _("You don't have any vote going on."));
2654 return FALSE;
2655 }
2656 } else if (fc_strcasecmp(arg, "all") == 0) {
2657 /* Cancel all votes (needs some privileges). */
2658 if (vote_list_size(vote_list) == 0) {
2659 cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
2660 _("There isn't any vote going on."));
2661 return FALSE;
2662 } else if (!caller || conn_get_access(caller) >= ALLOW_ADMIN) {
2663 clear_all_votes();
2664 notify_conn(NULL, NULL, E_VOTE_ABORTED, ftc_server,
2665 /* TRANS: "votes" as a process */
2666 _("All votes have been removed."));
2667 return TRUE;
2668 } else {
2669 cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
2670 _("You are not allowed to use this command."));
2671 return FALSE;
2672 }
2673 } else if (str_to_int(arg, &vote_no)) {
2674 /* Cancel one particular vote (needs some privileges if the vote
2675 * is not owned). */
2676 if (!(pvote = get_vote_by_no(vote_no))) {
2677 cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
2678 /* TRANS: "vote" as a process */
2679 _("No such vote (%d)."), vote_no);
2680 return FALSE;
2681 } else if (caller && conn_get_access(caller) < ALLOW_ADMIN
2682 && caller->id != pvote->caller_id) {
2683 cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
2684 /* TRANS: "vote" as a process */
2685 _("You are not allowed to cancel this vote (%d)."),
2686 vote_no);
2687 return FALSE;
2688 }
2689 } else {
2690 cmd_reply(CMD_CANCELVOTE, caller, C_SYNTAX,
2691 /* TRANS: "vote" as a process */
2692 _("Usage: /cancelvote [<vote number>|all]"));
2693 return FALSE;
2694 }
2695
2696 fc_assert_ret_val(NULL != pvote, FALSE);
2697
2698 if (caller) {
2699 notify_team(conn_get_player(vote_get_caller(pvote)),
2700 NULL, E_VOTE_ABORTED, ftc_server,
2701 /* TRANS: "vote" as a process */
2702 _("%s has canceled the vote \"%s\" (number %d)."),
2703 caller->username, pvote->cmdline, pvote->vote_no);
2704 } else {
2705 /* Server prompt */
2706 notify_team(conn_get_player(vote_get_caller(pvote)),
2707 NULL, E_VOTE_ABORTED, ftc_server,
2708 /* TRANS: "vote" as a process */
2709 _("The vote \"%s\" (number %d) has been canceled."),
2710 pvote->cmdline, pvote->vote_no);
2711 }
2712 /* Make it after, prevent crashs about a free pointer (pvote). */
2713 remove_vote(pvote);
2714
2715 return TRUE;
2716}
2717
2718/**********************************************************************/
2721 static bool debug_command(struct connection *caller, char *str,
2722 bool check)
2723{
2724 char buf[MAX_LEN_CONSOLE_LINE];
2725 char *arg[3];
2726 int ntokens = 0, i;
2727
2728 if (game.info.is_new_game) {
2729 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2730 _("Can only use this command once game has begun."));
2731 return FALSE;
2732 }
2733 if (check) {
2734 return TRUE; /* whatever! */
2735 }
2736
2737 if (str != NULL && strlen(str) > 0) {
2738 sz_strlcpy(buf, str);
2739 ntokens = get_tokens(buf, arg, 3, TOKEN_DELIMITERS);
2740 } else {
2741 ntokens = 0;
2742 }
2743
2744 if (ntokens > 0 && strcmp(arg[0], "diplomacy") == 0) {
2745 struct player *pplayer;
2746 enum m_pre_result match_result;
2747
2748 if (ntokens != 2) {
2749 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2750 _("Undefined argument. Usage:\n%s"),
2751 command_synopsis(command_by_number(CMD_DEBUG)));
2752 goto cleanup;
2753 }
2754 pplayer = player_by_name_prefix(arg[1], &match_result);
2755 if (pplayer == NULL) {
2756 cmd_reply_no_such_player(CMD_DEBUG, caller, arg[1], match_result);
2757 goto cleanup;
2758 }
2759 if (BV_ISSET(pplayer->server.debug, PLAYER_DEBUG_DIPLOMACY)) {
2760 BV_CLR(pplayer->server.debug, PLAYER_DEBUG_DIPLOMACY);
2761 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s diplomacy no longer debugged"),
2762 player_name(pplayer));
2763 } else {
2764 BV_SET(pplayer->server.debug, PLAYER_DEBUG_DIPLOMACY);
2765 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s diplomacy debugged"),
2766 player_name(pplayer));
2767 /* TODO: print some info about the player here */
2768 }
2769 } else if (ntokens > 0 && strcmp(arg[0], "tech") == 0) {
2770 struct player *pplayer;
2771 enum m_pre_result match_result;
2772
2773 if (ntokens != 2) {
2774 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2775 _("Undefined argument. Usage:\n%s"),
2776 command_synopsis(command_by_number(CMD_DEBUG)));
2777 goto cleanup;
2778 }
2779 pplayer = player_by_name_prefix(arg[1], &match_result);
2780 if (pplayer == NULL) {
2781 cmd_reply_no_such_player(CMD_DEBUG, caller, arg[1], match_result);
2782 goto cleanup;
2783 }
2784 if (BV_ISSET(pplayer->server.debug, PLAYER_DEBUG_TECH)) {
2785 BV_CLR(pplayer->server.debug, PLAYER_DEBUG_TECH);
2786 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s tech no longer debugged"),
2787 player_name(pplayer));
2788 } else {
2789 BV_SET(pplayer->server.debug, PLAYER_DEBUG_TECH);
2790 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s tech debugged"),
2791 player_name(pplayer));
2792 /* TODO: print some info about the player here */
2793 }
2794 } else if (ntokens > 0 && strcmp(arg[0], "info") == 0) {
2795 int cities = 0, players = 0, units = 0, citizen_count = 0;
2796
2797 players_iterate(plr) {
2798 players++;
2799 city_list_iterate(plr->cities, pcity) {
2800 cities++;
2801 citizen_count += city_size_get(pcity);
2802 } city_list_iterate_end;
2803 units += unit_list_size(plr->units);
2804 } players_iterate_end;
2805 log_normal(_("players=%d cities=%d citizens=%d units=%d"),
2806 players, cities, citizen_count, units);
2807 notify_conn(game.est_connections, NULL, E_AI_DEBUG, ftc_log,
2808 _("players=%d cities=%d citizens=%d units=%d"),
2809 players, cities, citizen_count, units);
2810 } else if (ntokens > 0 && strcmp(arg[0], "city") == 0) {
2811 int x, y;
2812 struct tile *ptile;
2813 struct city *pcity;
2814
2815 if (ntokens != 3) {
2816 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2817 _("Undefined argument. Usage:\n%s"),
2818 command_synopsis(command_by_number(CMD_DEBUG)));
2819 goto cleanup;
2820 }
2821 if (!str_to_int(arg[1], &x) || !str_to_int(arg[2], &y)) {
2822 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Value 2 & 3 must be integer."));
2823 goto cleanup;
2824 }
2825 if (!(ptile = map_pos_to_tile(&(wld.map), x, y))) {
2826 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Bad map coordinates."));
2827 goto cleanup;
2828 }
2829 pcity = tile_city(ptile);
2830 if (!pcity) {
2831 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("No city at this coordinate."));
2832 goto cleanup;
2833 }
2834 if (pcity->server.debug) {
2835 pcity->server.debug = FALSE;
2836 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s no longer debugged"),
2837 city_name_get(pcity));
2838 } else {
2839 pcity->server.debug = TRUE;
2840 CITY_LOG(LOG_NORMAL, pcity, "debugged");
2841 }
2842 } else if (ntokens > 0 && strcmp(arg[0], "units") == 0) {
2843 int x, y;
2844 struct tile *ptile;
2845
2846 if (ntokens != 3) {
2847 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2848 _("Undefined argument. Usage:\n%s"),
2849 command_synopsis(command_by_number(CMD_DEBUG)));
2850 goto cleanup;
2851 }
2852 if (!str_to_int(arg[1], &x) || !str_to_int(arg[2], &y)) {
2853 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Value 2 & 3 must be integer."));
2854 goto cleanup;
2855 }
2856 if (!(ptile = map_pos_to_tile(&(wld.map), x, y))) {
2857 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Bad map coordinates."));
2858 goto cleanup;
2859 }
2860 unit_list_iterate(ptile->units, punit) {
2861 if (punit->server.debug) {
2862 punit->server.debug = FALSE;
2863 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s %s no longer debugged."),
2864 nation_adjective_for_player(unit_owner(punit)),
2865 unit_name_translation(punit));
2866 } else {
2867 punit->server.debug = TRUE;
2868 UNIT_LOG(LOG_NORMAL, punit, "%s %s debugged.",
2869 nation_rule_name(nation_of_unit(punit)),
2870 unit_name_translation(punit));
2871 }
2872 } unit_list_iterate_end;
2873 } else if (ntokens > 0 && strcmp(arg[0], "timing") == 0) {
2874 TIMING_RESULTS();
2875 } else if (ntokens > 0 && strcmp(arg[0], "ferries") == 0) {
2876 if (game.server.debug[DEBUG_FERRIES]) {
2877 game.server.debug[DEBUG_FERRIES] = FALSE;
2878 cmd_reply(CMD_DEBUG, caller, C_OK, _("Ferry system is no longer "
2879 "in debug mode."));
2880 } else {
2881 game.server.debug[DEBUG_FERRIES] = TRUE;
2882 cmd_reply(CMD_DEBUG, caller, C_OK, _("Ferry system in debug mode."));
2883 }
2884 } else if (ntokens > 0 && strcmp(arg[0], "unit") == 0) {
2885 int id;
2886 struct unit *punit;
2887
2888 if (ntokens != 2) {
2889 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2890 _("Undefined argument. Usage:\n%s"),
2891 command_synopsis(command_by_number(CMD_DEBUG)));
2892 goto cleanup;
2893 }
2894 if (!str_to_int(arg[1], &id)) {
2895 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Value 2 must be integer."));
2896 goto cleanup;
2897 }
2898 if (!(punit = game_unit_by_number(id))) {
2899 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Unit %d does not exist."), id);
2900 goto cleanup;
2901 }
2902 if (punit->server.debug) {
2903 punit->server.debug = FALSE;
2904 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s %s no longer debugged."),
2905 nation_adjective_for_player(unit_owner(punit)),
2906 unit_name_translation(punit));
2907 } else {
2908 punit->server.debug = TRUE;
2909 UNIT_LOG(LOG_NORMAL, punit, "%s %s debugged.",
2910 nation_rule_name(nation_of_unit(punit)),
2911 unit_name_translation(punit));
2912 }
2913 } else {
2914 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2915 _("Undefined argument. Usage:\n%s"),
2916 command_synopsis(command_by_number(CMD_DEBUG)));
2917 }
2918 cleanup:
2919 for (i = 0; i < ntokens; i++) {
2920 free(arg[i]);
2921 }
2922 return TRUE;
2923}
2924
2925/**********************************************************************/
2929 static struct setting *validate_setting_arg(enum command_id cmd,
2930 struct connection *caller,
2931 char *arg)
2932{
2933 int opt = lookup_option(arg);
2934
2935 if (opt < 0) {
2936 switch (opt) {
2937 case LOOKUP_OPTION_NO_RESULT:
2938 case LOOKUP_OPTION_LEVEL_NAME:
2939 cmd_reply(cmd, caller, C_SYNTAX, _("Option '%s' not recognized."), arg);
2940 break;
2941 case LOOKUP_OPTION_AMBIGUOUS:
2942 cmd_reply(cmd, caller, C_SYNTAX, _("Ambiguous option name."));
2943 break;
2944 case LOOKUP_OPTION_RULESETDIR:
2945 cmd_reply(cmd, caller, C_SYNTAX,
2946 /* TRANS: 'rulesetdir' is the command. Do not translate. */
2947 _("Use the '%srulesetdir' command to change the ruleset "
2948 "directory."), caller ? "/" : "");
2949 break;
2950 default:
2951 fc_assert(opt >= LOOKUP_OPTION_RULESETDIR);
2952 break;
2953 }
2954 return NULL;
2955 }
2956
2957 return setting_by_number(opt);
2958}
2959
2960/**********************************************************************/
2963 static bool set_command(struct connection *caller, char *str, bool check)
2964{
2965 char *args[2];
2966 int val, nargs;
2967 struct setting *pset;
2968 bool do_update;
2969 char reject_msg[256] = "";
2970 bool ret = FALSE;
2971
2972 /* '=' is also a valid delimiter for this function. */
2973 nargs = get_tokens(str, args, ARRAY_SIZE(args), TOKEN_DELIMITERS "=");
2974
2975 if (nargs < 2) {
2976 cmd_reply(CMD_SET, caller, C_SYNTAX,
2977 _("Undefined argument. Usage:\n%s"),
2978 command_synopsis(command_by_number(CMD_SET)));
2979 goto cleanup;
2980 }
2981
2982 pset = validate_setting_arg(CMD_SET, caller, args[0]);
2983
2984 if (!pset) {
2985 /* Reason already reported. */
2986 goto cleanup;
2987 }
2988
2989 if (!setting_is_changeable(pset, caller, reject_msg, sizeof(reject_msg))
2990 && !check) {
2991 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
2992 goto cleanup;
2993 }
2994
2995 do_update = FALSE;
2996
2997 switch (setting_type(pset)) {
2998 case SST_BOOL:
2999 if (check) {
3000 if (!setting_is_changeable(pset, caller, reject_msg,
3001 sizeof(reject_msg))
3002 || (!setting_bool_validate(pset, args[1], caller,
3003 reject_msg, sizeof(reject_msg)))) {
3004 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3005 goto cleanup;
3006 }
3007 } else if (setting_bool_set(pset, args[1], caller,
3008 reject_msg, sizeof(reject_msg))) {
3009 do_update = TRUE;
3010 } else {
3011 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3012 goto cleanup;
3013 }
3014 break;
3015
3016 case SST_INT:
3017 if (!str_to_int(args[1], &val)) {
3018 cmd_reply(CMD_SET, caller, C_SYNTAX,
3019 _("The parameter %s should only contain +- and 0-9."),
3020 setting_name(pset));
3021 goto cleanup;
3022 }
3023 if (check) {
3024 if (!setting_is_changeable(pset, caller, reject_msg,
3025 sizeof(reject_msg))
3026 || !setting_int_validate(pset, val, caller, reject_msg,
3027 sizeof(reject_msg))) {
3028 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3029 goto cleanup;
3030 }
3031 } else {
3032 if (setting_int_set(pset, val, caller, reject_msg,
3033 sizeof(reject_msg))) {
3034 do_update = TRUE;
3035 } else {
3036 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3037 goto cleanup;
3038 }
3039 }
3040 break;
3041
3042 case SST_STRING:
3043 if (check) {
3044 if (!setting_is_changeable(pset, caller, reject_msg,
3045 sizeof(reject_msg))
3046 || !setting_str_validate(pset, args[1], caller, reject_msg,
3047 sizeof(reject_msg))) {
3048 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3049 goto cleanup;
3050 }
3051 } else {
3052 if (setting_str_set(pset, args[1], caller, reject_msg,
3053 sizeof(reject_msg))) {
3054 do_update = TRUE;
3055 } else {
3056 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3057 goto cleanup;
3058 }
3059 }
3060 break;
3061
3062 case SST_ENUM:
3063 if (check) {
3064 if (!setting_is_changeable(pset, caller, reject_msg,
3065 sizeof(reject_msg))
3066 || (!setting_enum_validate(pset, args[1], caller,
3067 reject_msg, sizeof(reject_msg)))) {
3068 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3069 goto cleanup;
3070 }
3071 } else if (setting_enum_set(pset, args[1], caller,
3072 reject_msg, sizeof(reject_msg))) {
3073 do_update = TRUE;
3074 } else {
3075 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3076 goto cleanup;
3077 }
3078 break;
3079
3080 case SST_BITWISE:
3081 if (check) {
3082 if (!setting_is_changeable(pset, caller, reject_msg,
3083 sizeof(reject_msg))
3084 || (!setting_bitwise_validate(pset, args[1], caller,
3085 reject_msg, sizeof(reject_msg)))) {
3086 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3087 goto cleanup;
3088 }
3089 } else if (setting_bitwise_set(pset, args[1], caller,
3090 reject_msg, sizeof(reject_msg))) {
3091 do_update = TRUE;
3092 } else {
3093 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3094 goto cleanup;
3095 }
3096 break;
3097
3098 case SST_COUNT:
3099 fc_assert(setting_type(pset) != SST_COUNT);
3100 goto cleanup;
3101 break;
3102 }
3103
3104 ret = TRUE; /* Looks like a success. */
3105
3106 if (!check && do_update) {
3107 /* Send only to connections able to see that. */
3108 char buf[256];
3109 struct packet_chat_msg packet;
3110
3111 package_event(&packet, NULL, E_SETTING, ftc_server,
3112 _("Console: '%s' has been set to %s."), setting_name(pset),
3113 setting_value_name(pset, TRUE, buf, sizeof(buf)));
3114 conn_list_iterate(game.est_connections, pconn) {
3115 if (setting_is_visible(pset, pconn)) {
3116 send_packet_chat_msg(pconn, &packet);
3117 }
3118 } conn_list_iterate_end;
3119 /* Notify the console. */
3120 con_write(C_OK, "%s", packet.message);
3121
3122 setting_changed(pset);
3123 setting_action(pset);
3124 send_server_setting(NULL, pset);
3125 /*
3126 * send any modified game parameters to the clients -- if sent
3127 * before S_S_RUNNING, triggers a popdown_races_dialog() call
3128 * in client/packhand.c#handle_game_info()
3129 */
3130 send_game_info(NULL);
3131 reset_all_start_commands(FALSE);
3132 send_server_info_to_metaserver(META_INFO);
3133 }
3134
3135 cleanup:
3136 free_tokens(args, nargs);
3137 return ret;
3138}
3139
3140/**********************************************************************/
3143 static bool lock_command(struct connection *caller, char *str, bool check)
3144{
3145 char *args[1];
3146 int nargs;
3147
3148 nargs = get_tokens(str, args, ARRAY_SIZE(args), TOKEN_DELIMITERS);
3149
3150 if (nargs < 1) {
3151 cmd_reply(CMD_LOCK, caller, C_SYNTAX,
3152 _("Undefined argument. Usage:\n%s"),
3153 command_synopsis(command_by_number(CMD_LOCK)));
3154 } else {
3155 struct setting *pset;
3156
3157 pset = validate_setting_arg(CMD_SET, caller, args[0]);
3158
3159 if (pset != NULL) {
3160 setting_admin_lock_set(pset);
3161 return TRUE;
3162 }
3163 }
3164
3165 return FALSE;
3166}
3167
3168/**********************************************************************/
3171 static bool unlock_command(struct connection *caller, char *str, bool check)
3172{
3173 char *args[1];
3174 int nargs;
3175
3176 nargs = get_tokens(str, args, ARRAY_SIZE(args), TOKEN_DELIMITERS);
3177
3178 if (nargs < 1) {
3179 cmd_reply(CMD_LOCK, caller, C_SYNTAX,
3180 _("Undefined argument. Usage:\n%s"),
3181 command_synopsis(command_by_number(CMD_LOCK)));
3182 } else {
3183 struct setting *pset;
3184
3185 pset = validate_setting_arg(CMD_SET, caller, args[0]);
3186
3187 if (pset != NULL) {
3188 setting_admin_lock_clear(pset);
3189 return TRUE;
3190 }
3191 }
3192
3193 return FALSE;
3194}
3195
3196/**********************************************************************/
3203 static bool is_allowed_to_take(struct connection *requester,
3204 struct connection *taker,
3205 struct player *pplayer, bool will_obs,
3206 char *msg, size_t msg_len)
3207{
3208 const char *allow;
3209
3210 if (!pplayer && !will_obs) {
3211 /* Auto-taking a new player */
3212
3213 if (game_was_started()) {
3214 fc_strlcpy(msg, _("You cannot take a new player at this time."),
3215 msg_len);
3216 return FALSE;
3217 }
3218
3219 if (normal_player_count() >= game.server.max_players) {
3220 fc_snprintf(msg, msg_len,
3221 /* TRANS: Do not translate "maxplayers". */
3222 PL_("You cannot take a new player because "
3223 "the maximum of %d player has already "
3224 "been reached (maxplayers setting).",
3225 "You cannot take a new player because "
3226 "the maximum of %d players has already "
3227 "been reached (maxplayers setting).",
3228 game.server.max_players),
3229 game.server.max_players);
3230 return FALSE;
3231 }
3232
3233 if (player_count() >= player_slot_count()) {
3234 fc_strlcpy(msg, _("You cannot take a new player because there "
3235 "are no free player slots."),
3236 msg_len);
3237 return FALSE;
3238 }
3239
3240 return TRUE;
3241
3242 }
3243
3244#ifdef HAVE_FCDB
3245 if (srvarg.fcdb_enabled) {
3246 bool ok = FALSE;
3247
3248 if (script_fcdb_call("user_take", requester, taker, pplayer, will_obs,
3249 &ok) && ok) {
3250 return TRUE;
3251 }
3252 }
3253#endif
3254
3255 if (!pplayer && will_obs) {
3256 /* Global observer. */
3257 if (!(allow = strchr(game.server.allow_take,
3258 (game.info.is_new_game ? 'O' : 'o')))) {
3259 fc_strlcpy(msg, _("Sorry, one can't observe globally in this game."),
3260 msg_len);
3261 return FALSE;
3262 }
3263 } else if (is_barbarian(pplayer)) {
3264 if (!(allow = strchr(game.server.allow_take, 'b'))) {
3265 if (will_obs) {
3266 fc_strlcpy(msg,
3267 _("Sorry, one can't observe barbarians in this game."),
3268 msg_len);
3269 } else {
3270 fc_strlcpy(msg, _("Sorry, one can't take barbarians in this game."),
3271 msg_len);
3272 }
3273 return FALSE;
3274 }
3275 } else if (!pplayer->is_alive) {
3276 if (!(allow = strchr(game.server.allow_take, 'd'))) {
3277 if (will_obs) {
3278 fc_strlcpy(msg,
3279 _("Sorry, one can't observe dead players in this game."),
3280 msg_len);
3281 } else {
3282 fc_strlcpy(msg,
3283 _("Sorry, one can't take dead players in this game."),
3284 msg_len);
3285 }
3286 return FALSE;
3287 }
3288 } else if (is_ai(pplayer)) {
3289 if (!(allow = strchr(game.server.allow_take,
3290 (game.info.is_new_game ? 'A' : 'a')))) {
3291 if (will_obs) {
3292 fc_strlcpy(msg,
3293 _("Sorry, one can't observe AI players in this game."),
3294 msg_len);
3295 } else {
3296 fc_strlcpy(msg, _("Sorry, one can't take AI players in this game."),
3297 msg_len);
3298 }
3299 return FALSE;
3300 }
3301 } else {
3302 if (!(allow = strchr(game.server.allow_take,
3303 (game.info.is_new_game ? 'H' : 'h')))) {
3304 if (will_obs) {
3305 fc_strlcpy(msg,
3306 _("Sorry, one can't observe human players in this game."),
3307 msg_len);
3308 } else {
3309 fc_strlcpy(msg,
3310 _("Sorry, one can't take human players in this game."),
3311 msg_len);
3312 }
3313 return FALSE;
3314 }
3315 }
3316
3317 allow++;
3318
3319 if (will_obs && (*allow == '2' || *allow == '3')) {
3320 fc_strlcpy(msg, _("Sorry, one can't observe in this game."), msg_len);
3321 return FALSE;
3322 }
3323
3324 if (!will_obs && *allow == '4') {
3325 fc_strlcpy(msg, _("Sorry, one can't take players in this game."),
3326 MAX_LEN_MSG);
3327 return FALSE;
3328 }
3329
3330 if (!will_obs && pplayer->is_connected
3331 && (*allow == '1' || *allow == '3')) {
3332 fc_strlcpy(msg, _("Sorry, one can't take players already "
3333 "connected in this game."), msg_len);
3334 return FALSE;
3335 }
3336
3337 return TRUE;
3338}
3339
3340/**********************************************************************/
3345 static bool observe_command(struct connection *caller, char *str, bool check)
3346{
3347 int i = 0, ntokens = 0;
3348 char buf[MAX_LEN_CONSOLE_LINE], *arg[2], msg[MAX_LEN_MSG];
3349 bool is_newgame = !game_was_started();
3350 enum m_pre_result result;
3351 struct connection *pconn = NULL;
3352 struct player *pplayer = NULL;
3353 bool res = FALSE;
3354
3355 /******** PART I: fill pconn and pplayer ********/
3356
3357 sz_strlcpy(buf, str);
3358 ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS);
3359
3360 /* check syntax, only certain syntax if allowed depending on the caller */
3361 if (!caller && ntokens < 1) {
3362 cmd_reply(CMD_OBSERVE, caller, C_SYNTAX, _("Usage:\n%s"),
3363 command_synopsis(command_by_number(CMD_OBSERVE)));
3364 goto end;
3365 }
3366
3367 if (ntokens == 2 && (caller && caller->access_level != ALLOW_HACK)) {
3368 cmd_reply(CMD_OBSERVE, caller, C_SYNTAX,
3369 _("Only the player name form is allowed."));
3370 goto end;
3371 }
3372
3373 /* match connection if we're console, match a player if we're not */
3374 if (ntokens == 1) {
3375 if (!caller && !(pconn = conn_by_user_prefix(arg[0], &result))) {
3376 cmd_reply_no_such_conn(CMD_OBSERVE, caller, arg[0], result);
3377 goto end;
3378 } else if (caller
3379 && !(pplayer = player_by_name_prefix(arg[0], &result))) {
3380 cmd_reply_no_such_player(CMD_OBSERVE, caller, arg[0], result);
3381 goto end;
3382 }
3383 }
3384
3385 /* get connection name then player name */
3386 if (ntokens == 2) {
3387 if (!(pconn = conn_by_user_prefix(arg[0], &result))) {
3388 cmd_reply_no_such_conn(CMD_OBSERVE, caller, arg[0], result);
3389 goto end;
3390 }
3391 if (!(pplayer = player_by_name_prefix(arg[1], &result))) {
3392 cmd_reply_no_such_player(CMD_OBSERVE, caller, arg[1], result);
3393 goto end;
3394 }
3395 }
3396
3397 /* if we can't force other connections to observe, assign us to be pconn. */
3398 if (!pconn) {
3399 pconn = caller;
3400 }
3401
3402 /* if we have no pplayer, it means that we want to be a global observer */
3403
3404 /******** PART II: do the observing ********/
3405
3406 /* check allowtake for permission */
3407 if (!is_allowed_to_take(caller, pconn, pplayer, TRUE, msg, sizeof(msg))) {
3408 cmd_reply(CMD_OBSERVE, caller, C_FAIL, "%s", msg);
3409 goto end;
3410 }
3411
3412 /* observing your own player (during pregame) makes no sense. */
3413 if (NULL != pplayer
3414 && pplayer == pconn->playing
3415 && !pconn->observer
3416 && is_newgame
3417 && !pplayer->was_created) {
3418 cmd_reply(CMD_OBSERVE, caller, C_FAIL,
3419 _("%s already controls %s. Using 'observe' would remove %s"),
3420 pconn->username,
3421 player_name(pplayer),
3422 player_name(pplayer));
3423 goto end;
3424 }
3425
3426 /* attempting to observe a player you're already observing should fail. */
3427 if (pplayer == pconn->playing && pconn->observer) {
3428 if (pplayer) {
3429 cmd_reply(CMD_OBSERVE, caller, C_FAIL,
3430 _("%s is already observing %s."),
3431 pconn->username,
3432 player_name(pplayer));
3433 } else {
3434 cmd_reply(CMD_OBSERVE, caller, C_FAIL,
3435 _("%s is already observing."),
3436 pconn->username);
3437 }
3438 goto end;
3439 }
3440
3441 res = TRUE; /* all tests passed */
3442 if (check) {
3443 goto end;
3444 }
3445
3446 /* if the connection is already attached to a player,
3447 * unattach and cleanup old player (rename, remove, etc) */
3448 if (TRUE) {
3449 char name[MAX_LEN_NAME];
3450
3451 if (pplayer) {
3452 /* if pconn->playing is removed, we'll lose pplayer */
3453 sz_strlcpy(name, player_name(pplayer));
3454 }
3455
3456 connection_detach(pconn, TRUE);
3457
3458 if (pplayer) {
3459 /* find pplayer again, the pointer might have been changed */
3460 pplayer = player_by_name(name);
3461 }
3462 }
3463
3464 /* attach pconn to new player as an observer or as global observer */
3465 if ((res = connection_attach(pconn, pplayer, TRUE))) {
3466 if (pplayer) {
3467 cmd_reply(CMD_OBSERVE, caller, C_OK, _("%s now observes %s"),
3468 pconn->username,
3469 player_name(pplayer));
3470 } else {
3471 cmd_reply(CMD_OBSERVE, caller, C_OK, _("%s now observes"),
3472 pconn->username);
3473 }
3474 }
3475
3476 end:;
3477 /* free our args */
3478 for (i = 0; i < ntokens; i++) {
3479 free(arg[i]);
3480 }
3481 return res;
3482}
3483
3484/**********************************************************************/
3493 static bool take_command(struct connection *caller, char *str, bool check)
3494{
3495 int i = 0, ntokens = 0;
3496 char buf[MAX_LEN_CONSOLE_LINE], *arg[2], msg[MAX_LEN_MSG];
3497 bool is_newgame = !game_was_started();
3498 enum m_pre_result match_result;
3499 struct connection *pconn = caller;
3500 struct player *pplayer = NULL;
3501 bool res = FALSE;
3502
3503 /******** PART I: fill pconn and pplayer ********/
3504
3505 sz_strlcpy(buf, str);
3506 ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS);
3507
3508 /* check syntax */
3509 if (!caller && ntokens != 2) {
3510 cmd_reply(CMD_TAKE, caller, C_SYNTAX, _("Usage:\n%s"),
3511 command_synopsis(command_by_number(CMD_TAKE)));
3512 goto end;
3513 }
3514
3515 if (caller && caller->access_level != ALLOW_HACK && ntokens != 1) {
3516 cmd_reply(CMD_TAKE, caller, C_SYNTAX,
3517 _("Only the player name form is allowed."));
3518 goto end;
3519 }
3520
3521 if (ntokens == 0) {
3522 cmd_reply(CMD_TAKE, caller, C_SYNTAX, _("Usage:\n%s"),
3523 command_synopsis(command_by_number(CMD_TAKE)));
3524 goto end;
3525 }
3526
3527 if (ntokens == 2) {
3528 if (!(pconn = conn_by_user_prefix(arg[i], &match_result))) {
3529 cmd_reply_no_such_conn(CMD_TAKE, caller, arg[i], match_result);
3530 goto end;
3531 }
3532 i++; /* found a conn, now reference the second argument */
3533 }
3534
3535 if (strcmp(arg[i], "-") == 0) {
3536 if (!is_newgame) {
3537 cmd_reply(CMD_TAKE, caller, C_FAIL,
3538 _("You cannot issue \"/take -\" when "
3539 "the game has already started."));
3540 goto end;
3541 }
3542
3543 /* Find first uncontrolled player. This will return NULL if there is
3544 * no free players at the moment. Later call to
3545 * connection_attach() will create new player for such NULL
3546 * cases. */
3547 pplayer = find_uncontrolled_player();
3548 if (pplayer) {
3549 /* Make it human! */
3550 set_as_human(pplayer);
3551 }
3552 } else if (!(pplayer = player_by_name_prefix(arg[i], &match_result))) {
3553 cmd_reply_no_such_player(CMD_TAKE, caller, arg[i], match_result);
3554 goto end;
3555 }
3556
3557 /******** PART II: do the attaching ********/
3558
3559 /* Take not possible if the player is involved in a delegation (either
3560 * it's being controlled, or it's been put aside by the delegate). */
3561 if (player_delegation_active(pplayer)) {
3562 cmd_reply(CMD_TAKE, caller, C_FAIL, _("A delegation is active for player "
3563 "'%s'. /take not possible."),
3564 player_name(pplayer));
3565 goto end;
3566 }
3567
3568 /* check allowtake for permission */
3569 if (!is_allowed_to_take(caller, pconn, pplayer, FALSE, msg, sizeof(msg))) {
3570 cmd_reply(CMD_TAKE, caller, C_FAIL, "%s", msg);
3571 goto end;
3572 }
3573
3574 /* taking your own player makes no sense. */
3575 if ((NULL != pplayer && !pconn->observer && pplayer == pconn->playing)
3576 || (NULL == pplayer && !pconn->observer && NULL != pconn->playing)) {
3577 cmd_reply(CMD_TAKE, caller, C_FAIL, _("%s already controls %s."),
3578 pconn->username,
3579 player_name(pconn->playing));
3580 goto end;
3581 }
3582
3583 /* Make sure there is free player slot if there is need to
3584 * create new player. This is necessary for previously
3585 * detached connections only. Others can reuse the slot
3586 * they first release. */
3587 if (!pplayer && !pconn->playing
3588 && (normal_player_count() >= game.server.max_players
3589 || normal_player_count() >= server.playable_nations)) {
3590 cmd_reply(CMD_TAKE, caller, C_FAIL,
3591 _("There is no free player slot for %s."),
3592 pconn->username);
3593 goto end;
3594 }
3595 fc_assert_action(player_count() <= player_slot_count(), goto end);
3596
3597 res = TRUE;
3598 if (check) {
3599 goto end;
3600 }
3601
3602 /* If the player is controlled by another user, forcibly detach
3603 * the user. */
3604 if (pplayer && pplayer->is_connected) {
3605 if (NULL == caller) {
3606 notify_conn(NULL, NULL, E_CONNECTION, ftc_server,
3607 _("Reassigned nation to %s by server console."),
3608 pconn->username);
3609 } else {
3610 notify_conn(NULL, NULL, E_CONNECTION, ftc_server,
3611 _("Reassigned nation to %s by %s."),
3612 pconn->username,
3613 caller->username);
3614 }
3615
3616 /* We are reassigning this nation, so we need to detach the current
3617 * user to set a new one. */
3618 conn_list_iterate(pplayer->connections, aconn) {
3619 if (!aconn->observer) {
3620 connection_detach(aconn, FALSE);
3621 }
3622 } conn_list_iterate_end;
3623 }
3624
3625 /* if the connection is already attached to another player,
3626 * unattach and cleanup old player (rename, remove, etc)
3627 * We may have been observing the player we now want to take */
3628 if (NULL != pconn->playing || pconn->observer) {
3629 char name[MAX_LEN_NAME];
3630
3631 if (pplayer) {
3632 /* if pconn->playing is removed, we'll lose pplayer */
3633 sz_strlcpy(name, player_name(pplayer));
3634 }
3635
3636 connection_detach(pconn, TRUE);
3637
3638 if (pplayer) {
3639 /* find pplayer again; the pointer might have been changed */
3640 pplayer = player_by_name(name);
3641 }
3642 }
3643
3644 /* Now attach to new player */
3645 if ((res = connection_attach(pconn, pplayer, FALSE))) {
3646 /* Successfully attached */
3647 pplayer = pconn->playing; /* In case pplayer was NULL. */
3648
3649 /* inform about the status before changes */
3650 cmd_reply(CMD_TAKE, caller, C_OK, _("%s now controls %s (%s, %s)."),
3651 pconn->username,
3652 player_name(pplayer),
3653 is_barbarian(pplayer)
3654 ? _("Barbarian")
3655 : is_ai(pplayer)
3656 ? _("AI")
3657 : _("Human"),
3658 pplayer->is_alive
3659 ? _("Alive")
3660 : _("Dead"));
3661 } else {
3662 cmd_reply(CMD_TAKE, caller, C_FAIL,
3663 _("%s failed to attach to any player."),
3664 pconn->username);
3665 }
3666
3667 end:;
3668 /* free our args */
3669 for (i = 0; i < ntokens; i++) {
3670 free(arg[i]);
3671 }
3672 return res;
3673}
3674
3675/**********************************************************************/
3682 static bool detach_command(struct connection *caller, char *str, bool check)
3683{
3684 int i = 0, ntokens = 0;
3685 char buf[MAX_LEN_CONSOLE_LINE], *arg[1];
3686 enum m_pre_result match_result;
3687 struct connection *pconn = NULL;
3688 struct player *pplayer = NULL;
3689 bool res = FALSE;
3690
3691 sz_strlcpy(buf, str);
3692 ntokens = get_tokens(buf, arg, 1, TOKEN_DELIMITERS);
3693
3694 if (!caller && ntokens == 0) {
3695 cmd_reply(CMD_DETACH, caller, C_SYNTAX, _("Usage:\n%s"),
3696 command_synopsis(command_by_number(CMD_DETACH)));
3697 goto end;
3698 }
3699
3700 /* match the connection if the argument was given */
3701 if (ntokens == 1
3702 && !(pconn = conn_by_user_prefix(arg[0], &match_result))) {
3703 cmd_reply_no_such_conn(CMD_DETACH, caller, arg[0], match_result);
3704 goto end;
3705 }
3706
3707 /* if no argument is given, the caller wants to detach themself */
3708 if (!pconn) {
3709 pconn = caller;
3710 }
3711
3712 /* if pconn and caller are not the same, only continue
3713 * if we're console, or we have ALLOW_HACK */
3714 if (pconn != caller && caller && caller->access_level != ALLOW_HACK) {
3715 cmd_reply(CMD_DETACH, caller, C_FAIL,
3716 _("You can not detach other users."));
3717 goto end;
3718 }
3719
3720 pplayer = pconn->playing;
3721
3722 /* must have someone to detach from... */
3723 if (!pplayer && !pconn->observer) {
3724 cmd_reply(CMD_DETACH, caller, C_FAIL,
3725 _("%s is not attached to any player."), pconn->username);
3726 goto end;
3727 }
3728
3729 res = TRUE;
3730 if (check) {
3731 goto end;
3732 }
3733
3734 if (pplayer) {
3735 cmd_reply(CMD_DETACH, caller, C_OK, _("%s detaching from %s"),
3736 pconn->username, player_name(pplayer));
3737 } else {
3738 cmd_reply(CMD_DETACH, caller, C_OK, _("%s no longer observing."),
3739 pconn->username);
3740 }
3741
3742 /* Actually do the detaching. */
3743 connection_detach(pconn, TRUE);
3744
3745 /* The user explicitly wanted to detach, so if a player is marked for
3746 * them, reset its username. */
3747 players_iterate(aplayer) {
3748 if (!fc_strncmp(aplayer->username, pconn->username, MAX_LEN_NAME)) {
3749 sz_strlcpy(aplayer->username, _(ANON_USER_NAME));
3750 aplayer->unassigned_user = TRUE;
3751 send_player_info_c(aplayer, NULL);
3752 }
3753 } players_iterate_end;
3754
3755 check_for_full_turn_done();
3756
3757 end:
3758 fc_assert_ret_val(ntokens <= 1, FALSE);
3759
3760 /* free our args */
3761 for (i = 0; i < ntokens; i++) {
3762 free(arg[i]);
3763 }
3764 return res;
3765}
3766
3767/**********************************************************************/
3788 bool load_command(struct connection *caller, const char *filename, bool check,
3789 bool cmdline_load)
3790{
3791 struct timer *loadtimer, *uloadtimer;
3792 struct section_file *file;
3793 char arg[MAX_LEN_PATH];
3794 struct conn_list *global_observers;
3795
3796 if (!filename || filename[0] == '\0') {
3797 cmd_reply(CMD_LOAD, caller, C_FAIL, _("Usage:\n%s"),
3798 command_synopsis(command_by_number(CMD_LOAD)));
3799 return FALSE;
3800 }
3801 if (S_S_INITIAL != server_state()) {
3802 cmd_reply(CMD_LOAD, caller, C_FAIL,
3803 _("Cannot load a game while another is running."));
3804 return FALSE;
3805 }
3806 if (!is_safe_filename(filename) && is_restricted(caller)) {
3807 cmd_reply(CMD_LOAD, caller, C_FAIL,
3808 _("Name \"%s\" disallowed for security reasons."),
3809 filename);
3810 return FALSE;
3811 }
3812
3813 {
3814 /* It is a normal savegame or maybe a scenario */
3815 char testfile[MAX_LEN_PATH];
3816 const struct strvec *paths[] = {
3817 get_save_dirs(), get_scenario_dirs(), NULL
3818 };
3819 const char *exts[] = {
3820 "sav", "gz", "bz2", "xz", "sav.gz", "sav.bz2", "sav.xz", "sav.zst", NULL
3821 };
3822 const char **ext, *found = NULL;
3823 const struct strvec **path;
3824
3825 if (cmdline_load) {
3826 /* Allow plain names being loaded with '--file' option, but not otherwise
3827 * (no loading of arbitrary files by unauthorized users)
3828 * Iterate through ALL paths to check for file with plain name before
3829 * looking any path with an extension, i.e., prefer plain name file
3830 * in later directory over file with extension in name in earlier
3831 * directory. */
3832 for (path = paths; !found && *path; path++) {
3833 found = fileinfoname(*path, filename);
3834 if (found != NULL) {
3835 sz_strlcpy(arg, found);
3836 }
3837 }
3838 }
3839
3840 for (path = paths; !found && *path; path++) {
3841 for (ext = exts; !found && *ext; ext++) {
3842 fc_snprintf(testfile, sizeof(testfile), "%s.%s", filename, *ext);
3843 found = fileinfoname(*path, testfile);
3844 if (found != NULL) {
3845 sz_strlcpy(arg, found);
3846 }
3847 }
3848 }
3849
3850 if (is_restricted(caller) && !found) {
3851 cmd_reply(CMD_LOAD, caller, C_FAIL, _("Cannot find savegame or "
3852 "scenario with the name \"%s\"."), filename);
3853 return FALSE;
3854 }
3855
3856 if (!found) {
3857 sz_strlcpy(arg, filename);
3858 }
3859 }
3860
3861 /* attempt to parse the file */
3862
3863 if (!(file = secfile_load(arg, FALSE))) {
3864 log_error("Error loading savefile '%s': %s", arg, secfile_error());
3865 cmd_reply(CMD_LOAD, caller, C_FAIL, _("Could not load savefile: %s"),
3866 arg);
3867 dlsend_packet_game_load(game.est_connections, FALSE, arg);
3868 return FALSE;
3869 }
3870
3871 if (check) {
3872 return TRUE;
3873 }
3874
3875 /* Detach current players, before we blow them away. */
3876 global_observers = conn_list_new();
3877 conn_list_iterate(game.est_connections, pconn) {
3878 if (pconn->playing != NULL) {
3879 connection_detach(pconn, TRUE);
3880 } else if (pconn->observer) {
3881 conn_list_append(global_observers, pconn);
3882 connection_detach(pconn, TRUE);
3883 }
3884 } conn_list_iterate_end;
3885
3886 player_info_freeze();
3887
3888 /* Now free all game data. */
3889 server_game_free();
3890
3891 /* Keep old ruleset value. Scenario file will either use the old value,
3892 * or to initialize new value itself. */
3893 server_game_init(TRUE);
3894
3895 loadtimer = timer_new(TIMER_CPU, TIMER_ACTIVE, "load cpu");
3896 timer_start(loadtimer);
3897 uloadtimer = timer_new(TIMER_USER, TIMER_ACTIVE, "load user");
3898 timer_start(uloadtimer);
3899
3900 sz_strlcpy(srvarg.load_filename, arg);
3901
3902 savegame_load(file);
3903 secfile_check_unused(file);
3904 secfile_destroy(file);
3905
3906 log_verbose("Load time: %g seconds (%g apparent)",
3907 timer_read_seconds(loadtimer), timer_read_seconds(uloadtimer));
3908 timer_destroy(loadtimer);
3909 timer_destroy(uloadtimer);
3910
3911 sanity_check();
3912
3913 log_verbose("load_command() does send_rulesets()");
3914 conn_list_compression_freeze(game.est_connections);
3915 send_rulesets(game.est_connections);
3916 send_server_settings(game.est_connections);
3917 send_scenario_info(game.est_connections);
3918 send_scenario_description(game.est_connections);
3919 send_game_info(game.est_connections);
3920 conn_list_compression_thaw(game.est_connections);
3921
3922 /* Send information about the new players. */
3923 player_info_thaw();
3924 send_player_diplstate_c(NULL, NULL);
3925
3926 /* Everything seemed to load ok; spread the good news. */
3927 dlsend_packet_game_load(game.est_connections, TRUE, srvarg.load_filename);
3928
3929 /* Attach connections to players. Currently, this applies only
3930 * to connections that have the same username as a player. */
3931 conn_list_iterate(game.est_connections, pconn) {
3932 players_iterate(pplayer) {
3933 if (strcmp(pconn->username, pplayer->username) == 0) {
3934 connection_attach(pconn, pplayer, FALSE);
3935 break;
3936 }
3937 } players_iterate_end;
3938 } conn_list_iterate_end;
3939
3940 /* Reattach global observers. */
3941 conn_list_iterate(global_observers, pconn) {
3942 if (NULL == pconn->playing) {
3943 /* May have been assigned to a player before. */
3944 connection_attach(pconn, NULL, TRUE);
3945 }
3946 } conn_list_iterate_end;
3947 conn_list_destroy(global_observers);
3948
3949 (void) aifill(game.info.aifill);
3950
3951 achievements_iterate(pach) {
3952 players_iterate(pplayer) {
3953 struct packet_achievement_info pack;
3954
3955 pack.id = achievement_index(pach);
3956 pack.gained = achievement_player_has(pach, pplayer);
3957 pack.first = (pach->first == pplayer);
3958
3959 lsend_packet_achievement_info(pplayer->connections, &pack);
3960 } players_iterate_end;
3961 } achievements_iterate_end;
3962
3963 return TRUE;
3964}
3965
3966/**********************************************************************/
3975 bool set_rulesetdir(struct connection *caller, const char *str, bool check,
3976 int read_recursion)
3977{
3978 char filename[512];
3979 const char *pfilename;
3980
3981 if (NULL == str || '\0' == str[0]) {
3982 cmd_reply(CMD_RULESETDIR, caller, C_SYNTAX,
3983 _("You must provide a ruleset name. Use \"/show ruleset\" to "
3984 "see what is the current ruleset."));
3985 return FALSE;
3986 }
3987
3988 if (srvarg.ruleset != NULL && is_restricted(caller)) {
3989 cmd_reply(CMD_RULESETDIR, caller, C_FAIL,
3990 _("Changing ruleset not allowed. It was locked from the commandline."));
3991
3992 return FALSE;
3993 }
3994
3995 if (game_was_started() || !map_is_empty()) {
3996 cmd_reply(CMD_RULESETDIR, caller, C_FAIL,
3997 _("This setting can't be modified after the game has started."));
3998 if (game.scenario.is_scenario && !game.scenario.ruleset_locked
3999 && !game_was_started()) {
4000 cmd_reply(CMD_RULESETDIR, caller, C_FAIL,
4001 /* TRANS: scenario name */
4002 _("The ruleset of \"%s\" can be changed by switching to a"
4003 " compatible ruleset before loading it."),
4004 game.scenario.name);
4005 }
4006 return FALSE;
4007 }
4008
4009 if (strcmp(str, game.server.rulesetdir) == 0) {
4010 cmd_reply(CMD_RULESETDIR, caller, C_COMMENT,
4011 _("Ruleset directory is already \"%s\""), str);
4012 return FALSE;
4013 }
4014
4015 if (is_restricted(caller)
4016 && (!is_safe_filename(str) || strchr(str, '.'))) {
4017 cmd_reply(CMD_RULESETDIR, caller, C_SYNTAX,
4018 _("Name \"%s\" disallowed for security reasons."),
4019 str);
4020 return FALSE;
4021 }
4022
4023 fc_snprintf(filename, sizeof(filename), "%s", str);
4024 pfilename = fileinfoname(get_data_dirs(), filename);
4025 if (!pfilename) {
4026 cmd_reply(CMD_RULESETDIR, caller, C_SYNTAX,
4027 _("Ruleset directory \"%s\" not found"), str);
4028 return FALSE;
4029 }
4030
4031 if (!check) {
4032 bool success = TRUE;
4033 char old[512];
4034
4035 sz_strlcpy(old, game.server.rulesetdir);
4036 log_verbose("set_rulesetdir() does load_rulesets() with \"%s\"", str);
4037 sz_strlcpy(game.server.rulesetdir, str);
4038
4039 /* load the ruleset (and game settings defined in the ruleset) */
4040 player_info_freeze();
4041 if (!load_rulesets(old, NULL, FALSE, NULL, TRUE, FALSE, TRUE)) {
4042 success = FALSE;
4043
4044 /* While loading of the requested ruleset failed, we might
4045 * have changed ruleset from third one to default. Handle
4046 * rest of the ruleset changing accordingly. */
4047 }
4048
4049 if (game.est_connections) {
4050 /* Now that the rulesets are loaded we immediately send updates to any
4051 * connected clients. */
4052 send_rulesets(game.est_connections);
4053 }
4054 /* show ruleset summary and list changed values */
4055 show_ruleset_info(caller, CMD_RULESETDIR, check, read_recursion);
4056 player_info_thaw();
4057
4058 if (success) {
4059 cmd_reply(CMD_RULESETDIR, caller, C_OK,
4060 _("Ruleset directory set to \"%s\""), str);
4061 } else {
4062 cmd_reply(CMD_RULESETDIR, caller, C_SYNTAX,
4063 _("Failed loading rulesets from directory \"%s\", using \"%s\""),
4064 str, game.server.rulesetdir);
4065 }
4066
4067 return success;
4068 }
4069
4070 return TRUE;
4071}
4072
4073/**********************************************************************/
4076 static bool ignore_command(struct connection *caller, char *str, bool check)
4077{
4078 char buf[128];
4079 struct conn_pattern *ppattern;
4080
4081 if (NULL == caller) {
4082 cmd_reply(CMD_IGNORE, caller, C_FAIL,
4083 _("That would be rather silly, since you are not a player."));
4084 return FALSE;
4085 }
4086
4087 ppattern = conn_pattern_from_string(str, CPT_USER, buf, sizeof(buf));
4088 if (NULL == ppattern) {
4089 cmd_reply(CMD_IGNORE, caller, C_SYNTAX,
4090 _("%s. Try /help ignore"), buf);
4091 return FALSE;
4092 }
4093
4094 if (check) {
4095 conn_pattern_destroy(ppattern);
4096 return TRUE;
4097 }
4098
4099 conn_pattern_to_string(ppattern, buf, sizeof(buf));
4100 conn_pattern_list_append(caller->server.ignore_list, ppattern);
4101 cmd_reply(CMD_IGNORE, caller, C_COMMENT,
4102 _("Added pattern %s as entry %d to your ignore list."),
4103 buf, conn_pattern_list_size(caller->server.ignore_list));
4104
4105 return TRUE;
4106}
4107
4108/**********************************************************************/
4111 static bool unignore_command(struct connection *caller,
4112 char *str, bool check)
4113{
4114 char buf[128], *c;
4115 int first, last, n;
4116
4117 if (!caller) {
4118 cmd_reply(CMD_IGNORE, caller, C_FAIL,
4119 _("That would be rather silly, since you are not a player."));
4120 return FALSE;
4121 }
4122
4123 sz_strlcpy(buf, str);
4124 remove_leading_trailing_spaces(buf);
4125
4126 n = conn_pattern_list_size(caller->server.ignore_list);
4127 if (n == 0) {
4128 cmd_reply(CMD_UNIGNORE, caller, C_FAIL, _("Your ignore list is empty."));
4129 return FALSE;
4130 }
4131
4132 /* Parse the range. */
4133 if ('\0' == buf[0]) {
4134 cmd_reply(CMD_UNIGNORE, caller, C_SYNTAX,
4135 _("Missing range. Try /help unignore."));
4136 return FALSE;
4137 } else if ((c = strchr(buf, '-'))) {
4138 *c++ = '\0';
4139 if ('\0' == buf[0]) {
4140 first = 1;
4141 } else if (!str_to_int(buf, &first)) {
4142 *--c = '-';
4143 cmd_reply(CMD_UNIGNORE, caller, C_SYNTAX,
4144 _("\"%s\" is not a valid range. Try /help unignore."), buf);
4145 return FALSE;
4146 }
4147 if ('\0' == *c) {
4148 last = n;
4149 } else if (!str_to_int(c, &last)) {
4150 *--c = '-';
4151 cmd_reply(CMD_UNIGNORE, caller, C_SYNTAX,
4152 _("\"%s\" is not a valid range. Try /help unignore."), buf);
4153 return FALSE;
4154 }
4155 } else {
4156 if (!str_to_int(buf, &first)) {
4157 cmd_reply(CMD_UNIGNORE, caller, C_SYNTAX,
4158 _("\"%s\" is not a valid range. Try /help unignore."), buf);
4159 return FALSE;
4160 }
4161 last = first;
4162 }
4163
4164 if (!(1 <= first && first <= last && last <= n)) {
4165 if (first == last) {
4166 cmd_reply(CMD_UNIGNORE, caller, C_FAIL,
4167 _("Invalid entry number: %d."), first);
4168 } else {
4169 cmd_reply(CMD_UNIGNORE, caller, C_FAIL,
4170 _("Invalid range: %d to %d."), first, last);
4171 }
4172 return FALSE;
4173 }
4174
4175 if (check) {
4176 return TRUE;
4177 }
4178
4179 n = 1;
4180 conn_pattern_list_iterate(caller->server.ignore_list, ppattern) {
4181 if (first <= n) {
4182 conn_pattern_to_string(ppattern, buf, sizeof(buf));
4183 cmd_reply(CMD_UNIGNORE, caller, C_COMMENT,
4184 _("Removed pattern %s (entry %d) from your ignore list."),
4185 buf, n);
4186 conn_pattern_list_remove(caller->server.ignore_list, ppattern);
4187 }
4188 n++;
4189 if (n > last) {
4190 break;
4191 }
4192 } conn_pattern_list_iterate_end;
4193
4194 return TRUE;
4195}
4196
4197/**********************************************************************/
4200 static bool playercolor_command(struct connection *caller,
4201 char *str, bool check)
4202{
4203 enum m_pre_result match_result;
4204 struct player *pplayer;
4205 struct rgbcolor *prgbcolor = NULL;
4206 int ntokens = 0;
4207 char *token[2];
4208 bool ret = TRUE;
4209
4210 ntokens = get_tokens(str, token, 2, TOKEN_DELIMITERS);
4211
4212 if (ntokens != 2) {
4213 cmd_reply(CMD_PLAYERCOLOR, caller, C_SYNTAX,
4214 _("Two arguments needed. See '/help playercolor'."));
4215 ret = FALSE;
4216 goto cleanup;
4217 }
4218
4219 pplayer = player_by_name_prefix(token[0], &match_result);
4220
4221 if (!pplayer) {
4222 cmd_reply_no_such_player(CMD_PLAYERCOLOR, caller, token[0], match_result);
4223 ret = FALSE;
4224 goto cleanup;
4225 }
4226
4227 {
4228 const char *reason;
4229 if (!player_color_changeable(pplayer, &reason)) {
4230 cmd_reply(CMD_PLAYERCOLOR, caller, C_FAIL, "%s", reason);
4231 ret = FALSE;
4232 goto cleanup;
4233 }
4234 }
4235
4236 if (0 == fc_strcasecmp(token[1], "reset")) {
4237 if (!game_was_started()) {
4238 prgbcolor = NULL;
4239 } else {
4240 cmd_reply(CMD_PLAYERCOLOR, caller, C_FAIL,
4241 _("Can only unset player color before game starts."));
4242 ret = FALSE;
4243 goto cleanup;
4244 }
4245 } else if (!rgbcolor_from_hex(&prgbcolor, token[1])) {
4246 cmd_reply(CMD_PLAYERCOLOR, caller, C_SYNTAX,
4247 _("Invalid player color definition. See '/help playercolor'."));
4248 ret = FALSE;
4249 goto cleanup;
4250 }
4251
4252 if (prgbcolor != NULL) {
4253 players_iterate(pother) {
4254 if (pother != pplayer && pother->rgb != NULL
4255 && rgbcolors_are_equal(pother->rgb, prgbcolor)) {
4256 cmd_reply(CMD_PLAYERCOLOR, caller, C_WARNING,
4257 /* TRANS: "... [c0ffee] for Caesar ... to Hammurabi." */
4258 _("Warning: new color [%s] for %s is identical to %s."),
4259 player_color_ftstr(pother), player_name(pplayer),
4260 player_name(pother));
4261 }
4262 } players_iterate_end;
4263 }
4264
4265 if (check) {
4266 goto cleanup;
4267 }
4268
4269 server_player_set_color(pplayer, prgbcolor);
4270 cmd_reply(CMD_PLAYERCOLOR, caller, C_OK,
4271 _("Color of player %s set to [%s]."), player_name(pplayer),
4272 player_color_ftstr(pplayer));
4273
4274 cleanup:
4275
4276 rgbcolor_destroy(prgbcolor);
4277 free_tokens(token, ntokens);
4278
4279 return ret;
4280}
4281
4282/**********************************************************************/
4285 static bool playernation_command(struct connection *caller,
4286 char *str, bool check)
4287{
4288 enum m_pre_result match_result;
4289 struct player *pplayer;
4290 struct nation_type *pnation;
4291 struct nation_style *pstyle;
4292 bool is_male = FALSE;
4293 int ntokens = 0;
4294 char *token[5];
4295
4296 ntokens = get_tokens(str, token, 5, TOKEN_DELIMITERS);
4297
4298 if (ntokens == 0) {
4299 cmd_reply(CMD_PLAYERNATION, caller, C_SYNTAX,
4300 _("At least one argument needed. See '/help playernation'."));
4301 free_tokens(token, ntokens);
4302 return FALSE;
4303 }
4304
4305 if (game_was_started()) {
4306 cmd_reply(CMD_PLAYERNATION, caller, C_FAIL,
4307 _("Can only set player nation before game starts."));
4308 free_tokens(token, ntokens);
4309 return FALSE;
4310 }
4311
4312 pplayer = player_by_name_prefix(token[0], &match_result);
4313 if (!pplayer) {
4314 cmd_reply_no_such_player(CMD_PLAYERNATION, caller, token[0], match_result);
4315 free_tokens(token, ntokens);
4316 return FALSE;
4317 }
4318
4319 if (ntokens == 1) {
4320 if (!check) {
4321 player_set_nation(pplayer, NO_NATION_SELECTED);
4322
4323 cmd_reply(CMD_PLAYERNATION, caller, C_OK,
4324 _("Nation of player %s reset."), player_name(pplayer));
4325 send_player_info_c(pplayer, game.est_connections);
4326 }
4327 } else {
4328 pnation = nation_by_rule_name(token[1]);
4329 if (pnation == NO_NATION_SELECTED) {
4330 cmd_reply(CMD_PLAYERNATION, caller, C_FAIL,
4331 _("Unrecognized nation: %s."), token[1]);
4332 free_tokens(token, ntokens);
4333 return FALSE;
4334 }
4335
4336 if (!client_can_pick_nation(pnation)) {
4337 cmd_reply(CMD_PLAYERNATION, caller, C_FAIL,
4338 _("%s nation is not available for user selection."),
4339 token[1]);
4340 free_tokens(token, ntokens);
4341 return FALSE;
4342 }
4343
4344 if (pnation->player && pnation->player != pplayer) {
4345 cmd_reply(CMD_PLAYERNATION, caller, C_FAIL,
4346 _("%s nation is already in use."), token[1]);
4347 free_tokens(token, ntokens);
4348 return FALSE;
4349 }
4350
4351 if (ntokens < 3) {
4352 cmd_reply(CMD_PLAYERNATION, caller, C_FAIL,
4353 /* TRANS: Nation resetting form of /playernation does not require sex */
4354 _("Leader sex must be given when setting nation."));
4355 free_tokens(token, ntokens);
4356 return FALSE;
4357 }
4358
4359 if (!strcmp(token[2], "0")) {
4360 is_male = FALSE;
4361 } else if (!strcmp(token[2], "1")) {
4362 is_male = TRUE;
4363 } else {
4364 cmd_reply(CMD_PLAYERNATION, caller, C_FAIL,
4365 _("Unrecognized gender: %s, expecting 1 or 0."), token[2]);
4366 free_tokens(token, ntokens);
4367 return FALSE;
4368 }
4369
4370 if (ntokens > 4) {
4371 pstyle = style_by_rule_name(token[4]);
4372 if (!pstyle) {
4373 cmd_reply(CMD_PLAYERNATION, caller, C_FAIL,
4374 _("Unrecognized style: %s."), token[4]);
4375 free_tokens(token, ntokens);
4376 return FALSE;
4377 }
4378 } else {
4379 pstyle = style_of_nation(pnation);
4380 }
4381
4382 if (!check) {
4383 char error_buf[256];
4384
4385 player_set_nation(pplayer, pnation);
4386 pplayer->style = pstyle;
4387 pplayer->is_male = is_male;
4388
4389 if (ntokens > 3) {
4390 if (!server_player_set_name_full(caller, pplayer, pnation, token[3],
4391 error_buf, sizeof(error_buf))) {
4392 cmd_reply(CMD_PLAYERNATION, caller, C_WARNING, "%s", error_buf);
4393 }
4394 } else {
4395 server_player_set_name(pplayer, token[0]);
4396 }
4397 cmd_reply(CMD_PLAYERNATION, caller, C_OK,
4398 _("Nation of player %s set to [%s]."), player_name(pplayer),
4399 nation_rule_name(pnation));
4400 send_player_info_c(pplayer, game.est_connections);
4401 }
4402 }
4403
4404 free_tokens(token, ntokens);
4405
4406 return TRUE;
4407}
4408
4409/**************************************************************************
4410 Handle quit command
4411**************************************************************************/
4412 static bool quit_game(struct connection *caller, bool check)
4413{
4414 if (!check) {
4415 cmd_reply(CMD_QUIT, caller, C_OK, _("Goodbye."));
4416 server_quit();
4417 }
4418
4419 return TRUE;
4420}
4421
4422/**********************************************************************/
4426 bool handle_stdin_input(struct connection *caller, char *str)
4427{
4428 return handle_stdin_input_real(caller, str, FALSE, 0);
4429}
4430
4431/**********************************************************************/
4434 bool handle_stdin_input_free(struct connection *caller, char *str)
4435{
4436 bool ret = handle_stdin_input_real(caller, str, FALSE, 0);
4437
4438 /* Since handle_stdin_input_real() returned,
4439 * we can be sure this was not freed in atexit(). */
4440 free(str);
4441
4442 return ret;
4443}
4444
4445/**********************************************************************/
4453 static bool handle_stdin_input_real(struct connection *caller, char *str,
4454 bool check, int read_recursion)
4455{
4456 char full_command[MAX_LEN_CONSOLE_LINE];
4457 char command[MAX_LEN_CONSOLE_LINE], arg[MAX_LEN_CONSOLE_LINE];
4458 char *cptr_s, *cptr_d;
4459 enum command_id cmd;
4460 enum cmdlevel level;
4461
4462 /* Remove leading and trailing spaces, and server command prefix. */
4463 cptr_s = str = skip_leading_spaces(str);
4464 if ('\0' == *cptr_s || '#' == *cptr_s) {
4465 /* This appear to be a comment or blank line. */
4466 return FALSE;
4467 }
4468
4469 if (SERVER_COMMAND_PREFIX == *cptr_s) {
4470 /* Commands may be prefixed with SERVER_COMMAND_PREFIX, even when
4471 * given on the server command line. */
4472 cptr_s++;
4473 remove_leading_spaces(cptr_s);
4474 if ('\0' == *cptr_s) {
4475 /* This appear to be a blank line. */
4476 return FALSE;
4477 }
4478 }
4479 remove_trailing_spaces(cptr_s);
4480
4481 /* notify to the server console */
4482 if (!check && caller) {
4483 con_write(C_COMMENT, "%s: '%s'", caller->username, str);
4484 }
4485
4486 /* if the caller may not use any commands at all, don't waste any time */
4487 if (may_use_nothing(caller)) {
4488 cmd_reply(CMD_HELP, caller, C_FAIL,
4489 _("Sorry, you are not allowed to use server commands."));
4490 return FALSE;
4491 }
4492
4493 /* copy the full command, in case we need it for voting purposes. */
4494 sz_strlcpy(full_command, cptr_s);
4495
4496 /*
4497 * cptr_s points now to the beginning of the real command. It has
4498 * skipped leading whitespace, the SERVER_COMMAND_PREFIX and any
4499 * other non-alphanumeric characters.
4500 */
4501 for (cptr_d = command; *cptr_s != '\0' && fc_isalnum(*cptr_s)
4502 && cptr_d < command + sizeof(command) - 1; cptr_s++, cptr_d++) {
4503 *cptr_d = *cptr_s;
4504 }
4505 *cptr_d = '\0';
4506
4507 /* cptr_s now contains the arguments. */
4508 sz_strlcpy(arg, skip_leading_spaces(cptr_s));
4509
4510 cmd = command_named(command, FALSE);
4511 if (cmd == CMD_AMBIGUOUS) {
4512 cmd = command_named(command, TRUE);
4513 cmd_reply(cmd, caller, C_SYNTAX,
4514 _("Warning: '%s' interpreted as '%s', but it is ambiguous."
4515 " Try '%shelp'."),
4516 command, command_name_by_number(cmd), caller?"/":"");
4517 } else if (cmd == CMD_UNRECOGNIZED) {
4518 cmd_reply(cmd, caller, C_SYNTAX, _("Unknown command '%s%s'. "
4519 " Try '%shelp'."),
4520 caller ? "/" : "", command, caller ? "/" : "");
4521 return FALSE;
4522 }
4523
4524 level = command_level(command_by_number(cmd));
4525
4526 if (conn_can_vote(caller, NULL) && level == ALLOW_CTRL
4527 && conn_get_access(caller) == ALLOW_BASIC && !check
4528 && !vote_would_pass_immediately(caller, cmd)) {
4529 struct vote *vote;
4530 bool caller_had_vote = (NULL != get_vote_by_caller(caller));
4531
4532 /* Check if the vote command would succeed. If we already have a vote
4533 * going, cancel it in favour of the new vote command. You can only
4534 * have one vote at a time. This is done by vote_new(). */
4535 if (handle_stdin_input_real(caller, full_command, TRUE,
4536 read_recursion + 1)
4537 && (vote = vote_new(caller, arg, cmd))) {
4538 char votedesc[MAX_LEN_CONSOLE_LINE];
4539 const struct player *teamplr;
4540 const char *what;
4541 struct ft_color color;
4542
4543 if (caller_had_vote) {
4544 cmd_reply(CMD_VOTE, caller, C_COMMENT,
4545 /* TRANS: "vote" as a process */
4546 _("Your new vote canceled your previous vote."));
4547 }
4548
4549 describe_vote(vote, votedesc, sizeof(votedesc));
4550
4551 if (vote_is_team_only(vote)) {
4552 /* TRANS: "vote" as a process */
4553 what = _("New teamvote");
4554 teamplr = conn_get_player(caller);
4555 color = ftc_vote_team;
4556 } else {
4557 /* TRANS: "vote" as a process */
4558 what = _("New vote");
4559 teamplr = NULL;
4560 color = ftc_vote_public;
4561 }
4562 notify_team(teamplr, NULL, E_VOTE_NEW, color,
4563 /* TRANS: "[New vote|New teamvote] (number 3)
4564 * by fred: proposed change" */
4565 _("%s (number %d) by %s: %s"), what,
4566 vote->vote_no, caller->username, votedesc);
4567
4568 /* Vote on your own suggestion. */
4569 connection_vote(caller, vote, VOTE_YES);
4570 return TRUE;
4571
4572 } else {
4573 cmd_reply(CMD_VOTE, caller, C_FAIL,
4574 /* TRANS: "vote" as a process */
4575 _("Your new vote (\"%s\") was not "
4576 "legal or was not recognized."), full_command);
4577 return FALSE;
4578 }
4579 }
4580
4581 if (caller
4582 && !((check || vote_would_pass_immediately(caller, cmd))
4583 && conn_get_access(caller) >= ALLOW_BASIC
4584 && level == ALLOW_CTRL)
4585 && conn_get_access(caller) < level) {
4586 cmd_reply(cmd, caller, C_FAIL,
4587 _("You are not allowed to use this command."));
4588 return FALSE;
4589 }
4590
4591 if (!check) {
4592 struct conn_list *echo_list = NULL;
4593 bool echo_list_allocated = FALSE;
4594
4595 switch (command_echo(command_by_number(cmd))) {
4596 case CMD_ECHO_NONE:
4597 break;
4598 case CMD_ECHO_ADMINS:
4599 conn_list_iterate(game.est_connections, pconn) {
4600 if (ALLOW_ADMIN <= conn_get_access(pconn)) {
4601 if (NULL == echo_list) {
4602 echo_list = conn_list_new();
4603 echo_list_allocated = TRUE;
4604 }
4605 conn_list_append(echo_list, pconn);
4606 }
4607 } conn_list_iterate_end;
4608 break;
4609 case CMD_ECHO_ALL:
4610 echo_list = game.est_connections;
4611 break;
4612 }
4613
4614 if (NULL != echo_list) {
4615 if (caller) {
4616 notify_conn(echo_list, NULL, E_SETTING, ftc_any,
4617 "%s: '%s %s'", caller->username, command, arg);
4618 } else {
4619 notify_conn(echo_list, NULL, E_SETTING, ftc_server_prompt,
4620 "%s: '%s %s'", _("(server prompt)"), command, arg);
4621 }
4622 if (echo_list_allocated) {
4623 conn_list_destroy(echo_list);
4624 }
4625 }
4626 }
4627
4628 switch (cmd) {
4629 case CMD_REMOVE:
4630 return remove_player_command(caller, arg, check);
4631 case CMD_SAVE:
4632 return save_command(caller, arg, check);
4633 case CMD_SCENSAVE:
4634 return scensave_command(caller, arg, check);
4635 case CMD_LOAD:
4636 return load_command(caller, arg, check, FALSE);
4637 case CMD_METAPATCHES:
4638 return metapatches_command(caller, arg, check);
4639 case CMD_METAMESSAGE:
4640 return metamessage_command(caller, arg, check);
4641 case CMD_METACONN:
4642 return metaconnection_command(caller, arg, check);
4643 case CMD_METASERVER:
4644 return metaserver_command(caller, arg, check);
4645 case CMD_HELP:
4646 return show_help(caller, arg);
4647 case CMD_SRVID:
4648 return show_serverid(caller, arg);
4649 case CMD_LIST:
4650 return show_list(caller, arg);
4651 case CMD_AITOGGLE:
4652 return toggle_ai_command(caller, arg, check);
4653 case CMD_TAKE:
4654 return take_command(caller, arg, check);
4655 case CMD_OBSERVE:
4656 return observe_command(caller, arg, check);
4657 case CMD_DETACH:
4658 return detach_command(caller, arg, check);
4659 case CMD_CREATE:
4660 return create_command(caller, arg, check);
4661 case CMD_AWAY:
4662 return away_command(caller, check);
4663 case CMD_RESTRICTED:
4664 case CMD_NOVICE:
4665 case CMD_EASY:
4666 case CMD_NORMAL:
4667 case CMD_HARD:
4668 case CMD_CHEATING:
4669#ifdef FREECIV_DEBUG
4670 case CMD_EXPERIMENTAL:
4671#endif
4672 return set_ai_level_named(caller, arg, command_name_by_number(cmd), check);
4673 case CMD_QUIT:
4674 return quit_game(caller, check);
4675 case CMD_CUT:
4676 return cut_client_connection(caller, arg, check);
4677 case CMD_SHOW:
4678 return show_command(caller, arg, check);
4679 case CMD_EXPLAIN:
4680 return explain_option(caller, arg, check);
4681 case CMD_DEBUG:
4682 return debug_command(caller, arg, check);
4683 case CMD_SET:
4684 return set_command(caller, arg, check);
4685 case CMD_TEAM:
4686 return team_command(caller, arg, check);
4687 case CMD_RULESETDIR:
4688 return set_rulesetdir(caller, arg, check, read_recursion);
4689 case CMD_WALL:
4690 return wall(arg, check);
4691 case CMD_CONNECTMSG:
4692 return connectmsg_command(caller, arg, check);
4693 case CMD_VOTE:
4694 return vote_command(caller, arg, check);
4695 case CMD_CANCELVOTE:
4696 return cancelvote_command(caller, arg, check);
4697 case CMD_READ_SCRIPT:
4698 return read_command(caller, arg, check, read_recursion);
4699 case CMD_WRITE_SCRIPT:
4700 return write_command(caller, arg, check);
4701 case CMD_RESET:
4702 return reset_command(caller, arg, check, read_recursion);
4703 case CMD_DEFAULT:
4704 return default_command(caller, arg, check);
4705 case CMD_LUA:
4706 return lua_command(caller, arg, check, read_recursion);
4707 case CMD_KICK:
4708 return kick_command(caller, arg, check);
4709 case CMD_DELEGATE:
4710 return delegate_command(caller, arg, check);
4711 case CMD_AICMD:
4712 return aicmd_command(caller, arg, check);
4713 case CMD_FCDB:
4714 return fcdb_command(caller, arg, check);
4715 case CMD_MAPIMG:
4716 return mapimg_command(caller, arg, check);
4717 case CMD_LOCK:
4718 return lock_command(caller, arg, check);
4719 case CMD_UNLOCK:
4720 return unlock_command(caller, arg, check);
4721 case CMD_RFCSTYLE: /* see console.h for an explanation */
4722 if (!check) {
4723 con_set_style(!con_get_style());
4724 }
4725 return TRUE;
4726 case CMD_CMDLEVEL:
4727 return cmdlevel_command(caller, arg, check);
4728 case CMD_FIRSTLEVEL:
4729 return firstlevel_command(caller, check);
4730 case CMD_TIMEOUT:
4731 return timeout_command(caller, arg, check);
4732 case CMD_START_GAME:
4733 return start_command(caller, check, FALSE);
4734 case CMD_END_GAME:
4735 return end_command(caller, arg, check);
4736 case CMD_SURRENDER:
4737 return surrender_command(caller, arg, check);
4738 case CMD_IGNORE:
4739 return ignore_command(caller, arg, check);
4740 case CMD_UNIGNORE:
4741 return unignore_command(caller, arg, check);
4742 case CMD_PLAYERCOLOR:
4743 return playercolor_command(caller, arg, check);
4744 case CMD_PLAYERNATION:
4745 return playernation_command(caller, arg, check);
4746 case CMD_NUM:
4747 case CMD_UNRECOGNIZED:
4748 case CMD_AMBIGUOUS:
4749 break;
4750 }
4751 /* should NEVER happen! */
4752 log_error("Unknown command variant: %d.", cmd);
4753 return FALSE;
4754}
4755
4756/**********************************************************************/
4759 static bool end_command(struct connection *caller, char *str, bool check)
4760{
4761 if (S_S_RUNNING == server_state()) {
4762 if (check) {
4763 return TRUE;
4764 }
4765 notify_conn(game.est_connections, NULL, E_GAME_END, ftc_server,
4766 _("Game is over."));
4767 set_server_state(S_S_OVER);
4768 force_end_of_sniff = TRUE;
4769 cmd_reply(CMD_END_GAME, caller, C_OK,
4770 _("Ending the game. The server will restart once all clients "
4771 "have disconnected."));
4772 return TRUE;
4773 } else {
4774 cmd_reply(CMD_END_GAME, caller, C_FAIL,
4775 _("Cannot end the game: no game running."));
4776 return FALSE;
4777 }
4778}
4779
4780/**********************************************************************/
4784 static bool surrender_command(struct connection *caller, char *str, bool check)
4785{
4786 struct player *pplayer;
4787
4788 if (caller == NULL || !conn_controls_player(caller)) {
4789 cmd_reply(CMD_SURRENDER, caller, C_FAIL,
4790 _("You are not allowed to use this command."));
4791 return FALSE;
4792 }
4793
4794 if (S_S_RUNNING != server_state()) {
4795 cmd_reply(CMD_SURRENDER, caller, C_FAIL, _("You cannot surrender now."));
4796 return FALSE;
4797 }
4798
4799 pplayer = conn_get_player(caller);
4800 if (player_status_check(pplayer, PSTATUS_SURRENDER)) {
4801 cmd_reply(CMD_SURRENDER, caller, C_FAIL,
4802 _("You have already conceded the game."));
4803 return FALSE;
4804 }
4805
4806 if (check) {
4807 return TRUE;
4808 }
4809
4810 notify_conn(game.est_connections, NULL, E_GAME_END, ftc_server,
4811 _("%s has conceded the game and can no longer win."),
4812 player_name(pplayer));
4813 player_status_add(pplayer, PSTATUS_SURRENDER);
4814 return TRUE;
4815}
4816
4817/* Define the possible arguments to the reset command */
4818#define SPECENUM_NAME reset_args
4819#define SPECENUM_VALUE0 RESET_GAME
4820#define SPECENUM_VALUE0NAME "game"
4821#define SPECENUM_VALUE1 RESET_RULESET
4822#define SPECENUM_VALUE1NAME "ruleset"
4823#define SPECENUM_VALUE2 RESET_SCRIPT
4824#define SPECENUM_VALUE2NAME "script"
4825#define SPECENUM_VALUE3 RESET_DEFAULT
4826#define SPECENUM_VALUE3NAME "default"
4827#include "specenum_gen.h"
4828
4829/**********************************************************************/
4832 static const char *reset_accessor(int i)
4833{
4834 i = CLIP(0, i, reset_args_max());
4835 return reset_args_name((enum reset_args) i);
4836}
4837
4838/**********************************************************************/
4842 static bool reset_command(struct connection *caller, char *arg, bool check,
4843 int read_recursion)
4844{
4845 enum m_pre_result result;
4846 int ind;
4847
4848 /* match the argument */
4849 result = match_prefix(reset_accessor, reset_args_max() + 1, 0,
4850 fc_strncasecmp, NULL, arg, &ind);
4851
4852 switch (result) {
4853 case M_PRE_EXACT:
4854 case M_PRE_ONLY:
4855 /* we have a match */
4856 break;
4857 case M_PRE_AMBIGUOUS:
4858 case M_PRE_EMPTY:
4859 /* use 'ruleset' [1] if the game was not started; else use 'game' [2] */
4860 if (S_S_INITIAL == server_state() && game.info.is_new_game) {
4861 cmd_reply(CMD_RESET, caller, C_WARNING,
4862 _("Guessing argument 'ruleset'."));
4863 ind = RESET_RULESET;
4864 } else {
4865 cmd_reply(CMD_RESET, caller, C_WARNING,
4866 _("Guessing argument 'game'."));
4867 ind = RESET_GAME;
4868 }
4869 break;
4870 case M_PRE_LONG:
4871 case M_PRE_FAIL:
4872 case M_PRE_LAST:
4873 cmd_reply(CMD_RESET, caller, C_FAIL,
4874 _("The valid arguments are: 'game', 'ruleset', 'script' "
4875 "or 'default'."));
4876 return FALSE;
4877 break;
4878 }
4879
4880 if (check) {
4881 return TRUE;
4882 }
4883
4884 switch (ind) {
4885 case RESET_GAME:
4886 if (!game.info.is_new_game) {
4887 if (settings_game_reset()) {
4888 cmd_reply(CMD_RESET, caller, C_OK,
4889 _("Reset all settings to the values at the game start."));
4890 } else {
4891 cmd_reply(CMD_RESET, caller, C_FAIL,
4892 _("No saved settings from the game start available."));
4893 return FALSE;
4894 }
4895 } else {
4896 cmd_reply(CMD_RESET, caller, C_FAIL, _("No game started..."));
4897 return FALSE;
4898 }
4899 break;
4900
4901 case RESET_RULESET:
4902 /* Restore game settings saved in game.ruleset. */
4903 if (reload_rulesets_settings()) {
4904 cmd_reply(CMD_RESET, caller, C_OK,
4905 _("Reset all settings to ruleset values."));
4906 } else {
4907 cmd_reply(CMD_RESET, caller, C_FAIL,
4908 _("Failed to reset settings to ruleset values."));
4909 }
4910 break;
4911
4912 case RESET_SCRIPT:
4913 cmd_reply(CMD_RESET, caller, C_OK,
4914 _("Reset all settings and rereading the server start "
4915 "script."));
4916 settings_reset();
4917 /* Load initial script */
4918 if (NULL != srvarg.script_filename
4919 && !read_init_script_real(NULL, srvarg.script_filename, TRUE, FALSE,
4920 read_recursion + 1)) {
4921 if (NULL != caller) {
4922 cmd_reply(CMD_RESET, caller, C_FAIL,
4923 _("Could not read script file '%s'."),
4924 srvarg.script_filename);
4925 }
4926 return FALSE;
4927 }
4928 break;
4929
4930 case RESET_DEFAULT:
4931 cmd_reply(CMD_RESET, caller, C_OK,
4932 _("Reset all settings to default values."));
4933 settings_reset();
4934 break;
4935 }
4936
4937 send_server_settings(game.est_connections);
4938 cmd_reply(CMD_RESET, caller, C_OK, _("Settings re-initialized."));
4939
4940 /* show ruleset summary and list changed values */
4941 show_ruleset_info(caller, CMD_RESET, check, read_recursion);
4942
4943 return TRUE;
4944}
4945
4946/**********************************************************************/
4949 static bool default_command(struct connection *caller, char *arg, bool check)
4950{
4951 struct setting *pset;
4952 char reject_msg[256] = "";
4953
4954 pset = validate_setting_arg(CMD_DEFAULT, caller, arg);
4955
4956 if (!pset) {
4957 /* Reason already reported. */
4958 return FALSE;
4959 }
4960
4961 if (!setting_is_changeable(pset, caller, reject_msg, sizeof(reject_msg))) {
4962 cmd_reply(CMD_DEFAULT, caller, C_FAIL, "%s", reject_msg);
4963
4964 return FALSE;
4965 }
4966
4967 if (!check) {
4968 setting_set_to_default(pset);
4969 cmd_reply(CMD_DEFAULT, caller, C_OK,
4970 _("Option '%s' reset to default value, and will track any "
4971 "default changes."), arg);
4972 }
4973
4974 return TRUE;
4975}
4976
4977/* Define the possible arguments to the delegation command */
4978#define SPECENUM_NAME lua_args
4979#define SPECENUM_VALUE0 LUA_CMD
4980#define SPECENUM_VALUE0NAME "cmd"
4981#define SPECENUM_VALUE1 LUA_FILE
4982#define SPECENUM_VALUE1NAME "file"
4983#define SPECENUM_VALUE2 LUA_UNSAFE_CMD
4984#define SPECENUM_VALUE2NAME "unsafe-cmd"
4985#define SPECENUM_VALUE3 LUA_UNSAFE_FILE
4986#define SPECENUM_VALUE3NAME "unsafe-file"
4987#include "specenum_gen.h"
4988
4989/**********************************************************************/
4992 static const char *lua_accessor(int i)
4993{
4994 i = CLIP(0, i, lua_args_max());
4995 return lua_args_name((enum lua_args) i);
4996}
4997
4998/**********************************************************************/
5001 static bool lua_command(struct connection *caller, char *arg, bool check,
5002 int read_recursion)
5003{
5004 struct stat statbuf;
5005 const char extension[] = ".lua", *real_filename = NULL;
5006 char luafile[4096], tilde_filename[4096];
5007 char *tokens[1], *luaarg = NULL;
5008 int ntokens, ind;
5009 enum m_pre_result result;
5010 bool ret = FALSE;
5011
5012 ntokens = get_tokens(arg, tokens, 1, TOKEN_DELIMITERS);
5013
5014 if (ntokens > 0) {
5015 /* match the argument */
5016 result = match_prefix(lua_accessor, lua_args_max() + 1, 0,
5017 fc_strncasecmp, NULL, tokens[0], &ind);
5018
5019 switch (result) {
5020 case M_PRE_EXACT:
5021 case M_PRE_ONLY:
5022 /* We have a match */
5023 luaarg = arg + strlen(lua_args_name(ind));
5024 luaarg = skip_leading_spaces(luaarg);
5025 break;
5026 case M_PRE_EMPTY:
5027 /* Nothing. */
5028 break;
5029 case M_PRE_AMBIGUOUS:
5030 case M_PRE_LONG:
5031 case M_PRE_FAIL:
5032 case M_PRE_LAST:
5033 /* Fall back to depreciated 'lua <script command>' syntax. */
5034 cmd_reply(CMD_LUA, caller, C_SYNTAX,
5035 _("Fall back to old syntax '%slua <script command>'."),
5036 caller ? "/" : "");
5037 ind = LUA_CMD;
5038 luaarg = arg;
5039 break;
5040 }
5041 }
5042
5043 if (luaarg == NULL) {
5044 cmd_reply(CMD_LUA, caller, C_FAIL,
5045 _("No lua command or lua script file. See '%shelp lua'."),
5046 caller ? "/" : "");
5047 ret = TRUE;
5048 goto cleanup;
5049 }
5050
5051 switch (ind) {
5052 case LUA_CMD:
5053 /* Nothing to check. */
5054 break;
5055 case LUA_UNSAFE_CMD:
5056 if (read_recursion > 0) {
5057 cmd_reply(CMD_LUA, caller, C_FAIL,
5058 _("Unsafe Lua code can only be run by explicit command."));
5059 ret = FALSE;
5060 goto cleanup;
5061 } else if (is_restricted(caller)) {
5062 cmd_reply(CMD_LUA, caller, C_FAIL,
5063 _("You aren't allowed to run unsafe Lua code."));
5064 ret = FALSE;
5065 goto cleanup;
5066 }
5067 break;
5068 case LUA_UNSAFE_FILE:
5069 if (read_recursion > 0) {
5070 cmd_reply(CMD_LUA, caller, C_FAIL,
5071 _("Unsafe Lua code can only be run by explicit command."));
5072 ret = FALSE;
5073 goto cleanup;
5074 } else if (is_restricted(caller)) {
5075 cmd_reply(CMD_LUA, caller, C_FAIL,
5076 _("You aren't allowed to run unsafe Lua code."));
5077 ret = FALSE;
5078 goto cleanup;
5079 }
5080
5081 fc__fallthrough;
5082 case LUA_FILE:
5083 /* Abuse real_filename to find if we already have a .lua extension. */
5084 real_filename = luaarg + strlen(luaarg) - MIN(strlen(extension),
5085 strlen(luaarg));
5086 if (strcmp(real_filename, extension) != 0) {
5087 fc_snprintf(luafile, sizeof(luafile), "%s%s", luaarg, extension);
5088 } else {
5089 sz_strlcpy(luafile, luaarg);
5090 }
5091
5092 if (is_restricted(caller)) {
5093 if (!is_safe_filename(luafile)) {
5094 cmd_reply(CMD_LUA, caller, C_FAIL,
5095 _("Freeciv script '%s' disallowed for security reasons."),
5096 luafile);
5097 ret = FALSE;
5098 goto cleanup;
5099 }
5100 sz_strlcpy(tilde_filename, luafile);
5101 } else {
5102 interpret_tilde(tilde_filename, sizeof(tilde_filename), luafile);
5103 }
5104
5105 real_filename = fileinfoname(get_data_dirs(), tilde_filename);
5106 if (!real_filename) {
5107 if (is_restricted(caller)) {
5108 cmd_reply(CMD_LUA, caller, C_FAIL,
5109 _("No Freeciv script found by the name '%s'."),
5110 tilde_filename);
5111 ret = FALSE;
5112 goto cleanup;
5113 }
5114 /* File is outside data directories */
5115 real_filename = tilde_filename;
5116 }
5117 break;
5118 }
5119
5120 if (check) {
5121 ret = TRUE;
5122 goto cleanup;
5123 }
5124
5125 switch (ind) {
5126 case LUA_CMD:
5127 ret = script_server_do_string(caller, luaarg);
5128 break;
5129 case LUA_UNSAFE_CMD:
5130 ret = script_server_unsafe_do_string(caller, luaarg);
5131 break;
5132 case LUA_FILE:
5133 cmd_reply(CMD_LUA, caller, C_COMMENT,
5134 _("Loading Freeciv script file '%s'."), real_filename);
5135
5136 if (is_reg_file_for_access(real_filename, FALSE)
5137 && !fc_stat(real_filename, &statbuf)) {
5138 ret = script_server_do_file(caller, real_filename);
5139 } else {
5140 cmd_reply(CMD_LUA, caller, C_FAIL,
5141 _("Cannot read Freeciv script '%s'."), real_filename);
5142 ret = FALSE;
5143 }
5144 break;
5145 case LUA_UNSAFE_FILE:
5146 cmd_reply(CMD_LUA, caller, C_COMMENT,
5147 _("Loading Freeciv script file '%s'."), real_filename);
5148
5149 if (is_reg_file_for_access(real_filename, FALSE)
5150 && !fc_stat(real_filename, &statbuf)) {
5151 ret = script_server_unsafe_do_file(caller, real_filename);
5152 } else {
5153 cmd_reply(CMD_LUA, caller, C_FAIL,
5154 _("Cannot read Freeciv script '%s'."), real_filename);
5155 ret = FALSE;
5156 }
5157 break;
5158 }
5159
5160 cleanup:
5161 free_tokens(tokens, ntokens);
5162 return ret;
5163}
5164
5165/* Define the possible arguments to the delegation command */
5166#define SPECENUM_NAME delegate_args
5167#define SPECENUM_VALUE0 DELEGATE_CANCEL
5168#define SPECENUM_VALUE0NAME "cancel"
5169#define SPECENUM_VALUE1 DELEGATE_RESTORE
5170#define SPECENUM_VALUE1NAME "restore"
5171#define SPECENUM_VALUE2 DELEGATE_SHOW
5172#define SPECENUM_VALUE2NAME "show"
5173#define SPECENUM_VALUE3 DELEGATE_TAKE
5174#define SPECENUM_VALUE3NAME "take"
5175#define SPECENUM_VALUE4 DELEGATE_TO
5176#define SPECENUM_VALUE4NAME "to"
5177#include "specenum_gen.h"
5178
5179/**********************************************************************/
5182 static const char *delegate_accessor(int i)
5183{
5184 i = CLIP(0, i, delegate_args_max());
5185 return delegate_args_name((enum delegate_args) i);
5186}
5187
5188/**********************************************************************/
5191 static bool delegate_command(struct connection *caller, char *arg,
5192 bool check)
5193{
5194 char *tokens[3];
5195 int ntokens, ind = delegate_args_invalid();
5196 enum m_pre_result result;
5197 bool player_specified = FALSE; /* affects messages only */
5198 bool ret = FALSE;
5199 const char *username = NULL;
5200 struct player *dplayer = NULL;
5201
5202 if (!game_was_started()) {
5203 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("Game not started - "
5204 "cannot delegate yet."));
5205 return FALSE;
5206 }
5207
5208 ntokens = get_tokens(arg, tokens, 3, TOKEN_DELIMITERS);
5209
5210 if (ntokens > 0) {
5211 /* match the argument */
5212 result = match_prefix(delegate_accessor, delegate_args_max() + 1, 0,
5213 fc_strncasecmp, NULL, tokens[0], &ind);
5214
5215 switch (result) {
5216 case M_PRE_EXACT:
5217 case M_PRE_ONLY:
5218 /* we have a match */
5219 break;
5220 case M_PRE_EMPTY:
5221 if (caller) {
5222 /* Use 'delegate show' as default. */
5223 ind = DELEGATE_SHOW;
5224 }
5225 break;
5226 case M_PRE_AMBIGUOUS:
5227 case M_PRE_LONG:
5228 case M_PRE_FAIL:
5229 case M_PRE_LAST:
5230 ind = delegate_args_invalid();
5231 break;
5232 }
5233 } else {
5234 if (caller) {
5235 /* Use 'delegate show' as default. */
5236 ind = DELEGATE_SHOW;
5237 }
5238 }
5239
5240 if (!delegate_args_is_valid(ind)) {
5241 char buf[256] = "";
5242 enum delegate_args valid_args;
5243
5244 for (valid_args = delegate_args_begin();
5245 valid_args != delegate_args_end();
5246 valid_args = delegate_args_next(valid_args)) {
5247 const char *name = delegate_args_name(valid_args);
5248
5249 if (name != NULL) {
5250 cat_snprintf(buf, sizeof(buf), "'%s'", name);
5251 if (valid_args != delegate_args_max()) {
5252 cat_snprintf(buf, sizeof(buf), ", ");
5253 }
5254 }
5255 }
5256
5257 cmd_reply(CMD_DELEGATE, caller, C_SYNTAX,
5258 /* TRANS: do not translate the command 'delegate'. */
5259 _("Valid arguments for 'delegate' are: %s."), buf);
5260 ret = FALSE;
5261 goto cleanup;
5262 }
5263
5264 /* Get the data (player, username for delegation) and validate it. */
5265 switch (ind) {
5266 case DELEGATE_CANCEL:
5267 /* delegate cancel [player] */
5268 if (ntokens > 1) {
5269 if (!caller || conn_get_access(caller) >= ALLOW_ADMIN) {
5270 player_specified = TRUE;
5271 dplayer = player_by_name_prefix(tokens[1], &result);
5272 if (!dplayer) {
5273 cmd_reply_no_such_player(CMD_DELEGATE, caller, tokens[1], result);
5274 ret = FALSE;
5275 goto cleanup;
5276 }
5277 } else {
5278 cmd_reply(CMD_DELEGATE, caller, C_SYNTAX,
5279 _("Command level '%s' or greater needed to modify "
5280 "others' delegations."), cmdlevel_name(ALLOW_ADMIN));
5281 ret = FALSE;
5282 goto cleanup;
5283 }
5284 } else {
5285 dplayer = conn_get_player(caller);
5286 if (!dplayer) {
5287 cmd_reply(CMD_DELEGATE, caller, C_SYNTAX,
5288 _("Please specify a player for whom delegation should "
5289 "be canceled."));
5290 ret = FALSE;
5291 goto cleanup;
5292 }
5293 }
5294 break;
5295 case DELEGATE_RESTORE:
5296 /* delegate restore */
5297 if (!caller) {
5298 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5299 _("You can't switch players from the console."));
5300 ret = FALSE;
5301 goto cleanup;
5302 }
5303 break;
5304 case DELEGATE_SHOW:
5305 /* delegate show [player] */
5306 if (ntokens > 1) {
5307 player_specified = TRUE;
5308 dplayer = player_by_name_prefix(tokens[1], &result);
5309 if (!dplayer) {
5310 cmd_reply_no_such_player(CMD_DELEGATE, caller, tokens[1], result);
5311 ret = FALSE;
5312 goto cleanup;
5313 }
5314 } else {
5315 dplayer = conn_get_player(caller);
5316 if (!dplayer) {
5317 cmd_reply(CMD_DELEGATE, caller, C_SYNTAX,
5318 _("Please specify a player for whom the delegation should "
5319 "be shown."));
5320 ret = FALSE;
5321 goto cleanup;
5322 }
5323 }
5324 break;
5325 case DELEGATE_TAKE:
5326 /* delegate take <player> */
5327 if (!caller) {
5328 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5329 _("You can't switch players from the console."));
5330 ret = FALSE;
5331 goto cleanup;
5332 }
5333 if (ntokens > 1) {
5334 player_specified = TRUE;
5335 dplayer = player_by_name_prefix(tokens[1], &result);
5336 if (!dplayer) {
5337 cmd_reply_no_such_player(CMD_DELEGATE, caller, tokens[1], result);
5338 ret = FALSE;
5339 goto cleanup;
5340 }
5341 } else {
5342 cmd_reply(CMD_DELEGATE, caller, C_SYNTAX,
5343 _("Please specify a player to take control of."));
5344 ret = FALSE;
5345 goto cleanup;
5346 }
5347 break;
5348 case DELEGATE_TO:
5349 break;
5350 }
5351 /* All checks done to this point will give pretty much the same result at
5352 * any time. Checks after this point are more likely to vary over time. */
5353 if (check) {
5354 ret = TRUE;
5355 goto cleanup;
5356 }
5357
5358 switch (ind) {
5359 case DELEGATE_TO:
5360 /* delegate to <username> [player] */
5361 if (ntokens > 1) {
5362 username = tokens[1];
5363 } else {
5364 cmd_reply(CMD_DELEGATE, caller, C_SYNTAX,
5365 _("Please specify a user to whom control is to be delegated."));
5366 ret = FALSE;
5367 break;
5368 }
5369 if (ntokens > 2) {
5370 player_specified = TRUE;
5371 dplayer = player_by_name_prefix(tokens[2], &result);
5372 if (!dplayer) {
5373 cmd_reply_no_such_player(CMD_DELEGATE, caller, tokens[2], result);
5374 ret = FALSE;
5375 break;
5376 }
5377#ifndef HAVE_FCDB
5378 if (caller && conn_get_access(caller) < ALLOW_ADMIN) {
5379#else
5380 if (caller && conn_get_access(caller) < ALLOW_ADMIN
5381 && !(srvarg.fcdb_enabled
5382 && script_fcdb_call("user_delegate_to", caller, dplayer,
5383 username, &ret) && ret)) {
5384#endif
5385 cmd_reply(CMD_DELEGATE, caller, C_SYNTAX,
5386 _("Command level '%s' or greater or special permission "
5387 "needed to modify others' delegations."),
5388 cmdlevel_name(ALLOW_ADMIN));
5389 ret = FALSE;
5390 break;
5391 }
5392 } else {
5393 dplayer = conn_controls_player(caller) ? conn_get_player(caller) : NULL;
5394 if (!dplayer) {
5395 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5396 _("You do not control a player."));
5397 ret = FALSE;
5398 break;
5399 }
5400 }
5401
5402 /* Delegate control of player to another user. */
5403 fc_assert_ret_val(dplayer, FALSE);
5404 fc_assert_ret_val(username != NULL, FALSE);
5405
5406 /* Forbid delegation of players already controlled by a delegate, and
5407 * those 'put aside' by a delegate.
5408 * For the former, if player is already under active delegate control,
5409 * we wouldn't handle the revocation that would be necessary if their
5410 * delegation changed; and the authority granted to delegates does not
5411 * include the ability to sub-delegate.
5412 * For the latter, allowing control of the 'put aside' player to be
5413 * delegated would break the invariant that whenever a user is connected,
5414 * they are attached to 'their' player. */
5415 if (player_delegation_active(dplayer)) {
5416 if (!player_delegation_get(dplayer)) {
5417 /* Attempting to change a 'put aside' player. Must be admin
5418 * or console. */
5419 fc_assert(player_specified);
5420 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5421 _("Can't delegate control of '%s' belonging to %s while "
5422 "they are controlling another player."),
5423 player_name(dplayer), dplayer->username);
5424 } else if (player_specified) {
5425 /* Admin or console attempting to change a controlled player. */
5426 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5427 _("Can't change delegation of '%s' while controlled by "
5428 "delegate %s."), player_name(dplayer), dplayer->username);
5429 } else {
5430 /* Caller must be the delegate. Give more specific message.
5431 * (We don't know if they thought they were delegating their
5432 * original or delegated player, but we don't allow either.) */
5433 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5434 _("You can't delegate control while you are controlling "
5435 "a delegated player yourself."));
5436 }
5437 ret = FALSE;
5438 break;
5439 }
5440
5441 /* Forbid delegation to player's original owner
5442 * (from above test we know that dplayer->username is the original now) */
5443 if (fc_strcasecmp(dplayer->username, username) == 0) {
5444 if (player_specified) {
5445 /* Probably admin or console. */
5446 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5447 /* TRANS: don't translate 'delegate cancel' */
5448 _("%s already owns '%s', so cannot also be delegate. "
5449 "Use '%sdelegate cancel' to cancel an existing "
5450 "delegation."),
5451 username, player_name(dplayer), caller?"/":"");
5452 } else {
5453 /* Player not specified on command line, so they must have been trying
5454 * to delegate control to themself. Give more specific message. */
5455 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5456 /* TRANS: don't translate '/delegate cancel' */
5457 _("You can't delegate control to yourself. "
5458 "Use '/delegate cancel' to cancel an existing "
5459 "delegation."));
5460 }
5461 ret = FALSE;
5462 break;
5463 }
5464
5465 /* FIXME: if control was already delegated to someone else, that
5466 * delegation is implicitly canceled. Perhaps we should tell someone. */
5467
5468 player_delegation_set(dplayer, username);
5469 cmd_reply(CMD_DELEGATE, caller, C_OK,
5470 _("Control of player '%s' delegated to user %s."),
5471 player_name(dplayer), username);
5472 ret = TRUE;
5473 break;
5474
5475 case DELEGATE_SHOW:
5476 /* Show delegations. */
5477 fc_assert_ret_val(dplayer, FALSE);
5478
5479 if (player_delegation_get(dplayer) == NULL) {
5480 /* No delegation set. */
5481 cmd_reply(CMD_DELEGATE, caller, C_COMMENT,
5482 _("No delegation defined for '%s'."),
5483 player_name(dplayer));
5484 } else {
5485 cmd_reply(CMD_DELEGATE, caller, C_COMMENT,
5486 _("Control of player '%s' delegated to user %s."),
5487 player_name(dplayer), player_delegation_get(dplayer));
5488 }
5489 ret = TRUE;
5490 break;
5491
5492 case DELEGATE_CANCEL:
5493 if (player_delegation_get(dplayer) == NULL) {
5494 /* No delegation set. */
5495 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5496 _("No delegation defined for '%s'."),
5497 player_name(dplayer));
5498 ret = FALSE;
5499 break;
5500 }
5501
5502 if (player_delegation_active(dplayer)) {
5503 /* Delegation is currently in use. Forcibly break connection. */
5504 struct connection *pdelegate;
5505 /* (Can only happen if admin/console issues this command, as owner
5506 * will end use by their mere presence.) */
5507 fc_assert(player_specified);
5508 pdelegate = conn_by_user(player_delegation_get(dplayer));
5509 fc_assert_ret_val(pdelegate != NULL, FALSE);
5510 if (!connection_delegate_restore(pdelegate)) {
5511 /* Should never happen. Generic failure message. */
5512 log_error("Failed to restore %s's connection as %s during "
5513 "'delegate cancel'.", pdelegate->username,
5514 delegate_player_str(pdelegate->server.delegation.playing,
5515 pdelegate->server.delegation.observer));
5516 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("Unexpected failure."));
5517 ret = FALSE;
5518 break;
5519 }
5520 notify_conn(pdelegate->self, NULL, E_CONNECTION, ftc_server,
5521 _("Your delegated control of player '%s' was canceled."),
5522 player_name(dplayer));
5523 }
5524
5525 player_delegation_set(dplayer, NULL);
5526 cmd_reply(CMD_DELEGATE, caller, C_OK, _("Delegation of '%s' canceled."),
5527 player_name(dplayer));
5528 ret = TRUE;
5529 break;
5530
5531 case DELEGATE_TAKE:
5532 /* Try to take another player. */
5533 fc_assert_ret_val(dplayer, FALSE);
5534 fc_assert_ret_val(caller, FALSE);
5535
5536 if (caller->server.delegation.status) {
5537 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5538 /* TRANS: don't translate '/delegate restore'. */
5539 _("You are already controlling a delegated player. "
5540 "Use '/delegate restore' to relinquish control of your "
5541 "current player first."));
5542 ret = FALSE;
5543 break;
5544 }
5545
5546 /* Don't allow 'put aside' players to be delegated; the invariant is
5547 * that while the owning user is connected to the server, they are
5548 * in sole control of 'their' player. */
5549 if (conn_controls_player(caller)
5550 && player_delegation_get(conn_get_player(caller)) != NULL) {
5551 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5552 /* TRANS: don't translate '/delegate cancel'. */
5553 _("Can't take player while you have delegated control "
5554 "yourself. Use '/delegate cancel' to cancel your own "
5555 "delegation first."));
5556 ret = FALSE;
5557 break;
5558 }
5559
5560 /* Taking your own player makes no sense. */
5561 if (conn_controls_player(caller)
5562 && dplayer == conn_get_player(caller)) {
5563 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("You already control '%s'."),
5564 player_name(conn_get_player(caller)));
5565 ret = FALSE;
5566 break;
5567 }
5568
5569 if (!player_delegation_get(dplayer)
5570 || fc_strcasecmp(player_delegation_get(dplayer), caller->username) != 0) {
5571 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5572 _("Control of player '%s' has not been delegated to you."),
5573 player_name(dplayer));
5574 ret = FALSE;
5575 break;
5576 }
5577
5578 /* If the player is controlled by another user, fail. */
5579 if (dplayer->is_connected) {
5580 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5581 _("Another user already controls player '%s'."),
5582 player_name(dplayer));
5583 ret = FALSE;
5584 break;
5585 }
5586
5587 if (!connection_delegate_take(caller, dplayer)) {
5588 /* Should never happen. Generic failure message. */
5589 log_error("%s failed to take control of '%s' during 'delegate take'.",
5590 caller->username, player_name(dplayer));
5591 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("Unexpected failure."));
5592 ret = FALSE;
5593 break;
5594 }
5595
5596 cmd_reply(CMD_DELEGATE, caller, C_OK,
5597 _("%s is now controlling player '%s'."), caller->username,
5598 player_name(conn_get_player(caller)));
5599 ret = TRUE;
5600 break;
5601
5602 case DELEGATE_RESTORE:
5603 /* Delegate user relinquishes control of delegated player, returning to
5604 * previous view (e.g. observer) if any. */
5605 fc_assert_ret_val(caller, FALSE);
5606
5607 if (!caller->server.delegation.status) {
5608 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5609 _("You are not currently controlling a delegated player."));
5610 ret = FALSE;
5611 break;
5612 }
5613
5614 if (!connection_delegate_restore(caller)) {
5615 /* Should never happen. Generic failure message. */
5616 log_error("Failed to restore %s's connection as %s during "
5617 "'delegate restore'.", caller->username,
5618 delegate_player_str(caller->server.delegation.playing,
5619 caller->server.delegation.observer));
5620 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("Unexpected failure."));
5621 ret = FALSE;
5622 break;
5623 }
5624
5625 cmd_reply(CMD_DELEGATE, caller, C_OK,
5626 /* TRANS: "<user> is now connected to <player>" where <player>
5627 * can also be "global observer" or "nothing" */
5628 _("%s is now connected as %s."), caller->username,
5629 delegate_player_str(conn_get_player(caller), caller->observer));
5630 ret = TRUE;
5631 break;
5632 }
5633
5634 cleanup:
5635 free_tokens(tokens, ntokens);
5636 return ret;
5637}
5638
5639/**********************************************************************/
5642 static const char *delegate_player_str(struct player *pplayer, bool observer)
5643{
5644 static struct astring buf;
5645
5646 if (pplayer) {
5647 if (observer) {
5648 astr_set(&buf, _("%s (observer)"), player_name(pplayer));
5649 } else {
5650 astr_set(&buf, "%s", player_name(pplayer));
5651 }
5652 } else if (observer) {
5653 astr_set(&buf, "%s", _("global observer"));
5654 } else {
5655 /* TRANS: in place of player name or "global observer" */
5656 astr_set(&buf, "%s", _("nothing"));
5657 }
5658
5659 return astr_str(&buf);
5660}
5661
5662/* Define the possible arguments to the mapimg command */
5663/* map image layers */
5664#define SPECENUM_NAME mapimg_args
5665#define SPECENUM_VALUE0 MAPIMG_COLORTEST
5666#define SPECENUM_VALUE0NAME "colortest"
5667#define SPECENUM_VALUE1 MAPIMG_CREATE
5668#define SPECENUM_VALUE1NAME "create"
5669#define SPECENUM_VALUE2 MAPIMG_DEFINE
5670#define SPECENUM_VALUE2NAME "define"
5671#define SPECENUM_VALUE3 MAPIMG_DELETE
5672#define SPECENUM_VALUE3NAME "delete"
5673#define SPECENUM_VALUE4 MAPIMG_SHOW
5674#define SPECENUM_VALUE4NAME "show"
5675#define SPECENUM_COUNT MAPIMG_COUNT
5676#include "specenum_gen.h"
5677
5678/**********************************************************************/
5681 static const char *mapimg_accessor(int i)
5682{
5683 i = CLIP(0, i, mapimg_args_max());
5684 return mapimg_args_name((enum mapimg_args) i);
5685}
5686
5687/**********************************************************************/
5690 static bool mapimg_command(struct connection *caller, char *arg, bool check)
5691{
5692 enum m_pre_result result;
5693 int ind, ntokens, id;
5694 char *token[2];
5695 bool ret = TRUE;
5696
5697 ntokens = get_tokens(arg, token, 2, TOKEN_DELIMITERS);
5698
5699 if (ntokens > 0) {
5700 /* match the argument */
5701 result = match_prefix(mapimg_accessor, MAPIMG_COUNT, 0,
5702 fc_strncasecmp, NULL, token[0], &ind);
5703
5704 switch (result) {
5705 case M_PRE_EXACT:
5706 case M_PRE_ONLY:
5707 /* we have a match */
5708 break;
5709 case M_PRE_AMBIGUOUS:
5710 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5711 _("Ambiguous 'mapimg' command."));
5712 ret = FALSE;
5713 goto cleanup;
5714 break;
5715 case M_PRE_EMPTY:
5716 /* use 'show' as default */
5717 ind = MAPIMG_SHOW;
5718 break;
5719 case M_PRE_LONG:
5720 case M_PRE_FAIL:
5721 case M_PRE_LAST:
5722 {
5723 char buf[256] = "";
5724 enum mapimg_args valid_args;
5725
5726 for (valid_args = mapimg_args_begin();
5727 valid_args != mapimg_args_end();
5728 valid_args = mapimg_args_next(valid_args)) {
5729 cat_snprintf(buf, sizeof(buf), "'%s'",
5730 mapimg_args_name(valid_args));
5731 if (valid_args != mapimg_args_max()) {
5732 cat_snprintf(buf, sizeof(buf), ", ");
5733 }
5734 }
5735
5736 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5737 _("The valid arguments are: %s."), buf);
5738 ret = FALSE;
5739 goto cleanup;
5740 }
5741 break;
5742 }
5743 } else {
5744 /* use 'show' as default */
5745 ind = MAPIMG_SHOW;
5746 }
5747
5748 switch (ind) {
5749 case MAPIMG_DEFINE:
5750 if (ntokens == 1) {
5751 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5752 _("Missing argument for 'mapimg define'."));
5753 ret = FALSE;
5754 } else {
5755 /* 'mapimg define <mapstr>' */
5756 if (!mapimg_define(token[1], check)) {
5757 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5758 _("Can't use definition: %s."), mapimg_error());
5759 ret = FALSE;
5760 } else if (check) {
5761 /* Validated OK, bail out now */
5762 goto cleanup;
5763 } else if (game_was_started()
5764 && mapimg_isvalid(mapimg_count() - 1) == NULL) {
5765 /* game was started - error in map image definition check */
5766 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5767 _("Can't use definition: %s."), mapimg_error());
5768 ret = FALSE;
5769 } else {
5770 char str[MAX_LEN_MAPDEF];
5771
5772 id = mapimg_count() - 1;
5773
5774 mapimg_id2str(id, str, sizeof(str));
5775 cmd_reply(CMD_MAPIMG, caller, C_OK, _("Defined as map image "
5776 "definition %d: '%s'."),
5777 id, str);
5778 }
5779 }
5780 break;
5781
5782 case MAPIMG_DELETE:
5783 if (ntokens == 1) {
5784 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5785 _("Missing argument for 'mapimg delete'."));
5786 ret = FALSE;
5787 } else if (ntokens == 2 && strcmp(token[1], "all") == 0) {
5788 /* 'mapimg delete all' */
5789 if (check) {
5790 goto cleanup;
5791 }
5792
5793 while (mapimg_count() > 0) {
5794 mapimg_delete(0);
5795 }
5796 cmd_reply(CMD_MAPIMG, caller, C_OK, _("All map image definitions "
5797 "deleted."));
5798 } else if (ntokens == 2 && sscanf(token[1], "%d", &id) != 0) {
5799 /* 'mapimg delete <id>' */
5800 if (check) {
5801 goto cleanup;
5802 }
5803
5804 if (!mapimg_delete(id)) {
5805 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5806 _("Couldn't delete definition: %s."), mapimg_error());
5807 ret = FALSE;
5808 } else {
5809 cmd_reply(CMD_MAPIMG, caller, C_OK, _("Map image definition %d "
5810 "deleted."), id);
5811 }
5812 } else {
5813 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5814 _("Bad argument for 'mapimg delete': '%s'."), token[1]);
5815 ret = FALSE;
5816 }
5817 break;
5818
5819 case MAPIMG_SHOW:
5820 if (ntokens < 2 || (ntokens == 2 && strcmp(token[1], "all") == 0)) {
5821 /* 'mapimg show' or 'mapimg show all' */
5822 if (check) {
5823 goto cleanup;
5824 }
5825 show_mapimg(caller, CMD_MAPIMG);
5826 } else if (ntokens == 2 && sscanf(token[1], "%d", &id) != 0) {
5827 char str[2048];
5828 /* 'mapimg show <id>' */
5829 if (check) {
5830 goto cleanup;
5831 }
5832
5833 if (mapimg_show(id, str, sizeof(str), TRUE)) {
5834 cmd_reply(CMD_MAPIMG, caller, C_OK, "%s", str);
5835 } else {
5836 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5837 _("Couldn't show definition: %s."), mapimg_error());
5838 ret = FALSE;
5839 }
5840 } else {
5841 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5842 _("Bad argument for 'mapimg show': '%s'."), token[1]);
5843 ret = FALSE;
5844 }
5845 break;
5846
5847 case MAPIMG_COLORTEST:
5848 if (check) {
5849 goto cleanup;
5850 }
5851
5852 mapimg_colortest(game.server.save_name, NULL);
5853 cmd_reply(CMD_MAPIMG, caller, C_OK, _("Map color test images saved."));
5854 break;
5855
5856 case MAPIMG_CREATE:
5857 if (ntokens < 2) {
5858 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5859 _("Missing argument for 'mapimg create'."));
5860 ret = FALSE;
5861 goto cleanup;
5862 }
5863
5864 if (strcmp(token[1], "all") == 0) {
5865 int count;
5866
5867 /* 'mapimg create all' */
5868 if (check) {
5869 goto cleanup;
5870 }
5871
5872 count = mapimg_count();
5873 for (id = 0; id < count; id++) {
5874 struct mapdef *pmapdef = mapimg_isvalid(id);
5875
5876 if (pmapdef == NULL
5877 || !mapimg_create(pmapdef, TRUE, game.server.save_name,
5878 srvarg.saves_pathname)) {
5879 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5880 _("Error saving map image %d: %s."), id, mapimg_error());
5881 ret = FALSE;
5882 }
5883 }
5884 } else if (sscanf(token[1], "%d", &id) != 0) {
5885 struct mapdef *pmapdef;
5886
5887 /* 'mapimg create <id>' */
5888 if (check) {
5889 goto cleanup;
5890 }
5891
5892 pmapdef = mapimg_isvalid(id);
5893 if (pmapdef == NULL
5894 || !mapimg_create(pmapdef, TRUE, game.server.save_name,
5895 srvarg.saves_pathname)) {
5896 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5897 _("Error saving map image %d: %s."), id, mapimg_error());
5898 ret = FALSE;
5899 }
5900 } else {
5901 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5902 _("Bad argument for 'mapimg create': '%s'."), token[1]);
5903 ret = FALSE;
5904 }
5905 break;
5906 }
5907
5908 cleanup:
5909
5910 free_tokens(token, ntokens);
5911
5912 return ret;
5913}
5914
5915/**********************************************************************/
5918 static bool aicmd_command(struct connection *caller, char *arg, bool check)
5919{
5920 enum m_pre_result match_result;
5921 struct player *pplayer;
5922 char *tokens[1], *cmd = NULL;
5923 int ntokens;
5924 bool ret = FALSE;
5925
5926 ntokens = get_tokens(arg, tokens, 1, TOKEN_DELIMITERS);
5927
5928 if (ntokens < 1) {
5929 cmd_reply(CMD_AICMD, caller, C_FAIL,
5930 _("No player given for aicmd."));
5931 goto cleanup;
5932 }
5933
5934 pplayer = player_by_name_prefix(tokens[0], &match_result);
5935
5936 if (NULL == pplayer) {
5937 cmd_reply_no_such_player(CMD_AICMD, caller, tokens[0], match_result);
5938 goto cleanup;
5939 }
5940
5941 /* We have a player - extract the command. */
5942 cmd = arg + strlen(tokens[0]);
5943 cmd = skip_leading_spaces(cmd);
5944
5945 if (strlen(cmd) == 0) {
5946 cmd_reply(CMD_AICMD, caller, C_FAIL,
5947 _("No command for the AI console defined."));
5948 goto cleanup;
5949 }
5950
5951 if (check) {
5952 ret = TRUE;
5953 goto cleanup;
5954 }
5955
5956 /* This check is needed to return a message if the function is not defined
5957 * for the AI of the player. */
5958 if (pplayer && pplayer->ai) {
5959 if (pplayer->ai->funcs.player_console) {
5960 cmd_reply(CMD_AICMD, caller, C_OK,
5961 _("AI console for player %s. Command: '%s'."),
5962 player_name(pplayer), cmd);
5963 CALL_PLR_AI_FUNC(player_console, pplayer, pplayer, cmd);
5964 ret = TRUE;
5965 } else {
5966 cmd_reply(CMD_AICMD, caller, C_FAIL,
5967 _("No AI console defined for the AI '%s' of player %s."),
5968 ai_name(pplayer->ai), player_name(pplayer));
5969 }
5970 } else {
5971 cmd_reply(CMD_AICMD, caller, C_FAIL, _("No AI defined for player %s."),
5972 player_name(pplayer));
5973 }
5974
5975 cleanup:
5976 free_tokens(tokens, ntokens);
5977 return ret;
5978}
5979
5980/* Define the possible arguments to the fcdb command */
5981#define SPECENUM_NAME fcdb_args
5982#define SPECENUM_VALUE0 FCDB_RELOAD
5983#define SPECENUM_VALUE0NAME "reload"
5984#define SPECENUM_VALUE1 FCDB_LUA
5985#define SPECENUM_VALUE1NAME "lua"
5986#define SPECENUM_COUNT FCDB_COUNT
5987#include "specenum_gen.h"
5988
5989/**********************************************************************/
5992 static const char *fcdb_accessor(int i)
5993{
5994 i = CLIP(0, i, fcdb_args_max());
5995 return fcdb_args_name((enum fcdb_args) i);
5996}
5997
5998/**********************************************************************/
6001 static bool fcdb_command(struct connection *caller, char *arg, bool check)
6002{
6003 enum m_pre_result result;
6004 int ind, ntokens;
6005 char *token[1];
6006 bool ret = TRUE;
6007 bool usage = FALSE;
6008
6009#ifndef HAVE_FCDB
6010 cmd_reply(CMD_FCDB, caller, C_FAIL,
6011 _("Freeciv database script deactivated at compile time."));
6012 return FALSE;
6013#endif
6014
6015 if (!srvarg.fcdb_enabled) {
6016 /* Not supposed to be used. It isn't initialized. */
6017 cmd_reply(CMD_FCDB, caller, C_FAIL,
6018 _("Freeciv database script not activated at server start. "
6019 "See the Freeciv server's --auth command line option."));
6020 return FALSE;
6021 }
6022
6023 ntokens = get_tokens(arg, token, 1, TOKEN_DELIMITERS);
6024
6025 if (ntokens > 0) {
6026 /* match the argument */
6027 result = match_prefix(fcdb_accessor, FCDB_COUNT, 0,
6028 fc_strncasecmp, NULL, token[0], &ind);
6029
6030 switch (result) {
6031 case M_PRE_EXACT:
6032 case M_PRE_ONLY:
6033 /* we have a match */
6034 break;
6035 case M_PRE_AMBIGUOUS:
6036 cmd_reply(CMD_FCDB, caller, C_FAIL,
6037 _("Ambiguous fcdb command."));
6038 ret = FALSE;
6039 goto cleanup;
6040 break;
6041 case M_PRE_EMPTY:
6042 case M_PRE_LONG:
6043 case M_PRE_FAIL:
6044 case M_PRE_LAST:
6045 usage = TRUE;
6046 break;
6047 }
6048 } else {
6049 usage = TRUE;
6050 }
6051
6052 if (usage) {
6053 char buf[256] = "";
6054 enum fcdb_args valid_args;
6055
6056 for (valid_args = fcdb_args_begin();
6057 valid_args != fcdb_args_end();
6058 valid_args = fcdb_args_next(valid_args)) {
6059 cat_snprintf(buf, sizeof(buf), "'%s'",
6060 fcdb_args_name(valid_args));
6061 if (valid_args != fcdb_args_max()) {
6062 cat_snprintf(buf, sizeof(buf), ", ");
6063 }
6064 }
6065
6066 cmd_reply(CMD_FCDB, caller, C_FAIL,
6067 _("The valid arguments are: %s."), buf);
6068 ret = FALSE;
6069 goto cleanup;
6070 }
6071
6072 if (check) {
6073 ret = TRUE;
6074 goto cleanup;
6075 }
6076
6077 switch (ind) {
6078 case FCDB_RELOAD:
6079 /* Reload database lua script. */
6080 script_fcdb_free();
6081 script_fcdb_init(NULL);
6082 break;
6083
6084 case FCDB_LUA:
6085 /* Skip whitespaces. */
6086 arg = skip_leading_spaces(arg);
6087 /* Skip the base argument 'lua'. */
6088 arg += 3;
6089 /* Now execute the scriptlet. */
6090 ret = script_fcdb_do_string(caller, arg);
6091 break;
6092 }
6093
6094 cleanup:
6095
6096 free_tokens(token, ntokens);
6097
6098 return ret;
6099}
6100
6101/**********************************************************************/
6104 static void start_cmd_reply(struct connection *caller, bool notify, char *msg)
6105{
6106 cmd_reply(CMD_START_GAME, caller, C_FAIL, "%s", msg);
6107 if (notify) {
6108 notify_conn(NULL, NULL, E_SETTING, ftc_server, "%s", msg);
6109 }
6110}
6111
6112/**********************************************************************/
6115 bool start_command(struct connection *caller, bool check, bool notify)
6116{
6117 int human_players;
6118
6119 switch (server_state()) {
6120 case S_S_INITIAL:
6121 /* Sanity check scenario */
6122 if (game.info.is_new_game && !check) {
6123 if (0 < map_startpos_count()
6124 && game.server.max_players > map_startpos_count()) {
6125 /* If we load a pre-generated map (i.e., a scenario) it is possible
6126 * to increase the number of players beyond the number supported by
6127 * the scenario. The solution is a hack: cut the extra players
6128 * when the game starts. */
6129 log_verbose("Reduced maxplayers from %d to %d to fit "
6130 "to the number of start positions.",
6131 game.server.max_players, map_startpos_count());
6132 game.server.max_players = map_startpos_count();
6133 }
6134
6135 if (normal_player_count() > game.server.max_players) {
6136 int i;
6137 struct player *pplayer;
6138
6139 for (i = player_slot_count() - 1; i >= 0; i--) {
6140 pplayer = player_by_number(i);
6141 if (pplayer) {
6142 server_remove_player(pplayer);
6143 }
6144 if (normal_player_count() <= game.server.max_players) {
6145 break;
6146 }
6147 }
6148
6149 log_verbose("Had to cut down the number of players to the "
6150 "number of map start positions, there must be "
6151 "something wrong with the savegame or you "
6152 "adjusted the maxplayers value.");
6153 }
6154 }
6155
6156 human_players = 0;
6157 players_iterate(plr) {
6158 if (is_human(plr)) {
6159 human_players++;
6160 }
6161 } players_iterate_end;
6162
6163 /* check min_players.
6164 * Allow continuing of savegames where some of the original
6165 * players have died */
6166 if (game.info.is_new_game
6167 && human_players < game.server.min_players) {
6168 char buf[512] = "";
6169
6170 fc_snprintf(buf, sizeof(buf),
6171 _("Not enough human players ('minplayers' server setting has value %d); game will not start."),
6172 game.server.min_players);
6173 start_cmd_reply(caller, notify, buf);
6174 return FALSE;
6175 } else if (player_count() < 1) {
6176 /* At least one player required */
6177 start_cmd_reply(caller, notify,
6178 _("No players; game will not start."));
6179 return FALSE;
6180 } else if (normal_player_count() > server.playable_nations) {
6181 if (nation_set_count() > 1) {
6182 start_cmd_reply(caller, notify,
6183 _("Not enough nations in the current nation set "
6184 "for all players; game will not start. "
6185 "(See 'nationset' setting.)"));
6186 } else {
6187 start_cmd_reply(caller, notify,
6188 _("Not enough nations for all players; game will "
6189 "not start."));
6190 }
6191 return FALSE;
6192 } else if (strlen(game.server.start_units) == 0 && !game.server.start_city) {
6193 start_cmd_reply(caller, notify,
6194 _("Neither 'startcity' nor 'startunits' setting gives "
6195 "players anything to start game with; game will "
6196 "not start."));
6197 return FALSE;
6198 } else if (check) {
6199 return TRUE;
6200 } else if (!caller) {
6201 if (notify) {
6202 /* Called from handle_player_ready()
6203 * Last player just toggled ready-status. */
6204 notify_conn(NULL, NULL, E_SETTING, ftc_game_start,
6205 _("All players are ready; starting game."));
6206 }
6207 start_game();
6208 return TRUE;
6209 } else if (NULL == caller->playing || caller->observer) {
6210 /* A detached or observer player can't do /start. */
6211 return TRUE;
6212 } else {
6213 /* This might trigger recursive call to start_command() if this is
6214 * last player who gets ready. In that case caller is NULL. */
6215 handle_player_ready(caller->playing, player_number(caller->playing), TRUE);
6216 return TRUE;
6217 }
6218 case S_S_OVER:
6219 start_cmd_reply(caller, notify,
6220 /* TRANS: given when /start is invoked during gameover. */
6221 _("Cannot start the game: the game is waiting for all clients "
6222 "to disconnect."));
6223 return FALSE;
6224 case S_S_RUNNING:
6225 start_cmd_reply(caller, notify,
6226 /* TRANS: given when /start is invoked while the game
6227 * is running. */
6228 _("Cannot start the game: it is already running."));
6229 return FALSE;
6230 }
6231 log_error("Unknown server state variant: %d.", server_state());
6232 return FALSE;
6233}
6234
6235/**********************************************************************/
6238 static bool cut_client_connection(struct connection *caller, char *name,
6239 bool check)
6240{
6241 enum m_pre_result match_result;
6242 struct connection *ptarget;
6243
6244 ptarget = conn_by_user_prefix(name, &match_result);
6245
6246 if (!ptarget) {
6247 cmd_reply_no_such_conn(CMD_CUT, caller, name, match_result);
6248 return FALSE;
6249 } else if (check) {
6250 return TRUE;
6251 }
6252
6253 if (conn_controls_player(ptarget)) {
6254 /* If we cut the connection, unassign the login name.*/
6255 sz_strlcpy(ptarget->playing->username, _(ANON_USER_NAME));
6256 ptarget->playing->unassigned_user = TRUE;
6257 }
6258
6259 cmd_reply(CMD_CUT, caller, C_DISCONNECTED,
6260 _("Cutting connection %s."), ptarget->username);
6261 connection_close_server(ptarget, _("connection cut"));
6262
6263 return TRUE;
6264}
6265
6266
6267/**********************************************************************/
6270 static time_t *time_duplicate(const time_t *t)
6271{
6272 time_t *d = fc_malloc(sizeof(*d));
6273 *d = *t;
6274 return d;
6275}
6276
6277/**********************************************************************/
6281 bool conn_is_kicked(struct connection *pconn, int *time_remaining)
6282{
6283 time_t time_of_addr_kick, time_of_user_kick;
6284 time_t now, time_of_kick = 0;
6285
6286 if (NULL != time_remaining) {
6287 *time_remaining = 0;
6288 }
6289
6290 fc_assert_ret_val(NULL != kick_table_by_addr, FALSE);
6291 fc_assert_ret_val(NULL != kick_table_by_user, FALSE);
6292 fc_assert_ret_val(NULL != pconn, FALSE);
6293
6294 if (kick_hash_lookup(kick_table_by_addr, pconn->server.ipaddr,
6295 &time_of_addr_kick)) {
6296 time_of_kick = time_of_addr_kick;
6297 }
6298 if (kick_hash_lookup(kick_table_by_user, pconn->username,
6299 &time_of_user_kick)
6300 && time_of_user_kick > time_of_kick) {
6301 time_of_kick = time_of_user_kick;
6302 }
6303
6304 if (0 == time_of_kick) {
6305 return FALSE; /* Not found. */
6306 }
6307
6308 now = time(NULL);
6309 if (now - time_of_kick > game.server.kick_time) {
6310 /* Kick timeout expired. */
6311 if (0 != time_of_addr_kick) {
6312 kick_hash_remove(kick_table_by_addr, pconn->server.ipaddr);
6313 }
6314 if (0 != time_of_user_kick) {
6315 kick_hash_remove(kick_table_by_user, pconn->username);
6316 }
6317 return FALSE;
6318 }
6319
6320 if (NULL != time_remaining) {
6321 *time_remaining = game.server.kick_time - (now - time_of_kick);
6322 }
6323 return TRUE;
6324}
6325
6326/**********************************************************************/
6329 static bool kick_command(struct connection *caller, char *name, bool check)
6330{
6331 char ipaddr[FC_MEMBER_SIZEOF(struct connection, server.ipaddr)];
6332 struct connection *pconn;
6333 enum m_pre_result match_result;
6334 time_t now;
6335
6336 remove_leading_trailing_spaces(name);
6337 pconn = conn_by_user_prefix(name, &match_result);
6338 if (NULL == pconn) {
6339 cmd_reply_no_such_conn(CMD_KICK, caller, name, match_result);
6340 return FALSE;
6341 }
6342
6343 if (NULL != caller && ALLOW_ADMIN > conn_get_access(caller)) {
6344 const int MIN_UNIQUE_CONNS = 3;
6345 const char *unique_ipaddr[MIN_UNIQUE_CONNS];
6346 int i, num_unique_connections = 0;
6347
6348 if (pconn == caller) {
6349 cmd_reply(CMD_KICK, caller, C_FAIL, _("You may not kick yourself."));
6350 return FALSE;
6351 }
6352
6353 conn_list_iterate(game.est_connections, aconn) {
6354 for (i = 0; i < num_unique_connections; i++) {
6355 if (0 == strcmp(unique_ipaddr[i], aconn->server.ipaddr)) {
6356 /* Already listed. */
6357 break;
6358 }
6359 }
6360 if (i >= num_unique_connections) {
6361 num_unique_connections++;
6362 if (MIN_UNIQUE_CONNS <= num_unique_connections) {
6363 /* We have enought already. */
6364 break;
6365 }
6366 unique_ipaddr[num_unique_connections - 1] = aconn->server.ipaddr;
6367 }
6368 } conn_list_iterate_end;
6369
6370 if (MIN_UNIQUE_CONNS > num_unique_connections) {
6371 cmd_reply(CMD_KICK, caller, C_FAIL,
6372 _("There must be at least %d unique connections to the "
6373 "server for this command to be valid."), MIN_UNIQUE_CONNS);
6374 return FALSE;
6375 }
6376 }
6377
6378 if (check) {
6379 return TRUE;
6380 }
6381
6382 sz_strlcpy(ipaddr, pconn->server.ipaddr);
6383 now = time(NULL);
6384 kick_hash_replace(kick_table_by_addr, ipaddr, now);
6385
6386 conn_list_iterate(game.all_connections, aconn) {
6387 if (0 != strcmp(ipaddr, aconn->server.ipaddr)) {
6388 continue;
6389 }
6390
6391 if (conn_controls_player(aconn)) {
6392 /* Unassign the username. */
6393 sz_strlcpy(aconn->playing->username, _(ANON_USER_NAME));
6394 aconn->playing->unassigned_user = TRUE;
6395 }
6396
6397 kick_hash_replace(kick_table_by_user, aconn->username, now);
6398
6399 connection_close_server(aconn, _("kicked"));
6400 } conn_list_iterate_end;
6401
6402 return TRUE;
6403}
6404
6405
6406/**********************************************************************/
6410 static void show_help_intro(struct connection *caller,
6411 enum command_id help_cmd)
6412{
6413 /* This is formatted like extra_help entries for settings and commands: */
6414 char *help = fc_strdup(
6415 _("Welcome - this is the introductory help text for the Freeciv "
6416 "server.\n"
6417 "\n"
6418 "Two important server concepts are Commands and Options. Commands, "
6419 "such as 'help', are used to interact with the server. Some commands "
6420 "take one or more arguments, separated by spaces. In many cases "
6421 "commands and command arguments may be abbreviated. Options are "
6422 "settings which control the server as it is running.\n"
6423 "\n"
6424 "To find out how to get more information about commands and options, "
6425 "use 'help help'.\n"
6426 "\n"
6427 "For the impatient, the main commands to get going are:\n"
6428 " show - to see current options\n"
6429 " set - to set options\n"
6430 " start - to start the game once players have connected\n"
6431 " save - to save the current game\n"
6432 " quit - to exit"));
6433
6434 fc_break_lines(help, LINE_BREAK);
6435 cmd_reply(help_cmd, caller, C_COMMENT, "%s", help);
6436 FC_FREE(help);
6437}
6438
6439/**********************************************************************/
6443 static void show_help_command(struct connection *caller,
6444 enum command_id help_cmd,
6445 enum command_id id)
6446{
6447 const struct command *cmd = command_by_number(id);
6448
6449 if (command_short_help(cmd)) {
6450 cmd_reply(help_cmd, caller, C_COMMENT,
6451 /* TRANS: <untranslated name> - translated short help */
6452 _("Command: %s - %s"),
6453 command_name(cmd),
6454 command_short_help(cmd));
6455 } else {
6456 cmd_reply(help_cmd, caller, C_COMMENT,
6457 /* TRANS: <untranslated name> */
6458 _("Command: %s"),
6459 command_name(cmd));
6460 }
6461 if (command_synopsis(cmd)) {
6462 /* line up the synopsis lines: */
6463 const char *syn = _("Synopsis: ");
6464 size_t synlen = strlen(syn);
6465 char prefix[40];
6466
6467 fc_snprintf(prefix, sizeof(prefix), "%*s", (int) synlen, " ");
6468 cmd_reply_prefix(help_cmd, caller, C_COMMENT, prefix,
6469 "%s%s", syn, command_synopsis(cmd));
6470 }
6471 cmd_reply(help_cmd, caller, C_COMMENT,
6472 _("Level: %s"), cmdlevel_name(command_level(cmd)));
6473 {
6474 char *help = command_extra_help(cmd);
6475
6476 if (help) {
6477 fc_break_lines(help, LINE_BREAK);
6478 cmd_reply(help_cmd, caller, C_COMMENT, _("Description:"));
6479 cmd_reply_prefix(help_cmd, caller, C_COMMENT, " ", " %s", help);
6480 FC_FREE(help);
6481 }
6482 }
6483}
6484
6485/**********************************************************************/
6489 static void show_help_command_list(struct connection *caller,
6490 enum command_id help_cmd)
6491{
6492 enum command_id i;
6493
6494 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
6495 cmd_reply(help_cmd, caller, C_COMMENT,
6496 _("The following server commands are available:"));
6497 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
6498 if (!caller && con_get_style()) {
6499 for (i = 0; i < CMD_NUM; i++) {
6500 cmd_reply(help_cmd, caller, C_COMMENT, "%s", command_name_by_number(i));
6501 }
6502 } else {
6503 char buf[MAX_LEN_CONSOLE_LINE];
6504 int j;
6505
6506 buf[0] = '\0';
6507 for (i = 0, j = 0; i < CMD_NUM; i++) {
6508 if (may_use(caller, i)) {
6509 cat_snprintf(buf, sizeof(buf), "%-19s", command_name_by_number(i));
6510 if ((++j % 4) == 0) {
6511 cmd_reply(help_cmd, caller, C_COMMENT, "%s", buf);
6512 buf[0] = '\0';
6513 }
6514 }
6515 }
6516 if (buf[0] != '\0') {
6517 cmd_reply(help_cmd, caller, C_COMMENT, "%s", buf);
6518 }
6519 }
6520 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
6521}
6522
6523/**********************************************************************/
6527 static void cmd_reply_matches(enum command_id cmd,
6528 struct connection *caller,
6529 m_pre_accessor_fn_t accessor_fn,
6530 int *matches, int num_matches)
6531{
6532 char buf[MAX_LEN_MSG];
6533 const char *src, *end;
6534 char *dest;
6535 int i;
6536
6537 if (accessor_fn == NULL || matches == NULL || num_matches < 1) {
6538 return;
6539 }
6540
6541 dest = buf;
6542 end = buf + sizeof(buf) - 1;
6543
6544 for (i = 0; i < num_matches && dest < end; i++) {
6545 src = accessor_fn(matches[i]);
6546 if (!src) {
6547 continue;
6548 }
6549 if (dest != buf) {
6550 *dest++ = ' ';
6551 }
6552 while (*src != '\0' && dest < end) {
6553 *dest++ = *src++;
6554 }
6555 }
6556 *dest = '\0';
6557
6558 cmd_reply(cmd, caller, C_COMMENT, _("Possible matches: %s"), buf);
6559}
6560
6561/**************************************************************************
6562 Additional 'help' arguments
6563**************************************************************************/
6564#define SPECENUM_NAME help_general_args
6565#define SPECENUM_VALUE0 HELP_GENERAL_COMMANDS
6566#define SPECENUM_VALUE0NAME "commands"
6567#define SPECENUM_VALUE1 HELP_GENERAL_OPTIONS
6568#define SPECENUM_VALUE1NAME "options"
6569#define SPECENUM_COUNT HELP_GENERAL_COUNT
6570#include "specenum_gen.h"
6571
6572/**************************************************************************
6573 Unified indices for help arguments:
6574 CMD_NUM - Server commands
6575 HELP_GENERAL_NUM - General help arguments, above
6576 settings_number() - Server options
6577**************************************************************************/
6578#define HELP_ARG_NUM (CMD_NUM + HELP_GENERAL_COUNT + settings_number())
6579
6580/**********************************************************************/
6583 static const char *helparg_accessor(int i)
6584{
6585 if (i < CMD_NUM) {
6586 return command_name_by_number(i);
6587 }
6588
6589 i -= CMD_NUM;
6590 if (i < HELP_GENERAL_COUNT) {
6591 return help_general_args_name((enum help_general_args) i);
6592 }
6593
6594 i -= HELP_GENERAL_COUNT;
6595 return optname_accessor(i);
6596}
6597
6598/**********************************************************************/
6601 static bool show_help(struct connection *caller, char *arg)
6602{
6603 int matches[64], num_matches = 0;
6604 enum m_pre_result match_result;
6605 int ind;
6606
6607 fc_assert_ret_val(!may_use_nothing(caller), FALSE);
6608 /* no commands means no help, either */
6609
6610 match_result = match_prefix_full(helparg_accessor, HELP_ARG_NUM, 0,
6611 fc_strncasecmp, NULL, arg, &ind, matches,
6612 ARRAY_SIZE(matches), &num_matches);
6613
6614 if (match_result == M_PRE_EMPTY) {
6615 show_help_intro(caller, CMD_HELP);
6616 return FALSE;
6617 }
6618 if (match_result == M_PRE_AMBIGUOUS) {
6619 cmd_reply(CMD_HELP, caller, C_FAIL,
6620 _("Help argument '%s' is ambiguous."), arg);
6621 cmd_reply_matches(CMD_HELP, caller, helparg_accessor,
6622 matches, num_matches);
6623 return FALSE;
6624 }
6625 if (match_result == M_PRE_FAIL) {
6626 cmd_reply(CMD_HELP, caller, C_FAIL,
6627 _("No match for help argument '%s'."), arg);
6628 return FALSE;
6629 }
6630
6631 /* other cases should be above */
6632 fc_assert_ret_val(match_result < M_PRE_AMBIGUOUS, FALSE);
6633
6634 if (ind < CMD_NUM) {
6635 show_help_command(caller, CMD_HELP, ind);
6636 return TRUE;
6637 }
6638 ind -= CMD_NUM;
6639
6640 if (ind == HELP_GENERAL_OPTIONS) {
6641 show_help_option_list(caller, CMD_HELP);
6642 return TRUE;
6643 }
6644 if (ind == HELP_GENERAL_COMMANDS) {
6645 show_help_command_list(caller, CMD_HELP);
6646 return TRUE;
6647 }
6648 ind -= HELP_GENERAL_COUNT;
6649
6650 if (ind < settings_number()) {
6651 show_help_option(caller, CMD_HELP, ind);
6652 return TRUE;
6653 }
6654
6655 /* should have finished by now */
6656 log_error("Bug in show_help!");
6657 return FALSE;
6658}
6659
6660/**********************************************************************/
6663 static void show_connections(struct connection *caller)
6664{
6665 char buf[MAX_LEN_CONSOLE_LINE];
6666
6667 cmd_reply(CMD_LIST, caller, C_COMMENT,
6668 _("List of connections to server:"));
6669 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6670
6671 if (conn_list_size(game.all_connections) == 0) {
6672 cmd_reply(CMD_LIST, caller, C_COMMENT, _("<no connections>"));
6673 } else {
6674 conn_list_iterate(game.all_connections, pconn) {
6675 sz_strlcpy(buf, conn_description(pconn));
6676 if (pconn->established) {
6677 cat_snprintf(buf, sizeof(buf), " command access level %s",
6678 cmdlevel_name(pconn->access_level));
6679 }
6680 cmd_reply(CMD_LIST, caller, C_COMMENT, "%s", buf);
6681 } conn_list_iterate_end;
6682 }
6683 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6684}
6685
6686/**********************************************************************/
6689 static void show_delegations(struct connection *caller)
6690{
6691 bool empty = TRUE;
6692
6693 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of all delegations:"));
6694 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6695
6696 players_iterate(pplayer) {
6697 const char *delegate_to = player_delegation_get(pplayer);
6698 if (delegate_to != NULL) {
6699 const char *owner =
6700 player_delegation_active(pplayer) ? pplayer->server.orig_username
6701 : pplayer->username;
6702 fc_assert(owner);
6703 cmd_reply(CMD_LIST, caller, C_COMMENT,
6704 /* TRANS: last %s is either " (active)" or empty string */
6705 _("%s delegates control over player '%s' to user %s%s."),
6706 owner, player_name(pplayer), delegate_to,
6707 /* TRANS: preserve leading space */
6708 player_delegation_active(pplayer) ? _(" (active)") : "");
6709 empty = FALSE;
6710 }
6711 } players_iterate_end;
6712
6713 if (empty) {
6714 cmd_reply(CMD_LIST, caller, C_COMMENT, _("No delegations defined."));
6715 }
6716
6717 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6718}
6719
6720/**********************************************************************/
6723 static bool show_ignore(struct connection *caller)
6724{
6725 char buf[128];
6726 int n = 1;
6727
6728 if (NULL == caller) {
6729 cmd_reply(CMD_IGNORE, caller, C_FAIL,
6730 _("That would be rather silly, since you are not a player."));
6731 return FALSE;
6732 }
6733
6734 if (0 == conn_pattern_list_size(caller->server.ignore_list)) {
6735 cmd_reply(CMD_LIST, caller, C_COMMENT, _("Your ignore list is empty."));
6736 return TRUE;
6737 }
6738
6739 cmd_reply(CMD_LIST, caller, C_COMMENT, _("Your ignore list:"));
6740 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6741 conn_pattern_list_iterate(caller->server.ignore_list, ppattern) {
6742 conn_pattern_to_string(ppattern, buf, sizeof(buf));
6743 cmd_reply(CMD_LIST, caller, C_COMMENT, "%d: %s", n++, buf);
6744 } conn_pattern_list_iterate_end;
6745 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6746
6747 return TRUE;
6748}
6749
6750/**********************************************************************/
6753 void show_players(struct connection *caller)
6754{
6755 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of players:"));
6756 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6757
6758 if (player_count() == 0) {
6759 cmd_reply(CMD_LIST, caller, C_COMMENT, _("<no players>"));
6760 } else {
6761 players_iterate(pplayer) {
6762 char buf[MAX_LEN_CONSOLE_LINE];
6763 int n;
6764
6765 /* Low access level callers don't get to see barbarians in list: */
6766 if (is_barbarian(pplayer) && caller
6767 && (caller->access_level < ALLOW_CTRL)) {
6768 continue;
6769 }
6770
6771 /* The output for each player looks like:
6772 *
6773 * <Player name> [color]: Team[, Nation][, Username][, Status]
6774 * AI/Barbarian/Human[, AI type, skill level][, Connections]
6775 * [Details for each connection]
6776 */
6777
6778 /* '<Player name> [color]: [Nation][, Username][, Status]' */
6779 buf[0] = '\0';
6780 cat_snprintf(buf, sizeof(buf), "%s [%s]: %s", player_name(pplayer),
6781 player_color_ftstr(pplayer),
6782 team_name_translation(pplayer->team));
6783 if (!game.info.is_new_game) {
6784 cat_snprintf(buf, sizeof(buf), ", %s",
6785 nation_adjective_for_player(pplayer));
6786 }
6787 if (strlen(pplayer->username) > 0
6788 && strcmp(pplayer->username, "nouser") != 0) {
6789 cat_snprintf(buf, sizeof(buf), _(", user %s"), pplayer->username);
6790 }
6791 if (S_S_INITIAL == server_state() && pplayer->is_connected) {
6792 if (pplayer->is_ready) {
6793 sz_strlcat(buf, _(", ready"));
6794 } else {
6795 /* Emphasizes this */
6796 n = strlen(buf);
6797 featured_text_apply_tag(_(", not ready"),
6798 buf + n, sizeof(buf) - n,
6799 TTT_COLOR, 1, FT_OFFSET_UNSET,
6800 ftc_changed);
6801 }
6802 } else if (!pplayer->is_alive) {
6803 sz_strlcat(buf, _(", Dead"));
6804 }
6805 cmd_reply(CMD_LIST, caller, C_COMMENT, "%s", buf);
6806
6807 /* ' AI/Barbarian/Human[, skill level][, Connections]' */
6808 buf[0] = '\0';
6809 if (is_barbarian(pplayer)) {
6810 sz_strlcat(buf, _("Barbarian"));
6811 } else if (is_ai(pplayer)) {
6812 sz_strlcat(buf, _("AI"));
6813 } else {
6814 sz_strlcat(buf, _("Human"));
6815 }
6816 if (is_ai(pplayer)) {
6817 cat_snprintf(buf, sizeof(buf), _(", %s"), ai_name(pplayer->ai));
6818 cat_snprintf(buf, sizeof(buf), _(", difficulty level %s"),
6819 ai_level_translated_name(pplayer->ai_common.skill_level));
6820 }
6821 n = conn_list_size(pplayer->connections);
6822 if (n > 0) {
6823 cat_snprintf(buf, sizeof(buf),
6824 PL_(", %d connection:", ", %d connections:", n), n);
6825 }
6826 cmd_reply(CMD_LIST, caller, C_COMMENT, " %s", buf);
6827
6828 /* ' [Details for each connection]' */
6829 conn_list_iterate(pplayer->connections, pconn) {
6830 fc_snprintf(buf, sizeof(buf),
6831 _("%s from %s (command access level %s), "
6832 "bufsize=%dkb"), pconn->username, pconn->addr,
6833 cmdlevel_name(pconn->access_level),
6834 (pconn->send_buffer->nsize >> 10));
6835 if (pconn->observer) {
6836 /* TRANS: preserve leading space */
6837 sz_strlcat(buf, _(" (observer mode)"));
6838 }
6839 cmd_reply(CMD_LIST, caller, C_COMMENT, " %s", buf);
6840 } conn_list_iterate_end;
6841 } players_iterate_end;
6842 }
6843 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6844}
6845
6846 struct mrc_listcmd_data {
6847 struct connection *caller;
6848};
6849
6850/************************************************************************/
6853 static void ruleset_cache_listcmd_cb(const char *mp_name,
6854 const char *filename, void *data_in)
6855{
6856 struct mrc_listcmd_data *data = (struct mrc_listcmd_data *)data_in;
6857 struct section_file *sf;
6858 const char *name;
6859 const char *serv;
6860 const char *rsdir;
6861
6862 name = modpack_file_from_ruleset_cache(mp_name);
6863
6864 if (name == NULL) {
6865 log_error("Modpack \"%s\" not in ruleset cache", mp_name);
6866 return;
6867 }
6868
6869 sf = secfile_load(name, FALSE);
6870
6871 if (sf == NULL) {
6872 log_error("Failed to load modpack file \"%s\"", name);
6873 return;
6874 }
6875
6876 serv = modpack_serv_file(sf);
6877 rsdir = modpack_rulesetdir(sf);
6878
6879 if (serv != NULL || rsdir != NULL) {
6880 /* Modpack has ruleset component */
6881 cmd_reply(CMD_LIST, data->caller, C_COMMENT, "%s : %s : %s", mp_name,
6882 rsdir != NULL ? rsdir : "-",
6883 serv != NULL ? serv : "-");
6884 }
6885
6886 secfile_destroy(sf);
6887}
6888
6889/**********************************************************************/
6892 static void show_rulesets(struct connection *caller)
6893{
6894 struct mrc_listcmd_data data;
6895
6896 cmd_reply(CMD_LIST, caller, C_COMMENT,
6897 /* TRANS: don't translate text between '' */
6898 _("List of available rulesets, and how to load them:"));
6899 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6900 cmd_reply(CMD_LIST, caller, C_COMMENT,
6901 _("Ruleset : /rulesetdir <dir> : /read <script>"));
6902 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6903
6904 cache_rulesets();
6905
6906 data.caller = caller;
6907 modpack_ruleset_cache_iterate(ruleset_cache_listcmd_cb, &data);
6908
6909 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6910}
6911
6912/**********************************************************************/
6915 static void show_scenarios(struct connection *caller)
6916{
6917 char buf[MAX_LEN_CONSOLE_LINE];
6918 struct fileinfo_list *files;
6919
6920 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of scenarios available:"));
6921 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6922
6923 files = fileinfolist_infix(get_scenario_dirs(), ".sav", TRUE);
6924
6925 fileinfo_list_iterate(files, pfile) {
6926 struct section_file *sf = secfile_load_section(pfile->fullname, "scenario", TRUE);
6927
6928 if (secfile_lookup_bool_default(sf, TRUE, "scenario.is_scenario")) {
6929 fc_snprintf(buf, sizeof(buf), "%s", pfile->name);
6930 cmd_reply(CMD_LIST, caller, C_COMMENT, "%s", buf);
6931 }
6932 } fileinfo_list_iterate_end;
6933 fileinfo_list_destroy(files);
6934
6935 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6936}
6937
6938/**********************************************************************/
6941 static void show_nationsets(struct connection *caller)
6942{
6943 cmd_reply(CMD_LIST, caller, C_COMMENT,
6944 /* TRANS: don't translate text between '' */
6945 _("List of nation sets available for 'nationset' option:"));
6946 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6947
6948 nation_sets_iterate(pset) {
6949 const char *description = nation_set_description(pset);
6950 int num_nations = 0;
6951 nations_iterate(pnation) {
6952 if (is_nation_playable(pnation) && nation_is_in_set(pnation, pset)) {
6953 num_nations++;
6954 }
6955 } nations_iterate_end;
6956 cmd_reply(CMD_LIST, caller, C_COMMENT,
6957 /* TRANS: nation set description; %d refers to number of playable
6958 * nations in set */
6959 PL_(" %-10s %s (%d playable)",
6960 " %-10s %s (%d playable)", num_nations),
6961 nation_set_rule_name(pset), nation_set_name_translation(pset),
6962 num_nations);
6963 if (strlen(description) > 0) {
6964 static const char prefix[] = " ";
6965 char *translated = fc_strdup(_(description));
6966 fc_break_lines(translated, LINE_BREAK);
6967 cmd_reply_prefix(CMD_LIST, caller, C_COMMENT, prefix, "%s%s",
6968 prefix, translated);
6969 }
6970 } nation_sets_iterate_end;
6971
6972 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6973}
6974
6975/**********************************************************************/
6978 static void show_teams(struct connection *caller)
6979{
6980 /* Currently this just lists all teams (typically 32 of them) with their
6981 * names and # of players on the team. This could probably be improved. */
6982 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of teams:"));
6983 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
6984
6985 teams_iterate(pteam) {
6986 const struct player_list *members = team_members(pteam);
6987
6988 /* PL_() is needed here because some languages may differentiate
6989 * between 2 and 3 (although English does not). */
6990 cmd_reply(CMD_LIST, caller, C_COMMENT,
6991 /* TRANS: There will always be at least 2 players here. */
6992 PL_("%2d : '%s' : %d player :",
6993 "%2d : '%s' : %d players :",
6994 player_list_size(members)),
6995 team_index(pteam), team_name_translation(pteam),
6996 player_list_size(members));
6997 player_list_iterate(members, pplayer) {
6998 cmd_reply(CMD_LIST, caller, C_COMMENT, " %s", player_name(pplayer));
6999 } player_list_iterate_end;
7000 } teams_iterate_end;
7001
7002 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
7003}
7004
7005/**********************************************************************/
7008 static void show_mapimg(struct connection *caller, enum command_id cmd)
7009{
7010 int id;
7011
7012 if (mapimg_count() == 0) {
7013 cmd_reply(cmd, caller, C_OK, _("No map image definitions."));
7014 } else {
7015 cmd_reply(cmd, caller, C_COMMENT, _("List of map image definitions:"));
7016 cmd_reply(cmd, caller, C_COMMENT, horiz_line);
7017 for (id = 0; id < mapimg_count(); id++) {
7018 char str[MAX_LEN_MAPDEF] = "";
7019 mapimg_show(id, str, sizeof(str), FALSE);
7020 cmd_reply(cmd, caller, C_COMMENT, _("[%2d] %s"), id, str);
7021 }
7022 cmd_reply(cmd, caller, C_COMMENT, horiz_line);
7023 }
7024}
7025
7026/**********************************************************************/
7029 static void show_colors(struct connection *caller)
7030{
7031 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of player colors:"));
7032 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
7033 if (player_count() == 0) {
7034 cmd_reply(CMD_LIST, caller, C_COMMENT, _("<no players>"));
7035 } else {
7036 players_iterate(pplayer) {
7037 cmd_reply(CMD_LIST, caller, C_COMMENT, _("%s (user %s): [%s]"),
7038 player_name(pplayer), pplayer->username,
7039 player_color_ftstr(pplayer));
7040 } players_iterate_end;
7041 }
7042 cmd_reply(CMD_LIST, caller, C_COMMENT, horiz_line);
7043}
7044
7045/**************************************************************************
7046 '/list' arguments
7047**************************************************************************/
7048#define SPECENUM_NAME list_args
7049#define SPECENUM_VALUE0 LIST_COLORS
7050#define SPECENUM_VALUE0NAME "colors"
7051#define SPECENUM_VALUE1 LIST_CONNECTIONS
7052#define SPECENUM_VALUE1NAME "connections"
7053#define SPECENUM_VALUE2 LIST_DELEGATIONS
7054#define SPECENUM_VALUE2NAME "delegations"
7055#define SPECENUM_VALUE3 LIST_IGNORE
7056#define SPECENUM_VALUE3NAME "ignored users"
7057#define SPECENUM_VALUE4 LIST_MAPIMG
7058#define SPECENUM_VALUE4NAME "map image definitions"
7059#define SPECENUM_VALUE5 LIST_PLAYERS
7060#define SPECENUM_VALUE5NAME "players"
7061#define SPECENUM_VALUE6 LIST_RULESETS
7062#define SPECENUM_VALUE6NAME "rulesets"
7063#define SPECENUM_VALUE7 LIST_SCENARIOS
7064#define SPECENUM_VALUE7NAME "scenarios"
7065#define SPECENUM_VALUE8 LIST_NATIONSETS
7066#define SPECENUM_VALUE8NAME "nationsets"
7067#define SPECENUM_VALUE9 LIST_TEAMS
7068#define SPECENUM_VALUE9NAME "teams"
7069#define SPECENUM_VALUE10 LIST_VOTES
7070#define SPECENUM_VALUE10NAME "votes"
7071#include "specenum_gen.h"
7072
7073/**********************************************************************/
7076 static const char *list_accessor(int i)
7077{
7078 i = CLIP(0, i, list_args_max());
7079 return list_args_name((enum list_args) i);
7080}
7081
7082/**********************************************************************/
7085 static bool show_list(struct connection *caller, char *arg)
7086{
7087 enum m_pre_result match_result;
7088 int ind_int;
7089 enum list_args ind;
7090
7091 remove_leading_trailing_spaces(arg);
7092 match_result = match_prefix(list_accessor, list_args_max() + 1, 0,
7093 fc_strncasecmp, NULL, arg, &ind_int);
7094 ind = ind_int;
7095
7096 if (match_result > M_PRE_EMPTY) {
7097 cmd_reply(CMD_LIST, caller, C_SYNTAX,
7098 _("Bad list argument: '%s'. Try '%shelp list'."),
7099 arg, (caller ? "/" : ""));
7100 return FALSE;
7101 }
7102
7103 if (match_result == M_PRE_EMPTY) {
7104 ind = LIST_PLAYERS;
7105 }
7106
7107 switch (ind) {
7108 case LIST_COLORS:
7109 show_colors(caller);
7110 return TRUE;
7111 case LIST_CONNECTIONS:
7112 show_connections(caller);
7113 return TRUE;
7114 case LIST_DELEGATIONS:
7115 show_delegations(caller);
7116 return TRUE;
7117 case LIST_IGNORE:
7118 return show_ignore(caller);
7119 case LIST_MAPIMG:
7120 show_mapimg(caller, CMD_LIST);
7121 return TRUE;
7122 case LIST_PLAYERS:
7123 show_players(caller);
7124 return TRUE;
7125 case LIST_RULESETS:
7126 show_rulesets(caller);
7127 return TRUE;
7128 case LIST_SCENARIOS:
7129 show_scenarios(caller);
7130 return TRUE;
7131 case LIST_NATIONSETS:
7132 show_nationsets(caller);
7133 return TRUE;
7134 case LIST_TEAMS:
7135 show_teams(caller);
7136 return TRUE;
7137 case LIST_VOTES:
7138 show_votes(caller);
7139 return TRUE;
7140 }
7141
7142 cmd_reply(CMD_LIST, caller, C_FAIL,
7143 "Internal error: ind %d in show_list", ind);
7144 log_error("Internal error: ind %d in show_list", ind);
7145 return FALSE;
7146}
7147
7148#ifdef FREECIV_HAVE_LIBREADLINE
7149/********************* RL completion functions ***************************/
7150/* To properly complete both commands, player names, options and filenames
7151 there is one array per type of completion with the commands that
7152 the type is relevant for.
7153*/
7154
7155/**********************************************************************/
7163static char *generic_generator(const char *text, int state, int num,
7164 const char*(*index2str)(int))
7165{
7166 static int list_index, len;
7167 const char *name = ""; /* dummy non-NULL string */
7168 char *mytext = local_to_internal_string_malloc(text);
7169
7170 /* This function takes a string (text) in the local format and must return
7171 * a string in the local format. However comparisons are done against
7172 * names that are in the internal format (UTF-8). Thus we have to convert
7173 * the text function from the local to the internal format before doing
7174 * the comparison, and convert the string we return *back* to the
7175 * local format when returning it. */
7176
7177 /* If this is a new word to complete, initialize now. This includes
7178 saving the length of TEXT for efficiency, and initializing the index
7179 variable to 0. */
7180 if (state == 0) {
7181 list_index = 0;
7182 len = strlen(mytext);
7183 }
7184
7185 /* Return the next name which partially matches: */
7186 while ((num < 0 && name) || (list_index < num)) {
7187 name = index2str(list_index);
7188 list_index++;
7189
7190 if (name != NULL && fc_strncasecmp(name, mytext, len) == 0) {
7191 free(mytext);
7192 return internal_to_local_string_malloc(name);
7193 }
7194 }
7195 free(mytext);
7196
7197 /* If no names matched, then return NULL. */
7198 return ((char *)NULL);
7199}
7200
7201/**********************************************************************/
7204static char *command_generator(const char *text, int state)
7205{
7206 return generic_generator(text, state, CMD_NUM, command_name_by_number);
7207}
7208
7209/**********************************************************************/
7212static char *option_generator(const char *text, int state)
7213{
7214 return generic_generator(text, state, settings_number(), optname_accessor);
7215}
7216
7217/**********************************************************************/
7220static char *olevel_generator(const char *text, int state)
7221{
7222 return generic_generator(text, state, settings_number() + OLEVELS_NUM + 1,
7223 olvlname_accessor);
7224}
7225
7226/**********************************************************************/
7230static int completion_option;
7231static const char *option_value_accessor(int idx) {
7232 const struct setting *pset = setting_by_number(completion_option);
7233
7234 switch (setting_type(pset)) {
7235 case SST_ENUM:
7236 return setting_enum_val(pset, idx, FALSE);
7237 case SST_BITWISE:
7238 return setting_bitwise_bit(pset, idx, FALSE);
7239 default:
7240 fc_assert(FALSE);
7241 }
7242
7243 return NULL;
7244}
7245
7246/**********************************************************************/
7250static char *option_value_generator(const char *text, int state)
7251{
7252 return generic_generator(text, state, -1, option_value_accessor);
7253}
7254
7255/**********************************************************************/
7258static const char *playername_accessor(int idx)
7259{
7260 const struct player_slot *pslot = player_slot_by_number(idx);
7261
7262 if (!player_slot_is_used(pslot)) {
7263 return NULL;
7264 }
7265
7266 return player_name(player_slot_get_player(pslot));
7267}
7268
7269/**********************************************************************/
7272static char *player_generator(const char *text, int state)
7273{
7274 return generic_generator(text, state, player_slot_count(),
7275 playername_accessor);
7276}
7277
7278/**********************************************************************/
7281static const char *connection_name_accessor(int idx)
7282{
7283 return conn_list_get(game.all_connections, idx)->username;
7284}
7285
7286/**********************************************************************/
7289static char *connection_generator(const char *text, int state)
7290{
7291 return generic_generator(text, state, conn_list_size(game.all_connections),
7292 connection_name_accessor);
7293}
7294
7295/**********************************************************************/
7298static const char *cmdlevel_arg1_accessor(int idx)
7299{
7300 return cmdlevel_name(idx);
7301}
7302
7303/**********************************************************************/
7306static char *cmdlevel_arg1_generator(const char *text, int state)
7307{
7308 return generic_generator(text, state, cmdlevel_max()+1,
7309 cmdlevel_arg1_accessor);
7310}
7311
7312/**********************************************************************/
7316static const char *cmdlevel_arg2_accessor(int idx)
7317{
7318 return ((idx == 0) ? "first" :
7319 (idx == 1) ? "new" :
7320 connection_name_accessor(idx - 2));
7321}
7322
7323/**********************************************************************/
7326static char *cmdlevel_arg2_generator(const char *text, int state)
7327{
7328 return generic_generator(text, state,
7329 /* "first", "new", connection names */
7330 2 + conn_list_size(game.all_connections),
7331 cmdlevel_arg2_accessor);
7332}
7333
7334/**********************************************************************/
7337static const char *aitype_accessor(int idx)
7338{
7339 return get_ai_type(idx)->name;
7340}
7341
7342/**********************************************************************/
7345static char *aitype_generator(const char *text, int state)
7346{
7347 return generic_generator(text, state, ai_type_get_count(),
7348 aitype_accessor);
7349}
7350
7351/**********************************************************************/
7354static char *reset_generator(const char *text, int state)
7355{
7356 return generic_generator(text, state, reset_args_max() + 1, reset_accessor);
7357}
7358
7359/**********************************************************************/
7362static char *vote_generator(const char *text, int state)
7363{
7364 return generic_generator(text, state, -1, vote_arg_accessor);
7365}
7366
7367/**********************************************************************/
7370static char *delegate_generator(const char *text, int state)
7371{
7372 return generic_generator(text, state, delegate_args_max() + 1,
7373 delegate_accessor);
7374}
7375
7376/**********************************************************************/
7379static char *mapimg_generator(const char *text, int state)
7380{
7381 return generic_generator(text, state, mapimg_args_max() + 1,
7382 mapimg_accessor);
7383}
7384
7385/**********************************************************************/
7388static char *fcdb_generator(const char *text, int state)
7389{
7390 return generic_generator(text, state, FCDB_COUNT, fcdb_accessor);
7391}
7392
7393/**********************************************************************/
7396static char *lua_generator(const char *text, int state)
7397{
7398 return generic_generator(text, state, lua_args_max() + 1, lua_accessor);
7399}
7400
7401/**********************************************************************/
7404static char *help_generator(const char *text, int state)
7405{
7406 return generic_generator(text, state, HELP_ARG_NUM, helparg_accessor);
7407}
7408
7409/**********************************************************************/
7412static char *list_generator(const char *text, int state)
7413{
7414 return generic_generator(text, state, list_args_max() + 1, list_accessor);
7415}
7416
7417/**********************************************************************/
7421static bool contains_token_before_start(int start, int token, const char *arg,
7422 bool allow_fluff)
7423{
7424 char *str_itr = rl_line_buffer;
7425 int arg_len = strlen(arg);
7426
7427 /* Swallow unwanted tokens and their preceding delimiters */
7428 while (token--) {
7429 while (str_itr < rl_line_buffer + start && !fc_isalnum(*str_itr)) {
7430 str_itr++;
7431 }
7432 while (str_itr < rl_line_buffer + start && fc_isalnum(*str_itr)) {
7433 str_itr++;
7434 }
7435 }
7436
7437 /* Swallow any delimiters before the token we're interested in */
7438 while (str_itr < rl_line_buffer + start && !fc_isalnum(*str_itr)) {
7439 str_itr++;
7440 }
7441
7442 if (fc_strncasecmp(str_itr, arg, arg_len) != 0) {
7443 return FALSE;
7444 }
7445 str_itr += arg_len;
7446
7447 if (fc_isalnum(*str_itr)) {
7448 /* Not a distinct word. */
7449 return FALSE;
7450 }
7451
7452 if (!allow_fluff) {
7453 for (; str_itr < rl_line_buffer + start; str_itr++) {
7454 if (fc_isalnum(*str_itr)) {
7455 return FALSE;
7456 }
7457 }
7458 }
7459
7460 return TRUE;
7461}
7462
7463/**********************************************************************/
7468static bool contains_str_before_start(int start, const char *cmd,
7469 bool allow_fluff)
7470{
7471 return contains_token_before_start(start, 0, cmd, allow_fluff);
7472}
7473
7474/**********************************************************************/
7478static bool is_command(int start)
7479{
7480 char *str_itr;
7481
7482 if (contains_str_before_start(start, command_name_by_number(CMD_HELP), FALSE))
7483 return TRUE;
7484
7485 /* if there is only it is also OK */
7486 str_itr = rl_line_buffer;
7487 while (str_itr - rl_line_buffer < start) {
7488 if (fc_isalnum(*str_itr)) {
7489 return FALSE;
7490 }
7491 str_itr++;
7492 }
7493 return TRUE;
7494}
7495
7496/**********************************************************************/
7499static int num_tokens(int start)
7500{
7501 int res = 0;
7502 bool alnum = FALSE;
7503 char *chptr = rl_line_buffer;
7504
7505 while (chptr - rl_line_buffer < start) {
7506 if (fc_isalnum(*chptr)) {
7507 if (!alnum) {
7508 alnum = TRUE;
7509 res++;
7510 }
7511 } else {
7512 alnum = FALSE;
7513 }
7514 chptr++;
7515 }
7516
7517 return res;
7518}
7519
7520/**************************************************************************
7521 Commands that may be followed by a player name
7522**************************************************************************/
7523static const int player_cmd[] = {
7524 CMD_AITOGGLE,
7525 CMD_RESTRICTED,
7526 CMD_NOVICE,
7527 CMD_EASY,
7528 CMD_NORMAL,
7529 CMD_HARD,
7530 CMD_CHEATING,
7531#ifdef FREECIV_DEBUG
7532 CMD_EXPERIMENTAL,
7533#endif
7534 CMD_REMOVE,
7535 CMD_TEAM,
7536 CMD_PLAYERCOLOR,
7537 -1
7538};
7539
7540/**********************************************************************/
7543static bool is_player(int start)
7544{
7545 int i = 0;
7546
7547 while (player_cmd[i] != -1) {
7548 if (contains_str_before_start(start, command_name_by_number(player_cmd[i]), FALSE)) {
7549 return TRUE;
7550 }
7551 i++;
7552 }
7553
7554 return FALSE;
7555}
7556
7557/**************************************************************************
7558 Commands that may be followed by a connection name
7559**************************************************************************/
7560static const int connection_cmd[] = {
7561 CMD_CUT,
7562 CMD_KICK,
7563 -1
7564};
7565
7566/**********************************************************************/
7569static bool is_connection(int start)
7570{
7571 int i = 0;
7572
7573 while (connection_cmd[i] != -1) {
7574 if (contains_str_before_start(start,
7575 command_name_by_number(connection_cmd[i]),
7576 FALSE)) {
7577 return TRUE;
7578 }
7579 i++;
7580 }
7581
7582 return FALSE;
7583}
7584
7585/**********************************************************************/
7588static bool is_cmdlevel_arg2(int start)
7589{
7590 return (contains_str_before_start(start, command_name_by_number(CMD_CMDLEVEL), TRUE)
7591 && num_tokens(start) == 2);
7592}
7593
7594/**********************************************************************/
7597static bool is_cmdlevel_arg1(int start)
7598{
7599 return contains_str_before_start(start, command_name_by_number(CMD_CMDLEVEL), FALSE);
7600}
7601
7602/**************************************************************************
7603 Commands that may be followed by a server option name
7604
7605 CMD_SHOW is handled by option_level_cmd, which is for both option levels
7606 and server options
7607**************************************************************************/
7608static const int server_option_cmd[] = {
7609 CMD_EXPLAIN,
7610 CMD_SET,
7611 CMD_DEFAULT,
7612 -1
7613};
7614
7615/**********************************************************************/
7619static bool is_server_option(int start)
7620{
7621 int i = 0;
7622
7623 while (server_option_cmd[i] != -1) {
7624 if (contains_str_before_start(start, command_name_by_number(server_option_cmd[i]),
7625 FALSE)) {
7626 return TRUE;
7627 }
7628 i++;
7629 }
7630
7631 return FALSE;
7632}
7633
7634/**************************************************************************
7635 Commands that may be followed by an option level or server option
7636**************************************************************************/
7637static const int option_level_cmd[] = {
7638 CMD_SHOW,
7639 -1
7640};
7641
7642/**********************************************************************/
7646static bool is_option_level(int start)
7647{
7648 int i = 0;
7649
7650 while (option_level_cmd[i] != -1) {
7651 if (contains_str_before_start(start, command_name_by_number(option_level_cmd[i]),
7652 FALSE)) {
7653 return TRUE;
7654 }
7655 i++;
7656 }
7657
7658 return FALSE;
7659}
7660
7661/**********************************************************************/
7666static bool is_enum_option_value(int start, int *opt_p)
7667{
7668 if (contains_str_before_start(start, command_name_by_number(CMD_SET),
7669 TRUE)) {
7670 settings_iterate(SSET_ALL, pset) {
7671 if (setting_type(pset) != SST_ENUM
7672 && setting_type(pset) != SST_BITWISE) {
7673 continue;
7674 }
7675 /* Allow a single token for enum options, multiple for bitwise
7676 * (the separator | will separate tokens for these purposes) */
7677 if (contains_token_before_start(start, 1, setting_name(pset),
7678 setting_type(pset) == SST_BITWISE)) {
7679 *opt_p = setting_number(pset);
7680 /* Suppress appended space for bitwise options (user may want |) */
7681 rl_completion_suppress_append = (setting_type(pset) == SST_BITWISE);
7682 return TRUE;
7683 }
7684 } settings_iterate_end;
7685 }
7686 return FALSE;
7687}
7688
7689/**************************************************************************
7690 Commands that may be followed by a filename
7691**************************************************************************/
7692static const int filename_cmd[] = {
7693 CMD_LOAD,
7694 CMD_SAVE,
7695 CMD_READ_SCRIPT,
7696 CMD_WRITE_SCRIPT,
7697 -1
7698};
7699
7700/**********************************************************************/
7703static bool is_filename(int start)
7704{
7705 int i = 0;
7706
7707 while (filename_cmd[i] != -1) {
7708 if (contains_str_before_start(start, command_name_by_number(filename_cmd[i]), FALSE)) {
7709 return TRUE;
7710 }
7711 i++;
7712 }
7713
7714 return FALSE;
7715}
7716
7717/**********************************************************************/
7720static bool is_create_arg2(int start)
7721{
7722 return (contains_str_before_start(start, command_name_by_number(CMD_CREATE), TRUE)
7723 && num_tokens(start) == 2);
7724}
7725
7726/**********************************************************************/
7729static bool is_reset(int start)
7730{
7731 return contains_str_before_start(start,
7732 command_name_by_number(CMD_RESET),
7733 FALSE);
7734}
7735
7736/**********************************************************************/
7739static bool is_vote(int start)
7740{
7741 return contains_str_before_start(start,
7742 command_name_by_number(CMD_VOTE),
7743 FALSE);
7744}
7745
7746/**********************************************************************/
7749static bool is_delegate_arg1(int start)
7750{
7751 return contains_str_before_start(start,
7752 command_name_by_number(CMD_DELEGATE),
7753 FALSE);
7754}
7755
7756/**********************************************************************/
7759static bool is_mapimg(int start)
7760{
7761 return contains_str_before_start(start,
7762 command_name_by_number(CMD_MAPIMG),
7763 FALSE);
7764}
7765
7766/**********************************************************************/
7769static bool is_fcdb(int start)
7770{
7771 return contains_str_before_start(start,
7772 command_name_by_number(CMD_FCDB),
7773 FALSE);
7774}
7775
7776/**********************************************************************/
7779static bool is_lua(int start)
7780{
7781 return contains_str_before_start(start,
7782 command_name_by_number(CMD_LUA),
7783 FALSE);
7784}
7785
7786/**********************************************************************/
7789static bool is_help(int start)
7790{
7791 return contains_str_before_start(start, command_name_by_number(CMD_HELP), FALSE);
7792}
7793
7794/**********************************************************************/
7797static bool is_list(int start)
7798{
7799 return contains_str_before_start(start, command_name_by_number(CMD_LIST), FALSE);
7800}
7801
7802/**********************************************************************/
7809char **freeciv_completion(const char *text, int start, int end)
7810{
7811 char **matches = (char **)NULL;
7812
7813 if (is_help(start)) {
7814 matches = rl_completion_matches(text, help_generator);
7815 } else if (is_command(start)) {
7816 matches = rl_completion_matches(text, command_generator);
7817 } else if (is_list(start)) {
7818 matches = rl_completion_matches(text, list_generator);
7819 } else if (is_cmdlevel_arg2(start)) {
7820 matches = rl_completion_matches(text, cmdlevel_arg2_generator);
7821 } else if (is_cmdlevel_arg1(start)) {
7822 matches = rl_completion_matches(text, cmdlevel_arg1_generator);
7823 } else if (is_connection(start)) {
7824 matches = rl_completion_matches(text, connection_generator);
7825 } else if (is_player(start)) {
7826 matches = rl_completion_matches(text, player_generator);
7827 } else if (is_server_option(start)) {
7828 matches = rl_completion_matches(text, option_generator);
7829 } else if (is_option_level(start)) {
7830 matches = rl_completion_matches(text, olevel_generator);
7831 } else if (is_enum_option_value(start, &completion_option)) {
7832 matches = rl_completion_matches(text, option_value_generator);
7833 } else if (is_filename(start)) {
7834 /* This function we get from readline */
7835 matches = rl_completion_matches(text, rl_filename_completion_function);
7836 } else if (is_create_arg2(start)) {
7837 matches = rl_completion_matches(text, aitype_generator);
7838 } else if (is_reset(start)) {
7839 matches = rl_completion_matches(text, reset_generator);
7840 } else if (is_vote(start)) {
7841 matches = rl_completion_matches(text, vote_generator);
7842 } else if (is_delegate_arg1(start)) {
7843 matches = rl_completion_matches(text, delegate_generator);
7844 } else if (is_mapimg(start)) {
7845 matches = rl_completion_matches(text, mapimg_generator);
7846 } else if (is_fcdb(start)) {
7847 matches = rl_completion_matches(text, fcdb_generator);
7848 } else if (is_lua(start)) {
7849 matches = rl_completion_matches(text, lua_generator);
7850 } else {
7851 /* We have no idea what to do */
7852 matches = NULL;
7853 }
7854
7855 /* Don't automatically try to complete with filenames */
7856 rl_attempted_completion_over = 1;
7857
7858 return (matches);
7859}
7860
7861#endif /* FREECIV_HAVE_LIBREADLINE */
achievement_player_has
bool achievement_player_has(const struct achievement *pach, const struct player *pplayer)
Definition achievements.c:364
achievement_index
int achievement_index(const struct achievement *pach)
Definition achievements.c:86
achievements_iterate_end
#define achievements_iterate_end
Definition achievements.h:70
achievements_iterate
#define achievements_iterate(_ach_)
Definition achievements.h:64
ai_name
const char * ai_name(const struct ai_type *ai)
Definition ai.c:335
ai_type_by_name
struct ai_type * ai_type_by_name(const char *search)
Definition ai.c:290
ai_type_get_count
int ai_type_get_count(void)
Definition ai.c:327
get_ai_type
struct ai_type * get_ai_type(int id)
Definition ai.c:260
CALL_PLR_AI_FUNC
#define CALL_PLR_AI_FUNC(_func, _player,...)
Definition ai.h:377
default_ai_type_name
const char * default_ai_type_name(void)
Definition aiiface.c:264
aiiface.h
astr_free
void astr_free(struct astring *astr)
Definition astring.c:148
astr_build_or_list
const char * astr_build_or_list(struct astring *astr, const char *const *items, size_t number)
Definition astring.c:313
astr_set
void astr_set(struct astring *astr, const char *format,...)
Definition astring.c:251
str
#define str
Definition astring.c:76
n
#define n
Definition astring.c:77
astring.h
astr_str
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
ASTRING_INIT
#define ASTRING_INIT
Definition astring.h:44
bitvector.h
BV_SET
#define BV_SET(bv, bit)
Definition bitvector.h:81
BV_ISSET
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
BV_CLR
#define BV_CLR(bv, bit)
Definition bitvector.h:86
capability.h
SERVER_COMMAND_PREFIX
#define SERVER_COMMAND_PREFIX
Definition chat.h:28
city_name_get
const char * city_name_get(const struct city *pcity)
Definition city.c:1133
city_list_iterate
#define city_list_iterate(citylist, pcity)
Definition city.h:508
city_size_get
static citizens city_size_get(const struct city *pcity)
Definition city.h:569
city_list_iterate_end
#define city_list_iterate_end
Definition city.h:510
citytools.h
command_echo
enum cmd_echo command_echo(const struct command *pcommand)
Definition commands.c:799
command_name_by_number
const char * command_name_by_number(int i)
Definition commands.c:751
command_name
const char * command_name(const struct command *pcommand)
Definition commands.c:743
command_by_number
const struct command * command_by_number(int i)
Definition commands.c:734
command_short_help
const char * command_short_help(const struct command *pcommand)
Definition commands.c:767
command_extra_help
char * command_extra_help(const struct command *pcommand)
Definition commands.c:776
command_level
enum cmdlevel command_level(const struct command *pcommand)
Definition commands.c:791
command_synopsis
const char * command_synopsis(const struct command *pcommand)
Definition commands.c:759
command_id
command_id
Definition commands.h:35
CMD_NUM
@ CMD_NUM
Definition commands.h:109
CMD_UNLOCK
@ CMD_UNLOCK
Definition commands.h:102
CMD_IGNORE
@ CMD_IGNORE
Definition commands.h:78
CMD_LOCK
@ CMD_LOCK
Definition commands.h:101
CMD_METASERVER
@ CMD_METASERVER
Definition commands.h:58
CMD_END_GAME
@ CMD_END_GAME
Definition commands.h:84
CMD_DEFAULT
@ CMD_DEFAULT
Definition commands.h:93
CMD_METAPATCHES
@ CMD_METAPATCHES
Definition commands.h:56
CMD_TEAM
@ CMD_TEAM
Definition commands.h:53
CMD_DELEGATE
@ CMD_DELEGATE
Definition commands.h:96
CMD_CHEATING
@ CMD_CHEATING
Definition commands.h:70
CMD_PLAYERCOLOR
@ CMD_PLAYERCOLOR
Definition commands.h:80
CMD_LIST
@ CMD_LIST
Definition commands.h:39
CMD_AITOGGLE
@ CMD_AITOGGLE
Definition commands.h:59
CMD_CUT
@ CMD_CUT
Definition commands.h:41
CMD_EXPLAIN
@ CMD_EXPLAIN
Definition commands.h:44
CMD_SHOW
@ CMD_SHOW
Definition commands.h:45
CMD_METAMESSAGE
@ CMD_METAMESSAGE
Definition commands.h:55
CMD_RULESETDIR
@ CMD_RULESETDIR
Definition commands.h:54
CMD_HARD
@ CMD_HARD
Definition commands.h:69
CMD_RFCSTYLE
@ CMD_RFCSTYLE
Definition commands.h:105
CMD_DETACH
@ CMD_DETACH
Definition commands.h:62
CMD_NORMAL
@ CMD_NORMAL
Definition commands.h:68
CMD_RESTRICTED
@ CMD_RESTRICTED
Definition commands.h:65
CMD_VOTE
@ CMD_VOTE
Definition commands.h:48
CMD_NOVICE
@ CMD_NOVICE
Definition commands.h:66
CMD_UNRECOGNIZED
@ CMD_UNRECOGNIZED
Definition commands.h:110
CMD_TIMEOUT
@ CMD_TIMEOUT
Definition commands.h:76
CMD_CREATE
@ CMD_CREATE
Definition commands.h:63
CMD_LOAD
@ CMD_LOAD
Definition commands.h:89
CMD_AICMD
@ CMD_AICMD
Definition commands.h:97
CMD_AMBIGUOUS
@ CMD_AMBIGUOUS
Definition commands.h:111
CMD_LUA
@ CMD_LUA
Definition commands.h:94
CMD_FCDB
@ CMD_FCDB
Definition commands.h:98
CMD_CANCELVOTE
@ CMD_CANCELVOTE
Definition commands.h:77
CMD_SAVE
@ CMD_SAVE
Definition commands.h:87
CMD_SRVID
@ CMD_SRVID
Definition commands.h:106
CMD_SCENSAVE
@ CMD_SCENSAVE
Definition commands.h:88
CMD_START_GAME
@ CMD_START_GAME
Definition commands.h:37
CMD_UNIGNORE
@ CMD_UNIGNORE
Definition commands.h:79
CMD_FIRSTLEVEL
@ CMD_FIRSTLEVEL
Definition commands.h:75
CMD_WALL
@ CMD_WALL
Definition commands.h:46
CMD_EASY
@ CMD_EASY
Definition commands.h:67
CMD_KICK
@ CMD_KICK
Definition commands.h:95
CMD_WRITE_SCRIPT
@ CMD_WRITE_SCRIPT
Definition commands.h:91
CMD_CONNECTMSG
@ CMD_CONNECTMSG
Definition commands.h:47
CMD_TAKE
@ CMD_TAKE
Definition commands.h:60
CMD_HELP
@ CMD_HELP
Definition commands.h:38
CMD_REMOVE
@ CMD_REMOVE
Definition commands.h:86
CMD_OBSERVE
@ CMD_OBSERVE
Definition commands.h:61
CMD_RESET
@ CMD_RESET
Definition commands.h:92
CMD_SURRENDER
@ CMD_SURRENDER
Definition commands.h:85
CMD_METACONN
@ CMD_METACONN
Definition commands.h:57
CMD_READ_SCRIPT
@ CMD_READ_SCRIPT
Definition commands.h:90
CMD_CMDLEVEL
@ CMD_CMDLEVEL
Definition commands.h:74
CMD_SET
@ CMD_SET
Definition commands.h:52
CMD_AWAY
@ CMD_AWAY
Definition commands.h:64
CMD_QUIT
@ CMD_QUIT
Definition commands.h:40
CMD_DEBUG
@ CMD_DEBUG
Definition commands.h:51
CMD_PLAYERNATION
@ CMD_PLAYERNATION
Definition commands.h:81
CMD_MAPIMG
@ CMD_MAPIMG
Definition commands.h:99
CMD_ECHO_ADMINS
@ CMD_ECHO_ADMINS
Definition commands.h:22
CMD_ECHO_NONE
@ CMD_ECHO_NONE
Definition commands.h:21
CMD_ECHO_ALL
@ CMD_ECHO_ALL
Definition commands.h:23
incite_cost
char * incite_cost
Definition comments.c:74
MAX_LEN_MSG
#define MAX_LEN_MSG
Definition conn_types.h:37
connection_attach
bool connection_attach(struct connection *pconn, struct player *pplayer, bool observing)
Definition connecthand.c:793
connection_delegate_take
bool connection_delegate_take(struct connection *pconn, struct player *dplayer)
Definition connecthand.c:884
find_uncontrolled_player
struct player * find_uncontrolled_player(void)
Definition connecthand.c:618
connection_close_server
void connection_close_server(struct connection *pconn, const char *reason)
Definition connecthand.c:1007
connection_detach
void connection_detach(struct connection *pconn, bool remove_unused_player)
Definition connecthand.c:809
conn_set_access
void conn_set_access(struct connection *pconn, enum cmdlevel new_level, bool granted)
Definition connecthand.c:72
connection_delegate_restore
bool connection_delegate_restore(struct connection *pconn)
Definition connecthand.c:945
connecthand.h
conn_pattern_to_string
size_t conn_pattern_to_string(const struct conn_pattern *ppattern, char *buf, size_t buf_len)
Definition connection.c:865
conn_get_player
struct player * conn_get_player(const struct connection *pconn)
Definition connection.c:763
conn_by_user_prefix
struct connection * conn_by_user_prefix(const char *user_name, enum m_pre_result *result)
Definition connection.c:398
conn_by_user
struct connection * conn_by_user(const char *user_name)
Definition connection.c:377
conn_list_compression_thaw
void conn_list_compression_thaw(const struct conn_list *pconn_list)
Definition connection.c:732
conn_pattern_destroy
void conn_pattern_destroy(struct conn_pattern *ppattern)
Definition connection.c:809
conn_list_compression_freeze
void conn_list_compression_freeze(const struct conn_list *pconn_list)
Definition connection.c:720
conn_controls_player
bool conn_controls_player(const struct connection *pconn)
Definition connection.c:745
conn_description
const char * conn_description(const struct connection *pconn)
Definition connection.c:474
conn_pattern_from_string
struct conn_pattern * conn_pattern_from_string(const char *pattern, enum conn_pattern_type prefer, char *error_buf, size_t error_buf_len)
Definition connection.c:878
conn_get_access
enum cmdlevel conn_get_access(const struct connection *pconn)
Definition connection.c:775
conn_pattern_list_iterate_end
#define conn_pattern_list_iterate_end
Definition connection.h:338
conn_list_iterate
#define conn_list_iterate(connlist, pconn)
Definition connection.h:108
conn_pattern_list_iterate
#define conn_pattern_list_iterate(plist, ppatern)
Definition connection.h:336
conn_list_iterate_end
#define conn_list_iterate_end
Definition connection.h:110
con_get_style
bool con_get_style(void)
Definition console.c:264
con_set_style
void con_set_style(bool i)
Definition console.c:251
con_write
void con_write(enum rfc_status rfc_status, const char *message,...)
Definition console.c:203
rfc_status
rfc_status
Definition console.h:35
C_DISCONNECTED
@ C_DISCONNECTED
Definition console.h:43
C_BOUNCE
@ C_BOUNCE
Definition console.h:48
C_FAIL
@ C_FAIL
Definition console.h:45
C_SYNTAX
@ C_SYNTAX
Definition console.h:47
C_OK
@ C_OK
Definition console.h:41
C_METAERROR
@ C_METAERROR
Definition console.h:46
C_GENFAIL
@ C_GENFAIL
Definition console.h:49
C_COMMENT
@ C_COMMENT
Definition console.h:37
C_WARNING
@ C_WARNING
Definition console.h:50
MAX_LEN_CONSOLE_LINE
#define MAX_LEN_CONSOLE_LINE
Definition console.h:19
deprecations.h
log_deprecation
#define log_deprecation(message,...)
Definition deprecations.h:35
punit
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:74
set_ai_level_directer
void set_ai_level_directer(struct player *pplayer, enum ai_level level)
Definition difficulty.c:39
difficulty.h
diplhand.h
id
int int id
Definition editgui_g.h:28
events.h
free_tokens
void free_tokens(char **tokens, size_t ntokens)
Definition fc_cmdline.c:203
get_tokens
int get_tokens(const char *str, char **tokens, size_t num_tokens, const char *delimiterset)
Definition fc_cmdline.c:166
fc_cmdline.h
fc_prehdrs.h
fc_types.h
RULESET_SUFFIX
#define RULESET_SUFFIX
Definition fc_types.h:416
MAX_LEN_NAME
#define MAX_LEN_NAME
Definition fc_types.h:66
LINE_BREAK
#define LINE_BREAK
Definition fc_types.h:77
fciconv.h
internal_to_local_string_malloc
char * internal_to_local_string_malloc(const char *text)
local_to_internal_string_malloc
char * local_to_internal_string_malloc(const char *text)
fcintl.h
PL_
#define PL_(String1, String2, n)
Definition fcintl.h:71
_
#define _(String)
Definition fcintl.h:67
featured_text_apply_tag
size_t featured_text_apply_tag(const char *text_source, char *featured_text, size_t featured_text_len, enum text_tag_type tag_type, ft_offset_t start_offset, ft_offset_t stop_offset,...)
Definition featured_text.c:997
ftc_log
const struct ft_color ftc_log
Definition featured_text.c:76
ftc_command
const struct ft_color ftc_command
Definition featured_text.c:80
ftc_server
const struct ft_color ftc_server
Definition featured_text.c:77
ftc_any
const struct ft_color ftc_any
Definition featured_text.c:73
ftc_vote_team
const struct ft_color ftc_vote_team
Definition featured_text.c:92
ftc_game_start
const struct ft_color ftc_game_start
Definition featured_text.c:84
ftc_server_prompt
const struct ft_color ftc_server_prompt
Definition featured_text.c:82
ftc_changed
struct ft_color ftc_changed
Definition featured_text.c:81
ftc_vote_public
const struct ft_color ftc_vote_public
Definition featured_text.c:91
featured_text.h
FT_OFFSET_UNSET
#define FT_OFFSET_UNSET
Definition featured_text.h:104
TTT_COLOR
@ TTT_COLOR
Definition featured_text.h:125
game
struct civ_game game
Definition game.c:61
wld
struct world wld
Definition game.c:62
game_unit_by_number
struct unit * game_unit_by_number(int id)
Definition game.c:115
game.h
DEBUG_FERRIES
@ DEBUG_FERRIES
Definition game.h:40
GAME_MAX_READ_RECURSION
#define GAME_MAX_READ_RECURSION
Definition game.h:745
send_scenario_description
void send_scenario_description(struct conn_list *dest)
Definition gamehand.c:967
send_scenario_info
void send_scenario_info(struct conn_list *dest)
Definition gamehand.c:953
send_game_info
void send_game_info(struct conn_list *dest)
Definition gamehand.c:910
cache_rulesets
void cache_rulesets(void)
Definition gamehand.c:1136
gamehand.h
owner
struct city * owner
Definition citydlg.c:226
persistent
static GtkWidget * persistent
Definition rallypointdlg.c:40
title
const char * title
Definition repodlgs.c:1314
leader_name
static char * leader_name
Definition dialogs.c:97
handle_player_ready
void handle_player_ready(struct player *pplayer, int player_no, bool is_ready)
Definition srv_main.c:2451
handicaps.h
name
const char * name
Definition inputfile.c:127
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
__FC_LINE__
#define __FC_LINE__
Definition log.h:40
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
log_testmatic_alt
#define log_testmatic_alt(altlvl, message,...)
Definition log.h:124
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
fc_assert_action
#define fc_assert_action(condition, action)
Definition log.h:187
log_normal
#define log_normal(message,...)
Definition log.h:107
LOG_NORMAL
@ LOG_NORMAL
Definition log.h:32
log_error
#define log_error(message,...)
Definition log.h:103
map_pos_to_tile
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Definition map.c:425
map_startpos_count
int map_startpos_count(void)
Definition map.c:1882
map_is_empty
bool map_is_empty(void)
Definition map.c:148
map.h
mapgen.h
maphand.h
mapimg_id2str
bool mapimg_id2str(int id, char *str, size_t str_len)
Definition mapimg.c:1314
mapimg_colortest
bool mapimg_colortest(const char *savename, const char *path)
Definition mapimg.c:1441
mapimg_isvalid
struct mapdef * mapimg_isvalid(int id)
Definition mapimg.c:1124
mapimg_define
bool mapimg_define(const char *maparg, bool check)
Definition mapimg.c:769
mapimg_delete
bool mapimg_delete(int id)
Definition mapimg.c:1207
mapimg_count
int mapimg_count(void)
Definition mapimg.c:573
mapimg_create
bool mapimg_create(struct mapdef *pmapdef, bool force, const char *savename, const char *path)
Definition mapimg.c:1335
mapimg_error
const char * mapimg_error(void)
Definition mapimg.c:759
mapimg_show
bool mapimg_show(int id, char *str, size_t str_len, bool detail)
Definition mapimg.c:1226
mapimg.h
MAX_LEN_MAPDEF
#define MAX_LEN_MAPDEF
Definition mapimg.h:65
mem.h
FC_FREE
#define FC_FREE(ptr)
Definition mem.h:41
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
set_meta_patches_string
void set_meta_patches_string(const char *string)
Definition meta.c:172
is_metaserver_open
bool is_metaserver_open(void)
Definition meta.c:483
meta_addr_port
char * meta_addr_port(void)
Definition meta.c:203
default_meta_message_string
const char * default_meta_message_string(void)
Definition meta.c:91
server_close_meta
void server_close_meta(void)
Definition meta.c:455
default_meta_patches_string
const char * default_meta_patches_string(void)
Definition meta.c:83
get_meta_message_string
const char * get_meta_message_string(void)
Definition meta.c:115
send_server_info_to_metaserver
bool send_server_info_to_metaserver(enum meta_flag flag)
Definition meta.c:491
server_open_meta
bool server_open_meta(bool persistent)
Definition meta.c:464
get_meta_patches_string
const char * get_meta_patches_string(void)
Definition meta.c:107
set_user_meta_message_string
void set_user_meta_message_string(const char *string)
Definition meta.c:188
meta.h
DEFAULT_META_SERVER_ADDR
#define DEFAULT_META_SERVER_ADDR
Definition meta.h:21
META_GOODBYE
@ META_GOODBYE
Definition meta.h:28
META_INFO
@ META_INFO
Definition meta.h:26
modpack_ruleset_cache_iterate
void modpack_ruleset_cache_iterate(mrc_cb cb, void *data)
Definition modpack.c:346
modpack_file_from_ruleset_cache
const char * modpack_file_from_ruleset_cache(const char *name)
Definition modpack.c:295
modpack_serv_file
const char * modpack_serv_file(struct section_file *sf)
Definition modpack.c:189
modpack_rulesetdir
const char * modpack_rulesetdir(struct section_file *sf)
Definition modpack.c:204
modpack.h
translated
#define translated
Definition name_translation.h:31
nation_rule_name
const char * nation_rule_name(const struct nation_type *pnation)
Definition nation.c:138
nations_match
int nations_match(const struct nation_type *pnation1, const struct nation_type *pnation2, bool ignore_conflicts)
Definition nation.c:1206
nation_of_unit
struct nation_type * nation_of_unit(const struct unit *punit)
Definition nation.c:463
nation_adjective_for_player
const char * nation_adjective_for_player(const struct player *pplayer)
Definition nation.c:169
nation_set_name_translation
const char * nation_set_name_translation(const struct nation_set *pset)
Definition nation.c:818
nation_of_player
struct nation_type * nation_of_player(const struct player *pplayer)
Definition nation.c:444
is_nation_playable
bool is_nation_playable(const struct nation_type *nation)
Definition nation.c:200
nation_is_in_set
bool nation_is_in_set(const struct nation_type *pnation, const struct nation_set *pset)
Definition nation.c:837
nation_set_description
const char * nation_set_description(const struct nation_set *pset)
Definition nation.c:828
nation_set_count
int nation_set_count(void)
Definition nation.c:691
nation_by_rule_name
struct nation_type * nation_by_rule_name(const char *name)
Definition nation.c:121
nation_plural_translation
const char * nation_plural_translation(const struct nation_type *pnation)
Definition nation.c:159
nation_set_rule_name
const char * nation_set_rule_name(const struct nation_set *pset)
Definition nation.c:807
nation_plural_for_player
const char * nation_plural_for_player(const struct player *pplayer)
Definition nation.c:178
init_government_of_nation
struct government * init_government_of_nation(const struct nation_type *pnation)
Definition nation.c:659
style_of_nation
struct nation_style * style_of_nation(const struct nation_type *pnation)
Definition nation.c:672
nation_sets_iterate_end
#define nation_sets_iterate_end
Definition nation.h:305
nation_sets_iterate
#define nation_sets_iterate(NAME_pset)
Definition nation.h:301
nations_iterate_end
#define nations_iterate_end
Definition nation.h:336
nations_iterate
#define nations_iterate(NAME_pnation)
Definition nation.h:333
NO_NATION_SELECTED
#define NO_NATION_SELECTED
Definition nation.h:30
notify_conn
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:239
notify_team
void notify_team(const struct player *pplayer, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:346
package_event
void package_event(struct packet_chat_msg *packet, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:168
event_cache_add_for_all
void event_cache_add_for_all(const struct packet_chat_msg *packet)
Definition notify.c:620
notify.h
packets.h
send_packet_chat_msg
int send_packet_chat_msg(struct connection *pc, const struct packet_chat_msg *packet)
Definition packets_gen.c:13424
dlsend_packet_game_load
void dlsend_packet_game_load(struct conn_list *dest, bool load_successful, const char *load_filename)
Definition packets_gen.c:83779
lsend_packet_achievement_info
void lsend_packet_achievement_info(struct conn_list *dest, const struct packet_achievement_info *packet)
Definition packets_gen.c:12979
cities
struct city_list * cities
Definition packhand.c:119
len
int len
Definition packhand.c:127
player_slot_is_used
bool player_slot_is_used(const struct player_slot *pslot)
Definition player.c:448
player_by_name_prefix
struct player * player_by_name_prefix(const char *name, enum m_pre_result *result)
Definition player.c:920
player_by_number
struct player * player_by_number(const int player_id)
Definition player.c:849
player_count
int player_count(void)
Definition player.c:817
player_slot_count
int player_slot_count(void)
Definition player.c:418
player_slot_by_number
struct player_slot * player_slot_by_number(int player_id)
Definition player.c:463
player_number
int player_number(const struct player *pplayer)
Definition player.c:837
player_name
const char * player_name(const struct player *pplayer)
Definition player.c:895
player_by_name
struct player * player_by_name(const char *name)
Definition player.c:881
player_by_user
struct player * player_by_user(const char *name)
Definition player.c:940
player_set_nation
bool player_set_nation(struct player *pplayer, struct nation_type *pnation)
Definition player.c:861
player_slot_get_player
struct player * player_slot_get_player(const struct player_slot *pslot)
Definition player.c:437
player.h
ai_level_cmd
#define ai_level_cmd(_level_)
Definition player.h:569
players_iterate_end
#define players_iterate_end
Definition player.h:539
players_iterate
#define players_iterate(_pplayer)
Definition player.h:534
player_list_iterate
#define player_list_iterate(playerlist, pplayer)
Definition player.h:557
ANON_USER_NAME
#define ANON_USER_NAME
Definition player.h:48
is_barbarian
static bool is_barbarian(const struct player *pplayer)
Definition player.h:491
is_ai
#define is_ai(plr)
Definition player.h:232
player_list_iterate_end
#define player_list_iterate_end
Definition player.h:559
set_as_human
#define set_as_human(plr)
Definition player.h:233
set_as_ai
#define set_as_ai(plr)
Definition player.h:234
ANON_PLAYER_NAME
#define ANON_PLAYER_NAME
Definition player.h:43
PLAYER_DEBUG_DIPLOMACY
@ PLAYER_DEBUG_DIPLOMACY
Definition player.h:215
PLAYER_DEBUG_TECH
@ PLAYER_DEBUG_TECH
Definition player.h:215
is_human
#define is_human(plr)
Definition player.h:231
server_player_set_name
void server_player_set_name(struct player *pplayer, const char *name)
Definition plrhand.c:2268
server_create_player
struct player * server_create_player(int player_id, const char *ai_tname, struct rgbcolor *prgbcolor, bool allow_ai_type_fallbacking)
Definition plrhand.c:1894
player_status_add
void player_status_add(struct player *plr, enum player_status pstatus)
Definition plrhand.c:3219
normal_player_count
int normal_player_count(void)
Definition plrhand.c:3211
player_set_under_human_control
void player_set_under_human_control(struct player *pplayer)
Definition plrhand.c:3460
server_player_set_color
void server_player_set_color(struct player *pplayer, const struct rgbcolor *prgbcolor)
Definition plrhand.c:1823
player_set_to_ai_mode
void player_set_to_ai_mode(struct player *pplayer, enum ai_level skill_level)
Definition plrhand.c:3438
server_player_set_name_full
bool server_player_set_name_full(const struct connection *caller, struct player *pplayer, const struct nation_type *pnation, const char *name, char *error_buf, size_t error_buf_len)
Definition plrhand.c:2168
player_delegation_active
bool player_delegation_active(const struct player *pplayer)
Definition plrhand.c:3273
player_info_thaw
void player_info_thaw(void)
Definition plrhand.c:1108
player_info_freeze
void player_info_freeze(void)
Definition plrhand.c:1099
pick_a_nation
struct nation_type * pick_a_nation(const struct nation_list *choices, bool ignore_conflicts, bool needs_startpos, enum barbarian_type barb_type)
Definition plrhand.c:2456
player_color_ftstr
const char * player_color_ftstr(struct player *pplayer)
Definition plrhand.c:1843
send_player_info_c
void send_player_info_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1146
player_status_check
bool player_status_check(struct player *plr, enum player_status pstatus)
Definition plrhand.c:3227
player_delegation_set
void player_delegation_set(struct player *pplayer, const char *username)
Definition plrhand.c:3257
server_remove_player
void server_remove_player(struct player *pplayer)
Definition plrhand.c:1943
server_player_init
void server_player_init(struct player *pplayer, bool initmap, bool needs_team)
Definition plrhand.c:1618
player_color_changeable
bool player_color_changeable(const struct player *pplayer, const char **reason)
Definition plrhand.c:1716
assign_player_colors
void assign_player_colors(void)
Definition plrhand.c:1734
client_can_pick_nation
bool client_can_pick_nation(const struct nation_type *pnation)
Definition plrhand.c:2617
send_player_diplstate_c
void send_player_diplstate_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1212
player_delegation_get
const char * player_delegation_get(const struct player *pplayer)
Definition plrhand.c:3244
nation_is_in_current_set
bool nation_is_in_current_set(const struct nation_type *pnation)
Definition plrhand.c:2593
reset_all_start_commands
void reset_all_start_commands(bool plrchange)
Definition plrhand.c:2727
plrhand.h
rand.h
secfile_load
struct section_file * secfile_load(const char *filename, bool allow_duplicates)
Definition registry.c:51
registry.h
secfile_error
const char * secfile_error(void)
Definition section_file.c:36
secfile_destroy
void secfile_destroy(struct section_file *secfile)
Definition section_file.c:95
secfile_check_unused
void secfile_check_unused(const struct section_file *secfile)
Definition registry_ini.c:907
secfile_load_section
struct section_file * secfile_load_section(const char *filename, const char *section, bool allow_duplicates)
Definition registry_ini.c:596
secfile_lookup_bool_default
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
Definition registry_ini.c:1902
report.h
research_get
struct research * research_get(const struct player *pplayer)
Definition research.c:128
research.h
rgbcolor_from_hex
bool rgbcolor_from_hex(struct rgbcolor **prgbcolor, const char *hex)
Definition rgbcolor.c:162
rgbcolor_destroy
void rgbcolor_destroy(struct rgbcolor *prgbcolor)
Definition rgbcolor.c:74
rgbcolors_are_equal
bool rgbcolors_are_equal(const struct rgbcolor *c1, const struct rgbcolor *c2)
Definition rgbcolor.c:62
rgbcolor.h
load_rulesets
bool load_rulesets(const char *restore, const char *alt, bool compat_mode, rs_conversion_logger logger, bool act, bool buffer_script, bool load_luadata)
Definition ruleload.c:9115
reload_rulesets_settings
bool reload_rulesets_settings(void)
Definition ruleload.c:9443
send_rulesets
void send_rulesets(struct conn_list *dest)
Definition ruleload.c:9466
ruleload.h
sanitycheck.h
sanity_check
#define sanity_check()
Definition sanitycheck.h:43
savegame_load
void savegame_load(struct section_file *sfile)
Definition savemain.c:43
save_game
void save_game(const char *orig_filename, const char *save_reason, bool scenario)
Definition savemain.c:143
savemain.h
score.h
script_fcdb_free
void script_fcdb_free(void)
Definition script_fcdb.c:377
script_fcdb_do_string
bool script_fcdb_do_string(struct connection *caller, const char *str)
Definition script_fcdb.c:396
script_fcdb_call
bool script_fcdb_call(const char *func_name,...)
Definition script_fcdb.c:359
script_fcdb_init
bool script_fcdb_init(const char *fcdb_luafile)
Definition script_fcdb.c:239
script_fcdb.h
script_server_unsafe_do_string
bool script_server_unsafe_do_string(struct connection *caller, const char *str)
Definition script_server.c:120
script_server_do_string
bool script_server_do_string(struct connection *caller, const char *str)
Definition script_server.c:112
script_server_unsafe_do_file
bool script_server_unsafe_do_file(struct connection *caller, const char *filename)
Definition script_server.c:196
script_server_do_file
bool script_server_do_file(struct connection *caller, const char *filename)
Definition script_server.c:188
script_server.h
section_file.h
sernet.h
setting_int_validate
bool setting_int_validate(const struct setting *pset, int val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3756
setting_action
void setting_action(const struct setting *pset)
Definition settings.c:4362
setting_admin_lock_clear
void setting_admin_lock_clear(struct setting *pset)
Definition settings.c:4681
setting_default_name
const char * setting_default_name(const struct setting *pset, bool pretty, char *buf, size_t buf_len)
Definition settings.c:4296
setting_enum_validate
bool setting_enum_validate(const struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:4044
setting_by_name
struct setting * setting_by_name(const char *name)
Definition settings.c:3302
setting_set_to_default
void setting_set_to_default(struct setting *pset)
Definition settings.c:4332
setting_value_name
const char * setting_value_name(const struct setting *pset, bool pretty, char *buf, size_t buf_len)
Definition settings.c:4260
setting_extra_help
const char * setting_extra_help(const struct setting *pset, bool constant)
Definition settings.c:3343
setting_number
int setting_number(const struct setting *pset)
Definition settings.c:3317
setting_by_number
struct setting * setting_by_number(int id)
Definition settings.c:3294
setting_int_set
bool setting_int_set(struct setting *pset, int val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3736
setting_is_visible
bool setting_is_visible(const struct setting *pset, struct connection *caller)
Definition settings.c:3499
setting_locked
bool setting_locked(const struct setting *pset)
Definition settings.c:4633
setting_non_default
bool setting_non_default(const struct setting *pset)
Definition settings.c:4607
setting_type
enum sset_type setting_type(const struct setting *pset)
Definition settings.c:3355
setting_admin_lock_set
void setting_admin_lock_set(struct setting *pset)
Definition settings.c:4661
setting_str_set
bool setting_str_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3807
setting_int_max
int setting_int_max(const struct setting *pset)
Definition settings.c:3726
setting_bitwise_set
bool setting_bitwise_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:4216
settings_number
int settings_number(void)
Definition settings.c:5259
setting_str_validate
bool setting_str_validate(const struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3827
setting_enum_val
const char * setting_enum_val(const struct setting *pset, int val, bool pretty)
Definition settings.c:3886
level
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:190
setting_changed
void setting_changed(struct setting *pset)
Definition settings.c:5597
setting_get_setdef
enum setting_default_level setting_get_setdef(const struct setting *pset)
Definition settings.c:5605
setting_enum_set
bool setting_enum_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:4015
setting_short_help
const char * setting_short_help(const struct setting *pset)
Definition settings.c:3334
setting_bitwise_bit
const char * setting_bitwise_bit(const struct setting *pset, int bit, bool pretty)
Definition settings.c:4081
setting_int_min
int setting_int_min(const struct setting *pset)
Definition settings.c:3717
setting_bitwise_validate
bool setting_bitwise_validate(const struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:4237
setting_bool_validate
bool setting_bool_validate(const struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3681
setting_is_changeable
bool setting_is_changeable(const struct setting *pset, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3453
settings_reset
void settings_reset(void)
Definition settings.c:5225
setting_name
const char * setting_name(const struct setting *pset)
Definition settings.c:3326
settings_game_reset
bool settings_game_reset(void)
Definition settings.c:5188
settings_list_update
void settings_list_update(void)
Definition settings.c:5526
setting_bool_set
bool setting_bool_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3650
send_server_setting
void send_server_setting(struct conn_list *dest, const struct setting *pset)
Definition settings.c:5268
send_server_settings
void send_server_settings(struct conn_list *dest)
Definition settings.c:5387
settings.h
settings_iterate
#define settings_iterate(_level, _pset)
Definition settings.h:188
settings_iterate_end
#define settings_iterate_end
Definition settings.h:194
fileinfoname
const char * fileinfoname(const struct strvec *dirs, const char *filename)
Definition shared.c:1094
remove_trailing_spaces
void remove_trailing_spaces(char *s)
Definition shared.c:422
str_to_int
bool str_to_int(const char *str, int *pint)
Definition shared.c:515
m_pre_description
const char * m_pre_description(enum m_pre_result result)
Definition shared.c:1561
fileinfolist
struct strvec * fileinfolist(const struct strvec *dirs, const char *suffix)
Definition shared.c:1020
skip_leading_spaces
char * skip_leading_spaces(char *s)
Definition shared.c:392
match_prefix_full
enum m_pre_result match_prefix_full(m_pre_accessor_fn_t accessor_fn, size_t n_names, size_t max_len_name, m_pre_strncmp_fn_t cmp_fn, m_strlen_fn_t len_fn, const char *prefix, int *ind_result, int *matches, int max_matches, int *pnum_matches)
Definition shared.c:1603
get_scenario_dirs
const struct strvec * get_scenario_dirs(void)
Definition shared.c:971
interpret_tilde
void interpret_tilde(char *buf, size_t buf_size, const char *filename)
Definition shared.c:1710
get_save_dirs
const struct strvec * get_save_dirs(void)
Definition shared.c:934
remove_leading_spaces
void remove_leading_spaces(char *s)
Definition shared.c:405
match_prefix
enum m_pre_result match_prefix(m_pre_accessor_fn_t accessor_fn, size_t n_names, size_t max_len_name, m_pre_strncmp_fn_t cmp_fn, m_strlen_fn_t len_fn, const char *prefix, int *ind_result)
Definition shared.c:1580
is_safe_filename
bool is_safe_filename(const char *name)
Definition shared.c:256
remove_leading_trailing_spaces
void remove_leading_trailing_spaces(char *s)
Definition shared.c:444
get_data_dirs
const struct strvec * get_data_dirs(void)
Definition shared.c:886
fileinfolist_infix
struct fileinfo_list * fileinfolist_infix(const struct strvec *dirs, const char *infix, bool nodups)
Definition shared.c:1204
CLIP
#define CLIP(lower, current, upper)
Definition shared.h:57
FC_MEMBER_SIZEOF
#define FC_MEMBER_SIZEOF(type, member)
Definition shared.h:90
ARRAY_SIZE
#define ARRAY_SIZE(x)
Definition shared.h:85
MIN
#define MIN(x, y)
Definition shared.h:55
fileinfo_list_iterate
#define fileinfo_list_iterate(list, pnode)
Definition shared.h:182
MAX_LEN_PATH
#define MAX_LEN_PATH
Definition shared.h:32
m_pre_result
m_pre_result
Definition shared.h:213
M_PRE_EXACT
@ M_PRE_EXACT
Definition shared.h:214
M_PRE_ONLY
@ M_PRE_ONLY
Definition shared.h:215
M_PRE_LAST
@ M_PRE_LAST
Definition shared.h:220
M_PRE_LONG
@ M_PRE_LONG
Definition shared.h:218
M_PRE_AMBIGUOUS
@ M_PRE_AMBIGUOUS
Definition shared.h:216
M_PRE_EMPTY
@ M_PRE_EMPTY
Definition shared.h:217
M_PRE_FAIL
@ M_PRE_FAIL
Definition shared.h:219
fileinfo_list_iterate_end
#define fileinfo_list_iterate_end
Definition shared.h:184
m_pre_accessor_fn_t
const char *(* m_pre_accessor_fn_t)(int)
Definition shared.h:226
specenum_gen.h
spechash.h
y
struct sprite int int y
Definition sprite_g.h:31
x
struct sprite int x
Definition sprite_g.h:31
srv_log.h
CITY_LOG
#define CITY_LOG(loglevel, pcity, msg,...)
Definition srv_log.h:83
UNIT_LOG
#define UNIT_LOG(loglevel, punit, msg,...)
Definition srv_log.h:98
TIMING_RESULTS
#define TIMING_RESULTS()
Definition srv_log.h:126
server_game_init
void server_game_init(bool keep_ruleset_value)
Definition srv_main.c:3496
player_nation_defaults
void player_nation_defaults(struct player *pplayer, struct nation_type *pnation, bool set_name)
Definition srv_main.c:2620
force_end_of_sniff
bool force_end_of_sniff
Definition srv_main.c:193
start_game
void start_game(void)
Definition srv_main.c:1878
aifill
const char * aifill(int amount)
Definition srv_main.c:2505
set_server_state
void set_server_state(enum server_states newstate)
Definition srv_main.c:346
game_was_started
bool game_was_started(void)
Definition srv_main.c:354
srvarg
struct server_arguments srvarg
Definition srv_main.c:181
check_for_full_turn_done
void check_for_full_turn_done(void)
Definition srv_main.c:2255
server_quit
void fc__noreturn server_quit(void)
Definition srv_main.c:1915
server_state
enum server_states server_state(void)
Definition srv_main.c:338
server_game_free
void server_game_free(void)
Definition srv_main.c:3520
srv_main.h
srvdefs.h
TOKEN_DELIMITERS
#define TOKEN_DELIMITERS
Definition srvdefs.h:20
write_command
static bool write_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:1340
reset_accessor
static const char * reset_accessor(int i)
Definition stdinhand.c:4832
set_cmdlevel
static bool set_cmdlevel(struct connection *caller, struct connection *ptarget, enum cmdlevel level)
Definition stdinhand.c:1379
validate_setting_arg
static struct setting * validate_setting_arg(enum command_id cmd, struct connection *caller, char *arg)
Definition stdinhand.c:2929
LOOKUP_OPTION_AMBIGUOUS
#define LOOKUP_OPTION_AMBIGUOUS
Definition stdinhand.c:1730
mapimg_accessor
static const char * mapimg_accessor(int i)
Definition stdinhand.c:5681
cmd_reply
void cmd_reply(enum command_id cmd, struct connection *caller, enum rfc_status rfc_status, const char *format,...)
Definition stdinhand.c:419
set_command
static bool set_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2963
cmd_of_level
static enum command_id cmd_of_level(enum ai_level level)
Definition stdinhand.c:1982
show_delegations
static void show_delegations(struct connection *caller)
Definition stdinhand.c:6689
setting_status
static char setting_status(struct connection *caller, const struct setting *pset)
Definition stdinhand.c:306
show_scenarios
static void show_scenarios(struct connection *caller)
Definition stdinhand.c:6915
delegate_command
static bool delegate_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:5191
ignore_command
static bool ignore_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4076
show_help_command
static void show_help_command(struct connection *caller, enum command_id help_cmd, enum command_id id)
Definition stdinhand.c:6443
set_running_game_access_level
void set_running_game_access_level(void)
Definition stdinhand.c:1634
notify_if_first_access_level_is_available
void notify_if_first_access_level_is_available(void)
Definition stdinhand.c:1450
lua_accessor
static const char * lua_accessor(int i)
Definition stdinhand.c:4992
fcdb_accessor
static const char * fcdb_accessor(int i)
Definition stdinhand.c:5992
show_help_command_list
static void show_help_command_list(struct connection *caller, enum command_id help_cmd)
Definition stdinhand.c:6489
stdinhand_turn
void stdinhand_turn(void)
Definition stdinhand.c:255
show_connections
static void show_connections(struct connection *caller)
Definition stdinhand.c:6663
explain_option
static bool explain_option(struct connection *caller, char *str, bool check)
Definition stdinhand.c:1896
kick_table_by_user
static struct kick_hash * kick_table_by_user
Definition stdinhand.c:117
conn_is_kicked
bool conn_is_kicked(struct connection *pconn, int *time_remaining)
Definition stdinhand.c:6281
create_command_newcomer
enum rfc_status create_command_newcomer(const char *name, const char *ai, bool check, struct nation_type *pnation, struct player **newplayer, char *buf, size_t buflen)
Definition stdinhand.c:811
show_colors
static void show_colors(struct connection *caller)
Definition stdinhand.c:7029
set_ai_level
static bool set_ai_level(struct connection *caller, const char *name, enum ai_level level, bool check)
Definition stdinhand.c:2029
kick_table_by_addr
static struct kick_hash * kick_table_by_addr
Definition stdinhand.c:116
show_help_option_list
static void show_help_option_list(struct connection *caller, enum command_id help_cmd)
Definition stdinhand.c:1860
lock_command
static bool lock_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:3143
stdinhand_init
void stdinhand_init(void)
Definition stdinhand.c:242
take_command
static bool take_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:3493
wall
static bool wall(char *str, bool check)
Definition stdinhand.c:1929
default_access_level
static enum cmdlevel default_access_level
Definition stdinhand.c:98
show_ruleset_info
static void show_ruleset_info(struct connection *caller, enum command_id cmd, bool check, int read_recursion)
Definition stdinhand.c:2126
show_players
void show_players(struct connection *caller)
Definition stdinhand.c:6753
cmd_reply_matches
static void cmd_reply_matches(enum command_id cmd, struct connection *caller, m_pre_accessor_fn_t accessor_fn, int *matches, int num_matches)
Definition stdinhand.c:6527
LOOKUP_OPTION_NO_RESULT
#define LOOKUP_OPTION_NO_RESULT
Definition stdinhand.c:1729
list_accessor
static const char * list_accessor(int i)
Definition stdinhand.c:7076
lookup_option
static int lookup_option(const char *name)
Definition stdinhand.c:1741
reset_command
static bool reset_command(struct connection *caller, char *arg, bool check, int read_recursion)
Definition stdinhand.c:4842
show_teams
static void show_teams(struct connection *caller)
Definition stdinhand.c:6978
handle_stdin_input_real
static bool handle_stdin_input_real(struct connection *caller, char *str, bool check, int read_recursion)
Definition stdinhand.c:4453
create_command_pregame
enum rfc_status create_command_pregame(const char *name, const char *ai, bool check, struct player **newplayer, char *buf, size_t buflen)
Definition stdinhand.c:995
metaconnection_command
static bool metaconnection_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:528
show_serverid
static bool show_serverid(struct connection *caller, char *arg)
Definition stdinhand.c:661
show_nationsets
static void show_nationsets(struct connection *caller)
Definition stdinhand.c:6941
helparg_accessor
static const char * helparg_accessor(int i)
Definition stdinhand.c:6583
metamessage_command
static bool metamessage_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:609
away_command
static bool away_command(struct connection *caller, bool check)
Definition stdinhand.c:2085
access_level_for_next_connection
enum cmdlevel access_level_for_next_connection(void)
Definition stdinhand.c:1436
playercolor_command
static bool playercolor_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4200
handle_stdin_input_free
bool handle_stdin_input_free(struct connection *caller, char *str)
Definition stdinhand.c:4434
set_ai_level_direct
void set_ai_level_direct(struct player *pplayer, enum ai_level level)
Definition stdinhand.c:2004
player_name_check
static bool player_name_check(const char *name, char *buf, size_t buflen)
Definition stdinhand.c:192
default_command
static bool default_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:4949
create_command
static bool create_command(struct connection *caller, const char *str, bool check)
Definition stdinhand.c:753
vcmd_reply_prefix
static void vcmd_reply_prefix(enum command_id cmd, struct connection *caller, enum rfc_status rfc_status, const char *prefix, const char *format, va_list ap)
Definition stdinhand.c:379
delegate_accessor
static const char * delegate_accessor(int i)
Definition stdinhand.c:5182
show_rulesets
static void show_rulesets(struct connection *caller)
Definition stdinhand.c:6892
surrender_command
static bool surrender_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4784
end_command
static bool end_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4759
delegate_player_str
static const char * delegate_player_str(struct player *pplayer, bool observer)
Definition stdinhand.c:5642
cmd_reply_prefix
static void cmd_reply_prefix(enum command_id cmd, struct connection *caller, enum rfc_status rfc_status, const char *prefix, const char *format,...) fc__attribute((__format__(__printf__
LOOKUP_OPTION_RULESETDIR
#define LOOKUP_OPTION_RULESETDIR
Definition stdinhand.c:1732
timeout_command
static bool timeout_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:1671
cmd_reply_no_such_player
static void cmd_reply_no_such_player(enum command_id cmd, struct connection *caller, const char *name, enum m_pre_result match_result)
Definition stdinhand.c:432
metaserver_command
static bool metaserver_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:643
handle_stdin_input
bool handle_stdin_input(struct connection *caller, char *str)
Definition stdinhand.c:4426
cut_client_connection
static bool cut_client_connection(struct connection *caller, char *name, bool check)
Definition stdinhand.c:6238
open_metaserver_connection
static void open_metaserver_connection(struct connection *caller, bool persistent)
Definition stdinhand.c:501
HELP_ARG_NUM
#define HELP_ARG_NUM
Definition stdinhand.c:6578
time_duplicate
static time_t * time_duplicate(const time_t *t)
Definition stdinhand.c:6270
show_mapimg
static void show_mapimg(struct connection *caller, enum command_id cmd)
Definition stdinhand.c:7008
may_use_nothing
static bool may_use_nothing(struct connection *caller)
Definition stdinhand.c:294
show_votes
static void show_votes(struct connection *caller)
Definition stdinhand.c:2472
vote_args
static const char *const vote_args[]
Definition stdinhand.c:2507
show_settings
static bool show_settings(struct connection *caller, enum command_id called_as, char *str, bool check)
Definition stdinhand.c:2161
read_init_script
bool read_init_script(struct connection *caller, const char *script_filename, bool from_cmdline, bool check)
Definition stdinhand.c:1168
unlock_command
static bool unlock_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:3171
a_connection_exists
static bool a_connection_exists(void)
Definition stdinhand.c:1414
stdinhand_free
void stdinhand_free(void)
Definition stdinhand.c:263
cmdlevel_command
static bool cmdlevel_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:1464
is_first_access_level_taken
static bool is_first_access_level_taken(void)
Definition stdinhand.c:1422
LOOKUP_OPTION_LEVEL_NAME
#define LOOKUP_OPTION_LEVEL_NAME
Definition stdinhand.c:1731
firstlevel_command
static bool firstlevel_command(struct connection *caller, bool check)
Definition stdinhand.c:1607
start_cmd_reply
static void start_cmd_reply(struct connection *caller, bool notify, char *msg)
Definition stdinhand.c:6104
connectmsg_command
static bool connectmsg_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:1941
horiz_line
static const char horiz_line[]
Definition stdinhand.c:176
cmd_reply_no_such_conn
static void cmd_reply_no_such_conn(enum command_id cmd, struct connection *caller, const char *name, enum m_pre_result match_result)
Definition stdinhand.c:467
cmd_reply_line
static void cmd_reply_line(enum command_id cmd, struct connection *caller, enum rfc_status rfc_status, const char *prefix, const char *line)
Definition stdinhand.c:332
show_help_intro
static void show_help_intro(struct connection *caller, enum command_id help_cmd)
Definition stdinhand.c:6410
cancelvote_command
static bool cancelvote_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:2626
set_rulesetdir
bool set_rulesetdir(struct connection *caller, const char *str, bool check, int read_recursion)
Definition stdinhand.c:3975
load_command
bool load_command(struct connection *caller, const char *filename, bool check, bool cmdline_load)
Definition stdinhand.c:3788
read_init_script_real
static bool read_init_script_real(struct connection *caller, const char *script_filename, bool from_cmdline, bool check, int read_recursion)
Definition stdinhand.c:1186
show_settings_one
static void show_settings_one(struct connection *caller, enum command_id cmd, struct setting *pset)
Definition stdinhand.c:2333
toggle_ai_command
static bool toggle_ai_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:730
playernation_command
static bool playernation_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4285
team_command
static bool team_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2395
quit_game
static bool quit_game(struct connection *caller, bool check)
Definition stdinhand.c:4412
vote_command
static bool vote_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2521
cmd_reply_show
#define cmd_reply_show(string)
start_command
bool start_command(struct connection *caller, bool check, bool notify)
Definition stdinhand.c:6115
optname_accessor
static const char * optname_accessor(int i)
Definition stdinhand.c:1647
show_help
static bool show_help(struct connection *caller, char *arg)
Definition stdinhand.c:6601
OPTION_NAME_SPACE
#define OPTION_NAME_SPACE
Definition stdinhand.c:96
get_init_script_choices
struct strvec * get_init_script_choices(void)
Definition stdinhand.c:1269
remove_player_command
static bool remove_player_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:1122
ruleset_cache_listcmd_cb
static void ruleset_cache_listcmd_cb(const char *mp_name, const char *filename, void *data_in)
Definition stdinhand.c:6853
debug_command
static bool debug_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2721
command_named
static enum command_id command_named(const char *token, bool accept_ambiguity)
Definition stdinhand.c:222
fcdb_command
static bool fcdb_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:6001
mapimg_command
static bool mapimg_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:5690
unignore_command
static bool unignore_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4111
observe_command
static bool observe_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:3345
show_list
static bool show_list(struct connection *caller, char *arg)
Definition stdinhand.c:7085
scensave_command
static bool scensave_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:689
lookup_option_level
static enum sset_level lookup_option_level(const char *name)
Definition stdinhand.c:1715
may_use
static bool may_use(struct connection *caller, enum command_id cmd)
Definition stdinhand.c:282
kick_command
static bool kick_command(struct connection *caller, char *name, bool check)
Definition stdinhand.c:6329
vote_arg_accessor
static const char * vote_arg_accessor(int i)
Definition stdinhand.c:2513
is_restricted
static bool is_restricted(struct connection *caller)
Definition stdinhand.c:183
script_extension
const char * script_extension
Definition stdinhand.c:114
show_command
static bool show_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2151
lua_command
static bool lua_command(struct connection *caller, char *arg, bool check, int read_recursion)
Definition stdinhand.c:5001
write_init_script
static bool write_init_script(char *script_filename)
Definition stdinhand.c:1279
first_access_level
static enum cmdlevel first_access_level
Definition stdinhand.c:99
detach_command
static bool detach_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:3682
aicmd_command
static bool aicmd_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:5918
close_metaserver_connection
static void close_metaserver_connection(struct connection *caller)
Definition stdinhand.c:515
save_command
static bool save_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:672
set_ai_level_named
static bool set_ai_level_named(struct connection *caller, const char *name, const char *level_name, bool check)
Definition stdinhand.c:2018
metapatches_command
static bool metapatches_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:584
show_ignore
static bool show_ignore(struct connection *caller)
Definition stdinhand.c:6723
is_allowed_to_take
static bool is_allowed_to_take(struct connection *requester, struct connection *taker, struct player *pplayer, bool will_obs, char *msg, size_t msg_len)
Definition stdinhand.c:3203
toggle_ai_player_direct
void toggle_ai_player_direct(struct connection *caller, struct player *pplayer)
Definition stdinhand.c:705
show_help_option
static void show_help_option(struct connection *caller, enum command_id help_cmd, int id)
Definition stdinhand.c:1770
read_command
static bool read_command(struct connection *caller, char *arg, bool check, int read_recursion)
Definition stdinhand.c:1159
stdinhand.h
ai_type
Definition ai.h:50
ai_type::funcs
struct ai_type::@14 funcs
ai_type::gained_control
void(* gained_control)(struct player *pplayer)
Definition ai.h:108
ai_type::name
char name[MAX_LEN_NAME]
Definition ai.h:51
ai_type::player_console
void(* player_console)(struct player *pplayer, const char *cmd)
Definition ai.h:105
astring
Definition astring.h:36
city
Definition city.h:320
city::server
struct city::@17::@19 server
city::debug
bool debug
Definition city.h:450
civ_game::kick_time
int kick_time
Definition game.h:153
civ_game::start_units
char start_units[MAX_LEN_STARTUNIT]
Definition game.h:189
civ_game::debug
bool debug[DEBUG_LAST]
Definition game.h:202
civ_game::connectmsg
char connectmsg[MAX_LEN_MSG]
Definition game.h:219
civ_game::ruleset_summary
char * ruleset_summary
Definition game.h:84
civ_game::est_connections
struct conn_list * est_connections
Definition game.h:97
civ_game::info
struct packet_game_info info
Definition game.h:89
civ_game::min_players
int min_players
Definition game.h:166
civ_game::timeoutcounter
int timeoutcounter
Definition game.h:207
civ_game::rulesetdir
char rulesetdir[MAX_LEN_NAME]
Definition game.h:239
civ_game::scenario
struct packet_scenario_info scenario
Definition game.h:87
civ_game::timeoutint
int timeoutint
Definition game.h:203
civ_game::all_connections
struct conn_list * all_connections
Definition game.h:96
civ_game::save_name
char save_name[MAX_LEN_NAME]
Definition game.h:220
civ_game::server
struct civ_game::@31::@35 server
civ_game::timeoutincmult
int timeoutincmult
Definition game.h:205
civ_game::timeoutinc
int timeoutinc
Definition game.h:204
civ_game::allow_take
char allow_take[MAX_LEN_ALLOW_TAKE]
Definition game.h:241
civ_game::start_city
bool start_city
Definition game.h:190
civ_game::max_players
int max_players
Definition game.h:156
civ_game::timeoutintinc
int timeoutintinc
Definition game.h:206
color
Definition colors.h:21
command
Definition commands.c:37
conn_pattern
Definition connection.c:787
connection
Definition connection.h:136
connection::playing
struct player * playing
Definition connection.h:151
connection::access_level
enum cmdlevel access_level
Definition connection.h:177
connection::self
struct conn_list * self
Definition connection.h:163
connection::observer
bool observer
Definition connection.h:147
connection::username
char username[MAX_LEN_NAME]
Definition connection.h:164
connection::server
struct connection::@58::@64 server
connection::status
enum auth_status status
Definition connection.h:217
connection::ipaddr
char ipaddr[MAX_LEN_ADDR]
Definition connection.h:221
connection::delegation
struct connection::@58::@64::@65 delegation
connection::id
int id
Definition connection.h:137
connection::ignore_list
struct conn_pattern_list * ignore_list
Definition connection.h:230
connection::used
bool used
Definition connection.h:139
data_in
Definition dataio_raw.h:30
ft_color
Definition featured_text.h:141
mapdef
Definition mapimg.c:320
mrc_listcmd_data
Definition stdinhand.c:6846
mrc_listcmd_data::caller
struct connection * caller
Definition stdinhand.c:6847
nation_style
Definition style.h:22
nation_type
Definition nation.h:98
nation_type::player
struct player * player
Definition nation.h:118
packet_achievement_info
Definition packets_gen.h:290
packet_achievement_info::id
int id
Definition packets_gen.h:291
packet_chat_msg
Definition packets_gen.h:296
packet_chat_msg::message
char message[MAX_LEN_MSG]
Definition packets_gen.h:297
packet_game_info::aifill
int aifill
Definition packets_gen.h:120
packet_game_info::is_new_game
bool is_new_game
Definition packets_gen.h:190
packet_game_info::skill_level
enum ai_level skill_level
Definition packets_gen.h:226
packet_scenario_info::is_scenario
bool is_scenario
Definition packets_gen.h:1591
packet_scenario_info::ruleset_locked
bool ruleset_locked
Definition packets_gen.h:1601
packet_scenario_info::name
char name[256]
Definition packets_gen.h:1592
player_ai::skill_level
enum ai_level skill_level
Definition player.h:116
player_slot
Definition player.c:46
player
Definition player.h:249
player::random_name
bool random_name
Definition player.h:295
player::ai_common
struct player_ai ai_common
Definition player.h:288
player::status
bv_pstatus status
Definition player.h:322
player::is_male
bool is_male
Definition player.h:257
player::target_government
struct government * target_government
Definition player.h:259
player::username
char username[MAX_LEN_NAME]
Definition player.h:252
player::is_connected
bool is_connected
Definition player.h:296
player::government
struct government * government
Definition player.h:258
player::was_created
bool was_created
Definition player.h:294
player::ai
const struct ai_type * ai
Definition player.h:289
player::units
struct unit_list * units
Definition player.h:282
player::connections
struct conn_list * connections
Definition player.h:298
player::is_alive
bool is_alive
Definition player.h:268
player::style
struct nation_style * style
Definition player.h:279
player::server
struct player::@70::@72 server
player::debug
bv_debug debug
Definition player.h:332
player::rgb
struct rgbcolor * rgb
Definition player.h:312
player::unassigned_user
bool unassigned_user
Definition player.h:253
research
Definition research.h:39
rgbcolor
Definition rgbcolor.h:33
section_file
Definition section_file.h:36
server_arguments::metaserver_addr
char metaserver_addr[256]
Definition srv_main.h:29
server_arguments::load_filename
char load_filename[512]
Definition srv_main.h:44
server_arguments::fcdb_enabled
bool fcdb_enabled
Definition srv_main.h:55
server_arguments::saves_pathname
char * saves_pathname
Definition srv_main.h:46
server_arguments::ruleset
char * ruleset
Definition srv_main.h:48
server_arguments::script_filename
char * script_filename
Definition srv_main.h:45
server_arguments::serverid
char serverid[256]
Definition srv_main.h:49
server
Definition servers.h:29
setting
Definition settings.c:92
setting::value
char *const value
Definition settings.c:147
startpos
Definition map.c:40
strvec
Definition string_vector.c:29
team_slot
Definition team.c:31
tile
Definition tile.h:50
tile::units
struct unit_list * units
Definition tile.h:58
timer
Definition timing.c:81
unit
Definition unit.h:140
unit::debug
bool debug
Definition unit.h:237
unit::server
struct unit::@81::@84 server
vote
Definition voting.h:46
vote::vote_no
int vote_no
Definition voting.h:52
world::map
struct civ_map map
Definition world_object.h:38
style_by_rule_name
struct nation_style * style_by_rule_name(const char *name)
Definition style.c:117
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
cat_snprintf
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:986
fc_vsnprintf
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:886
fc_fopen
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:505
fc_break_lines
int fc_break_lines(char *str, size_t desired_len)
Definition support.c:1135
fc_stat
int fc_stat(const char *filename, struct stat *buf)
Definition support.c:574
is_reg_file_for_access
bool is_reg_file_for_access(const char *name, bool write_access)
Definition support.c:1120
fc_isalnum
bool fc_isalnum(char c)
Definition support.c:1196
fc_strncasecmp
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:235
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
fc__attribute
#define fc__attribute(x)
Definition support.h:99
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
sz_strlcat
#define sz_strlcat(dest, src)
Definition support.h:190
fc_strncmp
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:154
fc__fallthrough
#define fc__fallthrough
Definition support.h:119
team_index
int team_index(const struct team *pteam)
Definition team.c:383
team_name_translation
const char * team_name_translation(const struct team *pteam)
Definition team.c:420
team_slot_by_number
struct team_slot * team_slot_by_number(int team_id)
Definition team.c:175
team_slot_name_translation
const char * team_slot_name_translation(const struct team_slot *tslot)
Definition team.c:253
team_add_player
bool team_add_player(struct player *pplayer, struct team *pteam)
Definition team.c:467
team_new
struct team * team_new(struct team_slot *tslot)
Definition team.c:317
team_slot_by_rule_name
struct team_slot * team_slot_by_rule_name(const char *team_name)
Definition team.c:189
team_members
const struct player_list * team_members(const struct team *pteam)
Definition team.c:456
team_remove_player
void team_remove_player(struct player *pplayer)
Definition team.c:502
teams_iterate_end
#define teams_iterate_end
Definition team.h:87
teams_iterate
#define teams_iterate(_pteam)
Definition team.h:82
init_tech
void init_tech(struct research *research, bool update)
Definition techtools.c:1093
send_research_info
void send_research_info(const struct research *presearch, const struct conn_list *dest)
Definition techtools.c:293
give_initial_techs
void give_initial_techs(struct research *presearch, int num_random_techs)
Definition techtools.c:1187
techtools.h
tile_city
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
timer_destroy
void timer_destroy(struct timer *t)
Definition timing.c:208
timer_start
void timer_start(struct timer *t)
Definition timing.c:264
timer_new
struct timer * timer_new(enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:160
timer_read_seconds
double timer_read_seconds(struct timer *t)
Definition timing.c:384
timing.h
TIMER_ACTIVE
@ TIMER_ACTIVE
Definition timing.h:46
TIMER_CPU
@ TIMER_CPU
Definition timing.h:41
TIMER_USER
@ TIMER_USER
Definition timing.h:42
unit_owner
#define unit_owner(_pu)
Definition unit.h:396
unitlist.h
unit_list_iterate
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
unit_list_iterate_end
#define unit_list_iterate_end
Definition unitlist.h:33
unit_name_translation
const char * unit_name_translation(const struct unit *punit)
Definition unittype.c:1569
version.h
describe_vote
int describe_vote(struct vote *pvote, char *buf, int buflen)
Definition voting.c:748
conn_can_vote
bool conn_can_vote(const struct connection *pconn, const struct vote *pvote)
Definition voting.c:248
vote_new
struct vote * vote_new(struct connection *caller, const char *allargs, int command_id)
Definition voting.c:338
vote_is_team_only
bool vote_is_team_only(const struct vote *pvote)
Definition voting.c:235
get_vote_by_no
struct vote * get_vote_by_no(int vote_no)
Definition voting.c:301
vote_number_sequence
int vote_number_sequence
Definition voting.c:42
vote_would_pass_immediately
bool vote_would_pass_immediately(const struct connection *caller, int command_id)
Definition voting.c:391
clear_all_votes
void clear_all_votes(void)
Definition voting.c:219
get_vote_by_caller
struct vote * get_vote_by_caller(const struct connection *caller)
Definition voting.c:319
connection_vote
void connection_vote(struct connection *pconn, struct vote *pvote, enum vote_type type)
Definition voting.c:663
vote_list
struct vote_list * vote_list
Definition voting.c:41
vote_get_caller
const struct connection * vote_get_caller(const struct vote *pvote)
Definition voting.c:891
count_voters
int count_voters(const struct vote *pvote)
Definition voting.c:48
remove_vote
void remove_vote(struct vote *pvote)
Definition voting.c:205
conn_can_see_vote
bool conn_can_see_vote(const struct connection *pconn, const struct vote *pvote)
Definition voting.c:272
voting.h
VOTE_ABSTAIN
@ VOTE_ABSTAIN
Definition voting.h:27
VOTE_YES
@ VOTE_YES
Definition voting.h:27
VOTE_NUM
@ VOTE_NUM
Definition voting.h:27
VOTE_NO
@ VOTE_NO
Definition voting.h:27
vote_list_iterate_end
#define vote_list_iterate_end
Definition voting.h:65
VCF_NODISSENT
@ VCF_NODISSENT
Definition voting.h:20
vote_list_iterate
#define vote_list_iterate(alist, pvote)
Definition voting.h:63