Freeciv-3.1
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 "packets.h"
53#include "player.h"
54#include "research.h"
55#include "rgbcolor.h"
56#include "srvdefs.h"
57#include "unitlist.h"
58#include "version.h"
59
60/* server */
61#include "aiiface.h"
62#include "citytools.h"
63#include "connecthand.h"
64#include "diplhand.h"
65#include "gamehand.h"
66#include "mapgen.h"
67#include "maphand.h"
68#include "meta.h"
69#include "notify.h"
70#include "plrhand.h"
71#include "report.h"
72#include "ruleset.h"
73#include "sanitycheck.h"
74#include "score.h"
75#include "sernet.h"
76#include "settings.h"
77#include "srv_log.h"
78#include "srv_main.h"
79#include "techtools.h"
80#include "voting.h"
81
82/* server/advisors */
83#include "advdata.h"
84
85/* server/savegame */
86#include "savemain.h"
87
88/* server/scripting */
89#include "script_server.h"
90#include "script_fcdb.h"
91
92/* ai */
93#include "difficulty.h"
94#include "handicaps.h"
95
96#include "stdinhand.h"
97
98#define OPTION_NAME_SPACE 25
99
100static enum cmdlevel default_access_level = ALLOW_BASIC;
101static enum cmdlevel first_access_level = ALLOW_BASIC;
102
103static time_t *time_duplicate(const time_t *t);
104
105/* 'struct kick_hash' and related functions. */
106#define SPECHASH_TAG kick
107#define SPECHASH_ASTR_KEY_TYPE
108#define SPECHASH_IDATA_TYPE time_t *
109#define SPECHASH_UDATA_TYPE time_t
110#define SPECHASH_IDATA_COPY time_duplicate
111#define SPECHASH_IDATA_FREE (kick_hash_data_free_fn_t) free
112#define SPECHASH_UDATA_TO_IDATA(t) (&(t))
113#define SPECHASH_IDATA_TO_UDATA(p) (NULL != p ? *p : 0)
114#include "spechash.h"
115
116const char *script_extension = ".serv";
117
118static struct kick_hash *kick_table_by_addr = NULL;
119static struct kick_hash *kick_table_by_user = NULL;
120
121
122static bool cut_client_connection(struct connection *caller, char *name,
123 bool check);
124static bool show_help(struct connection *caller, char *arg);
125static bool show_list(struct connection *caller, char *arg);
126static void show_colors(struct connection *caller);
127static bool set_ai_level_named(struct connection *caller, const char *name,
128 const char *level_name, bool check);
129static bool set_ai_level(struct connection *caller, const char *name,
130 enum ai_level level, bool check);
131static bool away_command(struct connection *caller, bool check);
132static bool set_rulesetdir(struct connection *caller, char *str, bool check,
133 int read_recursion);
134static bool show_command(struct connection *caller, char *str, bool check);
135static bool show_settings(struct connection *caller,
136 enum command_id called_as,
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);
144
145static bool create_command(struct connection *caller, const char *str,
146 bool check);
147static bool end_command(struct connection *caller, char *str, bool check);
148static bool surrender_command(struct connection *caller, char *str, bool check);
149static bool handle_stdin_input_real(struct connection *caller, char *str,
150 bool check, int read_recursion);
151static bool read_init_script_real(struct connection *caller,
152 char *script_filename, bool from_cmdline,
153 bool check, int read_recursion);
154static bool reset_command(struct connection *caller, char *arg, bool check,
155 int read_recursion);
156static bool default_command(struct connection *caller, char *arg, bool check);
157static bool lua_command(struct connection *caller, char *arg, bool check,
158 int read_recursion);
159static bool kick_command(struct connection *caller, char *name, bool check);
160static bool delegate_command(struct connection *caller, char *arg,
161 bool check);
162static const char *delegate_player_str(struct player *pplayer, bool observer);
163static bool aicmd_command(struct connection *caller, char *arg, bool check);
164static bool fcdb_command(struct connection *caller, char *arg, bool check);
165static const char *fcdb_accessor(int i);
166static char setting_status(struct connection *caller,
167 const struct setting *pset);
168static bool player_name_check(const char *name, char *buf, size_t buflen);
169static bool playercolor_command(struct connection *caller,
170 char *str, bool check);
171static bool playernation_command(struct connection *caller,
172 char *str, bool check);
173static bool mapimg_command(struct connection *caller, char *arg, bool check);
174static const char *mapimg_accessor(int i);
175
176static void show_delegations(struct connection *caller);
177
178static const char horiz_line[] =
179"------------------------------------------------------------------------------";
180
181/**********************************************************************/
185static bool is_restricted(struct connection *caller)
186{
187 return (caller && caller->access_level != ALLOW_HACK);
188}
189
190/**********************************************************************/
194static bool player_name_check(const char *name, char *buf, size_t buflen)
195{
196 size_t len = strlen(name);
197
198 if (len == 0) {
199 fc_snprintf(buf, buflen, _("Can't use an empty name."));
200 return FALSE;
201 } else if (len > MAX_LEN_NAME-1) {
202 fc_snprintf(buf, buflen, _("That name exceeds the maximum of %d chars."),
203 MAX_LEN_NAME-1);
204 return FALSE;
205 } else if (fc_strcasecmp(name, ANON_PLAYER_NAME) == 0
206 || fc_strcasecmp(name, "Observer") == 0) {
207 fc_snprintf(buf, buflen, _("That name is not allowed."));
208 /* "Observer" used to be illegal and we keep it that way for now. */
209 /* FIXME: This disallows anonymous player name as it appears in English,
210 * but not one in any other language that the user may see. */
211 return FALSE;
212 }
213
214 return TRUE;
215}
216
217/**********************************************************************/
224static enum command_id command_named(const char *token, bool accept_ambiguity)
225{
226 enum m_pre_result result;
227 int ind;
228
230 fc_strncasecmp, NULL, token, &ind);
231
232 if (result < M_PRE_AMBIGUOUS) {
233 return ind;
234 } else if (result == M_PRE_AMBIGUOUS) {
235 return accept_ambiguity ? ind : CMD_AMBIGUOUS;
236 } else {
237 return CMD_UNRECOGNIZED;
238 }
239}
240
241/**********************************************************************/
245{
247 kick_table_by_addr = kick_hash_new();
248
250 kick_table_by_user = kick_hash_new();
251}
252
253/**********************************************************************/
258{
259 /* Nothing at the moment. */
260}
261
262/**********************************************************************/
266{
268 if (NULL != kick_table_by_addr) {
269 kick_hash_destroy(kick_table_by_addr);
270 kick_table_by_addr = NULL;
271 }
272
274 if (NULL != kick_table_by_user) {
275 kick_hash_destroy(kick_table_by_user);
276 kick_table_by_user = NULL;
277 }
278}
279
280/**********************************************************************/
284static bool may_use(struct connection *caller, enum command_id cmd)
285{
286 if (!caller) {
287 return TRUE; /* on the console, everything is allowed */
288 }
289 return (caller->access_level >= command_level(command_by_number(cmd)));
290}
291
292/**********************************************************************/
296static bool may_use_nothing(struct connection *caller)
297{
298 if (!caller) {
299 return FALSE; /* on the console, everything is allowed */
300 }
301 return (ALLOW_NONE == conn_get_access(caller));
302}
303
304/**********************************************************************/
308static char setting_status(struct connection *caller,
309 const struct setting *pset)
310{
311 /* first check for a ruleset lock as this is included in
312 * setting_is_changeable() */
313 if (setting_locked(pset)) {
314 /* setting is locked by the ruleset */
315 return '!';
316 }
317
318 if (setting_is_changeable(pset, caller, NULL, 0)) {
319 /* setting can be changed */
320 return '+';
321 }
322
323 /* setting is fixed */
324 return ' ';
325}
326
327/**********************************************************************/
334static void cmd_reply_line(enum command_id cmd, struct connection *caller,
335 enum rfc_status rfc_status, const char *prefix,
336 const char *line)
337{
338 const char *cmdname = cmd < CMD_NUM
340 : cmd == CMD_AMBIGUOUS
341 /* TRANS: ambiguous command */
342 ? _("(ambiguous)")
343 : cmd == CMD_UNRECOGNIZED
344 /* TRANS: unrecognized command */
345 ? _("(unknown)")
346 : "(?!?)"; /* this case is a bug! */
347
348 if (caller) {
349 notify_conn(caller->self, NULL, E_SETTING, ftc_command,
350 "/%s: %s%s", cmdname, prefix, line);
351 /* cc: to the console - testing has proved it's too verbose - rp
352 con_write(rfc_status, "%s/%s: %s%s", caller->name, cmdname, prefix, line);
353 */
354 } else {
355 con_write(rfc_status, "%s%s", prefix, line);
356 }
357
358 if (rfc_status == C_OK) {
359 struct packet_chat_msg packet;
360
361 package_event(&packet, NULL, E_SETTING, ftc_server, "%s", line);
363 /* Do not tell caller, since they were told above! */
364 if (caller != pconn) {
365 send_packet_chat_msg(pconn, &packet);
366 }
369
370 if (NULL != caller) {
371 /* Echo to the console. */
372 log_normal("%s", line);
373 }
374 }
375}
376
377/**********************************************************************/
381static void vcmd_reply_prefix(enum command_id cmd, struct connection *caller,
382 enum rfc_status rfc_status, const char *prefix,
383 const char *format, va_list ap)
384{
385 char buf[4096];
386 char *c0, *c1;
387
388 fc_vsnprintf(buf, sizeof(buf), format, ap);
389
390 c0 = buf;
391 while ((c1 = strstr(c0, "\n"))) {
392 *c1 = '\0';
393 cmd_reply_line(cmd, caller, rfc_status, (c0 == buf ? "" : prefix), c0);
394 c0 = c1 + 1;
395 }
396
397 cmd_reply_line(cmd, caller, rfc_status, (c0 == buf ? "" : prefix), c0);
398}
399
400/**********************************************************************/
404static void cmd_reply_prefix(enum command_id cmd, struct connection *caller,
405 enum rfc_status rfc_status, const char *prefix,
406 const char *format, ...)
407 fc__attribute((__format__ (__printf__, 5, 6)));
408static void cmd_reply_prefix(enum command_id cmd, struct connection *caller,
409 enum rfc_status rfc_status, const char *prefix,
410 const char *format, ...)
411{
412 va_list ap;
413 va_start(ap, format);
414 vcmd_reply_prefix(cmd, caller, rfc_status, prefix, format, ap);
415 va_end(ap);
416}
417
418/**********************************************************************/
421void cmd_reply(enum command_id cmd, struct connection *caller,
422 enum rfc_status rfc_status, const char *format, ...)
423{
424 va_list ap;
425 va_start(ap, format);
426 vcmd_reply_prefix(cmd, caller, rfc_status, "", format, ap);
427 va_end(ap);
428}
429
430/**********************************************************************/
435 struct connection *caller,
436 const char *name,
437 enum m_pre_result match_result)
438{
439 switch (match_result) {
440 case M_PRE_EMPTY:
441 cmd_reply(cmd, caller, C_SYNTAX,
442 _("Name is empty, so cannot be a player."));
443 break;
444 case M_PRE_LONG:
445 cmd_reply(cmd, caller, C_SYNTAX,
446 _("Name is too long, so cannot be a player."));
447 break;
448 case M_PRE_AMBIGUOUS:
449 cmd_reply(cmd, caller, C_FAIL,
450 _("Player name prefix '%s' is ambiguous."), name);
451 break;
452 case M_PRE_FAIL:
453 cmd_reply(cmd, caller, C_FAIL,
454 _("No player by the name of '%s'."), name);
455 break;
456 default:
457 cmd_reply(cmd, caller, C_FAIL,
458 _("Unexpected match_result %d (%s) for '%s'."),
459 match_result, _(m_pre_description(match_result)), name);
460 log_error("Unexpected match_result %d (%s) for '%s'.",
461 match_result, m_pre_description(match_result), name);
462 }
463}
464
465/**********************************************************************/
470 struct connection *caller,
471 const char *name,
472 enum m_pre_result match_result)
473{
474 switch (match_result) {
475 case M_PRE_EMPTY:
476 cmd_reply(cmd, caller, C_SYNTAX,
477 _("Name is empty, so cannot be a connection."));
478 break;
479 case M_PRE_LONG:
480 cmd_reply(cmd, caller, C_SYNTAX,
481 _("Name is too long, so cannot be a connection."));
482 break;
483 case M_PRE_AMBIGUOUS:
484 cmd_reply(cmd, caller, C_FAIL,
485 _("Connection name prefix '%s' is ambiguous."), name);
486 break;
487 case M_PRE_FAIL:
488 cmd_reply(cmd, caller, C_FAIL,
489 _("No connection by the name of '%s'."), name);
490 break;
491 default:
492 cmd_reply(cmd, caller, C_FAIL,
493 _("Unexpected match_result %d (%s) for '%s'."),
494 match_result, _(m_pre_description(match_result)), name);
495 log_error("Unexpected match_result %d (%s) for '%s'.",
496 match_result, m_pre_description(match_result), name);
497 }
498}
499
500/**********************************************************************/
503static void open_metaserver_connection(struct connection *caller,
504 bool persistent)
505{
508 cmd_reply(CMD_METACONN, caller, C_OK,
509 _("Open metaserver connection to [%s]."),
511 }
512}
513
514/**********************************************************************/
517static void close_metaserver_connection(struct connection *caller)
518{
521 cmd_reply(CMD_METACONN, caller, C_OK,
522 _("Close metaserver connection to [%s]."),
524 }
525}
526
527/**********************************************************************/
530static bool metaconnection_command(struct connection *caller, char *arg,
531 bool check)
532{
533 bool persistent = FALSE;
534
535 if ((*arg == '\0')
536 || (!strcmp(arg, "?"))) {
537 if (is_metaserver_open()) {
539 _("Metaserver connection is open."));
540 } else {
542 _("Metaserver connection is closed."));
543 }
544 return TRUE;
545 }
546
547 if (!fc_strcasecmp(arg, "p")
548 || !fc_strcasecmp(arg, "persistent")) {
550 }
551
552 if (persistent
553 || !fc_strcasecmp(arg, "u")
554 || !fc_strcasecmp(arg, "up")) {
555 if (!is_metaserver_open()) {
556 if (!check) {
558 }
559 } else {
561 _("Metaserver connection is already open."));
562 return FALSE;
563 }
564 } else if (!fc_strcasecmp(arg, "d")
565 || !fc_strcasecmp(arg, "down")) {
566 if (is_metaserver_open()) {
567 if (!check) {
569 }
570 } else {
572 _("Metaserver connection is already closed."));
573 return FALSE;
574 }
575 } else {
577 _("Argument must be 'u', 'up', 'd', 'down', 'p', 'persistent', or '?'."));
578 return FALSE;
579 }
580 return TRUE;
581}
582
583/**********************************************************************/
586static bool metapatches_command(struct connection *caller,
587 char *arg, bool check)
588{
589 if (check) {
590 return TRUE;
591 }
592
594
595 if (is_metaserver_open()) {
598 _("Metaserver patches string set to '%s'."), arg);
599 } else {
601 _("Metaserver patches string set to '%s', "
602 "not reporting to metaserver."), arg);
603 }
604
605 return TRUE;
606}
607
608/**********************************************************************/
611static bool metamessage_command(struct connection *caller,
612 char *arg, bool check)
613{
614 struct setting *pset;
615
616 log_deprecation(_("/metamessage command is deprecated. "
617 "Set metamessage setting instead."));
618
619 if (check) {
620 return TRUE;
621 }
622
624 if (is_metaserver_open()) {
627 _("Metaserver message string set to '%s'."), arg);
628 } else {
630 _("Metaserver message string set to '%s', "
631 "not reporting to metaserver."), arg);
632 }
633
634 /* Metamessage is also a setting. */
635 pset = setting_by_name("metamessage");
636 setting_changed(pset);
637 send_server_setting(NULL, pset);
638
639 return TRUE;
640}
641
642/**********************************************************************/
645static bool metaserver_command(struct connection *caller, char *arg,
646 bool check)
647{
648 if (check) {
649 return TRUE;
650 }
652
654
656 _("Metaserver is now [%s]."), meta_addr_port());
657 return TRUE;
658}
659
660/**********************************************************************/
663static bool show_serverid(struct connection *caller, char *arg)
664{
665 cmd_reply(CMD_SRVID, caller, C_COMMENT, _("Server id: %s"), srvarg.serverid);
666
667 return TRUE;
668}
669
670/**********************************************************************/
674static bool save_command(struct connection *caller, char *arg, bool check)
675{
676 if (is_restricted(caller)) {
677 cmd_reply(CMD_SAVE, caller, C_FAIL,
678 _("You cannot save games manually on this server."));
679 return FALSE;
680 }
681 if (!check) {
682 save_game(arg, "User request", FALSE);
683 }
684 return TRUE;
685}
686
687/**********************************************************************/
691static bool scensave_command(struct connection *caller, char *arg, bool check)
692{
693 if (is_restricted(caller)) {
694 cmd_reply(CMD_SAVE, caller, C_FAIL,
695 _("You cannot save games manually on this server."));
696 return FALSE;
697 }
698 if (!check) {
699 save_game(arg, "Scenario", TRUE);
700 }
701 return TRUE;
702}
703
704/**********************************************************************/
707void toggle_ai_player_direct(struct connection *caller, struct player *pplayer)
708{
709 fc_assert_ret(pplayer != NULL);
710
711 if (is_human(pplayer)) {
712 cmd_reply(CMD_AITOGGLE, caller, C_OK,
713 _("%s is now under AI control."),
714 player_name(pplayer));
715 player_set_to_ai_mode(pplayer,
716 !ai_level_is_valid(pplayer->ai_common.skill_level)
718 : pplayer->ai_common.skill_level);
719 fc_assert(is_ai(pplayer));
720 } else {
721 cmd_reply(CMD_AITOGGLE, caller, C_OK,
722 _("%s is now under human control."),
723 player_name(pplayer));
725 fc_assert(is_human(pplayer));
726 }
727}
728
729/**********************************************************************/
732static bool toggle_ai_command(struct connection *caller, char *arg, bool check)
733{
734 enum m_pre_result match_result;
735 struct player *pplayer;
736
737 pplayer = player_by_name_prefix(arg, &match_result);
738
739 if (!pplayer) {
740 cmd_reply_no_such_player(CMD_AITOGGLE, caller, arg, match_result);
741 return FALSE;
742 } else if (!check) {
743 toggle_ai_player_direct(caller, pplayer);
745 }
746 return TRUE;
747}
748
749/**********************************************************************/
755static bool create_command(struct connection *caller, const char *str,
756 bool check)
757{
758 enum rfc_status status;
759 char buf[MAX_LEN_CONSOLE_LINE];
760
761 /* 2 legal arguments, and extra space for stuffing illegal part */
762 char *arg[3];
763 int ntokens;
764 const char *ai_type_name;
765
766 sz_strlcpy(buf, str);
767 ntokens = get_tokens(buf, arg, 3, TOKEN_DELIMITERS);
768
769 if (ntokens == 1) {
770 ai_type_name = default_ai_type_name();
771 } else if (ntokens == 2) {
772 ai_type_name = arg[1];
773 } else {
775 _("Wrong number of arguments to create command."));
776 free_tokens(arg, ntokens);
777 return FALSE;
778 }
779
780 if (game_was_started()) {
781 status = create_command_newcomer(arg[0], ai_type_name, check,
782 NULL, NULL, buf, sizeof(buf));
783 } else {
784 status = create_command_pregame(arg[0], ai_type_name, check,
785 NULL, buf, sizeof(buf));
786 }
787
788 free_tokens(arg, ntokens);
789
790 if (status != C_OK) {
791 /* No player created. */
792 cmd_reply(CMD_CREATE, caller, status, "%s", buf);
793 return FALSE;
794 }
795
796 if (strlen(buf) > 0) {
797 /* Send a notification. */
798 cmd_reply(CMD_CREATE, caller, C_OK, "%s", buf);
799 }
800
801 return TRUE;
802}
803
804/**********************************************************************/
814 const char *ai,
815 bool check,
816 struct nation_type *pnation,
817 struct player **newplayer,
818 char *buf, size_t buflen)
819{
820 struct player *pplayer = NULL;
821 struct research *presearch;
822 bool new_slot = FALSE;
823
824 /* Check player name. */
825 if (!player_name_check(name, buf, buflen)) {
826 return C_SYNTAX;
827 }
828
829 /* Check first if we can replace a player with
830 * [1a] - the same username. */
831 pplayer = player_by_user(name);
832 if (pplayer && pplayer->is_alive) {
833 fc_snprintf(buf, buflen,
834 _("A living user already exists by that name."));
835 return C_BOUNCE;
836 }
837
838 /* [1b] - the same player name. */
839 pplayer = player_by_name(name);
840 if (pplayer && pplayer->is_alive) {
841 fc_snprintf(buf, buflen,
842 _("A living player already exists by that name."));
843 return C_BOUNCE;
844 }
845
846 if (pnation) {
847 if (!nation_is_in_current_set(pnation)) {
848 fc_snprintf(buf, buflen,
849 _("Can't create player, requested nation %s not in "
850 "current nation set."),
852 return C_FAIL;
853 }
854 players_iterate(aplayer) {
855 if (0 > nations_match(pnation, nation_of_player(aplayer), FALSE)) {
856 fc_snprintf(buf, buflen,
857 _("Can't create players, nation %s conflicts with %s."),
859 nation_plural_for_player(pplayer));
860 return C_FAIL;
861 }
863 } else {
864 /* Try to find a nation. */
865 pnation = pick_a_nation(NULL, FALSE, TRUE, NOT_A_BARBARIAN);
866 if (pnation == NO_NATION_SELECTED) {
867 fc_snprintf(buf, buflen,
868 _("Can't create players, no nations available."));
869 return C_FAIL;
870 }
871 }
872
873 if (pplayer == NULL) {
874 if (player_count() == player_slot_count()) {
875 bool dead_found = FALSE;
876
877 players_iterate(aplayer) {
878 if (!aplayer->is_alive) {
879 dead_found = TRUE;
880 break;
881 }
883
884 if (!dead_found) {
885 fc_snprintf(buf, buflen,
886 _("Can't create players, no slots available."));
887 return C_FAIL;
888 }
889 } else if (normal_player_count() == game.server.max_players) {
890 fc_snprintf(buf, buflen,
891 _("Maxplayers setting prevents creation of more players."));
892 return C_FAIL;
893 }
894 }
895
896 if (check) {
897 /* All code below will change the game state. */
898
899 /* Return an empty string. */
900 buf[0] = '\0';
901
902 return C_OK;
903 }
904
905 if (pplayer) {
906 /* [1] Replace a player. 'pplayer' was set above. */
907 fc_snprintf(buf, buflen,
908 _("%s is replacing dead player %s as an AI-controlled "
909 "player."), name, player_name(pplayer));
910 /* remove player and thus free a player slot */
911 server_remove_player(pplayer);
912 pplayer = NULL;
913 } else if (player_count() == player_slot_count()) {
914 /* [2] All player slots are used; try to remove a dead player. */
915 bool dead_found = FALSE;
916
917 players_iterate(aplayer) {
918 if (!aplayer->is_alive) {
919 if (!dead_found) {
920 /* Fill the buffer with the name of the first found dead player */
921 fc_snprintf(buf, buflen,
922 _("%s is replacing dead player %s as an AI-controlled "
923 "player."), name, player_name(aplayer));
924 dead_found = TRUE;
925 }
926
927 /* Remove player and thus free a player slot */
928 server_remove_player(aplayer);
929 }
930
931 fc_assert(dead_found);
933 } else {
934 /* [3] An empty player slot must be used for the new player. */
935 new_slot = TRUE;
936 }
937
938 /* Create the new player. */
939 pplayer = server_create_player(-1, ai, NULL, FALSE);
940 if (!pplayer) {
941 fc_snprintf(buf, buflen, _("Failed to create new player %s."), name);
942 return C_FAIL;
943 }
944
945 if (new_slot) {
946 /* 'buf' must be set if a new player slot is used. */
947 fc_snprintf(buf, buflen, _("New player %s created."), name);
948 }
949
950 /* We have a player; now initialise all needed data. */
951 (void) aifill(game.info.aifill);
952
953 /* Initialise player. */
954 server_player_init(pplayer, TRUE, TRUE);
955
956 player_nation_defaults(pplayer, pnation, FALSE);
957 pplayer->government = pplayer->target_government
958 = init_government_of_nation(pnation);
959 /* Find a color for the new player. */
961
962 /* TRANS: keep one space at the beginning of the string. */
963 cat_snprintf(buf, buflen, _(" Nation of the new player: %s."),
964 nation_rule_name(pnation));
965
966 presearch = research_get(pplayer);
967 init_tech(presearch, TRUE);
968 give_initial_techs(presearch, 0);
969
972 pplayer->unassigned_user = TRUE;
973
974 pplayer->was_created = TRUE; /* must use /remove explicitly to remove */
975 set_as_ai(pplayer);
977
978 CALL_PLR_AI_FUNC(gained_control, pplayer, pplayer);
979
980 send_player_info_c(pplayer, NULL);
981 /* Send updated diplstate information to all players. */
982 send_player_diplstate_c(NULL, NULL);
983 /* Send research info after player info, else the client will complain
984 * about invalid team. */
985 send_research_info(presearch, NULL);
987
988 if (newplayer != NULL) {
989 *newplayer = pplayer;
990 }
991
992 adv_data_phase_init(pplayer, TRUE);
993 CALL_PLR_AI_FUNC(phase_begin, pplayer, pplayer, TRUE);
994
995 return C_OK;
996}
997
998/**********************************************************************/
1002 const char *ai,
1003 bool check,
1004 struct player **newplayer,
1005 char *buf, size_t buflen)
1006{
1007 char leader_name[MAX_LEN_NAME]; /* Must be in whole function scope */
1008 struct player *pplayer = NULL;
1009 bool rand_name = FALSE;
1010
1011 if (name[0] == '\0') {
1012 int filled = 1;
1013
1014 do {
1015 fc_snprintf(leader_name, sizeof(leader_name), "%s*%d", ai, filled++);
1016 } while (player_by_name(leader_name));
1017
1018 name = leader_name;
1019 rand_name = TRUE;
1020 }
1021
1022 if (!player_name_check(name, buf, buflen)) {
1023 return C_SYNTAX;
1024 }
1025
1026 if (NULL != player_by_name(name)) {
1027 fc_snprintf(buf, buflen,
1028 _("A player already exists by that name."));
1029 return C_BOUNCE;
1030 }
1031 if (NULL != player_by_user(name)) {
1032 fc_snprintf(buf, buflen,
1033 _("A user already exists by that name."));
1034 return C_BOUNCE;
1035 }
1036
1037 /* Search for first uncontrolled player */
1038 pplayer = find_uncontrolled_player();
1039
1040 if (NULL == pplayer) {
1041 /* Check that we are not going over max players setting */
1043 fc_snprintf(buf, buflen,
1044 _("Can't add more players, server is full."));
1045 return C_FAIL;
1046 }
1047 /* Check that we have nations available */
1048 if (normal_player_count() >= server.playable_nations) {
1049 if (nation_set_count() > 1) {
1050 fc_snprintf(buf, buflen,
1051 _("Can't add more players, not enough playable nations "
1052 "in current nation set (see 'nationset' setting)."));
1053 } else {
1054 fc_snprintf(buf, buflen,
1055 _("Can't add more players, not enough playable nations."));
1056 }
1057 return C_FAIL;
1058 }
1059 }
1060
1061 if (pplayer) {
1062 struct ai_type *ait = ai_type_by_name(ai);
1063
1064 if (ait == NULL) {
1065 fc_snprintf(buf, buflen,
1066 _("There is no AI type %s."), ai);
1067 return C_FAIL;
1068 }
1069 }
1070
1071 if (check) {
1072 /* All code below will change the game state. */
1073
1074 /* Return an empty string. */
1075 buf[0] = '\0';
1076
1077 return C_OK;
1078 }
1079
1080 if (pplayer) {
1081 fc_snprintf(buf, buflen,
1082 /* TRANS: <name> replacing <name> ... */
1083 _("%s replacing %s as an AI-controlled player."),
1084 name, player_name(pplayer));
1085
1086 team_remove_player(pplayer);
1087 pplayer->ai = ai_type_by_name(ai);
1088 } else {
1089 /* add new player */
1090 pplayer = server_create_player(-1, ai, NULL, FALSE);
1091 /* pregame so no need to assign_player_colors() */
1092 if (!pplayer) {
1093 fc_snprintf(buf, buflen,
1094 _("Failed to create new player %s."), name);
1095 return C_GENFAIL;
1096 }
1097
1098 fc_snprintf(buf, buflen,
1099 _("%s has been added as an AI-controlled player (%s)."),
1100 name, ai_name(pplayer->ai));
1101 }
1102 server_player_init(pplayer, FALSE, TRUE);
1103
1104 server_player_set_name(pplayer, name);
1105 sz_strlcpy(pplayer->username, _(ANON_USER_NAME));
1106 pplayer->unassigned_user = TRUE;
1107
1108 pplayer->was_created = TRUE; /* must use /remove explicitly to remove */
1109 pplayer->random_name = rand_name;
1110 set_as_ai(pplayer);
1112 CALL_PLR_AI_FUNC(gained_control, pplayer, pplayer);
1114
1115 (void) aifill(game.info.aifill);
1118
1119 if (newplayer != NULL) {
1120 *newplayer = pplayer;
1121 }
1122 return C_OK;
1123}
1124
1125/**********************************************************************/
1128static bool remove_player_command(struct connection *caller, char *arg,
1129 bool check)
1130{
1131 enum m_pre_result match_result;
1132 struct player *pplayer;
1133 char name[MAX_LEN_NAME];
1134
1135 pplayer = player_by_name_prefix(arg, &match_result);
1136
1137 if (NULL == pplayer) {
1138 cmd_reply_no_such_player(CMD_REMOVE, caller, arg, match_result);
1139 return FALSE;
1140 }
1141
1142 if (game_was_started() && caller && caller->access_level < ALLOW_ADMIN) {
1143 cmd_reply(CMD_REMOVE, caller, C_FAIL,
1144 _("Command level '%s' or greater needed to remove a player "
1145 "once the game has started."), cmdlevel_name(ALLOW_ADMIN));
1146 return FALSE;
1147 }
1148 if (check) {
1149 return TRUE;
1150 }
1151
1152 sz_strlcpy(name, player_name(pplayer));
1153 server_remove_player(pplayer);
1154 if (!caller || caller->used) { /* may have removed self */
1155 cmd_reply(CMD_REMOVE, caller, C_OK,
1156 _("Removed player %s from the game."), name);
1157 }
1158 (void) aifill(game.info.aifill);
1159 return TRUE;
1160}
1161
1162/**********************************************************************/
1165static bool read_command(struct connection *caller, char *arg, bool check,
1166 int read_recursion)
1167{
1168 return read_init_script_real(caller, arg, FALSE, check, read_recursion);
1169}
1170
1171/**********************************************************************/
1174bool read_init_script(struct connection *caller, char *script_filename,
1175 bool from_cmdline, bool check)
1176{
1177 return read_init_script_real(caller, script_filename, from_cmdline,
1178 check, 0);
1179}
1180
1181/**********************************************************************/
1192static bool read_init_script_real(struct connection *caller,
1193 char *script_filename, bool from_cmdline,
1194 bool check, int read_recursion)
1195{
1196 FILE *script_file;
1197 char serv_filename[strlen(script_extension) + strlen(script_filename) + 2];
1198 char tilde_filename[4096];
1199 const char *real_filename;
1200 size_t fnlen;
1201
1202 /* check recursion depth */
1203 if (read_recursion > GAME_MAX_READ_RECURSION) {
1204 log_error("Error: recursive calls to read!");
1205 return FALSE;
1206 }
1207
1208 /* abuse real_filename to find if we already have a .serv extension */
1209 fnlen = strlen(script_filename);
1210 real_filename = script_filename + fnlen
1211 - MIN(strlen(script_extension), fnlen);
1212 if (strcmp(real_filename, script_extension) != 0) {
1213 fc_snprintf(serv_filename, sizeof(serv_filename), "%s%s",
1214 script_filename, script_extension);
1215 } else {
1216 sz_strlcpy(serv_filename, script_filename);
1217 }
1218
1219 if (is_restricted(caller) && !from_cmdline) {
1220 if (!is_safe_filename(serv_filename)) {
1222 _("Name \"%s\" disallowed for security reasons."),
1223 serv_filename);
1224 return FALSE;
1225 }
1226 sz_strlcpy(tilde_filename, serv_filename);
1227 } else {
1228 interpret_tilde(tilde_filename, sizeof(tilde_filename), serv_filename);
1229 }
1230
1231 real_filename = fileinfoname(get_data_dirs(), tilde_filename);
1232 if (!real_filename) {
1233 if (is_restricted(caller) && !from_cmdline) {
1235 _("No command script found by the name \"%s\"."),
1236 serv_filename);
1237 return FALSE;
1238 }
1239 /* File is outside data directories */
1240 real_filename = tilde_filename;
1241 }
1242
1243 log_testmatic_alt(LOG_NORMAL, _("Loading script file '%s'."), real_filename);
1244
1245 if (is_reg_file_for_access(real_filename, FALSE)
1246 && (script_file = fc_fopen(real_filename, "r"))) {
1247 char buffer[MAX_LEN_CONSOLE_LINE];
1248
1249 /* The size is set as to not overflow buffer in handle_stdin_input */
1250 while (fgets(buffer, MAX_LEN_CONSOLE_LINE - 1, script_file)) {
1251 /* Execute script contents with same permissions as caller */
1252 handle_stdin_input_real(caller, buffer, check, read_recursion + 1);
1253 }
1254 fclose(script_file);
1255
1256 show_ruleset_info(caller, CMD_READ_SCRIPT, check, read_recursion);
1257
1258 return TRUE;
1259 } else {
1261 _("Cannot read command line scriptfile '%s'."), real_filename);
1262 if (NULL != caller) {
1263 log_error(_("Could not read script file '%s'."), real_filename);
1264 }
1265 return FALSE;
1266 }
1267}
1268
1269/**********************************************************************/
1279
1280/**********************************************************************/
1285static bool write_init_script(char *script_filename)
1286{
1287 char real_filename[1024], buf[256];
1288 FILE *script_file;
1289
1290 interpret_tilde(real_filename, sizeof(real_filename), script_filename);
1291
1292 if (is_reg_file_for_access(real_filename, TRUE)
1293 && (script_file = fc_fopen(real_filename, "w"))) {
1294 fprintf(script_file,
1295 "#FREECIV SERVER COMMAND FILE, version %s\n", VERSION_STRING);
1296 fputs("# These are server options saved from a running freeciv-server.\n",
1297 script_file);
1298
1299 /* First rulesetdir. Setting rulesetdir resets the settings to their
1300 * default value, so they would be lost if placed before this. */
1301 fprintf(script_file, "rulesetdir %s\n", game.server.rulesetdir);
1302
1303 /* Some state info from commands (we can't save everything) */
1304
1305 fprintf(script_file, "cmdlevel %s new\n",
1306 cmdlevel_name(default_access_level));
1307
1308 fprintf(script_file, "cmdlevel %s first\n",
1309 cmdlevel_name(first_access_level));
1310
1311 fprintf(script_file, "%s\n",
1313
1314 if (*srvarg.metaserver_addr != '\0'
1315 && ((0 != strcmp(srvarg.metaserver_addr, DEFAULT_META_SERVER_ADDR)))) {
1316 fprintf(script_file, "metaserver %s\n", meta_addr_port());
1317 }
1318
1320 fprintf(script_file, "metapatches %s\n", get_meta_patches_string());
1321 }
1322
1323 /* Then, the 'set' option settings */
1324
1325 settings_iterate(SSET_ALL, pset) {
1326 fprintf(script_file, "set %s \"%s\"\n", setting_name(pset),
1327 setting_value_name(pset, FALSE, buf, sizeof(buf)));
1329
1330 fclose(script_file);
1331
1332 return TRUE;
1333 } else {
1334 log_error(_("Could not write script file '%s'."), real_filename);
1335
1336 return FALSE;
1337 }
1338}
1339
1340/**********************************************************************/
1343static bool write_command(struct connection *caller, char *arg, bool check)
1344{
1345 if (is_restricted(caller)) {
1347 _("You cannot use the write command on this server"
1348 " for security reasons."));
1349 return FALSE;
1350 } else if (!check) {
1351 char serv_filename[strlen(script_extension) + strlen(arg) + 2];
1352 const char *real_filename;
1353 size_t arglen = strlen(arg);
1354
1355 /* abuse real_filename to find if we already have a .serv extension */
1356 real_filename = arg + arglen - MIN(strlen(script_extension), arglen);
1357 if (strcmp(real_filename, script_extension) != 0) {
1358 fc_snprintf(serv_filename, sizeof(serv_filename), "%s%s",
1359 arg, script_extension);
1360 } else {
1361 sz_strlcpy(serv_filename, arg);
1362 }
1363
1364 if (!write_init_script(serv_filename)) {
1366 /* TRANS: Failed to write server script, e.g., 'example.serv' */
1367 _("Failed to write %s."), serv_filename);
1368 return FALSE;
1369 }
1370
1372 /* TRANS: Wrote server script, e.g., 'example.serv' */
1373 _("Wrote %s."), serv_filename);
1374 }
1375
1376 return TRUE;
1377}
1378
1379/**********************************************************************/
1382static bool set_cmdlevel(struct connection *caller,
1383 struct connection *ptarget,
1384 enum cmdlevel level)
1385{
1386 /* Only ever call me for specific connection. */
1387 fc_assert_ret_val(ptarget != NULL, FALSE);
1388
1389 if (caller && ptarget->access_level > caller->access_level) {
1390 /*
1391 * This command is intended to be used at ctrl access level
1392 * and thus this if clause is needed.
1393 * (Imagine a ctrl level access player that wants to change
1394 * access level of a hack level access player)
1395 * At the moment it can be used only by hack access level
1396 * and thus this clause is never used.
1397 */
1398 cmd_reply(CMD_CMDLEVEL, caller, C_FAIL,
1399 _("Cannot decrease command access level '%s' "
1400 "for connection '%s'; you only have '%s'."),
1401 cmdlevel_name(ptarget->access_level),
1402 ptarget->username,
1403 cmdlevel_name(caller->access_level));
1404 return FALSE;
1405 } else {
1406 conn_set_access(ptarget, level, TRUE);
1407 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1408 _("Command access level set to '%s' for connection %s."),
1409 cmdlevel_name(level), ptarget->username);
1410 return TRUE;
1411 }
1412}
1413
1414/**********************************************************************/
1417static bool a_connection_exists(void)
1418{
1419 return conn_list_size(game.est_connections) > 0;
1420}
1421
1422/**********************************************************************/
1426{
1428 if (pconn->access_level >= first_access_level) {
1429 return TRUE;
1430 }
1431 }
1433 return FALSE;
1434}
1435
1436/**********************************************************************/
1440{
1442 && !a_connection_exists()) {
1443 return first_access_level;
1444 } else {
1445 return default_access_level;
1446 }
1447}
1448
1449/**********************************************************************/
1454{
1457 notify_conn(NULL, NULL, E_SETTING, ftc_any,
1458 _("Anyone can now become game organizer "
1459 "'%s' by issuing the 'first' command."),
1460 cmdlevel_name(first_access_level));
1461 }
1462}
1463
1464/**********************************************************************/
1467static bool cmdlevel_command(struct connection *caller, char *str, bool check)
1468{
1469 char *arg[2];
1470 int ntokens;
1471 bool ret = FALSE;
1472 enum m_pre_result match_result;
1473 enum cmdlevel level;
1474 struct connection *ptarget;
1475
1476 ntokens = get_tokens(str, arg, 2, TOKEN_DELIMITERS);
1477
1478 if (ntokens == 0) {
1479 /* No argument supplied; list the levels */
1482 _("Command access levels in effect:"));
1485 const char *lvl_name = cmdlevel_name(conn_get_access(pconn));
1486
1487 if (lvl_name != NULL) {
1488 cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, "cmdlevel %s %s",
1489 lvl_name, pconn->username);
1490 } else {
1491 fc_assert(lvl_name != NULL); /* Always fails when reached. */
1492 }
1495 _("Command access level for new connections: %s"),
1496 cmdlevel_name(default_access_level));
1498 _("Command access level for first player to take it: %s"),
1499 cmdlevel_name(first_access_level));
1501 return TRUE;
1502 }
1503
1504 /* A level name was supplied; set the level. */
1505 level = cmdlevel_by_name(arg[0], fc_strcasecmp);
1506 if (!cmdlevel_is_valid(level)) {
1507 const char *cmdlevel_names[CMDLEVEL_COUNT];
1508 struct astring astr = ASTRING_INIT;
1509 int i = 0;
1510
1511 for (level = cmdlevel_begin(); level != cmdlevel_end();
1512 level = cmdlevel_next(level)) {
1513 cmdlevel_names[i++] = cmdlevel_name(level);
1514 }
1516 /* TRANS: comma and 'or' separated list of access levels */
1517 _("Command access level must be one of %s."),
1518 astr_build_or_list(&astr, cmdlevel_names, i));
1519 astr_free(&astr);
1520 goto CLEAN_UP;
1521 } else if (caller && level > conn_get_access(caller)) {
1522 cmd_reply(CMD_CMDLEVEL, caller, C_FAIL,
1523 _("Cannot increase command access level to '%s';"
1524 " you only have '%s' yourself."),
1525 arg[0], cmdlevel_name(conn_get_access(caller)));
1526 goto CLEAN_UP;
1527 }
1528
1529 if (check) {
1530 return TRUE; /* looks good */
1531 }
1532
1533 if (ntokens == 1) {
1534 /* No playername supplied: set for all connections */
1536 if (pconn != caller) {
1537 (void) set_cmdlevel(caller, pconn, level);
1538 }
1540
1541 /* Set the caller access level at last, because it could make the
1542 * previous operations impossible if set before. */
1543 if (caller) {
1544 (void) set_cmdlevel(caller, caller, level);
1545 }
1546
1547 /* Set default access for new connections. */
1549 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1550 _("Command access level set to '%s' for new players."),
1551 cmdlevel_name(level));
1552 /* Set default access for first connection. */
1554 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1555 _("Command access level set to '%s' "
1556 "for first player to grab it."),
1557 cmdlevel_name(level));
1558
1559 ret = TRUE;
1560
1561 } else if (fc_strcasecmp(arg[1], "new") == 0) {
1563 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1564 _("Command access level set to '%s' for new players."),
1565 cmdlevel_name(level));
1566 if (level > first_access_level) {
1568 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1569 _("Command access level set to '%s' "
1570 "for first player to grab it."),
1571 cmdlevel_name(level));
1572 }
1573
1574 ret = TRUE;
1575
1576 } else if (fc_strcasecmp(arg[1], "first") == 0) {
1578 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1579 _("Command access level set to '%s' "
1580 "for first player to grab it."),
1581 cmdlevel_name(level));
1584 cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1585 _("Command access level set to '%s' for new players."),
1586 cmdlevel_name(level));
1587 }
1588
1589 ret = TRUE;
1590
1591 } else if ((ptarget = conn_by_user_prefix(arg[1], &match_result))) {
1592 if (set_cmdlevel(caller, ptarget, level)) {
1593 ret = TRUE;
1594 }
1595 } else {
1596 cmd_reply_no_such_conn(CMD_CMDLEVEL, caller, arg[1], match_result);
1597 }
1598
1599CLEAN_UP:
1600 free_tokens(arg, ntokens);
1601 return ret;
1602}
1603
1604/**********************************************************************/
1610static bool firstlevel_command(struct connection *caller, bool check)
1611{
1612 if (!caller) {
1614 _("The 'first' command makes no sense from the server command line."));
1615 return FALSE;
1616 } else if (caller->access_level >= first_access_level) {
1618 _("You already have command access level '%s' or better."),
1619 cmdlevel_name(first_access_level));
1620 return FALSE;
1621 } else if (is_first_access_level_taken()) {
1623 _("Someone else is already game organizer."));
1624 return FALSE;
1625 } else if (!check) {
1627 cmd_reply(CMD_FIRSTLEVEL, caller, C_OK,
1628 _("Connection %s has opted to become the game organizer."),
1629 caller->username);
1630 }
1631 return TRUE;
1632}
1633
1634/**********************************************************************/
1638{
1639 if (default_access_level > ALLOW_BASIC) {
1640 notify_conn(NULL, NULL, E_SETTING, ftc_server,
1641 _("Default cmdlevel lowered to 'basic' on game start."));
1642 default_access_level = ALLOW_BASIC;
1643 }
1644}
1645
1646/**********************************************************************/
1650static const char *optname_accessor(int i)
1651{
1653}
1654
1655#ifdef FREECIV_HAVE_LIBREADLINE
1656/**********************************************************************/
1659static const char *olvlname_accessor(int i)
1660{
1661 if (i == 0) {
1662 return "rulesetdir";
1663 } else if (i < OLEVELS_NUM+1) {
1664 return sset_level_name(i-1);
1665 } else {
1666 return optname_accessor(i-OLEVELS_NUM-1);
1667 }
1668}
1669#endif /* FREECIV_HAVE_LIBREADLINE */
1670
1671/**********************************************************************/
1674static bool timeout_command(struct connection *caller, char *str, bool check)
1675{
1676 char buf[MAX_LEN_CONSOLE_LINE];
1677 char *arg[4];
1678 int i = 0, ntokens;
1679 int *timeouts[4];
1680
1681 timeouts[0] = &game.server.timeoutint;
1682 timeouts[1] = &game.server.timeoutintinc;
1683 timeouts[2] = &game.server.timeoutinc;
1684 timeouts[3] = &game.server.timeoutincmult;
1685
1686 sz_strlcpy(buf, str);
1687 ntokens = get_tokens(buf, arg, 4, TOKEN_DELIMITERS);
1688
1689 for (i = 0; i < ntokens; i++) {
1690 if (!str_to_int(arg[i], timeouts[i])) {
1691 cmd_reply(CMD_TIMEOUT, caller, C_FAIL, _("Invalid argument %d."),
1692 i + 1);
1693 }
1694 free(arg[i]);
1695 }
1696
1697 if (ntokens == 0) {
1698 cmd_reply(CMD_TIMEOUT, caller, C_SYNTAX, _("Usage:\n%s"),
1700 return FALSE;
1701 } else if (check) {
1702 return TRUE;
1703 }
1704
1705 cmd_reply(CMD_TIMEOUT, caller, C_OK, _("Dynamic timeout set to "
1706 "%d %d %d %d"),
1709
1710 /* if we set anything here, reset the counter */
1712 return TRUE;
1713}
1714
1715/**********************************************************************/
1718static enum sset_level lookup_option_level(const char *name)
1719{
1720 enum sset_level i;
1721
1722 for (i = SSET_ALL; i < OLEVELS_NUM; i++) {
1723 if (0 == fc_strcasecmp(name, sset_level_name(i))) {
1724 return i;
1725 }
1726 }
1727
1728 return SSET_NONE;
1729}
1730
1731/* Special return values of lookup options */
1732#define LOOKUP_OPTION_NO_RESULT (-1)
1733#define LOOKUP_OPTION_AMBIGUOUS (-2)
1734#define LOOKUP_OPTION_LEVEL_NAME (-3)
1735#define LOOKUP_OPTION_RULESETDIR (-4)
1736
1737/**********************************************************************/
1744static int lookup_option(const char *name)
1745{
1746 enum m_pre_result result;
1747 int ind;
1748
1749 /* Check for option levels, first off */
1750 if (lookup_option_level(name) != SSET_NONE) {
1752 }
1753
1755 0, fc_strncasecmp, NULL, name, &ind);
1756 if (M_PRE_AMBIGUOUS > result) {
1757 return ind;
1758 } else if (M_PRE_AMBIGUOUS == result) {
1760 } else if ('\0' != name[0]
1761 && 0 == fc_strncasecmp("rulesetdir", name, strlen(name))) {
1763 } else {
1765 }
1766}
1767
1768/**********************************************************************/
1773static void show_help_option(struct connection *caller,
1774 enum command_id help_cmd, int id)
1775{
1776 char val_buf[256], def_buf[256];
1777 struct setting *pset = setting_by_number(id);
1778 const char *sethelp;
1779
1780 if (setting_short_help(pset)) {
1781 cmd_reply(help_cmd, caller, C_COMMENT,
1782 /* TRANS: <untranslated name> - translated short help */
1783 _("Option: %s - %s"), setting_name(pset),
1784 _(setting_short_help(pset)));
1785 } else {
1786 cmd_reply(help_cmd, caller, C_COMMENT,
1787 /* TRANS: <untranslated name> */
1788 _("Option: %s"), setting_name(pset));
1789 }
1790
1791 sethelp = setting_extra_help(pset, FALSE);
1792 if (strlen(sethelp) > 0) {
1793 char *help = fc_strdup(sethelp);
1794
1796 cmd_reply(help_cmd, caller, C_COMMENT, _("Description:"));
1797 cmd_reply_prefix(help_cmd, caller, C_COMMENT, " ", " %s", help);
1798 FC_FREE(help);
1799 }
1800 cmd_reply(help_cmd, caller, C_COMMENT,
1801 _("Status: %s"), (setting_is_changeable(pset, NULL, NULL, 0)
1802 ? _("changeable") : _("fixed")));
1803
1804 if (setting_is_visible(pset, caller)) {
1805 setting_value_name(pset, TRUE, val_buf, sizeof(val_buf));
1806 setting_default_name(pset, TRUE, def_buf, sizeof(def_buf));
1807
1808 switch (setting_type(pset)) {
1809 case SST_INT:
1810 cmd_reply(help_cmd, caller, C_COMMENT, "%s %s, %s %d, %s %s, %s %d",
1811 _("Value:"), val_buf,
1812 _("Minimum:"), setting_int_min(pset),
1813 _("Default:"), def_buf,
1814 _("Maximum:"), setting_int_max(pset));
1815 break;
1816 case SST_ENUM:
1817 {
1818 int i;
1819 const char *value;
1820
1821 cmd_reply(help_cmd, caller, C_COMMENT, _("Possible values:"));
1822 for (i = 0; (value = setting_enum_val(pset, i, FALSE)); i++) {
1823 cmd_reply(help_cmd, caller, C_COMMENT, "- %s: \"%s\"",
1824 value, setting_enum_val(pset, i, TRUE));
1825 }
1826 }
1827
1829 case SST_BOOL:
1830 case SST_STRING:
1831 cmd_reply(help_cmd, caller, C_COMMENT, "%s %s, %s %s",
1832 _("Value:"), val_buf, _("Default:"), def_buf);
1833 break;
1834 case SST_BITWISE:
1835 {
1836 int i;
1837 const char *value;
1838
1839 cmd_reply(help_cmd, caller, C_COMMENT,
1840 _("Possible values (option can take any number of these):"));
1841 for (i = 0; (value = setting_bitwise_bit(pset, i, FALSE)); i++) {
1842 cmd_reply(help_cmd, caller, C_COMMENT, "- %s: \"%s\"",
1843 value, setting_bitwise_bit(pset, i, TRUE));
1844 }
1845 cmd_reply(help_cmd, caller, C_COMMENT, "%s %s",
1846 _("Value:"), val_buf);
1847 cmd_reply(help_cmd, caller, C_COMMENT, "%s %s",
1848 _("Default:"), def_buf);
1849 }
1850 break;
1851 case SST_COUNT:
1852 fc_assert(setting_type(pset) != SST_COUNT);
1853 break;
1854 }
1855 }
1856}
1857
1858/**********************************************************************/
1863static void show_help_option_list(struct connection *caller,
1864 enum command_id help_cmd)
1865{
1866 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
1867 cmd_reply(help_cmd, caller, C_COMMENT,
1868 _("Explanations are available for the following server options:"));
1869 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
1870 if (!caller && con_get_style()) {
1871 settings_iterate(SSET_ALL, pset) {
1872 cmd_reply(help_cmd, caller, C_COMMENT, "%s", setting_name(pset));
1874 } else {
1875 char buf[MAX_LEN_CONSOLE_LINE];
1876 int j = 0;
1877 buf[0] = '\0';
1878
1879 settings_iterate(SSET_ALL, pset) {
1880 if (setting_is_visible(pset, caller)) {
1881 cat_snprintf(buf, sizeof(buf), "%-19s", setting_name(pset));
1882 if ((++j % 4) == 0) {
1883 cmd_reply(help_cmd, caller, C_COMMENT, "%s", buf);
1884 buf[0] = '\0';
1885 }
1886 }
1888
1889 if (buf[0] != '\0') {
1890 cmd_reply(help_cmd, caller, C_COMMENT, "%s", buf);
1891 }
1892 }
1893 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
1894}
1895
1896/**********************************************************************/
1899static bool explain_option(struct connection *caller, char *str, bool check)
1900{
1901 int cmd;
1902
1904
1905 if (*str != '\0') {
1906 cmd = lookup_option(str);
1907 if (cmd >= 0 && cmd < settings_number()) {
1908 show_help_option(caller, CMD_EXPLAIN, cmd);
1909 } else if (cmd == LOOKUP_OPTION_NO_RESULT
1910 || cmd == LOOKUP_OPTION_LEVEL_NAME
1911 || cmd == LOOKUP_OPTION_RULESETDIR) {
1912 cmd_reply(CMD_EXPLAIN, caller, C_FAIL,
1913 _("No explanation for that yet."));
1914 return FALSE;
1915 } else if (cmd == LOOKUP_OPTION_AMBIGUOUS) {
1916 cmd_reply(CMD_EXPLAIN, caller, C_FAIL, _("Ambiguous option name."));
1917 return FALSE;
1918 } else {
1919 log_error("Unexpected case %d in %s line %d", cmd, __FILE__,
1920 __FC_LINE__);
1921 return FALSE;
1922 }
1923 } else {
1925 }
1926 return TRUE;
1927}
1928
1929/**********************************************************************/
1932static bool wall(char *str, bool check)
1933{
1934 if (!check) {
1935 notify_conn(NULL, NULL, E_MESSAGE_WALL, ftc_server_prompt,
1936 _("Server Operator: %s"), str);
1937 }
1938 return TRUE;
1939}
1940
1941/**********************************************************************/
1944static bool connectmsg_command(struct connection *caller, char *str,
1945 bool check)
1946{
1947 unsigned int bufsize = sizeof(game.server.connectmsg);
1948
1949 if (is_restricted(caller)) {
1950 return FALSE;
1951 }
1952 if (!check) {
1953 int i;
1954 int c = 0;
1955
1956 for (i = 0; c < bufsize -1 && str[i] != '\0'; i++) {
1957 if (str[i] == '\\') {
1958 i++;
1959
1960 if (str[i] == 'n') {
1961 game.server.connectmsg[c++] = '\n';
1962 } else {
1963 game.server.connectmsg[c++] = str[i];
1964 }
1965 } else {
1966 game.server.connectmsg[c++] = str[i];
1967 }
1968 }
1969
1970 game.server.connectmsg[c++] = '\0';
1971
1972 if (c == bufsize) {
1973 /* Truncated */
1975 _("Connectmsg truncated to %u bytes."), bufsize);
1976 }
1977 }
1978 return TRUE;
1979}
1980
1981/**********************************************************************/
1985static enum command_id cmd_of_level(enum ai_level level)
1986{
1987 switch (level) {
1988 case AI_LEVEL_AWAY : return CMD_AWAY;
1989 case AI_LEVEL_RESTRICTED : return CMD_RESTRICTED;
1990 case AI_LEVEL_NOVICE : return CMD_NOVICE;
1991 case AI_LEVEL_EASY : return CMD_EASY;
1992 case AI_LEVEL_NORMAL : return CMD_NORMAL;
1993 case AI_LEVEL_HARD : return CMD_HARD;
1994 case AI_LEVEL_CHEATING : return CMD_CHEATING;
1995#ifdef FREECIV_DEBUG
1996 case AI_LEVEL_EXPERIMENTAL : return CMD_EXPERIMENTAL;
1997#endif /* FREECIV_DEBUG */
1998 case AI_LEVEL_COUNT : return CMD_NORMAL;
1999 }
2000 log_error("Unknown AI level variant: %d.", level);
2001 return CMD_NORMAL;
2002}
2003
2004/**********************************************************************/
2007void set_ai_level_direct(struct player *pplayer, enum ai_level level)
2008{
2009 set_ai_level_directer(pplayer, level);
2010 send_player_info_c(pplayer, NULL);
2012 _("Player '%s' now has AI skill level '%s'."),
2013 player_name(pplayer),
2014 ai_level_translated_name(level));
2015
2016}
2017
2018/**********************************************************************/
2021static bool set_ai_level_named(struct connection *caller, const char *name,
2022 const char *level_name, bool check)
2023{
2024 enum ai_level level = ai_level_by_name(level_name, fc_strcasecmp);
2025
2026 return set_ai_level(caller, name, level, check);
2027}
2028
2029/**********************************************************************/
2032static bool set_ai_level(struct connection *caller, const char *name,
2033 enum ai_level level, bool check)
2034{
2035 enum m_pre_result match_result;
2036 struct player *pplayer;
2037
2038 fc_assert_ret_val(level > 0 && level < 11, FALSE);
2039
2040 pplayer = player_by_name_prefix(name, &match_result);
2041
2042 if (pplayer) {
2043 if (is_ai(pplayer)) {
2044 if (check) {
2045 return TRUE;
2046 }
2047 set_ai_level_directer(pplayer, level);
2048 send_player_info_c(pplayer, NULL);
2049 cmd_reply(cmd_of_level(level), caller, C_OK,
2050 _("Player '%s' now has AI skill level '%s'."),
2051 player_name(pplayer),
2052 ai_level_translated_name(level));
2053 } else {
2055 _("%s is not controlled by the AI."),
2056 player_name(pplayer));
2057 return FALSE;
2058 }
2059 } else if (match_result == M_PRE_EMPTY) {
2060 if (check) {
2061 return TRUE;
2062 }
2063 players_iterate(cplayer) {
2064 if (is_ai(cplayer)) {
2065 set_ai_level_directer(cplayer, level);
2066 send_player_info_c(cplayer, NULL);
2067 cmd_reply(cmd_of_level(level), caller, C_OK,
2068 _("Player '%s' now has AI skill level '%s'."),
2069 player_name(cplayer),
2070 ai_level_translated_name(level));
2071 }
2074 send_game_info(NULL);
2075 cmd_reply(cmd_of_level(level), caller, C_OK,
2076 _("Default AI skill level set to '%s'."),
2077 ai_level_translated_name(level));
2078 } else {
2079 cmd_reply_no_such_player(cmd_of_level(level), caller, name, match_result);
2080 return FALSE;
2081 }
2082 return TRUE;
2083}
2084
2085/**********************************************************************/
2088static bool away_command(struct connection *caller, bool check)
2089{
2090 struct player *pplayer;
2091
2092 if (caller == NULL) {
2093 cmd_reply(CMD_AWAY, caller, C_FAIL, _("This command is client only."));
2094 return FALSE;
2095 }
2096
2097 if (!conn_controls_player(caller)) {
2098 /* This happens for detached or observer connections. */
2099 cmd_reply(CMD_AWAY, caller, C_FAIL,
2100 _("Only players may use the away command."));
2101 return FALSE;
2102 }
2103
2104 if (check) {
2105 return TRUE;
2106 }
2107
2108 pplayer = conn_get_player(caller);
2109 if (is_human(pplayer)) {
2110 cmd_reply(CMD_AWAY, caller, C_OK,
2111 _("%s set to away mode."), player_name(pplayer));
2112 player_set_to_ai_mode(pplayer, AI_LEVEL_AWAY);
2113 fc_assert(!is_human(pplayer));
2114 } else {
2115 cmd_reply(CMD_AWAY, caller, C_OK,
2116 _("%s returned to game."), player_name(pplayer));
2118 fc_assert(is_human(pplayer));
2119 }
2120
2122
2123 return TRUE;
2124}
2125
2126/**********************************************************************/
2129static void show_ruleset_info(struct connection *caller, enum command_id cmd,
2130 bool check, int read_recursion)
2131{
2132 char *show_arg = "changed";
2133
2134 /* show changed settings only at the top level of recursion */
2135 if (read_recursion != 0) {
2136 return;
2137 }
2138
2139 show_settings(caller, cmd, show_arg, check);
2140
2141 if (game.ruleset_summary != NULL) {
2143
2145 cmd_reply(cmd, caller, C_COMMENT, "%s", translated);
2146 cmd_reply(cmd, caller, C_COMMENT, horiz_line);
2147 free(translated);
2148 }
2149}
2150
2151/**********************************************************************/
2154static bool show_command(struct connection *caller, char *str, bool check)
2155{
2156 return show_settings(caller, CMD_SHOW, str, check);
2157}
2158
2159/**********************************************************************/
2164static bool show_settings(struct connection *caller,
2165 enum command_id called_as,
2166 char *str, bool check)
2167{
2168 int cmd;
2169 enum sset_level level = SSET_ALL;
2170 size_t clen = 0;
2171
2173 if (str[0] != '\0') {
2174 /* In "/show forests", figure out that it's the forests option we're
2175 * looking at. */
2176 cmd = lookup_option(str);
2177 if (cmd >= 0) {
2178 /* Ignore levels when a particular option is specified. */
2179 level = SSET_NONE;
2180
2181 if (!setting_is_visible(setting_by_number(cmd), caller)) {
2182 cmd_reply(called_as, caller, C_FAIL,
2183 _("Sorry, you do not have access to view option '%s'."),
2184 str);
2185 return FALSE;
2186 }
2187 }
2188
2189 /* Valid negative values for 'cmd' are defined as LOOKUP_OPTION_*. */
2190 switch (cmd) {
2192 cmd_reply(called_as, caller, C_FAIL, _("Unknown option '%s'."), str);
2193 return FALSE;
2195 /* Allow ambiguous: show all matching. */
2196 clen = strlen(str);
2197 break;
2199 /* Option level. */
2201 break;
2203 /* Ruleset. */
2204 cmd_reply(called_as, caller, C_COMMENT,
2205 _("Current ruleset directory is \"%s\""),
2207 return TRUE;
2208 }
2209 } else {
2210 /* to indicate that no command was specified */
2212 /* Use vital level by default. */
2213 level = SSET_VITAL;
2214 }
2215
2217 || cmd == LOOKUP_OPTION_LEVEL_NAME
2218 || cmd == LOOKUP_OPTION_NO_RESULT, FALSE);
2219
2220#define cmd_reply_show(string) \
2221 cmd_reply(called_as, caller, C_COMMENT, "%s", string)
2222
2223 {
2224 const char *heading = NULL;
2225 switch (level) {
2226 case SSET_NONE:
2227 break;
2228 case SSET_CHANGED:
2229 heading = _("All options with non-default values");
2230 break;
2231 case SSET_ALL:
2232 heading = _("All options");
2233 break;
2234 case SSET_VITAL:
2235 heading = _("Vital options");
2236 break;
2237 case SSET_SITUATIONAL:
2238 heading = _("Situational options");
2239 break;
2240 case SSET_RARE:
2241 heading = _("Rarely used options");
2242 break;
2243 case SSET_LOCKED:
2244 heading = _("Options locked by the ruleset");
2245 break;
2246 case OLEVELS_NUM:
2247 /* nothing */
2248 break;
2249 }
2250 if (heading) {
2252 cmd_reply_show(heading);
2253 }
2254 }
2256 cmd_reply_show(_("In the column '##' the status of the option is shown:"));
2257 cmd_reply_show(_(" - a '!' means the option is locked by the ruleset."));
2258 cmd_reply_show(_(" - a '+' means you may change the option."));
2259 cmd_reply_show(_(" - a '~' means that option follows default value."));
2260 cmd_reply_show(_(" - a '=' means the value is same as default."));
2262 cmd_reply(called_as, caller, C_COMMENT, _("%-*s ## value (min, max)"),
2263 OPTION_NAME_SPACE, _("Option"));
2265
2266 /* Update changed and locked levels. */
2268
2269 switch (level) {
2270 case SSET_NONE:
2271 /* Show _one_ setting. */
2272 fc_assert_ret_val(0 <= cmd, FALSE);
2273 {
2274 struct setting *pset = setting_by_number(cmd);
2275
2276 show_settings_one(caller, called_as, pset);
2277 }
2278 break;
2279 case SSET_CHANGED:
2280 case SSET_ALL:
2281 case SSET_VITAL:
2282 case SSET_SITUATIONAL:
2283 case SSET_RARE:
2284 case SSET_LOCKED:
2285 settings_iterate(level, pset) {
2286 if (!setting_is_visible(pset, caller)) {
2287 continue;
2288 }
2289
2290 if (LOOKUP_OPTION_AMBIGUOUS == cmd
2291 && 0 != fc_strncasecmp(setting_name(pset), str, clen)) {
2292 continue;
2293 }
2294
2295 show_settings_one(caller, called_as, pset);
2297 break;
2298 case OLEVELS_NUM:
2299 /* nothing */
2300 break;
2301 }
2302
2304 /* Only emit this additional help for bona fide 'show' command */
2305 if (called_as == CMD_SHOW) {
2306 cmd_reply_show(_("A help text for each option is available via 'help "
2307 "<option>'."));
2309 if (level == SSET_VITAL) {
2310 cmd_reply_show(_("Try 'show situational' or 'show rare' to show "
2311 "more options.\n"
2312 "Try 'show changed' to show settings with "
2313 "non-default values.\n"
2314 "Try 'show locked' to show settings locked "
2315 "by the ruleset."));
2317 }
2318 }
2319 return TRUE;
2320#undef cmd_reply_show
2321}
2322
2323/**********************************************************************/
2336static void show_settings_one(struct connection *caller, enum command_id cmd,
2337 struct setting *pset)
2338{
2339 char buf[MAX_LEN_CONSOLE_LINE] = "", value[MAX_LEN_CONSOLE_LINE] = "";
2340 bool is_changed;
2341 static char prefix[OPTION_NAME_SPACE + 4 + 1] = "";
2342 char defaultness;
2343
2344 fc_assert_ret(pset != NULL);
2345
2346 is_changed = setting_non_default(pset);
2347 setting_value_name(pset, TRUE, value, sizeof(value));
2348
2349 /* Wrap long option values, such as bitwise options */
2350 fc_break_lines(value, LINE_BREAK - (sizeof(prefix)-1));
2351
2352 if (prefix[0] == '\0') {
2353 memset(prefix, ' ', sizeof(prefix)-1);
2354 }
2355
2356 if (is_changed) {
2357 /* Emphasizes the changed option. */
2358 /* Apply tags to each line fragment. */
2359 size_t startpos = 0;
2360 char *nl;
2361
2362 do {
2363 nl = strchr(value + startpos, '\n');
2364 featured_text_apply_tag(value, buf, sizeof(buf), TTT_COLOR,
2365 startpos, nl ? nl - value : FT_OFFSET_UNSET,
2366 ftc_changed);
2367 sz_strlcpy(value, buf);
2368 if (nl) {
2369 char *p = strchr(nl, '\n');
2370
2371 fc_assert_action(p != NULL, break);
2372 startpos = p + 1 - value;
2373 }
2374 } while (nl);
2375 }
2376
2377 if (SST_INT == setting_type(pset)) {
2378 /* Add the range. */
2379 cat_snprintf(value, sizeof(value), " (%d, %d)",
2380 setting_int_min(pset), setting_int_max(pset));
2381 }
2382
2383 if (setting_get_setdef(pset) == SETDEF_INTERNAL) {
2384 defaultness = '~';
2385 } else if (is_changed) {
2386 defaultness = ' ';
2387 } else {
2388 defaultness = '=';
2389 }
2390
2391 cmd_reply_prefix(cmd, caller, C_COMMENT, prefix, "%-*s %c%c %s",
2393 setting_status(caller, pset), defaultness,
2394 value);
2395}
2396
2397/**********************************************************************/
2400static bool team_command(struct connection *caller, char *str, bool check)
2401{
2402 struct player *pplayer;
2403 enum m_pre_result match_result;
2404 char buf[MAX_LEN_CONSOLE_LINE];
2405 char *arg[2];
2406 int ntokens = 0, i;
2407 bool res = FALSE;
2408 struct team_slot *tslot;
2409
2410 if (game_was_started()) {
2411 cmd_reply(CMD_TEAM, caller, C_SYNTAX,
2412 _("Cannot change teams once game has begun."));
2413 return FALSE;
2414 }
2415
2416 if (str != NULL || strlen(str) > 0) {
2417 sz_strlcpy(buf, str);
2418 ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS);
2419 }
2420 if (ntokens != 2) {
2421 cmd_reply(CMD_TEAM, caller, C_SYNTAX,
2422 _("Undefined argument. Usage:\n%s"),
2424 goto cleanup;
2425 }
2426
2427 pplayer = player_by_name_prefix(arg[0], &match_result);
2428 if (pplayer == NULL) {
2429 cmd_reply_no_such_player(CMD_TEAM, caller, arg[0], match_result);
2430 goto cleanup;
2431 }
2432
2433 tslot = team_slot_by_rule_name(arg[1]);
2434 if (NULL == tslot) {
2435 int teamno;
2436
2437 if (str_to_int(arg[1], &teamno)) {
2438 tslot = team_slot_by_number(teamno);
2439 }
2440 }
2441
2442 if (NULL == tslot) {
2443 cmd_reply(CMD_TEAM, caller, C_SYNTAX,
2444 _("No such team %s. Please give a "
2445 "valid team name or number."), arg[1]);
2446 goto cleanup;
2447 }
2448
2449 if (is_barbarian(pplayer)) {
2450 /* This can happen if we change team settings on a loaded game. */
2451 cmd_reply(CMD_TEAM, caller, C_SYNTAX, _("Cannot team a barbarian."));
2452 goto cleanup;
2453 }
2454
2455 if (!check) {
2456 /* Should never fail when slot given is not NULL */
2457 team_add_player(pplayer, team_new(tslot));
2458 send_player_info_c(pplayer, NULL);
2459 cmd_reply(CMD_TEAM, caller, C_OK, _("Player %s set to team %s."),
2460 player_name(pplayer),
2462 }
2463
2464 res = TRUE;
2465
2466 cleanup:
2467 for (i = 0; i < ntokens; i++) {
2468 free(arg[i]);
2469 }
2470
2471 return res;
2472}
2473
2474/**********************************************************************/
2477static void show_votes(struct connection *caller)
2478{
2479 int count = 0;
2480 const char *title;
2481
2482 if (vote_list != NULL) {
2484 if (NULL != caller && !conn_can_see_vote(caller, pvote)) {
2485 continue;
2486 }
2487 /* TRANS: "Vote" or "Teamvote" is voting-as-a-process. Used as
2488 * part of a sentence. */
2489 title = vote_is_team_only(pvote) ? _("Teamvote") : _("Vote");
2490 cmd_reply(CMD_VOTE, caller, C_COMMENT,
2491 /* TRANS: "[Vote|Teamvote] 3 \"proposed change\" (needs ..." */
2492 _("%s %d \"%s\" (needs %0.0f%%%s): %d for, "
2493 "%d against, and %d abstained out of %d players."),
2494 title, pvote->vote_no, pvote->cmdline,
2495 MIN(100, pvote->need_pc * 100 + 1),
2496 /* TRANS: preserve leading space */
2497 pvote->flags & VCF_NODISSENT ? _(" no dissent") : "",
2498 pvote->yes, pvote->no, pvote->abstain, count_voters(pvote));
2499 count++;
2501 }
2502
2503 if (count == 0) {
2504 cmd_reply(CMD_VOTE, caller, C_COMMENT,
2505 _("There are no votes going on."));
2506 }
2507}
2508
2509/**********************************************************************/
2512static const char *const vote_args[] = {
2513 "yes",
2514 "no",
2515 "abstain",
2516 NULL
2517};
2518static const char *vote_arg_accessor(int i)
2519{
2520 return vote_args[i];
2521}
2522
2523/**********************************************************************/
2526static bool vote_command(struct connection *caller, char *str,
2527 bool check)
2528{
2529 char buf[MAX_LEN_CONSOLE_LINE];
2530 char *arg[2];
2531 int ntokens = 0, i = 0, which = -1;
2532 enum m_pre_result match_result;
2533 struct vote *pvote = NULL;
2534 bool res = FALSE;
2535
2536 if (check) {
2537 /* This should never happen, since /vote must always be
2538 * set to ALLOW_BASIC or less. But just in case... */
2539 return FALSE;
2540 }
2541
2542 sz_strlcpy(buf, str);
2543 ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS);
2544
2545 if (ntokens == 0) {
2546 show_votes(caller);
2547 goto CLEANUP;
2548 } else if (!conn_can_vote(caller, NULL)) {
2549 cmd_reply(CMD_VOTE, caller, C_FAIL,
2550 _("You are not allowed to use this command."));
2551 goto CLEANUP;
2552 }
2553
2554 match_result = match_prefix(vote_arg_accessor, VOTE_NUM, 0,
2555 fc_strncasecmp, NULL, arg[0], &i);
2556
2557 if (match_result == M_PRE_AMBIGUOUS) {
2558 cmd_reply(CMD_VOTE, caller, C_SYNTAX,
2559 _("The argument \"%s\" is ambiguous."), arg[0]);
2560 goto CLEANUP;
2561 } else if (match_result > M_PRE_AMBIGUOUS) {
2562 /* Failed */
2563 cmd_reply(CMD_VOTE, caller, C_SYNTAX,
2564 _("Undefined argument. Usage:\n%s"),
2566 goto CLEANUP;
2567 }
2568
2569 if (ntokens == 1) {
2570 /* Applies to last vote */
2572 which = vote_number_sequence;
2573 } else {
2574 int num_votes = vote_list_size(vote_list);
2575 if (num_votes == 0) {
2576 cmd_reply(CMD_VOTE, caller, C_FAIL, _("There are no votes running."));
2577 } else {
2578 /* TRANS: "vote" as a process */
2579 cmd_reply(CMD_VOTE, caller, C_FAIL, _("No legal last vote (%d %s)."),
2580 num_votes, PL_("other vote running", "other votes running",
2581 num_votes));
2582 }
2583 goto CLEANUP;
2584 }
2585 } else {
2586 if (!str_to_int(arg[1], &which)) {
2587 cmd_reply(CMD_VOTE, caller, C_SYNTAX, _("Value must be an integer."));
2588 goto CLEANUP;
2589 }
2590 }
2591
2592 if (!(pvote = get_vote_by_no(which))) {
2593 /* TRANS: "vote" as a process */
2594 cmd_reply(CMD_VOTE, caller, C_FAIL, _("No such vote (%d)."), which);
2595 goto CLEANUP;
2596 }
2597
2598 if (!conn_can_vote(caller, pvote)) {
2599 cmd_reply(CMD_VOTE, caller, C_FAIL,
2600 _("You are not allowed to vote on that."));
2601 goto CLEANUP;
2602 }
2603
2604 if (i == VOTE_YES) {
2605 cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted for \"%s\""),
2606 pvote->cmdline);
2607 connection_vote(caller, pvote, VOTE_YES);
2608 } else if (i == VOTE_NO) {
2609 cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted against \"%s\""),
2610 pvote->cmdline);
2611 connection_vote(caller, pvote, VOTE_NO);
2612 } else if (i == VOTE_ABSTAIN) {
2613 cmd_reply(CMD_VOTE, caller, C_COMMENT,
2614 _("You abstained from voting on \"%s\""), pvote->cmdline);
2615 connection_vote(caller, pvote, VOTE_ABSTAIN);
2616 } else {
2617 /* Must never happen. */
2618 fc_assert_action(FALSE, goto CLEANUP);
2619 }
2620
2621 res = TRUE;
2622
2623CLEANUP:
2624 free_tokens(arg, ntokens);
2625 return res;
2626}
2627
2628/**********************************************************************/
2631static bool cancelvote_command(struct connection *caller,
2632 char *arg, bool check)
2633{
2634 struct vote *pvote = NULL;
2635 int vote_no;
2636
2637 if (check) {
2638 /* This should never happen anyway, since /cancelvote
2639 * is set to ALLOW_BASIC in both pregame and while the
2640 * game is running. */
2641 return FALSE;
2642 }
2643
2645
2646 if (arg[0] == '\0') {
2647 if (caller == NULL) {
2648 /* Server prompt */
2650 /* TRANS: "vote" as a process */
2651 _("Missing argument <vote number> or "
2652 "the string \"all\"."));
2653 return FALSE;
2654 }
2655 /* The caller is canceling their own vote. */
2656 if (!(pvote = get_vote_by_caller(caller))) {
2658 _("You don't have any vote going on."));
2659 return FALSE;
2660 }
2661 } else if (fc_strcasecmp(arg, "all") == 0) {
2662 /* Cancel all votes (needs some privileges). */
2663 if (vote_list_size(vote_list) == 0) {
2665 _("There isn't any vote going on."));
2666 return FALSE;
2667 } else if (!caller || conn_get_access(caller) >= ALLOW_ADMIN) {
2669 notify_conn(NULL, NULL, E_VOTE_ABORTED, ftc_server,
2670 /* TRANS: "votes" as a process */
2671 _("All votes have been removed."));
2672 return TRUE;
2673 } else {
2675 _("You are not allowed to use this command."));
2676 return FALSE;
2677 }
2678 } else if (str_to_int(arg, &vote_no)) {
2679 /* Cancel one particular vote (needs some privileges if the vote
2680 * is not owned). */
2681 if (!(pvote = get_vote_by_no(vote_no))) {
2683 /* TRANS: "vote" as a process */
2684 _("No such vote (%d)."), vote_no);
2685 return FALSE;
2686 } else if (caller && conn_get_access(caller) < ALLOW_ADMIN
2687 && caller->id != pvote->caller_id) {
2689 /* TRANS: "vote" as a process */
2690 _("You are not allowed to cancel this vote (%d)."),
2691 vote_no);
2692 return FALSE;
2693 }
2694 } else {
2696 /* TRANS: "vote" as a process */
2697 _("Usage: /cancelvote [<vote number>|all]"));
2698 return FALSE;
2699 }
2700
2701 fc_assert_ret_val(NULL != pvote, FALSE);
2702
2703 if (caller) {
2705 NULL, E_VOTE_ABORTED, ftc_server,
2706 /* TRANS: "vote" as a process */
2707 _("%s has canceled the vote \"%s\" (number %d)."),
2708 caller->username, pvote->cmdline, pvote->vote_no);
2709 } else {
2710 /* Server prompt */
2712 NULL, E_VOTE_ABORTED, ftc_server,
2713 /* TRANS: "vote" as a process */
2714 _("The vote \"%s\" (number %d) has been canceled."),
2715 pvote->cmdline, pvote->vote_no);
2716 }
2717 /* Make it after, prevent crashs about a free pointer (pvote). */
2718 remove_vote(pvote);
2719
2720 return TRUE;
2721}
2722
2723/**********************************************************************/
2726static bool debug_command(struct connection *caller, char *str,
2727 bool check)
2728{
2729 char buf[MAX_LEN_CONSOLE_LINE];
2730 char *arg[3];
2731 int ntokens = 0, i;
2732
2733 if (game.info.is_new_game) {
2734 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2735 _("Can only use this command once game has begun."));
2736 return FALSE;
2737 }
2738 if (check) {
2739 return TRUE; /* whatever! */
2740 }
2741
2742 if (str != NULL && strlen(str) > 0) {
2743 sz_strlcpy(buf, str);
2744 ntokens = get_tokens(buf, arg, 3, TOKEN_DELIMITERS);
2745 } else {
2746 ntokens = 0;
2747 }
2748
2749 if (ntokens > 0 && strcmp(arg[0], "diplomacy") == 0) {
2750 struct player *pplayer;
2751 enum m_pre_result match_result;
2752
2753 if (ntokens != 2) {
2754 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2755 _("Undefined argument. Usage:\n%s"),
2757 goto cleanup;
2758 }
2759 pplayer = player_by_name_prefix(arg[1], &match_result);
2760 if (pplayer == NULL) {
2761 cmd_reply_no_such_player(CMD_DEBUG, caller, arg[1], match_result);
2762 goto cleanup;
2763 }
2766 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s diplomacy no longer debugged"),
2767 player_name(pplayer));
2768 } else {
2770 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s diplomacy debugged"),
2771 player_name(pplayer));
2772 /* TODO: print some info about the player here */
2773 }
2774 } else if (ntokens > 0 && strcmp(arg[0], "tech") == 0) {
2775 struct player *pplayer;
2776 enum m_pre_result match_result;
2777
2778 if (ntokens != 2) {
2779 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2780 _("Undefined argument. Usage:\n%s"),
2782 goto cleanup;
2783 }
2784 pplayer = player_by_name_prefix(arg[1], &match_result);
2785 if (pplayer == NULL) {
2786 cmd_reply_no_such_player(CMD_DEBUG, caller, arg[1], match_result);
2787 goto cleanup;
2788 }
2789 if (BV_ISSET(pplayer->server.debug, PLAYER_DEBUG_TECH)) {
2791 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s tech no longer debugged"),
2792 player_name(pplayer));
2793 } else {
2795 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s tech debugged"),
2796 player_name(pplayer));
2797 /* TODO: print some info about the player here */
2798 }
2799 } else if (ntokens > 0 && strcmp(arg[0], "info") == 0) {
2800 int cities = 0, players = 0, units = 0, citizen_count = 0;
2801
2802 players_iterate(plr) {
2803 players++;
2804 city_list_iterate(plr->cities, pcity) {
2805 cities++;
2806 citizen_count += city_size_get(pcity);
2808 units += unit_list_size(plr->units);
2810 log_normal(_("players=%d cities=%d citizens=%d units=%d"),
2811 players, cities, citizen_count, units);
2812 notify_conn(game.est_connections, NULL, E_AI_DEBUG, ftc_log,
2813 _("players=%d cities=%d citizens=%d units=%d"),
2814 players, cities, citizen_count, units);
2815 } else if (ntokens > 0 && strcmp(arg[0], "city") == 0) {
2816 int x, y;
2817 struct tile *ptile;
2818 struct city *pcity;
2819
2820 if (ntokens != 3) {
2821 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2822 _("Undefined argument. Usage:\n%s"),
2824 goto cleanup;
2825 }
2826 if (!str_to_int(arg[1], &x) || !str_to_int(arg[2], &y)) {
2827 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Value 2 & 3 must be integer."));
2828 goto cleanup;
2829 }
2830 if (!(ptile = map_pos_to_tile(&(wld.map), x, y))) {
2831 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Bad map coordinates."));
2832 goto cleanup;
2833 }
2834 pcity = tile_city(ptile);
2835 if (!pcity) {
2836 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("No city at this coordinate."));
2837 goto cleanup;
2838 }
2839 if (pcity->server.debug) {
2840 pcity->server.debug = FALSE;
2841 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s no longer debugged"),
2842 city_name_get(pcity));
2843 } else {
2844 pcity->server.debug = TRUE;
2845 CITY_LOG(LOG_NORMAL, pcity, "debugged");
2846 }
2847 } else if (ntokens > 0 && strcmp(arg[0], "units") == 0) {
2848 int x, y;
2849 struct tile *ptile;
2850
2851 if (ntokens != 3) {
2852 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2853 _("Undefined argument. Usage:\n%s"),
2855 goto cleanup;
2856 }
2857 if (!str_to_int(arg[1], &x) || !str_to_int(arg[2], &y)) {
2858 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Value 2 & 3 must be integer."));
2859 goto cleanup;
2860 }
2861 if (!(ptile = map_pos_to_tile(&(wld.map), x, y))) {
2862 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Bad map coordinates."));
2863 goto cleanup;
2864 }
2865 unit_list_iterate(ptile->units, punit) {
2866 if (punit->server.debug) {
2868 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s %s no longer debugged."),
2871 } else {
2873 UNIT_LOG(LOG_NORMAL, punit, "%s %s debugged.",
2876 }
2878 } else if (ntokens > 0 && strcmp(arg[0], "timing") == 0) {
2880 } else if (ntokens > 0 && strcmp(arg[0], "ferries") == 0) {
2883 cmd_reply(CMD_DEBUG, caller, C_OK, _("Ferry system is no longer "
2884 "in debug mode."));
2885 } else {
2887 cmd_reply(CMD_DEBUG, caller, C_OK, _("Ferry system in debug mode."));
2888 }
2889 } else if (ntokens > 0 && strcmp(arg[0], "unit") == 0) {
2890 int id;
2891 struct unit *punit;
2892
2893 if (ntokens != 2) {
2894 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2895 _("Undefined argument. Usage:\n%s"),
2897 goto cleanup;
2898 }
2899 if (!str_to_int(arg[1], &id)) {
2900 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Value 2 must be integer."));
2901 goto cleanup;
2902 }
2903 if (!(punit = game_unit_by_number(id))) {
2904 cmd_reply(CMD_DEBUG, caller, C_SYNTAX, _("Unit %d does not exist."), id);
2905 goto cleanup;
2906 }
2907 if (punit->server.debug) {
2909 cmd_reply(CMD_DEBUG, caller, C_OK, _("%s %s no longer debugged."),
2912 } else {
2914 UNIT_LOG(LOG_NORMAL, punit, "%s %s debugged.",
2917 }
2918 } else {
2919 cmd_reply(CMD_DEBUG, caller, C_SYNTAX,
2920 _("Undefined argument. Usage:\n%s"),
2922 }
2923 cleanup:
2924 for (i = 0; i < ntokens; i++) {
2925 free(arg[i]);
2926 }
2927 return TRUE;
2928}
2929
2930/**********************************************************************/
2935 struct connection *caller,
2936 char *arg)
2937{
2938 int opt = lookup_option(arg);
2939
2940 if (opt < 0) {
2941 switch (opt) {
2944 cmd_reply(cmd, caller, C_SYNTAX, _("Option '%s' not recognized."), arg);
2945 break;
2947 cmd_reply(cmd, caller, C_SYNTAX, _("Ambiguous option name."));
2948 break;
2950 cmd_reply(cmd, caller, C_SYNTAX,
2951 /* TRANS: 'rulesetdir' is the command. Do not translate. */
2952 _("Use the '%srulesetdir' command to change the ruleset "
2953 "directory."), caller ? "/" : "");
2954 break;
2955 default:
2957 break;
2958 }
2959 return NULL;
2960 }
2961
2962 return setting_by_number(opt);
2963}
2964
2965/**********************************************************************/
2968static bool set_command(struct connection *caller, char *str, bool check)
2969{
2970 char *args[2];
2971 int val, nargs;
2972 struct setting *pset;
2973 bool do_update;
2974 char reject_msg[256] = "";
2975 bool ret = FALSE;
2976
2977 /* '=' is also a valid delimiter for this function. */
2978 nargs = get_tokens(str, args, ARRAY_SIZE(args), TOKEN_DELIMITERS "=");
2979
2980 if (nargs < 2) {
2981 cmd_reply(CMD_SET, caller, C_SYNTAX,
2982 _("Undefined argument. Usage:\n%s"),
2984 goto cleanup;
2985 }
2986
2987 pset = validate_setting_arg(CMD_SET, caller, args[0]);
2988
2989 if (!pset) {
2990 /* Reason already reported. */
2991 goto cleanup;
2992 }
2993
2994 if (!setting_is_changeable(pset, caller, reject_msg, sizeof(reject_msg))
2995 && !check) {
2996 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
2997 goto cleanup;
2998 }
2999
3000 do_update = FALSE;
3001
3002 switch (setting_type(pset)) {
3003 case SST_BOOL:
3004 if (check) {
3005 if (!setting_is_changeable(pset, caller, reject_msg,
3006 sizeof(reject_msg))
3007 || (!setting_bool_validate(pset, args[1], caller,
3008 reject_msg, sizeof(reject_msg)))) {
3009 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3010 goto cleanup;
3011 }
3012 } else if (setting_bool_set(pset, args[1], caller,
3013 reject_msg, sizeof(reject_msg))) {
3014 do_update = TRUE;
3015 } else {
3016 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3017 goto cleanup;
3018 }
3019 break;
3020
3021 case SST_INT:
3022 if (!str_to_int(args[1], &val)) {
3023 cmd_reply(CMD_SET, caller, C_SYNTAX,
3024 _("The parameter %s should only contain +- and 0-9."),
3025 setting_name(pset));
3026 goto cleanup;
3027 }
3028 if (check) {
3029 if (!setting_is_changeable(pset, caller, reject_msg,
3030 sizeof(reject_msg))
3031 || !setting_int_validate(pset, val, caller, reject_msg,
3032 sizeof(reject_msg))) {
3033 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3034 goto cleanup;
3035 }
3036 } else {
3037 if (setting_int_set(pset, val, caller, reject_msg,
3038 sizeof(reject_msg))) {
3039 do_update = TRUE;
3040 } else {
3041 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3042 goto cleanup;
3043 }
3044 }
3045 break;
3046
3047 case SST_STRING:
3048 if (check) {
3049 if (!setting_is_changeable(pset, caller, reject_msg,
3050 sizeof(reject_msg))
3051 || !setting_str_validate(pset, args[1], caller, reject_msg,
3052 sizeof(reject_msg))) {
3053 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3054 goto cleanup;
3055 }
3056 } else {
3057 if (setting_str_set(pset, args[1], caller, reject_msg,
3058 sizeof(reject_msg))) {
3059 do_update = TRUE;
3060 } else {
3061 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3062 goto cleanup;
3063 }
3064 }
3065 break;
3066
3067 case SST_ENUM:
3068 if (check) {
3069 if (!setting_is_changeable(pset, caller, reject_msg,
3070 sizeof(reject_msg))
3071 || (!setting_enum_validate(pset, args[1], caller,
3072 reject_msg, sizeof(reject_msg)))) {
3073 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3074 goto cleanup;
3075 }
3076 } else if (setting_enum_set(pset, args[1], caller,
3077 reject_msg, sizeof(reject_msg))) {
3078 do_update = TRUE;
3079 } else {
3080 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3081 goto cleanup;
3082 }
3083 break;
3084
3085 case SST_BITWISE:
3086 if (check) {
3087 if (!setting_is_changeable(pset, caller, reject_msg,
3088 sizeof(reject_msg))
3089 || (!setting_bitwise_validate(pset, args[1], caller,
3090 reject_msg, sizeof(reject_msg)))) {
3091 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3092 goto cleanup;
3093 }
3094 } else if (setting_bitwise_set(pset, args[1], caller,
3095 reject_msg, sizeof(reject_msg))) {
3096 do_update = TRUE;
3097 } else {
3098 cmd_reply(CMD_SET, caller, C_FAIL, "%s", reject_msg);
3099 goto cleanup;
3100 }
3101 break;
3102
3103 case SST_COUNT:
3104 fc_assert(setting_type(pset) != SST_COUNT);
3105 goto cleanup;
3106 break;
3107 }
3108
3109 ret = TRUE; /* Looks like a success. */
3110
3111 if (!check && do_update) {
3112 /* Send only to connections able to see that. */
3113 char buf[256];
3114 struct packet_chat_msg packet;
3115
3116 package_event(&packet, NULL, E_SETTING, ftc_server,
3117 _("Console: '%s' has been set to %s."), setting_name(pset),
3118 setting_value_name(pset, TRUE, buf, sizeof(buf)));
3120 if (setting_is_visible(pset, pconn)) {
3121 send_packet_chat_msg(pconn, &packet);
3122 }
3124 /* Notify the console. */
3125 con_write(C_OK, "%s", packet.message);
3126
3127 setting_changed(pset);
3128 setting_action(pset);
3129 send_server_setting(NULL, pset);
3130 /*
3131 * send any modified game parameters to the clients -- if sent
3132 * before S_S_RUNNING, triggers a popdown_races_dialog() call
3133 * in client/packhand.c#handle_game_info()
3134 */
3135 send_game_info(NULL);
3138 }
3139
3140 cleanup:
3141 free_tokens(args, nargs);
3142 return ret;
3143}
3144
3145/**********************************************************************/
3152static bool is_allowed_to_take(struct connection *requester,
3153 struct connection *taker,
3154 struct player *pplayer, bool will_obs,
3155 char *msg, size_t msg_len)
3156{
3157 const char *allow;
3158
3159 if (!pplayer && !will_obs) {
3160 /* Auto-taking a new player */
3161
3162 if (game_was_started()) {
3163 fc_strlcpy(msg, _("You cannot take a new player at this time."),
3164 msg_len);
3165 return FALSE;
3166 }
3167
3169 fc_snprintf(msg, msg_len,
3170 /* TRANS: Do not translate "maxplayers". */
3171 PL_("You cannot take a new player because "
3172 "the maximum of %d player has already "
3173 "been reached (maxplayers setting).",
3174 "You cannot take a new player because "
3175 "the maximum of %d players has already "
3176 "been reached (maxplayers setting).",
3179 return FALSE;
3180 }
3181
3182 if (player_count() >= player_slot_count()) {
3183 fc_strlcpy(msg, _("You cannot take a new player because there "
3184 "are no free player slots."),
3185 msg_len);
3186 return FALSE;
3187 }
3188
3189 return TRUE;
3190
3191 }
3192
3193#ifdef HAVE_FCDB
3194 if (srvarg.fcdb_enabled) {
3195 bool ok = FALSE;
3196
3197 if (script_fcdb_call("user_take", requester, taker, pplayer, will_obs,
3198 &ok) && ok) {
3199 return TRUE;
3200 }
3201 }
3202#endif
3203
3204 if (!pplayer && will_obs) {
3205 /* Global observer. */
3206 if (!(allow = strchr(game.server.allow_take,
3207 (game.info.is_new_game ? 'O' : 'o')))) {
3208 fc_strlcpy(msg, _("Sorry, one can't observe globally in this game."),
3209 msg_len);
3210 return FALSE;
3211 }
3212 } else if (is_barbarian(pplayer)) {
3213 if (!(allow = strchr(game.server.allow_take, 'b'))) {
3214 if (will_obs) {
3215 fc_strlcpy(msg,
3216 _("Sorry, one can't observe barbarians in this game."),
3217 msg_len);
3218 } else {
3219 fc_strlcpy(msg, _("Sorry, one can't take barbarians in this game."),
3220 msg_len);
3221 }
3222 return FALSE;
3223 }
3224 } else if (!pplayer->is_alive) {
3225 if (!(allow = strchr(game.server.allow_take, 'd'))) {
3226 if (will_obs) {
3227 fc_strlcpy(msg,
3228 _("Sorry, one can't observe dead players in this game."),
3229 msg_len);
3230 } else {
3231 fc_strlcpy(msg,
3232 _("Sorry, one can't take dead players in this game."),
3233 msg_len);
3234 }
3235 return FALSE;
3236 }
3237 } else if (is_ai(pplayer)) {
3238 if (!(allow = strchr(game.server.allow_take,
3239 (game.info.is_new_game ? 'A' : 'a')))) {
3240 if (will_obs) {
3241 fc_strlcpy(msg,
3242 _("Sorry, one can't observe AI players in this game."),
3243 msg_len);
3244 } else {
3245 fc_strlcpy(msg, _("Sorry, one can't take AI players in this game."),
3246 msg_len);
3247 }
3248 return FALSE;
3249 }
3250 } else {
3251 if (!(allow = strchr(game.server.allow_take,
3252 (game.info.is_new_game ? 'H' : 'h')))) {
3253 if (will_obs) {
3254 fc_strlcpy(msg,
3255 _("Sorry, one can't observe human players in this game."),
3256 msg_len);
3257 } else {
3258 fc_strlcpy(msg,
3259 _("Sorry, one can't take human players in this game."),
3260 msg_len);
3261 }
3262 return FALSE;
3263 }
3264 }
3265
3266 allow++;
3267
3268 if (will_obs && (*allow == '2' || *allow == '3')) {
3269 fc_strlcpy(msg, _("Sorry, one can't observe in this game."), msg_len);
3270 return FALSE;
3271 }
3272
3273 if (!will_obs && *allow == '4') {
3274 fc_strlcpy(msg, _("Sorry, one can't take players in this game."),
3275 MAX_LEN_MSG);
3276 return FALSE;
3277 }
3278
3279 if (!will_obs && pplayer->is_connected
3280 && (*allow == '1' || *allow == '3')) {
3281 fc_strlcpy(msg, _("Sorry, one can't take players already "
3282 "connected in this game."), msg_len);
3283 return FALSE;
3284 }
3285
3286 return TRUE;
3287}
3288
3289/**********************************************************************/
3294static bool observe_command(struct connection *caller, char *str, bool check)
3295{
3296 int i = 0, ntokens = 0;
3297 char buf[MAX_LEN_CONSOLE_LINE], *arg[2], msg[MAX_LEN_MSG];
3298 bool is_newgame = !game_was_started();
3299 enum m_pre_result result;
3300 struct connection *pconn = NULL;
3301 struct player *pplayer = NULL;
3302 bool res = FALSE;
3303
3304 /******** PART I: fill pconn and pplayer ********/
3305
3306 sz_strlcpy(buf, str);
3307 ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS);
3308
3309 /* check syntax, only certain syntax if allowed depending on the caller */
3310 if (!caller && ntokens < 1) {
3311 cmd_reply(CMD_OBSERVE, caller, C_SYNTAX, _("Usage:\n%s"),
3313 goto end;
3314 }
3315
3316 if (ntokens == 2 && (caller && caller->access_level != ALLOW_HACK)) {
3318 _("Only the player name form is allowed."));
3319 goto end;
3320 }
3321
3322 /* match connection if we're console, match a player if we're not */
3323 if (ntokens == 1) {
3324 if (!caller && !(pconn = conn_by_user_prefix(arg[0], &result))) {
3325 cmd_reply_no_such_conn(CMD_OBSERVE, caller, arg[0], result);
3326 goto end;
3327 } else if (caller
3328 && !(pplayer = player_by_name_prefix(arg[0], &result))) {
3329 cmd_reply_no_such_player(CMD_OBSERVE, caller, arg[0], result);
3330 goto end;
3331 }
3332 }
3333
3334 /* get connection name then player name */
3335 if (ntokens == 2) {
3336 if (!(pconn = conn_by_user_prefix(arg[0], &result))) {
3337 cmd_reply_no_such_conn(CMD_OBSERVE, caller, arg[0], result);
3338 goto end;
3339 }
3340 if (!(pplayer = player_by_name_prefix(arg[1], &result))) {
3341 cmd_reply_no_such_player(CMD_OBSERVE, caller, arg[1], result);
3342 goto end;
3343 }
3344 }
3345
3346 /* if we can't force other connections to observe, assign us to be pconn. */
3347 if (!pconn) {
3348 pconn = caller;
3349 }
3350
3351 /* if we have no pplayer, it means that we want to be a global observer */
3352
3353 /******** PART II: do the observing ********/
3354
3355 /* check allowtake for permission */
3356 if (!is_allowed_to_take(caller, pconn, pplayer, TRUE, msg, sizeof(msg))) {
3357 cmd_reply(CMD_OBSERVE, caller, C_FAIL, "%s", msg);
3358 goto end;
3359 }
3360
3361 /* observing your own player (during pregame) makes no sense. */
3362 if (NULL != pplayer
3363 && pplayer == pconn->playing
3364 && !pconn->observer
3365 && is_newgame
3366 && !pplayer->was_created) {
3367 cmd_reply(CMD_OBSERVE, caller, C_FAIL,
3368 _("%s already controls %s. Using 'observe' would remove %s"),
3369 pconn->username,
3370 player_name(pplayer),
3371 player_name(pplayer));
3372 goto end;
3373 }
3374
3375 /* attempting to observe a player you're already observing should fail. */
3376 if (pplayer == pconn->playing && pconn->observer) {
3377 if (pplayer) {
3378 cmd_reply(CMD_OBSERVE, caller, C_FAIL,
3379 _("%s is already observing %s."),
3380 pconn->username,
3381 player_name(pplayer));
3382 } else {
3383 cmd_reply(CMD_OBSERVE, caller, C_FAIL,
3384 _("%s is already observing."),
3385 pconn->username);
3386 }
3387 goto end;
3388 }
3389
3390 res = TRUE; /* all tests passed */
3391 if (check) {
3392 goto end;
3393 }
3394
3395 /* if the connection is already attached to a player,
3396 * unattach and cleanup old player (rename, remove, etc) */
3397 if (TRUE) {
3398 char name[MAX_LEN_NAME];
3399
3400 if (pplayer) {
3401 /* if pconn->playing is removed, we'll lose pplayer */
3402 sz_strlcpy(name, player_name(pplayer));
3403 }
3404
3405 connection_detach(pconn, TRUE);
3406
3407 if (pplayer) {
3408 /* find pplayer again, the pointer might have been changed */
3409 pplayer = player_by_name(name);
3410 }
3411 }
3412
3413 /* attach pconn to new player as an observer or as global observer */
3414 if ((res = connection_attach(pconn, pplayer, TRUE))) {
3415 if (pplayer) {
3416 cmd_reply(CMD_OBSERVE, caller, C_OK, _("%s now observes %s"),
3417 pconn->username,
3418 player_name(pplayer));
3419 } else {
3420 cmd_reply(CMD_OBSERVE, caller, C_OK, _("%s now observes"),
3421 pconn->username);
3422 }
3423 }
3424
3425 end:;
3426 /* free our args */
3427 for (i = 0; i < ntokens; i++) {
3428 free(arg[i]);
3429 }
3430 return res;
3431}
3432
3433/**********************************************************************/
3442static bool take_command(struct connection *caller, char *str, bool check)
3443{
3444 int i = 0, ntokens = 0;
3445 char buf[MAX_LEN_CONSOLE_LINE], *arg[2], msg[MAX_LEN_MSG];
3446 bool is_newgame = !game_was_started();
3447 enum m_pre_result match_result;
3448 struct connection *pconn = caller;
3449 struct player *pplayer = NULL;
3450 bool res = FALSE;
3451
3452 /******** PART I: fill pconn and pplayer ********/
3453
3454 sz_strlcpy(buf, str);
3455 ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS);
3456
3457 /* check syntax */
3458 if (!caller && ntokens != 2) {
3459 cmd_reply(CMD_TAKE, caller, C_SYNTAX, _("Usage:\n%s"),
3461 goto end;
3462 }
3463
3464 if (caller && caller->access_level != ALLOW_HACK && ntokens != 1) {
3465 cmd_reply(CMD_TAKE, caller, C_SYNTAX,
3466 _("Only the player name form is allowed."));
3467 goto end;
3468 }
3469
3470 if (ntokens == 0) {
3471 cmd_reply(CMD_TAKE, caller, C_SYNTAX, _("Usage:\n%s"),
3473 goto end;
3474 }
3475
3476 if (ntokens == 2) {
3477 if (!(pconn = conn_by_user_prefix(arg[i], &match_result))) {
3478 cmd_reply_no_such_conn(CMD_TAKE, caller, arg[i], match_result);
3479 goto end;
3480 }
3481 i++; /* found a conn, now reference the second argument */
3482 }
3483
3484 if (strcmp(arg[i], "-") == 0) {
3485 if (!is_newgame) {
3486 cmd_reply(CMD_TAKE, caller, C_FAIL,
3487 _("You cannot issue \"/take -\" when "
3488 "the game has already started."));
3489 goto end;
3490 }
3491
3492 /* Find first uncontrolled player. This will return NULL if there is
3493 * no free players at the moment. Later call to
3494 * connection_attach() will create new player for such NULL
3495 * cases. */
3496 pplayer = find_uncontrolled_player();
3497 if (pplayer) {
3498 /* Make it human! */
3499 set_as_human(pplayer);
3500 }
3501 } else if (!(pplayer = player_by_name_prefix(arg[i], &match_result))) {
3502 cmd_reply_no_such_player(CMD_TAKE, caller, arg[i], match_result);
3503 goto end;
3504 }
3505
3506 /******** PART II: do the attaching ********/
3507
3508 /* Take not possible if the player is involved in a delegation (either
3509 * it's being controlled, or it's been put aside by the delegate). */
3510 if (player_delegation_active(pplayer)) {
3511 cmd_reply(CMD_TAKE, caller, C_FAIL, _("A delegation is active for player "
3512 "'%s'. /take not possible."),
3513 player_name(pplayer));
3514 goto end;
3515 }
3516
3517 /* check allowtake for permission */
3518 if (!is_allowed_to_take(caller, pconn, pplayer, FALSE, msg, sizeof(msg))) {
3519 cmd_reply(CMD_TAKE, caller, C_FAIL, "%s", msg);
3520 goto end;
3521 }
3522
3523 /* taking your own player makes no sense. */
3524 if ((NULL != pplayer && !pconn->observer && pplayer == pconn->playing)
3525 || (NULL == pplayer && !pconn->observer && NULL != pconn->playing)) {
3526 cmd_reply(CMD_TAKE, caller, C_FAIL, _("%s already controls %s."),
3527 pconn->username,
3528 player_name(pconn->playing));
3529 goto end;
3530 }
3531
3532 /* Make sure there is free player slot if there is need to
3533 * create new player. This is necessary for previously
3534 * detached connections only. Others can reuse the slot
3535 * they first release. */
3536 if (!pplayer && !pconn->playing
3538 || normal_player_count() >= server.playable_nations)) {
3539 cmd_reply(CMD_TAKE, caller, C_FAIL,
3540 _("There is no free player slot for %s."),
3541 pconn->username);
3542 goto end;
3543 }
3545
3546 res = TRUE;
3547 if (check) {
3548 goto end;
3549 }
3550
3551 /* If the player is controlled by another user, forcibly detach
3552 * the user. */
3553 if (pplayer && pplayer->is_connected) {
3554 if (NULL == caller) {
3555 notify_conn(NULL, NULL, E_CONNECTION, ftc_server,
3556 _("Reassigned nation to %s by server console."),
3557 pconn->username);
3558 } else {
3559 notify_conn(NULL, NULL, E_CONNECTION, ftc_server,
3560 _("Reassigned nation to %s by %s."),
3561 pconn->username,
3562 caller->username);
3563 }
3564
3565 /* We are reassigning this nation, so we need to detach the current
3566 * user to set a new one. */
3567 conn_list_iterate(pplayer->connections, aconn) {
3568 if (!aconn->observer) {
3569 connection_detach(aconn, FALSE);
3570 }
3572 }
3573
3574 /* if the connection is already attached to another player,
3575 * unattach and cleanup old player (rename, remove, etc)
3576 * We may have been observing the player we now want to take */
3577 if (NULL != pconn->playing || pconn->observer) {
3578 char name[MAX_LEN_NAME];
3579
3580 if (pplayer) {
3581 /* if pconn->playing is removed, we'll lose pplayer */
3582 sz_strlcpy(name, player_name(pplayer));
3583 }
3584
3585 connection_detach(pconn, TRUE);
3586
3587 if (pplayer) {
3588 /* find pplayer again; the pointer might have been changed */
3589 pplayer = player_by_name(name);
3590 }
3591 }
3592
3593 /* Now attach to new player */
3594 if ((res = connection_attach(pconn, pplayer, FALSE))) {
3595 /* Successfully attached */
3596 pplayer = pconn->playing; /* In case pplayer was NULL. */
3597
3598 /* inform about the status before changes */
3599 cmd_reply(CMD_TAKE, caller, C_OK, _("%s now controls %s (%s, %s)."),
3600 pconn->username,
3601 player_name(pplayer),
3602 is_barbarian(pplayer)
3603 ? _("Barbarian")
3604 : is_ai(pplayer)
3605 ? _("AI")
3606 : _("Human"),
3607 pplayer->is_alive
3608 ? _("Alive")
3609 : _("Dead"));
3610 } else {
3611 cmd_reply(CMD_TAKE, caller, C_FAIL,
3612 _("%s failed to attach to any player."),
3613 pconn->username);
3614 }
3615
3616 end:;
3617 /* free our args */
3618 for (i = 0; i < ntokens; i++) {
3619 free(arg[i]);
3620 }
3621 return res;
3622}
3623
3624/**********************************************************************/
3631static bool detach_command(struct connection *caller, char *str, bool check)
3632{
3633 int i = 0, ntokens = 0;
3634 char buf[MAX_LEN_CONSOLE_LINE], *arg[1];
3635 enum m_pre_result match_result;
3636 struct connection *pconn = NULL;
3637 struct player *pplayer = NULL;
3638 bool res = FALSE;
3639
3640 sz_strlcpy(buf, str);
3641 ntokens = get_tokens(buf, arg, 1, TOKEN_DELIMITERS);
3642
3643 if (!caller && ntokens == 0) {
3644 cmd_reply(CMD_DETACH, caller, C_SYNTAX, _("Usage:\n%s"),
3646 goto end;
3647 }
3648
3649 /* match the connection if the argument was given */
3650 if (ntokens == 1
3651 && !(pconn = conn_by_user_prefix(arg[0], &match_result))) {
3652 cmd_reply_no_such_conn(CMD_DETACH, caller, arg[0], match_result);
3653 goto end;
3654 }
3655
3656 /* if no argument is given, the caller wants to detach themself */
3657 if (!pconn) {
3658 pconn = caller;
3659 }
3660
3661 /* if pconn and caller are not the same, only continue
3662 * if we're console, or we have ALLOW_HACK */
3663 if (pconn != caller && caller && caller->access_level != ALLOW_HACK) {
3664 cmd_reply(CMD_DETACH, caller, C_FAIL,
3665 _("You can not detach other users."));
3666 goto end;
3667 }
3668
3669 pplayer = pconn->playing;
3670
3671 /* must have someone to detach from... */
3672 if (!pplayer && !pconn->observer) {
3673 cmd_reply(CMD_DETACH, caller, C_FAIL,
3674 _("%s is not attached to any player."), pconn->username);
3675 goto end;
3676 }
3677
3678 res = TRUE;
3679 if (check) {
3680 goto end;
3681 }
3682
3683 if (pplayer) {
3684 cmd_reply(CMD_DETACH, caller, C_OK, _("%s detaching from %s"),
3685 pconn->username, player_name(pplayer));
3686 } else {
3687 cmd_reply(CMD_DETACH, caller, C_OK, _("%s no longer observing."),
3688 pconn->username);
3689 }
3690
3691 /* Actually do the detaching. */
3692 connection_detach(pconn, TRUE);
3693
3694 /* The user explicitly wanted to detach, so if a player is marked for
3695 * them, reset its username. */
3696 players_iterate(aplayer) {
3697 if (0 == strncmp(aplayer->username, pconn->username, MAX_LEN_NAME)) {
3698 sz_strlcpy(aplayer->username, _(ANON_USER_NAME));
3699 aplayer->unassigned_user = TRUE;
3700 send_player_info_c(aplayer, NULL);
3701 }
3703
3705
3706 end:
3707 fc_assert_ret_val(ntokens <= 1, FALSE);
3708
3709 /* free our args */
3710 for (i = 0; i < ntokens; i++) {
3711 free(arg[i]);
3712 }
3713 return res;
3714}
3715
3716/**********************************************************************/
3737bool load_command(struct connection *caller, const char *filename, bool check,
3738 bool cmdline_load)
3739{
3740 struct timer *loadtimer, *uloadtimer;
3741 struct section_file *file;
3742 char arg[MAX_LEN_PATH];
3743 struct conn_list *global_observers;
3744
3745 if (!filename || filename[0] == '\0') {
3746 cmd_reply(CMD_LOAD, caller, C_FAIL, _("Usage:\n%s"),
3748 return FALSE;
3749 }
3750 if (S_S_INITIAL != server_state()) {
3751 cmd_reply(CMD_LOAD, caller, C_FAIL,
3752 _("Cannot load a game while another is running."));
3753 return FALSE;
3754 }
3755 if (!is_safe_filename(filename) && is_restricted(caller)) {
3756 cmd_reply(CMD_LOAD, caller, C_FAIL,
3757 _("Name \"%s\" disallowed for security reasons."),
3758 filename);
3759 return FALSE;
3760 }
3761
3762 {
3763 /* It is a normal savegame or maybe a scenario */
3764 char testfile[MAX_LEN_PATH];
3765 const struct strvec *paths[] = {
3767 };
3768 const char *exts[] = {
3769 "sav", "gz", "bz2", "xz", "sav.gz", "sav.bz2", "sav.xz", "sav.zst", NULL
3770 };
3771 const char **ext, *found = NULL;
3772 const struct strvec **path;
3773
3774 if (cmdline_load) {
3775 /* Allow plain names being loaded with '--file' option, but not otherwise
3776 * (no loading of arbitrary files by unauthorized users)
3777 * Iterate through ALL paths to check for file with plain name before
3778 * looking any path with an extension, i.e., prefer plain name file
3779 * in later directory over file with extension in name in earlier
3780 * directory. */
3781 for (path = paths; !found && *path; path++) {
3782 found = fileinfoname(*path, filename);
3783 if (found != NULL) {
3784 sz_strlcpy(arg, found);
3785 }
3786 }
3787 }
3788
3789 for (path = paths; !found && *path; path++) {
3790 for (ext = exts; !found && *ext; ext++) {
3791 fc_snprintf(testfile, sizeof(testfile), "%s.%s", filename, *ext);
3792 found = fileinfoname(*path, testfile);
3793 if (found != NULL) {
3794 sz_strlcpy(arg, found);
3795 }
3796 }
3797 }
3798
3799 if (is_restricted(caller) && !found) {
3800 cmd_reply(CMD_LOAD, caller, C_FAIL, _("Cannot find savegame or "
3801 "scenario with the name \"%s\"."), filename);
3802 return FALSE;
3803 }
3804
3805 if (!found) {
3806 sz_strlcpy(arg, filename);
3807 }
3808 }
3809
3810 /* attempt to parse the file */
3811
3812 if (!(file = secfile_load(arg, FALSE))) {
3813 log_error("Error loading savefile '%s': %s", arg, secfile_error());
3814 cmd_reply(CMD_LOAD, caller, C_FAIL, _("Could not load savefile: %s"),
3815 arg);
3817 return FALSE;
3818 }
3819
3820 if (check) {
3821 return TRUE;
3822 }
3823
3824 /* Detach current players, before we blow them away. */
3825 global_observers = conn_list_new();
3827 if (pconn->playing != NULL) {
3828 connection_detach(pconn, TRUE);
3829 } else if (pconn->observer) {
3830 conn_list_append(global_observers, pconn);
3831 connection_detach(pconn, TRUE);
3832 }
3834
3836
3837 /* Now free all game data. */
3839
3840 /* Keep old ruleset value. Scenario file will either use the old value,
3841 * or to initialize new value itself. */
3843
3844 loadtimer = timer_new(TIMER_CPU, TIMER_ACTIVE);
3845 timer_start(loadtimer);
3846 uloadtimer = timer_new(TIMER_USER, TIMER_ACTIVE);
3847 timer_start(uloadtimer);
3848
3850
3851 savegame_load(file);
3853 secfile_destroy(file);
3854
3855 log_verbose("Load time: %g seconds (%g apparent)",
3856 timer_read_seconds(loadtimer), timer_read_seconds(uloadtimer));
3857 timer_destroy(loadtimer);
3858 timer_destroy(uloadtimer);
3859
3860 sanity_check();
3861
3862 log_verbose("load_command() does send_rulesets()");
3870
3871 /* Send information about the new players. */
3873 send_player_diplstate_c(NULL, NULL);
3874
3875 /* Everything seemed to load ok; spread the good news. */
3877
3878 /* Attach connections to players. Currently, this applies only
3879 * to connections that have the same username as a player. */
3881 players_iterate(pplayer) {
3882 if (strcmp(pconn->username, pplayer->username) == 0) {
3883 connection_attach(pconn, pplayer, FALSE);
3884 break;
3885 }
3888
3889 /* Reattach global observers. */
3890 conn_list_iterate(global_observers, pconn) {
3891 if (NULL == pconn->playing) {
3892 /* May have been assigned to a player before. */
3893 connection_attach(pconn, NULL, TRUE);
3894 }
3896 conn_list_destroy(global_observers);
3897
3898 (void) aifill(game.info.aifill);
3899
3900 achievements_iterate(pach) {
3901 players_iterate(pplayer) {
3902 struct packet_achievement_info pack;
3903
3904 pack.id = achievement_index(pach);
3905 pack.gained = achievement_player_has(pach, pplayer);
3906 pack.first = (pach->first == pplayer);
3907
3908 lsend_packet_achievement_info(pplayer->connections, &pack);
3911
3912 return TRUE;
3913}
3914
3915/**********************************************************************/
3924static bool set_rulesetdir(struct connection *caller, char *str, bool check,
3925 int read_recursion)
3926{
3927 char filename[512];
3928 const char *pfilename;
3929
3930 if (NULL == str || '\0' == str[0]) {
3932 _("You must provide a ruleset name. Use \"/show ruleset\" to "
3933 "see what is the current ruleset."));
3934 return FALSE;
3935 }
3936 if (game_was_started() || !map_is_empty()) {
3938 _("This setting can't be modified after the game has started."));
3940 && !game_was_started()) {
3942 /* TRANS: scenario name */
3943 _("The ruleset of \"%s\" can be changed by switching to a"
3944 " compatible ruleset before loading it."),
3946 }
3947 return FALSE;
3948 }
3949
3950 if (strcmp(str, game.server.rulesetdir) == 0) {
3952 _("Ruleset directory is already \"%s\""), str);
3953 return FALSE;
3954 }
3955
3956 if (is_restricted(caller)
3957 && (!is_safe_filename(str) || strchr(str, '.'))) {
3959 _("Name \"%s\" disallowed for security reasons."),
3960 str);
3961 return FALSE;
3962 }
3963
3964 fc_snprintf(filename, sizeof(filename), "%s", str);
3965 pfilename = fileinfoname(get_data_dirs(), filename);
3966 if (!pfilename) {
3968 _("Ruleset directory \"%s\" not found"), str);
3969 return FALSE;
3970 }
3971
3972 if (!check) {
3973 bool success = TRUE;
3974 char old[512];
3975
3977 log_verbose("set_rulesetdir() does load_rulesets() with \"%s\"", str);
3979
3980 /* load the ruleset (and game settings defined in the ruleset) */
3982 if (!load_rulesets(old, NULL, FALSE, NULL, TRUE, FALSE, TRUE)) {
3983 success = FALSE;
3984
3985 /* While loading of the requested ruleset failed, we might
3986 * have changed ruleset from third one to default. Handle
3987 * rest of the ruleset changing accordingly. */
3988 }
3989
3990 if (game.est_connections) {
3991 /* Now that the rulesets are loaded we immediately send updates to any
3992 * connected clients. */
3994 }
3995 /* show ruleset summary and list changed values */
3996 show_ruleset_info(caller, CMD_RULESETDIR, check, read_recursion);
3998
3999 if (success) {
4000 cmd_reply(CMD_RULESETDIR, caller, C_OK,
4001 _("Ruleset directory set to \"%s\""), str);
4002 } else {
4004 _("Failed loading rulesets from directory \"%s\", using \"%s\""),
4006 }
4007
4008 return success;
4009 }
4010
4011 return TRUE;
4012}
4013
4014/**********************************************************************/
4017static bool ignore_command(struct connection *caller, char *str, bool check)
4018{
4019 char buf[128];
4020 struct conn_pattern *ppattern;
4021
4022 if (NULL == caller) {
4023 cmd_reply(CMD_IGNORE, caller, C_FAIL,
4024 _("That would be rather silly, since you are not a player."));
4025 return FALSE;
4026 }
4027
4028 ppattern = conn_pattern_from_string(str, CPT_USER, buf, sizeof(buf));
4029 if (NULL == ppattern) {
4030 cmd_reply(CMD_IGNORE, caller, C_SYNTAX,
4031 _("%s. Try /help ignore"), buf);
4032 return FALSE;
4033 }
4034
4035 if (check) {
4036 conn_pattern_destroy(ppattern);
4037 return TRUE;
4038 }
4039
4040 conn_pattern_to_string(ppattern, buf, sizeof(buf));
4041 conn_pattern_list_append(caller->server.ignore_list, ppattern);
4043 _("Added pattern %s as entry %d to your ignore list."),
4044 buf, conn_pattern_list_size(caller->server.ignore_list));
4045
4046 return TRUE;
4047}
4048
4049/**********************************************************************/
4052static bool unignore_command(struct connection *caller,
4053 char *str, bool check)
4054{
4055 char buf[128], *c;
4056 int first, last, n;
4057
4058 if (!caller) {
4059 cmd_reply(CMD_IGNORE, caller, C_FAIL,
4060 _("That would be rather silly, since you are not a player."));
4061 return FALSE;
4062 }
4063
4064 sz_strlcpy(buf, str);
4066
4067 n = conn_pattern_list_size(caller->server.ignore_list);
4068 if (n == 0) {
4069 cmd_reply(CMD_UNIGNORE, caller, C_FAIL, _("Your ignore list is empty."));
4070 return FALSE;
4071 }
4072
4073 /* Parse the range. */
4074 if ('\0' == buf[0]) {
4076 _("Missing range. Try /help unignore."));
4077 return FALSE;
4078 } else if ((c = strchr(buf, '-'))) {
4079 *c++ = '\0';
4080 if ('\0' == buf[0]) {
4081 first = 1;
4082 } else if (!str_to_int(buf, &first)) {
4083 *--c = '-';
4085 _("\"%s\" is not a valid range. Try /help unignore."), buf);
4086 return FALSE;
4087 }
4088 if ('\0' == *c) {
4089 last = n;
4090 } else if (!str_to_int(c, &last)) {
4091 *--c = '-';
4093 _("\"%s\" is not a valid range. Try /help unignore."), buf);
4094 return FALSE;
4095 }
4096 } else {
4097 if (!str_to_int(buf, &first)) {
4099 _("\"%s\" is not a valid range. Try /help unignore."), buf);
4100 return FALSE;
4101 }
4102 last = first;
4103 }
4104
4105 if (!(1 <= first && first <= last && last <= n)) {
4106 if (first == last) {
4107 cmd_reply(CMD_UNIGNORE, caller, C_FAIL,
4108 _("Invalid entry number: %d."), first);
4109 } else {
4110 cmd_reply(CMD_UNIGNORE, caller, C_FAIL,
4111 _("Invalid range: %d to %d."), first, last);
4112 }
4113 return FALSE;
4114 }
4115
4116 if (check) {
4117 return TRUE;
4118 }
4119
4120 n = 1;
4121 conn_pattern_list_iterate(caller->server.ignore_list, ppattern) {
4122 if (first <= n) {
4123 conn_pattern_to_string(ppattern, buf, sizeof(buf));
4125 _("Removed pattern %s (entry %d) from your ignore list."),
4126 buf, n);
4127 conn_pattern_list_remove(caller->server.ignore_list, ppattern);
4128 }
4129 n++;
4130 if (n > last) {
4131 break;
4132 }
4134
4135 return TRUE;
4136}
4137
4138/**********************************************************************/
4141static bool playercolor_command(struct connection *caller,
4142 char *str, bool check)
4143{
4144 enum m_pre_result match_result;
4145 struct player *pplayer;
4146 struct rgbcolor *prgbcolor = NULL;
4147 int ntokens = 0;
4148 char *token[2];
4149 bool ret = TRUE;
4150
4151 ntokens = get_tokens(str, token, 2, TOKEN_DELIMITERS);
4152
4153 if (ntokens != 2) {
4155 _("Two arguments needed. See '/help playercolor'."));
4156 ret = FALSE;
4157 goto cleanup;
4158 }
4159
4160 pplayer = player_by_name_prefix(token[0], &match_result);
4161
4162 if (!pplayer) {
4163 cmd_reply_no_such_player(CMD_PLAYERCOLOR, caller, token[0], match_result);
4164 ret = FALSE;
4165 goto cleanup;
4166 }
4167
4168 {
4169 const char *reason;
4170 if (!player_color_changeable(pplayer, &reason)) {
4171 cmd_reply(CMD_PLAYERCOLOR, caller, C_FAIL, "%s", reason);
4172 ret = FALSE;
4173 goto cleanup;
4174 }
4175 }
4176
4177 if (0 == fc_strcasecmp(token[1], "reset")) {
4178 if (!game_was_started()) {
4179 prgbcolor = NULL;
4180 } else {
4182 _("Can only unset player color before game starts."));
4183 ret = FALSE;
4184 goto cleanup;
4185 }
4186 } else if (!rgbcolor_from_hex(&prgbcolor, token[1])) {
4188 _("Invalid player color definition. See '/help playercolor'."));
4189 ret = FALSE;
4190 goto cleanup;
4191 }
4192
4193 if (prgbcolor != NULL) {
4194 players_iterate(pother) {
4195 if (pother != pplayer && pother->rgb != NULL
4196 && rgbcolors_are_equal(pother->rgb, prgbcolor)) {
4198 /* TRANS: "... [c0ffee] for Caesar ... to Hammurabi." */
4199 _("Warning: new color [%s] for %s is identical to %s."),
4200 player_color_ftstr(pother), player_name(pplayer),
4201 player_name(pother));
4202 }
4204 }
4205
4206 if (check) {
4207 goto cleanup;
4208 }
4209
4210 server_player_set_color(pplayer, prgbcolor);
4212 _("Color of player %s set to [%s]."), player_name(pplayer),
4213 player_color_ftstr(pplayer));
4214
4215 cleanup:
4216
4217 rgbcolor_destroy(prgbcolor);
4218 free_tokens(token, ntokens);
4219
4220 return ret;
4221}
4222
4223/**********************************************************************/
4226static bool playernation_command(struct connection *caller,
4227 char *str, bool check)
4228{
4229 enum m_pre_result match_result;
4230 struct player *pplayer;
4231 struct nation_type *pnation;
4232 struct nation_style *pstyle;
4233 bool is_male = FALSE;
4234 int ntokens = 0;
4235 char *token[5];
4236
4237 ntokens = get_tokens(str, token, 5, TOKEN_DELIMITERS);
4238
4239 if (ntokens == 0) {
4241 _("At least one argument needed. See '/help playernation'."));
4242 free_tokens(token, ntokens);
4243 return FALSE;
4244 }
4245
4246 if (game_was_started()) {
4248 _("Can only set player nation before game starts."));
4249 free_tokens(token, ntokens);
4250 return FALSE;
4251 }
4252
4253 pplayer = player_by_name_prefix(token[0], &match_result);
4254 if (!pplayer) {
4255 cmd_reply_no_such_player(CMD_PLAYERNATION, caller, token[0], match_result);
4256 free_tokens(token, ntokens);
4257 return FALSE;
4258 }
4259
4260 if (ntokens == 1) {
4261 if (!check) {
4263
4265 _("Nation of player %s reset."), player_name(pplayer));
4267 }
4268 } else {
4269 pnation = nation_by_rule_name(token[1]);
4270 if (pnation == NO_NATION_SELECTED) {
4272 _("Unrecognized nation: %s."), token[1]);
4273 free_tokens(token, ntokens);
4274 return FALSE;
4275 }
4276
4277 if (!client_can_pick_nation(pnation)) {
4279 _("%s nation is not available for user selection."),
4280 token[1]);
4281 free_tokens(token, ntokens);
4282 return FALSE;
4283 }
4284
4285 if (pnation->player && pnation->player != pplayer) {
4287 _("%s nation is already in use."), token[1]);
4288 free_tokens(token, ntokens);
4289 return FALSE;
4290 }
4291
4292 if (ntokens < 3) {
4294 /* TRANS: Nation resetting form of /playernation does not require sex */
4295 _("Leader sex must be given when setting nation."));
4296 free_tokens(token, ntokens);
4297 return FALSE;
4298 }
4299
4300 if (!strcmp(token[2], "0")) {
4301 is_male = FALSE;
4302 } else if (!strcmp(token[2], "1")) {
4303 is_male = TRUE;
4304 } else {
4306 _("Unrecognized gender: %s, expecting 1 or 0."), token[2]);
4307 free_tokens(token, ntokens);
4308 return FALSE;
4309 }
4310
4311 if (ntokens > 4) {
4312 pstyle = style_by_rule_name(token[4]);
4313 if (!pstyle) {
4315 _("Unrecognized style: %s."), token[4]);
4316 free_tokens(token, ntokens);
4317 return FALSE;
4318 }
4319 } else {
4320 pstyle = style_of_nation(pnation);
4321 }
4322
4323 if (!check) {
4324 char error_buf[256];
4325
4326 player_set_nation(pplayer, pnation);
4327 pplayer->style = pstyle;
4328 pplayer->is_male = is_male;
4329
4330 if (ntokens > 3) {
4331 if (!server_player_set_name_full(caller, pplayer, pnation, token[3],
4332 error_buf, sizeof(error_buf))) {
4333 cmd_reply(CMD_PLAYERNATION, caller, C_WARNING, "%s", error_buf);
4334 }
4335 } else {
4336 server_player_set_name(pplayer, token[0]);
4337 }
4339 _("Nation of player %s set to [%s]."), player_name(pplayer),
4340 nation_rule_name(pnation));
4342 }
4343 }
4344
4345 free_tokens(token, ntokens);
4346
4347 return TRUE;
4348}
4349
4350/**************************************************************************
4351 Handle quit command
4352**************************************************************************/
4353static bool quit_game(struct connection *caller, bool check)
4354{
4355 if (!check) {
4356 cmd_reply(CMD_QUIT, caller, C_OK, _("Goodbye."));
4357 server_quit();
4358 }
4359 return TRUE;
4360}
4361
4362/**********************************************************************/
4366bool handle_stdin_input(struct connection *caller, char *str)
4367{
4368 return handle_stdin_input_real(caller, str, FALSE, 0);
4369}
4370
4371/**********************************************************************/
4374bool handle_stdin_input_free(struct connection *caller, char *str)
4375{
4376 bool ret = handle_stdin_input_real(caller, str, FALSE, 0);
4377
4378 /* Since handle_stdin_input_real() returned,
4379 * we can be sure this was not freed in atexit(). */
4380 free(str);
4381
4382 return ret;
4383}
4384
4385/**********************************************************************/
4393static bool handle_stdin_input_real(struct connection *caller, char *str,
4394 bool check, int read_recursion)
4395{
4396 char full_command[MAX_LEN_CONSOLE_LINE];
4398 char *cptr_s, *cptr_d;
4399 enum command_id cmd;
4400 enum cmdlevel level;
4401
4402 /* Remove leading and trailing spaces, and server command prefix. */
4403 cptr_s = str = skip_leading_spaces(str);
4404 if ('\0' == *cptr_s || '#' == *cptr_s) {
4405 /* This appear to be a comment or blank line. */
4406 return FALSE;
4407 }
4408
4409 if (SERVER_COMMAND_PREFIX == *cptr_s) {
4410 /* Commands may be prefixed with SERVER_COMMAND_PREFIX, even when
4411 * given on the server command line. */
4412 cptr_s++;
4413 remove_leading_spaces(cptr_s);
4414 if ('\0' == *cptr_s) {
4415 /* This appear to be a blank line. */
4416 return FALSE;
4417 }
4418 }
4419 remove_trailing_spaces(cptr_s);
4420
4421 /* notify to the server console */
4422 if (!check && caller) {
4423 con_write(C_COMMENT, "%s: '%s'", caller->username, str);
4424 }
4425
4426 /* if the caller may not use any commands at all, don't waste any time */
4427 if (may_use_nothing(caller)) {
4428 cmd_reply(CMD_HELP, caller, C_FAIL,
4429 _("Sorry, you are not allowed to use server commands."));
4430 return FALSE;
4431 }
4432
4433 /* copy the full command, in case we need it for voting purposes. */
4434 sz_strlcpy(full_command, cptr_s);
4435
4436 /*
4437 * cptr_s points now to the beginning of the real command. It has
4438 * skipped leading whitespace, the SERVER_COMMAND_PREFIX and any
4439 * other non-alphanumeric characters.
4440 */
4441 for (cptr_d = command; *cptr_s != '\0' && fc_isalnum(*cptr_s)
4442 && cptr_d < command + sizeof(command) - 1; cptr_s++, cptr_d++) {
4443 *cptr_d = *cptr_s;
4444 }
4445 *cptr_d = '\0';
4446
4447 /* cptr_s now contains the arguments. */
4448 sz_strlcpy(arg, skip_leading_spaces(cptr_s));
4449
4450 cmd = command_named(command, FALSE);
4451 if (cmd == CMD_AMBIGUOUS) {
4452 cmd = command_named(command, TRUE);
4453 cmd_reply(cmd, caller, C_SYNTAX,
4454 _("Warning: '%s' interpreted as '%s', but it is ambiguous."
4455 " Try '%shelp'."),
4456 command, command_name_by_number(cmd), caller?"/":"");
4457 } else if (cmd == CMD_UNRECOGNIZED) {
4458 cmd_reply(cmd, caller, C_SYNTAX, _("Unknown command '%s%s'. "
4459 " Try '%shelp'."),
4460 caller ? "/" : "", command, caller ? "/" : "");
4461 return FALSE;
4462 }
4463
4465
4466 if (conn_can_vote(caller, NULL) && level == ALLOW_CTRL
4467 && conn_get_access(caller) == ALLOW_BASIC && !check
4468 && !vote_would_pass_immediately(caller, cmd)) {
4469 struct vote *vote;
4470 bool caller_had_vote = (NULL != get_vote_by_caller(caller));
4471
4472 /* Check if the vote command would succeed. If we already have a vote
4473 * going, cancel it in favour of the new vote command. You can only
4474 * have one vote at a time. This is done by vote_new(). */
4475 if (handle_stdin_input_real(caller, full_command, TRUE,
4476 read_recursion + 1)
4477 && (vote = vote_new(caller, arg, cmd))) {
4478 char votedesc[MAX_LEN_CONSOLE_LINE];
4479 const struct player *teamplr;
4480 const char *what;
4481 struct ft_color color;
4482
4483 if (caller_had_vote) {
4484 cmd_reply(CMD_VOTE, caller, C_COMMENT,
4485 /* TRANS: "vote" as a process */
4486 _("Your new vote canceled your previous vote."));
4487 }
4488
4489 describe_vote(vote, votedesc, sizeof(votedesc));
4490
4491 if (vote_is_team_only(vote)) {
4492 /* TRANS: "vote" as a process */
4493 what = _("New teamvote");
4494 teamplr = conn_get_player(caller);
4496 } else {
4497 /* TRANS: "vote" as a process */
4498 what = _("New vote");
4499 teamplr = NULL;
4501 }
4502 notify_team(teamplr, NULL, E_VOTE_NEW, color,
4503 /* TRANS: "[New vote|New teamvote] (number 3)
4504 * by fred: proposed change" */
4505 _("%s (number %d) by %s: %s"), what,
4506 vote->vote_no, caller->username, votedesc);
4507
4508 /* Vote on your own suggestion. */
4509 connection_vote(caller, vote, VOTE_YES);
4510 return TRUE;
4511
4512 } else {
4513 cmd_reply(CMD_VOTE, caller, C_FAIL,
4514 /* TRANS: "vote" as a process */
4515 _("Your new vote (\"%s\") was not "
4516 "legal or was not recognized."), full_command);
4517 return FALSE;
4518 }
4519 }
4520
4521 if (caller
4522 && !((check || vote_would_pass_immediately(caller, cmd))
4523 && conn_get_access(caller) >= ALLOW_BASIC
4524 && level == ALLOW_CTRL)
4525 && conn_get_access(caller) < level) {
4526 cmd_reply(cmd, caller, C_FAIL,
4527 _("You are not allowed to use this command."));
4528 return FALSE;
4529 }
4530
4531 if (!check) {
4532 struct conn_list *echo_list = NULL;
4533 bool echo_list_allocated = FALSE;
4534
4535 switch (command_echo(command_by_number(cmd))) {
4536 case CMD_ECHO_NONE:
4537 break;
4538 case CMD_ECHO_ADMINS:
4540 if (ALLOW_ADMIN <= conn_get_access(pconn)) {
4541 if (NULL == echo_list) {
4542 echo_list = conn_list_new();
4543 echo_list_allocated = TRUE;
4544 }
4545 conn_list_append(echo_list, pconn);
4546 }
4548 break;
4549 case CMD_ECHO_ALL:
4550 echo_list = game.est_connections;
4551 break;
4552 }
4553
4554 if (NULL != echo_list) {
4555 if (caller) {
4556 notify_conn(echo_list, NULL, E_SETTING, ftc_any,
4557 "%s: '%s %s'", caller->username, command, arg);
4558 } else {
4559 notify_conn(echo_list, NULL, E_SETTING, ftc_server_prompt,
4560 "%s: '%s %s'", _("(server prompt)"), command, arg);
4561 }
4562 if (echo_list_allocated) {
4563 conn_list_destroy(echo_list);
4564 }
4565 }
4566 }
4567
4568 switch (cmd) {
4569 case CMD_REMOVE:
4570 return remove_player_command(caller, arg, check);
4571 case CMD_SAVE:
4572 return save_command(caller, arg, check);
4573 case CMD_SCENSAVE:
4574 return scensave_command(caller, arg, check);
4575 case CMD_LOAD:
4576 return load_command(caller, arg, check, FALSE);
4577 case CMD_METAPATCHES:
4578 return metapatches_command(caller, arg, check);
4579 case CMD_METAMESSAGE:
4580 return metamessage_command(caller, arg, check);
4581 case CMD_METACONN:
4582 return metaconnection_command(caller, arg, check);
4583 case CMD_METASERVER:
4584 return metaserver_command(caller, arg, check);
4585 case CMD_HELP:
4586 return show_help(caller, arg);
4587 case CMD_SRVID:
4588 return show_serverid(caller, arg);
4589 case CMD_LIST:
4590 return show_list(caller, arg);
4591 case CMD_AITOGGLE:
4592 return toggle_ai_command(caller, arg, check);
4593 case CMD_TAKE:
4594 return take_command(caller, arg, check);
4595 case CMD_OBSERVE:
4596 return observe_command(caller, arg, check);
4597 case CMD_DETACH:
4598 return detach_command(caller, arg, check);
4599 case CMD_CREATE:
4600 return create_command(caller, arg, check);
4601 case CMD_AWAY:
4602 return away_command(caller, check);
4603 case CMD_RESTRICTED:
4604 case CMD_NOVICE:
4605 case CMD_EASY:
4606 case CMD_NORMAL:
4607 case CMD_HARD:
4608 case CMD_CHEATING:
4609#ifdef FREECIV_DEBUG
4610 case CMD_EXPERIMENTAL:
4611#endif
4612 return set_ai_level_named(caller, arg, command_name_by_number(cmd), check);
4613 case CMD_QUIT:
4614 return quit_game(caller, check);
4615 case CMD_CUT:
4616 return cut_client_connection(caller, arg, check);
4617 case CMD_SHOW:
4618 return show_command(caller, arg, check);
4619 case CMD_EXPLAIN:
4620 return explain_option(caller, arg, check);
4621 case CMD_DEBUG:
4622 return debug_command(caller, arg, check);
4623 case CMD_SET:
4624 return set_command(caller, arg, check);
4625 case CMD_TEAM:
4626 return team_command(caller, arg, check);
4627 case CMD_RULESETDIR:
4628 return set_rulesetdir(caller, arg, check, read_recursion);
4629 case CMD_WALL:
4630 return wall(arg, check);
4631 case CMD_CONNECTMSG:
4632 return connectmsg_command(caller, arg, check);
4633 case CMD_VOTE:
4634 return vote_command(caller, arg, check);
4635 case CMD_CANCELVOTE:
4636 return cancelvote_command(caller, arg, check);
4637 case CMD_READ_SCRIPT:
4638 return read_command(caller, arg, check, read_recursion);
4639 case CMD_WRITE_SCRIPT:
4640 return write_command(caller, arg, check);
4641 case CMD_RESET:
4642 return reset_command(caller, arg, check, read_recursion);
4643 case CMD_DEFAULT:
4644 return default_command(caller, arg, check);
4645 case CMD_LUA:
4646 return lua_command(caller, arg, check, read_recursion);
4647 case CMD_KICK:
4648 return kick_command(caller, arg, check);
4649 case CMD_DELEGATE:
4650 return delegate_command(caller, arg, check);
4651 case CMD_AICMD:
4652 return aicmd_command(caller, arg, check);
4653 case CMD_FCDB:
4654 return fcdb_command(caller, arg, check);
4655 case CMD_MAPIMG:
4656 return mapimg_command(caller, arg, check);
4657 case CMD_RFCSTYLE: /* see console.h for an explanation */
4658 if (!check) {
4660 }
4661 return TRUE;
4662 case CMD_CMDLEVEL:
4663 return cmdlevel_command(caller, arg, check);
4664 case CMD_FIRSTLEVEL:
4665 return firstlevel_command(caller, check);
4666 case CMD_TIMEOUT:
4667 return timeout_command(caller, arg, check);
4668 case CMD_START_GAME:
4669 return start_command(caller, check, FALSE);
4670 case CMD_END_GAME:
4671 return end_command(caller, arg, check);
4672 case CMD_SURRENDER:
4673 return surrender_command(caller, arg, check);
4674 case CMD_IGNORE:
4675 return ignore_command(caller, arg, check);
4676 case CMD_UNIGNORE:
4677 return unignore_command(caller, arg, check);
4678 case CMD_PLAYERCOLOR:
4679 return playercolor_command(caller, arg, check);
4680 case CMD_PLAYERNATION:
4681 return playernation_command(caller, arg, check);
4682 case CMD_NUM:
4683 case CMD_UNRECOGNIZED:
4684 case CMD_AMBIGUOUS:
4685 break;
4686 }
4687 /* should NEVER happen! */
4688 log_error("Unknown command variant: %d.", cmd);
4689 return FALSE;
4690}
4691
4692/**********************************************************************/
4695static bool end_command(struct connection *caller, char *str, bool check)
4696{
4697 if (S_S_RUNNING == server_state()) {
4698 if (check) {
4699 return TRUE;
4700 }
4701 notify_conn(game.est_connections, NULL, E_GAME_END, ftc_server,
4702 _("Game is over."));
4703 set_server_state(S_S_OVER);
4705 cmd_reply(CMD_END_GAME, caller, C_OK,
4706 _("Ending the game. The server will restart once all clients "
4707 "have disconnected."));
4708 return TRUE;
4709 } else {
4710 cmd_reply(CMD_END_GAME, caller, C_FAIL,
4711 _("Cannot end the game: no game running."));
4712 return FALSE;
4713 }
4714}
4715
4716/**********************************************************************/
4720static bool surrender_command(struct connection *caller, char *str, bool check)
4721{
4722 struct player *pplayer;
4723
4724 if (caller == NULL || !conn_controls_player(caller)) {
4726 _("You are not allowed to use this command."));
4727 return FALSE;
4728 }
4729
4730 if (S_S_RUNNING != server_state()) {
4731 cmd_reply(CMD_SURRENDER, caller, C_FAIL, _("You cannot surrender now."));
4732 return FALSE;
4733 }
4734
4735 pplayer = conn_get_player(caller);
4736 if (player_status_check(pplayer, PSTATUS_SURRENDER)) {
4738 _("You have already conceded the game."));
4739 return FALSE;
4740 }
4741
4742 if (check) {
4743 return TRUE;
4744 }
4745
4746 notify_conn(game.est_connections, NULL, E_GAME_END, ftc_server,
4747 _("%s has conceded the game and can no longer win."),
4748 player_name(pplayer));
4749 player_status_add(pplayer, PSTATUS_SURRENDER);
4750 return TRUE;
4751}
4752
4753/* Define the possible arguments to the reset command */
4754#define SPECENUM_NAME reset_args
4755#define SPECENUM_VALUE0 RESET_GAME
4756#define SPECENUM_VALUE0NAME "game"
4757#define SPECENUM_VALUE1 RESET_RULESET
4758#define SPECENUM_VALUE1NAME "ruleset"
4759#define SPECENUM_VALUE2 RESET_SCRIPT
4760#define SPECENUM_VALUE2NAME "script"
4761#define SPECENUM_VALUE3 RESET_DEFAULT
4762#define SPECENUM_VALUE3NAME "default"
4763#include "specenum_gen.h"
4764
4765/**********************************************************************/
4768static const char *reset_accessor(int i)
4769{
4770 i = CLIP(0, i, reset_args_max());
4771 return reset_args_name((enum reset_args) i);
4772}
4773
4774/**********************************************************************/
4778static bool reset_command(struct connection *caller, char *arg, bool check,
4779 int read_recursion)
4780{
4781 enum m_pre_result result;
4782 int ind;
4783
4784 /* match the argument */
4785 result = match_prefix(reset_accessor, reset_args_max() + 1, 0,
4786 fc_strncasecmp, NULL, arg, &ind);
4787
4788 switch (result) {
4789 case M_PRE_EXACT:
4790 case M_PRE_ONLY:
4791 /* we have a match */
4792 break;
4793 case M_PRE_AMBIGUOUS:
4794 case M_PRE_EMPTY:
4795 /* use 'ruleset' [1] if the game was not started; else use 'game' [2] */
4796 if (S_S_INITIAL == server_state() && game.info.is_new_game) {
4797 cmd_reply(CMD_RESET, caller, C_WARNING,
4798 _("Guessing argument 'ruleset'."));
4799 ind = RESET_RULESET;
4800 } else {
4801 cmd_reply(CMD_RESET, caller, C_WARNING,
4802 _("Guessing argument 'game'."));
4803 ind = RESET_GAME;
4804 }
4805 break;
4806 case M_PRE_LONG:
4807 case M_PRE_FAIL:
4808 case M_PRE_LAST:
4809 cmd_reply(CMD_RESET, caller, C_FAIL,
4810 _("The valid arguments are: 'game', 'ruleset', 'script' "
4811 "or 'default'."));
4812 return FALSE;
4813 break;
4814 }
4815
4816 if (check) {
4817 return TRUE;
4818 }
4819
4820 switch (ind) {
4821 case RESET_GAME:
4822 if (!game.info.is_new_game) {
4823 if (settings_game_reset()) {
4824 cmd_reply(CMD_RESET, caller, C_OK,
4825 _("Reset all settings to the values at the game start."));
4826 } else {
4827 cmd_reply(CMD_RESET, caller, C_FAIL,
4828 _("No saved settings from the game start available."));
4829 return FALSE;
4830 }
4831 } else {
4832 cmd_reply(CMD_RESET, caller, C_FAIL, _("No game started..."));
4833 return FALSE;
4834 }
4835 break;
4836
4837 case RESET_RULESET:
4838 /* Restore game settings saved in game.ruleset. */
4840 cmd_reply(CMD_RESET, caller, C_OK,
4841 _("Reset all settings to ruleset values."));
4842 } else {
4843 cmd_reply(CMD_RESET, caller, C_FAIL,
4844 _("Failed to reset settings to ruleset values."));
4845 }
4846 break;
4847
4848 case RESET_SCRIPT:
4849 cmd_reply(CMD_RESET, caller, C_OK,
4850 _("Reset all settings and rereading the server start "
4851 "script."));
4853 /* Load initial script */
4854 if (NULL != srvarg.script_filename
4856 read_recursion + 1)) {
4857 if (NULL != caller) {
4858 cmd_reply(CMD_RESET, caller, C_FAIL,
4859 _("Could not read script file '%s'."),
4861 }
4862 return FALSE;
4863 }
4864 break;
4865
4866 case RESET_DEFAULT:
4867 cmd_reply(CMD_RESET, caller, C_OK,
4868 _("Reset all settings to default values."));
4870 break;
4871 }
4872
4874 cmd_reply(CMD_RESET, caller, C_OK, _("Settings re-initialized."));
4875
4876 /* show ruleset summary and list changed values */
4877 show_ruleset_info(caller, CMD_RESET, check, read_recursion);
4878
4879 return TRUE;
4880}
4881
4882/**********************************************************************/
4885static bool default_command(struct connection *caller, char *arg, bool check)
4886{
4887 struct setting *pset;
4888 char reject_msg[256] = "";
4889
4890 pset = validate_setting_arg(CMD_DEFAULT, caller, arg);
4891
4892 if (!pset) {
4893 /* Reason already reported. */
4894 return FALSE;
4895 }
4896
4897 if (!setting_is_changeable(pset, caller, reject_msg, sizeof(reject_msg))) {
4898 cmd_reply(CMD_DEFAULT, caller, C_FAIL, "%s", reject_msg);
4899
4900 return FALSE;
4901 }
4902
4903 if (!check) {
4905 cmd_reply(CMD_DEFAULT, caller, C_OK,
4906 _("Option '%s' reset to default value, and will track any "
4907 "default changes."), arg);
4908 }
4909
4910 return TRUE;
4911}
4912
4913/* Define the possible arguments to the delegation command */
4914#define SPECENUM_NAME lua_args
4915#define SPECENUM_VALUE0 LUA_CMD
4916#define SPECENUM_VALUE0NAME "cmd"
4917#define SPECENUM_VALUE1 LUA_FILE
4918#define SPECENUM_VALUE1NAME "file"
4919#define SPECENUM_VALUE2 LUA_UNSAFE_CMD
4920#define SPECENUM_VALUE2NAME "unsafe-cmd"
4921#define SPECENUM_VALUE3 LUA_UNSAFE_FILE
4922#define SPECENUM_VALUE3NAME "unsafe-file"
4923#include "specenum_gen.h"
4924
4925/**********************************************************************/
4928static const char *lua_accessor(int i)
4929{
4930 i = CLIP(0, i, lua_args_max());
4931 return lua_args_name((enum lua_args) i);
4932}
4933
4934/**********************************************************************/
4937static bool lua_command(struct connection *caller, char *arg, bool check,
4938 int read_recursion)
4939{
4940 struct stat statbuf;
4941 const char extension[] = ".lua", *real_filename = NULL;
4942 char luafile[4096], tilde_filename[4096];
4943 char *tokens[1], *luaarg = NULL;
4944 int ntokens, ind;
4945 enum m_pre_result result;
4946 bool ret = FALSE;
4947
4948 ntokens = get_tokens(arg, tokens, 1, TOKEN_DELIMITERS);
4949
4950 if (ntokens > 0) {
4951 /* match the argument */
4952 result = match_prefix(lua_accessor, lua_args_max() + 1, 0,
4953 fc_strncasecmp, NULL, tokens[0], &ind);
4954
4955 switch (result) {
4956 case M_PRE_EXACT:
4957 case M_PRE_ONLY:
4958 /* We have a match */
4959 luaarg = arg + strlen(lua_args_name(ind));
4960 luaarg = skip_leading_spaces(luaarg);
4961 break;
4962 case M_PRE_EMPTY:
4963 /* Nothing. */
4964 break;
4965 case M_PRE_AMBIGUOUS:
4966 case M_PRE_LONG:
4967 case M_PRE_FAIL:
4968 case M_PRE_LAST:
4969 /* Fall back to depreciated 'lua <script command>' syntax. */
4970 cmd_reply(CMD_LUA, caller, C_SYNTAX,
4971 _("Fall back to old syntax '%slua <script command>'."),
4972 caller ? "/" : "");
4973 ind = LUA_CMD;
4974 luaarg = arg;
4975 break;
4976 }
4977 }
4978
4979 if (luaarg == NULL) {
4980 cmd_reply(CMD_LUA, caller, C_FAIL,
4981 _("No lua command or lua script file. See '%shelp lua'."),
4982 caller ? "/" : "");
4983 ret = TRUE;
4984 goto cleanup;
4985 }
4986
4987 switch (ind) {
4988 case LUA_CMD:
4989 /* Nothing to check. */
4990 break;
4991 case LUA_UNSAFE_CMD:
4992 if (read_recursion > 0) {
4993 cmd_reply(CMD_LUA, caller, C_FAIL,
4994 _("Unsafe Lua code can only be run by explicit command."));
4995 ret = FALSE;
4996 goto cleanup;
4997 } else if (is_restricted(caller)) {
4998 cmd_reply(CMD_LUA, caller, C_FAIL,
4999 _("You aren't allowed to run unsafe Lua code."));
5000 ret = FALSE;
5001 goto cleanup;
5002 }
5003 break;
5004 case LUA_UNSAFE_FILE:
5005 if (read_recursion > 0) {
5006 cmd_reply(CMD_LUA, caller, C_FAIL,
5007 _("Unsafe Lua code can only be run by explicit command."));
5008 ret = FALSE;
5009 goto cleanup;
5010 } else if (is_restricted(caller)) {
5011 cmd_reply(CMD_LUA, caller, C_FAIL,
5012 _("You aren't allowed to run unsafe Lua code."));
5013 ret = FALSE;
5014 goto cleanup;
5015 }
5016
5018 case LUA_FILE:
5019 /* Abuse real_filename to find if we already have a .lua extension. */
5020 real_filename = luaarg + strlen(luaarg) - MIN(strlen(extension),
5021 strlen(luaarg));
5022 if (strcmp(real_filename, extension) != 0) {
5023 fc_snprintf(luafile, sizeof(luafile), "%s%s", luaarg, extension);
5024 } else {
5025 sz_strlcpy(luafile, luaarg);
5026 }
5027
5028 if (is_restricted(caller)) {
5029 if (!is_safe_filename(luafile)) {
5030 cmd_reply(CMD_LUA, caller, C_FAIL,
5031 _("Freeciv script '%s' disallowed for security reasons."),
5032 luafile);
5033 ret = FALSE;
5034 goto cleanup;;
5035 }
5036 sz_strlcpy(tilde_filename, luafile);
5037 } else {
5038 interpret_tilde(tilde_filename, sizeof(tilde_filename), luafile);
5039 }
5040
5041 real_filename = fileinfoname(get_data_dirs(), tilde_filename);
5042 if (!real_filename) {
5043 if (is_restricted(caller)) {
5044 cmd_reply(CMD_LUA, caller, C_FAIL,
5045 _("No Freeciv script found by the name '%s'."),
5046 tilde_filename);
5047 ret = FALSE;
5048 goto cleanup;
5049 }
5050 /* File is outside data directories */
5051 real_filename = tilde_filename;
5052 }
5053 break;
5054 }
5055
5056 if (check) {
5057 ret = TRUE;
5058 goto cleanup;
5059 }
5060
5061 switch (ind) {
5062 case LUA_CMD:
5063 ret = script_server_do_string(caller, luaarg);
5064 break;
5065 case LUA_UNSAFE_CMD:
5066 ret = script_server_unsafe_do_string(caller, luaarg);
5067 break;
5068 case LUA_FILE:
5069 cmd_reply(CMD_LUA, caller, C_COMMENT,
5070 _("Loading Freeciv script file '%s'."), real_filename);
5071
5072 if (is_reg_file_for_access(real_filename, FALSE)
5073 && !fc_stat(real_filename, &statbuf)) {
5074 ret = script_server_do_file(caller, real_filename);
5075 } else {
5076 cmd_reply(CMD_LUA, caller, C_FAIL,
5077 _("Cannot read Freeciv script '%s'."), real_filename);
5078 ret = FALSE;
5079 }
5080 break;
5081 case LUA_UNSAFE_FILE:
5082 cmd_reply(CMD_LUA, caller, C_COMMENT,
5083 _("Loading Freeciv script file '%s'."), real_filename);
5084
5085 if (is_reg_file_for_access(real_filename, FALSE)
5086 && !fc_stat(real_filename, &statbuf)) {
5087 ret = script_server_unsafe_do_file(caller, real_filename);
5088 } else {
5089 cmd_reply(CMD_LUA, caller, C_FAIL,
5090 _("Cannot read Freeciv script '%s'."), real_filename);
5091 ret = FALSE;
5092 }
5093 break;
5094 }
5095
5096 cleanup:
5097 free_tokens(tokens, ntokens);
5098 return ret;
5099}
5100
5101/* Define the possible arguments to the delegation command */
5102#define SPECENUM_NAME delegate_args
5103#define SPECENUM_VALUE0 DELEGATE_CANCEL
5104#define SPECENUM_VALUE0NAME "cancel"
5105#define SPECENUM_VALUE1 DELEGATE_RESTORE
5106#define SPECENUM_VALUE1NAME "restore"
5107#define SPECENUM_VALUE2 DELEGATE_SHOW
5108#define SPECENUM_VALUE2NAME "show"
5109#define SPECENUM_VALUE3 DELEGATE_TAKE
5110#define SPECENUM_VALUE3NAME "take"
5111#define SPECENUM_VALUE4 DELEGATE_TO
5112#define SPECENUM_VALUE4NAME "to"
5113#include "specenum_gen.h"
5114
5115/**********************************************************************/
5118static const char *delegate_accessor(int i)
5119{
5120 i = CLIP(0, i, delegate_args_max());
5121 return delegate_args_name((enum delegate_args) i);
5122}
5123
5124/**********************************************************************/
5127static bool delegate_command(struct connection *caller, char *arg,
5128 bool check)
5129{
5130 char *tokens[3];
5131 int ntokens, ind = delegate_args_invalid();
5132 enum m_pre_result result;
5133 bool player_specified = FALSE; /* affects messages only */
5134 bool ret = FALSE;
5135 const char *username = NULL;
5136 struct player *dplayer = NULL;
5137
5138 if (!game_was_started()) {
5139 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("Game not started - "
5140 "cannot delegate yet."));
5141 return FALSE;
5142 }
5143
5144 ntokens = get_tokens(arg, tokens, 3, TOKEN_DELIMITERS);
5145
5146 if (ntokens > 0) {
5147 /* match the argument */
5148 result = match_prefix(delegate_accessor, delegate_args_max() + 1, 0,
5149 fc_strncasecmp, NULL, tokens[0], &ind);
5150
5151 switch (result) {
5152 case M_PRE_EXACT:
5153 case M_PRE_ONLY:
5154 /* we have a match */
5155 break;
5156 case M_PRE_EMPTY:
5157 if (caller) {
5158 /* Use 'delegate show' as default. */
5159 ind = DELEGATE_SHOW;
5160 }
5161 break;
5162 case M_PRE_AMBIGUOUS:
5163 case M_PRE_LONG:
5164 case M_PRE_FAIL:
5165 case M_PRE_LAST:
5166 ind = delegate_args_invalid();
5167 break;
5168 }
5169 } else {
5170 if (caller) {
5171 /* Use 'delegate show' as default. */
5172 ind = DELEGATE_SHOW;
5173 }
5174 }
5175
5176 if (!delegate_args_is_valid(ind)) {
5177 char buf[256] = "";
5178 enum delegate_args valid_args;
5179
5180 for (valid_args = delegate_args_begin();
5181 valid_args != delegate_args_end();
5182 valid_args = delegate_args_next(valid_args)) {
5183 const char *name = delegate_args_name(valid_args);
5184
5185 if (name != NULL) {
5186 cat_snprintf(buf, sizeof(buf), "'%s'", name);
5187 if (valid_args != delegate_args_max()) {
5188 cat_snprintf(buf, sizeof(buf), ", ");
5189 }
5190 }
5191 }
5192
5194 /* TRANS: do not translate the command 'delegate'. */
5195 _("Valid arguments for 'delegate' are: %s."), buf);
5196 ret = FALSE;
5197 goto cleanup;
5198 }
5199
5200 /* Get the data (player, username for delegation) and validate it. */
5201 switch (ind) {
5202 case DELEGATE_CANCEL:
5203 /* delegate cancel [player] */
5204 if (ntokens > 1) {
5205 if (!caller || conn_get_access(caller) >= ALLOW_ADMIN) {
5206 player_specified = TRUE;
5207 dplayer = player_by_name_prefix(tokens[1], &result);
5208 if (!dplayer) {
5209 cmd_reply_no_such_player(CMD_DELEGATE, caller, tokens[1], result);
5210 ret = FALSE;
5211 goto cleanup;
5212 }
5213 } else {
5215 _("Command level '%s' or greater needed to modify "
5216 "others' delegations."), cmdlevel_name(ALLOW_ADMIN));
5217 ret = FALSE;
5218 goto cleanup;
5219 }
5220 } else {
5221 dplayer = conn_get_player(caller);
5222 if (!dplayer) {
5224 _("Please specify a player for whom delegation should "
5225 "be canceled."));
5226 ret = FALSE;
5227 goto cleanup;
5228 }
5229 }
5230 break;
5231 case DELEGATE_RESTORE:
5232 /* delegate restore */
5233 if (!caller) {
5234 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5235 _("You can't switch players from the console."));
5236 ret = FALSE;
5237 goto cleanup;
5238 }
5239 break;
5240 case DELEGATE_SHOW:
5241 /* delegate show [player] */
5242 if (ntokens > 1) {
5243 player_specified = TRUE;
5244 dplayer = player_by_name_prefix(tokens[1], &result);
5245 if (!dplayer) {
5246 cmd_reply_no_such_player(CMD_DELEGATE, caller, tokens[1], result);
5247 ret = FALSE;
5248 goto cleanup;
5249 }
5250 } else {
5251 dplayer = conn_get_player(caller);
5252 if (!dplayer) {
5254 _("Please specify a player for whom the delegation should "
5255 "be shown."));
5256 ret = FALSE;
5257 goto cleanup;
5258 }
5259 }
5260 break;
5261 case DELEGATE_TAKE:
5262 /* delegate take <player> */
5263 if (!caller) {
5264 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5265 _("You can't switch players from the console."));
5266 ret = FALSE;
5267 goto cleanup;
5268 }
5269 if (ntokens > 1) {
5270 player_specified = TRUE;
5271 dplayer = player_by_name_prefix(tokens[1], &result);
5272 if (!dplayer) {
5273 cmd_reply_no_such_player(CMD_DELEGATE, caller, tokens[1], result);
5274 ret = FALSE;
5275 goto cleanup;
5276 }
5277 } else {
5279 _("Please specify a player to take control of."));
5280 ret = FALSE;
5281 goto cleanup;
5282 }
5283 break;
5284 case DELEGATE_TO:
5285 break;
5286 }
5287 /* All checks done to this point will give pretty much the same result at
5288 * any time. Checks after this point are more likely to vary over time. */
5289 if (check) {
5290 ret = TRUE;
5291 goto cleanup;
5292 }
5293
5294 switch (ind) {
5295 case DELEGATE_TO:
5296 /* delegate to <username> [player] */
5297 if (ntokens > 1) {
5298 username = tokens[1];
5299 } else {
5301 _("Please specify a user to whom control is to be delegated."));
5302 ret = FALSE;
5303 break;
5304 }
5305 if (ntokens > 2) {
5306 player_specified = TRUE;
5307 dplayer = player_by_name_prefix(tokens[2], &result);
5308 if (!dplayer) {
5309 cmd_reply_no_such_player(CMD_DELEGATE, caller, tokens[2], result);
5310 ret = FALSE;
5311 break;
5312 }
5313#ifndef HAVE_FCDB
5314 if (caller && conn_get_access(caller) < ALLOW_ADMIN) {
5315#else
5316 if (caller && conn_get_access(caller) < ALLOW_ADMIN
5317 && !(srvarg.fcdb_enabled
5318 && script_fcdb_call("user_delegate_to", caller, dplayer,
5319 username, &ret) && ret)) {
5320#endif
5322 _("Command level '%s' or greater or special permission "
5323 "needed to modify others' delegations."),
5324 cmdlevel_name(ALLOW_ADMIN));
5325 ret = FALSE;
5326 break;
5327 }
5328 } else {
5329 dplayer = conn_controls_player(caller) ? conn_get_player(caller) : NULL;
5330 if (!dplayer) {
5331 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5332 _("You do not control a player."));
5333 ret = FALSE;
5334 break;
5335 }
5336 }
5337
5338 /* Delegate control of player to another user. */
5339 fc_assert_ret_val(dplayer, FALSE);
5341
5342 /* Forbid delegation of players already controlled by a delegate, and
5343 * those 'put aside' by a delegate.
5344 * For the former, if player is already under active delegate control,
5345 * we wouldn't handle the revocation that would be necessary if their
5346 * delegation changed; and the authority granted to delegates does not
5347 * include the ability to sub-delegate.
5348 * For the latter, allowing control of the 'put aside' player to be
5349 * delegated would break the invariant that whenever a user is connected,
5350 * they are attached to 'their' player. */
5351 if (player_delegation_active(dplayer)) {
5352 if (!player_delegation_get(dplayer)) {
5353 /* Attempting to change a 'put aside' player. Must be admin
5354 * or console. */
5355 fc_assert(player_specified);
5356 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5357 _("Can't delegate control of '%s' belonging to %s while "
5358 "they are controlling another player."),
5359 player_name(dplayer), dplayer->username);
5360 } else if (player_specified) {
5361 /* Admin or console attempting to change a controlled player. */
5362 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5363 _("Can't change delegation of '%s' while controlled by "
5364 "delegate %s."), player_name(dplayer), dplayer->username);
5365 } else {
5366 /* Caller must be the delegate. Give more specific message.
5367 * (We don't know if they thought they were delegating their
5368 * original or delegated player, but we don't allow either.) */
5369 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5370 _("You can't delegate control while you are controlling "
5371 "a delegated player yourself."));
5372 }
5373 ret = FALSE;
5374 break;
5375 }
5376
5377 /* Forbid delegation to player's original owner
5378 * (from above test we know that dplayer->username is the original now) */
5379 if (fc_strcasecmp(dplayer->username, username) == 0) {
5380 if (player_specified) {
5381 /* Probably admin or console. */
5382 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5383 /* TRANS: don't translate 'delegate cancel' */
5384 _("%s already owns '%s', so cannot also be delegate. "
5385 "Use '%sdelegate cancel' to cancel an existing "
5386 "delegation."),
5387 username, player_name(dplayer), caller?"/":"");
5388 } else {
5389 /* Player not specified on command line, so they must have been trying
5390 * to delegate control to themself. Give more specific message. */
5391 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5392 /* TRANS: don't translate '/delegate cancel' */
5393 _("You can't delegate control to yourself. "
5394 "Use '/delegate cancel' to cancel an existing "
5395 "delegation."));
5396 }
5397 ret = FALSE;
5398 break;
5399 }
5400
5401 /* FIXME: if control was already delegated to someone else, that
5402 * delegation is implicitly canceled. Perhaps we should tell someone. */
5403
5405 cmd_reply(CMD_DELEGATE, caller, C_OK,
5406 _("Control of player '%s' delegated to user %s."),
5407 player_name(dplayer), username);
5408 ret = TRUE;
5409 break;
5410
5411 case DELEGATE_SHOW:
5412 /* Show delegations. */
5413 fc_assert_ret_val(dplayer, FALSE);
5414
5415 if (player_delegation_get(dplayer) == NULL) {
5416 /* No delegation set. */
5418 _("No delegation defined for '%s'."),
5419 player_name(dplayer));
5420 } else {
5422 _("Control of player '%s' delegated to user %s."),
5423 player_name(dplayer), player_delegation_get(dplayer));
5424 }
5425 ret = TRUE;
5426 break;
5427
5428 case DELEGATE_CANCEL:
5429 if (player_delegation_get(dplayer) == NULL) {
5430 /* No delegation set. */
5431 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5432 _("No delegation defined for '%s'."),
5433 player_name(dplayer));
5434 ret = FALSE;
5435 break;
5436 }
5437
5438 if (player_delegation_active(dplayer)) {
5439 /* Delegation is currently in use. Forcibly break connection. */
5440 struct connection *pdelegate;
5441 /* (Can only happen if admin/console issues this command, as owner
5442 * will end use by their mere presence.) */
5443 fc_assert(player_specified);
5444 pdelegate = conn_by_user(player_delegation_get(dplayer));
5445 fc_assert_ret_val(pdelegate != NULL, FALSE);
5446 if (!connection_delegate_restore(pdelegate)) {
5447 /* Should never happen. Generic failure message. */
5448 log_error("Failed to restore %s's connection as %s during "
5449 "'delegate cancel'.", pdelegate->username,
5451 pdelegate->server.delegation.observer));
5452 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("Unexpected failure."));
5453 ret = FALSE;
5454 break;
5455 }
5456 notify_conn(pdelegate->self, NULL, E_CONNECTION, ftc_server,
5457 _("Your delegated control of player '%s' was canceled."),
5458 player_name(dplayer));
5459 }
5460
5461 player_delegation_set(dplayer, NULL);
5462 cmd_reply(CMD_DELEGATE, caller, C_OK, _("Delegation of '%s' canceled."),
5463 player_name(dplayer));
5464 ret = TRUE;
5465 break;
5466
5467 case DELEGATE_TAKE:
5468 /* Try to take another player. */
5469 fc_assert_ret_val(dplayer, FALSE);
5470 fc_assert_ret_val(caller, FALSE);
5471
5472 if (caller->server.delegation.status) {
5473 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5474 /* TRANS: don't translate '/delegate restore'. */
5475 _("You are already controlling a delegated player. "
5476 "Use '/delegate restore' to relinquish control of your "
5477 "current player first."));
5478 ret = FALSE;
5479 break;
5480 }
5481
5482 /* Don't allow 'put aside' players to be delegated; the invariant is
5483 * that while the owning user is connected to the server, they are
5484 * in sole control of 'their' player. */
5485 if (conn_controls_player(caller)
5486 && player_delegation_get(conn_get_player(caller)) != NULL) {
5487 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5488 /* TRANS: don't translate '/delegate cancel'. */
5489 _("Can't take player while you have delegated control "
5490 "yourself. Use '/delegate cancel' to cancel your own "
5491 "delegation first."));
5492 ret = FALSE;
5493 break;
5494 }
5495
5496 /* Taking your own player makes no sense. */
5497 if (conn_controls_player(caller)
5498 && dplayer == conn_get_player(caller)) {
5499 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("You already control '%s'."),
5500 player_name(conn_get_player(caller)));
5501 ret = FALSE;
5502 break;
5503 }
5504
5505 if (!player_delegation_get(dplayer)
5506 || fc_strcasecmp(player_delegation_get(dplayer), caller->username) != 0) {
5507 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5508 _("Control of player '%s' has not been delegated to you."),
5509 player_name(dplayer));
5510 ret = FALSE;
5511 break;
5512 }
5513
5514 /* If the player is controlled by another user, fail. */
5515 if (dplayer->is_connected) {
5516 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5517 _("Another user already controls player '%s'."),
5518 player_name(dplayer));
5519 ret = FALSE;
5520 break;
5521 }
5522
5523 if (!connection_delegate_take(caller, dplayer)) {
5524 /* Should never happen. Generic failure message. */
5525 log_error("%s failed to take control of '%s' during 'delegate take'.",
5526 caller->username, player_name(dplayer));
5527 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("Unexpected failure."));
5528 ret = FALSE;
5529 break;
5530 }
5531
5532 cmd_reply(CMD_DELEGATE, caller, C_OK,
5533 _("%s is now controlling player '%s'."), caller->username,
5534 player_name(conn_get_player(caller)));
5535 ret = TRUE;
5536 break;
5537
5538 case DELEGATE_RESTORE:
5539 /* Delegate user relinquishes control of delegated player, returning to
5540 * previous view (e.g. observer) if any. */
5541 fc_assert_ret_val(caller, FALSE);
5542
5543 if (!caller->server.delegation.status) {
5544 cmd_reply(CMD_DELEGATE, caller, C_FAIL,
5545 _("You are not currently controlling a delegated player."));
5546 ret = FALSE;
5547 break;
5548 }
5549
5550 if (!connection_delegate_restore(caller)) {
5551 /* Should never happen. Generic failure message. */
5552 log_error("Failed to restore %s's connection as %s during "
5553 "'delegate restore'.", caller->username,
5555 caller->server.delegation.observer));
5556 cmd_reply(CMD_DELEGATE, caller, C_FAIL, _("Unexpected failure."));
5557 ret = FALSE;
5558 break;
5559 }
5560
5561 cmd_reply(CMD_DELEGATE, caller, C_OK,
5562 /* TRANS: "<user> is now connected to <player>" where <player>
5563 * can also be "global observer" or "nothing" */
5564 _("%s is now connected as %s."), caller->username,
5565 delegate_player_str(conn_get_player(caller), caller->observer));
5566 ret = TRUE;
5567 break;
5568 }
5569
5570 cleanup:
5571 free_tokens(tokens, ntokens);
5572 return ret;
5573}
5574
5575/**********************************************************************/
5578static const char *delegate_player_str(struct player *pplayer, bool observer)
5579{
5580 static struct astring buf;
5581
5582 if (pplayer) {
5583 if (observer) {
5584 astr_set(&buf, _("%s (observer)"), player_name(pplayer));
5585 } else {
5586 astr_set(&buf, "%s", player_name(pplayer));
5587 }
5588 } else if (observer) {
5589 astr_set(&buf, "%s", _("global observer"));
5590 } else {
5591 /* TRANS: in place of player name or "global observer" */
5592 astr_set(&buf, "%s", _("nothing"));
5593 }
5594
5595 return astr_str(&buf);
5596}
5597
5598/* Define the possible arguments to the mapimg command */
5599/* map image layers */
5600#define SPECENUM_NAME mapimg_args
5601#define SPECENUM_VALUE0 MAPIMG_COLORTEST
5602#define SPECENUM_VALUE0NAME "colortest"
5603#define SPECENUM_VALUE1 MAPIMG_CREATE
5604#define SPECENUM_VALUE1NAME "create"
5605#define SPECENUM_VALUE2 MAPIMG_DEFINE
5606#define SPECENUM_VALUE2NAME "define"
5607#define SPECENUM_VALUE3 MAPIMG_DELETE
5608#define SPECENUM_VALUE3NAME "delete"
5609#define SPECENUM_VALUE4 MAPIMG_SHOW
5610#define SPECENUM_VALUE4NAME "show"
5611#define SPECENUM_COUNT MAPIMG_COUNT
5612#include "specenum_gen.h"
5613
5614/**********************************************************************/
5617static const char *mapimg_accessor(int i)
5618{
5619 i = CLIP(0, i, mapimg_args_max());
5620 return mapimg_args_name((enum mapimg_args) i);
5621}
5622
5623/**********************************************************************/
5626static bool mapimg_command(struct connection *caller, char *arg, bool check)
5627{
5628 enum m_pre_result result;
5629 int ind, ntokens, id;
5630 char *token[2];
5631 bool ret = TRUE;
5632
5633 ntokens = get_tokens(arg, token, 2, TOKEN_DELIMITERS);
5634
5635 if (ntokens > 0) {
5636 /* match the argument */
5637 result = match_prefix(mapimg_accessor, MAPIMG_COUNT, 0,
5638 fc_strncasecmp, NULL, token[0], &ind);
5639
5640 switch (result) {
5641 case M_PRE_EXACT:
5642 case M_PRE_ONLY:
5643 /* we have a match */
5644 break;
5645 case M_PRE_AMBIGUOUS:
5646 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5647 _("Ambiguous 'mapimg' command."));
5648 ret = FALSE;
5649 goto cleanup;
5650 break;
5651 case M_PRE_EMPTY:
5652 /* use 'show' as default */
5653 ind = MAPIMG_SHOW;
5654 break;
5655 case M_PRE_LONG:
5656 case M_PRE_FAIL:
5657 case M_PRE_LAST:
5658 {
5659 char buf[256] = "";
5660 enum mapimg_args valid_args;
5661
5662 for (valid_args = mapimg_args_begin();
5663 valid_args != mapimg_args_end();
5664 valid_args = mapimg_args_next(valid_args)) {
5665 cat_snprintf(buf, sizeof(buf), "'%s'",
5666 mapimg_args_name(valid_args));
5667 if (valid_args != mapimg_args_max()) {
5668 cat_snprintf(buf, sizeof(buf), ", ");
5669 }
5670 }
5671
5672 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5673 _("The valid arguments are: %s."), buf);
5674 ret = FALSE;
5675 goto cleanup;
5676 }
5677 break;
5678 }
5679 } else {
5680 /* use 'show' as default */
5681 ind = MAPIMG_SHOW;
5682 }
5683
5684 switch (ind) {
5685 case MAPIMG_DEFINE:
5686 if (ntokens == 1) {
5687 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5688 _("Missing argument for 'mapimg define'."));
5689 ret = FALSE;
5690 } else {
5691 /* 'mapimg define <mapstr>' */
5692 if (!mapimg_define(token[1], check)) {
5693 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5694 _("Can't use definition: %s."), mapimg_error());
5695 ret = FALSE;
5696 } else if (check) {
5697 /* Validated OK, bail out now */
5698 goto cleanup;
5699 } else if (game_was_started()
5700 && mapimg_isvalid(mapimg_count() - 1) == NULL) {
5701 /* game was started - error in map image definition check */
5702 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5703 _("Can't use definition: %s."), mapimg_error());
5704 ret = FALSE;
5705 } else {
5706 char str[MAX_LEN_MAPDEF];
5707
5708 id = mapimg_count() - 1;
5709
5710 mapimg_id2str(id, str, sizeof(str));
5711 cmd_reply(CMD_MAPIMG, caller, C_OK, _("Defined as map image "
5712 "definition %d: '%s'."),
5713 id, str);
5714 }
5715 }
5716 break;
5717
5718 case MAPIMG_DELETE:
5719 if (ntokens == 1) {
5720 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5721 _("Missing argument for 'mapimg delete'."));
5722 ret = FALSE;
5723 } else if (ntokens == 2 && strcmp(token[1], "all") == 0) {
5724 /* 'mapimg delete all' */
5725 if (check) {
5726 goto cleanup;
5727 }
5728
5729 while (mapimg_count() > 0) {
5730 mapimg_delete(0);
5731 }
5732 cmd_reply(CMD_MAPIMG, caller, C_OK, _("All map image definitions "
5733 "deleted."));
5734 } else if (ntokens == 2 && sscanf(token[1], "%d", &id) != 0) {
5735 /* 'mapimg delete <id>' */
5736 if (check) {
5737 goto cleanup;
5738 }
5739
5740 if (!mapimg_delete(id)) {
5741 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5742 _("Couldn't delete definition: %s."), mapimg_error());
5743 ret = FALSE;
5744 } else {
5745 cmd_reply(CMD_MAPIMG, caller, C_OK, _("Map image definition %d "
5746 "deleted."), id);
5747 }
5748 } else {
5749 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5750 _("Bad argument for 'mapimg delete': '%s'."), token[1]);
5751 ret = FALSE;
5752 }
5753 break;
5754
5755 case MAPIMG_SHOW:
5756 if (ntokens < 2 || (ntokens == 2 && strcmp(token[1], "all") == 0)) {
5757 /* 'mapimg show' or 'mapimg show all' */
5758 if (check) {
5759 goto cleanup;
5760 }
5761 show_mapimg(caller, CMD_MAPIMG);
5762 } else if (ntokens == 2 && sscanf(token[1], "%d", &id) != 0) {
5763 char str[2048];
5764 /* 'mapimg show <id>' */
5765 if (check) {
5766 goto cleanup;
5767 }
5768
5769 if (mapimg_show(id, str, sizeof(str), TRUE)) {
5770 cmd_reply(CMD_MAPIMG, caller, C_OK, "%s", str);
5771 } else {
5772 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5773 _("Couldn't show definition: %s."), mapimg_error());
5774 ret = FALSE;
5775 }
5776 } else {
5777 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5778 _("Bad argument for 'mapimg show': '%s'."), token[1]);
5779 ret = FALSE;
5780 }
5781 break;
5782
5783 case MAPIMG_COLORTEST:
5784 if (check) {
5785 goto cleanup;
5786 }
5787
5789 cmd_reply(CMD_MAPIMG, caller, C_OK, _("Map color test images saved."));
5790 break;
5791
5792 case MAPIMG_CREATE:
5793 if (ntokens < 2) {
5794 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5795 _("Missing argument for 'mapimg create'."));
5796 ret = FALSE;
5797 goto cleanup;
5798 }
5799
5800 if (strcmp(token[1], "all") == 0) {
5801 /* 'mapimg create all' */
5802 if (check) {
5803 goto cleanup;
5804 }
5805
5806 for (id = 0; id < mapimg_count(); id++) {
5807 struct mapdef *pmapdef = mapimg_isvalid(id);
5808
5809 if (pmapdef == NULL
5810 || !mapimg_create(pmapdef, TRUE, game.server.save_name,
5812 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5813 _("Error saving map image %d: %s."), id, mapimg_error());
5814 ret = FALSE;
5815 }
5816 }
5817 } else if (sscanf(token[1], "%d", &id) != 0) {
5818 struct mapdef *pmapdef;
5819
5820 /* 'mapimg create <id>' */
5821 if (check) {
5822 goto cleanup;
5823 }
5824
5825 pmapdef = mapimg_isvalid(id);
5826 if (pmapdef == NULL
5827 || !mapimg_create(pmapdef, TRUE, game.server.save_name,
5829 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5830 _("Error saving map image %d: %s."), id, mapimg_error());
5831 ret = FALSE;
5832 }
5833 } else {
5834 cmd_reply(CMD_MAPIMG, caller, C_FAIL,
5835 _("Bad argument for 'mapimg create': '%s'."), token[1]);
5836 ret = FALSE;
5837 }
5838 break;
5839 }
5840
5841 cleanup:
5842
5843 free_tokens(token, ntokens);
5844
5845 return ret;
5846}
5847
5848/**********************************************************************/
5851static bool aicmd_command(struct connection *caller, char *arg, bool check)
5852{
5853 enum m_pre_result match_result;
5854 struct player *pplayer;
5855 char *tokens[1], *cmd = NULL;
5856 int ntokens;
5857 bool ret = FALSE;
5858
5859 ntokens = get_tokens(arg, tokens, 1, TOKEN_DELIMITERS);
5860
5861 if (ntokens < 1) {
5862 cmd_reply(CMD_AICMD, caller, C_FAIL,
5863 _("No player given for aicmd."));
5864 goto cleanup;
5865 }
5866
5867 pplayer = player_by_name_prefix(tokens[0], &match_result);
5868
5869 if (NULL == pplayer) {
5870 cmd_reply_no_such_player(CMD_AICMD, caller, tokens[0], match_result);
5871 goto cleanup;
5872 }
5873
5874 /* We have a player - extract the command. */
5875 cmd = arg + strlen(tokens[0]);
5876 cmd = skip_leading_spaces(cmd);
5877
5878 if (strlen(cmd) == 0) {
5879 cmd_reply(CMD_AICMD, caller, C_FAIL,
5880 _("No command for the AI console defined."));
5881 goto cleanup;
5882 }
5883
5884 if (check) {
5885 ret = TRUE;
5886 goto cleanup;
5887 }
5888
5889 /* This check is needed to return a message if the function is not defined
5890 * for the AI of the player. */
5891 if (pplayer && pplayer->ai) {
5892 if (pplayer->ai->funcs.player_console) {
5893 cmd_reply(CMD_AICMD, caller, C_OK,
5894 _("AI console for player %s. Command: '%s'."),
5895 player_name(pplayer), cmd);
5896 CALL_PLR_AI_FUNC(player_console, pplayer, pplayer, cmd);
5897 ret = TRUE;
5898 } else {
5899 cmd_reply(CMD_AICMD, caller, C_FAIL,
5900 _("No AI console defined for the AI '%s' of player %s."),
5901 ai_name(pplayer->ai), player_name(pplayer));
5902 }
5903 } else {
5904 cmd_reply(CMD_AICMD, caller, C_FAIL, _("No AI defined for player %s."),
5905 player_name(pplayer));
5906 }
5907
5908 cleanup:
5909 free_tokens(tokens, ntokens);
5910 return ret;
5911}
5912
5913/* Define the possible arguments to the fcdb command */
5914#define SPECENUM_NAME fcdb_args
5915#define SPECENUM_VALUE0 FCDB_RELOAD
5916#define SPECENUM_VALUE0NAME "reload"
5917#define SPECENUM_VALUE1 FCDB_LUA
5918#define SPECENUM_VALUE1NAME "lua"
5919#define SPECENUM_COUNT FCDB_COUNT
5920#include "specenum_gen.h"
5921
5922/**********************************************************************/
5925static const char *fcdb_accessor(int i)
5926{
5927 i = CLIP(0, i, fcdb_args_max());
5928 return fcdb_args_name((enum fcdb_args) i);
5929}
5930
5931/**********************************************************************/
5934static bool fcdb_command(struct connection *caller, char *arg, bool check)
5935{
5936 enum m_pre_result result;
5937 int ind, ntokens;
5938 char *token[1];
5939 bool ret = TRUE;
5940 bool usage = FALSE;
5941
5942#ifndef HAVE_FCDB
5943 cmd_reply(CMD_FCDB, caller, C_FAIL,
5944 _("Freeciv database script deactivated at compile time."));
5945 return FALSE;
5946#endif
5947
5948 if (!srvarg.fcdb_enabled) {
5949 /* Not supposed to be used. It isn't initialized. */
5950 cmd_reply(CMD_FCDB, caller, C_FAIL,
5951 _("Freeciv database script not activated at server start. "
5952 "See the Freeciv server's --auth command line option."));
5953 return FALSE;
5954 }
5955
5956 ntokens = get_tokens(arg, token, 1, TOKEN_DELIMITERS);
5957
5958 if (ntokens > 0) {
5959 /* match the argument */
5960 result = match_prefix(fcdb_accessor, FCDB_COUNT, 0,
5961 fc_strncasecmp, NULL, token[0], &ind);
5962
5963 switch (result) {
5964 case M_PRE_EXACT:
5965 case M_PRE_ONLY:
5966 /* we have a match */
5967 break;
5968 case M_PRE_AMBIGUOUS:
5969 cmd_reply(CMD_FCDB, caller, C_FAIL,
5970 _("Ambiguous fcdb command."));
5971 ret = FALSE;
5972 goto cleanup;
5973 break;
5974 case M_PRE_EMPTY:
5975 case M_PRE_LONG:
5976 case M_PRE_FAIL:
5977 case M_PRE_LAST:
5978 usage = TRUE;
5979 break;
5980 }
5981 } else {
5982 usage = TRUE;
5983 }
5984
5985 if (usage) {
5986 char buf[256] = "";
5987 enum fcdb_args valid_args;
5988
5989 for (valid_args = fcdb_args_begin();
5990 valid_args != fcdb_args_end();
5991 valid_args = fcdb_args_next(valid_args)) {
5992 cat_snprintf(buf, sizeof(buf), "'%s'",
5993 fcdb_args_name(valid_args));
5994 if (valid_args != fcdb_args_max()) {
5995 cat_snprintf(buf, sizeof(buf), ", ");
5996 }
5997 }
5998
5999 cmd_reply(CMD_FCDB, caller, C_FAIL,
6000 _("The valid arguments are: %s."), buf);
6001 ret = FALSE;
6002 goto cleanup;
6003 }
6004
6005 if (check) {
6006 ret = TRUE;
6007 goto cleanup;
6008 }
6009
6010 switch (ind) {
6011 case FCDB_RELOAD:
6012 /* Reload database lua script. */
6014 script_fcdb_init(NULL);
6015 break;
6016
6017 case FCDB_LUA:
6018 /* Skip whitespaces. */
6019 arg = skip_leading_spaces(arg);
6020 /* Skip the base argument 'lua'. */
6021 arg += 3;
6022 /* Now execute the scriptlet. */
6023 ret = script_fcdb_do_string(caller, arg);
6024 break;
6025 }
6026
6027 cleanup:
6028
6029 free_tokens(token, ntokens);
6030
6031 return ret;
6032}
6033
6034/**********************************************************************/
6037static void start_cmd_reply(struct connection *caller, bool notify, char *msg)
6038{
6039 cmd_reply(CMD_START_GAME, caller, C_FAIL, "%s", msg);
6040 if (notify) {
6041 notify_conn(NULL, NULL, E_SETTING, ftc_server, "%s", msg);
6042 }
6043}
6044
6045/**********************************************************************/
6048bool start_command(struct connection *caller, bool check, bool notify)
6049{
6050 int human_players;
6051
6052 switch (server_state()) {
6053 case S_S_INITIAL:
6054 /* Sanity check scenario */
6055 if (game.info.is_new_game && !check) {
6056 if (0 < map_startpos_count()
6058 /* If we load a pre-generated map (i.e., a scenario) it is possible
6059 * to increase the number of players beyond the number supported by
6060 * the scenario. The solution is a hack: cut the extra players
6061 * when the game starts. */
6062 log_verbose("Reduced maxplayers from %d to %d to fit "
6063 "to the number of start positions.",
6066 }
6067
6069 int i;
6070 struct player *pplayer;
6071
6072 for (i = player_slot_count() - 1; i >= 0; i--) {
6073 pplayer = player_by_number(i);
6074 if (pplayer) {
6075 server_remove_player(pplayer);
6076 }
6078 break;
6079 }
6080 }
6081
6082 log_verbose("Had to cut down the number of players to the "
6083 "number of map start positions, there must be "
6084 "something wrong with the savegame or you "
6085 "adjusted the maxplayers value.");
6086 }
6087 }
6088
6089 human_players = 0;
6090 players_iterate(plr) {
6091 if (is_human(plr)) {
6092 human_players++;
6093 }
6095
6096 /* check min_players.
6097 * Allow continuing of savegames where some of the original
6098 * players have died */
6100 && human_players < game.server.min_players) {
6101 char buf[512] = "";
6102
6103 fc_snprintf(buf, sizeof(buf),
6104 _("Not enough human players ('minplayers' server setting has value %d); game will not start."),
6106 start_cmd_reply(caller, notify, buf);
6107 return FALSE;
6108 } else if (player_count() < 1) {
6109 /* At least one player required */
6110 start_cmd_reply(caller, notify,
6111 _("No players; game will not start."));
6112 return FALSE;
6113 } else if (normal_player_count() > server.playable_nations) {
6114 if (nation_set_count() > 1) {
6115 start_cmd_reply(caller, notify,
6116 _("Not enough nations in the current nation set "
6117 "for all players; game will not start. "
6118 "(See 'nationset' setting.)"));
6119 } else {
6120 start_cmd_reply(caller, notify,
6121 _("Not enough nations for all players; game will "
6122 "not start."));
6123 }
6124 return FALSE;
6125 } else if (strlen(game.server.start_units) == 0 && !game.server.start_city) {
6126 start_cmd_reply(caller, notify,
6127 _("Neither 'startcity' nor 'startunits' setting gives "
6128 "players anything to start game with; game will "
6129 "not start."));
6130 return FALSE;
6131 } else if (check) {
6132 return TRUE;
6133 } else if (!caller) {
6134 if (notify) {
6135 /* Called from handle_player_ready()
6136 * Last player just toggled ready-status. */
6137 notify_conn(NULL, NULL, E_SETTING, ftc_game_start,
6138 _("All players are ready; starting game."));
6139 }
6140 start_game();
6141 return TRUE;
6142 } else if (NULL == caller->playing || caller->observer) {
6143 /* A detached or observer player can't do /start. */
6144 return TRUE;
6145 } else {
6146 /* This might trigger recursive call to start_command() if this is
6147 * last player who gets ready. In that case caller is NULL. */
6149 return TRUE;
6150 }
6151 case S_S_OVER:
6152 start_cmd_reply(caller, notify,
6153 /* TRANS: given when /start is invoked during gameover. */
6154 _("Cannot start the game: the game is waiting for all clients "
6155 "to disconnect."));
6156 return FALSE;
6157 case S_S_RUNNING:
6158 start_cmd_reply(caller, notify,
6159 /* TRANS: given when /start is invoked while the game
6160 * is running. */
6161 _("Cannot start the game: it is already running."));
6162 return FALSE;
6163 }
6164 log_error("Unknown server state variant: %d.", server_state());
6165 return FALSE;
6166}
6167
6168/**********************************************************************/
6171static bool cut_client_connection(struct connection *caller, char *name,
6172 bool check)
6173{
6174 enum m_pre_result match_result;
6175 struct connection *ptarget;
6176
6177 ptarget = conn_by_user_prefix(name, &match_result);
6178
6179 if (!ptarget) {
6180 cmd_reply_no_such_conn(CMD_CUT, caller, name, match_result);
6181 return FALSE;
6182 } else if (check) {
6183 return TRUE;
6184 }
6185
6186 if (conn_controls_player(ptarget)) {
6187 /* If we cut the connection, unassign the login name.*/
6189 ptarget->playing->unassigned_user = TRUE;
6190 }
6191
6193 _("Cutting connection %s."), ptarget->username);
6194 connection_close_server(ptarget, _("connection cut"));
6195
6196 return TRUE;
6197}
6198
6199
6200/**********************************************************************/
6203static time_t *time_duplicate(const time_t *t)
6204{
6205 time_t *d = fc_malloc(sizeof(*d));
6206 *d = *t;
6207 return d;
6208}
6209
6210/**********************************************************************/
6214bool conn_is_kicked(struct connection *pconn, int *time_remaining)
6215{
6216 time_t time_of_addr_kick, time_of_user_kick;
6217 time_t now, time_of_kick = 0;
6218
6219 if (NULL != time_remaining) {
6220 *time_remaining = 0;
6221 }
6222
6225 fc_assert_ret_val(NULL != pconn, FALSE);
6226
6227 if (kick_hash_lookup(kick_table_by_addr, pconn->server.ipaddr,
6228 &time_of_addr_kick)) {
6229 time_of_kick = time_of_addr_kick;
6230 }
6231 if (kick_hash_lookup(kick_table_by_user, pconn->username,
6232 &time_of_user_kick)
6233 && time_of_user_kick > time_of_kick) {
6234 time_of_kick = time_of_user_kick;
6235 }
6236
6237 if (0 == time_of_kick) {
6238 return FALSE; /* Not found. */
6239 }
6240
6241 now = time(NULL);
6242 if (now - time_of_kick > game.server.kick_time) {
6243 /* Kick timeout expired. */
6244 if (0 != time_of_addr_kick) {
6245 kick_hash_remove(kick_table_by_addr, pconn->server.ipaddr);
6246 }
6247 if (0 != time_of_user_kick) {
6248 kick_hash_remove(kick_table_by_user, pconn->username);
6249 }
6250 return FALSE;
6251 }
6252
6253 if (NULL != time_remaining) {
6254 *time_remaining = game.server.kick_time - (now - time_of_kick);
6255 }
6256 return TRUE;
6257}
6258
6259/**********************************************************************/
6262static bool kick_command(struct connection *caller, char *name, bool check)
6263{
6264 char ipaddr[FC_MEMBER_SIZEOF(struct connection, server.ipaddr)];
6265 struct connection *pconn;
6266 enum m_pre_result match_result;
6267 time_t now;
6268
6270 pconn = conn_by_user_prefix(name, &match_result);
6271 if (NULL == pconn) {
6272 cmd_reply_no_such_conn(CMD_KICK, caller, name, match_result);
6273 return FALSE;
6274 }
6275
6276 if (NULL != caller && ALLOW_ADMIN > conn_get_access(caller)) {
6277 const int MIN_UNIQUE_CONNS = 3;
6278 const char *unique_ipaddr[MIN_UNIQUE_CONNS];
6279 int i, num_unique_connections = 0;
6280
6281 if (pconn == caller) {
6282 cmd_reply(CMD_KICK, caller, C_FAIL, _("You may not kick yourself."));
6283 return FALSE;
6284 }
6285
6287 for (i = 0; i < num_unique_connections; i++) {
6288 if (0 == strcmp(unique_ipaddr[i], aconn->server.ipaddr)) {
6289 /* Already listed. */
6290 break;
6291 }
6292 }
6293 if (i >= num_unique_connections) {
6294 num_unique_connections++;
6295 if (MIN_UNIQUE_CONNS <= num_unique_connections) {
6296 /* We have enough already. */
6297 break;
6298 }
6299 unique_ipaddr[num_unique_connections - 1] = aconn->server.ipaddr;
6300 }
6302
6303 if (MIN_UNIQUE_CONNS > num_unique_connections) {
6304 cmd_reply(CMD_KICK, caller, C_FAIL,
6305 _("There must be at least %d unique connections to the "
6306 "server for this command to be valid."), MIN_UNIQUE_CONNS);
6307 return FALSE;
6308 }
6309 }
6310
6311 if (check) {
6312 return TRUE;
6313 }
6314
6315 sz_strlcpy(ipaddr, pconn->server.ipaddr);
6316 now = time(NULL);
6317 kick_hash_replace(kick_table_by_addr, ipaddr, now);
6318
6320 if (0 != strcmp(ipaddr, aconn->server.ipaddr)) {
6321 continue;
6322 }
6323
6324 if (conn_controls_player(aconn)) {
6325 /* Unassign the username. */
6326 sz_strlcpy(aconn->playing->username, _(ANON_USER_NAME));
6327 aconn->playing->unassigned_user = TRUE;
6328 }
6329
6330 kick_hash_replace(kick_table_by_user, aconn->username, now);
6331
6332 connection_close_server(aconn, _("kicked"));
6334
6335 return TRUE;
6336}
6337
6338
6339/**********************************************************************/
6343static void show_help_intro(struct connection *caller,
6344 enum command_id help_cmd)
6345{
6346 /* This is formatted like extra_help entries for settings and commands: */
6347 char *help = fc_strdup(
6348 _("Welcome - this is the introductory help text for the Freeciv "
6349 "server.\n"
6350 "\n"
6351 "Two important server concepts are Commands and Options. Commands, "
6352 "such as 'help', are used to interact with the server. Some commands "
6353 "take one or more arguments, separated by spaces. In many cases "
6354 "commands and command arguments may be abbreviated. Options are "
6355 "settings which control the server as it is running.\n"
6356 "\n"
6357 "To find out how to get more information about commands and options, "
6358 "use 'help help'.\n"
6359 "\n"
6360 "For the impatient, the main commands to get going are:\n"
6361 " show - to see current options\n"
6362 " set - to set options\n"
6363 " start - to start the game once players have connected\n"
6364 " save - to save the current game\n"
6365 " quit - to exit"));
6366
6368 cmd_reply(help_cmd, caller, C_COMMENT, "%s", help);
6369 FC_FREE(help);
6370}
6371
6372/**********************************************************************/
6376static void show_help_command(struct connection *caller,
6377 enum command_id help_cmd,
6378 enum command_id id)
6379{
6380 const struct command *cmd = command_by_number(id);
6381
6382 if (command_short_help(cmd)) {
6383 cmd_reply(help_cmd, caller, C_COMMENT,
6384 /* TRANS: <untranslated name> - translated short help */
6385 _("Command: %s - %s"),
6386 command_name(cmd),
6387 command_short_help(cmd));
6388 } else {
6389 cmd_reply(help_cmd, caller, C_COMMENT,
6390 /* TRANS: <untranslated name> */
6391 _("Command: %s"),
6392 command_name(cmd));
6393 }
6394 if (command_synopsis(cmd)) {
6395 /* line up the synopsis lines: */
6396 const char *syn = _("Synopsis: ");
6397 size_t synlen = strlen(syn);
6398 char prefix[40];
6399
6400 fc_snprintf(prefix, sizeof(prefix), "%*s", (int) synlen, " ");
6401 cmd_reply_prefix(help_cmd, caller, C_COMMENT, prefix,
6402 "%s%s", syn, command_synopsis(cmd));
6403 }
6404 cmd_reply(help_cmd, caller, C_COMMENT,
6405 _("Level: %s"), cmdlevel_name(command_level(cmd)));
6406 {
6407 char *help = command_extra_help(cmd);
6408
6409 if (help) {
6411 cmd_reply(help_cmd, caller, C_COMMENT, _("Description:"));
6412 cmd_reply_prefix(help_cmd, caller, C_COMMENT, " ", " %s", help);
6413 FC_FREE(help);
6414 }
6415 }
6416}
6417
6418/**********************************************************************/
6422static void show_help_command_list(struct connection *caller,
6423 enum command_id help_cmd)
6424{
6425 enum command_id i;
6426
6427 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
6428 cmd_reply(help_cmd, caller, C_COMMENT,
6429 _("The following server commands are available:"));
6430 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
6431 if (!caller && con_get_style()) {
6432 for (i = 0; i < CMD_NUM; i++) {
6433 cmd_reply(help_cmd, caller, C_COMMENT, "%s", command_name_by_number(i));
6434 }
6435 } else {
6436 char buf[MAX_LEN_CONSOLE_LINE];
6437 int j;
6438
6439 buf[0] = '\0';
6440 for (i=0, j=0; i<CMD_NUM; i++) {
6441 if (may_use(caller, i)) {
6442 cat_snprintf(buf, sizeof(buf), "%-19s", command_name_by_number(i));
6443 if ((++j % 4) == 0) {
6444 cmd_reply(help_cmd, caller, C_COMMENT, "%s", buf);
6445 buf[0] = '\0';
6446 }
6447 }
6448 }
6449 if (buf[0] != '\0') {
6450 cmd_reply(help_cmd, caller, C_COMMENT, "%s", buf);
6451 }
6452 }
6453 cmd_reply(help_cmd, caller, C_COMMENT, horiz_line);
6454}
6455
6456/**********************************************************************/
6460static void cmd_reply_matches(enum command_id cmd,
6461 struct connection *caller,
6462 m_pre_accessor_fn_t accessor_fn,
6463 int *matches, int num_matches)
6464{
6465 char buf[MAX_LEN_MSG];
6466 const char *src, *end;
6467 char *dest;
6468 int i;
6469
6470 if (accessor_fn == NULL || matches == NULL || num_matches < 1) {
6471 return;
6472 }
6473
6474 dest = buf;
6475 end = buf + sizeof(buf) - 1;
6476
6477 for (i = 0; i < num_matches && dest < end; i++) {
6478 src = accessor_fn(matches[i]);
6479 if (!src) {
6480 continue;
6481 }
6482 if (dest != buf) {
6483 *dest++ = ' ';
6484 }
6485 while (*src != '\0' && dest < end) {
6486 *dest++ = *src++;
6487 }
6488 }
6489 *dest = '\0';
6490
6491 cmd_reply(cmd, caller, C_COMMENT, _("Possible matches: %s"), buf);
6492}
6493
6494/**************************************************************************
6495 Additional 'help' arguments
6496**************************************************************************/
6497#define SPECENUM_NAME help_general_args
6498#define SPECENUM_VALUE0 HELP_GENERAL_COMMANDS
6499#define SPECENUM_VALUE0NAME "commands"
6500#define SPECENUM_VALUE1 HELP_GENERAL_OPTIONS
6501#define SPECENUM_VALUE1NAME "options"
6502#define SPECENUM_COUNT HELP_GENERAL_COUNT
6503#include "specenum_gen.h"
6504
6505/**************************************************************************
6506 Unified indices for help arguments:
6507 CMD_NUM - Server commands
6508 HELP_GENERAL_NUM - General help arguments, above
6509 settings_number() - Server options
6510**************************************************************************/
6511#define HELP_ARG_NUM (CMD_NUM + HELP_GENERAL_COUNT + settings_number())
6512
6513/**********************************************************************/
6516static const char *helparg_accessor(int i)
6517{
6518 if (i < CMD_NUM) {
6519 return command_name_by_number(i);
6520 }
6521
6522 i -= CMD_NUM;
6523 if (i < HELP_GENERAL_COUNT) {
6524 return help_general_args_name((enum help_general_args) i);
6525 }
6526
6527 i -= HELP_GENERAL_COUNT;
6528 return optname_accessor(i);
6529}
6530
6531/**********************************************************************/
6534static bool show_help(struct connection *caller, char *arg)
6535{
6536 int matches[64], num_matches = 0;
6537 enum m_pre_result match_result;
6538 int ind;
6539
6541 /* no commands means no help, either */
6542
6544 fc_strncasecmp, NULL, arg, &ind, matches,
6545 ARRAY_SIZE(matches), &num_matches);
6546
6547 if (match_result == M_PRE_EMPTY) {
6548 show_help_intro(caller, CMD_HELP);
6549 return FALSE;
6550 }
6551 if (match_result == M_PRE_AMBIGUOUS) {
6552 cmd_reply(CMD_HELP, caller, C_FAIL,
6553 _("Help argument '%s' is ambiguous."), arg);
6555 matches, num_matches);
6556 return FALSE;
6557 }
6558 if (match_result == M_PRE_FAIL) {
6559 cmd_reply(CMD_HELP, caller, C_FAIL,
6560 _("No match for help argument '%s'."), arg);
6561 return FALSE;
6562 }
6563
6564 /* other cases should be above */
6565 fc_assert_ret_val(match_result < M_PRE_AMBIGUOUS, FALSE);
6566
6567 if (ind < CMD_NUM) {
6568 show_help_command(caller, CMD_HELP, ind);
6569 return TRUE;
6570 }
6571 ind -= CMD_NUM;
6572
6573 if (ind == HELP_GENERAL_OPTIONS) {
6575 return TRUE;
6576 }
6577 if (ind == HELP_GENERAL_COMMANDS) {
6579 return TRUE;
6580 }
6581 ind -= HELP_GENERAL_COUNT;
6582
6583 if (ind < settings_number()) {
6584 show_help_option(caller, CMD_HELP, ind);
6585 return TRUE;
6586 }
6587
6588 /* should have finished by now */
6589 log_error("Bug in show_help!");
6590 return FALSE;
6591}
6592
6593/**********************************************************************/
6596static void show_connections(struct connection *caller)
6597{
6598 char buf[MAX_LEN_CONSOLE_LINE];
6599
6600 cmd_reply(CMD_LIST, caller, C_COMMENT,
6601 _("List of connections to server:"));
6603
6604 if (conn_list_size(game.all_connections) == 0) {
6605 cmd_reply(CMD_LIST, caller, C_COMMENT, _("<no connections>"));
6606 } else {
6608 sz_strlcpy(buf, conn_description(pconn));
6609 if (pconn->established) {
6610 cat_snprintf(buf, sizeof(buf), " command access level %s",
6611 cmdlevel_name(pconn->access_level));
6612 }
6613 cmd_reply(CMD_LIST, caller, C_COMMENT, "%s", buf);
6615 }
6617}
6618
6619/**********************************************************************/
6622static void show_delegations(struct connection *caller)
6623{
6624 bool empty = TRUE;
6625
6626 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of all delegations:"));
6628
6629 players_iterate(pplayer) {
6630 const char *delegate_to = player_delegation_get(pplayer);
6631 if (delegate_to != NULL) {
6632 const char *owner =
6633 player_delegation_active(pplayer) ? pplayer->server.orig_username
6634 : pplayer->username;
6636 cmd_reply(CMD_LIST, caller, C_COMMENT,
6637 /* TRANS: last %s is either " (active)" or empty string */
6638 _("%s delegates control over player '%s' to user %s%s."),
6639 owner, player_name(pplayer), delegate_to,
6640 /* TRANS: preserve leading space */
6641 player_delegation_active(pplayer) ? _(" (active)") : "");
6642 empty = FALSE;
6643 }
6645
6646 if (empty) {
6647 cmd_reply(CMD_LIST, caller, C_COMMENT, _("No delegations defined."));
6648 }
6649
6651}
6652
6653/**********************************************************************/
6656static bool show_ignore(struct connection *caller)
6657{
6658 char buf[128];
6659 int n = 1;
6660
6661 if (NULL == caller) {
6662 cmd_reply(CMD_IGNORE, caller, C_FAIL,
6663 _("That would be rather silly, since you are not a player."));
6664 return FALSE;
6665 }
6666
6667 if (0 == conn_pattern_list_size(caller->server.ignore_list)) {
6668 cmd_reply(CMD_LIST, caller, C_COMMENT, _("Your ignore list is empty."));
6669 return TRUE;
6670 }
6671
6672 cmd_reply(CMD_LIST, caller, C_COMMENT, _("Your ignore list:"));
6674 conn_pattern_list_iterate(caller->server.ignore_list, ppattern) {
6675 conn_pattern_to_string(ppattern, buf, sizeof(buf));
6676 cmd_reply(CMD_LIST, caller, C_COMMENT, "%d: %s", n++, buf);
6679
6680 return TRUE;
6681}
6682
6683/**********************************************************************/
6686void show_players(struct connection *caller)
6687{
6688 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of players:"));
6690
6691 if (player_count() == 0) {
6692 cmd_reply(CMD_LIST, caller, C_COMMENT, _("<no players>"));
6693 } else {
6694 players_iterate(pplayer) {
6695 char buf[MAX_LEN_CONSOLE_LINE];
6696 int n;
6697
6698 /* Low access level callers don't get to see barbarians in list: */
6699 if (is_barbarian(pplayer) && caller
6700 && (caller->access_level < ALLOW_CTRL)) {
6701 continue;
6702 }
6703
6704 /* The output for each player looks like:
6705 *
6706 * <Player name> [color]: Team[, Nation][, Username][, Status]
6707 * AI/Barbarian/Human[, AI type, skill level][, Connections]
6708 * [Details for each connection]
6709 */
6710
6711 /* '<Player name> [color]: [Nation][, Username][, Status]' */
6712 buf[0] = '\0';
6713 cat_snprintf(buf, sizeof(buf), "%s [%s]: %s", player_name(pplayer),
6714 player_color_ftstr(pplayer),
6715 team_name_translation(pplayer->team));
6716 if (!game.info.is_new_game) {
6717 cat_snprintf(buf, sizeof(buf), ", %s",
6719 }
6720 if (strlen(pplayer->username) > 0
6721 && strcmp(pplayer->username, "nouser") != 0) {
6722 cat_snprintf(buf, sizeof(buf), _(", user %s"), pplayer->username);
6723 }
6724 if (S_S_INITIAL == server_state() && pplayer->is_connected) {
6725 if (pplayer->is_ready) {
6726 sz_strlcat(buf, _(", ready"));
6727 } else {
6728 /* Emphasizes this */
6729 n = strlen(buf);
6730 featured_text_apply_tag(_(", not ready"),
6731 buf + n, sizeof(buf) - n,
6733 ftc_changed);
6734 }
6735 } else if (!pplayer->is_alive) {
6736 sz_strlcat(buf, _(", Dead"));
6737 }
6738 cmd_reply(CMD_LIST, caller, C_COMMENT, "%s", buf);
6739
6740 /* ' AI/Barbarian/Human[, skill level][, Connections]' */
6741 buf[0] = '\0';
6742 if (is_barbarian(pplayer)) {
6743 sz_strlcat(buf, _("Barbarian"));
6744 } else if (is_ai(pplayer)) {
6745 sz_strlcat(buf, _("AI"));
6746 } else {
6747 sz_strlcat(buf, _("Human"));
6748 }
6749 if (is_ai(pplayer)) {
6750 cat_snprintf(buf, sizeof(buf), _(", %s"), ai_name(pplayer->ai));
6751 cat_snprintf(buf, sizeof(buf), _(", difficulty level %s"),
6752 ai_level_translated_name(pplayer->ai_common.skill_level));
6753 }
6754 n = conn_list_size(pplayer->connections);
6755 if (n > 0) {
6756 cat_snprintf(buf, sizeof(buf),
6757 PL_(", %d connection:", ", %d connections:", n), n);
6758 }
6759 cmd_reply(CMD_LIST, caller, C_COMMENT, " %s", buf);
6760
6761 /* ' [Details for each connection]' */
6762 conn_list_iterate(pplayer->connections, pconn) {
6763 fc_snprintf(buf, sizeof(buf),
6764 _("%s from %s (command access level %s), "
6765 "bufsize=%dkb"), pconn->username, pconn->addr,
6766 cmdlevel_name(pconn->access_level),
6767 (pconn->send_buffer->nsize >> 10));
6768 if (pconn->observer) {
6769 /* TRANS: preserve leading space */
6770 sz_strlcat(buf, _(" (observer mode)"));
6771 }
6772 cmd_reply(CMD_LIST, caller, C_COMMENT, " %s", buf);
6775 }
6777}
6778
6779/**********************************************************************/
6783static void show_rulesets(struct connection *caller)
6784{
6785 struct strvec *serv_list;
6786
6787 cmd_reply(CMD_LIST, caller, C_COMMENT,
6788 /* TRANS: don't translate text between '' */
6789 _("List of rulesets available with '%sread' command:"),
6790 (caller ? "/" : ""));
6792
6793 serv_list = get_init_script_choices();
6794 strvec_iterate(serv_list, s) {
6795 cmd_reply(CMD_LIST, caller, C_COMMENT, "%s", s);
6797 strvec_destroy(serv_list);
6798
6800}
6801
6802/**********************************************************************/
6805static void show_scenarios(struct connection *caller)
6806{
6807 char buf[MAX_LEN_CONSOLE_LINE];
6808 struct fileinfo_list *files;
6809
6810 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of scenarios available:"));
6812
6813 files = fileinfolist_infix(get_scenario_dirs(), ".sav", TRUE);
6814
6815 fileinfo_list_iterate(files, pfile) {
6816 struct section_file *sf = secfile_load_section(pfile->fullname, "scenario", TRUE);
6817
6818 if (secfile_lookup_bool_default(sf, TRUE, "scenario.is_scenario")) {
6819 fc_snprintf(buf, sizeof(buf), "%s", pfile->name);
6820 cmd_reply(CMD_LIST, caller, C_COMMENT, "%s", buf);
6821 }
6823 fileinfo_list_destroy(files);
6824
6826}
6827
6828/**********************************************************************/
6831static void show_nationsets(struct connection *caller)
6832{
6833 cmd_reply(CMD_LIST, caller, C_COMMENT,
6834 /* TRANS: don't translate text between '' */
6835 _("List of nation sets available for 'nationset' option:"));
6837
6838 nation_sets_iterate(pset) {
6839 const char *description = nation_set_description(pset);
6840 int num_nations = 0;
6841 nations_iterate(pnation) {
6842 if (is_nation_playable(pnation) && nation_is_in_set(pnation, pset)) {
6843 num_nations++;
6844 }
6846 cmd_reply(CMD_LIST, caller, C_COMMENT,
6847 /* TRANS: nation set description; %d refers to number of playable
6848 * nations in set */
6849 PL_(" %-10s %s (%d playable)",
6850 " %-10s %s (%d playable)", num_nations),
6852 num_nations);
6853 if (strlen(description) > 0) {
6854 static const char prefix[] = " ";
6855 char *translated = fc_strdup(_(description));
6857 cmd_reply_prefix(CMD_LIST, caller, C_COMMENT, prefix, "%s%s",
6858 prefix, translated);
6859 }
6861
6863}
6864
6865/**********************************************************************/
6868static void show_teams(struct connection *caller)
6869{
6870 /* Currently this just lists all teams (typically 32 of them) with their
6871 * names and # of players on the team. This could probably be improved. */
6872 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of teams:"));
6874
6875 teams_iterate(pteam) {
6876 const struct player_list *members = team_members(pteam);
6877
6878 /* PL_() is needed here because some languages may differentiate
6879 * between 2 and 3 (although English does not). */
6880 cmd_reply(CMD_LIST, caller, C_COMMENT,
6881 /* TRANS: There will always be at least 2 players here. */
6882 PL_("%2d : '%s' : %d player :",
6883 "%2d : '%s' : %d players :",
6884 player_list_size(members)),
6885 team_index(pteam), team_name_translation(pteam),
6886 player_list_size(members));
6887 player_list_iterate(members, pplayer) {
6888 cmd_reply(CMD_LIST, caller, C_COMMENT, " %s", player_name(pplayer));
6891
6893}
6894
6895/**********************************************************************/
6898static void show_mapimg(struct connection *caller, enum command_id cmd)
6899{
6900 int id;
6901
6902 if (mapimg_count() == 0) {
6903 cmd_reply(cmd, caller, C_OK, _("No map image definitions."));
6904 } else {
6905 cmd_reply(cmd, caller, C_COMMENT, _("List of map image definitions:"));
6906 cmd_reply(cmd, caller, C_COMMENT, horiz_line);
6907 for (id = 0; id < mapimg_count(); id++) {
6908 char str[MAX_LEN_MAPDEF] = "";
6909 mapimg_show(id, str, sizeof(str), FALSE);
6910 cmd_reply(cmd, caller, C_COMMENT, _("[%2d] %s"), id, str);
6911 }
6912 cmd_reply(cmd, caller, C_COMMENT, horiz_line);
6913 }
6914}
6915
6916/**********************************************************************/
6919static void show_colors(struct connection *caller)
6920{
6921 cmd_reply(CMD_LIST, caller, C_COMMENT, _("List of player colors:"));
6923 if (player_count() == 0) {
6924 cmd_reply(CMD_LIST, caller, C_COMMENT, _("<no players>"));
6925 } else {
6926 players_iterate(pplayer) {
6927 cmd_reply(CMD_LIST, caller, C_COMMENT, _("%s (user %s): [%s]"),
6928 player_name(pplayer), pplayer->username,
6929 player_color_ftstr(pplayer));
6931 }
6933}
6934
6935/**************************************************************************
6936 '/list' arguments
6937**************************************************************************/
6938#define SPECENUM_NAME list_args
6939#define SPECENUM_VALUE0 LIST_COLORS
6940#define SPECENUM_VALUE0NAME "colors"
6941#define SPECENUM_VALUE1 LIST_CONNECTIONS
6942#define SPECENUM_VALUE1NAME "connections"
6943#define SPECENUM_VALUE2 LIST_DELEGATIONS
6944#define SPECENUM_VALUE2NAME "delegations"
6945#define SPECENUM_VALUE3 LIST_IGNORE
6946#define SPECENUM_VALUE3NAME "ignored users"
6947#define SPECENUM_VALUE4 LIST_MAPIMG
6948#define SPECENUM_VALUE4NAME "map image definitions"
6949#define SPECENUM_VALUE5 LIST_PLAYERS
6950#define SPECENUM_VALUE5NAME "players"
6951#define SPECENUM_VALUE6 LIST_RULESETS
6952#define SPECENUM_VALUE6NAME "rulesets"
6953#define SPECENUM_VALUE7 LIST_SCENARIOS
6954#define SPECENUM_VALUE7NAME "scenarios"
6955#define SPECENUM_VALUE8 LIST_NATIONSETS
6956#define SPECENUM_VALUE8NAME "nationsets"
6957#define SPECENUM_VALUE9 LIST_TEAMS
6958#define SPECENUM_VALUE9NAME "teams"
6959#define SPECENUM_VALUE10 LIST_VOTES
6960#define SPECENUM_VALUE10NAME "votes"
6961#include "specenum_gen.h"
6962
6963/**********************************************************************/
6966static const char *list_accessor(int i)
6967{
6968 i = CLIP(0, i, list_args_max());
6969 return list_args_name((enum list_args) i);
6970}
6971
6972/**********************************************************************/
6975static bool show_list(struct connection *caller, char *arg)
6976{
6977 enum m_pre_result match_result;
6978 int ind_int;
6979 enum list_args ind;
6980
6982 match_result = match_prefix(list_accessor, list_args_max() + 1, 0,
6983 fc_strncasecmp, NULL, arg, &ind_int);
6984 ind = ind_int;
6985
6986 if (match_result > M_PRE_EMPTY) {
6987 cmd_reply(CMD_LIST, caller, C_SYNTAX,
6988 _("Bad list argument: '%s'. Try '%shelp list'."),
6989 arg, (caller ? "/" : ""));
6990 return FALSE;
6991 }
6992
6993 if (match_result == M_PRE_EMPTY) {
6994 ind = LIST_PLAYERS;
6995 }
6996
6997 switch (ind) {
6998 case LIST_COLORS:
6999 show_colors(caller);
7000 return TRUE;
7001 case LIST_CONNECTIONS:
7002 show_connections(caller);
7003 return TRUE;
7004 case LIST_DELEGATIONS:
7005 show_delegations(caller);
7006 return TRUE;
7007 case LIST_IGNORE:
7008 return show_ignore(caller);
7009 case LIST_MAPIMG:
7010 show_mapimg(caller, CMD_LIST);
7011 return TRUE;
7012 case LIST_PLAYERS:
7013 show_players(caller);
7014 return TRUE;
7015 case LIST_RULESETS:
7016 show_rulesets(caller);
7017 return TRUE;
7018 case LIST_SCENARIOS:
7019 show_scenarios(caller);
7020 return TRUE;
7021 case LIST_NATIONSETS:
7022 show_nationsets(caller);
7023 return TRUE;
7024 case LIST_TEAMS:
7025 show_teams(caller);
7026 return TRUE;
7027 case LIST_VOTES:
7028 show_votes(caller);
7029 return TRUE;
7030 }
7031
7032 cmd_reply(CMD_LIST, caller, C_FAIL,
7033 "Internal error: ind %d in show_list", ind);
7034 log_error("Internal error: ind %d in show_list", ind);
7035 return FALSE;
7036}
7037
7038#ifdef FREECIV_HAVE_LIBREADLINE
7039/********************* RL completion functions ***************************/
7040/* To properly complete both commands, player names, options and filenames
7041 there is one array per type of completion with the commands that
7042 the type is relevant for.
7043*/
7044
7045/**********************************************************************/
7053static char *generic_generator(const char *text, int state, int num,
7054 const char*(*index2str)(int))
7055{
7056 static int list_index, len;
7057 const char *name = ""; /* dummy non-NULL string */
7058 char *mytext = local_to_internal_string_malloc(text);
7059
7060 /* This function takes a string (text) in the local format and must return
7061 * a string in the local format. However comparisons are done against
7062 * names that are in the internal format (UTF-8). Thus we have to convert
7063 * the text function from the local to the internal format before doing
7064 * the comparison, and convert the string we return *back* to the
7065 * local format when returning it. */
7066
7067 /* If this is a new word to complete, initialize now. This includes
7068 saving the length of TEXT for efficiency, and initializing the index
7069 variable to 0. */
7070 if (state == 0) {
7071 list_index = 0;
7072 len = strlen(mytext);
7073 }
7074
7075 /* Return the next name which partially matches: */
7076 while ((num < 0 && name) || (list_index < num)) {
7077 name = index2str(list_index);
7078 list_index++;
7079
7080 if (name != NULL && fc_strncasecmp(name, mytext, len) == 0) {
7081 free(mytext);
7083 }
7084 }
7085 free(mytext);
7086
7087 /* If no names matched, then return NULL. */
7088 return ((char *)NULL);
7089}
7090
7091/**********************************************************************/
7094static char *command_generator(const char *text, int state)
7095{
7096 return generic_generator(text, state, CMD_NUM, command_name_by_number);
7097}
7098
7099/**********************************************************************/
7102static char *option_generator(const char *text, int state)
7103{
7104 return generic_generator(text, state, settings_number(), optname_accessor);
7105}
7106
7107/**********************************************************************/
7110static char *olevel_generator(const char *text, int state)
7111{
7112 return generic_generator(text, state, settings_number() + OLEVELS_NUM + 1,
7113 olvlname_accessor);
7114}
7115
7116/**********************************************************************/
7120static int completion_option;
7121static const char *option_value_accessor(int idx) {
7122 const struct setting *pset = setting_by_number(completion_option);
7123
7124 switch (setting_type(pset)) {
7125 case SST_ENUM:
7126 return setting_enum_val(pset, idx, FALSE);
7127 case SST_BITWISE:
7128 return setting_bitwise_bit(pset, idx, FALSE);
7129 default:
7131 }
7132
7133 return NULL;
7134}
7135
7136/**********************************************************************/
7140static char *option_value_generator(const char *text, int state)
7141{
7142 return generic_generator(text, state, -1, option_value_accessor);
7143}
7144
7145/**********************************************************************/
7148static const char *playername_accessor(int idx)
7149{
7150 const struct player_slot *pslot = player_slot_by_number(idx);
7151
7152 if (!player_slot_is_used(pslot)) {
7153 return NULL;
7154 }
7155
7156 return player_name(player_slot_get_player(pslot));
7157}
7158
7159/**********************************************************************/
7162static char *player_generator(const char *text, int state)
7163{
7164 return generic_generator(text, state, player_slot_count(),
7165 playername_accessor);
7166}
7167
7168/**********************************************************************/
7171static const char *connection_name_accessor(int idx)
7172{
7173 return conn_list_get(game.all_connections, idx)->username;
7174}
7175
7176/**********************************************************************/
7179static char *connection_generator(const char *text, int state)
7180{
7181 return generic_generator(text, state, conn_list_size(game.all_connections),
7182 connection_name_accessor);
7183}
7184
7185/**********************************************************************/
7188static const char *cmdlevel_arg1_accessor(int idx)
7189{
7190 return cmdlevel_name(idx);
7191}
7192
7193/**********************************************************************/
7196static char *cmdlevel_arg1_generator(const char *text, int state)
7197{
7198 return generic_generator(text, state, cmdlevel_max()+1,
7199 cmdlevel_arg1_accessor);
7200}
7201
7202/**********************************************************************/
7206static const char *cmdlevel_arg2_accessor(int idx)
7207{
7208 return ((idx == 0) ? "first" :
7209 (idx == 1) ? "new" :
7210 connection_name_accessor(idx - 2));
7211}
7212
7213/**********************************************************************/
7216static char *cmdlevel_arg2_generator(const char *text, int state)
7217{
7218 return generic_generator(text, state,
7219 /* "first", "new", connection names */
7220 2 + conn_list_size(game.all_connections),
7221 cmdlevel_arg2_accessor);
7222}
7223
7224/**********************************************************************/
7227static const char *aitype_accessor(int idx)
7228{
7229 return get_ai_type(idx)->name;
7230}
7231
7232/**********************************************************************/
7235static char *aitype_generator(const char *text, int state)
7236{
7237 return generic_generator(text, state, ai_type_get_count(),
7238 aitype_accessor);
7239}
7240
7241/**********************************************************************/
7244static char *reset_generator(const char *text, int state)
7245{
7246 return generic_generator(text, state, reset_args_max() + 1, reset_accessor);
7247}
7248
7249/**********************************************************************/
7252static char *vote_generator(const char *text, int state)
7253{
7254 return generic_generator(text, state, -1, vote_arg_accessor);
7255}
7256
7257/**********************************************************************/
7260static char *delegate_generator(const char *text, int state)
7261{
7262 return generic_generator(text, state, delegate_args_max() + 1,
7264}
7265
7266/**********************************************************************/
7269static char *mapimg_generator(const char *text, int state)
7270{
7271 return generic_generator(text, state, mapimg_args_max() + 1,
7273}
7274
7275/**********************************************************************/
7278static char *fcdb_generator(const char *text, int state)
7279{
7280 return generic_generator(text, state, FCDB_COUNT, fcdb_accessor);
7281}
7282
7283/**********************************************************************/
7286static char *lua_generator(const char *text, int state)
7287{
7288 return generic_generator(text, state, lua_args_max() + 1, lua_accessor);
7289}
7290
7291/**********************************************************************/
7294static char *help_generator(const char *text, int state)
7295{
7296 return generic_generator(text, state, HELP_ARG_NUM, helparg_accessor);
7297}
7298
7299/**********************************************************************/
7302static char *list_generator(const char *text, int state)
7303{
7304 return generic_generator(text, state, list_args_max() + 1, list_accessor);
7305}
7306
7307/**********************************************************************/
7311static bool contains_token_before_start(int start, int token, const char *arg,
7312 bool allow_fluff)
7313{
7314 char *str_itr = rl_line_buffer;
7315 int arg_len = strlen(arg);
7316
7317 /* Swallow unwanted tokens and their preceding delimiters */
7318 while (token--) {
7319 while (str_itr < rl_line_buffer + start && !fc_isalnum(*str_itr)) {
7320 str_itr++;
7321 }
7322 while (str_itr < rl_line_buffer + start && fc_isalnum(*str_itr)) {
7323 str_itr++;
7324 }
7325 }
7326
7327 /* Swallow any delimiters before the token we're interested in */
7328 while (str_itr < rl_line_buffer + start && !fc_isalnum(*str_itr)) {
7329 str_itr++;
7330 }
7331
7332 if (fc_strncasecmp(str_itr, arg, arg_len) != 0) {
7333 return FALSE;
7334 }
7335 str_itr += arg_len;
7336
7337 if (fc_isalnum(*str_itr)) {
7338 /* Not a distinct word. */
7339 return FALSE;
7340 }
7341
7342 if (!allow_fluff) {
7343 for (; str_itr < rl_line_buffer + start; str_itr++) {
7344 if (fc_isalnum(*str_itr)) {
7345 return FALSE;
7346 }
7347 }
7348 }
7349
7350 return TRUE;
7351}
7352
7353/**********************************************************************/
7358static bool contains_str_before_start(int start, const char *cmd,
7359 bool allow_fluff)
7360{
7361 return contains_token_before_start(start, 0, cmd, allow_fluff);
7362}
7363
7364/**********************************************************************/
7368static bool is_command(int start)
7369{
7370 char *str_itr;
7371
7372 if (contains_str_before_start(start, command_name_by_number(CMD_HELP), FALSE))
7373 return TRUE;
7374
7375 /* if there is only it is also OK */
7376 str_itr = rl_line_buffer;
7377 while (str_itr - rl_line_buffer < start) {
7378 if (fc_isalnum(*str_itr)) {
7379 return FALSE;
7380 }
7381 str_itr++;
7382 }
7383 return TRUE;
7384}
7385
7386/**********************************************************************/
7389static int num_tokens(int start)
7390{
7391 int res = 0;
7392 bool alnum = FALSE;
7393 char *chptr = rl_line_buffer;
7394
7395 while (chptr - rl_line_buffer < start) {
7396 if (fc_isalnum(*chptr)) {
7397 if (!alnum) {
7398 alnum = TRUE;
7399 res++;
7400 }
7401 } else {
7402 alnum = FALSE;
7403 }
7404 chptr++;
7405 }
7406
7407 return res;
7408}
7409
7410/**************************************************************************
7411 Commands that may be followed by a player name
7412**************************************************************************/
7413static const int player_cmd[] = {
7416 CMD_NOVICE,
7417 CMD_EASY,
7418 CMD_NORMAL,
7419 CMD_HARD,
7421#ifdef FREECIV_DEBUG
7422 CMD_EXPERIMENTAL,
7423#endif
7424 CMD_REMOVE,
7425 CMD_TEAM,
7427 -1
7428};
7429
7430/**********************************************************************/
7433static bool is_player(int start)
7434{
7435 int i = 0;
7436
7437 while (player_cmd[i] != -1) {
7438 if (contains_str_before_start(start, command_name_by_number(player_cmd[i]), FALSE)) {
7439 return TRUE;
7440 }
7441 i++;
7442 }
7443
7444 return FALSE;
7445}
7446
7447/**************************************************************************
7448 Commands that may be followed by a connection name
7449**************************************************************************/
7450static const int connection_cmd[] = {
7451 CMD_CUT,
7452 CMD_KICK,
7453 -1
7454};
7455
7456/**********************************************************************/
7459static bool is_connection(int start)
7460{
7461 int i = 0;
7462
7463 while (connection_cmd[i] != -1) {
7464 if (contains_str_before_start(start,
7465 command_name_by_number(connection_cmd[i]),
7466 FALSE)) {
7467 return TRUE;
7468 }
7469 i++;
7470 }
7471
7472 return FALSE;
7473}
7474
7475/**********************************************************************/
7478static bool is_cmdlevel_arg2(int start)
7479{
7480 return (contains_str_before_start(start, command_name_by_number(CMD_CMDLEVEL), TRUE)
7481 && num_tokens(start) == 2);
7482}
7483
7484/**********************************************************************/
7487static bool is_cmdlevel_arg1(int start)
7488{
7489 return contains_str_before_start(start, command_name_by_number(CMD_CMDLEVEL), FALSE);
7490}
7491
7492/**************************************************************************
7493 Commands that may be followed by a server option name
7494
7495 CMD_SHOW is handled by option_level_cmd, which is for both option levels
7496 and server options
7497**************************************************************************/
7498static const int server_option_cmd[] = {
7500 CMD_SET,
7502 -1
7503};
7504
7505/**********************************************************************/
7509static bool is_server_option(int start)
7510{
7511 int i = 0;
7512
7513 while (server_option_cmd[i] != -1) {
7514 if (contains_str_before_start(start, command_name_by_number(server_option_cmd[i]),
7515 FALSE)) {
7516 return TRUE;
7517 }
7518 i++;
7519 }
7520
7521 return FALSE;
7522}
7523
7524/**************************************************************************
7525 Commands that may be followed by an option level or server option
7526**************************************************************************/
7527static const int option_level_cmd[] = {
7528 CMD_SHOW,
7529 -1
7530};
7531
7532/**********************************************************************/
7536static bool is_option_level(int start)
7537{
7538 int i = 0;
7539
7540 while (option_level_cmd[i] != -1) {
7541 if (contains_str_before_start(start, command_name_by_number(option_level_cmd[i]),
7542 FALSE)) {
7543 return TRUE;
7544 }
7545 i++;
7546 }
7547
7548 return FALSE;
7549}
7550
7551/**********************************************************************/
7556static bool is_enum_option_value(int start, int *opt_p)
7557{
7558 if (contains_str_before_start(start, command_name_by_number(CMD_SET),
7559 TRUE)) {
7560 settings_iterate(SSET_ALL, pset) {
7561 if (setting_type(pset) != SST_ENUM
7562 && setting_type(pset) != SST_BITWISE) {
7563 continue;
7564 }
7565 /* Allow a single token for enum options, multiple for bitwise
7566 * (the separator | will separate tokens for these purposes) */
7567 if (contains_token_before_start(start, 1, setting_name(pset),
7568 setting_type(pset) == SST_BITWISE)) {
7569 *opt_p = setting_number(pset);
7570 /* Suppress appended space for bitwise options (user may want |) */
7571 rl_completion_suppress_append = (setting_type(pset) == SST_BITWISE);
7572 return TRUE;
7573 }
7575 }
7576 return FALSE;
7577}
7578
7579/**************************************************************************
7580 Commands that may be followed by a filename
7581**************************************************************************/
7582static const int filename_cmd[] = {
7583 CMD_LOAD,
7584 CMD_SAVE,
7587 -1
7588};
7589
7590/**********************************************************************/
7593static bool is_filename(int start)
7594{
7595 int i = 0;
7596
7597 while (filename_cmd[i] != -1) {
7598 if (contains_str_before_start(start, command_name_by_number(filename_cmd[i]), FALSE)) {
7599 return TRUE;
7600 }
7601 i++;
7602 }
7603
7604 return FALSE;
7605}
7606
7607/**********************************************************************/
7610static bool is_create_arg2(int start)
7611{
7612 return (contains_str_before_start(start, command_name_by_number(CMD_CREATE), TRUE)
7613 && num_tokens(start) == 2);
7614}
7615
7616/**********************************************************************/
7619static bool is_reset(int start)
7620{
7621 return contains_str_before_start(start,
7623 FALSE);
7624}
7625
7626/**********************************************************************/
7629static bool is_vote(int start)
7630{
7631 return contains_str_before_start(start,
7633 FALSE);
7634}
7635
7636/**********************************************************************/
7639static bool is_delegate_arg1(int start)
7640{
7641 return contains_str_before_start(start,
7643 FALSE);
7644}
7645
7646/**********************************************************************/
7649static bool is_mapimg(int start)
7650{
7651 return contains_str_before_start(start,
7653 FALSE);
7654}
7655
7656/**********************************************************************/
7659static bool is_fcdb(int start)
7660{
7661 return contains_str_before_start(start,
7663 FALSE);
7664}
7665
7666/**********************************************************************/
7669static bool is_lua(int start)
7670{
7671 return contains_str_before_start(start,
7673 FALSE);
7674}
7675
7676/**********************************************************************/
7679static bool is_help(int start)
7680{
7681 return contains_str_before_start(start, command_name_by_number(CMD_HELP), FALSE);
7682}
7683
7684/**********************************************************************/
7687static bool is_list(int start)
7688{
7689 return contains_str_before_start(start, command_name_by_number(CMD_LIST), FALSE);
7690}
7691
7692/**********************************************************************/
7699char **freeciv_completion(const char *text, int start, int end)
7700{
7701 char **matches = (char **)NULL;
7702
7703 if (is_help(start)) {
7704 matches = rl_completion_matches(text, help_generator);
7705 } else if (is_command(start)) {
7706 matches = rl_completion_matches(text, command_generator);
7707 } else if (is_list(start)) {
7708 matches = rl_completion_matches(text, list_generator);
7709 } else if (is_cmdlevel_arg2(start)) {
7710 matches = rl_completion_matches(text, cmdlevel_arg2_generator);
7711 } else if (is_cmdlevel_arg1(start)) {
7712 matches = rl_completion_matches(text, cmdlevel_arg1_generator);
7713 } else if (is_connection(start)) {
7714 matches = rl_completion_matches(text, connection_generator);
7715 } else if (is_player(start)) {
7716 matches = rl_completion_matches(text, player_generator);
7717 } else if (is_server_option(start)) {
7718 matches = rl_completion_matches(text, option_generator);
7719 } else if (is_option_level(start)) {
7720 matches = rl_completion_matches(text, olevel_generator);
7721 } else if (is_enum_option_value(start, &completion_option)) {
7722 matches = rl_completion_matches(text, option_value_generator);
7723 } else if (is_filename(start)) {
7724 /* This function we get from readline */
7725 matches = rl_completion_matches(text, rl_filename_completion_function);
7726 } else if (is_create_arg2(start)) {
7727 matches = rl_completion_matches(text, aitype_generator);
7728 } else if (is_reset(start)) {
7729 matches = rl_completion_matches(text, reset_generator);
7730 } else if (is_vote(start)) {
7731 matches = rl_completion_matches(text, vote_generator);
7732 } else if (is_delegate_arg1(start)) {
7733 matches = rl_completion_matches(text, delegate_generator);
7734 } else if (is_mapimg(start)) {
7735 matches = rl_completion_matches(text, mapimg_generator);
7736 } else if (is_fcdb(start)) {
7737 matches = rl_completion_matches(text, fcdb_generator);
7738 } else if (is_lua(start)) {
7739 matches = rl_completion_matches(text, lua_generator);
7740 } else {
7741 /* We have no idea what to do */
7742 matches = NULL;
7743 }
7744
7745 /* Don't automatically try to complete with filenames */
7746 rl_attempted_completion_over = 1;
7747
7748 return (matches);
7749}
7750
7751#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:262
const char * ai_name(const struct ai_type *ai)
Definition ai.c:329
struct ai_type * ai_type_by_name(const char *search)
Definition ai.c:284
int ai_type_get_count(void)
Definition ai.c:321
struct ai_type * get_ai_type(int id)
Definition ai.c:254
#define CALL_PLR_AI_FUNC(_func, _player,...)
Definition ai.h:374
const char * default_ai_type_name(void)
Definition aiiface.c:262
void astr_free(struct astring *astr)
Definition astring.c:153
const char * astr_build_or_list(struct astring *astr, const char *const *items, size_t number)
Definition astring.c:329
void astr_set(struct astring *astr, const char *format,...)
Definition astring.c:267
#define str
Definition astring.c:76
#define n
Definition astring.c:77
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
#define ASTRING_INIT
Definition astring.h:44
#define BV_SET(bv, bit)
Definition bitvector.h:81
#define BV_ISSET(bv, bit)
Definition bitvector.h:78
#define BV_CLR(bv, bit)
Definition bitvector.h:86
#define SERVER_COMMAND_PREFIX
Definition chat.h:28
const char * city_name_get(const struct city *pcity)
Definition city.c:1115
#define city_list_iterate(citylist, pcity)
Definition city.h:488
static citizens city_size_get(const struct city *pcity)
Definition city.h:549
#define city_list_iterate_end
Definition city.h:490
enum cmd_echo command_echo(const struct command *pcommand)
Definition commands.c:787
const char * command_name_by_number(int i)
Definition commands.c:739
const char * command_name(const struct command *pcommand)
Definition commands.c:731
const struct command * command_by_number(int i)
Definition commands.c:722
const char * command_short_help(const struct command *pcommand)
Definition commands.c:755
char * command_extra_help(const struct command *pcommand)
Definition commands.c:764
enum cmdlevel command_level(const struct command *pcommand)
Definition commands.c:779
const char * command_synopsis(const struct command *pcommand)
Definition commands.c:747
command_id
Definition commands.h:34
@ CMD_NUM
Definition commands.h:105
@ CMD_IGNORE
Definition commands.h:77
@ 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:52
@ CMD_DELEGATE
Definition commands.h:95
@ CMD_CHEATING
Definition commands.h:69
@ CMD_PLAYERCOLOR
Definition commands.h:79
@ CMD_LIST
Definition commands.h:38
@ CMD_AITOGGLE
Definition commands.h:58
@ CMD_CUT
Definition commands.h:40
@ CMD_EXPLAIN
Definition commands.h:43
@ CMD_SHOW
Definition commands.h:44
@ CMD_METAMESSAGE
Definition commands.h:54
@ CMD_RULESETDIR
Definition commands.h:53
@ CMD_HARD
Definition commands.h:68
@ CMD_RFCSTYLE
Definition commands.h:101
@ CMD_DETACH
Definition commands.h:61
@ CMD_NORMAL
Definition commands.h:67
@ CMD_RESTRICTED
Definition commands.h:64
@ CMD_VOTE
Definition commands.h:47
@ CMD_NOVICE
Definition commands.h:65
@ CMD_UNRECOGNIZED
Definition commands.h:106
@ 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:107
@ 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:102
@ CMD_SCENSAVE
Definition commands.h:87
@ CMD_START_GAME
Definition commands.h:36
@ CMD_UNIGNORE
Definition commands.h:78
@ CMD_FIRSTLEVEL
Definition commands.h:74
@ CMD_WALL
Definition commands.h:45
@ CMD_EASY
Definition commands.h:66
@ CMD_KICK
Definition commands.h:94
@ CMD_WRITE_SCRIPT
Definition commands.h:90
@ CMD_CONNECTMSG
Definition commands.h:46
@ CMD_TAKE
Definition commands.h:59
@ CMD_HELP
Definition commands.h:37
@ 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:51
@ CMD_AWAY
Definition commands.h:63
@ CMD_QUIT
Definition commands.h:39
@ CMD_DEBUG
Definition commands.h:50
@ CMD_PLAYERNATION
Definition commands.h:80
@ CMD_MAPIMG
Definition commands.h:98
@ CMD_ECHO_ADMINS
Definition commands.h:21
@ CMD_ECHO_NONE
Definition commands.h:20
@ CMD_ECHO_ALL
Definition commands.h:22
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:68
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:862
struct player * conn_get_player(const struct connection *pconn)
Definition connection.c:760
struct connection * conn_by_user_prefix(const char *user_name, enum m_pre_result *result)
Definition connection.c:397
struct connection * conn_by_user(const char *user_name)
Definition connection.c:376
void conn_list_compression_thaw(const struct conn_list *pconn_list)
Definition connection.c:729
void conn_pattern_destroy(struct conn_pattern *ppattern)
Definition connection.c:806
void conn_list_compression_freeze(const struct conn_list *pconn_list)
Definition connection.c:717
bool conn_controls_player(const struct connection *pconn)
Definition connection.c:742
const char * conn_description(const struct connection *pconn)
Definition connection.c:473
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:875
enum cmdlevel conn_get_access(const struct connection *pconn)
Definition connection.c:772
#define conn_pattern_list_iterate_end
Definition connection.h:340
#define conn_list_iterate(connlist, pconn)
Definition connection.h:113
#define conn_pattern_list_iterate(plist, ppatern)
Definition connection.h:338
#define conn_list_iterate_end
Definition connection.h:115
bool con_get_style(void)
Definition console.c:264
void con_set_style(bool i)
Definition console.c:251
void con_write(enum rfc_status rfc_status, const char *message,...)
Definition console.c:203
rfc_status
Definition console.h:35
@ C_DISCONNECTED
Definition console.h:43
@ C_BOUNCE
Definition console.h:48
@ C_FAIL
Definition console.h:45
@ C_SYNTAX
Definition console.h:47
@ C_OK
Definition console.h:41
@ C_METAERROR
Definition console.h:46
@ C_GENFAIL
Definition console.h:49
@ C_COMMENT
Definition console.h:37
@ C_WARNING
Definition console.h:50
#define MAX_LEN_CONSOLE_LINE
Definition console.h:19
#define log_deprecation(message,...)
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:73
void set_ai_level_directer(struct player *pplayer, enum ai_level level)
Definition difficulty.c:39
int int id
Definition editgui_g.h:28
void free_tokens(char **tokens, size_t ntokens)
Definition fc_cmdline.c:203
int get_tokens(const char *str, char **tokens, size_t num_tokens, const char *delimiterset)
Definition fc_cmdline.c:166
#define RULESET_SUFFIX
Definition fc_types.h:384
#define MAX_LEN_NAME
Definition fc_types.h:66
#define LINE_BREAK
Definition fc_types.h:77
char * internal_to_local_string_malloc(const char *text)
char * local_to_internal_string_malloc(const char *text)
#define PL_(String1, String2, n)
Definition fcintl.h:71
#define _(String)
Definition fcintl.h:67
size_t featured_text_apply_tag(const char *text_source, char *featured_text, size_t featured_text_len, enum text_tag_type tag_type, ft_offset_t start_offset, ft_offset_t stop_offset,...)
const struct ft_color ftc_log
const struct ft_color ftc_command
const struct ft_color ftc_server
const struct ft_color ftc_any
VAR_ARG_CONST struct ft_color ftc_changed
const struct ft_color ftc_vote_team
const struct ft_color ftc_game_start
const struct ft_color ftc_server_prompt
const struct ft_color ftc_vote_public
#define FT_OFFSET_UNSET
@ TTT_COLOR
struct civ_game game
Definition game.c:57
struct world wld
Definition game.c:58
struct unit * game_unit_by_number(int id)
Definition game.c:111
@ DEBUG_FERRIES
Definition game.h:40
#define GAME_MAX_READ_RECURSION
Definition game.h:720
void send_scenario_description(struct conn_list *dest)
Definition gamehand.c:962
void send_scenario_info(struct conn_list *dest)
Definition gamehand.c:948
void send_game_info(struct conn_list *dest)
Definition gamehand.c:905
struct city * owner
Definition citydlg.c:219
const char * title
Definition repodlgs.c:1313
static GtkWidget * persistent
static char * leader_name
Definition dialogs.c:96
void handle_player_ready(struct player *pplayer, int player_no, bool is_ready)
Definition srv_main.c:2341
const char * name
Definition inputfile.c:127
#define fc_assert_ret(condition)
Definition log.h:191
#define __FC_LINE__
Definition log.h:40
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
#define log_testmatic_alt(altlvl, message,...)
Definition log.h:124
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_normal(message,...)
Definition log.h:107
@ LOG_NORMAL
Definition log.h:32
#define log_error(message,...)
Definition log.h:103
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Definition map.c:417
int map_startpos_count(void)
Definition map.c:1656
bool map_is_empty(void)
Definition map.c:149
bool mapimg_id2str(int id, char *str, size_t str_len)
Definition mapimg.c:1310
bool mapimg_colortest(const char *savename, const char *path)
Definition mapimg.c:1435
struct mapdef * mapimg_isvalid(int id)
Definition mapimg.c:1120
bool mapimg_define(const char *maparg, bool check)
Definition mapimg.c:768
bool mapimg_delete(int id)
Definition mapimg.c:1203
int mapimg_count(void)
Definition mapimg.c:572
bool mapimg_create(struct mapdef *pmapdef, bool force, const char *savename, const char *path)
Definition mapimg.c:1331
const char * mapimg_error(void)
Definition mapimg.c:758
bool mapimg_show(int id, char *str, size_t str_len, bool detail)
Definition mapimg.c:1222
#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:171
bool is_metaserver_open(void)
Definition meta.c:482
char * meta_addr_port(void)
Definition meta.c:202
void server_close_meta(void)
Definition meta.c:454
const char * default_meta_patches_string(void)
Definition meta.c:82
bool send_server_info_to_metaserver(enum meta_flag flag)
Definition meta.c:490
bool server_open_meta(bool persistent)
Definition meta.c:463
const char * get_meta_patches_string(void)
Definition meta.c:106
void set_user_meta_message_string(const char *string)
Definition meta.c:187
#define DEFAULT_META_SERVER_ADDR
Definition meta.h:21
@ META_GOODBYE
Definition meta.h:28
@ META_INFO
Definition meta.h:26
#define translated
const char * nation_rule_name(const struct nation_type *pnation)
Definition nation.c:137
int nations_match(const struct nation_type *pnation1, const struct nation_type *pnation2, bool ignore_conflicts)
Definition nation.c:1205
struct nation_type * nation_of_unit(const struct unit *punit)
Definition nation.c:462
const char * nation_adjective_for_player(const struct player *pplayer)
Definition nation.c:168
const char * nation_set_name_translation(const struct nation_set *pset)
Definition nation.c:817
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:199
bool nation_is_in_set(const struct nation_type *pnation, const struct nation_set *pset)
Definition nation.c:836
const char * nation_set_description(const struct nation_set *pset)
Definition nation.c:827
int nation_set_count(void)
Definition nation.c:690
struct nation_type * nation_by_rule_name(const char *name)
Definition nation.c:120
const char * nation_plural_translation(const struct nation_type *pnation)
Definition nation.c:158
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:177
struct government * init_government_of_nation(const struct nation_type *pnation)
Definition nation.c:658
struct nation_style * style_of_nation(const struct nation_type *pnation)
Definition nation.c:671
#define nation_sets_iterate_end
Definition nation.h:304
#define nation_sets_iterate(NAME_pset)
Definition nation.h:300
#define nations_iterate_end
Definition nation.h:335
#define nations_iterate(NAME_pnation)
Definition nation.h:332
#define NO_NATION_SELECTED
Definition nation.h:29
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
#define MAX_LEN_MSG
Definition packets.h:43
int send_packet_chat_msg(struct connection *pc, const struct packet_chat_msg *packet)
void dlsend_packet_game_load(struct conn_list *dest, bool load_successful, const char *load_filename)
void lsend_packet_achievement_info(struct conn_list *dest, const struct packet_achievement_info *packet)
struct city_list * cities
Definition packhand.c:117
int len
Definition packhand.c:125
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:911
struct player * player_by_number(const int player_id)
Definition player.c:840
int player_count(void)
Definition player.c:808
int player_slot_count(void)
Definition player.c:411
struct player_slot * player_slot_by_number(int player_id)
Definition player.c:456
int player_number(const struct player *pplayer)
Definition player.c:828
const char * player_name(const struct player *pplayer)
Definition player.c:886
struct player * player_by_name(const char *name)
Definition player.c:872
struct player * player_by_user(const char *name)
Definition player.c:931
bool player_set_nation(struct player *pplayer, struct nation_type *pnation)
Definition player.c:852
struct player * player_slot_get_player(const struct player_slot *pslot)
Definition player.c:430
#define ai_level_cmd(_level_)
Definition player.h:565
#define players_iterate_end
Definition player.h:535
#define players_iterate(_pplayer)
Definition player.h:530
#define player_list_iterate(playerlist, pplayer)
Definition player.h:553
#define ANON_USER_NAME
Definition player.h:48
static bool is_barbarian(const struct player *pplayer)
Definition player.h:488
#define is_ai(plr)
Definition player.h:234
#define player_list_iterate_end
Definition player.h:555
#define set_as_human(plr)
Definition player.h:235
#define set_as_ai(plr)
Definition player.h:236
#define ANON_PLAYER_NAME
Definition player.h:43
@ PLAYER_DEBUG_DIPLOMACY
Definition player.h:217
@ PLAYER_DEBUG_TECH
Definition player.h:217
#define is_human(plr)
Definition player.h:233
void server_player_set_name(struct player *pplayer, const char *name)
Definition plrhand.c:2098
struct player * server_create_player(int player_id, const char *ai_tname, struct rgbcolor *prgbcolor, bool allow_ai_type_fallbacking)
Definition plrhand.c:1724
void player_status_add(struct player *plr, enum player_status pstatus)
Definition plrhand.c:3043
int normal_player_count(void)
Definition plrhand.c:3035
void player_set_under_human_control(struct player *pplayer)
Definition plrhand.c:3282
void server_player_set_color(struct player *pplayer, const struct rgbcolor *prgbcolor)
Definition plrhand.c:1653
void player_set_to_ai_mode(struct player *pplayer, enum ai_level skill_level)
Definition plrhand.c:3260
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:1998
bool player_delegation_active(const struct player *pplayer)
Definition plrhand.c:3097
void player_info_thaw(void)
Definition plrhand.c:964
void player_info_freeze(void)
Definition plrhand.c:955
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:2283
const char * player_color_ftstr(struct player *pplayer)
Definition plrhand.c:1673
void send_player_info_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1000
bool player_status_check(struct player *plr, enum player_status pstatus)
Definition plrhand.c:3051
void player_delegation_set(struct player *pplayer, const char *username)
Definition plrhand.c:3081
void server_remove_player(struct player *pplayer)
Definition plrhand.c:1773
void server_player_init(struct player *pplayer, bool initmap, bool needs_team)
Definition plrhand.c:1451
bool player_color_changeable(const struct player *pplayer, const char **reason)
Definition plrhand.c:1547
void assign_player_colors(void)
Definition plrhand.c:1564
bool client_can_pick_nation(const struct nation_type *pnation)
Definition plrhand.c:2444
void send_player_diplstate_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1059
const char * player_delegation_get(const struct player *pplayer)
Definition plrhand.c:3068
bool nation_is_in_current_set(const struct nation_type *pnation)
Definition plrhand.c:2420
void reset_all_start_commands(bool plrchange)
Definition plrhand.c:2554
struct section_file * secfile_load(const char *filename, bool allow_duplicates)
Definition registry.c:50
const char * secfile_error(void)
void secfile_destroy(struct section_file *secfile)
void secfile_check_unused(const struct section_file *secfile)
struct section_file * secfile_load_section(const char *filename, const char *section, bool allow_duplicates)
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
struct research * research_get(const struct player *pplayer)
Definition research.c:126
bool rgbcolor_from_hex(struct rgbcolor **prgbcolor, const char *hex)
Definition rgbcolor.c:162
void rgbcolor_destroy(struct rgbcolor *prgbcolor)
Definition rgbcolor.c:74
bool rgbcolors_are_equal(const struct rgbcolor *c1, const struct rgbcolor *c2)
Definition rgbcolor.c:62
bool load_rulesets(const char *restore, const char *alt, bool compat_mode, rs_conversion_logger logger, bool act, bool buffer_script, bool load_luadata)
Definition ruleset.c:9231
bool reload_rulesets_settings(void)
Definition ruleset.c:9554
void send_rulesets(struct conn_list *dest)
Definition ruleset.c:9577
#define sanity_check()
Definition sanitycheck.h:43
void savegame_load(struct section_file *sfile)
Definition savemain.c:44
void save_game(const char *orig_filename, const char *save_reason, bool scenario)
Definition savemain.c:152
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:3583
void setting_action(const struct setting *pset)
Definition settings.c:4168
const char * setting_default_name(const struct setting *pset, bool pretty, char *buf, size_t buf_len)
Definition settings.c:4102
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:3861
struct setting * setting_by_name(const char *name)
Definition settings.c:3138
void setting_set_to_default(struct setting *pset)
Definition settings.c:4138
const char * setting_value_name(const struct setting *pset, bool pretty, char *buf, size_t buf_len)
Definition settings.c:4066
const char * setting_extra_help(const struct setting *pset, bool constant)
Definition settings.c:3179
int setting_number(const struct setting *pset)
Definition settings.c:3153
struct setting * setting_by_number(int id)
Definition settings.c:3130
bool setting_int_set(struct setting *pset, int val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3563
bool setting_is_visible(const struct setting *pset, struct connection *caller)
Definition settings.c:3326
bool setting_locked(const struct setting *pset)
Definition settings.c:4420
bool setting_non_default(const struct setting *pset)
Definition settings.c:4394
enum sset_type setting_type(const struct setting *pset)
Definition settings.c:3191
bool setting_str_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3634
int setting_int_max(const struct setting *pset)
Definition settings.c:3553
bool setting_bitwise_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:4022
int settings_number(void)
Definition settings.c:5005
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:3654
const char * setting_enum_val(const struct setting *pset, int val, bool pretty)
Definition settings.c:3702
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:183
void setting_changed(struct setting *pset)
Definition settings.c:5341
enum setting_default_level setting_get_setdef(const struct setting *pset)
Definition settings.c:5349
bool setting_enum_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3832
const char * setting_short_help(const struct setting *pset)
Definition settings.c:3170
const char * setting_bitwise_bit(const struct setting *pset, int bit, bool pretty)
Definition settings.c:3887
int setting_int_min(const struct setting *pset)
Definition settings.c:3544
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:4043
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:3508
bool setting_is_changeable(const struct setting *pset, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3289
void settings_reset(void)
Definition settings.c:4971
const char * setting_name(const struct setting *pset)
Definition settings.c:3162
bool settings_game_reset(void)
Definition settings.c:4935
void settings_list_update(void)
Definition settings.c:5270
bool setting_bool_set(struct setting *pset, const char *val, struct connection *caller, char *reject_msg, size_t reject_msg_len)
Definition settings.c:3477
void send_server_setting(struct conn_list *dest, const struct setting *pset)
Definition settings.c:5014
void send_server_settings(struct conn_list *dest)
Definition settings.c:5133
#define settings_iterate(_level, _pset)
Definition settings.h:177
#define settings_iterate_end
Definition settings.h:183
const char * fileinfoname(const struct strvec *dirs, const char *filename)
Definition shared.c:1094
void remove_trailing_spaces(char *s)
Definition shared.c:420
bool str_to_int(const char *str, int *pint)
Definition shared.c:512
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:387
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:1604
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:1711
const struct strvec * get_save_dirs(void)
Definition shared.c:934
void remove_leading_spaces(char *s)
Definition shared.c:402
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:1581
bool is_safe_filename(const char *name)
Definition shared.c:252
void remove_leading_trailing_spaces(char *s)
Definition shared.c:443
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:176
#define MAX_LEN_PATH
Definition shared.h:32
m_pre_result
Definition shared.h:207
@ M_PRE_EXACT
Definition shared.h:208
@ M_PRE_ONLY
Definition shared.h:209
@ M_PRE_LAST
Definition shared.h:214
@ M_PRE_LONG
Definition shared.h:212
@ M_PRE_AMBIGUOUS
Definition shared.h:210
@ M_PRE_EMPTY
Definition shared.h:211
@ M_PRE_FAIL
Definition shared.h:213
#define fileinfo_list_iterate_end
Definition shared.h:178
const char *(* m_pre_accessor_fn_t)(int)
Definition shared.h:220
#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:3382
void player_nation_defaults(struct player *pplayer, struct nation_type *pnation, bool set_name)
Definition srv_main.c:2510
bool force_end_of_sniff
Definition srv_main.c:185
void start_game(void)
Definition srv_main.c:1773
const char * aifill(int amount)
Definition srv_main.c:2395
void set_server_state(enum server_states newstate)
Definition srv_main.c:331
bool game_was_started(void)
Definition srv_main.c:339
struct server_arguments srvarg
Definition srv_main.c:173
void check_for_full_turn_done(void)
Definition srv_main.c:2145
void server_quit(void)
Definition srv_main.c:1810
enum server_states server_state(void)
Definition srv_main.c:323
void server_game_free(void)
Definition srv_main.c:3406
#define TOKEN_DELIMITERS
Definition srvdefs.h:20
static bool write_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:1343
static const char * reset_accessor(int i)
Definition stdinhand.c:4768
static bool set_cmdlevel(struct connection *caller, struct connection *ptarget, enum cmdlevel level)
Definition stdinhand.c:1382
static struct setting * validate_setting_arg(enum command_id cmd, struct connection *caller, char *arg)
Definition stdinhand.c:2934
#define LOOKUP_OPTION_AMBIGUOUS
Definition stdinhand.c:1733
static const char * mapimg_accessor(int i)
Definition stdinhand.c:5617
void cmd_reply(enum command_id cmd, struct connection *caller, enum rfc_status rfc_status, const char *format,...)
Definition stdinhand.c:421
static bool read_init_script_real(struct connection *caller, char *script_filename, bool from_cmdline, bool check, int read_recursion)
Definition stdinhand.c:1192
bool read_init_script(struct connection *caller, char *script_filename, bool from_cmdline, bool check)
Definition stdinhand.c:1174
static bool set_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2968
static enum command_id cmd_of_level(enum ai_level level)
Definition stdinhand.c:1985
static void show_delegations(struct connection *caller)
Definition stdinhand.c:6622
static char setting_status(struct connection *caller, const struct setting *pset)
Definition stdinhand.c:308
static void show_scenarios(struct connection *caller)
Definition stdinhand.c:6805
static bool delegate_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:5127
static bool ignore_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4017
static void show_help_command(struct connection *caller, enum command_id help_cmd, enum command_id id)
Definition stdinhand.c:6376
void set_running_game_access_level(void)
Definition stdinhand.c:1637
void notify_if_first_access_level_is_available(void)
Definition stdinhand.c:1453
static const char * lua_accessor(int i)
Definition stdinhand.c:4928
static const char * fcdb_accessor(int i)
Definition stdinhand.c:5925
static void show_help_command_list(struct connection *caller, enum command_id help_cmd)
Definition stdinhand.c:6422
void stdinhand_turn(void)
Definition stdinhand.c:257
static void show_connections(struct connection *caller)
Definition stdinhand.c:6596
static bool explain_option(struct connection *caller, char *str, bool check)
Definition stdinhand.c:1899
static struct kick_hash * kick_table_by_user
Definition stdinhand.c:119
bool conn_is_kicked(struct connection *pconn, int *time_remaining)
Definition stdinhand.c:6214
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:813
static void show_colors(struct connection *caller)
Definition stdinhand.c:6919
static bool set_ai_level(struct connection *caller, const char *name, enum ai_level level, bool check)
Definition stdinhand.c:2032
static struct kick_hash * kick_table_by_addr
Definition stdinhand.c:118
static void show_help_option_list(struct connection *caller, enum command_id help_cmd)
Definition stdinhand.c:1863
void stdinhand_init(void)
Definition stdinhand.c:244
static bool take_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:3442
static bool wall(char *str, bool check)
Definition stdinhand.c:1932
static enum cmdlevel default_access_level
Definition stdinhand.c:100
static void show_ruleset_info(struct connection *caller, enum command_id cmd, bool check, int read_recursion)
Definition stdinhand.c:2129
void show_players(struct connection *caller)
Definition stdinhand.c:6686
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:6460
#define LOOKUP_OPTION_NO_RESULT
Definition stdinhand.c:1732
static const char * list_accessor(int i)
Definition stdinhand.c:6966
static int lookup_option(const char *name)
Definition stdinhand.c:1744
static bool reset_command(struct connection *caller, char *arg, bool check, int read_recursion)
Definition stdinhand.c:4778
static void show_teams(struct connection *caller)
Definition stdinhand.c:6868
static bool handle_stdin_input_real(struct connection *caller, char *str, bool check, int read_recursion)
Definition stdinhand.c:4393
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:1001
static bool metaconnection_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:530
static bool show_serverid(struct connection *caller, char *arg)
Definition stdinhand.c:663
static void show_nationsets(struct connection *caller)
Definition stdinhand.c:6831
static const char * helparg_accessor(int i)
Definition stdinhand.c:6516
static bool metamessage_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:611
static bool away_command(struct connection *caller, bool check)
Definition stdinhand.c:2088
enum cmdlevel access_level_for_next_connection(void)
Definition stdinhand.c:1439
static bool playercolor_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4141
bool handle_stdin_input_free(struct connection *caller, char *str)
Definition stdinhand.c:4374
void set_ai_level_direct(struct player *pplayer, enum ai_level level)
Definition stdinhand.c:2007
static bool player_name_check(const char *name, char *buf, size_t buflen)
Definition stdinhand.c:194
static bool default_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:4885
static bool create_command(struct connection *caller, const char *str, bool check)
Definition stdinhand.c:755
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:381
static const char * delegate_accessor(int i)
Definition stdinhand.c:5118
static void show_rulesets(struct connection *caller)
Definition stdinhand.c:6783
static bool surrender_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4720
static bool end_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4695
static const char * delegate_player_str(struct player *pplayer, bool observer)
Definition stdinhand.c:5578
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:1735
static bool timeout_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:1674
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:434
static bool metaserver_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:645
bool handle_stdin_input(struct connection *caller, char *str)
Definition stdinhand.c:4366
static bool cut_client_connection(struct connection *caller, char *name, bool check)
Definition stdinhand.c:6171
static void open_metaserver_connection(struct connection *caller, bool persistent)
Definition stdinhand.c:503
#define HELP_ARG_NUM
Definition stdinhand.c:6511
static time_t * time_duplicate(const time_t *t)
Definition stdinhand.c:6203
static void show_mapimg(struct connection *caller, enum command_id cmd)
Definition stdinhand.c:6898
static bool may_use_nothing(struct connection *caller)
Definition stdinhand.c:296
static void show_votes(struct connection *caller)
Definition stdinhand.c:2477
static const char *const vote_args[]
Definition stdinhand.c:2512
static bool show_settings(struct connection *caller, enum command_id called_as, char *str, bool check)
Definition stdinhand.c:2164
static bool a_connection_exists(void)
Definition stdinhand.c:1417
void stdinhand_free(void)
Definition stdinhand.c:265
static bool cmdlevel_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:1467
static bool is_first_access_level_taken(void)
Definition stdinhand.c:1425
#define LOOKUP_OPTION_LEVEL_NAME
Definition stdinhand.c:1734
static bool firstlevel_command(struct connection *caller, bool check)
Definition stdinhand.c:1610
static void start_cmd_reply(struct connection *caller, bool notify, char *msg)
Definition stdinhand.c:6037
static bool connectmsg_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:1944
static const char horiz_line[]
Definition stdinhand.c:178
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:469
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:334
static void show_help_intro(struct connection *caller, enum command_id help_cmd)
Definition stdinhand.c:6343
static bool cancelvote_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:2631
bool load_command(struct connection *caller, const char *filename, bool check, bool cmdline_load)
Definition stdinhand.c:3737
static void show_settings_one(struct connection *caller, enum command_id cmd, struct setting *pset)
Definition stdinhand.c:2336
static bool toggle_ai_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:732
static bool playernation_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4226
static bool team_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2400
static bool quit_game(struct connection *caller, bool check)
Definition stdinhand.c:4353
static bool vote_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2526
#define cmd_reply_show(string)
bool start_command(struct connection *caller, bool check, bool notify)
Definition stdinhand.c:6048
static const char * optname_accessor(int i)
Definition stdinhand.c:1650
static bool show_help(struct connection *caller, char *arg)
Definition stdinhand.c:6534
#define OPTION_NAME_SPACE
Definition stdinhand.c:98
struct strvec * get_init_script_choices(void)
Definition stdinhand.c:1275
static bool remove_player_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:1128
static bool debug_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2726
static enum command_id command_named(const char *token, bool accept_ambiguity)
Definition stdinhand.c:224
static bool fcdb_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:5934
static bool set_rulesetdir(struct connection *caller, char *str, bool check, int read_recursion)
Definition stdinhand.c:3924
static bool mapimg_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:5626
static bool unignore_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:4052
static bool observe_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:3294
static bool show_list(struct connection *caller, char *arg)
Definition stdinhand.c:6975
static bool scensave_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:691
static enum sset_level lookup_option_level(const char *name)
Definition stdinhand.c:1718
static bool may_use(struct connection *caller, enum command_id cmd)
Definition stdinhand.c:284
static bool kick_command(struct connection *caller, char *name, bool check)
Definition stdinhand.c:6262
static const char * vote_arg_accessor(int i)
Definition stdinhand.c:2518
static bool is_restricted(struct connection *caller)
Definition stdinhand.c:185
const char * script_extension
Definition stdinhand.c:116
static bool show_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:2154
static bool lua_command(struct connection *caller, char *arg, bool check, int read_recursion)
Definition stdinhand.c:4937
static bool write_init_script(char *script_filename)
Definition stdinhand.c:1285
static enum cmdlevel first_access_level
Definition stdinhand.c:101
static bool detach_command(struct connection *caller, char *str, bool check)
Definition stdinhand.c:3631
static bool aicmd_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:5851
static void close_metaserver_connection(struct connection *caller)
Definition stdinhand.c:517
static bool save_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:674
static bool set_ai_level_named(struct connection *caller, const char *name, const char *level_name, bool check)
Definition stdinhand.c:2021
static bool metapatches_command(struct connection *caller, char *arg, bool check)
Definition stdinhand.c:586
static bool show_ignore(struct connection *caller)
Definition stdinhand.c:6656
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:3152
void toggle_ai_player_direct(struct connection *caller, struct player *pplayer)
Definition stdinhand.c:707
static void show_help_option(struct connection *caller, enum command_id help_cmd, int id)
Definition stdinhand.c:1773
static bool read_command(struct connection *caller, char *arg, bool check, int read_recursion)
Definition stdinhand.c:1165
void strvec_destroy(struct strvec *psv)
#define strvec_iterate(psv, str)
#define strvec_iterate_end
Definition ai.h:50
struct ai_type::@14 funcs
void(* gained_control)(struct player *pplayer)
Definition ai.h:108
char name[MAX_LEN_NAME]
Definition ai.h:51
void(* player_console)(struct player *pplayer, const char *cmd)
Definition ai.h:105
Definition city.h:309
struct city::@17::@19 server
bool debug
Definition city.h:433
int kick_time
Definition game.h:152
struct civ_game::@30::@34 server
char start_units[MAX_LEN_STARTUNIT]
Definition game.h:188
bool debug[DEBUG_LAST]
Definition game.h:201
char connectmsg[MAX_LEN_MSG]
Definition game.h:218
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:165
int timeoutcounter
Definition game.h:206
char rulesetdir[MAX_LEN_NAME]
Definition game.h:236
struct packet_scenario_info scenario
Definition game.h:87
int timeoutint
Definition game.h:202
struct conn_list * all_connections
Definition game.h:96
char save_name[MAX_LEN_NAME]
Definition game.h:219
int timeoutincmult
Definition game.h:204
int timeoutinc
Definition game.h:203
char allow_take[MAX_LEN_ALLOW_TAKE]
Definition game.h:238
bool start_city
Definition game.h:189
int max_players
Definition game.h:155
int timeoutintinc
Definition game.h:205
Definition colors.h:20
struct player * playing
Definition connection.h:156
struct connection::@57::@63::@64 delegation
enum cmdlevel access_level
Definition connection.h:182
struct conn_list * self
Definition connection.h:168
bool observer
Definition connection.h:152
char username[MAX_LEN_NAME]
Definition connection.h:169
struct connection::@57::@63 server
enum auth_status status
Definition connection.h:222
char ipaddr[MAX_LEN_ADDR]
Definition connection.h:226
struct conn_pattern_list * ignore_list
Definition connection.h:232
struct player * player
Definition nation.h:117
char message[MAX_LEN_MSG]
enum ai_level skill_level
enum ai_level skill_level
Definition player.h:122
bool random_name
Definition player.h:295
struct player_ai ai_common
Definition player.h:288
bv_pstatus status
Definition player.h:318
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 nation_style * style
Definition player.h:279
struct player::@69::@71 server
bv_debug debug
Definition player.h:332
struct rgbcolor * rgb
Definition player.h:308
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:143
Definition map.c:41
Definition tile.h:49
struct unit_list * units
Definition tile.h:57
Definition timing.c:81
Definition unit.h:138
bool debug
Definition unit.h:231
struct unit::@80::@83 server
Definition voting.h:46
int caller_id
Definition voting.h:47
char cmdline[512]
Definition voting.h:49
int vote_no
Definition voting.h:52
struct civ_map map
struct nation_style * style_by_rule_name(const char *name)
Definition style.c:117
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:787
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:995
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:896
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:506
int fc_break_lines(char *str, size_t desired_len)
Definition support.c:1144
int fc_stat(const char *filename, struct stat *buf)
Definition support.c:575
bool is_reg_file_for_access(const char *name, bool write_access)
Definition support.c:1129
bool fc_isalnum(char c)
Definition support.c:1205
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:238
#define sz_strlcpy(dest, src)
Definition support.h:167
#define fc__attribute(x)
Definition support.h:89
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define sz_strlcat(dest, src)
Definition support.h:168
#define fc__fallthrough
Definition support.h:109
int team_index(const struct team *pteam)
Definition team.c:383
const char * team_name_translation(const struct team *pteam)
Definition team.c:420
struct team_slot * team_slot_by_number(int team_id)
Definition team.c:175
const char * team_slot_name_translation(const struct team_slot *tslot)
Definition team.c:253
bool team_add_player(struct player *pplayer, struct team *pteam)
Definition team.c:467
struct team * team_new(struct team_slot *tslot)
Definition team.c:317
struct team_slot * team_slot_by_rule_name(const char *team_name)
Definition team.c:189
const struct player_list * team_members(const struct team *pteam)
Definition team.c:456
void team_remove_player(struct player *pplayer)
Definition team.c:502
#define teams_iterate_end
Definition team.h:85
#define teams_iterate(_pteam)
Definition team.h:80
void init_tech(struct research *research, bool update)
Definition techtools.c:1070
void send_research_info(const struct research *presearch, const struct conn_list *dest)
Definition techtools.c:273
void give_initial_techs(struct research *presearch, int num_random_techs)
Definition techtools.c:1162
struct city * tile_city(const struct tile *ptile)
Definition tile.c:83
struct timer * timer_new(enum timer_timetype type, enum timer_use use)
Definition timing.c:157
void timer_destroy(struct timer *t)
Definition timing.c:191
void timer_start(struct timer *t)
Definition timing.c:224
double timer_read_seconds(struct timer *t)
Definition timing.c:344
@ TIMER_ACTIVE
Definition timing.h:45
@ TIMER_CPU
Definition timing.h:40
@ TIMER_USER
Definition timing.h:41
#define unit_owner(_pu)
Definition unit.h:394
#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:1621
int describe_vote(struct vote *pvote, char *buf, int buflen)
Definition voting.c:748
bool conn_can_vote(const struct connection *pconn, const struct vote *pvote)
Definition voting.c:248
struct vote * vote_new(struct connection *caller, const char *allargs, int command_id)
Definition voting.c:338
bool vote_is_team_only(const struct vote *pvote)
Definition voting.c:235
struct vote * get_vote_by_no(int vote_no)
Definition voting.c:301
int vote_number_sequence
Definition voting.c:42
bool vote_would_pass_immediately(const struct connection *caller, int command_id)
Definition voting.c:391
void clear_all_votes(void)
Definition voting.c:219
struct vote * get_vote_by_caller(const struct connection *caller)
Definition voting.c:319
void connection_vote(struct connection *pconn, struct vote *pvote, enum vote_type type)
Definition voting.c:663
struct vote_list * vote_list
Definition voting.c:41
const struct connection * vote_get_caller(const struct vote *pvote)
Definition voting.c:891
int count_voters(const struct vote *pvote)
Definition voting.c:48
void remove_vote(struct vote *pvote)
Definition voting.c:205
bool conn_can_see_vote(const struct connection *pconn, const struct vote *pvote)
Definition voting.c:272
@ VOTE_ABSTAIN
Definition voting.h:27
@ VOTE_YES
Definition voting.h:27
@ VOTE_NUM
Definition voting.h:27
@ VOTE_NO
Definition voting.h:27
#define vote_list_iterate_end
Definition voting.h:65
@ VCF_NODISSENT
Definition voting.h:20
#define vote_list_iterate(alist, pvote)
Definition voting.h:63