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