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