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