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