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 HAVE_LIBREADLINE
24 #include <readline/readline.h>
29 #include "bitvector.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"
55 #include "citytools.h"
56 #include "connecthand.h"
59 #include "ggzserver.h"
67 #include "sanitycheck.h"
68 #include "savegame2.h"
74 #include "techtools.h"
77 /* server/scripting */
78 #include "script_server.h"
79 #include "script_fcdb.h"
81 #include "stdinhand.h"
83 #define TOKEN_DELIMITERS " \t\n,"
85 #define OPTION_NAME_SPACE 25
87 static enum cmdlevel default_access_level
= ALLOW_BASIC
;
88 static enum cmdlevel first_access_level
= ALLOW_BASIC
;
90 static time_t *time_duplicate(const time_t *t
);
92 /* 'struct kick_hash' and related functions. */
93 #define SPECHASH_TAG kick
94 #define SPECHASH_KEY_TYPE char *
95 #define SPECHASH_DATA_TYPE time_t
96 #define SPECHASH_KEY_VAL genhash_str_val_func
97 #define SPECHASH_KEY_COMP genhash_str_comp_func
98 #define SPECHASH_KEY_COPY genhash_str_copy_func
99 #define SPECHASH_KEY_FREE genhash_str_free_func
100 #define SPECHASH_DATA_COPY time_duplicate
101 #define SPECHASH_DATA_FREE free
102 #define SPECHASH_DATA_TO_PTR(t) (&(t))
103 #define SPECHASH_PTR_TO_DATA(p) (NULL != p ? *(time_t *) (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 set_away(struct connection
*caller
, char *name
, 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 void show_command_one(struct connection
*caller
, struct setting
*pset
);
124 static void show_changed(struct connection
*caller
, bool check
,
126 static void show_mapimg(struct connection
*caller
, enum command_id cmd
);
127 static bool set_command(struct connection
*caller
, char *str
, bool check
);
129 static bool create_command(struct connection
*caller
, const char *str
,
131 static bool end_command(struct connection
*caller
, char *str
, bool check
);
132 static bool surrender_command(struct connection
*caller
, char *str
, bool check
);
133 static bool handle_stdin_input_real(struct connection
*caller
, const char *str
,
134 bool check
, int read_recursion
);
135 static bool read_init_script_real(struct connection
*caller
,
136 char *script_filename
, bool from_cmdline
,
137 bool check
, int read_recursion
);
138 static bool reset_command(struct connection
*caller
, char *arg
, bool check
,
140 static bool lua_command(struct connection
*caller
, char *arg
, bool check
);
141 static bool kick_command(struct connection
*caller
, char *name
, bool check
);
142 static bool delegate_command(struct connection
*caller
, char *arg
,
144 static const char *delegate_player_str(struct player
*pplayer
, bool observer
);
145 static bool fcdb_command(struct connection
*caller
, char *arg
, bool check
);
146 static const char *fcdb_accessor(int i
);
147 static char setting_status(struct connection
*caller
,
148 const struct setting
*pset
);
149 static bool player_name_check(const char* name
, char *buf
, size_t buflen
);
150 static bool playercolor_command(struct connection
*caller
,
151 char *str
, bool check
);
152 static bool mapimg_command(struct connection
*caller
, char *arg
, bool check
);
153 static const char *mapimg_accessor(int i
);
155 static void show_delegations(struct connection
*caller
);
157 static const char horiz_line
[] =
158 "------------------------------------------------------------------------------";
160 /********************************************************************
161 Are we operating under a restricted security regime? For now
162 this does not do much.
163 *********************************************************************/
164 static bool is_restricted(struct connection
*caller
)
166 return (caller
&& caller
->access_level
!= ALLOW_HACK
);
169 /**************************************************************************
170 Check the player name. Returns TRUE if the player name is valid else
171 an error message is saved in 'buf'.
172 **************************************************************************/
173 static bool player_name_check(const char* name
, char *buf
, size_t buflen
)
175 size_t len
= strlen(name
);
178 fc_snprintf(buf
, buflen
, _("Can't use an empty name."));
180 } else if (len
> MAX_LEN_NAME
-1) {
181 fc_snprintf(buf
, buflen
, _("That name exceeds the maximum of %d chars."),
184 } else if (fc_strcasecmp(name
, ANON_PLAYER_NAME
) == 0
185 || fc_strcasecmp(name
, "Observer") == 0) {
186 fc_snprintf(buf
, buflen
, _("That name is not allowed."));
187 /* "Observer" used to be illegal and we keep it that way for now. */
194 /**************************************************************************
195 Convert a named command into an id.
196 If accept_ambiguity is true, return the first command in the
197 enum list which matches, else return CMD_AMBIGOUS on ambiguity.
198 (This is a trick to allow ambiguity to be handled in a flexible way
199 without importing notify_player() messages inside this routine - rp)
200 **************************************************************************/
201 static enum command_id
command_named(const char *token
, bool accept_ambiguity
)
203 enum m_pre_result result
;
206 result
= match_prefix(command_name_by_number
, CMD_NUM
, 0,
207 fc_strncasecmp
, NULL
, token
, &ind
);
209 if (result
< M_PRE_AMBIGUOUS
) {
211 } else if (result
== M_PRE_AMBIGUOUS
) {
212 return accept_ambiguity
? ind
: CMD_AMBIGUOUS
;
214 return CMD_UNRECOGNIZED
;
218 /**************************************************************************
219 Initialize stuff related to this code module.
220 **************************************************************************/
221 void stdinhand_init(void)
223 fc_assert(NULL
== kick_table_by_addr
);
224 kick_table_by_addr
= kick_hash_new();
226 fc_assert(NULL
== kick_table_by_user
);
227 kick_table_by_user
= kick_hash_new();
230 /**************************************************************************
231 Update stuff every turn that is related to this code module. Run this
233 **************************************************************************/
234 void stdinhand_turn(void)
236 /* Nothing at the moment. */
239 /**************************************************************************
240 Deinitialize stuff related to this code module.
241 **************************************************************************/
242 void stdinhand_free(void)
244 fc_assert(NULL
!= kick_table_by_addr
);
245 if (NULL
!= kick_table_by_addr
) {
246 kick_hash_destroy(kick_table_by_addr
);
247 kick_table_by_addr
= NULL
;
250 fc_assert(NULL
!= kick_table_by_user
);
251 if (NULL
!= kick_table_by_user
) {
252 kick_hash_destroy(kick_table_by_user
);
253 kick_table_by_user
= NULL
;
257 /**************************************************************************
258 Whether the caller can use the specified command. caller == NULL means
260 **************************************************************************/
261 static bool may_use(struct connection
*caller
, enum command_id cmd
)
264 return TRUE
; /* on the console, everything is allowed */
266 return (caller
->access_level
>= command_level(command_by_number(cmd
)));
269 /**************************************************************************
270 Whether the caller cannot use any commands at all.
271 caller == NULL means console.
272 **************************************************************************/
273 static bool may_use_nothing(struct connection
*caller
)
276 return FALSE
; /* on the console, everything is allowed */
278 return (ALLOW_NONE
== conn_get_access(caller
));
281 /**************************************************************************
282 Return the status of the setting (changeable, locked, fixed).
283 caller == NULL means console.
284 **************************************************************************/
285 static char setting_status(struct connection
*caller
,
286 const struct setting
*pset
)
288 /* first check for a ruleset lock as this is included in
289 * setting_is_changeable() */
290 if (setting_locked(pset
)) {
291 /* setting is locked by the ruleset */
295 if (setting_is_changeable(pset
, caller
, NULL
, 0)) {
296 /* setting can be changed */
300 /* setting is fixed */
304 /**************************************************************************
305 feedback related to server commands
306 caller == NULL means console.
307 No longer duplicate all output to console.
309 This lowlevel function takes a single line; prefix is prepended to line.
310 **************************************************************************/
311 static void cmd_reply_line(enum command_id cmd
, struct connection
*caller
,
312 enum rfc_status rfc_status
, const char *prefix
,
315 const char *cmdname
= cmd
< CMD_NUM
316 ? command_name_by_number(cmd
)
317 : cmd
== CMD_AMBIGUOUS
318 /* TRANS: ambiguous command */
320 : cmd
== CMD_UNRECOGNIZED
321 /* TRANS: unrecognized command */
323 : "(?!?)"; /* this case is a bug! */
326 notify_conn(caller
->self
, NULL
, E_SETTING
, ftc_command
,
327 "/%s: %s%s", cmdname
, prefix
, line
);
328 /* cc: to the console - testing has proved it's too verbose - rp
329 con_write(rfc_status, "%s/%s: %s%s", caller->name, cmdname, prefix, line);
332 con_write(rfc_status
, "%s%s", prefix
, line
);
335 if (rfc_status
== C_OK
) {
336 struct packet_chat_msg packet
;
338 package_event(&packet
, NULL
, E_SETTING
, ftc_server
, "%s", line
);
339 conn_list_iterate(game
.est_connections
, pconn
) {
340 /* Do not tell caller, since he was told above! */
341 if (caller
!= pconn
) {
342 send_packet_chat_msg(pconn
, &packet
);
344 } conn_list_iterate_end
;
345 event_cache_add_for_all(&packet
);
347 if (NULL
!= caller
) {
348 /* Echo to the console. */
349 log_normal("%s", line
);
354 /**************************************************************************
355 va_list version which allow embedded newlines, and each line is sent
356 separately. 'prefix' is prepended to every line _after_ the first line.
357 **************************************************************************/
358 static void vcmd_reply_prefix(enum command_id cmd
, struct connection
*caller
,
359 enum rfc_status rfc_status
, const char *prefix
,
360 const char *format
, va_list ap
)
365 fc_vsnprintf(buf
, sizeof(buf
), format
, ap
);
368 while ((c1
=strstr(c0
, "\n"))) {
370 cmd_reply_line(cmd
, caller
, rfc_status
, (c0
==buf
?"":prefix
), c0
);
373 cmd_reply_line(cmd
, caller
, rfc_status
, (c0
==buf
?"":prefix
), c0
);
376 /**************************************************************************
377 var-args version of above
378 duplicate declaration required for attribute to work...
379 **************************************************************************/
380 static void cmd_reply_prefix(enum command_id cmd
, struct connection
*caller
,
381 enum rfc_status rfc_status
, const char *prefix
,
382 const char *format
, ...)
383 fc__attribute((__format__ (__printf__
, 5, 6)));
384 static void cmd_reply_prefix(enum command_id cmd
, struct connection
*caller
,
385 enum rfc_status rfc_status
, const char *prefix
,
386 const char *format
, ...)
389 va_start(ap
, format
);
390 vcmd_reply_prefix(cmd
, caller
, rfc_status
, prefix
, format
, ap
);
394 /**************************************************************************
395 var-args version as above, no prefix
396 **************************************************************************/
397 void cmd_reply(enum command_id cmd
, struct connection
*caller
,
398 enum rfc_status rfc_status
, const char *format
, ...)
401 va_start(ap
, format
);
402 vcmd_reply_prefix(cmd
, caller
, rfc_status
, "", format
, ap
);
406 /**************************************************************************
407 Command specific argument parsing has detected that player argument
408 is invalid. This function is common handling for that situation.
409 **************************************************************************/
410 static void cmd_reply_no_such_player(enum command_id cmd
,
411 struct connection
*caller
,
413 enum m_pre_result match_result
)
415 switch(match_result
) {
417 cmd_reply(cmd
, caller
, C_SYNTAX
,
418 _("Name is empty, so cannot be a player."));
421 cmd_reply(cmd
, caller
, C_SYNTAX
,
422 _("Name is too long, so cannot be a player."));
424 case M_PRE_AMBIGUOUS
:
425 cmd_reply(cmd
, caller
, C_FAIL
,
426 _("Player name prefix '%s' is ambiguous."), name
);
429 cmd_reply(cmd
, caller
, C_FAIL
,
430 _("No player by the name of '%s'."), name
);
433 cmd_reply(cmd
, caller
, C_FAIL
,
434 _("Unexpected match_result %d (%s) for '%s'."),
435 match_result
, _(m_pre_description(match_result
)), name
);
436 log_error("Unexpected match_result %d (%s) for '%s'.",
437 match_result
, m_pre_description(match_result
), name
);
441 /**************************************************************************
442 Command specific argument parsing has detected that connection argument
443 is invalid. This function is common handling for that situation.
444 **************************************************************************/
445 static void cmd_reply_no_such_conn(enum command_id cmd
,
446 struct connection
*caller
,
448 enum m_pre_result match_result
)
450 switch(match_result
) {
452 cmd_reply(cmd
, caller
, C_SYNTAX
,
453 _("Name is empty, so cannot be a connection."));
456 cmd_reply(cmd
, caller
, C_SYNTAX
,
457 _("Name is too long, so cannot be a connection."));
459 case M_PRE_AMBIGUOUS
:
460 cmd_reply(cmd
, caller
, C_FAIL
,
461 _("Connection name prefix '%s' is ambiguous."), name
);
464 cmd_reply(cmd
, caller
, C_FAIL
,
465 _("No connection by the name of '%s'."), name
);
468 cmd_reply(cmd
, caller
, C_FAIL
,
469 _("Unexpected match_result %d (%s) for '%s'."),
470 match_result
, _(m_pre_description(match_result
)), name
);
471 log_error("Unexpected match_result %d (%s) for '%s'.",
472 match_result
, m_pre_description(match_result
), name
);
476 /**************************************************************************
477 Start sending game info to metaserver.
478 **************************************************************************/
479 static void open_metaserver_connection(struct connection
*caller
)
482 if (send_server_info_to_metaserver(META_INFO
)) {
483 cmd_reply(CMD_METACONN
, caller
, C_OK
,
484 _("Open metaserver connection to [%s]."),
489 /**************************************************************************
490 Stop sending game info to metaserver.
491 **************************************************************************/
492 static void close_metaserver_connection(struct connection
*caller
)
494 if (send_server_info_to_metaserver(META_GOODBYE
)) {
496 cmd_reply(CMD_METACONN
, caller
, C_OK
,
497 _("Close metaserver connection to [%s]."),
502 /**************************************************************************
503 Handle metaconnection command.
504 **************************************************************************/
505 static bool metaconnection_command(struct connection
*caller
, char *arg
,
508 if ((*arg
== '\0') ||
509 (0 == strcmp (arg
, "?"))) {
510 if (is_metaserver_open()) {
511 cmd_reply(CMD_METACONN
, caller
, C_COMMENT
,
512 _("Metaserver connection is open."));
514 cmd_reply(CMD_METACONN
, caller
, C_COMMENT
,
515 _("Metaserver connection is closed."));
517 } else if (0 == fc_strcasecmp(arg
, "u")
518 || 0 == fc_strcasecmp(arg
, "up")) {
519 if (!is_metaserver_open()) {
521 open_metaserver_connection(caller
);
524 cmd_reply(CMD_METACONN
, caller
, C_METAERROR
,
525 _("Metaserver connection is already open."));
528 } else if (0 == fc_strcasecmp(arg
, "d")
529 || 0 == fc_strcasecmp(arg
, "down")) {
530 if (is_metaserver_open()) {
532 close_metaserver_connection(caller
);
535 cmd_reply(CMD_METACONN
, caller
, C_METAERROR
,
536 _("Metaserver connection is already closed."));
540 cmd_reply(CMD_METACONN
, caller
, C_METAERROR
,
541 _("Argument must be 'u', 'up', 'd', 'down', or '?'."));
547 /**************************************************************************
548 Handle metapatches command.
549 **************************************************************************/
550 static bool metapatches_command(struct connection
*caller
,
551 char *arg
, bool check
)
557 set_meta_patches_string(arg
);
559 if (is_metaserver_open()) {
560 send_server_info_to_metaserver(META_INFO
);
561 cmd_reply(CMD_METAPATCHES
, caller
, C_OK
,
562 _("Metaserver patches string set to '%s'."), arg
);
564 cmd_reply(CMD_METAPATCHES
, caller
, C_OK
,
565 _("Metaserver patches string set to '%s', "
566 "not reporting to metaserver."), arg
);
572 /**************************************************************************
573 Handle metamessage command.
574 **************************************************************************/
575 static bool metamessage_command(struct connection
*caller
,
576 char *arg
, bool check
)
582 set_user_meta_message_string(arg
);
583 if (is_metaserver_open()) {
584 send_server_info_to_metaserver(META_INFO
);
585 cmd_reply(CMD_METAMESSAGE
, caller
, C_OK
,
586 _("Metaserver message string set to '%s'."), arg
);
588 cmd_reply(CMD_METAMESSAGE
, caller
, C_OK
,
589 _("Metaserver message string set to '%s', "
590 "not reporting to metaserver."), arg
);
596 /**************************************************************************
597 Handle metaserver command.
598 **************************************************************************/
599 static bool metaserver_command(struct connection
*caller
, char *arg
,
605 close_metaserver_connection(caller
);
607 sz_strlcpy(srvarg
.metaserver_addr
, arg
);
609 cmd_reply(CMD_METASERVER
, caller
, C_OK
,
610 _("Metaserver is now [%s]."), meta_addr_port());
614 /**************************************************************************
616 **************************************************************************/
617 static bool show_serverid(struct connection
*caller
, char *arg
)
619 cmd_reply(CMD_SRVID
, caller
, C_COMMENT
, _("Server id: %s"), srvarg
.serverid
);
624 /***************************************************************
625 Returns handicap bitvector for given AI skill level
626 ***************************************************************/
627 static bv_handicap
handicap_of_skill_level(int level
)
629 bv_handicap handicap
;
631 fc_assert(level
> 0 && level
<= 10);
633 BV_CLR_ALL(handicap
);
637 BV_SET(handicap
, H_AWAY
);
638 BV_SET(handicap
, H_FOG
);
639 BV_SET(handicap
, H_MAP
);
640 BV_SET(handicap
, H_RATES
);
641 BV_SET(handicap
, H_TARGETS
);
642 BV_SET(handicap
, H_HUTS
);
643 BV_SET(handicap
, H_REVOLUTION
);
645 case AI_LEVEL_NOVICE
:
646 BV_SET(handicap
, H_RATES
);
647 BV_SET(handicap
, H_TARGETS
);
648 BV_SET(handicap
, H_HUTS
);
649 BV_SET(handicap
, H_NOPLANES
);
650 BV_SET(handicap
, H_DIPLOMAT
);
651 BV_SET(handicap
, H_LIMITEDHUTS
);
652 BV_SET(handicap
, H_DEFENSIVE
);
653 BV_SET(handicap
, H_REVOLUTION
);
654 BV_SET(handicap
, H_EXPANSION
);
655 BV_SET(handicap
, H_DANGER
);
658 BV_SET(handicap
, H_RATES
);
659 BV_SET(handicap
, H_TARGETS
);
660 BV_SET(handicap
, H_HUTS
);
661 BV_SET(handicap
, H_NOPLANES
);
662 BV_SET(handicap
, H_DIPLOMAT
);
663 BV_SET(handicap
, H_LIMITEDHUTS
);
664 BV_SET(handicap
, H_DEFENSIVE
);
665 BV_SET(handicap
, H_DIPLOMACY
);
666 BV_SET(handicap
, H_REVOLUTION
);
667 BV_SET(handicap
, H_EXPANSION
);
669 case AI_LEVEL_NORMAL
:
670 BV_SET(handicap
, H_RATES
);
671 BV_SET(handicap
, H_TARGETS
);
672 BV_SET(handicap
, H_HUTS
);
673 BV_SET(handicap
, H_DIPLOMAT
);
675 case AI_LEVEL_EXPERIMENTAL
:
676 BV_SET(handicap
, H_EXPERIMENTAL
);
678 case AI_LEVEL_CHEATING
:
679 BV_SET(handicap
, H_RATES
);
686 /**************************************************************************
687 Return the AI fuzziness (0 to 1000) corresponding to a given skill
688 level (1 to 10). See ai_fuzzy() in common/player.c
689 **************************************************************************/
690 static int fuzzy_of_skill_level(int level
)
692 int f
[11] = { -1, 0, 400/*novice*/, 300/*easy*/, 0, 0, 0, 0, 0, 0, 0 };
694 fc_assert_ret_val(level
> 0 && level
<= 10, 0);
698 /**************************************************************************
699 Return the AI's science development cost; a science development cost of 100
700 means that the AI develops science at the same speed as a human; a science
701 development cost of 200 means that the AI develops science at half the speed
702 of a human, and a sceence development cost of 50 means that the AI develops
703 science twice as fast as the human
704 **************************************************************************/
705 static int science_cost_of_skill_level(int level
)
707 int x
[11] = { -1, 100, 250/*novice*/, 100/*easy*/, 100, 100, 100, 100,
710 fc_assert_ret_val(level
> 0 && level
<= 10, 0);
714 /**************************************************************************
715 Return the AI expansion tendency, a percentage factor to value new cities,
716 compared to defaults. 0 means _never_ build new cities, > 100 means to
717 (over?)value them even more than the default (already expansionistic) AI.
718 **************************************************************************/
719 static int expansionism_of_skill_level(int level
)
721 int x
[11] = { -1, 100, 10/*novice*/, 10/*easy*/, 100, 100, 100, 100,
724 fc_assert_ret_val(level
> 0 && level
<= 10, 0);
728 /**************************************************************************
729 For command "save foo";
730 Save the game, with filename=arg, provided server state is ok.
731 **************************************************************************/
732 static bool save_command(struct connection
*caller
, char *arg
, bool check
)
734 if (is_restricted(caller
)) {
735 cmd_reply(CMD_SAVE
, caller
, C_FAIL
,
736 _("You cannot save games manually on this server."));
740 save_game(arg
, "User request", FALSE
);
745 /**************************************************************************
746 For command "scensave foo";
747 Save the game, with filename=arg, provided server state is ok.
748 **************************************************************************/
750 static bool scensave_command(struct connection
*caller
, char *arg
, bool check
)
752 if (is_restricted(caller
)) {
753 cmd_reply(CMD_SAVE
, caller
, C_FAIL
,
754 _("You cannot save games manually on this server."));
758 save_game(arg
, "Scenario", TRUE
);
764 /**************************************************************************
765 Handle ai player ai toggling.
766 **************************************************************************/
767 void toggle_ai_player_direct(struct connection
*caller
, struct player
*pplayer
)
769 fc_assert_ret(pplayer
!= NULL
);
770 if (is_barbarian(pplayer
)) {
771 cmd_reply(CMD_AITOGGLE
, caller
, C_FAIL
,
772 _("Cannot toggle a barbarian player."));
776 pplayer
->ai_controlled
= !pplayer
->ai_controlled
;
777 if (pplayer
->ai_controlled
) {
778 cmd_reply(CMD_AITOGGLE
, caller
, C_OK
,
779 _("%s is now under AI control."),
780 player_name(pplayer
));
781 if (pplayer
->ai_common
.skill_level
== 0) {
782 pplayer
->ai_common
.skill_level
= game
.info
.skill_level
;
784 /* Set the skill level explicitly, because eg: the player skill
785 level could have been set as AI, then toggled, then saved,
787 set_ai_level(caller
, player_name(pplayer
),
788 pplayer
->ai_common
.skill_level
, FALSE
);
789 /* the AI can't do active diplomacy */
790 cancel_all_meetings(pplayer
);
792 CALL_PLR_AI_FUNC(gained_control
, pplayer
, pplayer
);
794 if (S_S_RUNNING
== server_state()) {
795 /* In case this was last player who has not pressed turn done. */
796 check_for_full_turn_done();
799 cmd_reply(CMD_AITOGGLE
, caller
, C_OK
,
800 _("%s is now under human control."),
801 player_name(pplayer
));
803 CALL_PLR_AI_FUNC(lost_control
, pplayer
, pplayer
);
805 /* because the AI `cheats' with government rates but humans shouldn't */
806 if (!game
.info
.is_new_game
) {
807 check_player_max_rates(pplayer
);
809 /* Remove hidden dialogs from clients. This way the player can initiate
811 cancel_all_meetings(pplayer
);
815 /**************************************************************************
816 Handle aitoggle command.
817 **************************************************************************/
818 static bool toggle_ai_command(struct connection
*caller
, char *arg
, bool check
)
820 enum m_pre_result match_result
;
821 struct player
*pplayer
;
823 pplayer
= player_by_name_prefix(arg
, &match_result
);
826 cmd_reply_no_such_player(CMD_AITOGGLE
, caller
, arg
, match_result
);
829 toggle_ai_player_direct(caller
, pplayer
);
830 send_player_info_c(pplayer
, game
.est_connections
);
835 /**************************************************************************
836 Creates a named AI player. The function can be called befor the start
837 of the game (see creat_command_pregame()) and for a running game
838 (see creat_command_newcomer(). In the later case, first free player slots
839 are used before the slots of dead players are (re)used.
840 **************************************************************************/
841 static bool create_command(struct connection
*caller
, const char *str
,
844 enum rfc_status status
;
845 char buf
[MAX_LEN_CONSOLE_LINE
];
847 /* 2 legal arguments, and extra space for stuffing illegal part */
850 const char *ai_type_name
;
852 sz_strlcpy(buf
, str
);
853 ntokens
= get_tokens(buf
, arg
, 3, TOKEN_DELIMITERS
);
856 ai_type_name
= default_ai_type_name();
857 } else if (ntokens
== 2) {
858 ai_type_name
= arg
[1];
860 cmd_reply(CMD_CREATE
, caller
, C_SYNTAX
,
861 _("Wrong number of arguments to create command."));
865 if (game_was_started()) {
866 status
= create_command_newcomer(arg
[0], ai_type_name
, check
,
867 NULL
, NULL
, buf
, sizeof(buf
));
869 status
= create_command_pregame(arg
[0], ai_type_name
, check
,
870 NULL
, buf
, sizeof(buf
));
873 if (status
!= C_OK
) {
874 /* No player created. */
875 cmd_reply(CMD_CREATE
, caller
, status
, "%s", buf
);
879 if (strlen(buf
) > 0) {
880 /* Send a notification. */
881 cmd_reply(CMD_CREATE
, caller
, C_OK
, "%s", buf
);
887 /**************************************************************************
888 Try to add a player to a running game in the following order:
890 1. Try to reuse the slot of a dead player with the username 'name'.
891 2. Try to reuse the slot of a dead player.
892 3. Try to use an empty player slot.
894 If 'pnation' is defined this nation is used for the new player.
895 **************************************************************************/
896 enum rfc_status
create_command_newcomer(const char *name
,
899 struct nation_type
*pnation
,
900 struct player
**newplayer
,
901 char *buf
, size_t buflen
)
903 struct player
*pplayer
= NULL
;
904 bool new_slot
= FALSE
;
906 /* Check player name. */
907 if (!player_name_check(name
, buf
, buflen
)) {
911 /* Check first if we can replace a player with
912 * [1a] - the same username. */
913 pplayer
= player_by_user(name
);
914 if (pplayer
&& pplayer
->is_alive
) {
915 fc_snprintf(buf
, buflen
,
916 _("A living user already exists by that name."));
920 /* [1b] - the same player name. */
921 pplayer
= player_by_name(name
);
922 if (pplayer
&& pplayer
->is_alive
) {
923 fc_snprintf(buf
, buflen
,
924 _("A living player already exists by that name."));
929 if (!nation_is_in_current_set(pnation
)) {
930 fc_snprintf(buf
, buflen
,
931 _("Can't create player, requested nation %s not in "
932 "current nationset."),
933 nation_plural_translation(pnation
));
936 players_iterate(aplayer
) {
937 if (0 > nations_match(pnation
, nation_of_player(aplayer
), FALSE
)) {
938 fc_snprintf(buf
, buflen
,
939 _("Can't create players, nation %s conflicts with %s."),
940 nation_plural_for_player(aplayer
),
941 nation_plural_for_player(pplayer
));
944 } players_iterate_end
;
946 /* Try to find a nation. */
947 pnation
= pick_a_nation(NULL
, FALSE
, TRUE
, NOT_A_BARBARIAN
);
948 if (pnation
== NO_NATION_SELECTED
) {
949 fc_snprintf(buf
, buflen
,
950 _("Can't create players, no nations available."));
956 /* All code below will change the game state. */
958 /* Return an empty string. */
965 /* [1] Replace a player. 'pplayer' was set above. */
966 fc_snprintf(buf
, buflen
,
967 _("%s is replacing dead player %s as an AI-controlled "
968 "player."), name
, player_name(pplayer
));
969 /* remove player and thus free a player slot */
970 server_remove_player(pplayer
);
972 } else if (player_count() == player_slot_count()) {
973 /* [2] All player slots are used; try to remove a dead player. */
974 players_iterate(aplayer
) {
975 if (!aplayer
->is_alive
) {
976 fc_snprintf(buf
, buflen
,
977 _("%s is replacing dead player %s as an AI-controlled "
978 "player."), name
, player_name(aplayer
));
979 /* remove player and thus free a player slot */
980 server_remove_player(aplayer
);
982 } players_iterate_end
;
984 /* [3] An empty player slot must be used for the new player. */
989 if (normal_player_count() == game
.server
.max_players
) {
991 fc_assert(game
.server
.max_players
< MAX_NUM_PLAYERS
);
993 game
.server
.max_players
++;
994 log_debug("Increased 'maxplayers' for creation of a new player.");
998 /* Create the new player. */
999 pplayer
= server_create_player(-1, ai
, NULL
);
1001 fc_snprintf(buf
, buflen
, _("Failed to create new player %s."), name
);
1006 /* 'buf' must be set if a new player slot is used. */
1007 fc_snprintf(buf
, buflen
, _("New player %s created."), name
);
1010 /* We have a player; now initialise all needed data. */
1011 aifill(game
.info
.aifill
);
1013 /* Initialise player. */
1014 server_player_init(pplayer
, TRUE
, TRUE
);
1016 player_set_nation(pplayer
, pnation
);
1017 pplayer
->government
= pnation
->init_government
;
1018 pplayer
->target_government
= pnation
->init_government
;
1019 /* Find a color for the new player. */
1020 assign_player_colors();
1022 /* TRANS: keep one space at the beginning of the string. */
1023 cat_snprintf(buf
, buflen
, _(" Nation of the new player: %s."),
1024 nation_rule_name(pnation
));
1026 init_tech(pplayer
, TRUE
);
1027 give_global_initial_techs(pplayer
);
1028 give_nation_initial_techs(pplayer
);
1030 server_player_set_name(pplayer
, name
);
1031 sz_strlcpy(pplayer
->username
, ANON_USER_NAME
);
1033 pplayer
->was_created
= TRUE
; /* must use /remove explicitly to remove */
1034 pplayer
->ai_controlled
= TRUE
;
1035 set_ai_level_directer(pplayer
, game
.info
.skill_level
);
1037 CALL_PLR_AI_FUNC(gained_control
, pplayer
, pplayer
);
1039 send_player_info_c(pplayer
, NULL
);
1040 /* Send updated diplstate information to all players. */
1041 send_player_diplstate_c(NULL
, NULL
);
1042 (void) send_server_info_to_metaserver(META_INFO
);
1044 if (newplayer
!= NULL
) {
1045 *newplayer
= pplayer
;
1050 /**************************************************************************
1051 Create player in pregame.
1052 **************************************************************************/
1053 enum rfc_status
create_command_pregame(const char *name
,
1056 struct player
**newplayer
,
1057 char *buf
, size_t buflen
)
1059 struct player
*pplayer
= NULL
;
1061 if (!player_name_check(name
, buf
, buflen
)) {
1065 if (NULL
!= player_by_name(name
)) {
1066 fc_snprintf(buf
, buflen
,
1067 _("A player already exists by that name."));
1070 if (NULL
!= player_by_user(name
)) {
1071 fc_snprintf(buf
, buflen
,
1072 _("A user already exists by that name."));
1076 /* Search for first uncontrolled player */
1077 pplayer
= find_uncontrolled_player();
1079 if (NULL
== pplayer
) {
1080 /* Check that we are not going over max players setting */
1081 if (normal_player_count() >= game
.server
.max_players
) {
1082 fc_snprintf(buf
, buflen
,
1083 _("Can't add more players, server is full."));
1086 /* Check that we have nations available */
1087 if (normal_player_count() >= server
.playable_nations
) {
1088 fc_snprintf(buf
, buflen
,
1089 _("Can't add more players, not enough nations."));
1095 struct ai_type
*ait
= ai_type_by_name(ai
);
1098 fc_snprintf(buf
, buflen
,
1099 _("There is no AI type %s."), ai
);
1105 /* All code below will change the game state. */
1107 /* Return an empty string. */
1114 fc_snprintf(buf
, buflen
,
1115 /* TRANS: <name> replacing <name> ... */
1116 _("%s replacing %s as an AI-controlled player."),
1117 name
, player_name(pplayer
));
1119 team_remove_player(pplayer
);
1120 pplayer
->ai
= ai_type_by_name(ai
);
1122 /* add new player */
1123 pplayer
= server_create_player(-1, ai
, NULL
);
1124 /* pregame so no need to assign_player_colors() */
1126 fc_snprintf(buf
, buflen
,
1127 _("Failed to create new player %s."), name
);
1131 fc_snprintf(buf
, buflen
,
1132 _("%s has been added as an AI-controlled player (%s)."),
1133 name
, ai_name(pplayer
->ai
));
1135 server_player_init(pplayer
, FALSE
, TRUE
);
1137 server_player_set_name(pplayer
, name
);
1138 sz_strlcpy(pplayer
->username
, ANON_USER_NAME
);
1140 pplayer
->was_created
= TRUE
; /* must use /remove explicitly to remove */
1141 pplayer
->ai_controlled
= TRUE
;
1142 set_ai_level_directer(pplayer
, game
.info
.skill_level
);
1143 CALL_PLR_AI_FUNC(gained_control
, pplayer
, pplayer
);
1144 send_player_info_c(pplayer
, game
.est_connections
);
1146 aifill(game
.info
.aifill
);
1147 reset_all_start_commands();
1148 (void) send_server_info_to_metaserver(META_INFO
);
1150 if (newplayer
!= NULL
) {
1151 *newplayer
= pplayer
;
1156 /**************************************************************************
1157 Handle remove command.
1158 **************************************************************************/
1159 static bool remove_player_command(struct connection
*caller
, char *arg
,
1162 enum m_pre_result match_result
;
1163 struct player
*pplayer
;
1164 char name
[MAX_LEN_NAME
];
1166 pplayer
= player_by_name_prefix(arg
, &match_result
);
1168 if (NULL
== pplayer
) {
1169 cmd_reply_no_such_player(CMD_REMOVE
, caller
, arg
, match_result
);
1173 if (game_was_started() && caller
&& caller
->access_level
< ALLOW_ADMIN
) {
1174 cmd_reply(CMD_REMOVE
, caller
, C_FAIL
,
1175 _("Command level '%s' or greater needed to remove a player "
1176 "once the game has started."), cmdlevel_name(ALLOW_ADMIN
));
1183 sz_strlcpy(name
, player_name(pplayer
));
1184 server_remove_player(pplayer
);
1185 if (!caller
|| caller
->used
) { /* may have removed self */
1186 cmd_reply(CMD_REMOVE
, caller
, C_OK
,
1187 _("Removed player %s from the game."), name
);
1189 aifill(game
.info
.aifill
);
1193 /**************************************************************************
1194 Main entry point for the read command.
1195 **************************************************************************/
1196 static bool read_command(struct connection
*caller
, char *arg
, bool check
,
1199 return read_init_script_real(caller
, arg
, FALSE
, check
, read_recursion
);
1202 /**************************************************************************
1203 Main entry point for reading an init script.
1204 **************************************************************************/
1205 bool read_init_script(struct connection
*caller
, char *script_filename
,
1206 bool from_cmdline
, bool check
)
1208 return read_init_script_real(caller
, script_filename
, from_cmdline
,
1212 /**************************************************************************
1213 Returns FALSE iff there was an error.
1215 Security: We will look for a file with mandatory extension '.serv',
1216 and on public servers we will not look outside the data directories.
1217 As long as the user cannot create files with arbitrary names in the
1218 root of the data directories, this should ensure that we will not be
1219 tricked into loading non-approved content. The script is read with the
1220 permissions of the caller, so it will in any case not lead to elevated
1221 permissions unless there are other bugs.
1222 **************************************************************************/
1223 static bool read_init_script_real(struct connection
*caller
,
1224 char *script_filename
, bool from_cmdline
,
1225 bool check
, int read_recursion
)
1228 const char extension
[] = ".serv";
1229 char serv_filename
[strlen(extension
) + strlen(script_filename
) + 2];
1230 char tilde_filename
[4096];
1231 const char *real_filename
;
1233 /* check recursion depth */
1234 if (read_recursion
> GAME_MAX_READ_RECURSION
) {
1235 log_error("Error: recursive calls to read!");
1239 /* abuse real_filename to find if we already have a .serv extension */
1240 real_filename
= script_filename
+ strlen(script_filename
)
1241 - MIN(strlen(extension
), strlen(script_filename
));
1242 if (strcmp(real_filename
, extension
) != 0) {
1243 fc_snprintf(serv_filename
, sizeof(serv_filename
), "%s%s",
1244 script_filename
, extension
);
1246 sz_strlcpy(serv_filename
, script_filename
);
1249 if (is_restricted(caller
) && !from_cmdline
) {
1250 if (!is_safe_filename(serv_filename
)) {
1251 cmd_reply(CMD_READ_SCRIPT
, caller
, C_FAIL
,
1252 _("Name \"%s\" disallowed for security reasons."),
1256 sz_strlcpy(tilde_filename
, serv_filename
);
1258 interpret_tilde(tilde_filename
, sizeof(tilde_filename
), serv_filename
);
1261 real_filename
= fileinfoname(get_data_dirs(), tilde_filename
);
1262 if (!real_filename
) {
1263 if (is_restricted(caller
) && !from_cmdline
) {
1264 cmd_reply(CMD_READ_SCRIPT
, caller
, C_FAIL
,
1265 _("No command script found by the name \"%s\"."),
1269 /* File is outside data directories */
1270 real_filename
= tilde_filename
;
1273 log_normal(_("Loading script file '%s'."), real_filename
);
1275 if (is_reg_file_for_access(real_filename
, FALSE
)
1276 && (script_file
= fc_fopen(real_filename
, "r"))) {
1277 char buffer
[MAX_LEN_CONSOLE_LINE
];
1279 /* the size is set as to not overflow buffer in handle_stdin_input */
1280 while (fgets(buffer
, MAX_LEN_CONSOLE_LINE
- 1, script_file
)) {
1281 /* Execute script contents with same permissions as caller */
1282 handle_stdin_input_real(caller
, buffer
, check
, read_recursion
+ 1);
1284 fclose(script_file
);
1286 show_changed(caller
, check
, read_recursion
);
1290 cmd_reply(CMD_READ_SCRIPT
, caller
, C_FAIL
,
1291 _("Cannot read command line scriptfile '%s'."), real_filename
);
1292 if (NULL
!= caller
) {
1293 log_error(_("Could not read script file '%s'."), real_filename
);
1299 /**************************************************************************
1300 Write current settings to new init script.
1302 (Should this take a 'caller' argument for output? --dwp)
1303 **************************************************************************/
1304 static void write_init_script(char *script_filename
)
1306 char real_filename
[1024], buf
[256];
1309 interpret_tilde(real_filename
, sizeof(real_filename
), script_filename
);
1311 if (is_reg_file_for_access(real_filename
, TRUE
)
1312 && (script_file
= fc_fopen(real_filename
, "w"))) {
1313 fprintf(script_file
,
1314 "#FREECIV SERVER COMMAND FILE, version %s\n", VERSION_STRING
);
1315 fputs("# These are server options saved from a running freeciv-server.\n",
1318 /* first, some state info from commands (we can't save everything) */
1320 fprintf(script_file
, "cmdlevel %s new\n",
1321 cmdlevel_name(default_access_level
));
1323 fprintf(script_file
, "cmdlevel %s first\n",
1324 cmdlevel_name(first_access_level
));
1326 fprintf(script_file
, "%s\n",
1327 ai_level_cmd(game
.info
.skill_level
));
1329 if (*srvarg
.metaserver_addr
!= '\0' &&
1330 ((0 != strcmp(srvarg
.metaserver_addr
, DEFAULT_META_SERVER_ADDR
)))) {
1331 fprintf(script_file
, "metaserver %s\n", meta_addr_port());
1334 if (0 != strcmp(get_meta_patches_string(), default_meta_patches_string())) {
1335 fprintf(script_file
, "metapatches %s\n", get_meta_patches_string());
1337 if (0 != strcmp(get_meta_message_string(), default_meta_message_string())) {
1338 fprintf(script_file
, "metamessage %s\n", get_meta_message_string());
1341 /* then, the 'set' option settings */
1343 settings_iterate(SSET_ALL
, pset
) {
1344 fprintf(script_file
, "set %s \"%s\"\n", setting_name(pset
),
1345 setting_value_name(pset
, FALSE
, buf
, sizeof(buf
)));
1346 } settings_iterate_end
;
1349 fprintf(script_file
, "rulesetdir %s\n", game
.server
.rulesetdir
);
1351 fclose(script_file
);
1354 log_error(_("Could not write script file '%s'."), real_filename
);
1358 /**************************************************************************
1359 Generate init script from settings currently in use
1360 **************************************************************************/
1361 static bool write_command(struct connection
*caller
, char *arg
, bool check
)
1363 if (is_restricted(caller
)) {
1364 cmd_reply(CMD_WRITE_SCRIPT
, caller
, C_FAIL
,
1365 _("You cannot use the write command on this server"
1366 " for security reasons."));
1368 } else if (!check
) {
1369 write_init_script(arg
);
1374 /**************************************************************************
1375 set ptarget's cmdlevel to level if caller is allowed to do so
1376 **************************************************************************/
1377 static bool set_cmdlevel(struct connection
*caller
,
1378 struct connection
*ptarget
,
1379 enum cmdlevel level
)
1381 /* Only ever call me for specific connection. */
1382 fc_assert_ret_val(ptarget
!= NULL
, FALSE
);
1384 if (caller
&& ptarget
->access_level
> caller
->access_level
) {
1386 * This command is intended to be used at ctrl access level
1387 * and thus this if clause is needed.
1388 * (Imagine a ctrl level access player that wants to change
1389 * access level of a hack level access player)
1390 * At the moment it can be used only by hack access level
1391 * and thus this clause is never used.
1393 cmd_reply(CMD_CMDLEVEL
, caller
, C_FAIL
,
1394 _("Cannot decrease command access level '%s' "
1395 "for connection '%s'; you only have '%s'."),
1396 cmdlevel_name(ptarget
->access_level
),
1398 cmdlevel_name(caller
->access_level
));
1401 conn_set_access(ptarget
, level
, TRUE
);
1402 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1403 _("Command access level set to '%s' for connection %s."),
1404 cmdlevel_name(level
), ptarget
->username
);
1409 /********************************************************************
1410 Returns true if there is at least one established connection.
1411 *********************************************************************/
1412 static bool a_connection_exists(void)
1414 return conn_list_size(game
.est_connections
) > 0;
1417 /********************************************************************
1418 Return whether first access level is already taken.
1419 *********************************************************************/
1420 static bool is_first_access_level_taken(void)
1422 conn_list_iterate(game
.est_connections
, pconn
) {
1423 if (pconn
->access_level
>= first_access_level
) {
1427 conn_list_iterate_end
;
1431 /********************************************************************
1432 Return access level for next connection
1433 *********************************************************************/
1434 enum cmdlevel
access_level_for_next_connection(void)
1436 if ((first_access_level
> default_access_level
)
1437 && !a_connection_exists()) {
1438 return first_access_level
;
1440 return default_access_level
;
1444 /********************************************************************
1445 Check if first access level is available and if it is, notify
1446 connections about it.
1447 *********************************************************************/
1448 void notify_if_first_access_level_is_available(void)
1450 if (first_access_level
> default_access_level
1451 && !is_first_access_level_taken()) {
1452 notify_conn(NULL
, NULL
, E_SETTING
, ftc_any
,
1453 _("Anyone can now become game organizer "
1454 "'%s' by issuing the 'first' command."),
1455 cmdlevel_name(first_access_level
));
1459 /**************************************************************************
1460 Change command access level for individual player, or all, or new.
1461 **************************************************************************/
1462 static bool cmdlevel_command(struct connection
*caller
, char *str
, bool check
)
1467 enum m_pre_result match_result
;
1468 enum cmdlevel level
;
1469 struct connection
*ptarget
;
1471 ntokens
= get_tokens(str
, arg
, 2, TOKEN_DELIMITERS
);
1474 /* No argument supplied; list the levels */
1475 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
, horiz_line
);
1476 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
,
1477 _("Command access levels in effect:"));
1478 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
, horiz_line
);
1479 conn_list_iterate(game
.est_connections
, pconn
) {
1480 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
, "cmdlevel %s %s",
1481 cmdlevel_name(conn_get_access(pconn
)), pconn
->username
);
1482 } conn_list_iterate_end
;
1483 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
,
1484 _("Command access level for new connections: %s"),
1485 cmdlevel_name(default_access_level
));
1486 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
,
1487 _("Command access level for first player to take it: %s"),
1488 cmdlevel_name(first_access_level
));
1489 cmd_reply(CMD_CMDLEVEL
, caller
, C_COMMENT
, horiz_line
);
1493 /* A level name was supplied; set the level. */
1494 level
= cmdlevel_by_name(arg
[0], fc_strcasecmp
);
1495 if (!cmdlevel_is_valid(level
)) {
1496 const char *cmdlevel_names
[CMDLEVEL_COUNT
];
1497 struct astring astr
= ASTRING_INIT
;
1500 for (level
= cmdlevel_begin(); level
!= cmdlevel_end();
1501 level
= cmdlevel_next(level
)) {
1502 cmdlevel_names
[i
++] = cmdlevel_name(level
);
1504 cmd_reply(CMD_CMDLEVEL
, caller
, C_SYNTAX
,
1505 /* TRANS: comma and 'or' separated list of access levels */
1506 _("Command access level must be one of %s."),
1507 astr_build_or_list(&astr
, cmdlevel_names
, i
));
1510 } else if (caller
&& level
> conn_get_access(caller
)) {
1511 cmd_reply(CMD_CMDLEVEL
, caller
, C_FAIL
,
1512 _("Cannot increase command access level to '%s';"
1513 " you only have '%s' yourself."),
1514 arg
[0], cmdlevel_name(conn_get_access(caller
)));
1519 return TRUE
; /* looks good */
1523 /* No playername supplied: set for all connections */
1524 conn_list_iterate(game
.est_connections
, pconn
) {
1525 if (pconn
!= caller
) {
1526 (void) set_cmdlevel(caller
, pconn
, level
);
1528 } conn_list_iterate_end
;
1530 /* Set the caller access level at last, because it could make the
1531 * previous operations impossible if set before. */
1533 (void) set_cmdlevel(caller
, caller
, level
);
1536 /* Set default access for new connections. */
1537 default_access_level
= level
;
1538 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1539 _("Command access level set to '%s' for new players."),
1540 cmdlevel_name(level
));
1541 /* Set default access for first connection. */
1542 first_access_level
= level
;
1543 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1544 _("Command access level set to '%s' "
1545 "for first player to grab it."),
1546 cmdlevel_name(level
));
1550 } else if (fc_strcasecmp(arg
[1], "new") == 0) {
1551 default_access_level
= level
;
1552 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1553 _("Command access level set to '%s' for new players."),
1554 cmdlevel_name(level
));
1555 if (level
> first_access_level
) {
1556 first_access_level
= level
;
1557 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1558 _("Command access level set to '%s' "
1559 "for first player to grab it."),
1560 cmdlevel_name(level
));
1565 } else if (fc_strcasecmp(arg
[1], "first") == 0) {
1566 first_access_level
= level
;
1567 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1568 _("Command access level set to '%s' "
1569 "for first player to grab it."),
1570 cmdlevel_name(level
));
1571 if (level
< default_access_level
) {
1572 default_access_level
= level
;
1573 cmd_reply(CMD_CMDLEVEL
, caller
, C_OK
,
1574 _("Command access level set to '%s' for new players."),
1575 cmdlevel_name(level
));
1580 } else if ((ptarget
= conn_by_user_prefix(arg
[1], &match_result
))) {
1581 if (set_cmdlevel(caller
, ptarget
, level
)) {
1585 cmd_reply_no_such_conn(CMD_CMDLEVEL
, caller
, arg
[1], match_result
);
1589 free_tokens(arg
, ntokens
);
1593 /**************************************************************************
1594 This special command to set the command access level is not included into
1595 cmdlevel_command because of its lower access level: it can be used
1596 to promote one's own connection to 'first come' cmdlevel if that isn't
1598 **************************************************************************/
1599 static bool firstlevel_command(struct connection
*caller
, bool check
)
1602 cmd_reply(CMD_FIRSTLEVEL
, caller
, C_FAIL
,
1603 _("The 'first' command makes no sense from the server command line."));
1605 } else if (caller
->access_level
>= first_access_level
) {
1606 cmd_reply(CMD_FIRSTLEVEL
, caller
, C_FAIL
,
1607 _("You already have command access level '%s' or better."),
1608 cmdlevel_name(first_access_level
));
1610 } else if (is_first_access_level_taken()) {
1611 cmd_reply(CMD_FIRSTLEVEL
, caller
, C_FAIL
,
1612 _("Someone else is already game organizer."));
1614 } else if (!check
) {
1615 conn_set_access(caller
, first_access_level
, FALSE
);
1616 cmd_reply(CMD_FIRSTLEVEL
, caller
, C_OK
,
1617 _("Connection %s has opted to become the game organizer."),
1624 /**************************************************************************
1625 Returns possible parameters for the commands that take server options
1626 as parameters (CMD_EXPLAIN and CMD_SET).
1627 **************************************************************************/
1628 static const char *optname_accessor(int i
)
1630 return setting_name(setting_by_number(i
));
1633 #ifdef HAVE_LIBREADLINE
1634 /**************************************************************************
1635 Returns possible parameters for the /show command.
1636 **************************************************************************/
1637 static const char *olvlname_accessor(int i
)
1640 return "rulesetdir";
1641 } else if (i
< OLEVELS_NUM
+1) {
1642 return sset_level_name(i
-1);
1644 return optname_accessor(i
-OLEVELS_NUM
-1);
1647 #endif /* HAVE_LIBREADLINE */
1649 /**************************************************************************
1650 Set timeout options.
1651 **************************************************************************/
1652 static bool timeout_command(struct connection
*caller
, char *str
, bool check
)
1654 char buf
[MAX_LEN_CONSOLE_LINE
];
1659 timeouts
[0] = &game
.server
.timeoutint
;
1660 timeouts
[1] = &game
.server
.timeoutintinc
;
1661 timeouts
[2] = &game
.server
.timeoutinc
;
1662 timeouts
[3] = &game
.server
.timeoutincmult
;
1664 sz_strlcpy(buf
, str
);
1665 ntokens
= get_tokens(buf
, arg
, 4, TOKEN_DELIMITERS
);
1667 for (i
= 0; i
< ntokens
; i
++) {
1668 if (!str_to_int(arg
[i
], timeouts
[i
])) {
1669 cmd_reply(CMD_TIMEOUT
, caller
, C_FAIL
, _("Invalid argument %d."),
1676 cmd_reply(CMD_TIMEOUT
, caller
, C_SYNTAX
, _("Usage:\n%s"),
1677 command_synopsis(command_by_number(CMD_TIMEOUT
)));
1683 cmd_reply(CMD_TIMEOUT
, caller
, C_OK
, _("Dynamic timeout set to "
1685 game
.server
.timeoutint
, game
.server
.timeoutintinc
,
1686 game
.server
.timeoutinc
, game
.server
.timeoutincmult
);
1688 /* if we set anything here, reset the counter */
1689 game
.server
.timeoutcounter
= 1;
1693 /**************************************************************************
1694 Find option level number by name.
1695 **************************************************************************/
1696 static enum sset_level
lookup_option_level(const char *name
)
1700 for (i
= SSET_ALL
; i
< OLEVELS_NUM
; i
++) {
1701 if (0 == fc_strcasecmp(name
, sset_level_name(i
))) {
1709 /* Special return values of lookup options */
1710 #define LOOKUP_OPTION_NO_RESULT (-1)
1711 #define LOOKUP_OPTION_AMBIGUOUS (-2)
1712 #define LOOKUP_OPTION_LEVEL_NAME (-3)
1713 #define LOOKUP_OPTION_RULESETDIR (-4)
1715 /**************************************************************************
1716 Find option index by name. Return index (>=0) on success, else returned
1717 - LOOKUP_OPTION_NO_RESULT if no suitable options were found
1718 - LOOKUP_OPTION_AMBIGUOUS if several matches were found
1719 - LOOKUP_OPTION_LEVEL_NAME if it is an option level
1720 - LOOKUP_OPTION_RULESETDIR if the argument is rulesetdir (special case)
1721 **************************************************************************/
1722 static int lookup_option(const char *name
)
1724 enum m_pre_result result
;
1727 /* Check for option levels, first off */
1728 if (lookup_option_level(name
) != SSET_NONE
) {
1729 return LOOKUP_OPTION_LEVEL_NAME
;
1732 result
= match_prefix(optname_accessor
, settings_number(),
1733 0, fc_strncasecmp
, NULL
, name
, &ind
);
1734 if (M_PRE_AMBIGUOUS
> result
) {
1736 } else if (M_PRE_AMBIGUOUS
== result
) {
1737 return LOOKUP_OPTION_AMBIGUOUS
;
1738 } else if ('\0' != name
[0]
1739 && 0 == fc_strncasecmp("rulesetdir", name
, strlen(name
))) {
1740 return LOOKUP_OPTION_RULESETDIR
;
1742 return LOOKUP_OPTION_NO_RESULT
;
1746 /**************************************************************************
1747 Show the caller detailed help for the single OPTION given by id.
1748 help_cmd is the command the player used.
1749 Only show option values for options which the caller can SEE.
1750 **************************************************************************/
1751 static void show_help_option(struct connection
*caller
,
1752 enum command_id help_cmd
, int id
)
1754 char val_buf
[256], def_buf
[256];
1755 struct setting
*pset
= setting_by_number(id
);
1757 if (setting_short_help(pset
)) {
1758 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1759 /* TRANS: <untranslated name> - translated short help */
1760 _("Option: %s - %s"), setting_name(pset
),
1761 _(setting_short_help(pset
)));
1763 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1764 /* TRANS: <untranslated name> */
1765 _("Option: %s"), setting_name(pset
));
1768 if (strlen(setting_extra_help(pset
)) > 0) {
1769 char *help
= fc_strdup(_(setting_extra_help(pset
)));
1771 fc_break_lines(help
, LINE_BREAK
);
1772 cmd_reply(help_cmd
, caller
, C_COMMENT
, _("Description:"));
1773 cmd_reply_prefix(help_cmd
, caller
, C_COMMENT
, " ", " %s", help
);
1776 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1777 _("Status: %s"), (setting_is_changeable(pset
, NULL
, NULL
, 0)
1778 ? _("changeable") : _("fixed")));
1780 if (setting_is_visible(pset
, caller
)) {
1781 setting_value_name(pset
, TRUE
, val_buf
, sizeof(val_buf
));
1782 setting_default_name(pset
, TRUE
, def_buf
, sizeof(def_buf
));
1784 switch (setting_type(pset
)) {
1786 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s %s, %s %d, %s %s, %s %d",
1787 _("Value:"), val_buf
,
1788 _("Minimum:"), setting_int_min(pset
),
1789 _("Default:"), def_buf
,
1790 _("Maximum:"), setting_int_max(pset
));
1797 cmd_reply(help_cmd
, caller
, C_COMMENT
, _("Possible values:"));
1798 for (i
= 0; (value
= setting_enum_val(pset
, i
, FALSE
)); i
++) {
1799 cmd_reply(help_cmd
, caller
, C_COMMENT
, "- %s: \"%s\"",
1800 value
, setting_enum_val(pset
, i
, TRUE
));
1806 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s %s, %s %s",
1807 _("Value:"), val_buf
, _("Default:"), def_buf
);
1814 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1815 _("Possible values (option can take any number of these):"));
1816 for (i
= 0; (value
= setting_bitwise_bit(pset
, i
, FALSE
)); i
++) {
1817 cmd_reply(help_cmd
, caller
, C_COMMENT
, "- %s: \"%s\"",
1818 value
, setting_bitwise_bit(pset
, i
, TRUE
));
1820 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s %s",
1821 _("Value:"), val_buf
);
1822 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s %s",
1823 _("Default:"), def_buf
);
1830 /**************************************************************************
1831 Show the caller list of OPTIONS.
1832 help_cmd is the command the player used.
1833 Only show options which the caller can SEE.
1834 **************************************************************************/
1835 static void show_help_option_list(struct connection
*caller
,
1836 enum command_id help_cmd
)
1838 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
1839 cmd_reply(help_cmd
, caller
, C_COMMENT
,
1840 _("Explanations are available for the following server options:"));
1841 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
1842 if(!caller
&& con_get_style()) {
1843 settings_iterate(SSET_ALL
, pset
) {
1844 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", setting_name(pset
));
1845 } settings_iterate_end
1847 char buf
[MAX_LEN_CONSOLE_LINE
];
1851 settings_iterate(SSET_ALL
, pset
) {
1852 if (setting_is_visible(pset
, caller
)) {
1853 cat_snprintf(buf
, sizeof(buf
), "%-19s", setting_name(pset
));
1854 if ((++j
% 4) == 0) {
1855 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", buf
);
1859 } settings_iterate_end
;
1861 if (buf
[0] != '\0') {
1862 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", buf
);
1865 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
1868 /**************************************************************************
1869 Handle explain command
1870 **************************************************************************/
1871 static bool explain_option(struct connection
*caller
, char *str
, bool check
)
1875 remove_leading_trailing_spaces(str
);
1878 cmd
= lookup_option(str
);
1879 if (cmd
>= 0 && cmd
< settings_number()) {
1880 show_help_option(caller
, CMD_EXPLAIN
, cmd
);
1881 } else if (cmd
== LOOKUP_OPTION_NO_RESULT
1882 || cmd
== LOOKUP_OPTION_LEVEL_NAME
1883 || cmd
== LOOKUP_OPTION_RULESETDIR
) {
1884 cmd_reply(CMD_EXPLAIN
, caller
, C_FAIL
,
1885 _("No explanation for that yet."));
1887 } else if (cmd
== LOOKUP_OPTION_AMBIGUOUS
) {
1888 cmd_reply(CMD_EXPLAIN
, caller
, C_FAIL
, _("Ambiguous option name."));
1891 log_error("Unexpected case %d in %s line %d", cmd
, __FILE__
,
1896 show_help_option_list(caller
, CMD_EXPLAIN
);
1901 /******************************************************************
1902 Send a message to all players
1903 ******************************************************************/
1904 static bool wall(char *str
, bool check
)
1907 notify_conn(NULL
, NULL
, E_MESSAGE_WALL
, ftc_server_prompt
,
1908 _("Server Operator: %s"), str
);
1913 /******************************************************************
1914 Set message to send to all new connections
1915 ******************************************************************/
1916 static bool connectmsg_command(struct connection
*caller
, char *str
,
1919 unsigned int bufsize
= sizeof(game
.server
.connectmsg
);
1921 if (is_restricted(caller
)) {
1928 for (i
= 0; c
< bufsize
-1 && str
[i
] != '\0'; i
++) {
1929 if (str
[i
] == '\\') {
1932 if (str
[i
] == 'n') {
1933 game
.server
.connectmsg
[c
++] = '\n';
1935 game
.server
.connectmsg
[c
++] = str
[i
];
1938 game
.server
.connectmsg
[c
++] = str
[i
];
1942 game
.server
.connectmsg
[c
++] = '\0';
1946 cmd_reply(CMD_CONNECTMSG
, caller
, C_WARNING
,
1947 _("Connectmsg truncated to %u bytes."), bufsize
);
1953 /******************************************************************
1954 Set an AI level and related quantities, with no feedback.
1955 ******************************************************************/
1956 void set_ai_level_directer(struct player
*pplayer
, enum ai_level level
)
1958 pplayer
->ai_common
.handicaps
= handicap_of_skill_level(level
);
1959 pplayer
->ai_common
.fuzzy
= fuzzy_of_skill_level(level
);
1960 pplayer
->ai_common
.expand
= expansionism_of_skill_level(level
);
1961 pplayer
->ai_common
.science_cost
= science_cost_of_skill_level(level
);
1962 pplayer
->ai_common
.skill_level
= level
;
1965 /******************************************************************
1966 Translate an AI level back to its CMD_* value.
1967 If we just used /set ailevel <num> we wouldn't have to do this - rp
1968 ******************************************************************/
1969 static enum command_id
cmd_of_level(enum ai_level level
)
1972 case AI_LEVEL_AWAY
: return CMD_AWAY
;
1973 case AI_LEVEL_NOVICE
: return CMD_NOVICE
;
1974 case AI_LEVEL_EASY
: return CMD_EASY
;
1975 case AI_LEVEL_NORMAL
: return CMD_NORMAL
;
1976 case AI_LEVEL_HARD
: return CMD_HARD
;
1977 case AI_LEVEL_CHEATING
: return CMD_CHEATING
;
1978 case AI_LEVEL_EXPERIMENTAL
: return CMD_EXPERIMENTAL
;
1979 case AI_LEVEL_LAST
: return CMD_NORMAL
;
1981 log_error("Unknown AI level variant: %d.", level
);
1985 /******************************************************************
1986 Set an AI level from the server prompt.
1987 ******************************************************************/
1988 void set_ai_level_direct(struct player
*pplayer
, enum ai_level level
)
1990 set_ai_level_directer(pplayer
, level
);
1991 send_player_info_c(pplayer
, NULL
);
1992 cmd_reply(cmd_of_level(level
), NULL
, C_OK
,
1993 _("Player '%s' now has AI skill level '%s'."),
1994 player_name(pplayer
),
1995 ai_level_name(level
));
1999 /******************************************************************
2000 Handle a user command to set an AI level.
2001 ******************************************************************/
2002 static bool set_ai_level_named(struct connection
*caller
, const char *name
,
2003 const char *level_name
, bool check
)
2005 enum ai_level level
= ai_level_by_name(level_name
);
2006 return set_ai_level(caller
, name
, level
, check
);
2009 /******************************************************************
2011 ******************************************************************/
2012 static bool set_ai_level(struct connection
*caller
, const char *name
,
2013 enum ai_level level
, bool check
)
2015 enum m_pre_result match_result
;
2016 struct player
*pplayer
;
2018 fc_assert_ret_val(level
> 0 && level
< 11, FALSE
);
2020 pplayer
= player_by_name_prefix(name
, &match_result
);
2023 if (pplayer
->ai_controlled
) {
2027 set_ai_level_directer(pplayer
, level
);
2028 send_player_info_c(pplayer
, NULL
);
2029 cmd_reply(cmd_of_level(level
), caller
, C_OK
,
2030 _("Player '%s' now has AI skill level '%s'."),
2031 player_name(pplayer
),
2032 ai_level_name(level
));
2034 cmd_reply(cmd_of_level(level
), caller
, C_FAIL
,
2035 _("%s is not controlled by the AI."),
2036 player_name(pplayer
));
2039 } else if(match_result
== M_PRE_EMPTY
) {
2043 players_iterate(pplayer
) {
2044 if (pplayer
->ai_controlled
) {
2045 set_ai_level_directer(pplayer
, level
);
2046 send_player_info_c(pplayer
, NULL
);
2047 cmd_reply(cmd_of_level(level
), caller
, C_OK
,
2048 _("Player '%s' now has AI skill level '%s'."),
2049 player_name(pplayer
),
2050 ai_level_name(level
));
2052 } players_iterate_end
;
2053 game
.info
.skill_level
= level
;
2054 cmd_reply(cmd_of_level(level
), caller
, C_OK
,
2055 _("Default AI skill level set to '%s'."),
2056 ai_level_name(level
));
2058 cmd_reply_no_such_player(cmd_of_level(level
), caller
, name
, match_result
);
2064 /******************************************************************
2065 Set user to away mode.
2066 ******************************************************************/
2067 static bool set_away(struct connection
*caller
, char *name
, bool check
)
2069 if (caller
== NULL
) {
2070 cmd_reply(CMD_AWAY
, caller
, C_FAIL
, _("This command is client only."));
2072 } else if (name
&& strlen(name
) > 0) {
2073 cmd_reply(CMD_AWAY
, caller
, C_SYNTAX
, _("Usage:\n%s"),
2074 command_synopsis(command_by_number(CMD_AWAY
)));
2076 } else if (NULL
== caller
->playing
|| caller
->observer
) {
2077 /* This happens for detached or observer connections. */
2078 cmd_reply(CMD_AWAY
, caller
, C_FAIL
,
2079 _("Only players may use the away command."));
2081 } else if (!caller
->playing
->ai_controlled
&& !check
) {
2082 cmd_reply(CMD_AWAY
, caller
, C_OK
,
2083 _("%s set to away mode."), player_name(caller
->playing
));
2084 set_ai_level_directer(caller
->playing
, AI_LEVEL_AWAY
);
2085 caller
->playing
->ai_controlled
= TRUE
;
2086 cancel_all_meetings(caller
->playing
);
2087 } else if (!check
) {
2088 cmd_reply(CMD_AWAY
, caller
, C_OK
,
2089 _("%s returned to game."), player_name(caller
->playing
));
2090 caller
->playing
->ai_controlled
= FALSE
;
2091 /* We have to do it, because the client doesn't display
2092 * dialogs for meetings in AI mode. */
2093 cancel_all_meetings(caller
->playing
);
2096 send_player_info_c(caller
->playing
, game
.est_connections
);
2101 /**************************************************************************
2102 Show changed settings.
2103 **************************************************************************/
2104 static void show_changed(struct connection
*caller
, bool check
,
2107 if (read_recursion
!= 0) {
2111 /* show changed settings only at the top level of recursion */
2112 char *show_arg
= "changed";
2113 show_command(caller
, show_arg
, check
);
2116 /**************************************************************************
2117 Print a summary of the settings and their values. Note that most values
2118 are at most 4 digits, except seeds, which we let overflow their columns,
2119 plus a sign character. Only show options which the caller can SEE.
2120 **************************************************************************/
2121 static bool show_command(struct connection
*caller
, char *str
, bool check
)
2124 enum sset_level level
= SSET_ALL
;
2127 remove_leading_trailing_spaces(str
);
2128 if (str
[0] != '\0') {
2129 /* In "/show forests", figure out that it's the forests option we're
2131 cmd
= lookup_option(str
);
2133 /* Ignore levels when a particular option is specified. */
2136 if (!setting_is_visible(setting_by_number(cmd
), caller
)) {
2137 cmd_reply(CMD_SHOW
, caller
, C_FAIL
,
2138 _("Sorry, you do not have access to view option '%s'."),
2144 /* Valid negative values for 'cmd' are defined as LOOKUP_OPTION_*. */
2146 case LOOKUP_OPTION_NO_RESULT
:
2147 cmd_reply(CMD_SHOW
, caller
, C_FAIL
, _("Unknown option '%s'."), str
);
2149 case LOOKUP_OPTION_AMBIGUOUS
:
2150 /* Allow ambiguous: show all matching. */
2153 case LOOKUP_OPTION_LEVEL_NAME
:
2155 level
= lookup_option_level(str
);
2157 case LOOKUP_OPTION_RULESETDIR
:
2159 cmd_reply(CMD_SHOW
, caller
, C_COMMENT
,
2160 _("Current ruleset directory is \"%s\""),
2161 game
.server
.rulesetdir
);
2165 /* to indicate that no command was specified */
2166 cmd
= LOOKUP_OPTION_NO_RESULT
;
2167 /* Use vital level by default. */
2171 fc_assert_ret_val(cmd
>= 0 || cmd
== LOOKUP_OPTION_AMBIGUOUS
2172 || cmd
== LOOKUP_OPTION_LEVEL_NAME
2173 || cmd
== LOOKUP_OPTION_NO_RESULT
, FALSE
);
2175 #define cmd_reply_show(string) \
2176 cmd_reply(CMD_SHOW, caller, C_COMMENT, "%s", string)
2179 const char *heading
= NULL
;
2184 heading
= _("All options with non-default values");
2187 heading
= _("All options");
2190 heading
= _("Vital options");
2192 case SSET_SITUATIONAL
:
2193 heading
= _("Situational options");
2196 heading
= _("Rarely used options");
2199 heading
= _("Options locked by the ruleset");
2206 cmd_reply_show(horiz_line
);
2207 cmd_reply_show(heading
);
2210 cmd_reply_show(horiz_line
);
2211 cmd_reply_show(_("In the column '##' the status of the option is shown:"));
2212 cmd_reply_show(_(" - a '!' means the option is locked by the ruleset."));
2213 cmd_reply_show(_(" - a '+' means you may change the option."));
2214 cmd_reply_show(_(" - a '=' means the option is on its default value."));
2215 cmd_reply_show(horiz_line
);
2216 cmd_reply(CMD_SHOW
, caller
, C_COMMENT
, _("%-*s ## value (min, max)"),
2217 OPTION_NAME_SPACE
, _("Option"));
2218 cmd_reply_show(horiz_line
);
2220 /* Update changed and locked levels. */
2221 settings_list_update();
2225 /* Show _one_ setting. */
2226 fc_assert_ret_val(0 <= cmd
, FALSE
);
2228 struct setting
*pset
= setting_by_number(cmd
);
2230 show_command_one(caller
, pset
);
2236 case SSET_SITUATIONAL
:
2239 settings_iterate(level
, pset
) {
2240 if (!setting_is_visible(pset
, caller
)) {
2244 if (LOOKUP_OPTION_AMBIGUOUS
== cmd
2245 && 0 != fc_strncasecmp(setting_name(pset
), str
, clen
)) {
2249 show_command_one(caller
, pset
);
2250 } settings_iterate_end
;
2257 cmd_reply_show(horiz_line
);
2258 cmd_reply_show(_("A help text for each option is available via 'help "
2260 cmd_reply_show(horiz_line
);
2261 if (level
== SSET_VITAL
) {
2262 cmd_reply_show(_("Try 'show situational' or 'show rare' to show "
2264 "Try 'show changed' to show settings with "
2265 "non-default values.\n"
2266 "Try 'show locked' to show settings locked "
2267 "by the ruleset."));
2268 cmd_reply_show(horiz_line
);
2271 #undef cmd_reply_show
2274 /*****************************************************************************
2277 Each option value will be displayed as:
2279 [OPTION_NAME_SPACE length for name] ## [value] ([min], [max])
2281 where '##' is a combination of ' ', '!' or '+' followed by ' ' or '=' with
2282 - '!': the option is locked by the ruleset
2283 - '+': you may change the option
2284 - '=': the option is on its default value
2285 *****************************************************************************/
2286 static void show_command_one(struct connection
*caller
, struct setting
*pset
)
2288 char buf
[MAX_LEN_CONSOLE_LINE
] = "", value
[MAX_LEN_CONSOLE_LINE
] = "";
2291 fc_assert_ret(pset
!= NULL
);
2293 is_changed
= setting_changed(pset
);
2294 setting_value_name(pset
, TRUE
, value
, sizeof(value
));
2297 /* Emphasizes the changed option. */
2298 featured_text_apply_tag(value
, buf
, sizeof(buf
), TTT_COLOR
,
2299 0, FT_OFFSET_UNSET
, ftc_changed
);
2300 sz_strlcpy(value
, buf
);
2303 if (SSET_INT
== setting_type(pset
)) {
2304 /* Add the range. */
2305 cat_snprintf(value
, sizeof(value
), " (%d, %d)",
2306 setting_int_min(pset
), setting_int_max(pset
));
2309 cmd_reply(CMD_SHOW
, caller
, C_COMMENT
, "%-*s %c%c %s",
2310 OPTION_NAME_SPACE
, setting_name(pset
),
2311 setting_status(caller
, pset
), is_changed
? ' ' : '=', value
);
2314 /******************************************************************
2316 ******************************************************************/
2317 static bool team_command(struct connection
*caller
, char *str
, bool check
)
2319 struct player
*pplayer
;
2320 enum m_pre_result match_result
;
2321 char buf
[MAX_LEN_CONSOLE_LINE
];
2325 struct team_slot
*tslot
;
2327 if (game_was_started()) {
2328 cmd_reply(CMD_TEAM
, caller
, C_SYNTAX
,
2329 _("Cannot change teams once game has begun."));
2333 if (str
!= NULL
|| strlen(str
) > 0) {
2334 sz_strlcpy(buf
, str
);
2335 ntokens
= get_tokens(buf
, arg
, 2, TOKEN_DELIMITERS
);
2338 cmd_reply(CMD_TEAM
, caller
, C_SYNTAX
,
2339 _("Undefined argument. Usage:\n%s"),
2340 command_synopsis(command_by_number(CMD_TEAM
)));
2344 pplayer
= player_by_name_prefix(arg
[0], &match_result
);
2345 if (pplayer
== NULL
) {
2346 cmd_reply_no_such_player(CMD_TEAM
, caller
, arg
[0], match_result
);
2350 tslot
= team_slot_by_rule_name(arg
[1]);
2351 if (NULL
== tslot
) {
2354 if (str_to_int(arg
[1], &teamno
)) {
2355 tslot
= team_slot_by_number(teamno
);
2358 if (NULL
== tslot
) {
2359 cmd_reply(CMD_TEAM
, caller
, C_SYNTAX
,
2360 _("No such team %s. Please give a "
2361 "valid team name or number."), arg
[1]);
2365 if (is_barbarian(pplayer
)) {
2366 /* This can happen if we change team settings on a loaded game. */
2367 cmd_reply(CMD_TEAM
, caller
, C_SYNTAX
, _("Cannot team a barbarian."));
2371 team_add_player(pplayer
, team_new(tslot
));
2372 send_player_info_c(pplayer
, NULL
);
2373 cmd_reply(CMD_TEAM
, caller
, C_OK
, _("Player %s set to team %s."),
2374 player_name(pplayer
),
2375 team_slot_name_translation(tslot
));
2380 for (i
= 0; i
< ntokens
; i
++) {
2386 /**************************************************************************
2387 List all running votes. Moved from /vote command.
2388 **************************************************************************/
2389 static void show_votes(struct connection
*caller
)
2394 if (vote_list
!= NULL
) {
2395 vote_list_iterate(vote_list
, pvote
) {
2396 if (NULL
!= caller
&& !conn_can_see_vote(caller
, pvote
)) {
2399 /* TRANS: "Vote" or "Teamvote" is voting-as-a-process. Used as
2400 * part of a sentence. */
2401 title
= vote_is_team_only(pvote
) ? _("Teamvote") : _("Vote");
2402 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
,
2403 /* TRANS: "[Vote|Teamvote] 3 \"proposed change\" (needs ..." */
2404 _("%s %d \"%s\" (needs %0.0f%%%s): %d for, "
2405 "%d against, and %d abstained out of %d players."),
2406 title
, pvote
->vote_no
, pvote
->cmdline
,
2407 MIN(100, pvote
->need_pc
* 100 + 1),
2408 pvote
->flags
& VCF_NODISSENT
? _(" no dissent") : "",
2409 pvote
->yes
, pvote
->no
, pvote
->abstain
, count_voters(pvote
));
2411 } vote_list_iterate_end
;
2415 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
,
2416 _("There are no votes going on."));
2420 /**************************************************************************
2421 Vote command argument definitions.
2422 **************************************************************************/
2423 static const char *const vote_args
[] = {
2429 static const char *vote_arg_accessor(int i
)
2431 return vote_args
[i
];
2434 /******************************************************************
2435 Make or participate in a vote.
2436 ******************************************************************/
2437 static bool vote_command(struct connection
*caller
, char *str
,
2440 char buf
[MAX_LEN_CONSOLE_LINE
];
2442 int ntokens
= 0, i
= 0, which
= -1;
2443 enum m_pre_result match_result
;
2444 struct vote
*pvote
= NULL
;
2448 /* This should never happen, since /vote must always be
2449 * set to ALLOW_BASIC or less. But just in case... */
2453 sz_strlcpy(buf
, str
);
2454 ntokens
= get_tokens(buf
, arg
, 2, TOKEN_DELIMITERS
);
2459 } else if (!conn_can_vote(caller
, NULL
)) {
2460 cmd_reply(CMD_VOTE
, caller
, C_FAIL
,
2461 _("You are not allowed to use this command."));
2465 match_result
= match_prefix(vote_arg_accessor
, VOTE_NUM
, 0,
2466 fc_strncasecmp
, NULL
, arg
[0], &i
);
2468 if (match_result
== M_PRE_AMBIGUOUS
) {
2469 cmd_reply(CMD_VOTE
, caller
, C_SYNTAX
,
2470 _("The argument \"%s\" is ambiguous."), arg
[0]);
2472 } else if (match_result
> M_PRE_AMBIGUOUS
) {
2474 cmd_reply(CMD_VOTE
, caller
, C_SYNTAX
,
2475 _("Undefined argument. Usage:\n%s"),
2476 command_synopsis(command_by_number(CMD_VOTE
)));
2481 /* Applies to last vote */
2482 if (vote_number_sequence
> 0 && get_vote_by_no(vote_number_sequence
)) {
2483 which
= vote_number_sequence
;
2485 int num_votes
= vote_list_size(vote_list
);
2486 if (num_votes
== 0) {
2487 cmd_reply(CMD_VOTE
, caller
, C_FAIL
, _("There are no votes running."));
2489 /* TRANS: "vote" as a process */
2490 cmd_reply(CMD_VOTE
, caller
, C_FAIL
, _("No legal last vote (%d %s)."),
2491 num_votes
, PL_("other vote running", "other votes running",
2497 if (!str_to_int(arg
[1], &which
)) {
2498 cmd_reply(CMD_VOTE
, caller
, C_SYNTAX
, _("Value must be an integer."));
2503 if (!(pvote
= get_vote_by_no(which
))) {
2504 /* TRANS: "vote" as a process */
2505 cmd_reply(CMD_VOTE
, caller
, C_FAIL
, _("No such vote (%d)."), which
);
2509 if (!conn_can_vote(caller
, pvote
)) {
2510 cmd_reply(CMD_VOTE
, caller
, C_FAIL
,
2511 _("You are not allowed to vote on that."));
2515 if (i
== VOTE_YES
) {
2516 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
, _("You voted for \"%s\""),
2518 connection_vote(caller
, pvote
, VOTE_YES
);
2519 } else if (i
== VOTE_NO
) {
2520 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
, _("You voted against \"%s\""),
2522 connection_vote(caller
, pvote
, VOTE_NO
);
2523 } else if (i
== VOTE_ABSTAIN
) {
2524 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
,
2525 _("You abstained from voting on \"%s\""), pvote
->cmdline
);
2526 connection_vote(caller
, pvote
, VOTE_ABSTAIN
);
2528 /* Must never happen. */
2529 fc_assert_action(FALSE
, goto CLEANUP
);
2535 free_tokens(arg
, ntokens
);
2539 /**************************************************************************
2540 Cancel a vote... /cancelvote <vote number>|all.
2541 **************************************************************************/
2542 static bool cancelvote_command(struct connection
*caller
,
2543 char *arg
, bool check
)
2545 struct vote
*pvote
= NULL
;
2549 /* This should never happen anyway, since /cancelvote
2550 * is set to ALLOW_BASIC in both pregame and while the
2551 * game is running. */
2555 remove_leading_trailing_spaces(arg
);
2557 if (arg
[0] == '\0') {
2558 if (caller
== NULL
) {
2560 cmd_reply(CMD_CANCELVOTE
, caller
, C_SYNTAX
,
2561 /* TRANS: "vote" as a process */
2562 _("Missing argument <vote number> or "
2563 "the string \"all\"."));
2566 /* The caller cancel his/her own vote. */
2567 if (!(pvote
= get_vote_by_caller(caller
))) {
2568 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2569 _("You don't have any vote going on."));
2572 } else if (fc_strcasecmp(arg
, "all") == 0) {
2573 /* Cancel all votes (needs some privileges). */
2574 if (vote_list_size(vote_list
) == 0) {
2575 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2576 _("There isn't any vote going on."));
2578 } else if (!caller
|| conn_get_access(caller
) >= ALLOW_ADMIN
) {
2580 notify_conn(NULL
, NULL
, E_VOTE_ABORTED
, ftc_server
,
2581 /* TRANS: "votes" as a process */
2582 _("All votes have been removed."));
2585 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2586 _("You are not allowed to use this command."));
2589 } else if (str_to_int(arg
, &vote_no
)) {
2590 /* Cancel one particular vote (needs some privileges if the vote
2592 if (!(pvote
= get_vote_by_no(vote_no
))) {
2593 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2594 /* TRANS: "vote" as a process */
2595 _("No such vote (%d)."), vote_no
);
2597 } else if (caller
&& conn_get_access(caller
) < ALLOW_ADMIN
2598 && caller
->id
!= pvote
->caller_id
) {
2599 cmd_reply(CMD_CANCELVOTE
, caller
, C_FAIL
,
2600 /* TRANS: "vote" as a process */
2601 _("You are not allowed to cancel this vote (%d)."),
2606 cmd_reply(CMD_CANCELVOTE
, caller
, C_SYNTAX
,
2607 /* TRANS: "vote" as a process */
2608 _("Usage: /cancelvote [<vote number>|all]"));
2612 fc_assert_ret_val(NULL
!= pvote
, FALSE
);
2615 notify_team(conn_get_player(vote_get_caller(pvote
)),
2616 NULL
, E_VOTE_ABORTED
, ftc_server
,
2617 /* TRANS: "vote" as a process */
2618 _("%s has canceled the vote \"%s\" (number %d)."),
2619 caller
->username
, pvote
->cmdline
, pvote
->vote_no
);
2622 notify_team(conn_get_player(vote_get_caller(pvote
)),
2623 NULL
, E_VOTE_ABORTED
, ftc_server
,
2624 /* TRANS: "vote" as a process */
2625 _("The vote \"%s\" (number %d) has been canceled."),
2626 pvote
->cmdline
, pvote
->vote_no
);
2628 /* Make it after, prevent crashs about a free pointer (pvote). */
2634 /******************************************************************
2635 Turn on selective debugging.
2636 ******************************************************************/
2637 static bool debug_command(struct connection
*caller
, char *str
,
2640 char buf
[MAX_LEN_CONSOLE_LINE
];
2644 if (game
.info
.is_new_game
) {
2645 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2646 _("Can only use this command once game has begun."));
2650 return TRUE
; /* whatever! */
2653 if (str
!= NULL
&& strlen(str
) > 0) {
2654 sz_strlcpy(buf
, str
);
2655 ntokens
= get_tokens(buf
, arg
, 3, TOKEN_DELIMITERS
);
2660 if (ntokens
> 0 && strcmp(arg
[0], "diplomacy") == 0) {
2661 struct player
*pplayer
;
2662 enum m_pre_result match_result
;
2665 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2666 _("Undefined argument. Usage:\n%s"),
2667 command_synopsis(command_by_number(CMD_DEBUG
)));
2670 pplayer
= player_by_name_prefix(arg
[1], &match_result
);
2671 if (pplayer
== NULL
) {
2672 cmd_reply_no_such_player(CMD_DEBUG
, caller
, arg
[1], match_result
);
2675 if (BV_ISSET(pplayer
->server
.debug
, PLAYER_DEBUG_DIPLOMACY
)) {
2676 BV_CLR(pplayer
->server
.debug
, PLAYER_DEBUG_DIPLOMACY
);
2677 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s diplomacy no longer debugged"),
2678 player_name(pplayer
));
2680 BV_SET(pplayer
->server
.debug
, PLAYER_DEBUG_DIPLOMACY
);
2681 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s diplomacy debugged"),
2682 player_name(pplayer
));
2683 /* TODO: print some info about the player here */
2685 } else if (ntokens
> 0 && strcmp(arg
[0], "tech") == 0) {
2686 struct player
*pplayer
;
2687 enum m_pre_result match_result
;
2690 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2691 _("Undefined argument. Usage:\n%s"),
2692 command_synopsis(command_by_number(CMD_DEBUG
)));
2695 pplayer
= player_by_name_prefix(arg
[1], &match_result
);
2696 if (pplayer
== NULL
) {
2697 cmd_reply_no_such_player(CMD_DEBUG
, caller
, arg
[1], match_result
);
2700 if (BV_ISSET(pplayer
->server
.debug
, PLAYER_DEBUG_TECH
)) {
2701 BV_CLR(pplayer
->server
.debug
, PLAYER_DEBUG_TECH
);
2702 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s tech no longer debugged"),
2703 player_name(pplayer
));
2705 BV_SET(pplayer
->server
.debug
, PLAYER_DEBUG_TECH
);
2706 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s tech debugged"),
2707 player_name(pplayer
));
2708 /* TODO: print some info about the player here */
2710 } else if (ntokens
> 0 && strcmp(arg
[0], "info") == 0) {
2711 int cities
= 0, players
= 0, units
= 0, citizens
= 0;
2712 players_iterate(plr
) {
2714 city_list_iterate(plr
->cities
, pcity
) {
2716 citizens
+= city_size_get(pcity
);
2717 } city_list_iterate_end
;
2718 units
+= unit_list_size(plr
->units
);
2719 } players_iterate_end
;
2720 log_normal(_("players=%d cities=%d citizens=%d units=%d"),
2721 players
, cities
, citizens
, units
);
2722 notify_conn(game
.est_connections
, NULL
, E_AI_DEBUG
, ftc_log
,
2723 _("players=%d cities=%d citizens=%d units=%d"),
2724 players
, cities
, citizens
, units
);
2725 } else if (ntokens
> 0 && strcmp(arg
[0], "city") == 0) {
2731 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2732 _("Undefined argument. Usage:\n%s"),
2733 command_synopsis(command_by_number(CMD_DEBUG
)));
2736 if (!str_to_int(arg
[1], &x
) || !str_to_int(arg
[2], &y
)) {
2737 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Value 2 & 3 must be integer."));
2740 if (!(ptile
= map_pos_to_tile(x
, y
))) {
2741 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Bad map coordinates."));
2744 pcity
= tile_city(ptile
);
2746 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("No city at this coordinate."));
2749 if (pcity
->server
.debug
) {
2750 pcity
->server
.debug
= FALSE
;
2751 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s no longer debugged"),
2754 pcity
->server
.debug
= TRUE
;
2755 CITY_LOG(LOG_NORMAL
, pcity
, "debugged");
2757 } else if (ntokens
> 0 && strcmp(arg
[0], "units") == 0) {
2762 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2763 _("Undefined argument. Usage:\n%s"),
2764 command_synopsis(command_by_number(CMD_DEBUG
)));
2767 if (!str_to_int(arg
[1], &x
) || !str_to_int(arg
[2], &y
)) {
2768 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Value 2 & 3 must be integer."));
2771 if (!(ptile
= map_pos_to_tile(x
, y
))) {
2772 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Bad map coordinates."));
2775 unit_list_iterate(ptile
->units
, punit
) {
2776 if (punit
->server
.debug
) {
2777 punit
->server
.debug
= FALSE
;
2778 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s %s no longer debugged."),
2779 nation_adjective_for_player(unit_owner(punit
)),
2780 unit_name_translation(punit
));
2782 punit
->server
.debug
= TRUE
;
2783 UNIT_LOG(LOG_NORMAL
, punit
, "%s %s debugged.",
2784 nation_rule_name(nation_of_unit(punit
)),
2785 unit_name_translation(punit
));
2787 } unit_list_iterate_end
;
2788 } else if (ntokens
> 0 && strcmp(arg
[0], "timing") == 0) {
2790 } else if (ntokens
> 0 && strcmp(arg
[0], "ferries") == 0) {
2791 if (game
.server
.debug
[DEBUG_FERRIES
]) {
2792 game
.server
.debug
[DEBUG_FERRIES
] = FALSE
;
2793 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("Ferry system is no longer "
2796 game
.server
.debug
[DEBUG_FERRIES
] = TRUE
;
2797 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("Ferry system in debug mode."));
2799 } else if (ntokens
> 0 && strcmp(arg
[0], "unit") == 0) {
2804 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2805 _("Undefined argument. Usage:\n%s"),
2806 command_synopsis(command_by_number(CMD_DEBUG
)));
2809 if (!str_to_int(arg
[1], &id
)) {
2810 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Value 2 must be integer."));
2813 if (!(punit
= game_unit_by_number(id
))) {
2814 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
, _("Unit %d does not exist."), id
);
2817 if (punit
->server
.debug
) {
2818 punit
->server
.debug
= FALSE
;
2819 cmd_reply(CMD_DEBUG
, caller
, C_OK
, _("%s %s no longer debugged."),
2820 nation_adjective_for_player(unit_owner(punit
)),
2821 unit_name_translation(punit
));
2823 punit
->server
.debug
= TRUE
;
2824 UNIT_LOG(LOG_NORMAL
, punit
, "%s %s debugged.",
2825 nation_rule_name(nation_of_unit(punit
)),
2826 unit_name_translation(punit
));
2829 cmd_reply(CMD_DEBUG
, caller
, C_SYNTAX
,
2830 _("Undefined argument. Usage:\n%s"),
2831 command_synopsis(command_by_number(CMD_DEBUG
)));
2834 for (i
= 0; i
< ntokens
; i
++) {
2840 /******************************************************************
2842 ******************************************************************/
2843 static bool set_command(struct connection
*caller
, char *str
, bool check
)
2846 int val
, cmd
, nargs
;
2847 struct setting
*pset
;
2849 char reject_msg
[256] = "";
2852 /* '=' is also a valid delimiter for this function. */
2853 nargs
= get_tokens(str
, args
, ARRAY_SIZE(args
), TOKEN_DELIMITERS
"=");
2856 cmd_reply(CMD_SET
, caller
, C_SYNTAX
,
2857 _("Undefined argument. Usage:\n%s"),
2858 command_synopsis(command_by_number(CMD_SET
)));
2862 cmd
= lookup_option(args
[0]);
2865 case LOOKUP_OPTION_NO_RESULT
:
2866 case LOOKUP_OPTION_LEVEL_NAME
:
2867 cmd_reply(CMD_SET
, caller
, C_SYNTAX
,
2868 _("Option '%s' not recognized."), args
[0]);
2870 case LOOKUP_OPTION_AMBIGUOUS
:
2871 cmd_reply(CMD_SET
, caller
, C_SYNTAX
, _("Ambiguous option name."));
2873 case LOOKUP_OPTION_RULESETDIR
:
2874 cmd_reply(CMD_SET
, caller
, C_SYNTAX
,
2875 /* TRANS: 'rulesetdir' is the command. Do not translate. */
2876 _("Use the '%srulesetdir' command to change the ruleset "
2877 "directory."), caller
? "/" : "");
2880 fc_assert_ret_val(cmd
>= LOOKUP_OPTION_RULESETDIR
, FALSE
);
2886 pset
= setting_by_number(cmd
);
2888 if (!setting_is_changeable(pset
, caller
, reject_msg
, sizeof(reject_msg
))
2890 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2896 switch (setting_type(pset
)) {
2899 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2901 || (!setting_bool_validate(pset
, args
[1], caller
,
2902 reject_msg
, sizeof(reject_msg
)))) {
2903 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2906 } else if (setting_bool_set(pset
, args
[1], caller
,
2907 reject_msg
, sizeof(reject_msg
))) {
2910 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2916 if (!str_to_int(args
[1], &val
)) {
2917 cmd_reply(CMD_SET
, caller
, C_SYNTAX
,
2918 _("The parameter %s should only contain +- and 0-9."),
2919 setting_name(pset
));
2923 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2925 || !setting_int_validate(pset
, val
, caller
, reject_msg
,
2926 sizeof(reject_msg
))) {
2927 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2931 if (setting_int_set(pset
, val
, caller
, reject_msg
,
2932 sizeof(reject_msg
))) {
2935 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2943 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2945 || !setting_str_validate(pset
, args
[1], caller
, reject_msg
,
2946 sizeof(reject_msg
))) {
2947 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2951 if (setting_str_set(pset
, args
[1], caller
, reject_msg
,
2952 sizeof(reject_msg
))) {
2955 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2963 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2965 || (!setting_enum_validate(pset
, args
[1], caller
,
2966 reject_msg
, sizeof(reject_msg
)))) {
2967 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2970 } else if (setting_enum_set(pset
, args
[1], caller
,
2971 reject_msg
, sizeof(reject_msg
))) {
2974 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2981 if (!setting_is_changeable(pset
, caller
, reject_msg
,
2983 || (!setting_bitwise_validate(pset
, args
[1], caller
,
2984 reject_msg
, sizeof(reject_msg
)))) {
2985 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2988 } else if (setting_bitwise_set(pset
, args
[1], caller
,
2989 reject_msg
, sizeof(reject_msg
))) {
2992 cmd_reply(CMD_SET
, caller
, C_FAIL
, "%s", reject_msg
);
2998 ret
= TRUE
; /* Looks like a success. */
3000 if (!check
&& do_update
) {
3001 /* Send only to connections able to see that. */
3003 struct packet_chat_msg packet
;
3005 package_event(&packet
, NULL
, E_SETTING
, ftc_server
,
3006 _("Console: '%s' has been set to %s."), setting_name(pset
),
3007 setting_value_name(pset
, TRUE
, buf
, sizeof(buf
)));
3008 conn_list_iterate(game
.est_connections
, pconn
) {
3009 if (setting_is_visible(pset
, pconn
)) {
3010 send_packet_chat_msg(pconn
, &packet
);
3012 } conn_list_iterate_end
;
3013 /* Notify the console. */
3014 con_write(C_OK
, "%s", packet
.message
);
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();
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 send_player_info_c(aplayer
, NULL
);
3573 } players_iterate_end
;
3575 check_for_full_turn_done();
3579 for (i
= 0; i
< ntokens
; i
++) {
3585 /**************************************************************************
3586 Loads a file, complete with access checks and error messages sent back
3587 to the caller on failure.
3589 * caller is the connection requesting the load, or NULL for a
3590 command-line load. Error messages are sent back to the caller and
3591 an access check is done to make sure they are allowed to load.
3593 * filename is simply the name of the file to be loaded. This may be
3594 approximate; the function will look for appropriate suffixes and will
3595 check in the various directories to see if the file is found.
3597 * if check is set then only a test run is done and no actual loading
3600 * The return value is true if the load succeeds, or would succeed;
3601 false if there's an error in the file or file name. Some errors
3602 in loading however could be unrecoverable (if the save game is
3603 legitimate but has inconsistencies) and would lead to a broken server
3605 **************************************************************************/
3606 bool load_command(struct connection
*caller
, const char *filename
, bool check
)
3608 struct timer
*loadtimer
, *uloadtimer
;
3609 struct section_file
*file
;
3610 char arg
[MAX_LEN_PATH
];
3611 struct conn_list
*global_observers
;
3613 if (!filename
|| filename
[0] == '\0') {
3614 cmd_reply(CMD_LOAD
, caller
, C_FAIL
, _("Usage:\n%s"),
3615 command_synopsis(command_by_number(CMD_LOAD
)));
3618 if (S_S_INITIAL
!= server_state()) {
3619 cmd_reply(CMD_LOAD
, caller
, C_FAIL
,
3620 _("Cannot load a game while another is running."));
3621 dlsend_packet_game_load(game
.est_connections
, TRUE
, filename
);
3624 if (!is_safe_filename(filename
) && is_restricted(caller
)) {
3625 cmd_reply(CMD_LOAD
, caller
, C_FAIL
,
3626 _("Name \"%s\" disallowed for security reasons."),
3632 /* it is a normal savegame or maybe a scenario */
3633 char testfile
[MAX_LEN_PATH
];
3634 const struct strvec
*pathes
[] = {
3635 get_save_dirs(), get_scenario_dirs(), NULL
3637 const char *exts
[] = {
3638 "sav", "gz", "bz2", "sav.gz", "sav.bz2", NULL
3640 const char **ext
, *found
= NULL
;
3641 const struct strvec
**path
;
3643 for (path
= pathes
; !found
&& *path
; path
++) {
3644 for (ext
= exts
; !found
&& *ext
; ext
++) {
3645 fc_snprintf(testfile
, sizeof(testfile
), "%s.%s", filename
, *ext
);
3646 if ((found
= fileinfoname(*path
, testfile
))) {
3647 sz_strlcpy(arg
, found
);
3652 if (is_restricted(caller
) && !found
) {
3653 cmd_reply(CMD_LOAD
, caller
, C_FAIL
, _("Cannot find savegame or "
3654 "scenario with the name \"%s\"."), filename
);
3659 sz_strlcpy(arg
, filename
);
3663 /* attempt to parse the file */
3665 if (!(file
= secfile_load(arg
, FALSE
))) {
3666 cmd_reply(CMD_LOAD
, caller
, C_FAIL
, _("Could not load savefile: %s"),
3668 log_debug("Error loading savefile '%s':\n%s", arg
, secfile_error());
3669 dlsend_packet_game_load(game
.est_connections
, TRUE
, arg
);
3677 /* Detach current players, before we blow them away. */
3678 global_observers
= conn_list_new();
3679 conn_list_iterate(game
.est_connections
, pconn
) {
3680 if (pconn
->playing
!= NULL
) {
3681 connection_detach(pconn
, TRUE
);
3682 } else if (pconn
->observer
) {
3683 conn_list_append(global_observers
, pconn
);
3684 connection_detach(pconn
, TRUE
);
3686 } conn_list_iterate_end
;
3688 player_info_freeze();
3690 /* Now free all game data. */
3694 loadtimer
= timer_new(TIMER_CPU
, TIMER_ACTIVE
);
3695 timer_start(loadtimer
);
3696 uloadtimer
= timer_new(TIMER_USER
, TIMER_ACTIVE
);
3697 timer_start(uloadtimer
);
3699 sz_strlcpy(srvarg
.load_filename
, arg
);
3701 savegame2_load(file
);
3702 secfile_check_unused(file
);
3703 secfile_destroy(file
);
3705 log_verbose("Load time: %g seconds (%g apparent)",
3706 timer_read_seconds(loadtimer
), timer_read_seconds(uloadtimer
));
3707 timer_destroy(loadtimer
);
3708 timer_destroy(uloadtimer
);
3712 log_verbose("load_command() does send_rulesets()");
3713 conn_list_compression_freeze(game
.est_connections
);
3714 send_rulesets(game
.est_connections
);
3715 send_server_settings(game
.est_connections
);
3716 send_scenario_info(game
.est_connections
);
3717 send_game_info(game
.est_connections
);
3718 conn_list_compression_thaw(game
.est_connections
);
3720 /* Send information about the new players. */
3722 send_player_diplstate_c(NULL
, NULL
);
3724 /* Everything seemed to load ok; spread the good news. */
3725 dlsend_packet_game_load(game
.est_connections
, TRUE
, srvarg
.load_filename
);
3727 /* Attach connections to players. Currently, this applies only
3728 * to connections that have the same username as a player. */
3729 conn_list_iterate(game
.est_connections
, pconn
) {
3730 players_iterate(pplayer
) {
3731 if (strcmp(pconn
->username
, pplayer
->username
) == 0) {
3732 connection_attach(pconn
, pplayer
, FALSE
);
3735 } players_iterate_end
;
3736 } conn_list_iterate_end
;
3738 /* Reattach global observers. */
3739 conn_list_iterate(global_observers
, pconn
) {
3740 if (NULL
== pconn
->playing
) {
3741 /* May have been assigned to a player before. */
3742 connection_attach(pconn
, NULL
, TRUE
);
3744 } conn_list_iterate_end
;
3745 conn_list_destroy(global_observers
);
3747 aifill(game
.info
.aifill
);
3751 /**************************************************************************
3752 Load rulesets from a given ruleset directory.
3754 Security: There are some rudimentary checks in load_rulesets() to see
3755 if this directory really is a viable ruleset directory. For public
3756 servers, we check against directory redirection (is_safe_filename) and
3757 other bad stuff in the directory name, and will only use directories
3758 inside the data directories.
3759 **************************************************************************/
3760 static bool set_rulesetdir(struct connection
*caller
, char *str
, bool check
,
3764 const char *pfilename
;
3766 if (NULL
== str
|| '\0' == str
[0]) {
3767 cmd_reply(CMD_RULESETDIR
, caller
, C_SYNTAX
,
3768 _("You must provide a ruleset name. Use \"/show ruleset\" to "
3769 "see what is the current ruleset."));
3772 if (game_was_started() || !map_is_empty()) {
3773 cmd_reply(CMD_RULESETDIR
, caller
, C_FAIL
,
3774 _("This setting can't be modified after the game has started."));
3778 if (strcmp(str
, game
.server
.rulesetdir
) == 0) {
3779 cmd_reply(CMD_RULESETDIR
, caller
, C_COMMENT
,
3780 _("Ruleset directory is already \"%s\""), str
);
3784 if (is_restricted(caller
)
3785 && (!is_safe_filename(str
) || strchr(str
, '.'))) {
3786 cmd_reply(CMD_RULESETDIR
, caller
, C_SYNTAX
,
3787 _("Name \"%s\" disallowed for security reasons."),
3792 fc_snprintf(filename
, sizeof(filename
), "%s", str
);
3793 pfilename
= fileinfoname(get_data_dirs(), filename
);
3795 cmd_reply(CMD_RULESETDIR
, caller
, C_SYNTAX
,
3796 _("Ruleset directory \"%s\" not found"), str
);
3801 bool success
= TRUE
;
3804 sz_strlcpy(old
, game
.server
.rulesetdir
);
3805 log_verbose("set_rulesetdir() does load_rulesets() with \"%s\"", str
);
3806 sz_strlcpy(game
.server
.rulesetdir
, str
);
3808 /* load the ruleset (and game settings defined in the ruleset) */
3809 player_info_freeze();
3810 if (!load_rulesets(old
, TRUE
)) {
3813 /* While loading of the requested ruleset failed, we might
3814 * have changed ruleset from third one to default. Handle
3815 * rest of the ruleset changing accordingly. */
3818 if (game
.est_connections
) {
3819 /* Now that the rulesets are loaded we immediately send updates to any
3820 * connected clients. */
3821 send_rulesets(game
.est_connections
);
3823 /* list changed values */
3824 show_changed(caller
, check
, read_recursion
);
3828 cmd_reply(CMD_RULESETDIR
, caller
, C_OK
,
3829 _("Ruleset directory set to \"%s\""), str
);
3831 cmd_reply(CMD_RULESETDIR
, caller
, C_SYNTAX
,
3832 _("Failed loading rulesets from directory \"%s\", using \"%s\""),
3833 str
, game
.server
.rulesetdir
);
3842 /****************************************************************************
3843 /ignore command handler.
3844 ****************************************************************************/
3845 static bool ignore_command(struct connection
*caller
, char *str
, bool check
)
3848 struct conn_pattern
*ppattern
;
3850 if (NULL
== caller
) {
3851 cmd_reply(CMD_IGNORE
, caller
, C_FAIL
,
3852 _("That would be rather silly, since you are not a player."));
3856 ppattern
= conn_pattern_from_string(str
, CPT_USER
, buf
, sizeof(buf
));
3857 if (NULL
== ppattern
) {
3858 cmd_reply(CMD_IGNORE
, caller
, C_SYNTAX
,
3859 _("%s. Try /help ignore"), buf
);
3864 conn_pattern_destroy(ppattern
);
3868 conn_pattern_to_string(ppattern
, buf
, sizeof(buf
));
3869 conn_pattern_list_append(caller
->server
.ignore_list
, ppattern
);
3870 cmd_reply(CMD_IGNORE
, caller
, C_COMMENT
,
3871 _("Added pattern %s as entry %d to your ignore list."),
3872 buf
, conn_pattern_list_size(caller
->server
.ignore_list
));
3877 /****************************************************************************
3878 /unignore command handler.
3879 ****************************************************************************/
3880 static bool unignore_command(struct connection
*caller
,
3881 char *str
, bool check
)
3887 cmd_reply(CMD_IGNORE
, caller
, C_FAIL
,
3888 _("That would be rather silly, since you are not a player."));
3892 sz_strlcpy(buf
, str
);
3893 remove_leading_trailing_spaces(buf
);
3895 n
= conn_pattern_list_size(caller
->server
.ignore_list
);
3897 cmd_reply(CMD_UNIGNORE
, caller
, C_FAIL
, _("Your ignore list is empty."));
3901 /* Parse the range. */
3902 if ('\0' == buf
[0]) {
3903 cmd_reply(CMD_UNIGNORE
, caller
, C_SYNTAX
,
3904 _("Missing range. Try /help unignore."));
3906 } else if ((c
= strchr(buf
, '-'))) {
3908 if ('\0' == buf
[0]) {
3910 } else if (!str_to_int(buf
, &first
)) {
3912 cmd_reply(CMD_UNIGNORE
, caller
, C_SYNTAX
,
3913 _("\"%s\" is not a valid range. Try /help unignore."), buf
);
3918 } else if (!str_to_int(c
, &last
)) {
3920 cmd_reply(CMD_UNIGNORE
, caller
, C_SYNTAX
,
3921 _("\"%s\" is not a valid range. Try /help unignore."), buf
);
3925 if (!str_to_int(buf
, &first
)) {
3926 cmd_reply(CMD_UNIGNORE
, caller
, C_SYNTAX
,
3927 _("\"%s\" is not a valid range. Try /help unignore."), buf
);
3933 if (!(1 <= first
&& first
<= last
&& last
<= n
)) {
3934 if (first
== last
) {
3935 cmd_reply(CMD_UNIGNORE
, caller
, C_FAIL
,
3936 _("Invalid entry number: %d."), first
);
3938 cmd_reply(CMD_UNIGNORE
, caller
, C_FAIL
,
3939 _("Invalid range: %d to %d."), first
, last
);
3949 conn_pattern_list_iterate(caller
->server
.ignore_list
, ppattern
) {
3951 conn_pattern_to_string(ppattern
, buf
, sizeof(buf
));
3952 cmd_reply(CMD_UNIGNORE
, caller
, C_COMMENT
,
3953 _("Removed pattern %s (entry %d) from your ignore list."),
3955 conn_pattern_list_remove(caller
->server
.ignore_list
, ppattern
);
3961 } conn_pattern_list_iterate_end
;
3966 /****************************************************************************
3967 /playercolor command handler.
3968 ****************************************************************************/
3969 static bool playercolor_command(struct connection
*caller
,
3970 char *str
, bool check
)
3972 enum m_pre_result match_result
;
3973 struct player
*pplayer
;
3974 struct rgbcolor
*prgbcolor
= NULL
;
3979 ntokens
= get_tokens(str
, token
, 2, TOKEN_DELIMITERS
);
3982 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_SYNTAX
,
3983 _("Two arguments needed. See '/help playercolor'."));
3988 pplayer
= player_by_name_prefix(token
[0], &match_result
);
3991 cmd_reply_no_such_player(CMD_PLAYERCOLOR
, caller
, token
[0], match_result
);
3996 if (!game_was_started() && game
.server
.plrcolormode
!= PLRCOL_PLR_SET
) {
3997 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_FAIL
,
3998 _("Can only set player color prior to game start if "
3999 "'plrcolormode' is PLR_SET."));
4004 if (0 == fc_strcasecmp(token
[1], "reset")) {
4005 if (!game_was_started()) {
4008 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_FAIL
,
4009 _("Can only unset player color before game starts."));
4013 } else if (!rgbcolor_from_hex(&prgbcolor
, token
[1])) {
4014 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_SYNTAX
,
4015 _("Invalid player color definition. See '/help playercolor'."));
4020 if (prgbcolor
!= NULL
) {
4021 players_iterate(pother
) {
4022 if (pother
!= pplayer
&& pother
->rgb
!= NULL
4023 && rgbcolors_are_equal(pother
->rgb
, prgbcolor
)) {
4024 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_WARNING
,
4025 /* TRANS: "... [c0ffee] for Caesar ... to Hammurabi." */
4026 _("Warning: new color [%s] for %s is identical to %s."),
4027 player_color_ftstr(pother
), player_name(pplayer
),
4028 player_name(pother
));
4030 } players_iterate_end
;
4037 server_player_set_color(pplayer
, prgbcolor
);
4038 cmd_reply(CMD_PLAYERCOLOR
, caller
, C_OK
,
4039 _("Color of player %s set to [%s]."), player_name(pplayer
),
4040 player_color_ftstr(pplayer
));
4044 rgbcolor_destroy(prgbcolor
);
4045 free_tokens(token
, ntokens
);
4050 /**************************************************************************
4051 Cutting away a trailing comment by putting a '\0' on the '#'. The
4052 method handles # in single or double quotes. It also takes care of
4054 **************************************************************************/
4055 static void cut_comment(char *str
)
4058 bool in_single_quotes
= FALSE
, in_double_quotes
= FALSE
;
4060 log_debug("cut_comment(str =' %s')", str
);
4062 for (i
= 0; i
< strlen(str
); i
++) {
4063 if (str
[i
] == '"' && !in_single_quotes
) {
4064 in_double_quotes
= !in_double_quotes
;
4065 } else if (str
[i
] == '\'' && !in_double_quotes
) {
4066 in_single_quotes
= !in_single_quotes
;
4067 } else if (str
[i
] == '#' && !(in_single_quotes
|| in_double_quotes
)
4068 && (i
== 0 || str
[i
- 1] != '\\')) {
4073 log_debug("cut_comment: returning '%s'", str
);
4076 /**************************************************************************
4078 **************************************************************************/
4079 static bool quit_game(struct connection
*caller
, bool check
)
4082 cmd_reply(CMD_QUIT
, caller
, C_OK
, _("Goodbye."));
4083 ggz_report_victory();
4089 /**************************************************************************
4090 Main entry point for "command input".
4091 **************************************************************************/
4092 bool handle_stdin_input(struct connection
*caller
, const char *str
,
4095 return handle_stdin_input_real(caller
, str
, check
, 0);
4098 /**************************************************************************
4099 Handle "command input", which could really come from stdin on console,
4100 or from client chat command, or read from file with -r, etc.
4101 caller==NULL means console, str is the input, which may optionally
4102 start with SERVER_COMMAND_PREFIX character.
4104 If check is TRUE, then do nothing, just check syntax.
4105 **************************************************************************/
4106 static bool handle_stdin_input_real(struct connection
*caller
,
4107 const char *str
, bool check
,
4110 char command
[MAX_LEN_CONSOLE_LINE
], arg
[MAX_LEN_CONSOLE_LINE
],
4111 allargs
[MAX_LEN_CONSOLE_LINE
], full_command
[MAX_LEN_CONSOLE_LINE
],
4114 enum command_id cmd
;
4115 enum cmdlevel level
;
4117 /* notify to the server console */
4118 if (!check
&& caller
) {
4119 con_write(C_COMMENT
, "%s: '%s'", caller
->username
, str
);
4122 /* if the caller may not use any commands at all, don't waste any time */
4123 if (may_use_nothing(caller
)) {
4124 cmd_reply(CMD_HELP
, caller
, C_FAIL
,
4125 _("Sorry, you are not allowed to use server commands."));
4129 /* Is it a comment or a blank line? */
4130 /* line is comment if the first non-whitespace character is '#': */
4131 cptr_s
= skip_leading_spaces((char *)str
);
4132 if (*cptr_s
== '\0' || *cptr_s
== '#') {
4136 /* commands may be prefixed with SERVER_COMMAND_PREFIX, even when
4137 given on the server command line - rp */
4138 if (*cptr_s
== SERVER_COMMAND_PREFIX
) cptr_s
++;
4140 for (; *cptr_s
!= '\0' && !fc_isalnum(*cptr_s
); cptr_s
++) {
4144 /* copy the full command, in case we need it for voting purposes. */
4145 sz_strlcpy(full_command
, cptr_s
);
4148 * cptr_s points now to the beginning of the real command. It has
4149 * skipped leading whitespace, the SERVER_COMMAND_PREFIX and any
4150 * other non-alphanumeric characters.
4152 for (cptr_d
= command
; *cptr_s
!= '\0' && fc_isalnum(*cptr_s
)
4153 && cptr_d
< command
+ sizeof(command
) - 1; cptr_s
++, cptr_d
++) {
4158 cptr_s
= skip_leading_spaces(cptr_s
);
4160 /* keep this before we cut everything after a space */
4161 sz_strlcpy(allargs
, cptr_s
);
4162 cut_comment(allargs
);
4164 sz_strlcpy(arg
, cptr_s
);
4167 i
= strlen(arg
) - 1;
4168 while (i
> 0 && fc_isspace(arg
[i
])) {
4172 cmd
= command_named(command
, FALSE
);
4173 if (cmd
== CMD_AMBIGUOUS
) {
4174 cmd
= command_named(command
, TRUE
);
4175 cmd_reply(cmd
, caller
, C_SYNTAX
,
4176 _("Warning: '%s' interpreted as '%s', but it is ambiguous."
4178 command
, command_name_by_number(cmd
), caller
?"/":"");
4179 } else if (cmd
== CMD_UNRECOGNIZED
) {
4180 cmd_reply(cmd
, caller
, C_SYNTAX
, _("Unknown command '%s%s'. "
4182 caller
? "/" : "", command
, caller
? "/" : "");
4186 level
= command_level(command_by_number(cmd
));
4188 if (conn_can_vote(caller
, NULL
) && level
== ALLOW_CTRL
4189 && conn_get_access(caller
) == ALLOW_BASIC
&& !check
) {
4191 bool caller_had_vote
= (NULL
!= get_vote_by_caller(caller
));
4193 /* Check if the vote command would succeed. If we already have a vote
4194 * going, cancel it in favour of the new vote command. You can only
4195 * have one vote at a time. This is done by vote_new(). */
4196 if (handle_stdin_input_real(caller
, full_command
, TRUE
,
4198 && (vote
= vote_new(caller
, allargs
, cmd
))) {
4199 char votedesc
[MAX_LEN_CONSOLE_LINE
];
4200 const struct player
*teamplr
;
4202 struct ft_color color
;
4204 if (caller_had_vote
) {
4205 cmd_reply(CMD_VOTE
, caller
, C_COMMENT
,
4206 /* TRANS: "vote" as a process */
4207 _("Your new vote canceled your previous vote."));
4210 describe_vote(vote
, votedesc
, sizeof(votedesc
));
4212 if (vote_is_team_only(vote
)) {
4213 /* TRANS: "vote" as a process */
4214 what
= _("New teamvote");
4215 teamplr
= conn_get_player(caller
);
4216 color
= ftc_vote_team
;
4218 /* TRANS: "vote" as a process */
4219 what
= _("New vote");
4221 color
= ftc_vote_public
;
4223 notify_team(teamplr
, NULL
, E_VOTE_NEW
, color
,
4224 /* TRANS: "[New vote|New teamvote] (number 3)
4225 * by fred: proposed change" */
4226 _("%s (number %d) by %s: %s"), what
,
4227 vote
->vote_no
, caller
->username
, votedesc
);
4229 /* Vote on your own suggestion. */
4230 connection_vote(caller
, vote
, VOTE_YES
);
4234 cmd_reply(CMD_VOTE
, caller
, C_FAIL
,
4235 /* TRANS: "vote" as a process */
4236 _("Your new vote (\"%s\") was not "
4237 "legal or was not recognized."), full_command
);
4242 if (caller
&& !(check
&& conn_get_access(caller
) >= ALLOW_BASIC
4243 && level
== ALLOW_CTRL
)
4244 && conn_get_access(caller
) < level
) {
4245 cmd_reply(cmd
, caller
, C_FAIL
,
4246 _("You are not allowed to use this command."));
4251 struct conn_list
*echo_list
= NULL
;
4252 bool echo_list_allocated
= FALSE
;
4254 switch (command_echo(command_by_number(cmd
))) {
4257 case CMD_ECHO_ADMINS
:
4258 conn_list_iterate(game
.est_connections
, pconn
) {
4259 if (ALLOW_ADMIN
<= conn_get_access(pconn
)) {
4260 if (NULL
== echo_list
) {
4261 echo_list
= conn_list_new();
4262 echo_list_allocated
= TRUE
;
4264 conn_list_append(echo_list
, pconn
);
4266 } conn_list_iterate_end
;
4269 echo_list
= game
.est_connections
;
4273 if (NULL
!= echo_list
) {
4275 notify_conn(echo_list
, NULL
, E_SETTING
, ftc_any
,
4276 "%s: '%s %s'", caller
->username
, command
, arg
);
4278 notify_conn(echo_list
, NULL
, E_SETTING
, ftc_server_prompt
,
4279 "%s: '%s %s'", _("(server prompt)"), command
, arg
);
4281 if (echo_list_allocated
) {
4282 conn_list_destroy(echo_list
);
4289 return remove_player_command(caller
, arg
, check
);
4291 return save_command(caller
, arg
, check
);
4294 return scensave_command(caller
, arg
, check
);
4297 return load_command(caller
, arg
, check
);
4298 case CMD_METAPATCHES
:
4299 return metapatches_command(caller
, arg
, check
);
4300 case CMD_METAMESSAGE
:
4301 return metamessage_command(caller
, arg
, check
);
4303 return metaconnection_command(caller
, arg
, check
);
4304 case CMD_METASERVER
:
4305 return metaserver_command(caller
, arg
, check
);
4307 return show_help(caller
, arg
);
4309 return show_serverid(caller
, arg
);
4311 return show_list(caller
, arg
);
4313 return toggle_ai_command(caller
, arg
, check
);
4315 return take_command(caller
, arg
, check
);
4317 return observe_command(caller
, arg
, check
);
4319 return detach_command(caller
, arg
, check
);
4321 return create_command(caller
, arg
, check
);
4323 return set_away(caller
, arg
, check
);
4329 case CMD_EXPERIMENTAL
:
4330 return set_ai_level_named(caller
, arg
, command_name_by_number(cmd
), check
);
4332 return quit_game(caller
, check
);
4334 return cut_client_connection(caller
, arg
, check
);
4336 return show_command(caller
, arg
, check
);
4338 return explain_option(caller
, arg
, check
);
4340 return debug_command(caller
, arg
, check
);
4342 return set_command(caller
, arg
, check
);
4344 return team_command(caller
, arg
, check
);
4345 case CMD_RULESETDIR
:
4346 return set_rulesetdir(caller
, arg
, check
, read_recursion
);
4348 return wall(arg
, check
);
4349 case CMD_CONNECTMSG
:
4350 return connectmsg_command(caller
, arg
, check
);
4352 return vote_command(caller
, arg
, check
);
4353 case CMD_CANCELVOTE
:
4354 return cancelvote_command(caller
, arg
, check
);
4355 case CMD_READ_SCRIPT
:
4356 return read_command(caller
, arg
, check
, read_recursion
);
4357 case CMD_WRITE_SCRIPT
:
4358 return write_command(caller
, arg
, check
);
4360 return reset_command(caller
, arg
, check
, read_recursion
);
4362 return lua_command(caller
, arg
, check
);
4364 return kick_command(caller
, arg
, check
);
4366 return delegate_command(caller
, arg
, check
);
4368 return fcdb_command(caller
, arg
, check
);
4370 return mapimg_command(caller
, arg
, check
);
4371 case CMD_RFCSTYLE
: /* see console.h for an explanation */
4373 con_set_style(!con_get_style());
4377 return cmdlevel_command(caller
, arg
, check
);
4378 case CMD_FIRSTLEVEL
:
4379 return firstlevel_command(caller
, check
);
4381 return timeout_command(caller
, allargs
, check
);
4382 case CMD_START_GAME
:
4383 return start_command(caller
, check
, FALSE
);
4385 return end_command(caller
, arg
, check
);
4387 return surrender_command(caller
, arg
, check
);
4389 return ignore_command(caller
, arg
, check
);
4391 return unignore_command(caller
, arg
, check
);
4392 case CMD_PLAYERCOLOR
:
4393 return playercolor_command(caller
, arg
, check
);
4395 case CMD_UNRECOGNIZED
:
4399 /* should NEVER happen! */
4400 log_error("Unknown command variant: %d.", cmd
);
4404 /**************************************************************************
4405 End the game immediately in a draw.
4406 **************************************************************************/
4407 static bool end_command(struct connection
*caller
, char *str
, bool check
)
4409 if (S_S_RUNNING
== server_state()) {
4413 notify_conn(game
.est_connections
, NULL
, E_GAME_END
, ftc_server
,
4414 _("Game is over."));
4415 set_server_state(S_S_OVER
);
4416 force_end_of_sniff
= TRUE
;
4417 cmd_reply(CMD_END_GAME
, caller
, C_OK
,
4418 _("Ending the game. The server will restart once all clients "
4419 "have disconnected."));
4422 cmd_reply(CMD_END_GAME
, caller
, C_FAIL
,
4423 _("Cannot end the game: no game running."));
4428 /**************************************************************************
4429 Concede the game. You still continue playing until all but one player
4430 or team remains un-conceded.
4431 **************************************************************************/
4432 static bool surrender_command(struct connection
*caller
, char *str
, bool check
)
4434 if (S_S_RUNNING
== server_state() && caller
&& NULL
!= caller
->playing
) {
4438 notify_conn(game
.est_connections
, NULL
, E_GAME_END
, ftc_server
,
4439 _("%s has conceded the game and can no longer win."),
4440 player_name(caller
->playing
));
4441 player_status_add(caller
->playing
, PSTATUS_SURRENDER
);
4444 cmd_reply(CMD_SURRENDER
, caller
, C_FAIL
, _("You cannot surrender now."));
4449 /* Define the possible arguments to the reset command */
4450 #define SPECENUM_NAME reset_args
4451 #define SPECENUM_VALUE0 RESET_GAME
4452 #define SPECENUM_VALUE0NAME "game"
4453 #define SPECENUM_VALUE1 RESET_RULESET
4454 #define SPECENUM_VALUE1NAME "ruleset"
4455 #define SPECENUM_VALUE2 RESET_SCRIPT
4456 #define SPECENUM_VALUE2NAME "script"
4457 #define SPECENUM_VALUE3 RESET_DEFAULT
4458 #define SPECENUM_VALUE3NAME "default"
4459 #include "specenum_gen.h"
4461 /**************************************************************************
4462 Returns possible parameters for the reset command.
4463 **************************************************************************/
4464 static const char *reset_accessor(int i
)
4466 i
= CLIP(0, i
, reset_args_max());
4467 return reset_args_name((enum reset_args
) i
);
4470 /**************************************************************************
4471 Reload the game settings from the ruleset and reload the init script if
4473 **************************************************************************/
4474 static bool reset_command(struct connection
*caller
, char *arg
, bool check
,
4477 enum m_pre_result result
;
4480 /* match the argument */
4481 result
= match_prefix(reset_accessor
, reset_args_max() + 1, 0,
4482 fc_strncasecmp
, NULL
, arg
, &ind
);
4487 /* we have a match */
4489 case M_PRE_AMBIGUOUS
:
4491 /* use 'ruleset' [1] if the game was not started; else use 'game' [2] */
4492 if (S_S_INITIAL
== server_state() && game
.info
.is_new_game
) {
4493 cmd_reply(CMD_RESET
, caller
, C_WARNING
,
4494 _("Guessing argument 'ruleset'."));
4495 ind
= RESET_RULESET
;
4497 cmd_reply(CMD_RESET
, caller
, C_WARNING
,
4498 _("Guessing argument 'game'."));
4505 cmd_reply(CMD_RESET
, caller
, C_FAIL
,
4506 _("The valid arguments are: 'game', 'ruleset', 'script' "
4518 if (!game
.info
.is_new_game
) {
4519 if (settings_game_reset()) {
4520 cmd_reply(CMD_RESET
, caller
, C_OK
,
4521 _("Reset all settings to the values at the game start."));
4523 cmd_reply(CMD_RESET
, caller
, C_FAIL
,
4524 _("No saved settings from the game start available."));
4528 cmd_reply(CMD_RESET
, caller
, C_FAIL
, _("No game started..."));
4534 /* Restore game settings save in game.ruleset. */
4535 if (reload_rulesets_settings()) {
4536 cmd_reply(CMD_RESET
, caller
, C_OK
,
4537 _("Reset all settings to ruleset values."));
4539 cmd_reply(CMD_RESET
, caller
, C_FAIL
,
4540 _("Failed to reset settings to ruleset values."));
4545 cmd_reply(CMD_RESET
, caller
, C_OK
,
4546 _("Reset all settings and rereading the server start "
4549 /* load initial script */
4550 if (NULL
!= srvarg
.script_filename
4551 && !read_init_script_real(NULL
, srvarg
.script_filename
, TRUE
, FALSE
,
4552 read_recursion
+ 1)) {
4553 if (NULL
!= caller
) {
4554 cmd_reply(CMD_RESET
, caller
, C_FAIL
,
4555 _("Could not read script file '%s'."),
4556 srvarg
.script_filename
);
4563 cmd_reply(CMD_RESET
, caller
, C_OK
,
4564 _("Reset all settings to default values."));
4569 send_server_settings(game
.est_connections
);
4570 cmd_reply(CMD_RESET
, caller
, C_OK
, _("Settings re-initialized."));
4572 /* list changed values */
4573 show_changed(caller
, check
, read_recursion
);
4577 /* Define the possible arguments to the delegation command */
4578 #define SPECENUM_NAME lua_args
4579 #define SPECENUM_VALUE0 LUA_CMD
4580 #define SPECENUM_VALUE0NAME "cmd"
4581 #define SPECENUM_VALUE1 LUA_FILE
4582 #define SPECENUM_VALUE1NAME "file"
4583 #include "specenum_gen.h"
4585 /*****************************************************************************
4586 Returns possible parameters for the reset command.
4587 *****************************************************************************/
4588 static const char *lua_accessor(int i
)
4590 i
= CLIP(0, i
, lua_args_max());
4591 return lua_args_name((enum lua_args
) i
);
4594 /*****************************************************************************
4595 Evaluate a line of lua script or a lua script file.
4596 *****************************************************************************/
4597 static bool lua_command(struct connection
*caller
, char *arg
, bool check
)
4600 const char extension
[] = ".lua", *real_filename
= NULL
;
4601 char luafile
[4096], tilde_filename
[4096];
4602 char *tokens
[1], *luaarg
= NULL
;
4604 enum m_pre_result result
;
4607 ntokens
= get_tokens(arg
, tokens
, 1, TOKEN_DELIMITERS
);
4610 /* match the argument */
4611 result
= match_prefix(lua_accessor
, lua_args_max() + 1, 0,
4612 fc_strncasecmp
, NULL
, tokens
[0], &ind
);
4617 /* We have a match */
4618 luaarg
= arg
+ strlen(lua_args_name(ind
));
4619 luaarg
= skip_leading_spaces(luaarg
);
4624 case M_PRE_AMBIGUOUS
:
4628 /* Fall back to depreciated 'lua <script command>' syntax. */
4629 cmd_reply(CMD_LUA
, caller
, C_SYNTAX
,
4630 _("Fall back to old syntax '%slua <script command>'."),
4638 if (luaarg
== NULL
) {
4639 cmd_reply(CMD_LUA
, caller
, C_FAIL
,
4640 _("No lua command or lua script file. See '%shelp lua'."),
4648 /* Nothing to check. */
4651 /* Abuse real_filename to find if we already have a .lua extension. */
4652 real_filename
= luaarg
+ strlen(luaarg
) - MIN(strlen(extension
),
4654 if (strcmp(real_filename
, extension
) != 0) {
4655 fc_snprintf(luafile
, sizeof(luafile
), "%s%s", luaarg
, extension
);
4657 sz_strlcpy(luafile
, luaarg
);
4660 if (is_restricted(caller
)) {
4661 if (!is_safe_filename(luafile
)) {
4662 cmd_reply(CMD_LUA
, caller
, C_FAIL
,
4663 _("Freeciv script '%s' disallowed for security reasons."),
4668 sz_strlcpy(tilde_filename
, luafile
);
4670 interpret_tilde(tilde_filename
, sizeof(tilde_filename
), luafile
);
4673 real_filename
= fileinfoname(get_data_dirs(), tilde_filename
);
4674 if (!real_filename
) {
4675 if (is_restricted(caller
)) {
4676 cmd_reply(CMD_LUA
, caller
, C_FAIL
,
4677 _("No Freeciv script found by the name '%s'."),
4682 /* File is outside data directories */
4683 real_filename
= tilde_filename
;
4695 ret
= script_server_do_string(caller
, luaarg
);
4698 cmd_reply(CMD_LUA
, caller
, C_COMMENT
,
4699 _("Loading Freeciv script file '%s'."), real_filename
);
4701 if (is_reg_file_for_access(real_filename
, FALSE
)
4702 && (script_file
= fc_fopen(real_filename
, "r"))) {
4703 ret
= script_server_do_file(caller
, real_filename
);
4706 cmd_reply(CMD_LUA
, caller
, C_FAIL
,
4707 _("Cannot read Freeciv script '%s'."), real_filename
);
4714 free_tokens(tokens
, ntokens
);
4718 /* Define the possible arguments to the delegation command */
4719 #define SPECENUM_NAME delegate_args
4720 #define SPECENUM_VALUE0 DELEGATE_CANCEL
4721 #define SPECENUM_VALUE0NAME "cancel"
4722 #define SPECENUM_VALUE1 DELEGATE_RESTORE
4723 #define SPECENUM_VALUE1NAME "restore"
4724 #define SPECENUM_VALUE2 DELEGATE_SHOW
4725 #define SPECENUM_VALUE2NAME "show"
4726 #define SPECENUM_VALUE3 DELEGATE_TAKE
4727 #define SPECENUM_VALUE3NAME "take"
4728 #define SPECENUM_VALUE4 DELEGATE_TO
4729 #define SPECENUM_VALUE4NAME "to"
4730 #include "specenum_gen.h"
4732 /*****************************************************************************
4733 Returns possible parameters for the 'delegate' command.
4734 *****************************************************************************/
4735 static const char *delegate_accessor(int i
)
4737 i
= CLIP(0, i
, delegate_args_max());
4738 return delegate_args_name((enum delegate_args
) i
);
4741 /*****************************************************************************
4742 Handle delegation of control.
4743 *****************************************************************************/
4744 static bool delegate_command(struct connection
*caller
, char *arg
,
4748 int ntokens
, ind
= delegate_args_invalid();
4749 enum m_pre_result result
;
4750 bool player_specified
= FALSE
; /* affects messages only */
4752 const char *username
= NULL
;
4753 struct player
*dplayer
= NULL
;
4755 if (!game_was_started()) {
4756 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("Game not started - "
4757 "cannot delegate yet."));
4761 ntokens
= get_tokens(arg
, tokens
, 3, TOKEN_DELIMITERS
);
4764 /* match the argument */
4765 result
= match_prefix(delegate_accessor
, delegate_args_max() + 1, 0,
4766 fc_strncasecmp
, NULL
, tokens
[0], &ind
);
4771 /* we have a match */
4775 /* Use 'delegate show' as default. */
4776 ind
= DELEGATE_SHOW
;
4779 case M_PRE_AMBIGUOUS
:
4783 ind
= delegate_args_invalid();
4788 /* Use 'delegate show' as default. */
4789 ind
= DELEGATE_SHOW
;
4793 if (!delegate_args_is_valid(ind
)) {
4795 enum delegate_args valid_args
;
4797 for (valid_args
= delegate_args_begin();
4798 valid_args
!= delegate_args_end();
4799 valid_args
= delegate_args_next(valid_args
)) {
4800 cat_snprintf(buf
, sizeof(buf
), "'%s'",
4801 delegate_args_name(valid_args
));
4802 if (valid_args
!= delegate_args_max()) {
4803 cat_snprintf(buf
, sizeof(buf
), ", ");
4807 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4808 /* TRANS: do not translate the command 'delegate'. */
4809 _("Valid arguments for 'delegate' are: %s."), buf
);
4814 /* Get the data (player, username for delegation) and validate it. */
4816 case DELEGATE_CANCEL
:
4817 /* delegate cancel [player] */
4819 if (!caller
|| conn_get_access(caller
) >= ALLOW_ADMIN
) {
4820 player_specified
= TRUE
;
4821 dplayer
= player_by_name_prefix(tokens
[1], &result
);
4823 cmd_reply_no_such_player(CMD_DELEGATE
, caller
, tokens
[1], result
);
4828 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4829 _("Command level '%s' or greater needed to modify "
4830 "others' delegations."), cmdlevel_name(ALLOW_ADMIN
));
4835 dplayer
= conn_get_player(caller
);
4837 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4838 _("Please specify a player for whom delegation should "
4845 case DELEGATE_RESTORE
:
4846 /* delegate restore */
4848 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4849 _("You can't switch players from the console."));
4855 /* delegate show [player] */
4857 player_specified
= TRUE
;
4858 dplayer
= player_by_name_prefix(tokens
[1], &result
);
4860 cmd_reply_no_such_player(CMD_DELEGATE
, caller
, tokens
[1], result
);
4865 dplayer
= conn_get_player(caller
);
4867 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4868 _("Please specify a player for whom the delegation should "
4876 /* delegate take <player> */
4878 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4879 _("You can't switch players from the console."));
4884 player_specified
= TRUE
;
4885 dplayer
= player_by_name_prefix(tokens
[1], &result
);
4887 cmd_reply_no_such_player(CMD_DELEGATE
, caller
, tokens
[1], result
);
4892 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4893 _("Please specify a player to take control of."));
4899 /* delegate to <username> [player] */
4901 username
= tokens
[1];
4903 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4904 _("Please specify a user to whom control is to be delegated."));
4909 if (!caller
|| conn_get_access(caller
) >= ALLOW_ADMIN
) {
4910 player_specified
= TRUE
;
4911 dplayer
= player_by_name_prefix(tokens
[2], &result
);
4913 cmd_reply_no_such_player(CMD_DELEGATE
, caller
, tokens
[2], result
);
4918 cmd_reply(CMD_DELEGATE
, caller
, C_SYNTAX
,
4919 _("Command level '%s' or greater needed to modify "
4920 "others' delegations."), cmdlevel_name(ALLOW_ADMIN
));
4925 dplayer
= conn_controls_player(caller
) ? conn_get_player(caller
) : NULL
;
4927 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4928 _("You do not control a player."));
4936 /* All checks done to this point will give pretty much the same result at
4937 * any time. Checks after this point are more likely to vary over time. */
4945 /* Delegate control of player to another user. */
4946 fc_assert_ret_val(dplayer
, FALSE
);
4947 fc_assert_ret_val(username
!= NULL
, FALSE
);
4949 /* Forbid delegation of players already controlled by a delegate, and
4950 * those 'put aside' by a delegate.
4951 * For the former, if player is already under active delegate control,
4952 * we wouldn't handle the revocation that would be necessary if their
4953 * delegation changed; and the authority granted to delegates does not
4954 * include the ability to sub-delegate.
4955 * For the latter, allowing control of the 'put aside' player to be
4956 * delegated would break the invariant that whenever a user is connected,
4957 * they are attached to 'their' player. */
4958 if (player_delegation_active(dplayer
)) {
4959 if (!player_delegation_get(dplayer
)) {
4960 /* Attempting to change a 'put aside' player. Must be admin
4962 fc_assert(player_specified
);
4963 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4964 _("Can't delegate control of '%s' belonging to %s while "
4965 "they are controlling another player."),
4966 player_name(dplayer
), dplayer
->username
);
4967 } else if (player_specified
) {
4968 /* Admin or console attempting to change a controlled player. */
4969 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4970 _("Can't change delegation of '%s' while controlled by "
4971 "delegate %s."), player_name(dplayer
), dplayer
->username
);
4973 /* Caller must be the delegate. Give more specific message.
4974 * (We don't know if they thought they were delegating their
4975 * original or delegated player, but we don't allow either.) */
4976 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4977 _("You can't delegate control while you are controlling "
4978 "a delegated player yourself."));
4984 /* Forbid delegation to player's original owner
4985 * (from above test we know that dplayer->username is the original now) */
4986 if (strcmp(dplayer
->username
, username
) == 0) {
4987 if (player_specified
) {
4988 /* Probably admin or console. */
4989 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4990 /* TRANS: don't translate 'delegate cancel' */
4991 _("%s already owns '%s', so cannot also be delegate. "
4992 "Use '%sdelegate cancel' to cancel an existing "
4994 username
, player_name(dplayer
), caller
?"/":"");
4996 /* Player not specified on command line, so they must have been trying
4997 * to delegate control to themself. Give more specific message. */
4998 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
4999 /* TRANS: don't translate '/delegate cancel' */
5000 _("You can't delegate control to yourself. "
5001 "Use '/delegate cancel' to cancel an existing "
5008 /* FIXME: if control was already delegated to someone else, that
5009 * delegation is implicitly canceled. Perhaps we should tell someone. */
5011 player_delegation_set(dplayer
, username
);
5012 cmd_reply(CMD_DELEGATE
, caller
, C_OK
,
5013 _("Control of player '%s' delegated to user %s."),
5014 player_name(dplayer
), username
);
5020 /* Show delegations. */
5021 fc_assert_ret_val(dplayer
, FALSE
);
5023 if (player_delegation_get(dplayer
) == NULL
) {
5024 /* No delegation set. */
5025 cmd_reply(CMD_DELEGATE
, caller
, C_COMMENT
,
5026 _("No delegation defined for '%s'."),
5027 player_name(dplayer
));
5029 cmd_reply(CMD_DELEGATE
, caller
, C_COMMENT
,
5030 _("Control of player '%s' delegated to user %s."),
5031 player_name(dplayer
), player_delegation_get(dplayer
));
5037 case DELEGATE_CANCEL
:
5038 if (player_delegation_get(dplayer
) == NULL
) {
5039 /* No delegation set. */
5040 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5041 _("No delegation defined for '%s'."),
5042 player_name(dplayer
));
5047 if (player_delegation_active(dplayer
)) {
5048 /* Delegation is currently in use. Forcibly break connection. */
5049 struct connection
*pdelegate
;
5050 /* (Can only happen if admin/console issues this command, as owner
5051 * will end use by their mere presence.) */
5052 fc_assert(player_specified
);
5053 pdelegate
= conn_by_user(player_delegation_get(dplayer
));
5054 fc_assert_ret_val(pdelegate
!= NULL
, FALSE
);
5055 if (!connection_delegate_restore(pdelegate
)) {
5056 /* Should never happen. Generic failure message. */
5057 log_error("Failed to restore %s's connection as %s during "
5058 "'delegate cancel'.", pdelegate
->username
,
5059 delegate_player_str(pdelegate
->server
.delegation
.playing
,
5060 pdelegate
->server
.delegation
.observer
));
5061 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("Unexpected failure."));
5065 notify_conn(pdelegate
->self
, NULL
, E_CONNECTION
, ftc_server
,
5066 _("Your delegated control of player '%s' was canceled."),
5067 player_name(dplayer
));
5070 player_delegation_set(dplayer
, NULL
);
5071 cmd_reply(CMD_DELEGATE
, caller
, C_OK
, _("Delegation of '%s' canceled."),
5072 player_name(dplayer
));
5078 /* Try to take another player. */
5079 fc_assert_ret_val(dplayer
, FALSE
);
5080 fc_assert_ret_val(caller
, FALSE
);
5082 if (caller
->server
.delegation
.status
) {
5083 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5084 /* TRANS: don't translate '/delegate restore'. */
5085 _("You are already controlling a delegated player. "
5086 "Use '/delegate restore' to relinquish control of your "
5087 "current player first."));
5092 /* Don't allow 'put aside' players to be delegated; the invariant is
5093 * that while the owning user is connected to the server, they are
5094 * in sole control of 'their' player. */
5095 if (conn_controls_player(caller
)
5096 && player_delegation_get(conn_get_player(caller
)) != NULL
) {
5097 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5098 /* TRANS: don't translate '/delegate cancel'. */
5099 _("Can't take player while you have delegated control "
5100 "yourself. Use '/delegate cancel' to cancel your own "
5101 "delegation first."));
5106 /* Taking your own player makes no sense. */
5107 if (conn_controls_player(caller
)
5108 && dplayer
== conn_get_player(caller
)) {
5109 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("You already control '%s'."),
5110 player_name(conn_get_player(caller
)));
5115 if (!player_delegation_get(dplayer
)
5116 || strcmp(player_delegation_get(dplayer
), caller
->username
) != 0) {
5117 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5118 _("Control of player '%s' has not been delegated to you."),
5119 player_name(dplayer
));
5124 /* If the player is controlled by another user, fail. */
5125 if (dplayer
->is_connected
) {
5126 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5127 _("Another user already controls player '%s'."),
5128 player_name(dplayer
));
5133 if (!connection_delegate_take(caller
, dplayer
)) {
5134 /* Should never happen. Generic failure message. */
5135 log_error("%s failed to take control of '%s' during 'delegate take'.",
5136 caller
->username
, player_name(dplayer
));
5137 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("Unexpected failure."));
5142 cmd_reply(CMD_DELEGATE
, caller
, C_OK
,
5143 _("%s is now controlling player '%s'."), caller
->username
,
5144 player_name(conn_get_player(caller
)));
5149 case DELEGATE_RESTORE
:
5150 /* Delegate user relinquishes control of delegated player, returning to
5151 * previous view (e.g. observer) if any. */
5152 fc_assert_ret_val(caller
, FALSE
);
5154 if (!caller
->server
.delegation
.status
) {
5155 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
,
5156 _("You are not currently controlling a delegated player."));
5161 if (!connection_delegate_restore(caller
)) {
5162 /* Should never happen. Generic failure message. */
5163 log_error("Failed to restore %s's connection as %s during "
5164 "'delegate restore'.", caller
->username
,
5165 delegate_player_str(caller
->server
.delegation
.playing
,
5166 caller
->server
.delegation
.observer
));
5167 cmd_reply(CMD_DELEGATE
, caller
, C_FAIL
, _("Unexpected failure."));
5172 cmd_reply(CMD_DELEGATE
, caller
, C_OK
,
5173 /* TRANS: "<user> is now connected to <player>" where <player>
5174 * can also be "global observer" or "nothing" */
5175 _("%s is now connected as %s."), caller
->username
,
5176 delegate_player_str(conn_get_player(caller
), caller
->observer
));
5183 free_tokens(tokens
, ntokens
);
5187 /*****************************************************************************
5188 Return static string describing what a connection is connected to.
5189 *****************************************************************************/
5190 static const char *delegate_player_str(struct player
*pplayer
, bool observer
)
5192 static struct astring buf
;
5196 astr_set(&buf
, _("%s (observer)"), player_name(pplayer
));
5198 astr_set(&buf
, "%s", player_name(pplayer
));
5200 } else if (observer
) {
5201 astr_set(&buf
, "%s", _("global observer"));
5203 /* TRANS: in place of player name or "global observer" */
5204 astr_set(&buf
, "%s", _("nothing"));
5207 return astr_str(&buf
);
5210 /* Define the possible arguments to the mapimg command */
5211 /* map image layers */
5212 #define SPECENUM_NAME mapimg_args
5213 #define SPECENUM_VALUE0 MAPIMG_COLORTEST
5214 #define SPECENUM_VALUE0NAME "colortest"
5215 #define SPECENUM_VALUE1 MAPIMG_CREATE
5216 #define SPECENUM_VALUE1NAME "create"
5217 #define SPECENUM_VALUE2 MAPIMG_DEFINE
5218 #define SPECENUM_VALUE2NAME "define"
5219 #define SPECENUM_VALUE3 MAPIMG_DELETE
5220 #define SPECENUM_VALUE3NAME "delete"
5221 #define SPECENUM_VALUE4 MAPIMG_SHOW
5222 #define SPECENUM_VALUE4NAME "show"
5223 #define SPECENUM_COUNT MAPIMG_COUNT
5224 #include "specenum_gen.h"
5226 /**************************************************************************
5227 Returns possible parameters for the mapimg command.
5228 **************************************************************************/
5229 static const char *mapimg_accessor(int i
)
5231 i
= CLIP(0, i
, mapimg_args_max());
5232 return mapimg_args_name((enum mapimg_args
) i
);
5235 /**************************************************************************
5236 Handle mapimg command
5237 **************************************************************************/
5238 static bool mapimg_command(struct connection
*caller
, char *arg
, bool check
)
5240 enum m_pre_result result
;
5241 int ind
, ntokens
, id
;
5245 ntokens
= get_tokens(arg
, token
, 2, TOKEN_DELIMITERS
);
5248 /* match the argument */
5249 result
= match_prefix(mapimg_accessor
, MAPIMG_COUNT
, 0,
5250 fc_strncasecmp
, NULL
, token
[0], &ind
);
5255 /* we have a match */
5257 case M_PRE_AMBIGUOUS
:
5258 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5259 _("Ambiguous 'mapimg' command."));
5264 /* use 'show' as default */
5272 enum mapimg_args valid_args
;
5274 for (valid_args
= mapimg_args_begin();
5275 valid_args
!= mapimg_args_end();
5276 valid_args
= mapimg_args_next(valid_args
)) {
5277 cat_snprintf(buf
, sizeof(buf
), "'%s'",
5278 mapimg_args_name(valid_args
));
5279 if (valid_args
!= mapimg_args_max()) {
5280 cat_snprintf(buf
, sizeof(buf
), ", ");
5284 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5285 _("The valid arguments are: %s."), buf
);
5292 /* use 'show' as default */
5299 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5300 _("Missing argument for 'mapimg define'."));
5303 /* 'mapimg define <mapstr>' */
5304 if (!mapimg_define(token
[1], check
)) {
5305 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5306 _("Can't use definition: %s."), mapimg_error());
5309 /* Validated OK, bail out now */
5311 } else if (game_was_started()
5312 && mapimg_isvalid(mapimg_count() - 1) == NULL
) {
5313 /* game was started - error in map image definition check */
5314 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5315 _("Can't use definition: %s."), mapimg_error());
5318 int id
= mapimg_count() - 1;
5319 char str
[MAX_LEN_MAPDEF
];
5321 mapimg_id2str(id
, str
, sizeof(str
));
5322 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, _("Defined as map image "
5323 "definition %d: '%s'."),
5331 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5332 _("Missing argument for 'mapimg delete'."));
5334 } else if (ntokens
== 2 && strcmp(token
[1], "all") == 0) {
5335 /* 'mapimg delete all' */
5340 for (id
= 0; id
< mapimg_count(); id
++) {
5343 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, _("All map image definitions "
5345 } else if (ntokens
== 2 && sscanf(token
[1], "%d", &id
) != 0) {
5346 /* 'mapimg delete <id>' */
5351 if (!mapimg_delete(id
)) {
5352 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5353 _("Couldn't delete definition: %s."), mapimg_error());
5356 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, _("Map image definition %d "
5360 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5361 _("Bad argument for 'mapimg delete': '%s'."), token
[1]);
5367 if (ntokens
< 2 || (ntokens
== 2 && strcmp(token
[1], "all") == 0)) {
5368 /* 'mapimg show' or 'mapimg show all' */
5372 show_mapimg(caller
, CMD_MAPIMG
);
5373 } else if (ntokens
== 2 && sscanf(token
[1], "%d", &id
) != 0) {
5375 /* 'mapimg show <id>' */
5380 if (mapimg_show(id
, str
, sizeof(str
), TRUE
)) {
5381 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, "%s", str
);
5383 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5384 _("Couldn't show definition: %s."), mapimg_error());
5388 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5389 _("Bad argument for 'mapimg show': '%s'."), token
[1]);
5394 case MAPIMG_COLORTEST
:
5399 mapimg_colortest(game
.server
.save_name
, NULL
);
5400 cmd_reply(CMD_MAPIMG
, caller
, C_OK
, _("Map color test images saved."));
5405 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5406 _("Missing argument for 'mapimg create'."));
5411 if (strcmp(token
[1], "all") == 0) {
5412 /* 'mapimg create all' */
5417 for (id
= 0; id
< mapimg_count(); id
++) {
5418 struct mapdef
*pmapdef
= mapimg_isvalid(id
);
5421 || !mapimg_create(pmapdef
, TRUE
, game
.server
.save_name
,
5422 srvarg
.saves_pathname
)) {
5423 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5424 _("Error saving map image %d: %s."), id
, mapimg_error());
5428 } else if (sscanf(token
[1], "%d", &id
) != 0) {
5429 struct mapdef
*pmapdef
;
5431 /* 'mapimg create <id>' */
5436 pmapdef
= mapimg_isvalid(id
);
5438 || !mapimg_create(pmapdef
, TRUE
, game
.server
.save_name
,
5439 srvarg
.saves_pathname
)) {
5440 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5441 _("Error saving map image %d: %s."), id
, mapimg_error());
5445 cmd_reply(CMD_MAPIMG
, caller
, C_FAIL
,
5446 _("Bad argument for 'mapimg create': '%s'."), token
[1]);
5454 free_tokens(token
, ntokens
);
5459 /* Define the possible arguments to the fcdb command */
5460 #define SPECENUM_NAME fcdb_args
5461 #define SPECENUM_VALUE0 FCDB_RELOAD
5462 #define SPECENUM_VALUE0NAME "reload"
5463 #define SPECENUM_VALUE1 FCDB_LUA
5464 #define SPECENUM_VALUE1NAME "lua"
5465 #define SPECENUM_COUNT FCDB_COUNT
5466 #include "specenum_gen.h"
5468 /**************************************************************************
5469 Returns possible parameters for the fcdb command.
5470 **************************************************************************/
5471 static const char *fcdb_accessor(int i
)
5473 i
= CLIP(0, i
, fcdb_args_max());
5474 return fcdb_args_name((enum fcdb_args
) i
);
5477 /**************************************************************************
5478 Handle the freeciv database script module.
5479 **************************************************************************/
5480 static bool fcdb_command(struct connection
*caller
, char *arg
, bool check
)
5482 enum m_pre_result result
;
5489 cmd_reply(CMD_FCDB
, caller
, C_FAIL
,
5490 _("Freeciv database script deactivated at compile time."));
5494 ntokens
= get_tokens(arg
, token
, 1, TOKEN_DELIMITERS
);
5497 /* match the argument */
5498 result
= match_prefix(fcdb_accessor
, FCDB_COUNT
, 0,
5499 fc_strncasecmp
, NULL
, token
[0], &ind
);
5504 /* we have a match */
5506 case M_PRE_AMBIGUOUS
:
5507 cmd_reply(CMD_FCDB
, caller
, C_FAIL
,
5508 _("Ambiguous fcdb command."));
5525 enum fcdb_args valid_args
;
5527 for (valid_args
= fcdb_args_begin();
5528 valid_args
!= fcdb_args_end();
5529 valid_args
= fcdb_args_next(valid_args
)) {
5530 cat_snprintf(buf
, sizeof(buf
), "'%s'",
5531 fcdb_args_name(valid_args
));
5532 if (valid_args
!= fcdb_args_max()) {
5533 cat_snprintf(buf
, sizeof(buf
), ", ");
5537 cmd_reply(CMD_FCDB
, caller
, C_FAIL
,
5538 _("The valid arguments are: %s."), buf
);
5550 /* Reload database lua script. */
5552 script_fcdb_init(NULL
);
5556 /* Skip whitespaces. */
5557 arg
= skip_leading_spaces(arg
);
5558 /* Skip the base argument 'lua'. */
5560 /* Now execute the scriptlet. */
5561 ret
= script_fcdb_do_string(caller
, arg
);
5567 free_tokens(token
, ntokens
);
5572 /**************************************************************************
5573 Send start command related message
5574 **************************************************************************/
5575 static void start_cmd_reply(struct connection
*caller
, bool notify
, char *msg
)
5577 cmd_reply(CMD_START_GAME
, caller
, C_FAIL
, "%s", msg
);
5579 notify_conn(NULL
, NULL
, E_SETTING
, ftc_server
, "%s", msg
);
5583 /**************************************************************************
5584 Handle start command. Notify all players about errors if notify set.
5585 **************************************************************************/
5586 bool start_command(struct connection
*caller
, bool check
, bool notify
)
5590 switch (server_state()) {
5592 /* Sanity check scenario */
5593 if (game
.info
.is_new_game
&& !check
) {
5594 if (0 < map_startpos_count()
5595 && game
.server
.max_players
> map_startpos_count()) {
5596 /* If we load a pre-generated map (i.e., a scenario) it is possible
5597 * to increase the number of players beyond the number supported by
5598 * the scenario. The solution is a hack: cut the extra players
5599 * when the game starts. */
5600 log_verbose("Reduced maxplayers from %d to %d to fit "
5601 "to the number of start positions.",
5602 game
.server
.max_players
, map_startpos_count());
5603 game
.server
.max_players
= map_startpos_count();
5606 if (normal_player_count() > game
.server
.max_players
) {
5608 struct player
*pplayer
;
5610 for (i
= player_slot_count() - 1; i
>= 0; i
--) {
5611 pplayer
= player_by_number(i
);
5613 server_remove_player(pplayer
);
5615 if (normal_player_count() <= game
.server
.max_players
) {
5620 log_verbose("Had to cut down the number of players to the "
5621 "number of map start positions, there must be "
5622 "something wrong with the savegame or you "
5623 "adjusted the maxplayers value.");
5628 players_iterate(plr
) {
5629 if (!plr
->ai_controlled
) {
5632 } players_iterate_end
;
5634 /* check min_players.
5635 * Allow continuing of savegames where some of the original
5636 * players have died */
5637 if (game
.info
.is_new_game
5638 && human_players
< game
.server
.min_players
) {
5639 start_cmd_reply(caller
, notify
,
5640 _("Not enough human players; game will not start."));
5642 } else if (player_count() < 1) {
5643 /* At least one player required */
5644 start_cmd_reply(caller
, notify
,
5645 _("No players; game will not start."));
5647 } else if (normal_player_count() > server
.playable_nations
) {
5648 start_cmd_reply(caller
, notify
,
5649 _("Not enough nations for all players; game will "
5654 } else if (!caller
) {
5656 /* Called from handle_player_ready()
5657 * Last player just toggled ready-status. */
5658 notify_conn(NULL
, NULL
, E_SETTING
, ftc_game_start
,
5659 _("All players are ready; starting game."));
5663 } else if (NULL
== caller
->playing
|| !caller
->playing
->is_connected
) {
5664 /* A detached or observer player can't do /start. */
5667 /* This might trigger recursive call to start_command() if this is
5668 * last player who gets ready. In that case caller is NULL. */
5669 handle_player_ready(caller
->playing
, player_number(caller
->playing
), TRUE
);
5673 start_cmd_reply(caller
, notify
,
5674 /* TRANS: given when /start is invoked during gameover. */
5675 _("Cannot start the game: the game is waiting for all clients "
5679 start_cmd_reply(caller
, notify
,
5680 /* TRANS: given when /start is invoked while the game
5682 _("Cannot start the game: it is already running."));
5685 log_error("Unknown server state variant: %d.", server_state());
5689 /**************************************************************************
5691 **************************************************************************/
5692 static bool cut_client_connection(struct connection
*caller
, char *name
,
5695 enum m_pre_result match_result
;
5696 struct connection
*ptarget
;
5698 ptarget
= conn_by_user_prefix(name
, &match_result
);
5701 cmd_reply_no_such_conn(CMD_CUT
, caller
, name
, match_result
);
5707 if (conn_controls_player(ptarget
)) {
5708 /* If we cut the connection, unassign the login name.*/
5709 sz_strlcpy(ptarget
->playing
->username
, ANON_USER_NAME
);
5712 cmd_reply(CMD_CUT
, caller
, C_DISCONNECTED
,
5713 _("Cutting connection %s."), ptarget
->username
);
5714 connection_close_server(ptarget
, _("connection cut"));
5720 /****************************************************************************
5721 Utility for 'kick_hash' tables.
5722 ****************************************************************************/
5723 static time_t *time_duplicate(const time_t *t
)
5725 time_t *d
= fc_malloc(sizeof(*d
));
5730 /****************************************************************************
5731 Returns FALSE if the connection isn't kicked and can connect the server
5733 ****************************************************************************/
5734 bool conn_is_kicked(struct connection
*pconn
, int *time_remaining
)
5736 time_t time_of_addr_kick
, time_of_user_kick
;
5737 time_t now
, time_of_kick
= 0;
5739 if (NULL
!= time_remaining
) {
5740 *time_remaining
= 0;
5743 fc_assert_ret_val(NULL
!= kick_table_by_addr
, FALSE
);
5744 fc_assert_ret_val(NULL
!= kick_table_by_user
, FALSE
);
5745 fc_assert_ret_val(NULL
!= pconn
, FALSE
);
5747 if (kick_hash_lookup(kick_table_by_addr
, pconn
->server
.ipaddr
,
5748 &time_of_addr_kick
)) {
5749 time_of_kick
= time_of_addr_kick
;
5751 if (kick_hash_lookup(kick_table_by_user
, pconn
->username
,
5753 && time_of_user_kick
> time_of_kick
) {
5754 time_of_kick
= time_of_user_kick
;
5757 if (0 == time_of_kick
) {
5758 return FALSE
; /* Not found. */
5762 if (now
- time_of_kick
> game
.server
.kick_time
) {
5763 /* Kick timeout expired. */
5764 if (0 != time_of_addr_kick
) {
5765 kick_hash_remove(kick_table_by_addr
, pconn
->server
.ipaddr
);
5767 if (0 != time_of_user_kick
) {
5768 kick_hash_remove(kick_table_by_user
, pconn
->username
);
5773 if (NULL
!= time_remaining
) {
5774 *time_remaining
= game
.server
.kick_time
- (now
- time_of_kick
);
5779 /****************************************************************************
5780 Kick command handler.
5781 ****************************************************************************/
5782 static bool kick_command(struct connection
*caller
, char *name
, bool check
)
5784 char ipaddr
[FC_MEMBER_SIZEOF(struct connection
, server
.ipaddr
)];
5785 struct connection
*pconn
;
5786 enum m_pre_result match_result
;
5789 remove_leading_trailing_spaces(name
);
5790 pconn
= conn_by_user_prefix(name
, &match_result
);
5791 if (NULL
== pconn
) {
5792 cmd_reply_no_such_conn(CMD_KICK
, caller
, name
, match_result
);
5796 if (NULL
!= caller
&& ALLOW_ADMIN
> conn_get_access(caller
)) {
5797 const int MIN_UNIQUE_CONNS
= 3;
5798 const char *unique_ipaddr
[MIN_UNIQUE_CONNS
];
5799 int i
, num_unique_connections
= 0;
5801 if (pconn
== caller
) {
5802 cmd_reply(CMD_KICK
, caller
, C_FAIL
, _("You may not kick yourself."));
5806 conn_list_iterate(game
.est_connections
, aconn
) {
5807 for (i
= 0; i
< num_unique_connections
; i
++) {
5808 if (0 == strcmp(unique_ipaddr
[i
], aconn
->server
.ipaddr
)) {
5809 /* Already listed. */
5813 if (i
>= num_unique_connections
) {
5814 num_unique_connections
++;
5815 if (MIN_UNIQUE_CONNS
<= num_unique_connections
) {
5816 /* We have enought already. */
5819 unique_ipaddr
[num_unique_connections
- 1] = aconn
->server
.ipaddr
;
5821 } conn_list_iterate_end
;
5823 if (MIN_UNIQUE_CONNS
> num_unique_connections
) {
5824 cmd_reply(CMD_KICK
, caller
, C_FAIL
,
5825 _("There must be at least %d unique connections to the "
5826 "server for this command to be valid."), MIN_UNIQUE_CONNS
);
5835 sz_strlcpy(ipaddr
, pconn
->server
.ipaddr
);
5837 kick_hash_replace(kick_table_by_addr
, ipaddr
, now
);
5839 conn_list_iterate(game
.all_connections
, aconn
) {
5840 if (0 != strcmp(ipaddr
, aconn
->server
.ipaddr
)) {
5844 if (conn_controls_player(aconn
)) {
5845 /* Unassign the username. */
5846 sz_strlcpy(aconn
->playing
->username
, ANON_USER_NAME
);
5849 kick_hash_replace(kick_table_by_user
, aconn
->username
, now
);
5851 connection_close_server(aconn
, _("kicked"));
5852 } conn_list_iterate_end
;
5858 /**************************************************************************
5859 Show caller introductory help about the server. help_cmd is the command
5861 **************************************************************************/
5862 static void show_help_intro(struct connection
*caller
,
5863 enum command_id help_cmd
)
5865 /* This is formated like extra_help entries for settings and commands: */
5866 char *help
= fc_strdup(
5867 _("Welcome - this is the introductory help text for the Freeciv "
5870 "Two important server concepts are Commands and Options. Commands, "
5871 "such as 'help', are used to interact with the server. Some commands "
5872 "take one or more arguments, separated by spaces. In many cases "
5873 "commands and command arguments may be abbreviated. Options are "
5874 "settings which control the server as it is running.\n"
5876 "To find out how to get more information about commands and options, "
5877 "use 'help help'.\n"
5879 "For the impatient, the main commands to get going are:\n"
5880 " show - to see current options\n"
5881 " set - to set options\n"
5882 " start - to start the game once players have connected\n"
5883 " save - to save the current game\n"
5884 " quit - to exit"));
5886 fc_break_lines(help
, LINE_BREAK
);
5887 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", help
);
5891 /**************************************************************************
5892 Show the caller detailed help for the single COMMAND given by id.
5893 help_cmd is the command the player used.
5894 **************************************************************************/
5895 static void show_help_command(struct connection
*caller
,
5896 enum command_id help_cmd
,
5899 const struct command
*cmd
= command_by_number(id
);
5901 if (command_short_help(cmd
)) {
5902 cmd_reply(help_cmd
, caller
, C_COMMENT
,
5903 /* TRANS: <untranslated name> - translated short help */
5904 _("Command: %s - %s"),
5906 command_short_help(cmd
));
5908 cmd_reply(help_cmd
, caller
, C_COMMENT
,
5909 /* TRANS: <untranslated name> */
5913 if (command_synopsis(cmd
)) {
5914 /* line up the synopsis lines: */
5915 const char *syn
= _("Synopsis: ");
5916 size_t synlen
= strlen(syn
);
5919 fc_snprintf(prefix
, sizeof(prefix
), "%*s", (int) synlen
, " ");
5920 cmd_reply_prefix(help_cmd
, caller
, C_COMMENT
, prefix
,
5921 "%s%s", syn
, command_synopsis(cmd
));
5923 cmd_reply(help_cmd
, caller
, C_COMMENT
,
5924 _("Level: %s"), cmdlevel_name(command_level(cmd
)));
5926 char *help
= command_extra_help(cmd
);
5929 fc_break_lines(help
, LINE_BREAK
);
5930 cmd_reply(help_cmd
, caller
, C_COMMENT
, _("Description:"));
5931 cmd_reply_prefix(help_cmd
, caller
, C_COMMENT
, " ", " %s", help
);
5937 /**************************************************************************
5938 Show the caller list of COMMANDS.
5939 help_cmd is the command the player used.
5940 **************************************************************************/
5941 static void show_help_command_list(struct connection
*caller
,
5942 enum command_id help_cmd
)
5946 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
5947 cmd_reply(help_cmd
, caller
, C_COMMENT
,
5948 _("The following server commands are available:"));
5949 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
5950 if(!caller
&& con_get_style()) {
5951 for (i
=0; i
<CMD_NUM
; i
++) {
5952 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", command_name_by_number(i
));
5955 char buf
[MAX_LEN_CONSOLE_LINE
];
5959 for (i
=0, j
=0; i
<CMD_NUM
; i
++) {
5960 if (may_use(caller
, i
)) {
5961 cat_snprintf(buf
, sizeof(buf
), "%-19s", command_name_by_number(i
));
5962 if((++j
% 4) == 0) {
5963 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", buf
);
5969 cmd_reply(help_cmd
, caller
, C_COMMENT
, "%s", buf
);
5971 cmd_reply(help_cmd
, caller
, C_COMMENT
, horiz_line
);
5974 /**************************************************************************
5975 Send a reply to the caller listing the matched names from an ambiguous
5977 **************************************************************************/
5978 static void cmd_reply_matches(enum command_id cmd
,
5979 struct connection
*caller
,
5980 m_pre_accessor_fn_t accessor_fn
,
5981 int *matches
, int num_matches
)
5983 char buf
[MAX_LEN_MSG
];
5984 const char *src
, *end
;
5988 if (accessor_fn
== NULL
|| matches
== NULL
|| num_matches
< 1) {
5993 end
= buf
+ sizeof(buf
) - 1;
5995 for (i
= 0; i
< num_matches
&& dest
< end
; i
++) {
5996 src
= accessor_fn(matches
[i
]);
6003 while (*src
!= '\0' && dest
< end
) {
6009 cmd_reply(cmd
, caller
, C_COMMENT
, _("Possible matches: %s"), buf
);
6012 /**************************************************************************
6013 Additional 'help' arguments
6014 **************************************************************************/
6015 #define SPECENUM_NAME help_general_args
6016 #define SPECENUM_VALUE0 HELP_GENERAL_COMMANDS
6017 #define SPECENUM_VALUE0NAME "commands"
6018 #define SPECENUM_VALUE1 HELP_GENERAL_OPTIONS
6019 #define SPECENUM_VALUE1NAME "options"
6020 #define SPECENUM_COUNT HELP_GENERAL_COUNT
6021 #include "specenum_gen.h"
6023 /**************************************************************************
6024 Unified indices for help arguments:
6025 CMD_NUM - Server commands
6026 HELP_GENERAL_NUM - General help arguments, above
6027 settings_number() - Server options
6028 **************************************************************************/
6029 #define HELP_ARG_NUM (CMD_NUM + HELP_GENERAL_COUNT + settings_number())
6031 /**************************************************************************
6032 Convert unified helparg index to string; see above.
6033 **************************************************************************/
6034 static const char *helparg_accessor(int i
)
6037 return command_name_by_number(i
);
6041 if (i
< HELP_GENERAL_COUNT
) {
6042 return help_general_args_name((enum help_general_args
) i
);
6045 i
-= HELP_GENERAL_COUNT
;
6046 return optname_accessor(i
);
6049 /**************************************************************************
6051 **************************************************************************/
6052 static bool show_help(struct connection
*caller
, char *arg
)
6054 int matches
[64], num_matches
= 0;
6055 enum m_pre_result match_result
;
6058 fc_assert_ret_val(!may_use_nothing(caller
), FALSE
);
6059 /* no commands means no help, either */
6061 match_result
= match_prefix_full(helparg_accessor
, HELP_ARG_NUM
, 0,
6062 fc_strncasecmp
, NULL
, arg
, &ind
, matches
,
6063 ARRAY_SIZE(matches
), &num_matches
);
6065 if (match_result
==M_PRE_EMPTY
) {
6066 show_help_intro(caller
, CMD_HELP
);
6069 if (match_result
==M_PRE_AMBIGUOUS
) {
6070 cmd_reply(CMD_HELP
, caller
, C_FAIL
,
6071 _("Help argument '%s' is ambiguous."), arg
);
6072 cmd_reply_matches(CMD_HELP
, caller
, helparg_accessor
,
6073 matches
, num_matches
);
6076 if (match_result
==M_PRE_FAIL
) {
6077 cmd_reply(CMD_HELP
, caller
, C_FAIL
,
6078 _("No match for help argument '%s'."), arg
);
6082 /* other cases should be above */
6083 fc_assert_ret_val(match_result
< M_PRE_AMBIGUOUS
, FALSE
);
6085 if (ind
< CMD_NUM
) {
6086 show_help_command(caller
, CMD_HELP
, ind
);
6091 if (ind
== HELP_GENERAL_OPTIONS
) {
6092 show_help_option_list(caller
, CMD_HELP
);
6095 if (ind
== HELP_GENERAL_COMMANDS
) {
6096 show_help_command_list(caller
, CMD_HELP
);
6099 ind
-= HELP_GENERAL_COUNT
;
6101 if (ind
< settings_number()) {
6102 show_help_option(caller
, CMD_HELP
, ind
);
6106 /* should have finished by now */
6107 log_error("Bug in show_help!");
6111 /****************************************************************************
6112 List connections; initially mainly for debugging
6113 ****************************************************************************/
6114 static void show_connections(struct connection
*caller
)
6116 char buf
[MAX_LEN_CONSOLE_LINE
];
6118 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6119 _("List of connections to server:"));
6120 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6122 if (conn_list_size(game
.all_connections
) == 0) {
6123 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("<no connections>"));
6125 conn_list_iterate(game
.all_connections
, pconn
) {
6126 sz_strlcpy(buf
, conn_description(pconn
));
6127 if (pconn
->established
) {
6128 cat_snprintf(buf
, sizeof(buf
), " command access level %s",
6129 cmdlevel_name(pconn
->access_level
));
6131 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, "%s", buf
);
6132 } conn_list_iterate_end
;
6134 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6137 /*****************************************************************************
6138 List all delegations of the current game.
6139 *****************************************************************************/
6140 static void show_delegations(struct connection
*caller
)
6144 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of all delegations:"));
6145 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6147 players_iterate(pplayer
) {
6148 const char *delegate_to
= player_delegation_get(pplayer
);
6149 if (delegate_to
!= NULL
) {
6151 player_delegation_active(pplayer
) ? pplayer
->server
.orig_username
6152 : pplayer
->username
;
6154 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6155 /* TRANS: last %s is either " (active)" or empty string */
6156 _("%s delegates control over player '%s' to user %s%s."),
6157 owner
, player_name(pplayer
), delegate_to
,
6158 player_delegation_active(pplayer
) ? _(" (active)") : "");
6161 } players_iterate_end
;
6164 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("No delegations defined."));
6167 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6170 /****************************************************************************
6171 Show the ignore list of the
6172 ****************************************************************************/
6173 static bool show_ignore(struct connection
*caller
)
6178 if (NULL
== caller
) {
6179 cmd_reply(CMD_IGNORE
, caller
, C_FAIL
,
6180 _("That would be rather silly, since you are not a player."));
6184 if (0 == conn_pattern_list_size(caller
->server
.ignore_list
)) {
6185 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("Your ignore list is empty."));
6189 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("Your ignore list:"));
6190 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6191 conn_pattern_list_iterate(caller
->server
.ignore_list
, ppattern
) {
6192 conn_pattern_to_string(ppattern
, buf
, sizeof(buf
));
6193 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, "%d: %s", n
++, buf
);
6194 } conn_pattern_list_iterate_end
;
6195 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6200 /****************************************************************************
6201 Show the list of the players of the game.
6202 ****************************************************************************/
6203 void show_players(struct connection
*caller
)
6205 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of players:"));
6206 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6208 if (player_count() == 0) {
6209 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("<no players>"));
6211 players_iterate(pplayer
) {
6212 char buf
[MAX_LEN_CONSOLE_LINE
];
6215 /* Low access level callers don't get to see barbarians in list: */
6216 if (is_barbarian(pplayer
) && caller
6217 && (caller
->access_level
< ALLOW_CTRL
)) {
6221 /* The output for each player looks like:
6223 * <Player name> [color]: Team[, Nation][, Username][, Status]
6224 * AI/Barbarian/Human[, AI type, skill level][, Connections]
6225 * [Details for each connection]
6228 /* '<Player name> [color]: [Nation][, Username][, Status]' */
6230 cat_snprintf(buf
, sizeof(buf
), "%s [%s]: %s", player_name(pplayer
),
6231 player_color_ftstr(pplayer
),
6232 team_name_translation(pplayer
->team
));
6233 if (!game
.info
.is_new_game
) {
6234 cat_snprintf(buf
, sizeof(buf
), ", %s",
6235 nation_adjective_for_player(pplayer
));
6237 if (strlen(pplayer
->username
) > 0
6238 && strcmp(pplayer
->username
, "nouser") != 0) {
6239 cat_snprintf(buf
, sizeof(buf
), _(", user %s"), pplayer
->username
);
6241 if (S_S_INITIAL
== server_state() && pplayer
->is_connected
) {
6242 if (pplayer
->is_ready
) {
6243 sz_strlcat(buf
, _(", ready"));
6245 /* Emphasizes this */
6247 featured_text_apply_tag(_(", not ready"),
6248 buf
+ n
, sizeof(buf
) - n
,
6249 TTT_COLOR
, 1, FT_OFFSET_UNSET
,
6252 } else if (!pplayer
->is_alive
) {
6253 sz_strlcat(buf
, _(", Dead"));
6255 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, "%s", buf
);
6257 /* ' AI/Barbarian/Human[, skill level][, Connections]' */
6259 if (is_barbarian(pplayer
)) {
6260 sz_strlcat(buf
, _("Barbarian"));
6261 } else if (pplayer
->ai_controlled
) {
6262 sz_strlcat(buf
, _("AI"));
6264 sz_strlcat(buf
, _("Human"));
6266 if(pplayer
->ai_controlled
) {
6267 cat_snprintf(buf
, sizeof(buf
), _(", %s"), ai_name(pplayer
->ai
));
6268 cat_snprintf(buf
, sizeof(buf
), _(", difficulty level %s"),
6269 ai_level_name(pplayer
->ai_common
.skill_level
));
6271 n
= conn_list_size(pplayer
->connections
);
6273 cat_snprintf(buf
, sizeof(buf
),
6274 PL_(", %d connection:", ", %d connections:", n
), n
);
6276 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, " %s", buf
);
6278 /* ' [Details for each connection]' */
6279 conn_list_iterate(pplayer
->connections
, pconn
) {
6280 fc_snprintf(buf
, sizeof(buf
),
6281 _("%s from %s (command access level %s), "
6282 "bufsize=%dkb"), pconn
->username
, pconn
->addr
,
6283 cmdlevel_name(pconn
->access_level
),
6284 (pconn
->send_buffer
->nsize
>> 10));
6285 if (pconn
->observer
) {
6286 sz_strlcat(buf
, _(" (observer mode)"));
6288 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, " %s", buf
);
6289 } conn_list_iterate_end
;
6290 } players_iterate_end
;
6292 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6295 /****************************************************************************
6296 List scenarios. We look both in the DATA_PATH and DATA_PATH/scenario
6297 ****************************************************************************/
6298 static void show_scenarios(struct connection
*caller
)
6300 char buf
[MAX_LEN_CONSOLE_LINE
];
6301 struct fileinfo_list
*files
;
6303 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of scenarios available:"));
6304 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6306 files
= fileinfolist_infix(get_scenario_dirs(), ".sav", TRUE
);
6308 fileinfo_list_iterate(files
, pfile
) {
6309 fc_snprintf(buf
, sizeof(buf
), "%s", pfile
->name
);
6310 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, "%s", buf
);
6311 } fileinfo_list_iterate_end
;
6312 fileinfo_list_destroy(files
);
6314 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6317 /****************************************************************************
6318 List nation sets in the current ruleset.
6319 ****************************************************************************/
6320 static void show_nationsets(struct connection
*caller
)
6322 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6323 /* TRANS: don't translate text between '' */
6324 _("List of nation sets available for 'nationset' option:"));
6325 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6327 nation_sets_iterate(pset
) {
6328 const char *description
= nation_set_description(pset
);
6329 int num_nations
= 0;
6330 nations_iterate(pnation
) {
6331 if (is_nation_playable(pnation
) && nation_is_in_set(pnation
, pset
)) {
6334 } nations_iterate_end
;
6335 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6336 /* TRANS: nation set description; %d refers to number of playable
6338 PL_(" %-10s %s (%d playable)",
6339 " %-10s %s (%d playable)", num_nations
),
6340 nation_set_rule_name(pset
), nation_set_name_translation(pset
),
6342 if (strlen(description
) > 0) {
6343 static const char prefix
[] = " ";
6344 char *translated
= fc_strdup(_(description
));
6345 fc_break_lines(translated
, LINE_BREAK
);
6346 cmd_reply_prefix(CMD_LIST
, caller
, C_COMMENT
, prefix
, "%s%s",
6347 prefix
, translated
);
6349 } nation_sets_iterate_end
;
6351 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6354 /****************************************************************************
6355 Show a list of teams on the command line.
6356 ****************************************************************************/
6357 static void show_teams(struct connection
*caller
)
6359 /* Currently this just lists all teams (typically 32 of them) with their
6360 * names and # of players on the team. This could probably be improved. */
6361 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of teams:"));
6362 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6364 teams_iterate(pteam
) {
6365 const struct player_list
*members
= team_members(pteam
);
6367 /* PL_() is needed here because some languages may differentiate
6368 * between 2 and 3 (although English does not). */
6369 cmd_reply(CMD_LIST
, caller
, C_COMMENT
,
6370 /* TRANS: There will always be at least 2 players here. */
6371 PL_("%2d : '%s' : %d player :",
6372 "%2d : '%s' : %d players :",
6373 player_list_size(members
)),
6374 team_index(pteam
), team_name_translation(pteam
),
6375 player_list_size(members
));
6376 player_list_iterate(members
, pplayer
) {
6377 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, " %s", player_name(pplayer
));
6378 } player_list_iterate_end
;
6379 } teams_iterate_end
;
6381 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6384 /****************************************************************************
6385 Show a list of all map image definitions on the command line.
6386 ****************************************************************************/
6387 static void show_mapimg(struct connection
*caller
, enum command_id cmd
)
6391 if (mapimg_count() == 0) {
6392 cmd_reply(cmd
, caller
, C_OK
, _("No map image definitions."));
6394 cmd_reply(cmd
, caller
, C_COMMENT
, _("List of map image definitions:"));
6395 cmd_reply(cmd
, caller
, C_COMMENT
, horiz_line
);
6396 for (id
= 0; id
< mapimg_count(); id
++) {
6397 char str
[MAX_LEN_MAPDEF
] = "";
6398 mapimg_show(id
, str
, sizeof(str
), FALSE
);
6399 cmd_reply(cmd
, caller
, C_COMMENT
, _("[%2d] %s"), id
, str
);
6401 cmd_reply(cmd
, caller
, C_COMMENT
, horiz_line
);
6405 /****************************************************************************
6406 Show a list of all players with the assigned color.
6407 ****************************************************************************/
6408 static void show_colors(struct connection
*caller
)
6410 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("List of player colors:"));
6411 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6412 if (player_count() == 0) {
6413 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("<no players>"));
6415 players_iterate(pplayer
) {
6416 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, _("%s (user %s): [%s]"),
6417 player_name(pplayer
), pplayer
->username
,
6418 player_color_ftstr(pplayer
));
6419 } players_iterate_end
;
6421 cmd_reply(CMD_LIST
, caller
, C_COMMENT
, horiz_line
);
6424 /****************************************************************************
6426 **************************************************************************/
6427 #define SPECENUM_NAME list_args
6428 #define SPECENUM_VALUE0 LIST_COLORS
6429 #define SPECENUM_VALUE0NAME "colors"
6430 #define SPECENUM_VALUE1 LIST_CONNECTIONS
6431 #define SPECENUM_VALUE1NAME "connections"
6432 #define SPECENUM_VALUE2 LIST_DELEGATIONS
6433 #define SPECENUM_VALUE2NAME "delegations"
6434 #define SPECENUM_VALUE3 LIST_IGNORE
6435 #define SPECENUM_VALUE3NAME "ignored users"
6436 #define SPECENUM_VALUE4 LIST_MAPIMG
6437 #define SPECENUM_VALUE4NAME "map image definitions"
6438 #define SPECENUM_VALUE5 LIST_PLAYERS
6439 #define SPECENUM_VALUE5NAME "players"
6440 #define SPECENUM_VALUE6 LIST_SCENARIOS
6441 #define SPECENUM_VALUE6NAME "scenarios"
6442 #define SPECENUM_VALUE7 LIST_NATIONSETS
6443 #define SPECENUM_VALUE7NAME "nationsets"
6444 #define SPECENUM_VALUE8 LIST_TEAMS
6445 #define SPECENUM_VALUE8NAME "teams"
6446 #define SPECENUM_VALUE9 LIST_VOTES
6447 #define SPECENUM_VALUE9NAME "votes"
6448 #include "specenum_gen.h"
6450 /**************************************************************************
6451 Returns possible parameters for the list command.
6452 **************************************************************************/
6453 static const char *list_accessor(int i
)
6455 i
= CLIP(0, i
, list_args_max());
6456 return list_args_name((enum list_args
) i
);
6459 /**************************************************************************
6460 Show list of players or connections, or connection statistics.
6461 **************************************************************************/
6462 static bool show_list(struct connection
*caller
, char *arg
)
6464 enum m_pre_result match_result
;
6468 remove_leading_trailing_spaces(arg
);
6469 match_result
= match_prefix(list_accessor
, list_args_max() + 1, 0,
6470 fc_strncasecmp
, NULL
, arg
, &ind_int
);
6473 if (match_result
> M_PRE_EMPTY
) {
6474 cmd_reply(CMD_LIST
, caller
, C_SYNTAX
,
6475 _("Bad list argument: '%s'. Try '%shelp list'."),
6476 arg
, (caller
?"/":""));
6480 if (match_result
== M_PRE_EMPTY
) {
6486 show_colors(caller
);
6488 case LIST_CONNECTIONS
:
6489 show_connections(caller
);
6491 case LIST_DELEGATIONS
:
6492 show_delegations(caller
);
6495 return show_ignore(caller
);
6497 show_mapimg(caller
, CMD_LIST
);
6500 show_players(caller
);
6502 case LIST_SCENARIOS
:
6503 show_scenarios(caller
);
6505 case LIST_NATIONSETS
:
6506 show_nationsets(caller
);
6516 cmd_reply(CMD_LIST
, caller
, C_FAIL
,
6517 "Internal error: ind %d in show_list", ind
);
6518 log_error("Internal error: ind %d in show_list", ind
);
6522 #ifdef HAVE_LIBREADLINE
6523 /********************* RL completion functions ***************************/
6524 /* To properly complete both commands, player names, options and filenames
6525 there is one array per type of completion with the commands that
6526 the type is relevant for.
6529 /**************************************************************************
6530 A generalised generator function: text and state are "standard"
6531 parameters to a readline generator function;
6532 num is number of possible completions, or -1 if this is not known and
6533 index2str should be iterated until it returns NULL;
6534 index2str is a function which returns each possible completion string
6535 by index (it may return NULL).
6536 **************************************************************************/
6537 static char *generic_generator(const char *text
, int state
, int num
,
6538 const char*(*index2str
)(int))
6540 static int list_index
, len
;
6541 const char *name
= ""; /* dummy non-NULL string */
6542 char *mytext
= local_to_internal_string_malloc(text
);
6544 /* This function takes a string (text) in the local format and must return
6545 * a string in the local format. However comparisons are done against
6546 * names that are in the internal format (UTF-8). Thus we have to convert
6547 * the text function from the local to the internal format before doing
6548 * the comparison, and convert the string we return *back* to the
6549 * local format when returning it. */
6551 /* If this is a new word to complete, initialize now. This includes
6552 saving the length of TEXT for efficiency, and initializing the index
6556 len
= strlen(mytext
);
6559 /* Return the next name which partially matches: */
6560 while ((num
< 0 && name
) || (list_index
< num
)) {
6561 name
= index2str(list_index
);
6564 if (name
!= NULL
&& fc_strncasecmp(name
, mytext
, len
) == 0) {
6566 return internal_to_local_string_malloc(name
);
6571 /* If no names matched, then return NULL. */
6572 return ((char *)NULL
);
6575 /**************************************************************************
6576 The valid commands at the root of the prompt.
6577 **************************************************************************/
6578 static char *command_generator(const char *text
, int state
)
6580 return generic_generator(text
, state
, CMD_NUM
, command_name_by_number
);
6583 /**************************************************************************
6584 The valid arguments to "set" and "explain"
6585 **************************************************************************/
6586 static char *option_generator(const char *text
, int state
)
6588 return generic_generator(text
, state
, settings_number(), optname_accessor
);
6591 /**************************************************************************
6592 The valid arguments to "show"
6593 **************************************************************************/
6594 static char *olevel_generator(const char *text
, int state
)
6596 return generic_generator(text
, state
, settings_number() + OLEVELS_NUM
+ 1,
6600 /**************************************************************************
6601 Accessor for values of the enum/bitwise option defined by
6602 'completion_option'.
6603 **************************************************************************/
6604 static int completion_option
;
6605 static const char *option_value_accessor(int idx
) {
6606 const struct setting
*pset
= setting_by_number(completion_option
);
6607 switch (setting_type(pset
)) {
6609 return setting_enum_val(pset
, idx
, FALSE
);
6612 return setting_bitwise_bit(pset
, idx
, FALSE
);
6615 fc_assert_ret_val(0, NULL
);
6619 /**************************************************************************
6620 The valid arguments to "set OPT", where OPT is the enumerated or
6621 bitwise option previously defined by completion_option
6622 **************************************************************************/
6623 static char *option_value_generator(const char *text
, int state
)
6625 return generic_generator(text
, state
, -1, option_value_accessor
);
6628 /**************************************************************************
6630 **************************************************************************/
6631 static const char *playername_accessor(int idx
)
6633 const struct player_slot
*pslot
= player_slot_by_number(idx
);
6635 if (!player_slot_is_used(pslot
)) {
6639 return player_name(player_slot_get_player(pslot
));
6642 /**************************************************************************
6643 The valid playername arguments.
6644 **************************************************************************/
6645 static char *player_generator(const char *text
, int state
)
6647 return generic_generator(text
, state
, player_slot_count(),
6648 playername_accessor
);
6651 /**************************************************************************
6652 Access connection user name, from game.all_connections.
6653 **************************************************************************/
6654 static const char *connection_name_accessor(int idx
)
6656 return conn_list_get(game
.all_connections
, idx
)->username
;
6659 /**************************************************************************
6660 The valid connection user name arguments.
6661 **************************************************************************/
6662 static char *connection_generator(const char *text
, int state
)
6664 return generic_generator(text
, state
, conn_list_size(game
.all_connections
),
6665 connection_name_accessor
);
6668 /**************************************************************************
6669 Extra accessor function since cmdlevel_name() takes enum argument, not int.
6670 **************************************************************************/
6671 static const char *cmdlevel_arg1_accessor(int idx
)
6673 return cmdlevel_name(idx
);
6676 /**************************************************************************
6677 The valid first argument to "cmdlevel"
6678 **************************************************************************/
6679 static char *cmdlevel_arg1_generator(const char *text
, int state
)
6681 return generic_generator(text
, state
, cmdlevel_max()+1,
6682 cmdlevel_arg1_accessor
);
6685 /**************************************************************************
6686 Accessor for the second argument to "cmdlevel": "first" or "new" or
6688 **************************************************************************/
6689 static const char *cmdlevel_arg2_accessor(int idx
)
6691 return ((idx
==0) ? "first" :
6693 connection_name_accessor(idx
-2));
6696 /**************************************************************************
6697 The valid arguments for the second argument to "cmdlevel".
6698 **************************************************************************/
6699 static char *cmdlevel_arg2_generator(const char *text
, int state
)
6701 return generic_generator(text
, state
,
6702 /* "first", "new", connection names */
6703 2 + conn_list_size(game
.all_connections
),
6704 cmdlevel_arg2_accessor
);
6707 /**************************************************************************
6708 Accessor for the second argument to "create": ai type name
6709 **************************************************************************/
6710 static const char *aitype_accessor(int idx
)
6712 return get_ai_type(idx
)->name
;
6715 /**************************************************************************
6716 The valid arguments for the second argument to "create".
6717 **************************************************************************/
6718 static char *aitype_generator(const char *text
, int state
)
6720 return generic_generator(text
, state
, ai_type_get_count(),
6724 /**************************************************************************
6725 The valid arguments for the argument to "reset".
6726 **************************************************************************/
6727 static char *reset_generator(const char *text
, int state
)
6729 return generic_generator(text
, state
, reset_args_max() + 1, reset_accessor
);
6732 /**************************************************************************
6733 The valid arguments for the argument to "vote".
6734 **************************************************************************/
6735 static char *vote_generator(const char *text
, int state
)
6737 return generic_generator(text
, state
, -1, vote_arg_accessor
);
6740 /**************************************************************************
6741 The valid arguments for the first argument to "delegate".
6742 **************************************************************************/
6743 static char *delegate_generator(const char *text
, int state
)
6745 return generic_generator(text
, state
, delegate_args_max() + 1,
6749 /**************************************************************************
6750 The valid arguments for the first argument to "mapimg".
6751 **************************************************************************/
6752 static char *mapimg_generator(const char *text
, int state
)
6754 return generic_generator(text
, state
, mapimg_args_max() + 1,
6758 /**************************************************************************
6759 The valid arguments for the argument to "fcdb".
6760 **************************************************************************/
6761 static char *fcdb_generator(const char *text
, int state
)
6763 return generic_generator(text
, state
, FCDB_COUNT
, fcdb_accessor
);
6766 /**************************************************************************
6767 The valid arguments for the argument to "lua".
6768 **************************************************************************/
6769 static char *lua_generator(const char *text
, int state
)
6771 return generic_generator(text
, state
, lua_args_max() + 1, lua_accessor
);
6774 /**************************************************************************
6775 The valid first arguments to "help".
6776 **************************************************************************/
6777 static char *help_generator(const char *text
, int state
)
6779 return generic_generator(text
, state
, HELP_ARG_NUM
, helparg_accessor
);
6782 /**************************************************************************
6783 The valid first arguments to "list".
6784 **************************************************************************/
6785 static char *list_generator(const char *text
, int state
)
6787 return generic_generator(text
, state
, list_args_max() + 1, list_accessor
);
6790 /**************************************************************************
6791 Generalised version of contains_str_before_start, which searches the
6792 N'th token in rl_line_buffer (0=first).
6793 **************************************************************************/
6794 static bool contains_token_before_start(int start
, int token
, const char *arg
,
6797 char *str_itr
= rl_line_buffer
;
6798 int arg_len
= strlen(arg
);
6800 /* Swallow unwanted tokens and their preceding delimiters */
6802 while (str_itr
< rl_line_buffer
+ start
&& !fc_isalnum(*str_itr
)) {
6805 while (str_itr
< rl_line_buffer
+ start
&& fc_isalnum(*str_itr
)) {
6810 /* Swallow any delimiters before the token we're interested in */
6811 while (str_itr
< rl_line_buffer
+ start
&& !fc_isalnum(*str_itr
)) {
6815 if (fc_strncasecmp(str_itr
, arg
, arg_len
) != 0) {
6820 if (fc_isalnum(*str_itr
)) {
6821 /* Not a distinct word. */
6826 for (; str_itr
< rl_line_buffer
+ start
; str_itr
++) {
6827 if (fc_isalnum(*str_itr
)) {
6836 /**************************************************************************
6837 Returns whether the text between the start of rl_line_buffer and the
6838 start position is of the form [non-alpha]*cmd[non-alpha]*
6839 allow_fluff changes the regexp to [non-alpha]*cmd[non-alpha].*
6840 **************************************************************************/
6841 static bool contains_str_before_start(int start
, const char *cmd
,
6844 return contains_token_before_start(start
, 0, cmd
, allow_fluff
);
6847 /**************************************************************************
6848 Return whether we are completing command name. This can be either
6849 command itself, or argument to 'help'.
6850 **************************************************************************/
6851 static bool is_command(int start
)
6855 if (contains_str_before_start(start
, command_name_by_number(CMD_HELP
), FALSE
))
6858 /* if there is only it is also OK */
6859 str_itr
= rl_line_buffer
;
6860 while (str_itr
- rl_line_buffer
< start
) {
6861 if (fc_isalnum(*str_itr
)) {
6869 /**************************************************************************
6870 number of tokens in rl_line_buffer before start
6871 **************************************************************************/
6872 static int num_tokens(int start
)
6876 char *chptr
= rl_line_buffer
;
6878 while (chptr
- rl_line_buffer
< start
) {
6879 if (fc_isalnum(*chptr
)) {
6893 /**************************************************************************
6894 Commands that may be followed by a player name
6895 **************************************************************************/
6896 static const int player_cmd
[] = {
6910 /**************************************************************************
6911 Return whether we are completing player name argument.
6912 **************************************************************************/
6913 static bool is_player(int start
)
6917 while (player_cmd
[i
] != -1) {
6918 if (contains_str_before_start(start
, command_name_by_number(player_cmd
[i
]), FALSE
)) {
6927 /**************************************************************************
6928 Commands that may be followed by a connection name
6929 **************************************************************************/
6930 static const int connection_cmd
[] = {
6936 /**************************************************************************
6937 Return whether we are completing connection name argument.
6938 **************************************************************************/
6939 static bool is_connection(int start
)
6943 while (connection_cmd
[i
] != -1) {
6944 if (contains_str_before_start(start
,
6945 command_name_by_number(connection_cmd
[i
]),
6955 /**************************************************************************
6956 Return whether we are completing cmdlevel command argument 2.
6957 **************************************************************************/
6958 static bool is_cmdlevel_arg2(int start
)
6960 return (contains_str_before_start(start
, command_name_by_number(CMD_CMDLEVEL
), TRUE
)
6961 && num_tokens(start
) == 2);
6964 /**************************************************************************
6965 Return whether we are completing cmdlevel command argument.
6966 **************************************************************************/
6967 static bool is_cmdlevel_arg1(int start
)
6969 return contains_str_before_start(start
, command_name_by_number(CMD_CMDLEVEL
), FALSE
);
6972 /**************************************************************************
6973 Commands that may be followed by a server option name
6975 CMD_SHOW is handled by option_level_cmd, which is for both option levels
6977 **************************************************************************/
6978 static const int server_option_cmd
[] = {
6984 /**************************************************************************
6985 Returns TRUE if the readline buffer string matches a server option at
6987 **************************************************************************/
6988 static bool is_server_option(int start
)
6992 while (server_option_cmd
[i
] != -1) {
6993 if (contains_str_before_start(start
, command_name_by_number(server_option_cmd
[i
]),
7003 /**************************************************************************
7004 Commands that may be followed by an option level or server option
7005 **************************************************************************/
7006 static const int option_level_cmd
[] = {
7011 /**************************************************************************
7012 Returns true if the readline buffer string matches an option level or an
7013 option at the given position.
7014 **************************************************************************/
7015 static bool is_option_level(int start
)
7019 while (option_level_cmd
[i
] != -1) {
7020 if (contains_str_before_start(start
, command_name_by_number(option_level_cmd
[i
]),
7030 /**************************************************************************
7031 Returns TRUE if the readline buffer string is such that we expect an
7032 enumerated value at the given position. The option for which values
7033 should be completed is written to opt_p.
7034 **************************************************************************/
7035 static bool is_enum_option_value(int start
, int *opt_p
)
7037 if (contains_str_before_start(start
, command_name_by_number(CMD_SET
),
7039 settings_iterate(SSET_ALL
, pset
) {
7040 if (setting_type(pset
) != SSET_ENUM
7041 && setting_type(pset
) != SSET_BITWISE
) {
7044 /* Allow a single token for enum options, multiple for bitwise
7045 * (the separator | will separate tokens for these purposes) */
7046 if (contains_token_before_start(start
, 1, setting_name(pset
),
7047 setting_type(pset
) == SSET_BITWISE
)) {
7048 *opt_p
= setting_number(pset
);
7049 /* Suppress appended space for bitwise options (user may want |) */
7050 rl_completion_suppress_append
= (setting_type(pset
) == SSET_BITWISE
);
7053 } settings_iterate_end
;
7058 /**************************************************************************
7059 Commands that may be followed by a filename
7060 **************************************************************************/
7061 static const int filename_cmd
[] = {
7069 /**************************************************************************
7070 Return whether we are completing filename.
7071 **************************************************************************/
7072 static bool is_filename(int start
)
7076 while (filename_cmd
[i
] != -1) {
7077 if (contains_str_before_start(start
, command_name_by_number(filename_cmd
[i
]), FALSE
)) {
7086 /**************************************************************************
7087 Return whether we are completing second argument for create command
7088 **************************************************************************/
7089 static bool is_create_arg2(int start
)
7091 return (contains_str_before_start(start
, command_name_by_number(CMD_CREATE
), TRUE
)
7092 && num_tokens(start
) == 2);
7095 /**************************************************************************
7096 Return whether we are completing argument for reset command
7097 **************************************************************************/
7098 static bool is_reset(int start
)
7100 return contains_str_before_start(start
,
7101 command_name_by_number(CMD_RESET
),
7105 /**************************************************************************
7106 Return whether we are completing argument for vote command
7107 **************************************************************************/
7108 static bool is_vote(int start
)
7110 return contains_str_before_start(start
,
7111 command_name_by_number(CMD_VOTE
),
7115 /**************************************************************************
7116 Return whether we are completing first argument for delegate command
7117 **************************************************************************/
7118 static bool is_delegate_arg1(int start
)
7120 return contains_str_before_start(start
,
7121 command_name_by_number(CMD_DELEGATE
),
7125 /**************************************************************************
7126 Return whether we are completing first argument for mapimg command
7127 **************************************************************************/
7128 static bool is_mapimg(int start
)
7130 return contains_str_before_start(start
,
7131 command_name_by_number(CMD_MAPIMG
),
7135 /**************************************************************************
7136 Return whether we are completing argument for fcdb command
7137 **************************************************************************/
7138 static bool is_fcdb(int start
)
7140 return contains_str_before_start(start
,
7141 command_name_by_number(CMD_FCDB
),
7145 /**************************************************************************
7146 Return whether we are completing argument for lua command
7147 **************************************************************************/
7148 static bool is_lua(int start
)
7150 return contains_str_before_start(start
,
7151 command_name_by_number(CMD_LUA
),
7155 /**************************************************************************
7156 Return whether we are completing help command argument.
7157 **************************************************************************/
7158 static bool is_help(int start
)
7160 return contains_str_before_start(start
, command_name_by_number(CMD_HELP
), FALSE
);
7163 /**************************************************************************
7164 Return whether we are completing list command argument.
7165 **************************************************************************/
7166 static bool is_list(int start
)
7168 return contains_str_before_start(start
, command_name_by_number(CMD_LIST
), FALSE
);
7171 /**************************************************************************
7172 Attempt to complete on the contents of TEXT. START and END bound the
7173 region of rl_line_buffer that contains the word to complete. TEXT is
7174 the word to complete. We can use the entire contents of rl_line_buffer
7175 in case we want to do some simple parsing. Return the array of matches,
7176 or NULL if there aren't any.
7177 **************************************************************************/
7178 char **freeciv_completion(const char *text
, int start
, int end
)
7180 char **matches
= (char **)NULL
;
7182 if (is_help(start
)) {
7183 matches
= rl_completion_matches(text
, help_generator
);
7184 } else if (is_command(start
)) {
7185 matches
= rl_completion_matches(text
, command_generator
);
7186 } else if (is_list(start
)) {
7187 matches
= rl_completion_matches(text
, list_generator
);
7188 } else if (is_cmdlevel_arg2(start
)) {
7189 matches
= rl_completion_matches(text
, cmdlevel_arg2_generator
);
7190 } else if (is_cmdlevel_arg1(start
)) {
7191 matches
= rl_completion_matches(text
, cmdlevel_arg1_generator
);
7192 } else if (is_connection(start
)) {
7193 matches
= rl_completion_matches(text
, connection_generator
);
7194 } else if (is_player(start
)) {
7195 matches
= rl_completion_matches(text
, player_generator
);
7196 } else if (is_server_option(start
)) {
7197 matches
= rl_completion_matches(text
, option_generator
);
7198 } else if (is_option_level(start
)) {
7199 matches
= rl_completion_matches(text
, olevel_generator
);
7200 } else if (is_enum_option_value(start
, &completion_option
)) {
7201 matches
= rl_completion_matches(text
, option_value_generator
);
7202 } else if (is_filename(start
)) {
7203 /* This function we get from readline */
7204 matches
= rl_completion_matches(text
, rl_filename_completion_function
);
7205 } else if (is_create_arg2(start
)) {
7206 matches
= rl_completion_matches(text
, aitype_generator
);
7207 } else if (is_reset(start
)) {
7208 matches
= rl_completion_matches(text
, reset_generator
);
7209 } else if (is_vote(start
)) {
7210 matches
= rl_completion_matches(text
, vote_generator
);
7211 } else if (is_delegate_arg1(start
)) {
7212 matches
= rl_completion_matches(text
, delegate_generator
);
7213 } else if (is_mapimg(start
)) {
7214 matches
= rl_completion_matches(text
, mapimg_generator
);
7215 } else if (is_fcdb(start
)) {
7216 matches
= rl_completion_matches(text
, fcdb_generator
);
7217 } else if (is_lua(start
)) {
7218 matches
= rl_completion_matches(text
, lua_generator
);
7220 /* We have no idea what to do */
7224 /* Don't automatically try to complete with filenames */
7225 rl_attempted_completion_over
= 1;
7230 #endif /* HAVE_LIBREADLINE */