Freeciv-3.1: /fast/freeciv/nightly/S3_1/server/stdinhand.c Source File

Freeciv-3.1

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