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