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)
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 ***********************************************************************/
15 #include <fc_config.h>
23 #ifdef FREECIV_HAVE_LIBREADLINE
24 #include <readline/readline.h>
29 #include "bitvector.h"
30 #include "fc_cmdline.h"
36 #include "support.h" /* fc__attribute, bool type, etc. */
40 #include "capability.h"
42 #include "fc_types.h" /* LINE_BREAK */
43 #include "featured_text.h"
57 #include "citytools.h"
58 #include "connecthand.h"
68 #include "sanitycheck.h"
69 #include "savegame2.h"
75 #include "techtools.h"
78 /* server/scripting */
79 #include "script_server.h"
80 #include "script_fcdb.h"
83 #include "difficulty.h"
84 #include "handicaps.h"
86 #include "stdinhand.h"
88 #define OPTION_NAME_SPACE 25
90 static enum cmdlevel default_access_level
= ALLOW_BASIC
;
91 static enum cmdlevel first_access_level
= ALLOW_BASIC
;
93 static time_t *time_duplicate(const time_t *t
);
95 /* 'struct kick_hash' and related functions. */
96 #define SPECHASH_TAG kick
97 #define SPECHASH_ASTR_KEY_TYPE
98 #define SPECHASH_IDATA_TYPE time_t *
99 #define SPECHASH_UDATA_TYPE time_t
100 #define SPECHASH_IDATA_COPY time_duplicate
101 #define SPECHASH_IDATA_FREE (kick_hash_data_free_fn_t) free
102 #define SPECHASH_UDATA_TO_IDATA(t) (&(t))
103 #define SPECHASH_IDATA_TO_UDATA(p) (NULL != p ? *p : 0)
104 #include "spechash.h"
106 static struct kick_hash
*kick_table_by_addr
= NULL
;
107 static struct kick_hash
*kick_table_by_user
= NULL
;
110 static bool cut_client_connection(struct connection
*caller
, char *name
,
112 static bool show_help(struct connection
*caller
, char *arg
);
113 static bool show_list(struct connection
*caller
, char *arg
);
114 static void show_colors(struct connection
*caller
);
115 static bool set_ai_level_named(struct connection
*caller
, const char *name
,
116 const char *level_name
, bool check
);
117 static bool set_ai_level(struct connection
*caller
, const char *name
,
118 enum ai_level level
, bool check
);
119 static bool away_command(struct connection
*caller
, bool check
);
120 static bool set_rulesetdir(struct connection
*caller
, char *str
, bool check
,
122 static bool show_command(struct connection
*caller
, char *str
, bool check
);
123 static bool show_settings(struct connection
*caller
,
124 enum command_id called_as
,
125 char *str
, bool check
);
126 static void show_settings_one(struct connection
*caller
, enum command_id cmd
,
127 struct setting
*pset
);
128 static void show_ruleset_info(struct connection
*caller
, enum command_id cmd
,
129 bool check
, int read_recursion
);
130 static void show_mapimg(struct connection
*caller
, enum command_id cmd
);
131 static bool set_command(struct connection
*caller
, char *str
, bool check
);
133 static bool create_command(struct connection
*caller
, const char *str
,
135 static bool end_command(struct connection
*caller
, char *str
, bool check
);
136 static bool surrender_command(struct connection
*caller
, char *str
, bool check
);
137 static bool handle_stdin_input_real(struct connection
*caller
, char *str
,
138 bool check
, int read_recursion
);
139 static bool read_init_script_real(struct connection
*caller
,
140 char *script_filename
, bool from_cmdline
,
141 bool check
, int read_recursion
);
142 static bool reset_command(struct connection
*caller
, char *arg
, bool check
,
144 static bool default_command(struct connection
*caller
, char *arg
, bool check
);
145 static bool lua_command(struct connection
*caller
, char *arg
, bool check
);
146 static bool kick_command(struct connection
*caller
, char *name
, bool check
);
147 static bool delegate_command(struct connection
*caller
, char *arg
,
149 static const char *delegate_player_str(struct player
*pplayer
, bool observer
);
150 static bool fcdb_command(struct connection
*caller
, char *arg
, bool check
);
151 static const char *fcdb_accessor(int i
);
152 static char setting_status(struct connection
*caller
,
153 const struct setting
*pset
);
154 static bool player_name_check(const char* name
, char *buf
, size_t buflen
);
155 static bool playercolor_command(struct connection
*caller
,
156 char *str
, bool check
);
157 static bool mapimg_command(struct connection
*caller
, char *arg
, bool check
);
158 static const char *mapimg_accessor(int i
);
160 static void show_delegations(struct connection
*caller
);
162 static const char horiz_line
[] =
163 "------------------------------------------------------------------------------";
165 /********************************************************************
166 Are we operating under a restricted security regime? For now
167 this does not do much.
168 *********************************************************************/
169 static bool is_restricted(struct connection
*caller
)
171 return (caller
&& caller
->access_level
!= ALLOW_HACK
);
174 /**************************************************************************
175 Check the player name. Returns TRUE if the player name is valid else
176 an error message is saved in 'buf'.
177 **************************************************************************/
178 static bool player_name_check(const char* name
, char *buf
, size_t buflen
)
180 size_t len
= strlen(name
);
183 fc_snprintf(buf
, buflen
, _("Can't use an empty name."));
185 } else if (len
> MAX_LEN_NAME
-1) {
186 fc_snprintf(buf
, buflen
, _("That name exceeds the maximum of %d chars."),
189 } else if (fc_strcasecmp(name
, ANON_PLAYER_NAME
) == 0
190 || fc_strcasecmp(name
, "Observer") == 0) {
191 fc_snprintf(buf
, buflen
, _("That name is not allowed."));
192 /* "Observer" used to be illegal and we keep it that way for now. */
193 /* FIXME: This disallows anonymous player name as it appears in English,
194 * but not one in any other language that the user may see. */
201 /**************************************************************************
202 Convert a named command into an id.
203 If accept_ambiguity is true, return the first command in the
204 enum list which matches, else return CMD_AMBIGUOUS on ambiguity.
205 (This is a trick to allow ambiguity to be handled in a flexible way
206 without importing notify_player() messages inside this routine - rp)
207 **************************************************************************/
208 static enum command_id
command_named(const char *token
, bool accept_ambiguity
)
210 enum m_pre_result result
;
213 result
= match_prefix(command_name_by_number
, CMD_NUM
, 0,
214 fc_strncasecmp
, NULL
, token
, &ind
);
216 if (result
< M_PRE_AMBIGUOUS
) {
218 } else if (result
== M_PRE_AMBIGUOUS
) {
219 return accept_ambiguity
? ind
: CMD_AMBIGUOUS
;
221 return CMD_UNRECOGNIZED
;
225 /**************************************************************************
226 Initialize stuff related to this code module.
227 **************************************************************************/
228 void stdinhand_init(void)
230 fc_assert(NULL
== kick_table_by_addr
);
231 kick_table_by_addr
= kick_hash_new();
233 fc_assert(NULL
== kick_table_by_user
);
234 kick_table_by_user
= kick_hash_new();
237 /**************************************************************************
238 Update stuff every turn that is related to this code module. Run this
240 **************************************************************************/
241 void stdinhand_turn(void)
243 /* Nothing at the moment. */
246 /**************************************************************************
247 Deinitialize stuff related to this code module.
248 **************************************************************************/
249 void stdinhand_free(void)
251 fc_assert(NULL
!= kick_table_by_addr
);
252 if (NULL
!= kick_table_by_addr
) {
253 kick_hash_destroy(kick_table_by_addr
);
254 kick_table_by_addr
= NULL
;
257 fc_assert(NULL
!= kick_table_by_user
);
258 if (NULL
!= kick_table_by_user
) {
259 kick_hash_destroy(kick_table_by_user
);
260 kick_table_by_user
= NULL
;
264 /**************************************************************************
265 Whether the caller can use the specified command. caller == NULL means
267 **************************************************************************/
268 static bool may_use(struct connection
*caller
, enum command_id cmd
)
271 return TRUE
; /* on the console, everything is allowed */
273 return (caller
->access_level
>= command_level(command_by_number(cmd
)));
276 /**************************************************************************
277 Whether the caller cannot use any commands at all.
278 caller == NULL means console.
279 **************************************************************************/
280 static bool may_use_nothing(struct connection
*caller
)
283 return FALSE
; /* on the console, everything is allowed */
285 return (ALLOW_NONE
== conn_get_access(caller
));
288 /**************************************************************************
289 Return the status of the setting (changeable, locked, fixed).
290 caller == NULL means console.
291 **************************************************************************/
292 static char setting_status(struct connection
*caller
,
293 const struct setting
*pset
)
295 /* first check for a ruleset lock as this is included in
296 * setting_is_changeable() */
297 if (setting_locked(pset
)) {
298 /* setting is locked by the ruleset */
302 if (setting_is_changeable(pset
, caller
, NULL
, 0)) {
303 /* setting can be changed */
307 /* setting is fixed */
311 /**************************************************************************
312 feedback related to server commands
313 caller == NULL means console.
314 No longer duplicate all output to console.
316 This lowlevel function takes a single line; prefix is prepended to line.
317 **************************************************************************/
318 static void cmd_reply_line(enum command_id cmd
, struct connection
*caller
,
319 enum rfc_status rfc_status
, const char *prefix
,
322 const char *cmdname
= cmd
< CMD_NUM
323 ? command_name_by_number(cmd
)
324 : cmd
== CMD_AMBIGUOUS
325 /* TRANS: ambiguous command */
327 : cmd
== CMD_UNRECOGNIZED
328 /* TRANS: unrecognized command */
330 : "(?!?)"; /* this case is a bug! */
333 notify_conn(caller
->self
, NULL
, E_SETTING
, ftc_command
,
334 "/%s: %s%s", cmdname
, prefix
, line
);
335 /* cc: to the console - testing has proved it's too verbose - rp
336 con_write(rfc_status, "%s/%s: %s%s", caller->name, cmdname, prefix, line);
339 con_write(rfc_status
, "%s%s", prefix
, line
);
342 if (rfc_status
== C_OK
) {
343 struct packet_chat_msg packet
;
345 package_event(&packet
, NULL
, E_SETTING
, ftc_server
, "%s", line
);
346 conn_list_iterate(game
.est_connections
, pconn
) {
347 /* Do not tell caller, since he was told above! */
348 if (caller
!= pconn
) {
349 send_packet_chat_msg(pconn
, &packet
);
351 } conn_list_iterate_end
;
352 event_cache_add_for_all(&packet
);
354 if (NULL
!= caller
) {
355 /* Echo to the console. */
356 log_normal("%s", line
);
361 /**************************************************************************
362 va_list version which allow embedded newlines, and each line is sent
363 separately. 'prefix' is prepended to every line _after_ the first line.
364 **************************************************************************/
365 static void vcmd_reply_prefix(enum command_id cmd
, struct connection
*caller
,
366 enum rfc_status rfc_status
, const char *prefix
,
367 const char *format
, va_list ap
)
372 fc_vsnprintf(buf
, sizeof(buf
), format
, ap
);
375 while ((c1
=strstr(c0
, "\n"))) {
377 cmd_reply_line(cmd
, caller
, rfc_status
, (c0
==buf
?"":prefix
), c0
);
380 cmd_reply_line(cmd
, caller
, rfc_status
, (c0
==buf
?"":prefix
), c0
);
383 /**************************************************************************
384 var-args version of above
385 duplicate declaration required for attribute to work...
386 **************************************************************************/
387 static void cmd_reply_prefix(enum command_id cmd
, struct connection
*caller
,
388 enum rfc_status rfc_status
, const char *prefix
,
389 const char *format
, ...)
390 fc__attribute((__format__ (__printf__
, 5, 6)));
391 static void cmd_reply_prefix(enum command_id cmd
, struct connection
*caller
,
392 enum rfc_status rfc_status
, const char *prefix
,
393 const char *format
, ...)
396 va_start(ap
, format
);
397 vcmd_reply_prefix(cmd
, caller
, rfc_status
, prefix
, format
, ap
);
401 /**************************************************************************
402 var-args version as above, no prefix
403 **************************************************************************/
404 void cmd_reply(enum command_id cmd
, struct connection
*caller
,
405 enum rfc_status rfc_status
, const char *format
, ...)
408 va_start(ap
, format
);
409 vcmd_reply_prefix(cmd
, caller
, rfc_status
, "", format
, ap
);
413 /**************************************************************************
414 Command specific argument parsing has detected that player argument
415 is invalid. This function is common handling for that situation.
416 **************************************************************************/
417 static void cmd_reply_no_such_player(enum command_id cmd
,
418 struct connection
*caller
,
420 enum m_pre_result match_result
)
422 switch(match_result
) {
424 cmd_reply(cmd
, caller
, C_SYNTAX
,
425 _("Name is empty, so cannot be a player."));
428 cmd_reply(cmd
, caller
, C_SYNTAX
,
429 _("Name is too long, so cannot be a player."));
431 case M_PRE_AMBIGUOUS
:
432 cmd_reply(cmd
, caller
, C_FAIL
,
433 _("Player name prefix '%s' is ambiguous."), name
);
436 cmd_reply(cmd
, caller
, C_FAIL
,
437 _("No player by the name of '%s'."), name
);
440 cmd_reply(cmd
, caller
, C_FAIL
,
441 _("Unexpected match_result %d (%s) for '%s'."),
442 match_result
, _(m_pre_description(match_result
)), name
);
443 log_error("Unexpected match_result %d (%s) for '%s'.",
444 match_result
, m_pre_description(match_result
), name
);
448 /**************************************************************************
449 Command specific argument parsing has detected that connection argument
450 is invalid. This function is common handling for that situation.
451 **************************************************************************/
452 static void cmd_reply_no_such_conn(enum command_id cmd
,
453 struct connection
*caller
,
455 enum m_pre_result match_result
)
457 switch(match_result
) {
459 cmd_reply(cmd
, caller
, C_SYNTAX
,
460 _("Name is empty, so cannot be a connection."));
463 cmd_reply(cmd
, caller
, C_SYNTAX
,
464 _("Name is too long, so cannot be a connection."));
466 case M_PRE_AMBIGUOUS
:
467 cmd_reply(cmd
, caller
, C_FAIL
,
468 _("Connection name prefix '%s' is ambiguous."), name
);
471 cmd_reply(cmd
, caller
, C_FAIL
,
472 _("No connection by the name of '%s'."), name
);
475 cmd_reply(cmd
, caller
, C_FAIL
,
476 _("Unexpected match_result %d (%s) for '%s'."),
477 match_result
, _(m_pre_description(match_result
)), name
);
478 log_error("Unexpected match_result %d (%s) for '%s'.",
479 match_result
, m_pre_description(match_result
), name
);
483 /**************************************************************************
484 Start sending game info to metaserver.
485 **************************************************************************/
486 static void open_metaserver_connection(struct connection
*caller
,
489 server_open_meta(persistent
);
490 if (send_server_info_to_metaserver(META_INFO
)) {
491 cmd_reply(CMD_METACONN
, caller
, C_OK
,
492 _("Open metaserver connection to [%s]."),
497 /**************************************************************************
498 Stop sending game info to metaserver.
499 **************************************************************************/
500 static void close_metaserver_connection(struct connection
*caller
)
502 if (send_server_info_to_metaserver(META_GOODBYE
)) {
504 cmd_reply(CMD_METACONN
, caller
, C_OK
,
505 _("Close metaserver connection to [%s]."),
510 /**************************************************************************
511 Handle metaconnection command.
512 **************************************************************************/
513 static bool metaconnection_command(struct connection
*caller
, char *arg
,
516 bool persistent
= FALSE
;
519 || (!strcmp(arg
, "?"))) {
520 if (is_metaserver_open()) {
521 cmd_reply(CMD_METACONN
, caller
, C_COMMENT
,
522 _("Metaserver connection is open."));
524 cmd_reply(CMD_METACONN
, caller
, C_COMMENT
,
525 _("Metaserver connection is closed."));
530 if (!fc_strcasecmp(arg
, "p")
531 || !fc_strcasecmp(arg
, "persistent")) {
536 || !fc_strcasecmp(arg
, "u")
537 || !fc_strcasecmp(arg
, "up")) {
538 if (!is_metaserver_open()) {
540 open_metaserver_connection(caller
, persistent
);
543 cmd_reply(CMD_METACONN
, caller
, C_METAERROR
,
544 _("Metaserver connection is already open."));
547 } else if (!fc_strcasecmp(arg
, "d")
548 || !fc_strcasecmp(arg
, "down")) {
549 if (is_metaserver_open()) {
551 close_metaserver_connection(caller
);
554 cmd_reply(CMD_METACONN
, caller
, C_METAERROR
,
555 _("Metaserver connection is already closed."));
559 cmd_reply(CMD_METACONN
, caller
, C_METAERROR
,
560 _("Argument must be 'u', 'up', 'd', 'down', 'p', 'persistent', or '?'."));
566 /**************************************************************************
567 Handle metapatches command.
568 **************************************************************************/
569 static bool metapatches_command(struct connection
*caller
,
570 char *arg
, bool check
)
576 set_meta_patches_string(arg
);
578 if (is_metaserver_open()) {
579 send_server_info_to_metaserver(META_INFO
);
580 cmd_reply(CMD_METAPATCHES
, caller
, C_OK
,
581 _("Metaserver patches string set to '%s'."), arg
);
583 cmd_reply(CMD_METAPATCHES
, caller
, C_OK
,
584 _("Metaserver patches string set to '%s', "
585 "not reporting to metaserver."), arg
);
591 /**************************************************************************
592 Handle metamessage command.
593 **************************************************************************/
594 static bool metamessage_command(struct connection
*caller
,
595 char *arg
, bool check
)
601 set_user_meta_message_string(arg
);
602 if (is_metaserver_open()) {
603 send_server_info_to_metaserver(META_INFO
);
604 cmd_reply(CMD_METAMESSAGE
, caller
, C_OK
,
605 _("Metaserver message string set to '%s'."), arg
);
607 cmd_reply(CMD_METAMESSAGE
, caller
, C_OK
,
608 _("Metaserver message string set to '%s', "
609 "not reporting to metaserver."), arg
);
615 /**************************************************************************
616 Handle metaserver command.
617 **************************************************************************/
618 static bool metaserver_command(struct connection
*caller
, char *arg
,
624 close_metaserver_connection(caller
);
626 sz_strlcpy(srvarg
.metaserver_addr
, arg
);
628 cmd_reply(CMD_METASERVER
, caller
, C_OK
,
629 _("Metaserver is now [%s]."), meta_addr_port());
633 /**************************************************************************
635 **************************************************************************/
636 static bool show_serverid(struct connection
*caller
, char *arg
)
638 cmd_reply(CMD_SRVID
, caller
, C_COMMENT
, _("Server id: %s"), srvarg
.serverid
);
643 /**************************************************************************
644 For command "save foo";
645 Save the game, with filename=arg, provided server state is ok.
646 **************************************************************************/
647 static bool save_command(struct connection
*caller
, char *arg
, bool check
)
649 if (is_restricted(caller
)) {
650 cmd_reply(CMD_SAVE
, caller
, C_FAIL
,
651 _("You cannot save games manually on this server."));
655 save_game(arg
, "User request", FALSE
);
660 /**************************************************************************
661 For command "scensave foo";
662 Save the game, with filename=arg, provided server state is ok.
663 **************************************************************************/
664 static bool scensave_command(struct connection
*caller
, char *arg
, bool check
)
666 if (is_restricted(caller
)) {
667 cmd_reply(CMD_SAVE
, caller
, C_FAIL
,
668 _("You cannot save games manually on this server."));
672 save_game(arg
, "Scenario", TRUE
);
677 /**************************************************************************
678 Handle ai player ai toggling.
679 **************************************************************************/
680 void toggle_ai_player_direct(struct connection
*caller
, struct player
*pplayer
)
682 fc_assert_ret(pplayer
!= NULL
);
684 if (!pplayer
->ai_controlled
) {
685 cmd_reply(CMD_AITOGGLE
, caller
, C_OK
,
686 _("%s is now under AI control."),
687 player_name(pplayer
));
688 player_set_to_ai_mode(pplayer
,
689 !ai_level_is_valid(pplayer
->ai_common
.skill_level
)
690 ? game
.info
.skill_level
691 : pplayer
->ai_common
.skill_level
);
692 fc_assert(pplayer
->ai_controlled
== TRUE
);
694 cmd_reply(CMD_AITOGGLE
, caller
, C_OK
,
695 _("%s is now under human control."),
696 player_name(pplayer
));
697 player_set_under_human_control(pplayer
);
698 fc_assert(pplayer
->ai_controlled
== FALSE
);
702 /**************************************************************************
703 Handle aitoggle command.
704 **************************************************************************/
705 static bool toggle_ai_command(struct connection
*caller
, char *arg
, bool check
)
707 enum m_pre_result match_result
;
708 struct player
*pplayer
;
710 pplayer
= player_by_name_prefix(arg
, &match_result
);
713 cmd_reply_no_such_player(CMD_AITOGGLE
, caller
, arg
, match_result
);
716 toggle_ai_player_direct(caller
, pplayer
);
717 send_player_info_c(pplayer
, game
.est_connections
);
722 /**************************************************************************
723 Creates a named AI player. The function can be called befor the start
724 of the game (see creat_command_pregame()) and for a running game
725 (see creat_command_newcomer(). In the later case, first free player slots
726 are used before the slots of dead players are (re)used.
727 **************************************************************************/
728 static bool create_command(struct connection
*caller
, const char *str
,
731 enum rfc_status status
;
732 char buf
[MAX_LEN_CONSOLE_LINE
];
734 /* 2 legal arguments, and extra space for stuffing illegal part */
737 const char *ai_type_name
;
739 sz_strlcpy(buf
, str
);
740 ntokens
= get_tokens(buf
, arg
, 3, TOKEN_DELIMITERS
);
743 ai_type_name
= default_ai_type_name();
744 } else if (ntokens
== 2) {
745 ai_type_name
= arg
[1];
747 cmd_reply(CMD_CREATE
, caller
, C_SYNTAX
,
748 _("Wrong number of arguments to create command."));
749 free_tokens(arg
, ntokens
);
753 if (game_was_started()) {
754 status
= create_command_newcomer(arg
[0], ai_type_name
, check
,
755 NULL
, NULL
, buf
, sizeof(buf
));
757 status
= create_command_pregame(arg
[0], ai_type_name
, check
,
758 NULL
, buf
, sizeof(buf
));
761 free_tokens(arg
, ntokens
);
763 if (status
!= C_OK
) {
764 /* No player created. */
765 cmd_reply(CMD_CREATE
, caller
, status
, "%s", buf
);
769 if (strlen(buf
) > 0) {
770 /* Send a notification. */
771 cmd_reply(CMD_CREATE
, caller
, C_OK
, "%s", buf
);
777 /**************************************************************************
778 Try to add a player to a running game in the following order:
780 1. Try to reuse the slot of a dead player with the username 'name'.
781 2. Try to reuse the slot of a dead player.
782 3. Try to use an empty player slot.
784 If 'pnation' is defined this nation is used for the new player.
785 **************************************************************************/
786 enum rfc_status
create_command_newcomer(const char *name
,
789 struct nation_type
*pnation
,
790 struct player
**newplayer
,
791 char *buf
, size_t buflen
)
793 struct player
*pplayer
= NULL
;
794 struct research
*presearch
;
795 bool new_slot
= FALSE
;
797 /* Check player name. */
798 if (!player_name_check(name
, buf
, buflen
)) {
802 /* Check first if we can replace a player with
803 * [1a] - the same username. */
804 pplayer
= player_by_user(name
);
805 if (pplayer
&& pplayer
->is_alive
) {
806 fc_snprintf(buf
, buflen
,
807 _("A living user already exists by that name."));
811 /* [1b] - the same player name. */
812 pplayer
= player_by_name(name
);
813 if (pplayer
&& pplayer
->is_alive
) {
814 fc_snprintf(buf
, buflen
,
815 _("A living player already exists by that name."));
820 if (!nation_is_in_current_set(pnation
)) {
821 fc_snprintf(buf
, buflen
,
822 _("Can't create player, requested nation %s not in "
823 "current nation set."),
824 nation_plural_translation(pnation
));
827 players_iterate(aplayer
) {
828 if (0 > nations_match(pnation
, nation_of_player(aplayer
), FALSE
)) {
829 fc_snprintf(buf
, buflen
,
830 _("Can't create players, nation %s conflicts with %s."),
831 nation_plural_for_player(aplayer
),
832 nation_plural_for_player(pplayer
));
835 } players_iterate_end
;
837 /* Try to find a nation. */
838 pnation
= pick_a_nation(NULL
, FALSE
, TRUE
, NOT_A_BARBARIAN
);
839 if (pnation
== NO_NATION_SELECTED
) {
840 fc_snprintf(buf
, buflen
,
841 _("Can't create players, no nations available."));
847 /* All code below will change the game state. */
849 /* Return an empty string. */
856 /* [1] Replace a player. 'pplayer' was set above. */
857 fc_snprintf(buf
, buflen
,
858 _("%s is replacing dead player %s as an AI-controlled "
859 "player."), name
, player_name(pplayer
));
860 /* remove player and thus free a player slot */
861 server_remove_player(pplayer
);
863 } else if (player_count() == player_slot_count()) {
864 /* [2] All player slots are used; try to remove a dead player. */
865 players_iterate(aplayer
) {
866 if (!aplayer
->is_alive
) {
867 fc_snprintf(buf
, buflen
,
868 _("%s is replacing dead player %s as an AI-controlled "
869 "player."), name
, player_name(aplayer
));
870 /* remove player and thus free a player slot */
871 server_remove_player(aplayer
);
873 } players_iterate_end
;
875 /* [3] An empty player slot must be used for the new player. */
880 if (normal_player_count() == game
.server
.max_players
) {
882 fc_assert(game
.server
.max_players
< MAX_NUM_PLAYERS
);
884 game
.server
.max_players
++;
885 log_debug("Increased 'maxplayers' for creation of a new player.");
889 /* Create the new player. */
890 pplayer
= server_create_player(-1, ai
, NULL
, FALSE
);
892 fc_snprintf(buf
, buflen
, _("Failed to create new player %s."), name
);
897 /* 'buf' must be set if a new player slot is used. */
898 fc_snprintf(buf
, buflen
, _("New player %s created."), name
);
901 /* We have a player; now initialise all needed data. */
902 (void) aifill(game
.info
.aifill
);
904 /* Initialise player. */
905 server_player_init(pplayer
, TRUE
, TRUE
);
907 player_nation_defaults(pplayer
, pnation
, FALSE
);
908 pplayer
->government
= pplayer
->target_government
=
909 init_government_of_nation(pnation
);
910 /* Find a color for the new player. */
911 assign_player_colors();
913 /* TRANS: keep one space at the beginning of the string. */
914 cat_snprintf(buf
, buflen
, _(" Nation of the new player: %s."),
915 nation_rule_name(pnation
));
917 presearch
= research_get(pplayer
);
918 init_tech(presearch
, TRUE
);
919 give_initial_techs(presearch
, 0);
921 server_player_set_name(pplayer
, name
);
922 sz_strlcpy(pplayer
->username
, _(ANON_USER_NAME
));
923 pplayer
->unassigned_user
= TRUE
;
925 pplayer
->was_created
= TRUE
; /* must use /remove explicitly to remove */
926 pplayer
->ai_controlled
= TRUE
;
927 set_ai_level_directer(pplayer
, game
.info
.skill_level
);
929 CALL_PLR_AI_FUNC(gained_control
, pplayer
, pplayer
);
931 send_player_info_c(pplayer
, NULL
);
932 /* Send updated diplstate information to all players. */
933 send_player_diplstate_c(NULL
, NULL
);
934 /* Send research info after player info, else the client will complain
935 * about invalid team. */
936 send_research_info(presearch
, NULL
);
937 (void) send_server_info_to_metaserver(META_INFO
);
939 if (newplayer
!= NULL
) {
940 *newplayer
= pplayer
;
945 /**************************************************************************
946 Create player in pregame.
947 **************************************************************************/
948 enum rfc_status
create_command_pregame(const char *name
,
951 struct player
**newplayer
,
952 char *buf
, size_t buflen
)
954 char leader_name
[MAX_LEN_NAME
]; /* Must be in whole function scope */
955 struct player
*pplayer
= NULL
;
956 bool rand_name
= FALSE
;
958 if (name
[0] == '\0') {
962 fc_snprintf(leader_name
, sizeof(leader_name
), "%s*%d", ai
, filled
++);
963 } while (player_by_name(leader_name
));
969 if (!player_name_check(name
, buf
, buflen
)) {
973 if (NULL
!= player_by_name(name
)) {
974 fc_snprintf(buf
, buflen
,
975 _("A player already exists by that name."));
978 if (NULL
!= player_by_user(name
)) {
979 fc_snprintf(buf
, buflen
,
980 _("A user already exists by that name."));
984 /* Search for first uncontrolled player */
985 pplayer
= find_uncontrolled_player();
987 if (NULL
== pplayer
) {
988 /* Check that we are not going over max players setting */
989 if (normal_player_count() >= game
.server
.max_players
) {
990 fc_snprintf(buf
, buflen
,
991 _("Can't add more players, server is full."));
994 /* Check that we have nations available */
995 if (normal_player_count() >= server
.playable_nations
) {
996 if (nation_set_count() > 1) {
997 fc_snprintf(buf
, buflen
,
998 _("Can't add more players, not enough playable nations "
999 "in current nation set (see 'nationset' setting)."));
1001 fc_snprintf(buf
, buflen
,
1002 _("Can't add more players, not enough playable nations."));
1009 struct ai_type
*ait
= ai_type_by_name(ai
);
1012 fc_snprintf(buf
, buflen
,
1013 _("There is no AI type %s."), ai
);
1019 /* All code below will change the game state. */
1021 /* Return an empty string. */
1028 fc_snprintf(buf
, buflen
,
1029 /* TRANS: <name> replacing <name> ... */
1030 _("%s replacing %s as an AI-controlled player."),
1031 name
, player_name(pplayer
));
1033 team_remove_player(pplayer
);
1034 pplayer
->ai
= ai_type_by_name(ai
);
1036 /* add new player */
1037 pplayer
= server_create_player(-1, ai
, NULL
, FALSE
);
1038 /* pregame so no need to assign_player_colors() */
1040 fc_snprintf(buf
, buflen
,
1041 _("Failed to create new player %s."), name
);
1045 fc_snprintf(buf
, buflen
,
1046 _("%s has been added as an AI-controlled player (%s)."),
1047 name
, ai_name(pplayer
->ai
));
1049 server_player_init(pplayer
, FALSE
, TRUE
);
1051 server_player_set_name(pplayer
, name
);
1052 sz_strlcpy(pplayer
->username
, _(ANON_USER_NAME
));
1053 pplayer
->unassigned_user
= TRUE
;
1055 pplayer
->was_created
= TRUE
; /* must use /remove explicitly to remove */
1056 pplayer
->random_name
= rand_name
;
1057 pplayer
->ai_controlled
= TRUE
;
1058 set_ai_level_directer(pplayer
, game
.info
.skill_level
);
1059 CALL_PLR_AI_FUNC(gained_control
, pplayer
, pplayer
);
1060 send_player_info_c(pplayer
, game
.est_connections
);
1062 (void) aifill(game
.info
.aifill
);
1063 reset_all_start_commands(TRUE
);
1064 (void) send_server_info_to_metaserver(META_INFO
);
1066 if (newplayer
!= NULL
) {
1067 *newplayer
= pplayer
;
1072 /**************************************************************************
1073 Handle remove command.
1074 **************************************************************************/
1075 static bool remove_player_command(struct connection
*caller
, char *arg
,
1078 enum m_pre_result match_result
;
1079 struct player
*pplayer
;
1080 char name
[MAX_LEN_NAME
];
1082 pplayer
= player_by_name_prefix(arg
, &match_result
);
1084 if (NULL
== pplayer
) {
1085 cmd_reply_no_such_player(CMD_REMOVE
, caller
, arg
, match_result
);
1089 if (game_was_started() && caller
&& caller
->access_level
< ALLOW_ADMIN
) {
1090 cmd_reply(CMD_REMOVE
, caller
, C_FAIL
,
1091 _("Command level '%s' or greater needed to remove a player "
1092 "once the game has started."), cmdlevel_name(ALLOW_ADMIN
));
1099 sz_strlcpy(name
, player_name(pplayer
));
1100 server_remove_player(pplayer
);
1101 if (!caller
|| caller
->used
) { /* may have removed self */
1102 cmd_reply(CMD_REMOVE
, caller
, C_OK
,
1103 _("Removed player %s from the game."), name
);
1105 (void) aifill(game
.info
.aifill
);
1109 /**************************************************************************
1110 Main entry point for the read command.
1111 **************************************************************************/
1112 static bool read_command(struct connection
*caller
, char *arg
, bool check
,
1115 return read_init_script_real(caller
, arg
, FALSE
, check
, read_recursion
);
1118 /**************************************************************************
1119 Main entry point for reading an init script.
1120 **************************************************************************/
1121 bool read_init_script(struct connection
*caller
, char *script_filename
,
1122 bool from_cmdline
, bool check
)
1124 return read_init_script_real(caller
, script_filename
, from_cmdline
,
1128 /**************************************************************************
1129 Returns FALSE iff there was an error.
1131 Security: We will look for a file with mandatory extension '.serv',
1132 and on public servers we will not look outside the data directories.
1133 As long as the user cannot create files with arbitrary names in the
1134 root of the data directories, this should ensure that we will not be
1135 tricked into loading non-approved content. The script is read with the
1136 permissions of the caller, so it will in any case not lead to elevated
1137 permissions unless there are other bugs.
1138 **************************************************************************/
1139 static bool read_init_script_real(struct connection
*caller
,
1140 char *script_filename
, bool from_cmdline
,
1141 bool check
, int read_recursion
)
1144 const char extension
[] = ".serv";
1145 char serv_filename
[strlen(extension
) + strlen(script_filename
) + 2];
1146 char tilde_filename
[4096];
1147 const char *real_filename
;
1149 /* check recursion depth */
1150 if (read_recursion
> GAME_MAX_READ_RECURSION
) {
1151 log_error("Error: recursive calls to read!");
1155 /* abuse real_filename to find if we already have a .serv extension */
1156 real_filename
= script_filename
+ strlen(script_filename
)
1157 - MIN(strlen(extension
), strlen(script_filename
));
1158 if (strcmp(real_filename
, extension
) != 0) {
1159 fc_snprintf(serv_filename
, sizeof(serv_filename
), "%s%s",
1160 script_filename
, extension
);
1162 sz_strlcpy(serv_filename
, script_filename
);
1165 if (is_restricted(caller
) && !from_cmdline
) {
1166 if (!is_safe_filename(serv_filename
)) {
1167 cmd_reply(CMD_READ_SCRIPT
, caller
, C_FAIL
,
1168 _("Name \"%s\" disallowed for security reasons."),
1172 sz_strlcpy(tilde_filename
, serv_filename
);
1174 interpret_tilde(tilde_filename
, sizeof(tilde_filename
), serv_filename
);
1177 real_filename
= fileinfoname(get_data_dirs(), tilde_filename
);
1178 if (!real_filename
) {
1179 if (is_restricted(caller
) && !from_cmdline
) {
1180 cmd_reply(CMD_READ_SCRIPT
, caller
, C_FAIL
,
1181 _("No command script found by the name \"%s\"."),
1185 /* File is outside data directories */
1186 real_filename
= tilde_filename
;
1189 log_testmatic_alt(LOG_NORMAL
, _("Loading script file '%s'."), real_filename
);
1191 if (is_reg_file_for_access(real_filename
, FALSE
)
1192 && (script_file
= fc_fopen(real_filename
, "r"))) {
1193 char buffer
[MAX_LEN_CONSOLE_LINE
];
1195 /* the size is set as to not overflow buffer in handle_stdin_input */
1196 while (fgets(buffer
, MAX_LEN_CONSOLE_LINE
- 1, script_file
)) {
1197 /* Execute script contents with same permissions as caller */
1198 handle_stdin_input_real(caller
, buffer
, check
, read_recursion
+ 1);
1200 fclose(script_file
);
1202 show_ruleset_info(caller
, CMD_READ_SCRIPT
, check
, read_recursion
);
1206 cmd_reply(CMD_READ_SCRIPT
, caller
, C_FAIL
,
1207 _("Cannot read command line scriptfile '%s'."), real_filename
);
1208 if (NULL
!= caller
) {
1209 log_error(_("Could not read script file '%s'."), real_filename
);
1215 /**************************************************************************
1216 Write current settings to new init script.
1218 (Should this take a 'caller' argument for output? --dwp)
1219 **************************************************************************/
1220 static void write_init_script(char *script_filename
)
1222 char real_filename
[1024], buf
[256];
1225 interpret_tilde(real_filename
, sizeof(real_filename
), script_filename
);
1227 if (is_reg_file_for_access(real_filename
, TRUE
)
1228 && (script_file
= fc_fopen(real_filename
, "w"))) {
1229 fprintf(script_file
,
1230 "#FREECIV SERVER COMMAND FILE, version %s\n", VERSION_STRING
);
1231 fputs("# These are server options saved from a running freeciv-server.\n",
1234 /* first rulesetdir. Setting rulesetdir resets the settings to their
1235 * default value, so they would be lost if placed before this. */
1236 fprintf(script_file
, "rulesetdir %s\n", game
.server
.rulesetdir
);
1238 /* some state info from commands (we can't save everything) */
1240 fprintf(script_file
, "cmdlevel %s new\n",
1241 cmdlevel_name(default_access_level
));
1243 fprintf(script_file
, "cmdlevel %s first\n",
1244 cmdlevel_name(first_access_level
));
1246 fprintf(script_file
, "%s\n",
1247 ai_level_cmd(game
.info
.skill_level
));
1249 if (*srvarg
.metaserver_addr
!= '\0' &&
1250 ((0 != strcmp(srvarg
.metaserver_addr
, DEFAULT_META_SERVER_ADDR
)))) {
1251 fprintf(script_file
, "metaserver %s\n", meta_addr_port());
1254 if (0 != strcmp(get_meta_patches_string(), default_meta_patches_string())) {
1255 fprintf(script_file
, "metapatches %s\n", get_meta_patches_string());
1257 if (0 != strcmp(get_meta_message_string(), default_meta_message_string())) {
1258 fprintf(script_file
, "metamessage %s\n", get_meta_message_string());
1261 /* then, the 'set' option settings */
1263 settings_iterate(SSET_ALL
, pset
) {
1264 fprintf(script_file
, "set %s \"%s\"\n", setting_name(pset
),
1265 setting_value_name(pset
, FALSE
, buf
, sizeof(buf
)));
1266 } settings_iterate_end
;
1268 fclose(script_file
);
1271 log_error(_("Could not write script file '%s'."), real_filename
);
1275 /**************************************************************************
1276 Generate init script from settings currently in use
1277 **************************************************************************/
1278 static bool write_command(struct connection
*caller
, char *arg
, bool check
)
1280 if (is_restricted(caller
)) {
1281 cmd_reply(CMD_WRITE_SCRIPT
, caller
, C_FAIL
,
1282 _("You cannot use the write command on this server"
1283 " for security reasons."));
1285 } else if (!check
) {
1286 write_init_script(arg
);
1291 /**************************************************************************
1292 set ptarget's cmdlevel to level if caller is allowed to do so
1293 **************************************************************************/
1294 static bool set_cmdlevel(struct connection
*caller
,
1295 struct connection
*ptarget
,
1296 enum cmdlevel level
)
1298 /* Only ever call me for specific connection. */
1299 fc_assert_ret_val(ptarget
!= NULL
, FALSE
);
1301 if (caller
&& ptarget
->access_level
> caller
->access_level
) {
1303 * This command is intended to be used at ctrl access level
1304 * and thus this if clause is needed.
1305 * (Imagine a ctrl level access player that wants to change
1306 * access level of a hack level access player)
1307 * At the moment it can be used only by hack access level
1308 * and thus this clause is never used.
1310 cmd_reply(CMD_CMDLEVEL
, caller
, C_FAIL
,
1311 _("Cannot decrease command access level '%s' "
1312 "for connection '%s'; you only have '%s'."),
1313 cmdlevel_name(ptarget
->access_level
),
1315 cmdlevel_name(caller
->access_level
));
1318 conn_set_access(ptarget
, level
, TRUE
);
1319 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1320 _("Command access level set to '%s' for connection %s."),
1321 cmdlevel_name(level
), ptarget
->username
);
1326 /********************************************************************
1327 Returns true if there is at least one established connection.
1328 *********************************************************************/
1329 static bool a_connection_exists(void)
1331 return conn_list_size(game
.est_connections
) > 0;
1334 /********************************************************************
1335 Return whether first access level is already taken.
1336 *********************************************************************/
1337 static bool is_first_access_level_taken(void)
1339 conn_list_iterate(game
.est_connections
, pconn
) {
1340 if (pconn
->access_level
>= first_access_level
) {
1344 conn_list_iterate_end
;
1348 /********************************************************************
1349 Return access level for next connection
1350 *********************************************************************/
1351 enum cmdlevel
access_level_for_next_connection(void)
1353 if ((first_access_level
> default_access_level
)
1354 && !a_connection_exists()) {
1355 return first_access_level
;
1357 return default_access_level
;
1361 /********************************************************************
1362 Check if first access level is available and if it is, notify
1363 connections about it.
1364 *********************************************************************/
1365 void notify_if_first_access_level_is_available(void)
1367 if (first_access_level
> default_access_level
1368 && !is_first_access_level_taken()) {
1369 notify_conn(NULL
, NULL
, E_SETTING
, ftc_any
,
1370 _("Anyone can now become game organizer "
1371 "'%s' by issuing the 'first' command."),
1372 cmdlevel_name(first_access_level
));
1376 /**************************************************************************
1377 Change command access level for individual player, or all, or new.
1378 **************************************************************************/
1379 static bool cmdlevel_command(struct connection
*caller
, char *str
, bool check
)
1384 enum m_pre_result match_result
;
1385 enum cmdlevel level
;
1386 struct connection
*ptarget
;
1388 ntokens
= get_tokens(str
, arg
, 2, TOKEN_DELIMITERS
);
1391 /* No argument supplied; list the levels */
1392 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
, horiz_line
);
1393 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
,
1394 _("Command access levels in effect:"));
1395 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
, horiz_line
);
1396 conn_list_iterate(game
.est_connections
, pconn
) {
1397 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
, "cmdlevel %s %s",
1398 cmdlevel_name(conn_get_access(pconn
)), pconn
->username
);
1399 } conn_list_iterate_end
;
1400 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
,
1401 _("Command access level for new connections: %s"),
1402 cmdlevel_name(default_access_level
));
1403 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
,
1404 _("Command access level for first player to take it: %s"),
1405 cmdlevel_name(first_access_level
));
1406 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
, horiz_line
);
1410 /* A level name was supplied; set the level. */
1411 level
= cmdlevel_by_name(arg
[0], fc_strcasecmp
);
1412 if (!cmdlevel_is_valid(level
)) {
1413 const char *cmdlevel_names
[CMDLEVEL_COUNT
];
1414 struct astring astr
= ASTRING_INIT
;
1417 for (level
= cmdlevel_begin(); level
!= cmdlevel_end();
1418 level
= cmdlevel_next(level
)) {
1419 cmdlevel_names
[i
++] = cmdlevel_name(level
);
1421 cmd_reply(CMD_CMDLEVEL
, caller
, C_SYNTAX
,
1422 /* TRANS: comma and 'or' separated list of access levels */
1423 _("Command access level must be one of %s."),
1424 astr_build_or_list(&astr
, cmdlevel_names
, i
));
1427 } else if (caller
&& level
> conn_get_access(caller
)) {
1428 cmd_reply(CMD_CMDLEVEL
, caller
, C_FAIL
,
1429 _("Cannot increase command access level to '%s';"
1430 " you only have '%s' yourself."),
1431 arg
[0], cmdlevel_name(conn_get_access(caller
)));
1436 return TRUE
; /* looks good */
1440 /* No playername supplied: set for all connections */
1441 conn_list_iterate(game
.est_connections
, pconn
) {
1442 if (pconn
!= caller
) {
1443 (void) set_cmdlevel(caller
, pconn
, level
);
1445 } conn_list_iterate_end
;
1447 /* Set the caller access level at last, because it could make the
1448 * previous operations impossible if set before. */
1450 (void) set_cmdlevel(caller
, caller
, level
);
1453 /* Set default access for new connections. */
1454 default_access_level
= level
;
1455 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1456 _("Command access level set to '%s' for new players."),
1457 cmdlevel_name(level
));
1458 /* Set default access for first connection. */
1459 first_access_level
= level
;
1460 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1461 _("Command access level set to '%s' "
1462 "for first player to grab it."),
1463 cmdlevel_name(level
));
1467 } else if (fc_strcasecmp(arg
[1], "new") == 0) {
1468 default_access_level
= level
;
1469 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1470 _("Command access level set to '%s' for new players."),
1471 cmdlevel_name(level
));
1472 if (level
> first_access_level
) {
1473 first_access_level
= level
;
1474 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1475 _("Command access level set to '%s' "
1476 "for first player to grab it."),
1477 cmdlevel_name(level
));
1482 } else if (fc_strcasecmp(arg
[1], "first") == 0) {
1483 first_access_level
= level
;
1484 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1485 _("Command access level set to '%s' "
1486 "for first player to grab it."),
1487 cmdlevel_name(level
));
1488 if (level
< default_access_level
) {
1489 default_access_level
= level
;
1490 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1491 _("Command access level set to '%s' for new players."),
1492 cmdlevel_name(level
));
1497 } else if ((ptarget
= conn_by_user_prefix(arg
[1], &match_result
))) {
1498 if (set_cmdlevel(caller
, ptarget
, level
)) {
1502 cmd_reply_no_such_conn(CMD_CMDLEVEL
, caller
, arg
[1], match_result
);
1506 free_tokens(arg
, ntokens
);
1510 /**************************************************************************
1511 This special command to set the command access level is not included into
1512 cmdlevel_command because of its lower access level: it can be used
1513 to promote one's own connection to 'first come' cmdlevel if that isn't
1515 **************************************************************************/
1516 static bool firstlevel_command(struct connection
*caller
, bool check
)
1519 cmd_reply(CMD_FIRSTLEVEL
, caller
, C_FAIL
,
1520 _("The 'first' command makes no sense from the server command line."));
1522 } else if (caller
->access_level
>= first_access_level
) {
1523 cmd_reply(CMD_FIRSTLEVEL
, caller
, C_FAIL
,
1524 _("You already have command access level '%s' or better."),
1525 cmdlevel_name(first_access_level
));
1527 } else if (is_first_access_level_taken()) {
1528 cmd_reply(CMD_FIRSTLEVEL
, caller
, C_FAIL
,
1529 _("Someone else is already game organizer."));
1531 } else if (!check
) {
1532 conn_set_access(caller
, first_access_level
, FALSE
);
1533 cmd_reply(CMD_FIRSTLEVEL
, caller
, C_OK
,
1534 _("Connection %s has opted to become the game organizer."),
1540 /**************************************************************************
1541 Adjust default command level on game start.
1542 **************************************************************************/
1543 void set_running_game_access_level(void)
1545 if (default_access_level
> ALLOW_BASIC
) {
1546 notify_conn(NULL
, NULL
, E_SETTING
, ftc_server
,
1547 _("Default cmdlevel lowered to 'basic' on game start."));
1548 default_access_level
= ALLOW_BASIC
;
1552 /**************************************************************************
1553 Returns possible parameters for the commands that take server options
1554 as parameters (CMD_EXPLAIN and CMD_SET).
1555 **************************************************************************/
1556 static const char *optname_accessor(int i
)
1558 return setting_name(setting_by_number(i
));
1561 #ifdef FREECIV_HAVE_LIBREADLINE
1562 /**************************************************************************
1563 Returns possible parameters for the /show command.
1564 **************************************************************************/
1565 static const char *olvlname_accessor(int i
)
1568 return "rulesetdir";
1569 } else if (i
< OLEVELS_NUM
+1) {
1570 return sset_level_name(i
-1);
1572 return optname_accessor(i
-OLEVELS_NUM
-1);
1575 #endif /* FREECIV_HAVE_LIBREADLINE */
1577 /**************************************************************************
1578 Set timeout options.
1579 **************************************************************************/
1580 static bool timeout_command(struct connection
*caller
, char *str
, bool check
)
1582 char buf
[MAX_LEN_CONSOLE_LINE
];
1587 timeouts
[0] = &game
.server
.timeoutint
;
1588 timeouts
[1] = &game
.server
.timeoutintinc
;
1589 timeouts
[2] = &game
.server
.timeoutinc
;
1590 timeouts
[3] = &game
.server
.timeoutincmult
;
1592 sz_strlcpy(buf
, str
);
1593 ntokens
= get_tokens(buf
, arg
, 4, TOKEN_DELIMITERS
);
1595 for (i
= 0; i
< ntokens
; i
++) {
1596 if (!str_to_int(arg
[i
], timeouts
[i
])) {
1597 cmd_reply(CMD_TIMEOUT
, caller
, C_FAIL
, _("Invalid argument %d."),
1604 cmd_reply(CMD_TIMEOUT
, caller
, C_SYNTAX
, _("Usage:\n%s"),
1605 command_synopsis(command_by_number(CMD_TIMEOUT
)));
1611 cmd_reply(CMD_TIMEOUT
, caller
, C_OK
, _("Dynamic timeout set to "
1613 game
.server
.timeoutint
, game
.server
.timeoutintinc
,
1614 game
.server
.timeoutinc
, game
.server
.timeoutincmult
);
1616 /* if we set anything here, reset the counter */
1617 game
.server
.timeoutcounter
= 1;
1621 /**************************************************************************
1622 Find option level number by name.
1623 **************************************************************************/
1624 static enum sset_level
lookup_option_level(const char *name
)
1628 for (i
= SSET_ALL
; i
< OLEVELS_NUM
; i
++) {
1629 if (0 == fc_strcasecmp(name
, sset_level_name(i
))) {
1637 /* Special return values of lookup options */
1638 #define LOOKUP_OPTION_NO_RESULT (-1)
1639 #define LOOKUP_OPTION_AMBIGUOUS (-2)
1640 #define LOOKUP_OPTION_LEVEL_NAME (-3)
1641 #define LOOKUP_OPTION_RULESETDIR (-4)
1643 /**************************************************************************
1644 Find option index by name. Return index (>=0) on success, else returned
1645 - LOOKUP_OPTION_NO_RESULT if no suitable options were found
1646 - LOOKUP_OPTION_AMBIGUOUS if several matches were found
1647 - LOOKUP_OPTION_LEVEL_NAME if it is an option level
1648 - LOOKUP_OPTION_RULESETDIR if the argument is rulesetdir (special case)
1649 **************************************************************************/
1650 static int lookup_option(const char *name
)
1652 enum m_pre_result result
;
1655 /* Check for option levels, first off */
1656 if (lookup_option_level(name
) != SSET_NONE
) {
1657 return LOOKUP_OPTION_LEVEL_NAME
;
1660 result
= match_prefix(optname_accessor
, settings_number(),
1661 0, fc_strncasecmp
, NULL
, name
, &ind
);
1662 if (M_PRE_AMBIGUOUS
> result
) {
1664 } else if (M_PRE_AMBIGUOUS
== result
) {
1665 return LOOKUP_OPTION_AMBIGUOUS
;
1666 } else if ('\0' != name
[0]
1667 && 0 == fc_strncasecmp("rulesetdir", name
, strlen(name
))) {
1668 return LOOKUP_OPTION_RULESETDIR
;
1670 return LOOKUP_OPTION_NO_RESULT
;
1674 /**************************************************************************
1675 Show the caller detailed help for the single OPTION given by id.
1676 help_cmd is the command the player used.
1677 Only show option values for options which the caller can SEE.
1678 **************************************************************************/
1679 static void show_help_option(struct connection
*caller
,
1680 enum command_id help_cmd
, int id
)
1682 char val_buf
[256], def_buf
[256];
1683 struct setting
*pset
= setting_by_number(id
);
1684 const char *sethelp
;
1686 if (setting_short_help(pset
)) {
1687 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1688 /* TRANS: <untranslated name> - translated short help */
1689 _("Option: %s - %s"), setting_name(pset
),
1690 _(setting_short_help(pset
)));
1692 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1693 /* TRANS: <untranslated name> */
1694 _("Option: %s"), setting_name(pset
));
1697 sethelp
= setting_extra_help(pset
, FALSE
);
1698 if (strlen(sethelp
) > 0) {
1699 char *help
= fc_strdup(sethelp
);
1701 fc_break_lines(help
, LINE_BREAK
);
1702 cmd_reply(help_cmd
, caller
, C_COMMENT
, _("Description:"));
1703 cmd_reply_prefix(help_cmd
, caller
, C_COMMENT
, " ", " %s", help
);
1706 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1707 _("Status: %s"), (setting_is_changeable(pset
, NULL
, NULL
, 0)
1708 ? _("changeable") : _("fixed")));
1710 if (setting_is_visible(pset
, caller
)) {
1711 setting_value_name(pset
, TRUE
, val_buf
, sizeof(val_buf
));
1712 setting_default_name(pset
, TRUE
, def_buf
, sizeof(def_buf
));
1714 switch (setting_type(pset
)) {
1716 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s %s, %s %d, %s %s, %s %d",
1717 _("Value:"), val_buf
,
1718 _("Minimum:"), setting_int_min(pset
),
1719 _("Default:"), def_buf
,
1720 _("Maximum:"), setting_int_max(pset
));
1727 cmd_reply(help_cmd
, caller
, C_COMMENT
, _("Possible values:"));
1728 for (i
= 0; (value
= setting_enum_val(pset
, i
, FALSE
)); i
++) {
1729 cmd_reply(help_cmd
, caller
, C_COMMENT
, "- %s: \"%s\"",
1730 value
, setting_enum_val(pset
, i
, TRUE
));
1736 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s %s, %s %s",
1737 _("Value:"), val_buf
, _("Default:"), def_buf
);
1744 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1745 _("Possible values (option can take any number of these):"));
1746 for (i
= 0; (value
= setting_bitwise_bit(pset
, i
, FALSE
)); i
++) {
1747 cmd_reply(help_cmd
, caller
, C_COMMENT
, "- %s: \"%s\"",
1748 value
, setting_bitwise_bit(pset
, i
, TRUE
));
1750 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s %s",
1751 _("Value:"), val_buf
);
1752 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s %s",
1753 _("Default:"), def_buf
);
1760 /**************************************************************************
1761 Show the caller list of OPTIONS.
1762 help_cmd is the command the player used.
1763 Only show options which the caller can SEE.
1764 **************************************************************************/
1765 static void show_help_option_list(struct connection
*caller
,
1766 enum command_id help_cmd
)
1768 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
1769 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1770 _("Explanations are available for the following server options:"));
1771 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
1772 if(!caller
&& con_get_style()) {
1773 settings_iterate(SSET_ALL
, pset
) {
1774 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", setting_name(pset
));
1775 } settings_iterate_end
1777 char buf
[MAX_LEN_CONSOLE_LINE
];
1781 settings_iterate(SSET_ALL
, pset
) {
1782 if (setting_is_visible(pset
, caller
)) {
1783 cat_snprintf(buf
, sizeof(buf
), "%-19s", setting_name(pset
));
1784 if ((++j
% 4) == 0) {
1785 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", buf
);
1789 } settings_iterate_end
;
1791 if (buf
[0] != '\0') {
1792 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", buf
);
1795 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
1798 /**************************************************************************
1799 Handle explain command
1800 **************************************************************************/
1801 static bool explain_option(struct connection
*caller
, char *str
, bool check
)
1805 remove_leading_trailing_spaces(str
);
1808 cmd
= lookup_option(str
);
1809 if (cmd
>= 0 && cmd
< settings_number()) {
1810 show_help_option(caller
, CMD_EXPLAIN
, cmd
);
1811 } else if (cmd
== LOOKUP_OPTION_NO_RESULT
1812 || cmd
== LOOKUP_OPTION_LEVEL_NAME
1813 || cmd
== LOOKUP_OPTION_RULESETDIR
) {
1814 cmd_reply(CMD_EXPLAIN
, caller
, C_FAIL
,
1815 _("No explanation for that yet."));
1817 } else if (cmd
== LOOKUP_OPTION_AMBIGUOUS
) {
1818 cmd_reply(CMD_EXPLAIN
, caller
, C_FAIL
, _("Ambiguous option name."));
1821 log_error("Unexpected case %d in %s line %d", cmd
, __FILE__
,
1826 show_help_option_list(caller
, CMD_EXPLAIN
);
1831 /******************************************************************
1832 Send a message to all players
1833 ******************************************************************/
1834 static bool wall(char *str
, bool check
)
1837 notify_conn(NULL
, NULL
, E_MESSAGE_WALL
, ftc_server_prompt
,
1838 _("Server Operator: %s"), str
);
1843 /******************************************************************
1844 Set message to send to all new connections
1845 ******************************************************************/
1846 static bool connectmsg_command(struct connection
*caller
, char *str
,
1849 unsigned int bufsize
= sizeof(game
.server
.connectmsg
);
1851 if (is_restricted(caller
)) {
1858 for (i
= 0; c
< bufsize
-1 && str
[i
] != '\0'; i
++) {
1859 if (str
[i
] == '\\') {
1862 if (str
[i
] == 'n') {
1863 game
.server
.connectmsg
[c
++] = '\n';
1865 game
.server
.connectmsg
[c
++] = str
[i
];
1868 game
.server
.connectmsg
[c
++] = str
[i
];
1872 game
.server
.connectmsg
[c
++] = '\0';
1876 cmd_reply(CMD_CONNECTMSG
, caller
, C_WARNING
,
1877 _("Connectmsg truncated to %u bytes."), bufsize
);
1883 /******************************************************************
1884 Translate an AI level back to its CMD_* value.
1885 If we just used /set ailevel <num> we wouldn't have to do this - rp
1886 ******************************************************************/
1887 static enum command_id
cmd_of_level(enum ai_level level
)
1890 case AI_LEVEL_AWAY
: return CMD_AWAY
;
1891 case AI_LEVEL_HANDICAPPED
: return CMD_HANDICAPPED
;
1892 case AI_LEVEL_NOVICE
: return CMD_NOVICE
;
1893 case AI_LEVEL_EASY
: return CMD_EASY
;
1894 case AI_LEVEL_NORMAL
: return CMD_NORMAL
;
1895 case AI_LEVEL_HARD
: return CMD_HARD
;
1896 case AI_LEVEL_CHEATING
: return CMD_CHEATING
;
1898 case AI_LEVEL_EXPERIMENTAL
: return CMD_EXPERIMENTAL
;
1900 case AI_LEVEL_COUNT
: return CMD_NORMAL
;
1902 log_error("Unknown AI level variant: %d.", level
);
1906 /******************************************************************
1907 Set an AI level from the server prompt.
1908 ******************************************************************/
1909 void set_ai_level_direct(struct player
*pplayer
, enum ai_level level
)
1911 set_ai_level_directer(pplayer
, level
);
1912 send_player_info_c(pplayer
, NULL
);
1913 cmd_reply(cmd_of_level(level
), NULL
, C_OK
,
1914 _("Player '%s' now has AI skill level '%s'."),
1915 player_name(pplayer
),
1916 ai_level_translated_name(level
));
1920 /******************************************************************
1921 Handle a user command to set an AI level.
1922 ******************************************************************/
1923 static bool set_ai_level_named(struct connection
*caller
, const char *name
,
1924 const char *level_name
, bool check
)
1926 enum ai_level level
= ai_level_by_name(level_name
, fc_strcasecmp
);
1928 return set_ai_level(caller
, name
, level
, check
);
1931 /******************************************************************
1933 ******************************************************************/
1934 static bool set_ai_level(struct connection
*caller
, const char *name
,
1935 enum ai_level level
, bool check
)
1937 enum m_pre_result match_result
;
1938 struct player
*pplayer
;
1940 fc_assert_ret_val(level
> 0 && level
< 11, FALSE
);
1942 pplayer
= player_by_name_prefix(name
, &match_result
);
1945 if (pplayer
->ai_controlled
) {
1949 set_ai_level_directer(pplayer
, level
);
1950 send_player_info_c(pplayer
, NULL
);
1951 cmd_reply(cmd_of_level(level
), caller
, C_OK
,
1952 _("Player '%s' now has AI skill level '%s'."),
1953 player_name(pplayer
),
1954 ai_level_translated_name(level
));
1956 cmd_reply(cmd_of_level(level
), caller
, C_FAIL
,
1957 _("%s is not controlled by the AI."),
1958 player_name(pplayer
));
1961 } else if (match_result
== M_PRE_EMPTY
) {
1965 players_iterate(cplayer
) {
1966 if (cplayer
->ai_controlled
) {
1967 set_ai_level_directer(cplayer
, level
);
1968 send_player_info_c(cplayer
, NULL
);
1969 cmd_reply(cmd_of_level(level
), caller
, C_OK
,
1970 _("Player '%s' now has AI skill level '%s'."),
1971 player_name(cplayer
),
1972 ai_level_translated_name(level
));
1974 } players_iterate_end
;
1975 game
.info
.skill_level
= level
;
1976 cmd_reply(cmd_of_level(level
), caller
, C_OK
,
1977 _("Default AI skill level set to '%s'."),
1978 ai_level_translated_name(level
));
1980 cmd_reply_no_such_player(cmd_of_level(level
), caller
, name
, match_result
);
1986 /******************************************************************
1987 Set user to away mode.
1988 ******************************************************************/
1989 static bool away_command(struct connection
*caller
, bool check
)
1991 struct player
*pplayer
;
1993 if (caller
== NULL
) {
1994 cmd_reply(CMD_AWAY
, caller
, C_FAIL
, _("This command is client only."));
1998 if (!conn_controls_player(caller
)) {
1999 /* This happens for detached or observer connections. */
2000 cmd_reply(CMD_AWAY
, caller
, C_FAIL
,
2001 _("Only players may use the away command."));
2009 pplayer
= conn_get_player(caller
);
2010 if (!pplayer
->ai_controlled
) {
2011 cmd_reply(CMD_AWAY
, caller
, C_OK
,
2012 _("%s set to away mode."), player_name(pplayer
));
2013 player_set_to_ai_mode(pplayer
, AI_LEVEL_AWAY
);
2014 fc_assert(pplayer
->ai_controlled
== TRUE
);
2016 cmd_reply(CMD_AWAY
, caller
, C_OK
,
2017 _("%s returned to game."), player_name(pplayer
));
2018 player_set_under_human_control(pplayer
);
2019 fc_assert(pplayer
->ai_controlled
== FALSE
);
2022 send_player_info_c(caller
->playing
, game
.est_connections
);
2027 /**************************************************************************
2028 Show changed settings and ruleset summary.
2029 **************************************************************************/
2030 static void show_ruleset_info(struct connection
*caller
, enum command_id cmd
,
2031 bool check
, int read_recursion
)
2033 char *show_arg
= "changed";
2035 /* show changed settings only at the top level of recursion */
2036 if (read_recursion
!= 0) {
2040 show_settings(caller
, cmd
, show_arg
, check
);
2042 if (game
.ruleset_summary
!= NULL
) {
2043 char *translated
= fc_strdup(_(game
.ruleset_summary
));
2045 fc_break_lines(translated
, LINE_BREAK
);
2046 cmd_reply(cmd
, caller
, C_COMMENT
, "%s", translated
);
2047 cmd_reply(cmd
, caller
, C_COMMENT
, horiz_line
);
2052 /**************************************************************************
2053 /show command: show settings and their values.
2054 **************************************************************************/
2055 static bool show_command(struct connection
*caller
, char *str
, bool check
)
2057 return show_settings(caller
, CMD_SHOW
, str
, check
);
2060 /**************************************************************************
2061 Print a summary of the settings and their values. Note that most values
2062 are at most 4 digits, except seeds, which we let overflow their columns,
2063 plus a sign character. Only show options which the caller can SEE.
2064 **************************************************************************/
2065 static bool show_settings(struct connection
*caller
,
2066 enum command_id called_as
,
2067 char *str
, bool check
)
2070 enum sset_level level
= SSET_ALL
;
2073 remove_leading_trailing_spaces(str
);
2074 if (str
[0] != '\0') {
2075 /* In "/show forests", figure out that it's the forests option we're
2077 cmd
= lookup_option(str
);
2079 /* Ignore levels when a particular option is specified. */
2082 if (!setting_is_visible(setting_by_number(cmd
), caller
)) {
2083 cmd_reply(called_as
, caller
, C_FAIL
,
2084 _("Sorry, you do not have access to view option '%s'."),
2090 /* Valid negative values for 'cmd' are defined as LOOKUP_OPTION_*. */
2092 case LOOKUP_OPTION_NO_RESULT
:
2093 cmd_reply(called_as
, caller
, C_FAIL
, _("Unknown option '%s'."), str
);
2095 case LOOKUP_OPTION_AMBIGUOUS
:
2096 /* Allow ambiguous: show all matching. */
2099 case LOOKUP_OPTION_LEVEL_NAME
:
2101 level
= lookup_option_level(str
);
2103 case LOOKUP_OPTION_RULESETDIR
:
2105 cmd_reply(called_as
, caller
, C_COMMENT
,
2106 _("Current ruleset directory is \"%s\""),
2107 game
.server
.rulesetdir
);
2111 /* to indicate that no command was specified */
2112 cmd
= LOOKUP_OPTION_NO_RESULT
;
2113 /* Use vital level by default. */
2117 fc_assert_ret_val(cmd
>= 0 || cmd
== LOOKUP_OPTION_AMBIGUOUS
2118 || cmd
== LOOKUP_OPTION_LEVEL_NAME
2119 || cmd
== LOOKUP_OPTION_NO_RESULT
, FALSE
);
2121 #define cmd_reply_show(string) \
2122 cmd_reply(called_as, caller, C_COMMENT, "%s", string)
2125 const char *heading
= NULL
;
2130 heading
= _("All options with non-default values");
2133 heading
= _("All options");
2136 heading
= _("Vital options");
2138 case SSET_SITUATIONAL
:
2139 heading
= _("Situational options");
2142 heading
= _("Rarely used options");
2145 heading
= _("Options locked by the ruleset");
2152 cmd_reply_show(horiz_line
);
2153 cmd_reply_show(heading
);
2156 cmd_reply_show(horiz_line
);
2157 cmd_reply_show(_("In the column '##' the status of the option is shown:"));
2158 cmd_reply_show(_(" - a '!' means the option is locked by the ruleset."));
2159 cmd_reply_show(_(" - a '+' means you may change the option."));
2160 cmd_reply_show(_(" - a '~' means that option follows default value."));
2161 cmd_reply_show(_(" - a '=' means the value is same as default."));
2162 cmd_reply_show(horiz_line
);
2163 cmd_reply(called_as
, caller
, C_COMMENT
, _("%-*s ## value (min, max)"),
2164 OPTION_NAME_SPACE
, _("Option"));
2165 cmd_reply_show(horiz_line
);
2167 /* Update changed and locked levels. */
2168 settings_list_update();
2172 /* Show _one_ setting. */
2173 fc_assert_ret_val(0 <= cmd
, FALSE
);
2175 struct setting
*pset
= setting_by_number(cmd
);
2177 show_settings_one(caller
, called_as
, pset
);
2183 case SSET_SITUATIONAL
:
2186 settings_iterate(level
, pset
) {
2187 if (!setting_is_visible(pset
, caller
)) {
2191 if (LOOKUP_OPTION_AMBIGUOUS
== cmd
2192 && 0 != fc_strncasecmp(setting_name(pset
), str
, clen
)) {
2196 show_settings_one(caller
, called_as
, pset
);
2197 } settings_iterate_end
;
2204 cmd_reply_show(horiz_line
);
2205 /* Only emit this additional help for bona fide 'show' command */
2206 if (called_as
== CMD_SHOW
) {
2207 cmd_reply_show(_("A help text for each option is available via 'help "
2209 cmd_reply_show(horiz_line
);
2210 if (level
== SSET_VITAL
) {
2211 cmd_reply_show(_("Try 'show situational' or 'show rare' to show "
2213 "Try 'show changed' to show settings with "
2214 "non-default values.\n"
2215 "Try 'show locked' to show settings locked "
2216 "by the ruleset."));
2217 cmd_reply_show(horiz_line
);
2221 #undef cmd_reply_show
2224 /*****************************************************************************
2227 Each option value will be displayed as:
2229 [OPTION_NAME_SPACE length for name] ## [value] ([min], [max])
2231 where '##' is a combination of ' ', '!' or '+' followed by ' ', '*', or '=' with
2232 - '!': the option is locked by the ruleset
2233 - '+': you may change the option
2234 - '~': the option follows default value
2235 - '=': the value is same as default
2236 *****************************************************************************/
2237 static void show_settings_one(struct connection
*caller
, enum command_id cmd
,
2238 struct setting
*pset
)
2240 char buf
[MAX_LEN_CONSOLE_LINE
] = "", value
[MAX_LEN_CONSOLE_LINE
] = "";
2242 static char prefix
[OPTION_NAME_SPACE
+ 4 + 1] = "";
2245 fc_assert_ret(pset
!= NULL
);
2247 is_changed
= setting_non_default(pset
);
2248 setting_value_name(pset
, TRUE
, value
, sizeof(value
));
2250 /* Wrap long option values, such as bitwise options */
2251 fc_break_lines(value
, LINE_BREAK
- (sizeof(prefix
)-1));
2253 if (prefix
[0] == '\0') {
2254 memset(prefix
, ' ', sizeof(prefix
)-1);
2258 /* Emphasizes the changed option. */
2259 /* Apply tags to each line fragment. */
2260 size_t startpos
= 0;
2263 nl
= strchr(value
+ startpos
, '\n');
2264 featured_text_apply_tag(value
, buf
, sizeof(buf
), TTT_COLOR
,
2265 startpos
, nl
? nl
- value
: FT_OFFSET_UNSET
,
2267 sz_strlcpy(value
, buf
);
2269 char *p
= strchr(nl
, '\n');
2270 fc_assert_action(p
!= NULL
, break);
2271 startpos
= p
+ 1 - value
;
2276 if (SSET_INT
== setting_type(pset
)) {
2277 /* Add the range. */
2278 cat_snprintf(value
, sizeof(value
), " (%d, %d)",
2279 setting_int_min(pset
), setting_int_max(pset
));
2282 if (setting_get_setdef(pset
) == SETDEF_INTERNAL
) {
2284 } else if (is_changed
) {
2290 cmd_reply_prefix(cmd
, caller
, C_COMMENT
, prefix
, "%-*s %c%c %s",
2291 OPTION_NAME_SPACE
, setting_name(pset
),
2292 setting_status(caller
, pset
), defaultness
,
2296 /******************************************************************
2298 ******************************************************************/
2299 static bool team_command(struct connection
*caller
, char *str
, bool check
)
2301 struct player
*pplayer
;
2302 enum m_pre_result match_result
;
2303 char buf
[MAX_LEN_CONSOLE_LINE
];
2307 struct team_slot
*tslot
;
2309 if (game_was_started()) {
2310 cmd_reply(CMD_TEAM
, caller
, C_SYNTAX
,
2311 _("Cannot change teams once game has begun."));
2315 if (str
!= NULL
|| strlen(str
) > 0) {
2316 sz_strlcpy(buf
, str
);
2317 ntokens
= get_tokens(buf
, arg
, 2, TOKEN_DELIMITERS
);
2320 cmd_reply(CMD_TEAM
, caller
, C_SYNTAX
,
2321 _("Undefined argument. Usage:\n%s"),
2322 command_synopsis(command_by_number(CMD_TEAM
)));
2326 pplayer
= player_by_name_prefix(arg
[0], &match_result
);
2327 if (pplayer
== NULL
) {
2328 cmd_reply_no_such_player(CMD_TEAM
, caller
, arg
[0], match_result
);
2332 tslot
= team_slot_by_rule_name(arg
[1]);
2333 if (NULL
== tslot
) {
2336 if (str_to_int(arg
[1], &teamno
)) {
2337 tslot
= team_slot_by_number(teamno
);
2340 if (NULL
== tslot
) {
2341 cmd_reply(CMD_TEAM
, caller
, C_SYNTAX
,
2342 _("No such team %s. Please give a "
2343 "valid team name or number."), arg
[1]);
2347 if (is_barbarian(pplayer
)) {
2348 /* This can happen if we change team settings on a loaded game. */
2349 cmd_reply(CMD_TEAM
, caller
, C_SYNTAX
, _("Cannot team a barbarian."));
2353 team_add_player(pplayer
, team_new(tslot
));
2354 send_player_info_c(pplayer
, NULL
);
2355 cmd_reply(CMD_TEAM
, caller
, C_OK
, _("Player %s set to team %s."),
2356 player_name(pplayer
),
2357 team_slot_name_translation(tslot
));
2362 for (i
= 0; i
< ntokens
; i
++) {
2368 /**************************************************************************
2369 List all running votes. Moved from /vote command.
2370 **************************************************************************/
2371 static void show_votes(struct connection
*caller
)
2376 if (vote_list
!= NULL
) {
2377 vote_list_iterate(vote_list
, pvote
) {
2378 if (NULL
!= caller
&& !conn_can_see_vote(caller
, pvote
)) {
2381 /* TRANS: "Vote" or "Teamvote" is voting-as-a-process. Used as
2382 * part of a sentence. */
2383 title
= vote_is_team_only(pvote
) ? _("Teamvote") : _("Vote");
2384 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
,
2385 /* TRANS: "[Vote|Teamvote] 3 \"proposed change\" (needs ..." */
2386 _("%s %d \"%s\" (needs %0.0f%%%s): %d for, "
2387 "%d against, and %d abstained out of %d players."),
2388 title
, pvote
->vote_no
, pvote
->cmdline
,
2389 MIN(100, pvote
->need_pc
* 100 + 1),
2390 pvote
->flags
& VCF_NODISSENT
? _(" no dissent") : "",
2391 pvote
->yes
, pvote
->no
, pvote
->abstain
, count_voters(pvote
));
2393 } vote_list_iterate_end
;
2397 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
,
2398 _("There are no votes going on."));
2402 /**************************************************************************
2403 Vote command argument definitions.
2404 **************************************************************************/
2405 static const char *const vote_args
[] = {
2411 static const char *vote_arg_accessor(int i
)
2413 return vote_args
[i
];
2416 /******************************************************************
2417 Make or participate in a vote.
2418 ******************************************************************/
2419 static bool vote_command(struct connection
*caller
, char *str
,
2422 char buf
[MAX_LEN_CONSOLE_LINE
];
2424 int ntokens
= 0, i
= 0, which
= -1;
2425 enum m_pre_result match_result
;
2426 struct vote
*pvote
= NULL
;
2430 /* This should never happen, since /vote must always be
2431 * set to ALLOW_BASIC or less. But just in case... */
2435 sz_strlcpy(buf
, str
);
2436 ntokens
= get_tokens(buf
, arg
, 2, TOKEN_DELIMITERS
);
2441 } else if (!conn_can_vote(caller
, NULL
)) {
2442 cmd_reply(CMD_VOTE
, caller
, C_FAIL
,
2443 _("You are not allowed to use this command."));
2447 match_result
= match_prefix(vote_arg_accessor
, VOTE_NUM
, 0,
2448 fc_strncasecmp
, NULL
, arg
[0], &i
);
2450 if (match_result
== M_PRE_AMBIGUOUS
) {
2451 cmd_reply(CMD_VOTE
, caller
, C_SYNTAX
,
2452 _("The argument \"%s\" is ambiguous."), arg
[0]);
2454 } else if (match_result
> M_PRE_AMBIGUOUS
) {
2456 cmd_reply(CMD_VOTE
, caller
, C_SYNTAX
,
2457 _("Undefined argument. Usage:\n%s"),
2458 command_synopsis(command_by_number(CMD_VOTE
)));
2463 /* Applies to last vote */
2464 if (vote_number_sequence
> 0 && get_vote_by_no(vote_number_sequence
)) {
2465 which
= vote_number_sequence
;
2467 int num_votes
= vote_list_size(vote_list
);
2468 if (num_votes
== 0) {
2469 cmd_reply(CMD_VOTE
, caller
, C_FAIL
, _("There are no votes running."));
2471 /* TRANS: "vote" as a process */
2472 cmd_reply(CMD_VOTE
, caller
, C_FAIL
, _("No legal last vote (%d %s)."),
2473 num_votes
, PL_("other vote running", "other votes running",
2479 if (!str_to_int(arg
[1], &which
)) {
2480 cmd_reply(CMD_VOTE
, caller
, C_SYNTAX
, _("Value must be an integer."));
2485 if (!(pvote
= get_vote_by_no(which
))) {
2486 /* TRANS: "vote" as a process */
2487 cmd_reply(CMD_VOTE
, caller
, C_FAIL
, _("No such vote (%d)."), which
);
2491 if (!conn_can_vote(caller
, pvote
)) {
2492 cmd_reply(CMD_VOTE
, caller
, C_FAIL
,
2493 _("You are not allowed to vote on that."));
2497 if (i
== VOTE_YES
) {
2498 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
, _("You voted for \"%s\""),
2500 connection_vote(caller
, pvote
, VOTE_YES
);
2501 } else if (i
== VOTE_NO
) {
2502 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
, _("You voted against \"%s\""),
2504 connection_vote(caller
, pvote
, VOTE_NO
);
2505 } else if (i
== VOTE_ABSTAIN
) {
2506 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
,
2507 _("You abstained from voting on \"%s\""), pvote
->cmdline
);
2508 connection_vote(caller
, pvote
, VOTE_ABSTAIN
);
2510 /* Must never happen. */
2511 fc_assert_action(FALSE
, goto CLEANUP
);
2517 free_tokens(arg
, ntokens
);
2521 /**************************************************************************
2522 Cancel a vote... /cancelvote <vote number>|all.
2523 **************************************************************************/
2524 static bool cancelvote_command(struct connection
*caller
,
2525 char *arg
, bool check
)
2527 struct vote
*pvote
= NULL
;
2531 /* This should never happen anyway, since /cancelvote
2532 * is set to ALLOW_BASIC in both pregame and while the
2533 * game is running. */
2537 remove_leading_trailing_spaces(arg
);
2539 if (arg
[0] == '\0') {
2540 if (caller
== NULL
) {
2542 cmd_reply(CMD_CANCELVOTE
, caller
, C_SYNTAX
,
2543 /* TRANS: "vote" as a process */
2544 _("Missing argument <vote number> or "
2545 "the string \"all\"."));
2548 /* The caller cancel his/her own vote. */
2549 if (!(pvote
= get_vote_by_caller(caller
))) {
2550 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2551 _("You don't have any vote going on."));
2554 } else if (fc_strcasecmp(arg
, "all") == 0) {
2555 /* Cancel all votes (needs some privileges). */
2556 if (vote_list_size(vote_list
) == 0) {
2557 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2558 _("There isn't any vote going on."));
2560 } else if (!caller
|| conn_get_access(caller
) >= ALLOW_ADMIN
) {
2562 notify_conn(NULL
, NULL
, E_VOTE_ABORTED
, ftc_server
,
2563 /* TRANS: "votes" as a process */
2564 _("All votes have been removed."));
2567 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2568 _("You are not allowed to use this command."));
2571 } else if (str_to_int(arg
, &vote_no
)) {
2572 /* Cancel one particular vote (needs some privileges if the vote
2574 if (!(pvote
= get_vote_by_no(vote_no
))) {
2575 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2576 /* TRANS: "vote" as a process */
2577 _("No such vote (%d)."), vote_no
);
2579 } else if (caller
&& conn_get_access(caller
) < ALLOW_ADMIN
2580 && caller
->id
!= pvote
->caller_id
) {
2581 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2582 /* TRANS: "vote" as a process */
2583 _("You are not allowed to cancel this vote (%d)."),
2588 cmd_reply(CMD_CANCELVOTE
, caller
, C_SYNTAX
,
2589 /* TRANS: "vote" as a process */
2590 _("Usage: /cancelvote [<vote number>|all]"));
2594 fc_assert_ret_val(NULL
!= pvote
, FALSE
);
2597 notify_team(conn_get_player(vote_get_caller(pvote
)),
2598 NULL
, E_VOTE_ABORTED
, ftc_server
,
2599 /* TRANS: "vote" as a process */
2600 _("%s has canceled the vote \"%s\" (number %d)."),
2601 caller
->username
, pvote
->cmdline
, pvote
->vote_no
);
2604 notify_team(conn_get_player(vote_get_caller(pvote
)),
2605 NULL
, E_VOTE_ABORTED
, ftc_server
,
2606 /* TRANS: "vote" as a process */
2607 _("The vote \"%s\" (number %d) has been canceled."),
2608 pvote
->cmdline
, pvote
->vote_no
);
2610 /* Make it after, prevent crashs about a free pointer (pvote). */
2616 /******************************************************************
2617 Turn on selective debugging.
2618 ******************************************************************/
2619 static bool debug_command(struct connection
*caller
, char *str
,
2622 char buf
[MAX_LEN_CONSOLE_LINE
];
2626 if (game
.info
.is_new_game
) {
2627 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2628 _("Can only use this command once game has begun."));
2632 return TRUE
; /* whatever! */
2635 if (str
!= NULL
&& strlen(str
) > 0) {
2636 sz_strlcpy(buf
, str
);
2637 ntokens
= get_tokens(buf
, arg
, 3, TOKEN_DELIMITERS
);
2642 if (ntokens
> 0 && strcmp(arg
[0], "diplomacy") == 0) {
2643 struct player
*pplayer
;
2644 enum m_pre_result match_result
;
2647 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2648 _("Undefined argument. Usage:\n%s"),
2649 command_synopsis(command_by_number(CMD_DEBUG
)));
2652 pplayer
= player_by_name_prefix(arg
[1], &match_result
);
2653 if (pplayer
== NULL
) {
2654 cmd_reply_no_such_player(CMD_DEBUG
, caller
, arg
[1], match_result
);
2657 if (BV_ISSET(pplayer
->server
.debug
, PLAYER_DEBUG_DIPLOMACY
)) {
2658 BV_CLR(pplayer
->server
.debug
, PLAYER_DEBUG_DIPLOMACY
);
2659 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s diplomacy no longer debugged"),
2660 player_name(pplayer
));
2662 BV_SET(pplayer
->server
.debug
, PLAYER_DEBUG_DIPLOMACY
);
2663 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s diplomacy debugged"),
2664 player_name(pplayer
));
2665 /* TODO: print some info about the player here */
2667 } else if (ntokens
> 0 && strcmp(arg
[0], "tech") == 0) {
2668 struct player
*pplayer
;
2669 enum m_pre_result match_result
;
2672 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2673 _("Undefined argument. Usage:\n%s"),
2674 command_synopsis(command_by_number(CMD_DEBUG
)));
2677 pplayer
= player_by_name_prefix(arg
[1], &match_result
);
2678 if (pplayer
== NULL
) {
2679 cmd_reply_no_such_player(CMD_DEBUG
, caller
, arg
[1], match_result
);
2682 if (BV_ISSET(pplayer
->server
.debug
, PLAYER_DEBUG_TECH
)) {
2683 BV_CLR(pplayer
->server
.debug
, PLAYER_DEBUG_TECH
);
2684 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s tech no longer debugged"),
2685 player_name(pplayer
));
2687 BV_SET(pplayer
->server
.debug
, PLAYER_DEBUG_TECH
);
2688 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s tech debugged"),
2689 player_name(pplayer
));
2690 /* TODO: print some info about the player here */
2692 } else if (ntokens
> 0 && strcmp(arg
[0], "info") == 0) {
2693 int cities
= 0, players
= 0, units
= 0, citizen_count
= 0;
2695 players_iterate(plr
) {
2697 city_list_iterate(plr
->cities
, pcity
) {
2699 citizen_count
+= city_size_get(pcity
);
2700 } city_list_iterate_end
;
2701 units
+= unit_list_size(plr
->units
);
2702 } players_iterate_end
;
2703 log_normal(_("players=%d cities=%d citizens=%d units=%d"),
2704 players
, cities
, citizen_count
, units
);
2705 notify_conn(game
.est_connections
, NULL
, E_AI_DEBUG
, ftc_log
,
2706 _("players=%d cities=%d citizens=%d units=%d"),
2707 players
, cities
, citizen_count
, units
);
2708 } else if (ntokens
> 0 && strcmp(arg
[0], "city") == 0) {
2714 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2715 _("Undefined argument. Usage:\n%s"),
2716 command_synopsis(command_by_number(CMD_DEBUG
)));
2719 if (!str_to_int(arg
[1], &x
) || !str_to_int(arg
[2], &y
)) {
2720 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Value 2 & 3 must be integer."));
2723 if (!(ptile
= map_pos_to_tile(x
, y
))) {
2724 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Bad map coordinates."));
2727 pcity
= tile_city(ptile
);
2729 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("No city at this coordinate."));
2732 if (pcity
->server
.debug
) {
2733 pcity
->server
.debug
= FALSE
;
2734 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s no longer debugged"),
2735 city_name_get(pcity
));
2737 pcity
->server
.debug
= TRUE
;
2738 CITY_LOG(LOG_NORMAL
, pcity
, "debugged");
2740 } else if (ntokens
> 0 && strcmp(arg
[0], "units") == 0) {
2745 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2746 _("Undefined argument. Usage:\n%s"),
2747 command_synopsis(command_by_number(CMD_DEBUG
)));
2750 if (!str_to_int(arg
[1], &x
) || !str_to_int(arg
[2], &y
)) {
2751 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Value 2 & 3 must be integer."));
2754 if (!(ptile
= map_pos_to_tile(x
, y
))) {
2755 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Bad map coordinates."));
2758 unit_list_iterate(ptile
->units
, punit
) {
2759 if (punit
->server
.debug
) {
2760 punit
->server
.debug
= FALSE
;
2761 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s %s no longer debugged."),
2762 nation_adjective_for_player(unit_owner(punit
)),
2763 unit_name_translation(punit
));
2765 punit
->server
.debug
= TRUE
;
2766 UNIT_LOG(LOG_NORMAL
, punit
, "%s %s debugged.",
2767 nation_rule_name(nation_of_unit(punit
)),
2768 unit_name_translation(punit
));
2770 } unit_list_iterate_end
;
2771 } else if (ntokens
> 0 && strcmp(arg
[0], "timing") == 0) {
2773 } else if (ntokens
> 0 && strcmp(arg
[0], "ferries") == 0) {
2774 if (game
.server
.debug
[DEBUG_FERRIES
]) {
2775 game
.server
.debug
[DEBUG_FERRIES
] = FALSE
;
2776 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("Ferry system is no longer "
2779 game
.server
.debug
[DEBUG_FERRIES
] = TRUE
;
2780 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("Ferry system in debug mode."));
2782 } else if (ntokens
> 0 && strcmp(arg
[0], "unit") == 0) {
2787 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2788 _("Undefined argument. Usage:\n%s"),
2789 command_synopsis(command_by_number(CMD_DEBUG
)));
2792 if (!str_to_int(arg
[1], &id
)) {
2793 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Value 2 must be integer."));
2796 if (!(punit
= game_unit_by_number(id
))) {
2797 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Unit %d does not exist."), id
);
2800 if (punit
->server
.debug
) {
2801 punit
->server
.debug
= FALSE
;
2802 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s %s no longer debugged."),
2803 nation_adjective_for_player(unit_owner(punit
)),
2804 unit_name_translation(punit
));
2806 punit
->server
.debug
= TRUE
;
2807 UNIT_LOG(LOG_NORMAL
, punit
, "%s %s debugged.",
2808 nation_rule_name(nation_of_unit(punit
)),
2809 unit_name_translation(punit
));
2812 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2813 _("Undefined argument. Usage:\n%s"),
2814 command_synopsis(command_by_number(CMD_DEBUG
)));
2817 for (i
= 0; i
< ntokens
; i
++) {
2823 /******************************************************************
2824 Helper to validate an argument referring to a server setting.
2825 Sends error message and returns NULL on failure.
2826 ******************************************************************/
2827 static struct setting
*validate_setting_arg(enum command_id cmd
,
2828 struct connection
*caller
,
2831 int opt
= lookup_option(arg
);
2835 case LOOKUP_OPTION_NO_RESULT
:
2836 case LOOKUP_OPTION_LEVEL_NAME
:
2837 cmd_reply(cmd
, caller
, C_SYNTAX
, _("Option '%s' not recognized."), arg
);
2839 case LOOKUP_OPTION_AMBIGUOUS
:
2840 cmd_reply(cmd
, caller
, C_SYNTAX
, _("Ambiguous option name."));
2842 case LOOKUP_OPTION_RULESETDIR
:
2843 cmd_reply(cmd
, caller
, C_SYNTAX
,
2844 /* TRANS: 'rulesetdir' is the command. Do not translate. */
2845 _("Use the '%srulesetdir' command to change the ruleset "
2846 "directory."), caller
? "/" : "");
2849 fc_assert(opt
>= LOOKUP_OPTION_RULESETDIR
);
2855 return setting_by_number(opt
);
2858 /******************************************************************
2860 ******************************************************************/
2861 static bool set_command(struct connection
*caller
, char *str
, bool check
)
2865 struct setting
*pset
;
2867 char reject_msg
[256] = "";
2870 /* '=' is also a valid delimiter for this function. */
2871 nargs
= get_tokens(str
, args
, ARRAY_SIZE(args
), TOKEN_DELIMITERS
"=");
2874 cmd_reply(CMD_SET
, caller
, C_SYNTAX
,
2875 _("Undefined argument. Usage:\n%s"),
2876 command_synopsis(command_by_number(CMD_SET
)));
2880 pset
= validate_setting_arg(CMD_SET
, caller
, args
[0]);
2883 /* Reason already reported. */
2887 if (!setting_is_changeable(pset
, caller
, reject_msg
, sizeof(reject_msg
))
2889 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2895 switch (setting_type(pset
)) {
2898 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2900 || (!setting_bool_validate(pset
, args
[1], caller
,
2901 reject_msg
, sizeof(reject_msg
)))) {
2902 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2905 } else if (setting_bool_set(pset
, args
[1], caller
,
2906 reject_msg
, sizeof(reject_msg
))) {
2909 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2915 if (!str_to_int(args
[1], &val
)) {
2916 cmd_reply(CMD_SET
, caller
, C_SYNTAX
,
2917 _("The parameter %s should only contain +- and 0-9."),
2918 setting_name(pset
));
2922 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2924 || !setting_int_validate(pset
, val
, caller
, reject_msg
,
2925 sizeof(reject_msg
))) {
2926 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2930 if (setting_int_set(pset
, val
, caller
, reject_msg
,
2931 sizeof(reject_msg
))) {
2934 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2942 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2944 || !setting_str_validate(pset
, args
[1], caller
, reject_msg
,
2945 sizeof(reject_msg
))) {
2946 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2950 if (setting_str_set(pset
, args
[1], caller
, reject_msg
,
2951 sizeof(reject_msg
))) {
2954 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2962 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2964 || (!setting_enum_validate(pset
, args
[1], caller
,
2965 reject_msg
, sizeof(reject_msg
)))) {
2966 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2969 } else if (setting_enum_set(pset
, args
[1], caller
,
2970 reject_msg
, sizeof(reject_msg
))) {
2973 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2980 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2982 || (!setting_bitwise_validate(pset
, args
[1], caller
,
2983 reject_msg
, sizeof(reject_msg
)))) {
2984 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2987 } else if (setting_bitwise_set(pset
, args
[1], caller
,
2988 reject_msg
, sizeof(reject_msg
))) {
2991 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2997 ret
= TRUE
; /* Looks like a success. */
2999 if (!check
&& do_update
) {
3000 /* Send only to connections able to see that. */
3002 struct packet_chat_msg packet
;
3004 package_event(&packet
, NULL
, E_SETTING
, ftc_server
,
3005 _("Console: '%s' has been set to %s."), setting_name(pset
),
3006 setting_value_name(pset
, TRUE
, buf
, sizeof(buf
)));
3007 conn_list_iterate(game
.est_connections
, pconn
) {
3008 if (setting_is_visible(pset
, pconn
)) {
3009 send_packet_chat_msg(pconn
, &packet
);
3011 } conn_list_iterate_end
;
3012 /* Notify the console. */
3013 con_write(C_OK
, "%s", packet
.message
);
3015 setting_changed(pset
);
3016 setting_action(pset
);
3017 send_server_setting(NULL
, pset
);
3019 * send any modified game parameters to the clients -- if sent
3020 * before S_S_RUNNING, triggers a popdown_races_dialog() call
3021 * in client/packhand.c#handle_game_info()
3023 send_game_info(NULL
);
3024 reset_all_start_commands(FALSE
);
3025 send_server_info_to_metaserver(META_INFO
);
3029 free_tokens(args
, nargs
);
3033 /**************************************************************************
3034 Check game.allow_take for permission to take or observe a player.
3036 NB: If this function returns FALSE, then callers expect that 'msg' will
3037 be filled in with a NULL-terminated string containing the reason.
3038 **************************************************************************/
3039 static bool is_allowed_to_take(struct player
*pplayer
, bool will_obs
,
3040 char *msg
, size_t msg_len
)
3044 if (!pplayer
&& will_obs
) {
3045 /* Global observer. */
3046 if (!(allow
= strchr(game
.server
.allow_take
,
3047 (game
.info
.is_new_game
? 'O' : 'o')))) {
3048 fc_strlcpy(msg
, _("Sorry, one can't observe globally in this game."),
3052 } else if (!pplayer
&& !will_obs
) {
3053 /* Auto-taking a new player */
3055 if (game_was_started()) {
3056 fc_strlcpy(msg
, _("You cannot take a new player at this time."),
3061 if (normal_player_count() >= game
.server
.max_players
) {
3062 fc_snprintf(msg
, msg_len
,
3063 /* TRANS: Do not translate "maxplayers". */
3064 PL_("You cannot take a new player because "
3065 "the maximum of %d player has already "
3066 "been reached (maxplayers setting).",
3067 "You cannot take a new player because "
3068 "the maximum of %d players has already "
3069 "been reached (maxplayers setting).",
3070 game
.server
.max_players
),
3071 game
.server
.max_players
);
3075 if (player_count() >= player_slot_count()) {
3076 fc_strlcpy(msg
, _("You cannot take a new player because there "
3077 "are no free player slots."),
3084 } else if (is_barbarian(pplayer
)) {
3085 if (!(allow
= strchr(game
.server
.allow_take
, 'b'))) {
3088 _("Sorry, one can't observe barbarians in this game."),
3091 fc_strlcpy(msg
, _("Sorry, one can't take barbarians in this game."),
3096 } else if (!pplayer
->is_alive
) {
3097 if (!(allow
= strchr(game
.server
.allow_take
, 'd'))) {
3100 _("Sorry, one can't observe dead players in this game."),
3104 _("Sorry, one can't take dead players in this game."),
3109 } else if (pplayer
->ai_controlled
) {
3110 if (!(allow
= strchr(game
.server
.allow_take
,
3111 (game
.info
.is_new_game
? 'A' : 'a')))) {
3114 _("Sorry, one can't observe AI players in this game."),
3117 fc_strlcpy(msg
, _("Sorry, one can't take AI players in this game."),
3123 if (!(allow
= strchr(game
.server
.allow_take
,
3124 (game
.info
.is_new_game
? 'H' : 'h')))) {
3127 _("Sorry, one can't observe human players in this game."),
3131 _("Sorry, one can't take human players in this game."),
3140 if (will_obs
&& (*allow
== '2' || *allow
== '3')) {
3141 fc_strlcpy(msg
, _("Sorry, one can't observe in this game."), msg_len
);
3145 if (!will_obs
&& *allow
== '4') {
3146 fc_strlcpy(msg
, _("Sorry, one can't take players in this game."),
3151 if (!will_obs
&& pplayer
->is_connected
3152 && (*allow
== '1' || *allow
== '3')) {
3153 fc_strlcpy(msg
, _("Sorry, one can't take players already "
3154 "connected in this game."), msg_len
);
3161 /**************************************************************************
3162 Observe another player. If we were already attached, detach
3163 (see connection_detach()). The console and those with ALLOW_HACK can
3164 use the two-argument command and force others to observe.
3165 **************************************************************************/
3166 static bool observe_command(struct connection
*caller
, char *str
, bool check
)
3168 int i
= 0, ntokens
= 0;
3169 char buf
[MAX_LEN_CONSOLE_LINE
], *arg
[2], msg
[MAX_LEN_MSG
];
3170 bool is_newgame
= !game_was_started();
3171 enum m_pre_result result
;
3172 struct connection
*pconn
= NULL
;
3173 struct player
*pplayer
= NULL
;
3176 /******** PART I: fill pconn and pplayer ********/
3178 sz_strlcpy(buf
, str
);
3179 ntokens
= get_tokens(buf
, arg
, 2, TOKEN_DELIMITERS
);
3181 /* check syntax, only certain syntax if allowed depending on the caller */
3182 if (!caller
&& ntokens
< 1) {
3183 cmd_reply(CMD_OBSERVE
, caller
, C_SYNTAX
, _("Usage:\n%s"),
3184 command_synopsis(command_by_number(CMD_OBSERVE
)));
3188 if (ntokens
== 2 && (caller
&& caller
->access_level
!= ALLOW_HACK
)) {
3189 cmd_reply(CMD_OBSERVE
, caller
, C_SYNTAX
,
3190 _("Only the player name form is allowed."));
3194 /* match connection if we're console, match a player if we're not */
3196 if (!caller
&& !(pconn
= conn_by_user_prefix(arg
[0], &result
))) {
3197 cmd_reply_no_such_conn(CMD_OBSERVE
, caller
, arg
[0], result
);
3200 && !(pplayer
= player_by_name_prefix(arg
[0], &result
))) {
3201 cmd_reply_no_such_player(CMD_OBSERVE
, caller
, arg
[0], result
);
3206 /* get connection name then player name */
3208 if (!(pconn
= conn_by_user_prefix(arg
[0], &result
))) {
3209 cmd_reply_no_such_conn(CMD_OBSERVE
, caller
, arg
[0], result
);
3212 if (!(pplayer
= player_by_name_prefix(arg
[1], &result
))) {
3213 cmd_reply_no_such_player(CMD_OBSERVE
, caller
, arg
[1], result
);
3218 /* if we can't force other connections to observe, assign us to be pconn. */
3223 /* if we have no pplayer, it means that we want to be a global observer */
3225 /******** PART II: do the observing ********/
3227 /* check allowtake for permission */
3228 if (!is_allowed_to_take(pplayer
, TRUE
, msg
, sizeof(msg
))) {
3229 cmd_reply(CMD_OBSERVE
, caller
, C_FAIL
, "%s", msg
);
3233 /* observing your own player (during pregame) makes no sense. */
3235 && pplayer
== pconn
->playing
3238 && !pplayer
->was_created
) {
3239 cmd_reply(CMD_OBSERVE
, caller
, C_FAIL
,
3240 _("%s already controls %s. Using 'observe' would remove %s"),
3242 player_name(pplayer
),
3243 player_name(pplayer
));
3247 /* attempting to observe a player you're already observing should fail. */
3248 if (pplayer
== pconn
->playing
&& pconn
->observer
) {
3250 cmd_reply(CMD_OBSERVE
, caller
, C_FAIL
,
3251 _("%s is already observing %s."),
3253 player_name(pplayer
));
3255 cmd_reply(CMD_OBSERVE
, caller
, C_FAIL
,
3256 _("%s is already observing."),
3262 res
= TRUE
; /* all tests passed */
3267 /* if the connection is already attached to a player,
3268 * unattach and cleanup old player (rename, remove, etc) */
3270 char name
[MAX_LEN_NAME
];
3273 /* if pconn->playing is removed, we'll lose pplayer */
3274 sz_strlcpy(name
, player_name(pplayer
));
3277 connection_detach(pconn
, TRUE
);
3280 /* find pplayer again, the pointer might have been changed */
3281 pplayer
= player_by_name(name
);
3285 /* attach pconn to new player as an observer or as global observer */
3286 if ((res
= connection_attach(pconn
, pplayer
, TRUE
))) {
3288 cmd_reply(CMD_OBSERVE
, caller
, C_OK
, _("%s now observes %s"),
3290 player_name(pplayer
));
3292 cmd_reply(CMD_OBSERVE
, caller
, C_OK
, _("%s now observes"),
3299 for (i
= 0; i
< ntokens
; i
++) {
3305 /**************************************************************************
3306 Take over a player. If a connection already has control of that player,
3309 If there are two arguments, treat the first as the connection name and the
3310 second as the player name (only hack and the console can do this).
3311 Otherwise, there should be one argument, that being the player that the
3312 caller wants to take.
3313 **************************************************************************/
3314 static bool take_command(struct connection
*caller
, char *str
, bool check
)
3316 int i
= 0, ntokens
= 0;
3317 char buf
[MAX_LEN_CONSOLE_LINE
], *arg
[2], msg
[MAX_LEN_MSG
];
3318 bool is_newgame
= !game_was_started();
3319 enum m_pre_result match_result
;
3320 struct connection
*pconn
= caller
;
3321 struct player
*pplayer
= NULL
;
3324 /******** PART I: fill pconn and pplayer ********/
3326 sz_strlcpy(buf
, str
);
3327 ntokens
= get_tokens(buf
, arg
, 2, TOKEN_DELIMITERS
);
3330 if (!caller
&& ntokens
!= 2) {
3331 cmd_reply(CMD_TAKE
, caller
, C_SYNTAX
, _("Usage:\n%s"),
3332 command_synopsis(command_by_number(CMD_TAKE
)));
3336 if (caller
&& caller
->access_level
!= ALLOW_HACK
&& ntokens
!= 1) {
3337 cmd_reply(CMD_TAKE
, caller
, C_SYNTAX
,
3338 _("Only the player name form is allowed."));
3343 cmd_reply(CMD_TAKE
, caller
, C_SYNTAX
, _("Usage:\n%s"),
3344 command_synopsis(command_by_number(CMD_TAKE
)));
3349 if (!(pconn
= conn_by_user_prefix(arg
[i
], &match_result
))) {
3350 cmd_reply_no_such_conn(CMD_TAKE
, caller
, arg
[i
], match_result
);
3353 i
++; /* found a conn, now reference the second argument */
3356 if (strcmp(arg
[i
], "-") == 0) {
3358 cmd_reply(CMD_TAKE
, caller
, C_FAIL
,
3359 _("You cannot issue \"/take -\" when "
3360 "the game has already started."));
3364 /* Find first uncontrolled player. This will return NULL if there is
3365 * no free players at the moment. Later call to
3366 * connection_attach() will create new player for such NULL
3368 pplayer
= find_uncontrolled_player();
3370 /* Make it human! */
3371 pplayer
->ai_controlled
= FALSE
;
3373 } else if (!(pplayer
= player_by_name_prefix(arg
[i
], &match_result
))) {
3374 cmd_reply_no_such_player(CMD_TAKE
, caller
, arg
[i
], match_result
);
3378 /******** PART II: do the attaching ********/
3380 /* Take not possible if the player is involved in a delegation (either
3381 * it's being controlled, or it's been put aside by the delegate). */
3382 if (player_delegation_active(pplayer
)) {
3383 cmd_reply(CMD_TAKE
, caller
, C_FAIL
, _("A delegation is active for player "
3384 "'%s'. /take not possible."),
3385 player_name(pplayer
));
3389 /* check allowtake for permission */
3390 if (!is_allowed_to_take(pplayer
, FALSE
, msg
, sizeof(msg
))) {
3391 cmd_reply(CMD_TAKE
, caller
, C_FAIL
, "%s", msg
);
3395 /* taking your own player makes no sense. */
3396 if ((NULL
!= pplayer
&& !pconn
->observer
&& pplayer
== pconn
->playing
)
3397 || (NULL
== pplayer
&& !pconn
->observer
&& NULL
!= pconn
->playing
)) {
3398 cmd_reply(CMD_TAKE
, caller
, C_FAIL
, _("%s already controls %s."),
3400 player_name(pconn
->playing
));
3404 /* Make sure there is free player slot if there is need to
3405 * create new player. This is necessary for previously
3406 * detached connections only. Others can reuse the slot
3407 * they first release. */
3408 if (!pplayer
&& !pconn
->playing
3409 && (normal_player_count() >= game
.server
.max_players
3410 || normal_player_count() >= server
.playable_nations
)) {
3411 cmd_reply(CMD_TAKE
, caller
, C_FAIL
,
3412 _("There is no free player slot for %s."),
3416 fc_assert_action(player_count() <= player_slot_count(), goto end
);
3423 /* If the player is controlled by another user, forcibly detach
3425 if (pplayer
&& pplayer
->is_connected
) {
3426 if (NULL
== caller
) {
3427 notify_conn(NULL
, NULL
, E_CONNECTION
, ftc_server
,
3428 _("Reassigned nation to %s by server console."),
3431 notify_conn(NULL
, NULL
, E_CONNECTION
, ftc_server
,
3432 _("Reassigned nation to %s by %s."),
3437 /* We are reassigning this nation, so we need to detach the current
3438 * user to set a new one. */
3439 conn_list_iterate(pplayer
->connections
, aconn
) {
3440 if (!aconn
->observer
) {
3441 connection_detach(aconn
, FALSE
);
3443 } conn_list_iterate_end
;
3446 /* if the connection is already attached to another player,
3447 * unattach and cleanup old player (rename, remove, etc)
3448 * We may have been observing the player we now want to take */
3449 if (NULL
!= pconn
->playing
|| pconn
->observer
) {
3450 char name
[MAX_LEN_NAME
];
3453 /* if pconn->playing is removed, we'll lose pplayer */
3454 sz_strlcpy(name
, player_name(pplayer
));
3457 connection_detach(pconn
, TRUE
);
3460 /* find pplayer again; the pointer might have been changed */
3461 pplayer
= player_by_name(name
);
3465 /* Now attach to new player */
3466 if ((res
= connection_attach(pconn
, pplayer
, FALSE
))) {
3467 /* Successfully attached */
3468 pplayer
= pconn
->playing
; /* In case pplayer was NULL. */
3470 /* inform about the status before changes */
3471 cmd_reply(CMD_TAKE
, caller
, C_OK
, _("%s now controls %s (%s, %s)."),
3473 player_name(pplayer
),
3474 is_barbarian(pplayer
)
3476 : pplayer
->ai_controlled
3483 cmd_reply(CMD_TAKE
, caller
, C_FAIL
,
3484 _("%s failed to attach to any player."),
3490 for (i
= 0; i
< ntokens
; i
++) {
3496 /**************************************************************************
3497 Detach from a player. if that player wasn't /created and you were
3498 controlling the player, remove it (and then detach any observers as well).
3500 If called for a global observer connection (where pconn->playing is NULL)
3501 then it will correctly detach from observing mode.
3502 **************************************************************************/
3503 static bool detach_command(struct connection
*caller
, char *str
, bool check
)
3505 int i
= 0, ntokens
= 0;
3506 char buf
[MAX_LEN_CONSOLE_LINE
], *arg
[1];
3507 enum m_pre_result match_result
;
3508 struct connection
*pconn
= NULL
;
3509 struct player
*pplayer
= NULL
;
3512 sz_strlcpy(buf
, str
);
3513 ntokens
= get_tokens(buf
, arg
, 1, TOKEN_DELIMITERS
);
3515 if (!caller
&& ntokens
== 0) {
3516 cmd_reply(CMD_DETACH
, caller
, C_SYNTAX
, _("Usage:\n%s"),
3517 command_synopsis(command_by_number(CMD_DETACH
)));
3521 /* match the connection if the argument was given */
3523 && !(pconn
= conn_by_user_prefix(arg
[0], &match_result
))) {
3524 cmd_reply_no_such_conn(CMD_DETACH
, caller
, arg
[0], match_result
);
3528 /* if no argument is given, the caller wants to detach himself */
3533 /* if pconn and caller are not the same, only continue
3534 * if we're console, or we have ALLOW_HACK */
3535 if (pconn
!= caller
&& caller
&& caller
->access_level
!= ALLOW_HACK
) {
3536 cmd_reply(CMD_DETACH
, caller
, C_FAIL
,
3537 _("You can not detach other users."));
3541 pplayer
= pconn
->playing
;
3543 /* must have someone to detach from... */
3544 if (!pplayer
&& !pconn
->observer
) {
3545 cmd_reply(CMD_DETACH
, caller
, C_FAIL
,
3546 _("%s is not attached to any player."), pconn
->username
);
3556 cmd_reply(CMD_DETACH
, caller
, C_OK
, _("%s detaching from %s"),
3557 pconn
->username
, player_name(pplayer
));
3559 cmd_reply(CMD_DETACH
, caller
, C_OK
, _("%s no longer observing."),
3563 /* Actually do the detaching. */
3564 connection_detach(pconn
, TRUE
);
3566 /* The user explicitly wanted to detach, so if a player is marked for him,
3567 * reset its username. */
3568 players_iterate(aplayer
) {
3569 if (0 == strncmp(aplayer
->username
, pconn
->username
, MAX_LEN_NAME
)) {
3570 sz_strlcpy(aplayer
->username
, _(ANON_USER_NAME
));
3571 aplayer
->unassigned_user
= TRUE
;
3572 send_player_info_c(aplayer
, NULL
);
3574 } players_iterate_end
;
3576 check_for_full_turn_done();
3579 fc_assert_ret_val(ntokens
<= 1, FALSE
);
3582 for (i
= 0; i
< ntokens
; i
++) {
3588 /**************************************************************************
3589 Loads a file, complete with access checks and error messages sent back
3590 to the caller on failure.
3592 * caller is the connection requesting the load, or NULL for a
3593 command-line load. Error messages are sent back to the caller and
3594 an access check is done to make sure they are allowed to load.
3596 * filename is simply the name of the file to be loaded. This may be
3597 approximate; the function will look for appropriate suffixes and will
3598 check in the various directories to see if the file is found.
3600 * if check is set then only a test run is done and no actual loading
3603 * The return value is true if the load succeeds, or would succeed;
3604 false if there's an error in the file or file name. Some errors
3605 in loading however could be unrecoverable (if the save game is
3606 legitimate but has inconsistencies) and would lead to a broken server
3608 **************************************************************************/
3609 bool load_command(struct connection
*caller
, const char *filename
, bool check
,
3612 struct timer
*loadtimer
, *uloadtimer
;
3613 struct section_file
*file
;
3614 char arg
[MAX_LEN_PATH
];
3615 struct conn_list
*global_observers
;
3617 if (!filename
|| filename
[0] == '\0') {
3618 cmd_reply(CMD_LOAD
, caller
, C_FAIL
, _("Usage:\n%s"),
3619 command_synopsis(command_by_number(CMD_LOAD
)));
3622 if (S_S_INITIAL
!= server_state()) {
3623 cmd_reply(CMD_LOAD
, caller
, C_FAIL
,
3624 _("Cannot load a game while another is running."));
3625 dlsend_packet_game_load(game
.est_connections
, TRUE
, filename
);
3628 if (!is_safe_filename(filename
) && is_restricted(caller
)) {
3629 cmd_reply(CMD_LOAD
, caller
, C_FAIL
,
3630 _("Name \"%s\" disallowed for security reasons."),
3636 /* it is a normal savegame or maybe a scenario */
3637 char testfile
[MAX_LEN_PATH
];
3638 const struct strvec
*pathes
[] = {
3639 get_save_dirs(), get_scenario_dirs(), NULL
3641 const char *exts
[] = {
3642 "sav", "gz", "bz2", "xz", "sav.gz", "sav.bz2", "sav.xz", NULL
3644 const char **ext
, *found
= NULL
;
3645 const struct strvec
**path
;
3648 /* Allow plain names being loaded with '--file' option, but not otherwise
3649 * (no loading of arbitrary files by unauthorized users)
3650 * Iterate through ALL paths to check for file with plain name before
3651 * looking any path with an extension, i.e., prefer plain name file
3652 * in later directory over file with extension in name in earlier
3654 for (path
= pathes
; !found
&& *path
; path
++) {
3655 found
= fileinfoname(*path
, filename
);
3656 if (found
!= NULL
) {
3657 sz_strlcpy(arg
, found
);
3662 for (path
= pathes
; !found
&& *path
; path
++) {
3663 for (ext
= exts
; !found
&& *ext
; ext
++) {
3664 fc_snprintf(testfile
, sizeof(testfile
), "%s.%s", filename
, *ext
);
3665 found
= fileinfoname(*path
, testfile
);
3666 if (found
!= NULL
) {
3667 sz_strlcpy(arg
, found
);
3672 if (is_restricted(caller
) && !found
) {
3673 cmd_reply(CMD_LOAD
, caller
, C_FAIL
, _("Cannot find savegame or "
3674 "scenario with the name \"%s\"."), filename
);
3679 sz_strlcpy(arg
, filename
);
3683 /* attempt to parse the file */
3685 if (!(file
= secfile_load(arg
, FALSE
))) {
3686 log_error("Error loading savefile '%s': %s", arg
, secfile_error());
3687 cmd_reply(CMD_LOAD
, caller
, C_FAIL
, _("Could not load savefile: %s"),
3689 dlsend_packet_game_load(game
.est_connections
, TRUE
, arg
);
3697 /* Detach current players, before we blow them away. */
3698 global_observers
= conn_list_new();
3699 conn_list_iterate(game
.est_connections
, pconn
) {
3700 if (pconn
->playing
!= NULL
) {
3701 connection_detach(pconn
, TRUE
);
3702 } else if (pconn
->observer
) {
3703 conn_list_append(global_observers
, pconn
);
3704 connection_detach(pconn
, TRUE
);
3706 } conn_list_iterate_end
;
3708 player_info_freeze();
3710 /* Now free all game data. */
3714 loadtimer
= timer_new(TIMER_CPU
, TIMER_ACTIVE
);
3715 timer_start(loadtimer
);
3716 uloadtimer
= timer_new(TIMER_USER
, TIMER_ACTIVE
);
3717 timer_start(uloadtimer
);
3719 sz_strlcpy(srvarg
.load_filename
, arg
);
3721 savegame2_load(file
);
3722 secfile_check_unused(file
);
3723 secfile_destroy(file
);
3725 log_verbose("Load time: %g seconds (%g apparent)",
3726 timer_read_seconds(loadtimer
), timer_read_seconds(uloadtimer
));
3727 timer_destroy(loadtimer
);
3728 timer_destroy(uloadtimer
);
3732 log_verbose("load_command() does send_rulesets()");
3733 conn_list_compression_freeze(game
.est_connections
);
3734 send_rulesets(game
.est_connections
);
3735 send_server_settings(game
.est_connections
);
3736 send_scenario_info(game
.est_connections
);
3737 send_scenario_description(game
.est_connections
);
3738 send_game_info(game
.est_connections
);
3739 conn_list_compression_thaw(game
.est_connections
);
3741 /* Send information about the new players. */
3743 send_player_diplstate_c(NULL
, NULL
);
3745 /* Everything seemed to load ok; spread the good news. */
3746 dlsend_packet_game_load(game
.est_connections
, TRUE
, srvarg
.load_filename
);
3748 /* Attach connections to players. Currently, this applies only
3749 * to connections that have the same username as a player. */
3750 conn_list_iterate(game
.est_connections
, pconn
) {
3751 players_iterate(pplayer
) {
3752 if (strcmp(pconn
->username
, pplayer
->username
) == 0) {
3753 connection_attach(pconn
, pplayer
, FALSE
);
3756 } players_iterate_end
;
3757 } conn_list_iterate_end
;
3759 /* Reattach global observers. */
3760 conn_list_iterate(global_observers
, pconn
) {
3761 if (NULL
== pconn
->playing
) {
3762 /* May have been assigned to a player before. */
3763 connection_attach(pconn
, NULL
, TRUE
);
3765 } conn_list_iterate_end
;
3766 conn_list_destroy(global_observers
);
3768 (void) aifill(game
.info
.aifill
);
3770 achievements_iterate(pach
) {
3771 players_iterate(pplayer
) {
3772 struct packet_achievement_info pack
;
3774 pack
.id
= achievement_index(pach
);
3775 pack
.gained
= achievement_player_has(pach
, pplayer
);
3776 pack
.first
= (pach
->first
== pplayer
);
3778 lsend_packet_achievement_info(pplayer
->connections
, &pack
);
3779 } players_iterate_end
;
3780 } achievements_iterate_end
;
3785 /**************************************************************************
3786 Load rulesets from a given ruleset directory.
3788 Security: There are some rudimentary checks in load_rulesets() to see
3789 if this directory really is a viable ruleset directory. For public
3790 servers, we check against directory redirection (is_safe_filename) and
3791 other bad stuff in the directory name, and will only use directories
3792 inside the data directories.
3793 **************************************************************************/
3794 static bool set_rulesetdir(struct connection
*caller
, char *str
, bool check
,
3798 const char *pfilename
;
3800 if (NULL
== str
|| '\0' == str
[0]) {
3801 cmd_reply(CMD_RULESETDIR
, caller
, C_SYNTAX
,
3802 _("You must provide a ruleset name. Use \"/show ruleset\" to "
3803 "see what is the current ruleset."));
3806 if (game_was_started() || !map_is_empty()) {
3807 cmd_reply(CMD_RULESETDIR
, caller
, C_FAIL
,
3808 _("This setting can't be modified after the game has started."));
3812 if (strcmp(str
, game
.server
.rulesetdir
) == 0) {
3813 cmd_reply(CMD_RULESETDIR
, caller
, C_COMMENT
,
3814 _("Ruleset directory is already \"%s\""), str
);
3818 if (is_restricted(caller
)
3819 && (!is_safe_filename(str
) || strchr(str
, '.'))) {
3820 cmd_reply(CMD_RULESETDIR
, caller
, C_SYNTAX
,
3821 _("Name \"%s\" disallowed for security reasons."),
3826 fc_snprintf(filename
, sizeof(filename
), "%s", str
);
3827 pfilename
= fileinfoname(get_data_dirs(), filename
);
3829 cmd_reply(CMD_RULESETDIR
, caller
, C_SYNTAX
,
3830 _("Ruleset directory \"%s\" not found"), str
);
3835 bool success
= TRUE
;
3838 sz_strlcpy(old
, game
.server
.rulesetdir
);
3839 log_verbose("set_rulesetdir() does load_rulesets() with \"%s\"", str
);
3840 sz_strlcpy(game
.server
.rulesetdir
, str
);
3842 /* load the ruleset (and game settings defined in the ruleset) */
3843 player_info_freeze();
3844 if (!load_rulesets(old
, TRUE
, FALSE
)) {
3847 /* While loading of the requested ruleset failed, we might
3848 * have changed ruleset from third one to default. Handle
3849 * rest of the ruleset changing accordingly. */
3852 if (game
.est_connections
) {
3853 /* Now that the rulesets are loaded we immediately send updates to any
3854 * connected clients. */
3855 send_rulesets(game
.est_connections
);
3857 /* show ruleset summary and list changed values */
3858 show_ruleset_info(caller
, CMD_RULESETDIR
, check
, read_recursion
);
3862 cmd_reply(CMD_RULESETDIR
, caller
, C_OK
,
3863 _("Ruleset directory set to \"%s\""), str
);
3865 cmd_reply(CMD_RULESETDIR
, caller
, C_SYNTAX
,
3866 _("Failed loading rulesets from directory \"%s\", using \"%s\""),
3867 str
, game
.server
.rulesetdir
);
3876 /****************************************************************************
3877 /ignore command handler.
3878 ****************************************************************************/
3879 static bool ignore_command(struct connection
*caller
, char *str
, bool check
)
3882 struct conn_pattern
*ppattern
;
3884 if (NULL
== caller
) {
3885 cmd_reply(CMD_IGNORE
, caller
, C_FAIL
,
3886 _("That would be rather silly, since you are not a player."));
3890 ppattern
= conn_pattern_from_string(str
, CPT_USER
, buf
, sizeof(buf
));
3891 if (NULL
== ppattern
) {
3892 cmd_reply(CMD_IGNORE
, caller
, C_SYNTAX
,
3893 _("%s. Try /help ignore"), buf
);
3898 conn_pattern_destroy(ppattern
);
3902 conn_pattern_to_string(ppattern
, buf
, sizeof(buf
));
3903 conn_pattern_list_append(caller
->server
.ignore_list
, ppattern
);
3904 cmd_reply(CMD_IGNORE
, caller
, C_COMMENT
,
3905 _("Added pattern %s as entry %d to your ignore list."),
3906 buf
, conn_pattern_list_size(caller
->server
.ignore_list
));
3911 /****************************************************************************
3912 /unignore command handler.
3913 ****************************************************************************/
3914 static bool unignore_command(struct connection
*caller
,
3915 char *str
, bool check
)
3921 cmd_reply(CMD_IGNORE
, caller
, C_FAIL
,
3922 _("That would be rather silly, since you are not a player."));
3926 sz_strlcpy(buf
, str
);
3927 remove_leading_trailing_spaces(buf
);
3929 n
= conn_pattern_list_size(caller
->server
.ignore_list
);
3931 cmd_reply(CMD_UNIGNORE
, caller
, C_FAIL
, _("Your ignore list is empty."));
3935 /* Parse the range. */
3936 if ('\0' == buf
[0]) {
3937 cmd_reply(CMD_UNIGNORE
, caller
, C_SYNTAX
,
3938 _("Missing range. Try /help unignore."));
3940 } else if ((c
= strchr(buf
, '-'))) {
3942 if ('\0' == buf
[0]) {
3944 } else if (!str_to_int(buf
, &first
)) {
3946 cmd_reply(CMD_UNIGNORE
, caller
, C_SYNTAX
,
3947 _("\"%s\" is not a valid range. Try /help unignore."), buf
);
3952 } else if (!str_to_int(c
, &last
)) {
3954 cmd_reply(CMD_UNIGNORE
, caller
, C_SYNTAX
,
3955 _("\"%s\" is not a valid range. Try /help unignore."), buf
);
3959 if (!str_to_int(buf
, &first
)) {
3960 cmd_reply(CMD_UNIGNORE
, caller
, C_SYNTAX
,
3961 _("\"%s\" is not a valid range. Try /help unignore."), buf
);
3967 if (!(1 <= first
&& first
<= last
&& last
<= n
)) {
3968 if (first
== last
) {
3969 cmd_reply(CMD_UNIGNORE
, caller
, C_FAIL
,
3970 _("Invalid entry number: %d."), first
);
3972 cmd_reply(CMD_UNIGNORE
, caller
, C_FAIL
,
3973 _("Invalid range: %d to %d."), first
, last
);
3983 conn_pattern_list_iterate(caller
->server
.ignore_list
, ppattern
) {
3985 conn_pattern_to_string(ppattern
, buf
, sizeof(buf
));
3986 cmd_reply(CMD_UNIGNORE
, caller
, C_COMMENT
,
3987 _("Removed pattern %s (entry %d) from your ignore list."),
3989 conn_pattern_list_remove(caller
->server
.ignore_list
, ppattern
);
3995 } conn_pattern_list_iterate_end
;
4000 /****************************************************************************
4001 /playercolor command handler.
4002 ****************************************************************************/
4003 static bool playercolor_command(struct connection
*caller
,
4004 char *str
, bool check
)
4006 enum m_pre_result match_result
;
4007 struct player
*pplayer
;
4008 struct rgbcolor
*prgbcolor
= NULL
;
4013 ntokens
= get_tokens(str
, token
, 2, TOKEN_DELIMITERS
);
4016 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_SYNTAX
,
4017 _("Two arguments needed. See '/help playercolor'."));
4022 pplayer
= player_by_name_prefix(token
[0], &match_result
);
4025 cmd_reply_no_such_player(CMD_PLAYERCOLOR
, caller
, token
[0], match_result
);
4032 if (!player_color_changeable(pplayer
, &reason
)) {
4033 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_FAIL
, "%s", reason
);
4039 if (0 == fc_strcasecmp(token
[1], "reset")) {
4040 if (!game_was_started()) {
4043 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_FAIL
,
4044 _("Can only unset player color before game starts."));
4048 } else if (!rgbcolor_from_hex(&prgbcolor
, token
[1])) {
4049 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_SYNTAX
,
4050 _("Invalid player color definition. See '/help playercolor'."));
4055 if (prgbcolor
!= NULL
) {
4056 players_iterate(pother
) {
4057 if (pother
!= pplayer
&& pother
->rgb
!= NULL
4058 && rgbcolors_are_equal(pother
->rgb
, prgbcolor
)) {
4059 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_WARNING
,
4060 /* TRANS: "... [c0ffee] for Caesar ... to Hammurabi." */
4061 _("Warning: new color [%s] for %s is identical to %s."),
4062 player_color_ftstr(pother
), player_name(pplayer
),
4063 player_name(pother
));
4065 } players_iterate_end
;
4072 server_player_set_color(pplayer
, prgbcolor
);
4073 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_OK
,
4074 _("Color of player %s set to [%s]."), player_name(pplayer
),
4075 player_color_ftstr(pplayer
));
4079 rgbcolor_destroy(prgbcolor
);
4080 free_tokens(token
, ntokens
);
4085 /**************************************************************************
4087 **************************************************************************/
4088 static bool quit_game(struct connection
*caller
, bool check
)
4091 cmd_reply(CMD_QUIT
, caller
, C_OK
, _("Goodbye."));
4097 /**************************************************************************
4098 Main entry point for "command input".
4099 **************************************************************************/
4100 bool handle_stdin_input(struct connection
*caller
, char *str
)
4102 return handle_stdin_input_real(caller
, str
, FALSE
, 0);
4105 /**************************************************************************
4106 Handle "command input", which could really come from stdin on console,
4107 or from client chat command, or read from file with -r, etc.
4108 caller==NULL means console, str is the input, which may optionally
4109 start with SERVER_COMMAND_PREFIX character.
4111 If check is TRUE, then do nothing, just check syntax.
4112 **************************************************************************/
4113 static bool handle_stdin_input_real(struct connection
*caller
, char *str
,
4114 bool check
, int read_recursion
)
4116 char full_command
[MAX_LEN_CONSOLE_LINE
];
4117 char command
[MAX_LEN_CONSOLE_LINE
], arg
[MAX_LEN_CONSOLE_LINE
];
4118 char *cptr_s
, *cptr_d
;
4119 enum command_id cmd
;
4120 enum cmdlevel level
;
4122 /* Remove leading and trailing spaces, and server command prefix. */
4123 cptr_s
= str
= skip_leading_spaces(str
);
4124 if ('\0' == *cptr_s
|| '#' == *cptr_s
) {
4125 /* This appear to be a comment or blank line. */
4129 if (SERVER_COMMAND_PREFIX
== *cptr_s
) {
4130 /* Commands may be prefixed with SERVER_COMMAND_PREFIX, even when
4131 * given on the server command line. */
4133 remove_leading_spaces(cptr_s
);
4134 if ('\0' == *cptr_s
) {
4135 /* This appear to be a blank line. */
4139 remove_trailing_spaces(cptr_s
);
4141 /* notify to the server console */
4142 if (!check
&& caller
) {
4143 con_write(C_COMMENT
, "%s: '%s'", caller
->username
, str
);
4146 /* if the caller may not use any commands at all, don't waste any time */
4147 if (may_use_nothing(caller
)) {
4148 cmd_reply(CMD_HELP
, caller
, C_FAIL
,
4149 _("Sorry, you are not allowed to use server commands."));
4153 /* copy the full command, in case we need it for voting purposes. */
4154 sz_strlcpy(full_command
, cptr_s
);
4157 * cptr_s points now to the beginning of the real command. It has
4158 * skipped leading whitespace, the SERVER_COMMAND_PREFIX and any
4159 * other non-alphanumeric characters.
4161 for (cptr_d
= command
; *cptr_s
!= '\0' && fc_isalnum(*cptr_s
)
4162 && cptr_d
< command
+ sizeof(command
) - 1; cptr_s
++, cptr_d
++) {
4167 /* cptr_s now contains the arguments. */
4168 sz_strlcpy(arg
, skip_leading_spaces(cptr_s
));
4170 cmd
= command_named(command
, FALSE
);
4171 if (cmd
== CMD_AMBIGUOUS
) {
4172 cmd
= command_named(command
, TRUE
);
4173 cmd_reply(cmd
, caller
, C_SYNTAX
,
4174 _("Warning: '%s' interpreted as '%s', but it is ambiguous."
4176 command
, command_name_by_number(cmd
), caller
?"/":"");
4177 } else if (cmd
== CMD_UNRECOGNIZED
) {
4178 cmd_reply(cmd
, caller
, C_SYNTAX
, _("Unknown command '%s%s'. "
4180 caller
? "/" : "", command
, caller
? "/" : "");
4184 level
= command_level(command_by_number(cmd
));
4186 if (conn_can_vote(caller
, NULL
) && level
== ALLOW_CTRL
4187 && conn_get_access(caller
) == ALLOW_BASIC
&& !check
4188 && !vote_would_pass_immediately(caller
, cmd
)) {
4190 bool caller_had_vote
= (NULL
!= get_vote_by_caller(caller
));
4192 /* Check if the vote command would succeed. If we already have a vote
4193 * going, cancel it in favour of the new vote command. You can only
4194 * have one vote at a time. This is done by vote_new(). */
4195 if (handle_stdin_input_real(caller
, full_command
, TRUE
,
4197 && (vote
= vote_new(caller
, arg
, cmd
))) {
4198 char votedesc
[MAX_LEN_CONSOLE_LINE
];
4199 const struct player
*teamplr
;
4201 struct ft_color color
;
4203 if (caller_had_vote
) {
4204 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
,
4205 /* TRANS: "vote" as a process */
4206 _("Your new vote canceled your previous vote."));
4209 describe_vote(vote
, votedesc
, sizeof(votedesc
));
4211 if (vote_is_team_only(vote
)) {
4212 /* TRANS: "vote" as a process */
4213 what
= _("New teamvote");
4214 teamplr
= conn_get_player(caller
);
4215 color
= ftc_vote_team
;
4217 /* TRANS: "vote" as a process */
4218 what
= _("New vote");
4220 color
= ftc_vote_public
;
4222 notify_team(teamplr
, NULL
, E_VOTE_NEW
, color
,
4223 /* TRANS: "[New vote|New teamvote] (number 3)
4224 * by fred: proposed change" */
4225 _("%s (number %d) by %s: %s"), what
,
4226 vote
->vote_no
, caller
->username
, votedesc
);
4228 /* Vote on your own suggestion. */
4229 connection_vote(caller
, vote
, VOTE_YES
);
4233 cmd_reply(CMD_VOTE
, caller
, C_FAIL
,
4234 /* TRANS: "vote" as a process */
4235 _("Your new vote (\"%s\") was not "
4236 "legal or was not recognized."), full_command
);
4242 && !((check
|| vote_would_pass_immediately(caller
, cmd
))
4243 && conn_get_access(caller
) >= ALLOW_BASIC
4244 && level
== ALLOW_CTRL
)
4245 && conn_get_access(caller
) < level
) {
4246 cmd_reply(cmd
, caller
, C_FAIL
,
4247 _("You are not allowed to use this command."));
4252 struct conn_list
*echo_list
= NULL
;
4253 bool echo_list_allocated
= FALSE
;
4255 switch (command_echo(command_by_number(cmd
))) {
4258 case CMD_ECHO_ADMINS
:
4259 conn_list_iterate(game
.est_connections
, pconn
) {
4260 if (ALLOW_ADMIN
<= conn_get_access(pconn
)) {
4261 if (NULL
== echo_list
) {
4262 echo_list
= conn_list_new();
4263 echo_list_allocated
= TRUE
;
4265 conn_list_append(echo_list
, pconn
);
4267 } conn_list_iterate_end
;
4270 echo_list
= game
.est_connections
;
4274 if (NULL
!= echo_list
) {
4276 notify_conn(echo_list
, NULL
, E_SETTING
, ftc_any
,
4277 "%s: '%s %s'", caller
->username
, command
, arg
);
4279 notify_conn(echo_list
, NULL
, E_SETTING
, ftc_server_prompt
,
4280 "%s: '%s %s'", _("(server prompt)"), command
, arg
);
4282 if (echo_list_allocated
) {
4283 conn_list_destroy(echo_list
);
4290 return remove_player_command(caller
, arg
, check
);
4292 return save_command(caller
, arg
, check
);
4294 return scensave_command(caller
, arg
, check
);
4296 return load_command(caller
, arg
, check
, FALSE
);
4297 case CMD_METAPATCHES
:
4298 return metapatches_command(caller
, arg
, check
);
4299 case CMD_METAMESSAGE
:
4300 return metamessage_command(caller
, arg
, check
);
4302 return metaconnection_command(caller
, arg
, check
);
4303 case CMD_METASERVER
:
4304 return metaserver_command(caller
, arg
, check
);
4306 return show_help(caller
, arg
);
4308 return show_serverid(caller
, arg
);
4310 return show_list(caller
, arg
);
4312 return toggle_ai_command(caller
, arg
, check
);
4314 return take_command(caller
, arg
, check
);
4316 return observe_command(caller
, arg
, check
);
4318 return detach_command(caller
, arg
, check
);
4320 return create_command(caller
, arg
, check
);
4322 return away_command(caller
, check
);
4323 case CMD_HANDICAPPED
:
4330 case CMD_EXPERIMENTAL
:
4332 return set_ai_level_named(caller
, arg
, command_name_by_number(cmd
), check
);
4334 return quit_game(caller
, check
);
4336 return cut_client_connection(caller
, arg
, check
);
4338 return show_command(caller
, arg
, check
);
4340 return explain_option(caller
, arg
, check
);
4342 return debug_command(caller
, arg
, check
);
4344 return set_command(caller
, arg
, check
);
4346 return team_command(caller
, arg
, check
);
4347 case CMD_RULESETDIR
:
4348 return set_rulesetdir(caller
, arg
, check
, read_recursion
);
4350 return wall(arg
, check
);
4351 case CMD_CONNECTMSG
:
4352 return connectmsg_command(caller
, arg
, check
);
4354 return vote_command(caller
, arg
, check
);
4355 case CMD_CANCELVOTE
:
4356 return cancelvote_command(caller
, arg
, check
);
4357 case CMD_READ_SCRIPT
:
4358 return read_command(caller
, arg
, check
, read_recursion
);
4359 case CMD_WRITE_SCRIPT
:
4360 return write_command(caller
, arg
, check
);
4362 return reset_command(caller
, arg
, check
, read_recursion
);
4364 return default_command(caller
, arg
, check
);
4366 return lua_command(caller
, arg
, check
);
4368 return kick_command(caller
, arg
, check
);
4370 return delegate_command(caller
, arg
, check
);
4372 return fcdb_command(caller
, arg
, check
);
4374 return mapimg_command(caller
, arg
, check
);
4375 case CMD_RFCSTYLE
: /* see console.h for an explanation */
4377 con_set_style(!con_get_style());
4381 return cmdlevel_command(caller
, arg
, check
);
4382 case CMD_FIRSTLEVEL
:
4383 return firstlevel_command(caller
, check
);
4385 return timeout_command(caller
, arg
, check
);
4386 case CMD_START_GAME
:
4387 return start_command(caller
, check
, FALSE
);
4389 return end_command(caller
, arg
, check
);
4391 return surrender_command(caller
, arg
, check
);
4393 return ignore_command(caller
, arg
, check
);
4395 return unignore_command(caller
, arg
, check
);
4396 case CMD_PLAYERCOLOR
:
4397 return playercolor_command(caller
, arg
, check
);
4399 case CMD_UNRECOGNIZED
:
4403 /* should NEVER happen! */
4404 log_error("Unknown command variant: %d.", cmd
);
4408 /**************************************************************************
4409 End the game immediately in a draw.
4410 **************************************************************************/
4411 static bool end_command(struct connection
*caller
, char *str
, bool check
)
4413 if (S_S_RUNNING
== server_state()) {
4417 notify_conn(game
.est_connections
, NULL
, E_GAME_END
, ftc_server
,
4418 _("Game is over."));
4419 set_server_state(S_S_OVER
);
4420 force_end_of_sniff
= TRUE
;
4421 cmd_reply(CMD_END_GAME
, caller
, C_OK
,
4422 _("Ending the game. The server will restart once all clients "
4423 "have disconnected."));
4426 cmd_reply(CMD_END_GAME
, caller
, C_FAIL
,
4427 _("Cannot end the game: no game running."));
4432 /**************************************************************************
4433 Concede the game. You still continue playing until all but one player
4434 or team remains un-conceded.
4435 **************************************************************************/
4436 static bool surrender_command(struct connection
*caller
, char *str
, bool check
)
4438 struct player
*pplayer
;
4440 if (caller
== NULL
|| !conn_controls_player(caller
)) {
4441 cmd_reply(CMD_SURRENDER
, caller
, C_FAIL
,
4442 _("You are not allowed to use this command."));
4446 if (S_S_RUNNING
!= server_state()) {
4447 cmd_reply(CMD_SURRENDER
, caller
, C_FAIL
, _("You cannot surrender now."));
4451 pplayer
= conn_get_player(caller
);
4452 if (player_status_check(pplayer
, PSTATUS_SURRENDER
)) {
4453 cmd_reply(CMD_SURRENDER
, caller
, C_FAIL
,
4454 _("You have already conceded the game."));
4462 notify_conn(game
.est_connections
, NULL
, E_GAME_END
, ftc_server
,
4463 _("%s has conceded the game and can no longer win."),
4464 player_name(pplayer
));
4465 player_status_add(pplayer
, PSTATUS_SURRENDER
);
4469 /* Define the possible arguments to the reset command */
4470 #define SPECENUM_NAME reset_args
4471 #define SPECENUM_VALUE0 RESET_GAME
4472 #define SPECENUM_VALUE0NAME "game"
4473 #define SPECENUM_VALUE1 RESET_RULESET
4474 #define SPECENUM_VALUE1NAME "ruleset"
4475 #define SPECENUM_VALUE2 RESET_SCRIPT
4476 #define SPECENUM_VALUE2NAME "script"
4477 #define SPECENUM_VALUE3 RESET_DEFAULT
4478 #define SPECENUM_VALUE3NAME "default"
4479 #include "specenum_gen.h"
4481 /**************************************************************************
4482 Returns possible parameters for the reset command.
4483 **************************************************************************/
4484 static const char *reset_accessor(int i
)
4486 i
= CLIP(0, i
, reset_args_max());
4487 return reset_args_name((enum reset_args
) i
);
4490 /**************************************************************************
4491 Reload the game settings from the ruleset and reload the init script if
4493 **************************************************************************/
4494 static bool reset_command(struct connection
*caller
, char *arg
, bool check
,
4497 enum m_pre_result result
;
4500 /* match the argument */
4501 result
= match_prefix(reset_accessor
, reset_args_max() + 1, 0,
4502 fc_strncasecmp
, NULL
, arg
, &ind
);
4507 /* we have a match */
4509 case M_PRE_AMBIGUOUS
:
4511 /* use 'ruleset' [1] if the game was not started; else use 'game' [2] */
4512 if (S_S_INITIAL
== server_state() && game
.info
.is_new_game
) {
4513 cmd_reply(CMD_RESET
, caller
, C_WARNING
,
4514 _("Guessing argument 'ruleset'."));
4515 ind
= RESET_RULESET
;
4517 cmd_reply(CMD_RESET
, caller
, C_WARNING
,
4518 _("Guessing argument 'game'."));
4525 cmd_reply(CMD_RESET
, caller
, C_FAIL
,
4526 _("The valid arguments are: 'game', 'ruleset', 'script' "
4538 if (!game
.info
.is_new_game
) {
4539 if (settings_game_reset()) {
4540 cmd_reply(CMD_RESET
, caller
, C_OK
,
4541 _("Reset all settings to the values at the game start."));
4543 cmd_reply(CMD_RESET
, caller
, C_FAIL
,
4544 _("No saved settings from the game start available."));
4548 cmd_reply(CMD_RESET
, caller
, C_FAIL
, _("No game started..."));
4554 /* Restore game settings save in game.ruleset. */
4555 if (reload_rulesets_settings()) {
4556 cmd_reply(CMD_RESET
, caller
, C_OK
,
4557 _("Reset all settings to ruleset values."));
4559 cmd_reply(CMD_RESET
, caller
, C_FAIL
,
4560 _("Failed to reset settings to ruleset values."));
4565 cmd_reply(CMD_RESET
, caller
, C_OK
,
4566 _("Reset all settings and rereading the server start "
4569 /* load initial script */
4570 if (NULL
!= srvarg
.script_filename
4571 && !read_init_script_real(NULL
, srvarg
.script_filename
, TRUE
, FALSE
,
4572 read_recursion
+ 1)) {
4573 if (NULL
!= caller
) {
4574 cmd_reply(CMD_RESET
, caller
, C_FAIL
,
4575 _("Could not read script file '%s'."),
4576 srvarg
.script_filename
);
4583 cmd_reply(CMD_RESET
, caller
, C_OK
,
4584 _("Reset all settings to default values."));
4589 send_server_settings(game
.est_connections
);
4590 cmd_reply(CMD_RESET
, caller
, C_OK
, _("Settings re-initialized."));
4592 /* show ruleset summary and list changed values */
4593 show_ruleset_info(caller
, CMD_RESET
, check
, read_recursion
);
4598 /**************************************************************************
4599 Set a setting to its default value
4600 **************************************************************************/
4601 static bool default_command(struct connection
*caller
, char *arg
, bool check
)
4603 struct setting
*pset
;
4604 char reject_msg
[256] = "";
4606 pset
= validate_setting_arg(CMD_DEFAULT
, caller
, arg
);
4609 /* Reason already reported. */
4613 if (!setting_is_changeable(pset
, caller
, reject_msg
, sizeof(reject_msg
))) {
4614 cmd_reply(CMD_DEFAULT
, caller
, C_FAIL
, "%s", reject_msg
);
4620 setting_set_to_default(pset
);
4621 cmd_reply(CMD_DEFAULT
, caller
, C_OK
,
4622 _("Option '%s' reset to default value."), arg
);
4628 /* Define the possible arguments to the delegation command */
4629 #define SPECENUM_NAME lua_args
4630 #define SPECENUM_VALUE0 LUA_CMD
4631 #define SPECENUM_VALUE0NAME "cmd"
4632 #define SPECENUM_VALUE1 LUA_FILE
4633 #define SPECENUM_VALUE1NAME "file"
4634 #include "specenum_gen.h"
4636 /*****************************************************************************
4637 Returns possible parameters for the reset command.
4638 *****************************************************************************/
4639 static const char *lua_accessor(int i
)
4641 i
= CLIP(0, i
, lua_args_max());
4642 return lua_args_name((enum lua_args
) i
);
4645 /*****************************************************************************
4646 Evaluate a line of lua script or a lua script file.
4647 *****************************************************************************/
4648 static bool lua_command(struct connection
*caller
, char *arg
, bool check
)
4651 const char extension
[] = ".lua", *real_filename
= NULL
;
4652 char luafile
[4096], tilde_filename
[4096];
4653 char *tokens
[1], *luaarg
= NULL
;
4655 enum m_pre_result result
;
4658 ntokens
= get_tokens(arg
, tokens
, 1, TOKEN_DELIMITERS
);
4661 /* match the argument */
4662 result
= match_prefix(lua_accessor
, lua_args_max() + 1, 0,
4663 fc_strncasecmp
, NULL
, tokens
[0], &ind
);
4668 /* We have a match */
4669 luaarg
= arg
+ strlen(lua_args_name(ind
));
4670 luaarg
= skip_leading_spaces(luaarg
);
4675 case M_PRE_AMBIGUOUS
:
4679 /* Fall back to depreciated 'lua <script command>' syntax. */
4680 cmd_reply(CMD_LUA
, caller
, C_SYNTAX
,
4681 _("Fall back to old syntax '%slua <script command>'."),
4689 if (luaarg
== NULL
) {
4690 cmd_reply(CMD_LUA
, caller
, C_FAIL
,
4691 _("No lua command or lua script file. See '%shelp lua'."),
4699 /* Nothing to check. */
4702 /* Abuse real_filename to find if we already have a .lua extension. */
4703 real_filename
= luaarg
+ strlen(luaarg
) - MIN(strlen(extension
),
4705 if (strcmp(real_filename
, extension
) != 0) {
4706 fc_snprintf(luafile
, sizeof(luafile
), "%s%s", luaarg
, extension
);
4708 sz_strlcpy(luafile
, luaarg
);
4711 if (is_restricted(caller
)) {
4712 if (!is_safe_filename(luafile
)) {
4713 cmd_reply(CMD_LUA
, caller
, C_FAIL
,
4714 _("Freeciv script '%s' disallowed for security reasons."),
4719 sz_strlcpy(tilde_filename
, luafile
);
4721 interpret_tilde(tilde_filename
, sizeof(tilde_filename
), luafile
);
4724 real_filename
= fileinfoname(get_data_dirs(), tilde_filename
);
4725 if (!real_filename
) {
4726 if (is_restricted(caller
)) {
4727 cmd_reply(CMD_LUA
, caller
, C_FAIL
,
4728 _("No Freeciv script found by the name '%s'."),
4733 /* File is outside data directories */
4734 real_filename
= tilde_filename
;
4746 ret
= script_server_do_string(caller
, luaarg
);
4749 cmd_reply(CMD_LUA
, caller
, C_COMMENT
,
4750 _("Loading Freeciv script file '%s'."), real_filename
);
4752 if (is_reg_file_for_access(real_filename
, FALSE
)
4753 && (script_file
= fc_fopen(real_filename
, "r"))) {
4754 ret
= script_server_do_file(caller
, real_filename
);
4757 cmd_reply(CMD_LUA
, caller
, C_FAIL
,
4758 _("Cannot read Freeciv script '%s'."), real_filename
);
4765 free_tokens(tokens
, ntokens
);
4769 /* Define the possible arguments to the delegation command */
4770 #define SPECENUM_NAME delegate_args
4771 #define SPECENUM_VALUE0 DELEGATE_CANCEL
4772 #define SPECENUM_VALUE0NAME "cancel"
4773 #define SPECENUM_VALUE1 DELEGATE_RESTORE
4774 #define SPECENUM_VALUE1NAME "restore"
4775 #define SPECENUM_VALUE2 DELEGATE_SHOW
4776 #define SPECENUM_VALUE2NAME "show"
4777 #define SPECENUM_VALUE3 DELEGATE_TAKE
4778 #define SPECENUM_VALUE3NAME "take"
4779 #define SPECENUM_VALUE4 DELEGATE_TO
4780 #define SPECENUM_VALUE4NAME "to"
4781 #include "specenum_gen.h"
4783 /*****************************************************************************
4784 Returns possible parameters for the 'delegate' command.
4785 *****************************************************************************/
4786 static const char *delegate_accessor(int i
)
4788 i
= CLIP(0, i
, delegate_args_max());
4789 return delegate_args_name((enum delegate_args
) i
);
4792 /*****************************************************************************
4793 Handle delegation of control.
4794 *****************************************************************************/
4795 static bool delegate_command(struct connection
*caller
, char *arg
,
4799 int ntokens
, ind
= delegate_args_invalid();
4800 enum m_pre_result result
;
4801 bool player_specified
= FALSE
; /* affects messages only */
4803 const char *username
= NULL
;
4804 struct player
*dplayer
= NULL
;
4806 if (!game_was_started()) {
4807 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("Game not started - "
4808 "cannot delegate yet."));
4812 ntokens
= get_tokens(arg
, tokens
, 3, TOKEN_DELIMITERS
);
4815 /* match the argument */
4816 result
= match_prefix(delegate_accessor
, delegate_args_max() + 1, 0,
4817 fc_strncasecmp
, NULL
, tokens
[0], &ind
);
4822 /* we have a match */
4826 /* Use 'delegate show' as default. */
4827 ind
= DELEGATE_SHOW
;
4830 case M_PRE_AMBIGUOUS
:
4834 ind
= delegate_args_invalid();
4839 /* Use 'delegate show' as default. */
4840 ind
= DELEGATE_SHOW
;
4844 if (!delegate_args_is_valid(ind
)) {
4846 enum delegate_args valid_args
;
4848 for (valid_args
= delegate_args_begin();
4849 valid_args
!= delegate_args_end();
4850 valid_args
= delegate_args_next(valid_args
)) {
4851 cat_snprintf(buf
, sizeof(buf
), "'%s'",
4852 delegate_args_name(valid_args
));
4853 if (valid_args
!= delegate_args_max()) {
4854 cat_snprintf(buf
, sizeof(buf
), ", ");
4858 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4859 /* TRANS: do not translate the command 'delegate'. */
4860 _("Valid arguments for 'delegate' are: %s."), buf
);
4865 /* Get the data (player, username for delegation) and validate it. */
4867 case DELEGATE_CANCEL
:
4868 /* delegate cancel [player] */
4870 if (!caller
|| conn_get_access(caller
) >= ALLOW_ADMIN
) {
4871 player_specified
= TRUE
;
4872 dplayer
= player_by_name_prefix(tokens
[1], &result
);
4874 cmd_reply_no_such_player(CMD_DELEGATE
, caller
, tokens
[1], result
);
4879 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4880 _("Command level '%s' or greater needed to modify "
4881 "others' delegations."), cmdlevel_name(ALLOW_ADMIN
));
4886 dplayer
= conn_get_player(caller
);
4888 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4889 _("Please specify a player for whom delegation should "
4896 case DELEGATE_RESTORE
:
4897 /* delegate restore */
4899 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4900 _("You can't switch players from the console."));
4906 /* delegate show [player] */
4908 player_specified
= TRUE
;
4909 dplayer
= player_by_name_prefix(tokens
[1], &result
);
4911 cmd_reply_no_such_player(CMD_DELEGATE
, caller
, tokens
[1], result
);
4916 dplayer
= conn_get_player(caller
);
4918 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4919 _("Please specify a player for whom the delegation should "
4927 /* delegate take <player> */
4929 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4930 _("You can't switch players from the console."));
4935 player_specified
= TRUE
;
4936 dplayer
= player_by_name_prefix(tokens
[1], &result
);
4938 cmd_reply_no_such_player(CMD_DELEGATE
, caller
, tokens
[1], result
);
4943 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4944 _("Please specify a player to take control of."));
4950 /* delegate to <username> [player] */
4952 username
= tokens
[1];
4954 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4955 _("Please specify a user to whom control is to be delegated."));
4960 if (!caller
|| conn_get_access(caller
) >= ALLOW_ADMIN
) {
4961 player_specified
= TRUE
;
4962 dplayer
= player_by_name_prefix(tokens
[2], &result
);
4964 cmd_reply_no_such_player(CMD_DELEGATE
, caller
, tokens
[2], result
);
4969 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4970 _("Command level '%s' or greater needed to modify "
4971 "others' delegations."), cmdlevel_name(ALLOW_ADMIN
));
4976 dplayer
= conn_controls_player(caller
) ? conn_get_player(caller
) : NULL
;
4978 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4979 _("You do not control a player."));
4987 /* All checks done to this point will give pretty much the same result at
4988 * any time. Checks after this point are more likely to vary over time. */
4996 /* Delegate control of player to another user. */
4997 fc_assert_ret_val(dplayer
, FALSE
);
4998 fc_assert_ret_val(username
!= NULL
, FALSE
);
5000 /* Forbid delegation of players already controlled by a delegate, and
5001 * those 'put aside' by a delegate.
5002 * For the former, if player is already under active delegate control,
5003 * we wouldn't handle the revocation that would be necessary if their
5004 * delegation changed; and the authority granted to delegates does not
5005 * include the ability to sub-delegate.
5006 * For the latter, allowing control of the 'put aside' player to be
5007 * delegated would break the invariant that whenever a user is connected,
5008 * they are attached to 'their' player. */
5009 if (player_delegation_active(dplayer
)) {
5010 if (!player_delegation_get(dplayer
)) {
5011 /* Attempting to change a 'put aside' player. Must be admin
5013 fc_assert(player_specified
);
5014 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5015 _("Can't delegate control of '%s' belonging to %s while "
5016 "they are controlling another player."),
5017 player_name(dplayer
), dplayer
->username
);
5018 } else if (player_specified
) {
5019 /* Admin or console attempting to change a controlled player. */
5020 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5021 _("Can't change delegation of '%s' while controlled by "
5022 "delegate %s."), player_name(dplayer
), dplayer
->username
);
5024 /* Caller must be the delegate. Give more specific message.
5025 * (We don't know if they thought they were delegating their
5026 * original or delegated player, but we don't allow either.) */
5027 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5028 _("You can't delegate control while you are controlling "
5029 "a delegated player yourself."));
5035 /* Forbid delegation to player's original owner
5036 * (from above test we know that dplayer->username is the original now) */
5037 if (fc_strcasecmp(dplayer
->username
, username
) == 0) {
5038 if (player_specified
) {
5039 /* Probably admin or console. */
5040 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5041 /* TRANS: don't translate 'delegate cancel' */
5042 _("%s already owns '%s', so cannot also be delegate. "
5043 "Use '%sdelegate cancel' to cancel an existing "
5045 username
, player_name(dplayer
), caller
?"/":"");
5047 /* Player not specified on command line, so they must have been trying
5048 * to delegate control to themself. Give more specific message. */
5049 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5050 /* TRANS: don't translate '/delegate cancel' */
5051 _("You can't delegate control to yourself. "
5052 "Use '/delegate cancel' to cancel an existing "
5059 /* FIXME: if control was already delegated to someone else, that
5060 * delegation is implicitly canceled. Perhaps we should tell someone. */
5062 player_delegation_set(dplayer
, username
);
5063 cmd_reply(CMD_DELEGATE
, caller
, C_OK
,
5064 _("Control of player '%s' delegated to user %s."),
5065 player_name(dplayer
), username
);
5071 /* Show delegations. */
5072 fc_assert_ret_val(dplayer
, FALSE
);
5074 if (player_delegation_get(dplayer
) == NULL
) {
5075 /* No delegation set. */
5076 cmd_reply(CMD_DELEGATE
, caller
, C_COMMENT
,
5077 _("No delegation defined for '%s'."),
5078 player_name(dplayer
));
5080 cmd_reply(CMD_DELEGATE
, caller
, C_COMMENT
,
5081 _("Control of player '%s' delegated to user %s."),
5082 player_name(dplayer
), player_delegation_get(dplayer
));
5088 case DELEGATE_CANCEL
:
5089 if (player_delegation_get(dplayer
) == NULL
) {
5090 /* No delegation set. */
5091 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5092 _("No delegation defined for '%s'."),
5093 player_name(dplayer
));
5098 if (player_delegation_active(dplayer
)) {
5099 /* Delegation is currently in use. Forcibly break connection. */
5100 struct connection
*pdelegate
;
5101 /* (Can only happen if admin/console issues this command, as owner
5102 * will end use by their mere presence.) */
5103 fc_assert(player_specified
);
5104 pdelegate
= conn_by_user(player_delegation_get(dplayer
));
5105 fc_assert_ret_val(pdelegate
!= NULL
, FALSE
);
5106 if (!connection_delegate_restore(pdelegate
)) {
5107 /* Should never happen. Generic failure message. */
5108 log_error("Failed to restore %s's connection as %s during "
5109 "'delegate cancel'.", pdelegate
->username
,
5110 delegate_player_str(pdelegate
->server
.delegation
.playing
,
5111 pdelegate
->server
.delegation
.observer
));
5112 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("Unexpected failure."));
5116 notify_conn(pdelegate
->self
, NULL
, E_CONNECTION
, ftc_server
,
5117 _("Your delegated control of player '%s' was canceled."),
5118 player_name(dplayer
));
5121 player_delegation_set(dplayer
, NULL
);
5122 cmd_reply(CMD_DELEGATE
, caller
, C_OK
, _("Delegation of '%s' canceled."),
5123 player_name(dplayer
));
5129 /* Try to take another player. */
5130 fc_assert_ret_val(dplayer
, FALSE
);
5131 fc_assert_ret_val(caller
, FALSE
);
5133 if (caller
->server
.delegation
.status
) {
5134 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5135 /* TRANS: don't translate '/delegate restore'. */
5136 _("You are already controlling a delegated player. "
5137 "Use '/delegate restore' to relinquish control of your "
5138 "current player first."));
5143 /* Don't allow 'put aside' players to be delegated; the invariant is
5144 * that while the owning user is connected to the server, they are
5145 * in sole control of 'their' player. */
5146 if (conn_controls_player(caller
)
5147 && player_delegation_get(conn_get_player(caller
)) != NULL
) {
5148 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5149 /* TRANS: don't translate '/delegate cancel'. */
5150 _("Can't take player while you have delegated control "
5151 "yourself. Use '/delegate cancel' to cancel your own "
5152 "delegation first."));
5157 /* Taking your own player makes no sense. */
5158 if (conn_controls_player(caller
)
5159 && dplayer
== conn_get_player(caller
)) {
5160 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("You already control '%s'."),
5161 player_name(conn_get_player(caller
)));
5166 if (!player_delegation_get(dplayer
)
5167 || fc_strcasecmp(player_delegation_get(dplayer
), caller
->username
) != 0) {
5168 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5169 _("Control of player '%s' has not been delegated to you."),
5170 player_name(dplayer
));
5175 /* If the player is controlled by another user, fail. */
5176 if (dplayer
->is_connected
) {
5177 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5178 _("Another user already controls player '%s'."),
5179 player_name(dplayer
));
5184 if (!connection_delegate_take(caller
, dplayer
)) {
5185 /* Should never happen. Generic failure message. */
5186 log_error("%s failed to take control of '%s' during 'delegate take'.",
5187 caller
->username
, player_name(dplayer
));
5188 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("Unexpected failure."));
5193 cmd_reply(CMD_DELEGATE
, caller
, C_OK
,
5194 _("%s is now controlling player '%s'."), caller
->username
,
5195 player_name(conn_get_player(caller
)));
5200 case DELEGATE_RESTORE
:
5201 /* Delegate user relinquishes control of delegated player, returning to
5202 * previous view (e.g. observer) if any. */
5203 fc_assert_ret_val(caller
, FALSE
);
5205 if (!caller
->server
.delegation
.status
) {
5206 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5207 _("You are not currently controlling a delegated player."));
5212 if (!connection_delegate_restore(caller
)) {
5213 /* Should never happen. Generic failure message. */
5214 log_error("Failed to restore %s's connection as %s during "
5215 "'delegate restore'.", caller
->username
,
5216 delegate_player_str(caller
->server
.delegation
.playing
,
5217 caller
->server
.delegation
.observer
));
5218 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("Unexpected failure."));
5223 cmd_reply(CMD_DELEGATE
, caller
, C_OK
,
5224 /* TRANS: "<user> is now connected to <player>" where <player>
5225 * can also be "global observer" or "nothing" */
5226 _("%s is now connected as %s."), caller
->username
,
5227 delegate_player_str(conn_get_player(caller
), caller
->observer
));
5234 free_tokens(tokens
, ntokens
);
5238 /*****************************************************************************
5239 Return static string describing what a connection is connected to.
5240 *****************************************************************************/
5241 static const char *delegate_player_str(struct player
*pplayer
, bool observer
)
5243 static struct astring buf
;
5247 astr_set(&buf
, _("%s (observer)"), player_name(pplayer
));
5249 astr_set(&buf
, "%s", player_name(pplayer
));
5251 } else if (observer
) {
5252 astr_set(&buf
, "%s", _("global observer"));
5254 /* TRANS: in place of player name or "global observer" */
5255 astr_set(&buf
, "%s", _("nothing"));
5258 return astr_str(&buf
);
5261 /* Define the possible arguments to the mapimg command */
5262 /* map image layers */
5263 #define SPECENUM_NAME mapimg_args
5264 #define SPECENUM_VALUE0 MAPIMG_COLORTEST
5265 #define SPECENUM_VALUE0NAME "colortest"
5266 #define SPECENUM_VALUE1 MAPIMG_CREATE
5267 #define SPECENUM_VALUE1NAME "create"
5268 #define SPECENUM_VALUE2 MAPIMG_DEFINE
5269 #define SPECENUM_VALUE2NAME "define"
5270 #define SPECENUM_VALUE3 MAPIMG_DELETE
5271 #define SPECENUM_VALUE3NAME "delete"
5272 #define SPECENUM_VALUE4 MAPIMG_SHOW
5273 #define SPECENUM_VALUE4NAME "show"
5274 #define SPECENUM_COUNT MAPIMG_COUNT
5275 #include "specenum_gen.h"
5277 /**************************************************************************
5278 Returns possible parameters for the mapimg command.
5279 **************************************************************************/
5280 static const char *mapimg_accessor(int i
)
5282 i
= CLIP(0, i
, mapimg_args_max());
5283 return mapimg_args_name((enum mapimg_args
) i
);
5286 /**************************************************************************
5287 Handle mapimg command
5288 **************************************************************************/
5289 static bool mapimg_command(struct connection
*caller
, char *arg
, bool check
)
5291 enum m_pre_result result
;
5292 int ind
, ntokens
, id
;
5296 ntokens
= get_tokens(arg
, token
, 2, TOKEN_DELIMITERS
);
5299 /* match the argument */
5300 result
= match_prefix(mapimg_accessor
, MAPIMG_COUNT
, 0,
5301 fc_strncasecmp
, NULL
, token
[0], &ind
);
5306 /* we have a match */
5308 case M_PRE_AMBIGUOUS
:
5309 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5310 _("Ambiguous 'mapimg' command."));
5315 /* use 'show' as default */
5323 enum mapimg_args valid_args
;
5325 for (valid_args
= mapimg_args_begin();
5326 valid_args
!= mapimg_args_end();
5327 valid_args
= mapimg_args_next(valid_args
)) {
5328 cat_snprintf(buf
, sizeof(buf
), "'%s'",
5329 mapimg_args_name(valid_args
));
5330 if (valid_args
!= mapimg_args_max()) {
5331 cat_snprintf(buf
, sizeof(buf
), ", ");
5335 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5336 _("The valid arguments are: %s."), buf
);
5343 /* use 'show' as default */
5350 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5351 _("Missing argument for 'mapimg define'."));
5354 /* 'mapimg define <mapstr>' */
5355 if (!mapimg_define(token
[1], check
)) {
5356 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5357 _("Can't use definition: %s."), mapimg_error());
5360 /* Validated OK, bail out now */
5362 } else if (game_was_started()
5363 && mapimg_isvalid(mapimg_count() - 1) == NULL
) {
5364 /* game was started - error in map image definition check */
5365 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5366 _("Can't use definition: %s."), mapimg_error());
5369 char str
[MAX_LEN_MAPDEF
];
5371 id
= mapimg_count() - 1;
5373 mapimg_id2str(id
, str
, sizeof(str
));
5374 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, _("Defined as map image "
5375 "definition %d: '%s'."),
5383 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5384 _("Missing argument for 'mapimg delete'."));
5386 } else if (ntokens
== 2 && strcmp(token
[1], "all") == 0) {
5387 /* 'mapimg delete all' */
5392 while (mapimg_count() > 0) {
5395 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, _("All map image definitions "
5397 } else if (ntokens
== 2 && sscanf(token
[1], "%d", &id
) != 0) {
5398 /* 'mapimg delete <id>' */
5403 if (!mapimg_delete(id
)) {
5404 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5405 _("Couldn't delete definition: %s."), mapimg_error());
5408 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, _("Map image definition %d "
5412 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5413 _("Bad argument for 'mapimg delete': '%s'."), token
[1]);
5419 if (ntokens
< 2 || (ntokens
== 2 && strcmp(token
[1], "all") == 0)) {
5420 /* 'mapimg show' or 'mapimg show all' */
5424 show_mapimg(caller
, CMD_MAPIMG
);
5425 } else if (ntokens
== 2 && sscanf(token
[1], "%d", &id
) != 0) {
5427 /* 'mapimg show <id>' */
5432 if (mapimg_show(id
, str
, sizeof(str
), TRUE
)) {
5433 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, "%s", str
);
5435 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5436 _("Couldn't show definition: %s."), mapimg_error());
5440 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5441 _("Bad argument for 'mapimg show': '%s'."), token
[1]);
5446 case MAPIMG_COLORTEST
:
5451 mapimg_colortest(game
.server
.save_name
, NULL
);
5452 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, _("Map color test images saved."));
5457 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5458 _("Missing argument for 'mapimg create'."));
5463 if (strcmp(token
[1], "all") == 0) {
5464 /* 'mapimg create all' */
5469 for (id
= 0; id
< mapimg_count(); id
++) {
5470 struct mapdef
*pmapdef
= mapimg_isvalid(id
);
5473 || !mapimg_create(pmapdef
, TRUE
, game
.server
.save_name
,
5474 srvarg
.saves_pathname
)) {
5475 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5476 _("Error saving map image %d: %s."), id
, mapimg_error());
5480 } else if (sscanf(token
[1], "%d", &id
) != 0) {
5481 struct mapdef
*pmapdef
;
5483 /* 'mapimg create <id>' */
5488 pmapdef
= mapimg_isvalid(id
);
5490 || !mapimg_create(pmapdef
, TRUE
, game
.server
.save_name
,
5491 srvarg
.saves_pathname
)) {
5492 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5493 _("Error saving map image %d: %s."), id
, mapimg_error());
5497 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5498 _("Bad argument for 'mapimg create': '%s'."), token
[1]);
5506 free_tokens(token
, ntokens
);
5511 /* Define the possible arguments to the fcdb command */
5512 #define SPECENUM_NAME fcdb_args
5513 #define SPECENUM_VALUE0 FCDB_RELOAD
5514 #define SPECENUM_VALUE0NAME "reload"
5515 #define SPECENUM_VALUE1 FCDB_LUA
5516 #define SPECENUM_VALUE1NAME "lua"
5517 #define SPECENUM_COUNT FCDB_COUNT
5518 #include "specenum_gen.h"
5520 /**************************************************************************
5521 Returns possible parameters for the fcdb command.
5522 **************************************************************************/
5523 static const char *fcdb_accessor(int i
)
5525 i
= CLIP(0, i
, fcdb_args_max());
5526 return fcdb_args_name((enum fcdb_args
) i
);
5529 /**************************************************************************
5530 Handle the freeciv database script module.
5531 **************************************************************************/
5532 static bool fcdb_command(struct connection
*caller
, char *arg
, bool check
)
5534 enum m_pre_result result
;
5541 cmd_reply(CMD_FCDB
, caller
, C_FAIL
,
5542 _("Freeciv database script deactivated at compile time."));
5546 ntokens
= get_tokens(arg
, token
, 1, TOKEN_DELIMITERS
);
5549 /* match the argument */
5550 result
= match_prefix(fcdb_accessor
, FCDB_COUNT
, 0,
5551 fc_strncasecmp
, NULL
, token
[0], &ind
);
5556 /* we have a match */
5558 case M_PRE_AMBIGUOUS
:
5559 cmd_reply(CMD_FCDB
, caller
, C_FAIL
,
5560 _("Ambiguous fcdb command."));
5577 enum fcdb_args valid_args
;
5579 for (valid_args
= fcdb_args_begin();
5580 valid_args
!= fcdb_args_end();
5581 valid_args
= fcdb_args_next(valid_args
)) {
5582 cat_snprintf(buf
, sizeof(buf
), "'%s'",
5583 fcdb_args_name(valid_args
));
5584 if (valid_args
!= fcdb_args_max()) {
5585 cat_snprintf(buf
, sizeof(buf
), ", ");
5589 cmd_reply(CMD_FCDB
, caller
, C_FAIL
,
5590 _("The valid arguments are: %s."), buf
);
5602 /* Reload database lua script. */
5604 script_fcdb_init(NULL
);
5608 /* Skip whitespaces. */
5609 arg
= skip_leading_spaces(arg
);
5610 /* Skip the base argument 'lua'. */
5612 /* Now execute the scriptlet. */
5613 ret
= script_fcdb_do_string(caller
, arg
);
5619 free_tokens(token
, ntokens
);
5624 /**************************************************************************
5625 Send start command related message
5626 **************************************************************************/
5627 static void start_cmd_reply(struct connection
*caller
, bool notify
, char *msg
)
5629 cmd_reply(CMD_START_GAME
, caller
, C_FAIL
, "%s", msg
);
5631 notify_conn(NULL
, NULL
, E_SETTING
, ftc_server
, "%s", msg
);
5635 /**************************************************************************
5636 Handle start command. Notify all players about errors if notify set.
5637 **************************************************************************/
5638 bool start_command(struct connection
*caller
, bool check
, bool notify
)
5642 switch (server_state()) {
5644 /* Sanity check scenario */
5645 if (game
.info
.is_new_game
&& !check
) {
5646 if (0 < map_startpos_count()
5647 && game
.server
.max_players
> map_startpos_count()) {
5648 /* If we load a pre-generated map (i.e., a scenario) it is possible
5649 * to increase the number of players beyond the number supported by
5650 * the scenario. The solution is a hack: cut the extra players
5651 * when the game starts. */
5652 log_verbose("Reduced maxplayers from %d to %d to fit "
5653 "to the number of start positions.",
5654 game
.server
.max_players
, map_startpos_count());
5655 game
.server
.max_players
= map_startpos_count();
5658 if (normal_player_count() > game
.server
.max_players
) {
5660 struct player
*pplayer
;
5662 for (i
= player_slot_count() - 1; i
>= 0; i
--) {
5663 pplayer
= player_by_number(i
);
5665 server_remove_player(pplayer
);
5667 if (normal_player_count() <= game
.server
.max_players
) {
5672 log_verbose("Had to cut down the number of players to the "
5673 "number of map start positions, there must be "
5674 "something wrong with the savegame or you "
5675 "adjusted the maxplayers value.");
5680 players_iterate(plr
) {
5681 if (!plr
->ai_controlled
) {
5684 } players_iterate_end
;
5686 /* check min_players.
5687 * Allow continuing of savegames where some of the original
5688 * players have died */
5689 if (game
.info
.is_new_game
5690 && human_players
< game
.server
.min_players
) {
5693 fc_snprintf(buf
, sizeof(buf
),
5694 _("Not enough human players ('minplayers' server setting has value %d); game will not start."),
5695 game
.server
.min_players
);
5696 start_cmd_reply(caller
, notify
, buf
);
5698 } else if (player_count() < 1) {
5699 /* At least one player required */
5700 start_cmd_reply(caller
, notify
,
5701 _("No players; game will not start."));
5703 } else if (normal_player_count() > server
.playable_nations
) {
5704 if (nation_set_count() > 1) {
5705 start_cmd_reply(caller
, notify
,
5706 _("Not enough nations in the current nation set "
5707 "for all players; game will not start. "
5708 "(See 'nationset' setting.)"));
5710 start_cmd_reply(caller
, notify
,
5711 _("Not enough nations for all players; game will "
5715 } else if (strlen(game
.server
.start_units
) == 0 && !game
.server
.start_city
) {
5716 start_cmd_reply(caller
, notify
,
5717 _("Neither 'startcity' nor 'startunits' setting gives "
5718 "players anything to start game with; game will "
5723 } else if (!caller
) {
5725 /* Called from handle_player_ready()
5726 * Last player just toggled ready-status. */
5727 notify_conn(NULL
, NULL
, E_SETTING
, ftc_game_start
,
5728 _("All players are ready; starting game."));
5732 } else if (NULL
== caller
->playing
|| caller
->observer
) {
5733 /* A detached or observer player can't do /start. */
5736 /* This might trigger recursive call to start_command() if this is
5737 * last player who gets ready. In that case caller is NULL. */
5738 handle_player_ready(caller
->playing
, player_number(caller
->playing
), TRUE
);
5742 start_cmd_reply(caller
, notify
,
5743 /* TRANS: given when /start is invoked during gameover. */
5744 _("Cannot start the game: the game is waiting for all clients "
5748 start_cmd_reply(caller
, notify
,
5749 /* TRANS: given when /start is invoked while the game
5751 _("Cannot start the game: it is already running."));
5754 log_error("Unknown server state variant: %d.", server_state());
5758 /**************************************************************************
5760 **************************************************************************/
5761 static bool cut_client_connection(struct connection
*caller
, char *name
,
5764 enum m_pre_result match_result
;
5765 struct connection
*ptarget
;
5767 ptarget
= conn_by_user_prefix(name
, &match_result
);
5770 cmd_reply_no_such_conn(CMD_CUT
, caller
, name
, match_result
);
5776 if (conn_controls_player(ptarget
)) {
5777 /* If we cut the connection, unassign the login name.*/
5778 sz_strlcpy(ptarget
->playing
->username
, _(ANON_USER_NAME
));
5779 ptarget
->playing
->unassigned_user
= TRUE
;
5782 cmd_reply(CMD_CUT
, caller
, C_DISCONNECTED
,
5783 _("Cutting connection %s."), ptarget
->username
);
5784 connection_close_server(ptarget
, _("connection cut"));
5790 /****************************************************************************
5791 Utility for 'kick_hash' tables.
5792 ****************************************************************************/
5793 static time_t *time_duplicate(const time_t *t
)
5795 time_t *d
= fc_malloc(sizeof(*d
));
5800 /****************************************************************************
5801 Returns FALSE if the connection isn't kicked and can connect the server
5803 ****************************************************************************/
5804 bool conn_is_kicked(struct connection
*pconn
, int *time_remaining
)
5806 time_t time_of_addr_kick
, time_of_user_kick
;
5807 time_t now
, time_of_kick
= 0;
5809 if (NULL
!= time_remaining
) {
5810 *time_remaining
= 0;
5813 fc_assert_ret_val(NULL
!= kick_table_by_addr
, FALSE
);
5814 fc_assert_ret_val(NULL
!= kick_table_by_user
, FALSE
);
5815 fc_assert_ret_val(NULL
!= pconn
, FALSE
);
5817 if (kick_hash_lookup(kick_table_by_addr
, pconn
->server
.ipaddr
,
5818 &time_of_addr_kick
)) {
5819 time_of_kick
= time_of_addr_kick
;
5821 if (kick_hash_lookup(kick_table_by_user
, pconn
->username
,
5823 && time_of_user_kick
> time_of_kick
) {
5824 time_of_kick
= time_of_user_kick
;
5827 if (0 == time_of_kick
) {
5828 return FALSE
; /* Not found. */
5832 if (now
- time_of_kick
> game
.server
.kick_time
) {
5833 /* Kick timeout expired. */
5834 if (0 != time_of_addr_kick
) {
5835 kick_hash_remove(kick_table_by_addr
, pconn
->server
.ipaddr
);
5837 if (0 != time_of_user_kick
) {
5838 kick_hash_remove(kick_table_by_user
, pconn
->username
);
5843 if (NULL
!= time_remaining
) {
5844 *time_remaining
= game
.server
.kick_time
- (now
- time_of_kick
);
5849 /****************************************************************************
5850 Kick command handler.
5851 ****************************************************************************/
5852 static bool kick_command(struct connection
*caller
, char *name
, bool check
)
5854 char ipaddr
[FC_MEMBER_SIZEOF(struct connection
, server
.ipaddr
)];
5855 struct connection
*pconn
;
5856 enum m_pre_result match_result
;
5859 remove_leading_trailing_spaces(name
);
5860 pconn
= conn_by_user_prefix(name
, &match_result
);
5861 if (NULL
== pconn
) {
5862 cmd_reply_no_such_conn(CMD_KICK
, caller
, name
, match_result
);
5866 if (NULL
!= caller
&& ALLOW_ADMIN
> conn_get_access(caller
)) {
5867 const int MIN_UNIQUE_CONNS
= 3;
5868 const char *unique_ipaddr
[MIN_UNIQUE_CONNS
];
5869 int i
, num_unique_connections
= 0;
5871 if (pconn
== caller
) {
5872 cmd_reply(CMD_KICK
, caller
, C_FAIL
, _("You may not kick yourself."));
5876 conn_list_iterate(game
.est_connections
, aconn
) {
5877 for (i
= 0; i
< num_unique_connections
; i
++) {
5878 if (0 == strcmp(unique_ipaddr
[i
], aconn
->server
.ipaddr
)) {
5879 /* Already listed. */
5883 if (i
>= num_unique_connections
) {
5884 num_unique_connections
++;
5885 if (MIN_UNIQUE_CONNS
<= num_unique_connections
) {
5886 /* We have enought already. */
5889 unique_ipaddr
[num_unique_connections
- 1] = aconn
->server
.ipaddr
;
5891 } conn_list_iterate_end
;
5893 if (MIN_UNIQUE_CONNS
> num_unique_connections
) {
5894 cmd_reply(CMD_KICK
, caller
, C_FAIL
,
5895 _("There must be at least %d unique connections to the "
5896 "server for this command to be valid."), MIN_UNIQUE_CONNS
);
5905 sz_strlcpy(ipaddr
, pconn
->server
.ipaddr
);
5907 kick_hash_replace(kick_table_by_addr
, ipaddr
, now
);
5909 conn_list_iterate(game
.all_connections
, aconn
) {
5910 if (0 != strcmp(ipaddr
, aconn
->server
.ipaddr
)) {
5914 if (conn_controls_player(aconn
)) {
5915 /* Unassign the username. */
5916 sz_strlcpy(aconn
->playing
->username
, _(ANON_USER_NAME
));
5917 aconn
->playing
->unassigned_user
= TRUE
;
5920 kick_hash_replace(kick_table_by_user
, aconn
->username
, now
);
5922 connection_close_server(aconn
, _("kicked"));
5923 } conn_list_iterate_end
;
5929 /**************************************************************************
5930 Show caller introductory help about the server. help_cmd is the command
5932 **************************************************************************/
5933 static void show_help_intro(struct connection
*caller
,
5934 enum command_id help_cmd
)
5936 /* This is formated like extra_help entries for settings and commands: */
5937 char *help
= fc_strdup(
5938 _("Welcome - this is the introductory help text for the Freeciv "
5941 "Two important server concepts are Commands and Options. Commands, "
5942 "such as 'help', are used to interact with the server. Some commands "
5943 "take one or more arguments, separated by spaces. In many cases "
5944 "commands and command arguments may be abbreviated. Options are "
5945 "settings which control the server as it is running.\n"
5947 "To find out how to get more information about commands and options, "
5948 "use 'help help'.\n"
5950 "For the impatient, the main commands to get going are:\n"
5951 " show - to see current options\n"
5952 " set - to set options\n"
5953 " start - to start the game once players have connected\n"
5954 " save - to save the current game\n"
5955 " quit - to exit"));
5957 fc_break_lines(help
, LINE_BREAK
);
5958 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", help
);
5962 /**************************************************************************
5963 Show the caller detailed help for the single COMMAND given by id.
5964 help_cmd is the command the player used.
5965 **************************************************************************/
5966 static void show_help_command(struct connection
*caller
,
5967 enum command_id help_cmd
,
5970 const struct command
*cmd
= command_by_number(id
);
5972 if (command_short_help(cmd
)) {
5973 cmd_reply(help_cmd
, caller
, C_COMMENT
,
5974 /* TRANS: <untranslated name> - translated short help */
5975 _("Command: %s - %s"),
5977 command_short_help(cmd
));
5979 cmd_reply(help_cmd
, caller
, C_COMMENT
,
5980 /* TRANS: <untranslated name> */
5984 if (command_synopsis(cmd
)) {
5985 /* line up the synopsis lines: */
5986 const char *syn
= _("Synopsis: ");
5987 size_t synlen
= strlen(syn
);
5990 fc_snprintf(prefix
, sizeof(prefix
), "%*s", (int) synlen
, " ");
5991 cmd_reply_prefix(help_cmd
, caller
, C_COMMENT
, prefix
,
5992 "%s%s", syn
, command_synopsis(cmd
));
5994 cmd_reply(help_cmd
, caller
, C_COMMENT
,
5995 _("Level: %s"), cmdlevel_name(command_level(cmd
)));
5997 char *help
= command_extra_help(cmd
);
6000 fc_break_lines(help
, LINE_BREAK
);
6001 cmd_reply(help_cmd
, caller
, C_COMMENT
, _("Description:"));
6002 cmd_reply_prefix(help_cmd
, caller
, C_COMMENT
, " ", " %s", help
);
6008 /**************************************************************************
6009 Show the caller list of COMMANDS.
6010 help_cmd is the command the player used.
6011 **************************************************************************/
6012 static void show_help_command_list(struct connection
*caller
,
6013 enum command_id help_cmd
)
6017 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
6018 cmd_reply(help_cmd
, caller
, C_COMMENT
,
6019 _("The following server commands are available:"));
6020 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
6021 if(!caller
&& con_get_style()) {
6022 for (i
=0; i
<CMD_NUM
; i
++) {
6023 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", command_name_by_number(i
));
6026 char buf
[MAX_LEN_CONSOLE_LINE
];
6030 for (i
=0, j
=0; i
<CMD_NUM
; i
++) {
6031 if (may_use(caller
, i
)) {
6032 cat_snprintf(buf
, sizeof(buf
), "%-19s", command_name_by_number(i
));
6033 if((++j
% 4) == 0) {
6034 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", buf
);
6040 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", buf
);
6042 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
6045 /**************************************************************************
6046 Send a reply to the caller listing the matched names from an ambiguous
6048 **************************************************************************/
6049 static void cmd_reply_matches(enum command_id cmd
,
6050 struct connection
*caller
,
6051 m_pre_accessor_fn_t accessor_fn
,
6052 int *matches
, int num_matches
)
6054 char buf
[MAX_LEN_MSG
];
6055 const char *src
, *end
;
6059 if (accessor_fn
== NULL
|| matches
== NULL
|| num_matches
< 1) {
6064 end
= buf
+ sizeof(buf
) - 1;
6066 for (i
= 0; i
< num_matches
&& dest
< end
; i
++) {
6067 src
= accessor_fn(matches
[i
]);
6074 while (*src
!= '\0' && dest
< end
) {
6080 cmd_reply(cmd
, caller
, C_COMMENT
, _("Possible matches: %s"), buf
);
6083 /**************************************************************************
6084 Additional 'help' arguments
6085 **************************************************************************/
6086 #define SPECENUM_NAME help_general_args
6087 #define SPECENUM_VALUE0 HELP_GENERAL_COMMANDS
6088 #define SPECENUM_VALUE0NAME "commands"
6089 #define SPECENUM_VALUE1 HELP_GENERAL_OPTIONS
6090 #define SPECENUM_VALUE1NAME "options"
6091 #define SPECENUM_COUNT HELP_GENERAL_COUNT
6092 #include "specenum_gen.h"
6094 /**************************************************************************
6095 Unified indices for help arguments:
6096 CMD_NUM - Server commands
6097 HELP_GENERAL_NUM - General help arguments, above
6098 settings_number() - Server options
6099 **************************************************************************/
6100 #define HELP_ARG_NUM (CMD_NUM + HELP_GENERAL_COUNT + settings_number())
6102 /**************************************************************************
6103 Convert unified helparg index to string; see above.
6104 **************************************************************************/
6105 static const char *helparg_accessor(int i
)
6108 return command_name_by_number(i
);
6112 if (i
< HELP_GENERAL_COUNT
) {
6113 return help_general_args_name((enum help_general_args
) i
);
6116 i
-= HELP_GENERAL_COUNT
;
6117 return optname_accessor(i
);
6120 /**************************************************************************
6122 **************************************************************************/
6123 static bool show_help(struct connection
*caller
, char *arg
)
6125 int matches
[64], num_matches
= 0;
6126 enum m_pre_result match_result
;
6129 fc_assert_ret_val(!may_use_nothing(caller
), FALSE
);
6130 /* no commands means no help, either */
6132 match_result
= match_prefix_full(helparg_accessor
, HELP_ARG_NUM
, 0,
6133 fc_strncasecmp
, NULL
, arg
, &ind
, matches
,
6134 ARRAY_SIZE(matches
), &num_matches
);
6136 if (match_result
==M_PRE_EMPTY
) {
6137 show_help_intro(caller
, CMD_HELP
);
6140 if (match_result
==M_PRE_AMBIGUOUS
) {
6141 cmd_reply(CMD_HELP
, caller
, C_FAIL
,
6142 _("Help argument '%s' is ambiguous."), arg
);
6143 cmd_reply_matches(CMD_HELP
, caller
, helparg_accessor
,
6144 matches
, num_matches
);
6147 if (match_result
==M_PRE_FAIL
) {
6148 cmd_reply(CMD_HELP
, caller
, C_FAIL
,
6149 _("No match for help argument '%s'."), arg
);
6153 /* other cases should be above */
6154 fc_assert_ret_val(match_result
< M_PRE_AMBIGUOUS
, FALSE
);
6156 if (ind
< CMD_NUM
) {
6157 show_help_command(caller
, CMD_HELP
, ind
);
6162 if (ind
== HELP_GENERAL_OPTIONS
) {
6163 show_help_option_list(caller
, CMD_HELP
);
6166 if (ind
== HELP_GENERAL_COMMANDS
) {
6167 show_help_command_list(caller
, CMD_HELP
);
6170 ind
-= HELP_GENERAL_COUNT
;
6172 if (ind
< settings_number()) {
6173 show_help_option(caller
, CMD_HELP
, ind
);
6177 /* should have finished by now */
6178 log_error("Bug in show_help!");
6182 /****************************************************************************
6183 List connections; initially mainly for debugging
6184 ****************************************************************************/
6185 static void show_connections(struct connection
*caller
)
6187 char buf
[MAX_LEN_CONSOLE_LINE
];
6189 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6190 _("List of connections to server:"));
6191 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6193 if (conn_list_size(game
.all_connections
) == 0) {
6194 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("<no connections>"));
6196 conn_list_iterate(game
.all_connections
, pconn
) {
6197 sz_strlcpy(buf
, conn_description(pconn
));
6198 if (pconn
->established
) {
6199 cat_snprintf(buf
, sizeof(buf
), " command access level %s",
6200 cmdlevel_name(pconn
->access_level
));
6202 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, "%s", buf
);
6203 } conn_list_iterate_end
;
6205 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6208 /*****************************************************************************
6209 List all delegations of the current game.
6210 *****************************************************************************/
6211 static void show_delegations(struct connection
*caller
)
6215 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of all delegations:"));
6216 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6218 players_iterate(pplayer
) {
6219 const char *delegate_to
= player_delegation_get(pplayer
);
6220 if (delegate_to
!= NULL
) {
6222 player_delegation_active(pplayer
) ? pplayer
->server
.orig_username
6223 : pplayer
->username
;
6225 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6226 /* TRANS: last %s is either " (active)" or empty string */
6227 _("%s delegates control over player '%s' to user %s%s."),
6228 owner
, player_name(pplayer
), delegate_to
,
6229 player_delegation_active(pplayer
) ? _(" (active)") : "");
6232 } players_iterate_end
;
6235 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("No delegations defined."));
6238 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6241 /****************************************************************************
6242 Show the ignore list of the
6243 ****************************************************************************/
6244 static bool show_ignore(struct connection
*caller
)
6249 if (NULL
== caller
) {
6250 cmd_reply(CMD_IGNORE
, caller
, C_FAIL
,
6251 _("That would be rather silly, since you are not a player."));
6255 if (0 == conn_pattern_list_size(caller
->server
.ignore_list
)) {
6256 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("Your ignore list is empty."));
6260 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("Your ignore list:"));
6261 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6262 conn_pattern_list_iterate(caller
->server
.ignore_list
, ppattern
) {
6263 conn_pattern_to_string(ppattern
, buf
, sizeof(buf
));
6264 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, "%d: %s", n
++, buf
);
6265 } conn_pattern_list_iterate_end
;
6266 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6271 /****************************************************************************
6272 Show the list of the players of the game.
6273 ****************************************************************************/
6274 void show_players(struct connection
*caller
)
6276 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of players:"));
6277 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6279 if (player_count() == 0) {
6280 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("<no players>"));
6282 players_iterate(pplayer
) {
6283 char buf
[MAX_LEN_CONSOLE_LINE
];
6286 /* Low access level callers don't get to see barbarians in list: */
6287 if (is_barbarian(pplayer
) && caller
6288 && (caller
->access_level
< ALLOW_CTRL
)) {
6292 /* The output for each player looks like:
6294 * <Player name> [color]: Team[, Nation][, Username][, Status]
6295 * AI/Barbarian/Human[, AI type, skill level][, Connections]
6296 * [Details for each connection]
6299 /* '<Player name> [color]: [Nation][, Username][, Status]' */
6301 cat_snprintf(buf
, sizeof(buf
), "%s [%s]: %s", player_name(pplayer
),
6302 player_color_ftstr(pplayer
),
6303 team_name_translation(pplayer
->team
));
6304 if (!game
.info
.is_new_game
) {
6305 cat_snprintf(buf
, sizeof(buf
), ", %s",
6306 nation_adjective_for_player(pplayer
));
6308 if (strlen(pplayer
->username
) > 0
6309 && strcmp(pplayer
->username
, "nouser") != 0) {
6310 cat_snprintf(buf
, sizeof(buf
), _(", user %s"), pplayer
->username
);
6312 if (S_S_INITIAL
== server_state() && pplayer
->is_connected
) {
6313 if (pplayer
->is_ready
) {
6314 sz_strlcat(buf
, _(", ready"));
6316 /* Emphasizes this */
6318 featured_text_apply_tag(_(", not ready"),
6319 buf
+ n
, sizeof(buf
) - n
,
6320 TTT_COLOR
, 1, FT_OFFSET_UNSET
,
6323 } else if (!pplayer
->is_alive
) {
6324 sz_strlcat(buf
, _(", Dead"));
6326 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, "%s", buf
);
6328 /* ' AI/Barbarian/Human[, skill level][, Connections]' */
6330 if (is_barbarian(pplayer
)) {
6331 sz_strlcat(buf
, _("Barbarian"));
6332 } else if (pplayer
->ai_controlled
) {
6333 sz_strlcat(buf
, _("AI"));
6335 sz_strlcat(buf
, _("Human"));
6337 if (pplayer
->ai_controlled
) {
6338 cat_snprintf(buf
, sizeof(buf
), _(", %s"), ai_name(pplayer
->ai
));
6339 cat_snprintf(buf
, sizeof(buf
), _(", difficulty level %s"),
6340 ai_level_translated_name(pplayer
->ai_common
.skill_level
));
6342 n
= conn_list_size(pplayer
->connections
);
6344 cat_snprintf(buf
, sizeof(buf
),
6345 PL_(", %d connection:", ", %d connections:", n
), n
);
6347 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, " %s", buf
);
6349 /* ' [Details for each connection]' */
6350 conn_list_iterate(pplayer
->connections
, pconn
) {
6351 fc_snprintf(buf
, sizeof(buf
),
6352 _("%s from %s (command access level %s), "
6353 "bufsize=%dkb"), pconn
->username
, pconn
->addr
,
6354 cmdlevel_name(pconn
->access_level
),
6355 (pconn
->send_buffer
->nsize
>> 10));
6356 if (pconn
->observer
) {
6357 sz_strlcat(buf
, _(" (observer mode)"));
6359 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, " %s", buf
);
6360 } conn_list_iterate_end
;
6361 } players_iterate_end
;
6363 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6366 /****************************************************************************
6367 List scenarios. We look both in the DATA_PATH and DATA_PATH/scenario
6368 ****************************************************************************/
6369 static void show_scenarios(struct connection
*caller
)
6371 char buf
[MAX_LEN_CONSOLE_LINE
];
6372 struct fileinfo_list
*files
;
6374 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of scenarios available:"));
6375 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6377 files
= fileinfolist_infix(get_scenario_dirs(), ".sav", TRUE
);
6379 fileinfo_list_iterate(files
, pfile
) {
6380 fc_snprintf(buf
, sizeof(buf
), "%s", pfile
->name
);
6381 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, "%s", buf
);
6382 } fileinfo_list_iterate_end
;
6383 fileinfo_list_destroy(files
);
6385 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6388 /****************************************************************************
6389 List nation sets in the current ruleset.
6390 ****************************************************************************/
6391 static void show_nationsets(struct connection
*caller
)
6393 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6394 /* TRANS: don't translate text between '' */
6395 _("List of nation sets available for 'nationset' option:"));
6396 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6398 nation_sets_iterate(pset
) {
6399 const char *description
= nation_set_description(pset
);
6400 int num_nations
= 0;
6401 nations_iterate(pnation
) {
6402 if (is_nation_playable(pnation
) && nation_is_in_set(pnation
, pset
)) {
6405 } nations_iterate_end
;
6406 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6407 /* TRANS: nation set description; %d refers to number of playable
6409 PL_(" %-10s %s (%d playable)",
6410 " %-10s %s (%d playable)", num_nations
),
6411 nation_set_rule_name(pset
), nation_set_name_translation(pset
),
6413 if (strlen(description
) > 0) {
6414 static const char prefix
[] = " ";
6415 char *translated
= fc_strdup(_(description
));
6416 fc_break_lines(translated
, LINE_BREAK
);
6417 cmd_reply_prefix(CMD_LIST
, caller
, C_COMMENT
, prefix
, "%s%s",
6418 prefix
, translated
);
6420 } nation_sets_iterate_end
;
6422 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6425 /****************************************************************************
6426 Show a list of teams on the command line.
6427 ****************************************************************************/
6428 static void show_teams(struct connection
*caller
)
6430 /* Currently this just lists all teams (typically 32 of them) with their
6431 * names and # of players on the team. This could probably be improved. */
6432 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of teams:"));
6433 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6435 teams_iterate(pteam
) {
6436 const struct player_list
*members
= team_members(pteam
);
6438 /* PL_() is needed here because some languages may differentiate
6439 * between 2 and 3 (although English does not). */
6440 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6441 /* TRANS: There will always be at least 2 players here. */
6442 PL_("%2d : '%s' : %d player :",
6443 "%2d : '%s' : %d players :",
6444 player_list_size(members
)),
6445 team_index(pteam
), team_name_translation(pteam
),
6446 player_list_size(members
));
6447 player_list_iterate(members
, pplayer
) {
6448 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, " %s", player_name(pplayer
));
6449 } player_list_iterate_end
;
6450 } teams_iterate_end
;
6452 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6455 /****************************************************************************
6456 Show a list of all map image definitions on the command line.
6457 ****************************************************************************/
6458 static void show_mapimg(struct connection
*caller
, enum command_id cmd
)
6462 if (mapimg_count() == 0) {
6463 cmd_reply(cmd
, caller
, C_OK
, _("No map image definitions."));
6465 cmd_reply(cmd
, caller
, C_COMMENT
, _("List of map image definitions:"));
6466 cmd_reply(cmd
, caller
, C_COMMENT
, horiz_line
);
6467 for (id
= 0; id
< mapimg_count(); id
++) {
6468 char str
[MAX_LEN_MAPDEF
] = "";
6469 mapimg_show(id
, str
, sizeof(str
), FALSE
);
6470 cmd_reply(cmd
, caller
, C_COMMENT
, _("[%2d] %s"), id
, str
);
6472 cmd_reply(cmd
, caller
, C_COMMENT
, horiz_line
);
6476 /****************************************************************************
6477 Show a list of all players with the assigned color.
6478 ****************************************************************************/
6479 static void show_colors(struct connection
*caller
)
6481 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of player colors:"));
6482 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6483 if (player_count() == 0) {
6484 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("<no players>"));
6486 players_iterate(pplayer
) {
6487 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("%s (user %s): [%s]"),
6488 player_name(pplayer
), pplayer
->username
,
6489 player_color_ftstr(pplayer
));
6490 } players_iterate_end
;
6492 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6495 /****************************************************************************
6497 **************************************************************************/
6498 #define SPECENUM_NAME list_args
6499 #define SPECENUM_VALUE0 LIST_COLORS
6500 #define SPECENUM_VALUE0NAME "colors"
6501 #define SPECENUM_VALUE1 LIST_CONNECTIONS
6502 #define SPECENUM_VALUE1NAME "connections"
6503 #define SPECENUM_VALUE2 LIST_DELEGATIONS
6504 #define SPECENUM_VALUE2NAME "delegations"
6505 #define SPECENUM_VALUE3 LIST_IGNORE
6506 #define SPECENUM_VALUE3NAME "ignored users"
6507 #define SPECENUM_VALUE4 LIST_MAPIMG
6508 #define SPECENUM_VALUE4NAME "map image definitions"
6509 #define SPECENUM_VALUE5 LIST_PLAYERS
6510 #define SPECENUM_VALUE5NAME "players"
6511 #define SPECENUM_VALUE6 LIST_SCENARIOS
6512 #define SPECENUM_VALUE6NAME "scenarios"
6513 #define SPECENUM_VALUE7 LIST_NATIONSETS
6514 #define SPECENUM_VALUE7NAME "nationsets"
6515 #define SPECENUM_VALUE8 LIST_TEAMS
6516 #define SPECENUM_VALUE8NAME "teams"
6517 #define SPECENUM_VALUE9 LIST_VOTES
6518 #define SPECENUM_VALUE9NAME "votes"
6519 #include "specenum_gen.h"
6521 /**************************************************************************
6522 Returns possible parameters for the list command.
6523 **************************************************************************/
6524 static const char *list_accessor(int i
)
6526 i
= CLIP(0, i
, list_args_max());
6527 return list_args_name((enum list_args
) i
);
6530 /**************************************************************************
6531 Show list of players or connections, or connection statistics.
6532 **************************************************************************/
6533 static bool show_list(struct connection
*caller
, char *arg
)
6535 enum m_pre_result match_result
;
6539 remove_leading_trailing_spaces(arg
);
6540 match_result
= match_prefix(list_accessor
, list_args_max() + 1, 0,
6541 fc_strncasecmp
, NULL
, arg
, &ind_int
);
6544 if (match_result
> M_PRE_EMPTY
) {
6545 cmd_reply(CMD_LIST
, caller
, C_SYNTAX
,
6546 _("Bad list argument: '%s'. Try '%shelp list'."),
6547 arg
, (caller
?"/":""));
6551 if (match_result
== M_PRE_EMPTY
) {
6557 show_colors(caller
);
6559 case LIST_CONNECTIONS
:
6560 show_connections(caller
);
6562 case LIST_DELEGATIONS
:
6563 show_delegations(caller
);
6566 return show_ignore(caller
);
6568 show_mapimg(caller
, CMD_LIST
);
6571 show_players(caller
);
6573 case LIST_SCENARIOS
:
6574 show_scenarios(caller
);
6576 case LIST_NATIONSETS
:
6577 show_nationsets(caller
);
6587 cmd_reply(CMD_LIST
, caller
, C_FAIL
,
6588 "Internal error: ind %d in show_list", ind
);
6589 log_error("Internal error: ind %d in show_list", ind
);
6593 #ifdef FREECIV_HAVE_LIBREADLINE
6594 /********************* RL completion functions ***************************/
6595 /* To properly complete both commands, player names, options and filenames
6596 there is one array per type of completion with the commands that
6597 the type is relevant for.
6600 /**************************************************************************
6601 A generalised generator function: text and state are "standard"
6602 parameters to a readline generator function;
6603 num is number of possible completions, or -1 if this is not known and
6604 index2str should be iterated until it returns NULL;
6605 index2str is a function which returns each possible completion string
6606 by index (it may return NULL).
6607 **************************************************************************/
6608 static char *generic_generator(const char *text
, int state
, int num
,
6609 const char*(*index2str
)(int))
6611 static int list_index
, len
;
6612 const char *name
= ""; /* dummy non-NULL string */
6613 char *mytext
= local_to_internal_string_malloc(text
);
6615 /* This function takes a string (text) in the local format and must return
6616 * a string in the local format. However comparisons are done against
6617 * names that are in the internal format (UTF-8). Thus we have to convert
6618 * the text function from the local to the internal format before doing
6619 * the comparison, and convert the string we return *back* to the
6620 * local format when returning it. */
6622 /* If this is a new word to complete, initialize now. This includes
6623 saving the length of TEXT for efficiency, and initializing the index
6627 len
= strlen(mytext
);
6630 /* Return the next name which partially matches: */
6631 while ((num
< 0 && name
) || (list_index
< num
)) {
6632 name
= index2str(list_index
);
6635 if (name
!= NULL
&& fc_strncasecmp(name
, mytext
, len
) == 0) {
6637 return internal_to_local_string_malloc(name
);
6642 /* If no names matched, then return NULL. */
6643 return ((char *)NULL
);
6646 /**************************************************************************
6647 The valid commands at the root of the prompt.
6648 **************************************************************************/
6649 static char *command_generator(const char *text
, int state
)
6651 return generic_generator(text
, state
, CMD_NUM
, command_name_by_number
);
6654 /**************************************************************************
6655 The valid arguments to "set" and "explain"
6656 **************************************************************************/
6657 static char *option_generator(const char *text
, int state
)
6659 return generic_generator(text
, state
, settings_number(), optname_accessor
);
6662 /**************************************************************************
6663 The valid arguments to "show"
6664 **************************************************************************/
6665 static char *olevel_generator(const char *text
, int state
)
6667 return generic_generator(text
, state
, settings_number() + OLEVELS_NUM
+ 1,
6671 /**************************************************************************
6672 Accessor for values of the enum/bitwise option defined by
6673 'completion_option'.
6674 **************************************************************************/
6675 static int completion_option
;
6676 static const char *option_value_accessor(int idx
) {
6677 const struct setting
*pset
= setting_by_number(completion_option
);
6678 switch (setting_type(pset
)) {
6680 return setting_enum_val(pset
, idx
, FALSE
);
6683 return setting_bitwise_bit(pset
, idx
, FALSE
);
6686 fc_assert_ret_val(0, NULL
);
6690 /**************************************************************************
6691 The valid arguments to "set OPT", where OPT is the enumerated or
6692 bitwise option previously defined by completion_option
6693 **************************************************************************/
6694 static char *option_value_generator(const char *text
, int state
)
6696 return generic_generator(text
, state
, -1, option_value_accessor
);
6699 /**************************************************************************
6701 **************************************************************************/
6702 static const char *playername_accessor(int idx
)
6704 const struct player_slot
*pslot
= player_slot_by_number(idx
);
6706 if (!player_slot_is_used(pslot
)) {
6710 return player_name(player_slot_get_player(pslot
));
6713 /**************************************************************************
6714 The valid playername arguments.
6715 **************************************************************************/
6716 static char *player_generator(const char *text
, int state
)
6718 return generic_generator(text
, state
, player_slot_count(),
6719 playername_accessor
);
6722 /**************************************************************************
6723 Access connection user name, from game.all_connections.
6724 **************************************************************************/
6725 static const char *connection_name_accessor(int idx
)
6727 return conn_list_get(game
.all_connections
, idx
)->username
;
6730 /**************************************************************************
6731 The valid connection user name arguments.
6732 **************************************************************************/
6733 static char *connection_generator(const char *text
, int state
)
6735 return generic_generator(text
, state
, conn_list_size(game
.all_connections
),
6736 connection_name_accessor
);
6739 /**************************************************************************
6740 Extra accessor function since cmdlevel_name() takes enum argument, not int.
6741 **************************************************************************/
6742 static const char *cmdlevel_arg1_accessor(int idx
)
6744 return cmdlevel_name(idx
);
6747 /**************************************************************************
6748 The valid first argument to "cmdlevel"
6749 **************************************************************************/
6750 static char *cmdlevel_arg1_generator(const char *text
, int state
)
6752 return generic_generator(text
, state
, cmdlevel_max()+1,
6753 cmdlevel_arg1_accessor
);
6756 /**************************************************************************
6757 Accessor for the second argument to "cmdlevel": "first" or "new" or
6759 **************************************************************************/
6760 static const char *cmdlevel_arg2_accessor(int idx
)
6762 return ((idx
==0) ? "first" :
6764 connection_name_accessor(idx
-2));
6767 /**************************************************************************
6768 The valid arguments for the second argument to "cmdlevel".
6769 **************************************************************************/
6770 static char *cmdlevel_arg2_generator(const char *text
, int state
)
6772 return generic_generator(text
, state
,
6773 /* "first", "new", connection names */
6774 2 + conn_list_size(game
.all_connections
),
6775 cmdlevel_arg2_accessor
);
6778 /**************************************************************************
6779 Accessor for the second argument to "create": ai type name
6780 **************************************************************************/
6781 static const char *aitype_accessor(int idx
)
6783 return get_ai_type(idx
)->name
;
6786 /**************************************************************************
6787 The valid arguments for the second argument to "create".
6788 **************************************************************************/
6789 static char *aitype_generator(const char *text
, int state
)
6791 return generic_generator(text
, state
, ai_type_get_count(),
6795 /**************************************************************************
6796 The valid arguments for the argument to "reset".
6797 **************************************************************************/
6798 static char *reset_generator(const char *text
, int state
)
6800 return generic_generator(text
, state
, reset_args_max() + 1, reset_accessor
);
6803 /**************************************************************************
6804 The valid arguments for the argument to "vote".
6805 **************************************************************************/
6806 static char *vote_generator(const char *text
, int state
)
6808 return generic_generator(text
, state
, -1, vote_arg_accessor
);
6811 /**************************************************************************
6812 The valid arguments for the first argument to "delegate".
6813 **************************************************************************/
6814 static char *delegate_generator(const char *text
, int state
)
6816 return generic_generator(text
, state
, delegate_args_max() + 1,
6820 /**************************************************************************
6821 The valid arguments for the first argument to "mapimg".
6822 **************************************************************************/
6823 static char *mapimg_generator(const char *text
, int state
)
6825 return generic_generator(text
, state
, mapimg_args_max() + 1,
6829 /**************************************************************************
6830 The valid arguments for the argument to "fcdb".
6831 **************************************************************************/
6832 static char *fcdb_generator(const char *text
, int state
)
6834 return generic_generator(text
, state
, FCDB_COUNT
, fcdb_accessor
);
6837 /**************************************************************************
6838 The valid arguments for the argument to "lua".
6839 **************************************************************************/
6840 static char *lua_generator(const char *text
, int state
)
6842 return generic_generator(text
, state
, lua_args_max() + 1, lua_accessor
);
6845 /**************************************************************************
6846 The valid first arguments to "help".
6847 **************************************************************************/
6848 static char *help_generator(const char *text
, int state
)
6850 return generic_generator(text
, state
, HELP_ARG_NUM
, helparg_accessor
);
6853 /**************************************************************************
6854 The valid first arguments to "list".
6855 **************************************************************************/
6856 static char *list_generator(const char *text
, int state
)
6858 return generic_generator(text
, state
, list_args_max() + 1, list_accessor
);
6861 /**************************************************************************
6862 Generalised version of contains_str_before_start, which searches the
6863 N'th token in rl_line_buffer (0=first).
6864 **************************************************************************/
6865 static bool contains_token_before_start(int start
, int token
, const char *arg
,
6868 char *str_itr
= rl_line_buffer
;
6869 int arg_len
= strlen(arg
);
6871 /* Swallow unwanted tokens and their preceding delimiters */
6873 while (str_itr
< rl_line_buffer
+ start
&& !fc_isalnum(*str_itr
)) {
6876 while (str_itr
< rl_line_buffer
+ start
&& fc_isalnum(*str_itr
)) {
6881 /* Swallow any delimiters before the token we're interested in */
6882 while (str_itr
< rl_line_buffer
+ start
&& !fc_isalnum(*str_itr
)) {
6886 if (fc_strncasecmp(str_itr
, arg
, arg_len
) != 0) {
6891 if (fc_isalnum(*str_itr
)) {
6892 /* Not a distinct word. */
6897 for (; str_itr
< rl_line_buffer
+ start
; str_itr
++) {
6898 if (fc_isalnum(*str_itr
)) {
6907 /**************************************************************************
6908 Returns whether the text between the start of rl_line_buffer and the
6909 start position is of the form [non-alpha]*cmd[non-alpha]*
6910 allow_fluff changes the regexp to [non-alpha]*cmd[non-alpha].*
6911 **************************************************************************/
6912 static bool contains_str_before_start(int start
, const char *cmd
,
6915 return contains_token_before_start(start
, 0, cmd
, allow_fluff
);
6918 /**************************************************************************
6919 Return whether we are completing command name. This can be either
6920 command itself, or argument to 'help'.
6921 **************************************************************************/
6922 static bool is_command(int start
)
6926 if (contains_str_before_start(start
, command_name_by_number(CMD_HELP
), FALSE
))
6929 /* if there is only it is also OK */
6930 str_itr
= rl_line_buffer
;
6931 while (str_itr
- rl_line_buffer
< start
) {
6932 if (fc_isalnum(*str_itr
)) {
6940 /**************************************************************************
6941 number of tokens in rl_line_buffer before start
6942 **************************************************************************/
6943 static int num_tokens(int start
)
6947 char *chptr
= rl_line_buffer
;
6949 while (chptr
- rl_line_buffer
< start
) {
6950 if (fc_isalnum(*chptr
)) {
6964 /**************************************************************************
6965 Commands that may be followed by a player name
6966 **************************************************************************/
6967 static const int player_cmd
[] = {
6984 /**************************************************************************
6985 Return whether we are completing player name argument.
6986 **************************************************************************/
6987 static bool is_player(int start
)
6991 while (player_cmd
[i
] != -1) {
6992 if (contains_str_before_start(start
, command_name_by_number(player_cmd
[i
]), FALSE
)) {
7001 /**************************************************************************
7002 Commands that may be followed by a connection name
7003 **************************************************************************/
7004 static const int connection_cmd
[] = {
7010 /**************************************************************************
7011 Return whether we are completing connection name argument.
7012 **************************************************************************/
7013 static bool is_connection(int start
)
7017 while (connection_cmd
[i
] != -1) {
7018 if (contains_str_before_start(start
,
7019 command_name_by_number(connection_cmd
[i
]),
7029 /**************************************************************************
7030 Return whether we are completing cmdlevel command argument 2.
7031 **************************************************************************/
7032 static bool is_cmdlevel_arg2(int start
)
7034 return (contains_str_before_start(start
, command_name_by_number(CMD_CMDLEVEL
), TRUE
)
7035 && num_tokens(start
) == 2);
7038 /**************************************************************************
7039 Return whether we are completing cmdlevel command argument.
7040 **************************************************************************/
7041 static bool is_cmdlevel_arg1(int start
)
7043 return contains_str_before_start(start
, command_name_by_number(CMD_CMDLEVEL
), FALSE
);
7046 /**************************************************************************
7047 Commands that may be followed by a server option name
7049 CMD_SHOW is handled by option_level_cmd, which is for both option levels
7051 **************************************************************************/
7052 static const int server_option_cmd
[] = {
7059 /**************************************************************************
7060 Returns TRUE if the readline buffer string matches a server option at
7062 **************************************************************************/
7063 static bool is_server_option(int start
)
7067 while (server_option_cmd
[i
] != -1) {
7068 if (contains_str_before_start(start
, command_name_by_number(server_option_cmd
[i
]),
7078 /**************************************************************************
7079 Commands that may be followed by an option level or server option
7080 **************************************************************************/
7081 static const int option_level_cmd
[] = {
7086 /**************************************************************************
7087 Returns true if the readline buffer string matches an option level or an
7088 option at the given position.
7089 **************************************************************************/
7090 static bool is_option_level(int start
)
7094 while (option_level_cmd
[i
] != -1) {
7095 if (contains_str_before_start(start
, command_name_by_number(option_level_cmd
[i
]),
7105 /**************************************************************************
7106 Returns TRUE if the readline buffer string is such that we expect an
7107 enumerated value at the given position. The option for which values
7108 should be completed is written to opt_p.
7109 **************************************************************************/
7110 static bool is_enum_option_value(int start
, int *opt_p
)
7112 if (contains_str_before_start(start
, command_name_by_number(CMD_SET
),
7114 settings_iterate(SSET_ALL
, pset
) {
7115 if (setting_type(pset
) != SSET_ENUM
7116 && setting_type(pset
) != SSET_BITWISE
) {
7119 /* Allow a single token for enum options, multiple for bitwise
7120 * (the separator | will separate tokens for these purposes) */
7121 if (contains_token_before_start(start
, 1, setting_name(pset
),
7122 setting_type(pset
) == SSET_BITWISE
)) {
7123 *opt_p
= setting_number(pset
);
7124 /* Suppress appended space for bitwise options (user may want |) */
7125 rl_completion_suppress_append
= (setting_type(pset
) == SSET_BITWISE
);
7128 } settings_iterate_end
;
7133 /**************************************************************************
7134 Commands that may be followed by a filename
7135 **************************************************************************/
7136 static const int filename_cmd
[] = {
7144 /**************************************************************************
7145 Return whether we are completing filename.
7146 **************************************************************************/
7147 static bool is_filename(int start
)
7151 while (filename_cmd
[i
] != -1) {
7152 if (contains_str_before_start(start
, command_name_by_number(filename_cmd
[i
]), FALSE
)) {
7161 /**************************************************************************
7162 Return whether we are completing second argument for create command
7163 **************************************************************************/
7164 static bool is_create_arg2(int start
)
7166 return (contains_str_before_start(start
, command_name_by_number(CMD_CREATE
), TRUE
)
7167 && num_tokens(start
) == 2);
7170 /**************************************************************************
7171 Return whether we are completing argument for reset command
7172 **************************************************************************/
7173 static bool is_reset(int start
)
7175 return contains_str_before_start(start
,
7176 command_name_by_number(CMD_RESET
),
7180 /**************************************************************************
7181 Return whether we are completing argument for vote command
7182 **************************************************************************/
7183 static bool is_vote(int start
)
7185 return contains_str_before_start(start
,
7186 command_name_by_number(CMD_VOTE
),
7190 /**************************************************************************
7191 Return whether we are completing first argument for delegate command
7192 **************************************************************************/
7193 static bool is_delegate_arg1(int start
)
7195 return contains_str_before_start(start
,
7196 command_name_by_number(CMD_DELEGATE
),
7200 /**************************************************************************
7201 Return whether we are completing first argument for mapimg command
7202 **************************************************************************/
7203 static bool is_mapimg(int start
)
7205 return contains_str_before_start(start
,
7206 command_name_by_number(CMD_MAPIMG
),
7210 /**************************************************************************
7211 Return whether we are completing argument for fcdb command
7212 **************************************************************************/
7213 static bool is_fcdb(int start
)
7215 return contains_str_before_start(start
,
7216 command_name_by_number(CMD_FCDB
),
7220 /**************************************************************************
7221 Return whether we are completing argument for lua command
7222 **************************************************************************/
7223 static bool is_lua(int start
)
7225 return contains_str_before_start(start
,
7226 command_name_by_number(CMD_LUA
),
7230 /**************************************************************************
7231 Return whether we are completing help command argument.
7232 **************************************************************************/
7233 static bool is_help(int start
)
7235 return contains_str_before_start(start
, command_name_by_number(CMD_HELP
), FALSE
);
7238 /**************************************************************************
7239 Return whether we are completing list command argument.
7240 **************************************************************************/
7241 static bool is_list(int start
)
7243 return contains_str_before_start(start
, command_name_by_number(CMD_LIST
), FALSE
);
7246 /**************************************************************************
7247 Attempt to complete on the contents of TEXT. START and END bound the
7248 region of rl_line_buffer that contains the word to complete. TEXT is
7249 the word to complete. We can use the entire contents of rl_line_buffer
7250 in case we want to do some simple parsing. Return the array of matches,
7251 or NULL if there aren't any.
7252 **************************************************************************/
7253 char **freeciv_completion(const char *text
, int start
, int end
)
7255 char **matches
= (char **)NULL
;
7257 if (is_help(start
)) {
7258 matches
= rl_completion_matches(text
, help_generator
);
7259 } else if (is_command(start
)) {
7260 matches
= rl_completion_matches(text
, command_generator
);
7261 } else if (is_list(start
)) {
7262 matches
= rl_completion_matches(text
, list_generator
);
7263 } else if (is_cmdlevel_arg2(start
)) {
7264 matches
= rl_completion_matches(text
, cmdlevel_arg2_generator
);
7265 } else if (is_cmdlevel_arg1(start
)) {
7266 matches
= rl_completion_matches(text
, cmdlevel_arg1_generator
);
7267 } else if (is_connection(start
)) {
7268 matches
= rl_completion_matches(text
, connection_generator
);
7269 } else if (is_player(start
)) {
7270 matches
= rl_completion_matches(text
, player_generator
);
7271 } else if (is_server_option(start
)) {
7272 matches
= rl_completion_matches(text
, option_generator
);
7273 } else if (is_option_level(start
)) {
7274 matches
= rl_completion_matches(text
, olevel_generator
);
7275 } else if (is_enum_option_value(start
, &completion_option
)) {
7276 matches
= rl_completion_matches(text
, option_value_generator
);
7277 } else if (is_filename(start
)) {
7278 /* This function we get from readline */
7279 matches
= rl_completion_matches(text
, rl_filename_completion_function
);
7280 } else if (is_create_arg2(start
)) {
7281 matches
= rl_completion_matches(text
, aitype_generator
);
7282 } else if (is_reset(start
)) {
7283 matches
= rl_completion_matches(text
, reset_generator
);
7284 } else if (is_vote(start
)) {
7285 matches
= rl_completion_matches(text
, vote_generator
);
7286 } else if (is_delegate_arg1(start
)) {
7287 matches
= rl_completion_matches(text
, delegate_generator
);
7288 } else if (is_mapimg(start
)) {
7289 matches
= rl_completion_matches(text
, mapimg_generator
);
7290 } else if (is_fcdb(start
)) {
7291 matches
= rl_completion_matches(text
, fcdb_generator
);
7292 } else if (is_lua(start
)) {
7293 matches
= rl_completion_matches(text
, lua_generator
);
7295 /* We have no idea what to do */
7299 /* Don't automatically try to complete with filenames */
7300 rl_attempted_completion_over
= 1;
7305 #endif /* FREECIV_HAVE_LIBREADLINE */