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