~ubuntu-branches/debian/sid/freeciv/sid

« back to all changes in this revision

Viewing changes to server/stdinhand.c

  • Committer: Bazaar Package Importer
  • Author(s): Clint Adams, Karl Goetz, Clint Adams
  • Date: 2009-11-27 23:24:00 UTC
  • mfrom: (7.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091127232400-nmoil1yvvskugn1h
[ Karl Goetz ]
* New upstream release
* Bump standards-version to 3.8.3
* Update watch file
  - Now version 3
  - Switched to gna.org instead of sf.net
* Switch readline dev dependency to libreadline-dev instead of
libreadline5-dev. Closes: #553758
* Changed compat to 5
* Relaxed dependencies on freeciv-server for sdl and gtk clients,
freeciv-server is now a recommends
* Stop d/rules trying to gzip scenarios - upstream does this.
* Remove export of datarootdir in d/rules, upstream seems to handle
this correctly now.
* Deleted 01_configure_ac_localedir.diff from d/patches/ and from series.
* Create per-client .desktop files. Closes: #470978, LP: #190555
* Desktop files mention which client they are (sdl/gtk/xaw3d).
* Add myself to uploaders on Clint's suggestion.

[ Clint Adams ]
* Change watch file to grab bz2 tarballs.
* Switch to 3.0 (quilt) source format.
* Remove quilt code from debian/rules.

Show diffs side-by-side

added added

removed removed

Lines of Context:
68
68
#include "settings.h"
69
69
#include "srv_main.h"
70
70
#include "stdinhand.h"
 
71
#include "voting.h"
71
72
 
72
73
#include "advmilitary.h"        /* assess_danger_player() */
73
74
#include "ailog.h"
75
76
 
76
77
#define TOKEN_DELIMITERS " \t\n,"
77
78
 
78
 
static enum cmdlevel_id default_access_level = ALLOW_INFO;
 
79
static enum cmdlevel_id default_access_level = ALLOW_BASIC;
79
80
static enum cmdlevel_id   first_access_level = ALLOW_CTRL;
80
81
 
81
82
static bool cut_client_connection(struct connection *caller, char *name,
95
96
static bool end_command(struct connection *caller, char *str, bool check);
96
97
static bool surrender_command(struct connection *caller, char *str, bool check);
97
98
 
98
 
enum vote_type {
99
 
  VOTE_NONE, VOTE_YES, VOTE_NO
100
 
};
101
 
struct voting {
102
 
  char command[MAX_LEN_CONSOLE_LINE]; /* [0] == \0 if none in action */
103
 
  enum vote_type votes_cast[MAX_NUM_PLAYERS]; /* see enum above */
104
 
  int vote_no; /* place in the queue */
105
 
  int yes, no;
106
 
};
107
 
static struct voting votes[MAX_NUM_PLAYERS];
108
 
static int last_vote;
109
99
 
110
100
static const char horiz_line[] =
111
101
"------------------------------------------------------------------------------";
190
180
**************************************************************************/
191
181
void stdinhand_init(void)
192
182
{
193
 
  int i;
194
 
 
195
 
  for (i = 0; i < MAX_NUM_PLAYERS; i++) {
196
 
    votes[i].command[0] = '\0';
197
 
    memset(votes[i].votes_cast, 0, sizeof(votes[i].votes_cast));
198
 
    votes[i].vote_no = -1;
199
 
  }
200
 
  last_vote = -1;
201
 
}
202
 
 
203
 
/**************************************************************************
204
 
  Check if we satisfy the criteria for resolving a vote, and resolve it
205
 
  if these critera are indeed met. Updates yes and no variables in voting 
206
 
  struct as well.
207
 
 
208
 
  Criteria:
209
 
    Accepted immediately if: > 50% of votes for
210
 
    Rejected immediately if: >= 50% of votes against
211
 
**************************************************************************/
212
 
static void check_vote(struct voting *vote)
213
 
{
214
 
  int i, num_cast = 0, num_voters = 0;
215
 
 
216
 
  vote->yes = 0;
217
 
  vote->no = 0;
218
 
 
219
 
  for (i = 0; i < MAX_NUM_PLAYERS; i++) {
220
 
    if (game.players[i].is_alive && game.players[i].is_connected) {
221
 
      num_voters++;
222
 
    } else {
223
 
      /* Disqualify already given vote (eg if disconnected after voting) */
224
 
      vote->votes_cast[i] = VOTE_NONE;
225
 
    }
226
 
  }
227
 
  for (i = 0; i < MAX_NUM_PLAYERS; i++) {
228
 
    num_cast = (vote->votes_cast[i] > VOTE_NONE) ? num_cast + 1 : num_cast;
229
 
    vote->yes = (vote->votes_cast[i] == VOTE_YES) ? vote->yes + 1 : vote->yes;
230
 
    vote->no = (vote->votes_cast[i] == VOTE_NO) ? vote->no + 1 : vote->no;
231
 
  }
232
 
 
233
 
  /* Check if we should resolve the vote */
234
 
  if (vote->command[0] != '\0'
235
 
      && num_voters > 0
236
 
      && (vote->yes > num_voters / 2
237
 
          || vote->no >= (num_voters + 1) / 2)) {
238
 
    /* Yep, resolve this one */
239
 
    vote->vote_no = -1;
240
 
    if (last_vote == vote->vote_no) {
241
 
      last_vote = -1;
242
 
    }
243
 
    if (vote->yes > num_voters / 2) {
244
 
      /* Do it! */
245
 
      notify_conn(NULL, NULL, E_SETTING,
246
 
                  _("Vote \"%s\" is passed %d to %d with %d "
247
 
                    "abstentions."),
248
 
                  vote->command, vote->yes, vote->no,
249
 
                  num_voters - vote->yes - vote->no);
250
 
      handle_stdin_input((struct connection *)NULL, vote->command, FALSE);
251
 
    } else {
252
 
      notify_conn(NULL, NULL, E_SETTING,
253
 
                  _("Vote \"%s\" failed with %d against, %d for "
254
 
                    "and %d abstentions."),
255
 
                  vote->command, vote->no, vote->yes, 
256
 
                  num_voters - vote->yes - vote->no);
257
 
    }
258
 
    vote->command[0] = '\0';
259
 
  }
 
183
  /* Nothing. */
260
184
}
261
185
 
262
186
/**************************************************************************
265
189
**************************************************************************/
266
190
void stdinhand_turn(void)
267
191
{
268
 
  int i;
269
 
 
270
 
  /* Check if any votes have passed */
271
 
  for (i = 0; i < MAX_NUM_PLAYERS; i++) {
272
 
    check_vote(&votes[i]);
273
 
  }
 
192
  /* Nothing. */
274
193
}
275
194
 
276
195
/**************************************************************************
1183
1102
     * and thus this clause is never used.
1184
1103
     */
1185
1104
    cmd_reply(CMD_CMDLEVEL, caller, C_FAIL,
1186
 
              _("Cannot decrease command access level '%s' for connection '%s';"
1187
 
                " you only have '%s'."),
1188
 
              cmdlevel_name(ptarget->access_level),
1189
 
              ptarget->username,
1190
 
              cmdlevel_name(caller->access_level));
 
1105
              _("Cannot decrease command access level '%s' "
 
1106
                "for connection '%s'; you only have '%s'."),
 
1107
              cmdlevel_name(ptarget->access_level),
 
1108
              ptarget->username,
 
1109
              cmdlevel_name(caller->access_level));
1191
1110
    return FALSE;
1192
1111
  } else {
1193
1112
    ptarget->access_level = level;
 
1113
    cmd_reply(CMD_CMDLEVEL, caller, C_OK,
 
1114
              _("Command access level set to '%s' for connection %s."),
 
1115
              cmdlevel_name(level), ptarget->username);
1194
1116
    return TRUE;
1195
1117
  }
1196
1118
}
1249
1171
**************************************************************************/
1250
1172
static bool cmdlevel_command(struct connection *caller, char *str, bool check)
1251
1173
{
1252
 
  char arg_level[MAX_LEN_CONSOLE_LINE]; /* info, ctrl etc */
1253
 
  char arg_name[MAX_LEN_CONSOLE_LINE];   /* a player name, or "new" */
1254
 
  char *cptr_s, *cptr_d;         /* used for string ops */
1255
 
 
 
1174
  char *arg[2];
 
1175
  int ntokens;
 
1176
  bool ret = FALSE;
1256
1177
  enum m_pre_result match_result;
1257
1178
  enum cmdlevel_id level;
1258
1179
  struct connection *ptarget;
1259
1180
 
1260
 
  /* find the start of the level: */
1261
 
  for (cptr_s = str; *cptr_s != '\0' && !my_isalnum(*cptr_s); cptr_s++) {
1262
 
    /* nothing */
1263
 
  }
1264
 
 
1265
 
  /* copy the level into arg_level[] */
1266
 
  for(cptr_d=arg_level; *cptr_s != '\0' && my_isalnum(*cptr_s); cptr_s++, cptr_d++) {
1267
 
    *cptr_d=*cptr_s;
1268
 
  }
1269
 
  *cptr_d='\0';
1270
 
  
1271
 
  if (arg_level[0] == '\0') {
1272
 
    /* no level name supplied; list the levels */
1273
 
 
1274
 
    cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, _("Command access levels in effect:"));
1275
 
 
 
1181
  ntokens = get_tokens(str, arg, 2, TOKEN_DELIMITERS);
 
1182
 
 
1183
  if (ntokens == 0) {
 
1184
    /* No argument supplied; list the levels */
 
1185
    cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, horiz_line);
 
1186
    cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT,
 
1187
              _("Command access levels in effect:"));
 
1188
    cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, horiz_line);
1276
1189
    conn_list_iterate(game.est_connections, pconn) {
1277
1190
      cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, "cmdlevel %s %s",
1278
 
                cmdlevel_name(pconn->access_level), pconn->username);
1279
 
    }
1280
 
    conn_list_iterate_end;
1281
 
    cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT,
1282
 
              _("Command access level for new connections: %s"),
1283
 
              cmdlevel_name(default_access_level));
1284
 
    cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT,
1285
 
              _("Command access level for first player to take it: %s"),
1286
 
              cmdlevel_name(first_access_level));
 
1191
                cmdlevel_name(conn_get_access(pconn)), pconn->username);
 
1192
    } conn_list_iterate_end;
 
1193
    cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT,
 
1194
              _("Command access level for new connections: %s"),
 
1195
              cmdlevel_name(default_access_level));
 
1196
    cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT,
 
1197
              _("Command access level for first player to take it: %s"),
 
1198
              cmdlevel_name(first_access_level));
 
1199
    cmd_reply(CMD_CMDLEVEL, caller, C_COMMENT, horiz_line);
1287
1200
    return TRUE;
1288
1201
  }
1289
1202
 
1290
 
  /* a level name was supplied; set the level */
1291
 
 
1292
 
  if ((level = cmdlevel_named(arg_level)) == ALLOW_UNRECOGNIZED) {
 
1203
  /* A level name was supplied; set the level */
 
1204
  if ((level = cmdlevel_named(arg[0])) == ALLOW_UNRECOGNIZED) {
1293
1205
    cmd_reply(CMD_CMDLEVEL, caller, C_SYNTAX,
1294
 
              _("Error: command access level must be one of"
1295
 
                " 'none', 'info', 'ctrl', or 'hack'."));
1296
 
    return FALSE;
1297
 
  } else if (caller && level > caller->access_level) {
 
1206
              _("Error: command access level must be one of"
 
1207
                " 'none', 'info', 'ctrl', or 'hack'."));
 
1208
    goto CLEAN_UP;
 
1209
  } else if (caller && level > conn_get_access(caller)) {
1298
1210
    cmd_reply(CMD_CMDLEVEL, caller, C_FAIL,
1299
 
              _("Cannot increase command access level to '%s';"
1300
 
                " you only have '%s' yourself."),
1301
 
              arg_level, cmdlevel_name(caller->access_level));
1302
 
    return FALSE;
 
1211
              _("Cannot increase command access level to '%s';"
 
1212
                " you only have '%s' yourself."),
 
1213
              arg[0], cmdlevel_name(conn_get_access(caller)));
 
1214
    goto CLEAN_UP;
1303
1215
  }
 
1216
 
1304
1217
  if (check) {
1305
 
    return TRUE; /* looks good */
1306
 
  }
1307
 
 
1308
 
  /* find the start of the name: */
1309
 
  for (; *cptr_s != '\0' && !my_isalnum(*cptr_s); cptr_s++) {
1310
 
    /* nothing */
1311
 
  }
1312
 
 
1313
 
  /* copy the name into arg_name[] */
1314
 
  for(cptr_d=arg_name;
1315
 
      *cptr_s != '\0' && (*cptr_s == '-' || *cptr_s == ' ' || my_isalnum(*cptr_s));
1316
 
      cptr_s++ , cptr_d++) {
1317
 
    *cptr_d=*cptr_s;
1318
 
  }
1319
 
  *cptr_d='\0';
1320
 
 
1321
 
  if (arg_name[0] == '\0') {
1322
 
    /* no playername supplied: set for all connections, and set the default */
 
1218
    return TRUE;                /* looks good */
 
1219
  }
 
1220
 
 
1221
  if (ntokens == 1) {
 
1222
    /* No playername supplied: set for all connections */
1323
1223
    conn_list_iterate(game.est_connections, pconn) {
1324
 
      if (set_cmdlevel(caller, pconn, level)) {
1325
 
        cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1326
 
                  _("Command access level set to '%s' for connection %s."),
1327
 
                  cmdlevel_name(level), pconn->username);
1328
 
        send_conn_info(pconn->self, NULL);
1329
 
      } else {
1330
 
        cmd_reply(CMD_CMDLEVEL, caller, C_FAIL,
1331
 
                  _("Command access level could not be set to '%s' for "
1332
 
                    "connection %s."),
1333
 
                  cmdlevel_name(level), pconn->username);
1334
 
        return FALSE;
 
1224
      if (pconn != caller) {
 
1225
        (void) set_cmdlevel(caller, pconn, level);
1335
1226
      }
 
1227
    } conn_list_iterate_end;
 
1228
 
 
1229
    /* Set the caller access level at last, because it could make the
 
1230
     * previous operations impossible if set before. */
 
1231
    if (caller) {
 
1232
      (void) set_cmdlevel(caller, caller, level);
1336
1233
    }
1337
 
    conn_list_iterate_end;
1338
 
    
 
1234
 
 
1235
    /* Set default access for new connections. */
1339
1236
    default_access_level = level;
1340
1237
    cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1341
 
                _("Command access level set to '%s' for new players."),
1342
 
                cmdlevel_name(level));
 
1238
              _("Command access level set to '%s' for new players."),
 
1239
              cmdlevel_name(level));
 
1240
    /* Set default access for first connection. */
1343
1241
    first_access_level = level;
1344
1242
    cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1345
 
                _("Command access level set to '%s' for first player to grab it."),
1346
 
                cmdlevel_name(level));
1347
 
  }
1348
 
  else if (strcmp(arg_name,"new") == 0) {
 
1243
              _("Command access level set to '%s' "
 
1244
                "for first player to grab it."),
 
1245
              cmdlevel_name(level));
 
1246
 
 
1247
    ret = TRUE;
 
1248
 
 
1249
  } else if (mystrcasecmp(arg[1], "new") == 0) {
1349
1250
    default_access_level = level;
1350
1251
    cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1351
 
                _("Command access level set to '%s' for new players."),
1352
 
                cmdlevel_name(level));
 
1252
              _("Command access level set to '%s' for new players."),
 
1253
              cmdlevel_name(level));
1353
1254
    if (level > first_access_level) {
1354
1255
      first_access_level = level;
1355
1256
      cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1356
 
                _("Command access level set to '%s' for first player to grab it."),
1357
 
                cmdlevel_name(level));
 
1257
                _("Command access level set to '%s' "
 
1258
                  "for first player to grab it."),
 
1259
                cmdlevel_name(level));
1358
1260
    }
1359
 
  }
1360
 
  else if (strcmp(arg_name,"first") == 0) {
 
1261
 
 
1262
    ret = TRUE;
 
1263
 
 
1264
  } else if (mystrcasecmp(arg[1], "first") == 0) {
1361
1265
    first_access_level = level;
1362
1266
    cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1363
 
                _("Command access level set to '%s' for first player to grab it."),
1364
 
                cmdlevel_name(level));
 
1267
              _("Command access level set to '%s' "
 
1268
                "for first player to grab it."),
 
1269
              cmdlevel_name(level));
1365
1270
    if (level < default_access_level) {
1366
1271
      default_access_level = level;
1367
1272
      cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1368
 
                _("Command access level set to '%s' for new players."),
1369
 
                cmdlevel_name(level));
 
1273
                _("Command access level set to '%s' for new players."),
 
1274
                cmdlevel_name(level));
1370
1275
    }
1371
 
  }
1372
 
  else if ((ptarget = find_conn_by_user_prefix(arg_name, &match_result))) {
 
1276
 
 
1277
    ret = TRUE;
 
1278
 
 
1279
  } else if ((ptarget = find_conn_by_user_prefix(arg[1], &match_result))) {
1373
1280
    if (set_cmdlevel(caller, ptarget, level)) {
1374
 
      cmd_reply(CMD_CMDLEVEL, caller, C_OK,
1375
 
                _("Command access level set to '%s' for connection %s."),
1376
 
                cmdlevel_name(level), ptarget->username);
1377
 
      send_conn_info(ptarget->self, NULL);
1378
 
    } else {
1379
 
      cmd_reply(CMD_CMDLEVEL, caller, C_FAIL,
1380
 
                _("Command access level could not be set to '%s'"
1381
 
                  " for connection %s."),
1382
 
                cmdlevel_name(level), ptarget->username);
1383
 
      return FALSE;
 
1281
      ret = TRUE;
1384
1282
    }
1385
1283
  } else {
1386
 
    cmd_reply_no_such_conn(CMD_CMDLEVEL, caller, arg_name, match_result);
1387
 
    return FALSE;
 
1284
    cmd_reply_no_such_conn(CMD_CMDLEVEL, caller, arg[1], match_result);
1388
1285
  }
1389
 
  return TRUE;
 
1286
 
 
1287
CLEAN_UP:
 
1288
  free_tokens(arg, ntokens);
 
1289
  return ret;
1390
1290
}
1391
1291
 
1392
1292
/**************************************************************************
1624
1524
**************************************************************************/
1625
1525
static bool explain_option(struct connection *caller, char *str, bool check)
1626
1526
{
1627
 
  char command[MAX_LEN_CONSOLE_LINE], *cptr_s, *cptr_d;
1628
1527
  int cmd;
1629
1528
 
1630
 
  for (cptr_s = str; *cptr_s != '\0' && !my_isalnum(*cptr_s); cptr_s++) {
1631
 
    /* nothing */
1632
 
  }
1633
 
  for (cptr_d = command; *cptr_s != '\0' && my_isalnum(*cptr_s); cptr_s++, cptr_d++)
1634
 
    *cptr_d=*cptr_s;
1635
 
  *cptr_d='\0';
 
1529
  remove_leading_trailing_spaces(str);
1636
1530
 
1637
 
  if (*command != '\0') {
1638
 
    cmd=lookup_option(command);
 
1531
  if (*str != '\0') {
 
1532
    cmd = lookup_option(str);
1639
1533
    if (cmd >= 0 && cmd < SETTINGS_NUM) {
1640
1534
      show_help_option(caller, CMD_EXPLAIN, cmd);
1641
1535
    } else if (cmd == -1 || cmd == -3) {
1716
1610
      };
1717
1611
    }
1718
1612
 
 
1613
    packet.initial_setting = game.info.is_new_game;
 
1614
 
1719
1615
    send_packet_options_settable(pconn, &packet);
1720
1616
  } conn_list_iterate_end;
1721
1617
}
1868
1764
    notify_conn(game.est_connections, NULL, E_SETTING,
1869
1765
                _("%s set to away mode."), 
1870
1766
                player_name(caller->player));
1871
 
    send_player_info(caller->player, NULL);
1872
1767
    set_ai_level_directer(caller->player, 1);
1873
1768
    caller->player->ai.control = TRUE;
1874
1769
    cancel_all_meetings(caller->player);
1881
1776
     * dialogs for meetings in AI mode. */
1882
1777
    cancel_all_meetings(caller->player);
1883
1778
  }
 
1779
 
 
1780
  send_player_info(caller->player, NULL);
 
1781
 
1884
1782
  return TRUE;
1885
1783
}
1886
1784
 
2051
1949
}
2052
1950
 
2053
1951
/******************************************************************
2054
 
  Which characters are allowed within option names: (for 'set')
2055
 
******************************************************************/
2056
 
static bool is_ok_opt_name_char(char c)
2057
 
{
2058
 
  return my_isalnum(c);
2059
 
}
2060
 
 
2061
 
/******************************************************************
2062
 
  Which characters are allowed within option values: (for 'set')
2063
 
******************************************************************/
2064
 
static bool is_ok_opt_value_char(char c)
2065
 
{
2066
 
  return (c == '-') || (c == '*') || (c == '+') || (c == '=') || my_isalnum(c);
2067
 
}
2068
 
 
2069
 
/******************************************************************
2070
 
  Which characters are allowed between option names and values: (for 'set')
2071
 
******************************************************************/
2072
 
static bool is_ok_opt_name_value_sep_char(char c)
2073
 
{
2074
 
  return (c == '=') || my_isspace(c);
2075
 
}
2076
 
 
2077
 
/******************************************************************
2078
1952
...
2079
1953
******************************************************************/
2080
1954
static bool team_command(struct connection *caller, char *str, bool check)
2145
2019
  return res;
2146
2020
}
2147
2021
 
2148
 
/******************************************************************
 
2022
/**************************************************************************
 
2023
  List all running votes. Moved from /vote command.
 
2024
**************************************************************************/
 
2025
static void show_votes(struct connection *caller)
 
2026
{
 
2027
  int count = 0;
 
2028
  const char *title;
 
2029
 
 
2030
  if (vote_list != NULL) {
 
2031
    vote_list_iterate(vote_list, pvote) {
 
2032
      if (!conn_can_see_vote(caller, pvote)) {
 
2033
        continue;
 
2034
      }
 
2035
      title = vote_is_team_only(pvote) ? _("Teamvote") : _("Vote");
 
2036
      cmd_reply(CMD_VOTE, caller, C_COMMENT,
 
2037
                _("%s %d \"%s\" (needs %0.0f%%%s): %d for, "
 
2038
                  "%d against, and %d abstained out of %d players."),
 
2039
                title, pvote->vote_no, pvote->cmdline,
 
2040
                MIN(100, pvote->need_pc * 100 + 1),
 
2041
                pvote->flags & VCF_NODISSENT ? _(" no dissent") : "",
 
2042
                pvote->yes, pvote->no, pvote->abstain, game.info.nplayers);
 
2043
      count++;
 
2044
    } vote_list_iterate_end;
 
2045
  }
 
2046
 
 
2047
  if (count == 0) {
 
2048
    cmd_reply(CMD_VOTE, caller, C_COMMENT,
 
2049
              _("There are no votes going on."));
 
2050
  }
 
2051
}
 
2052
 
 
2053
/**************************************************************************
 
2054
  Vote command argument definitions.
 
2055
**************************************************************************/
 
2056
static const char *const vote_args[] = {
 
2057
  "yes",
 
2058
  "no",
 
2059
  "abstain",
 
2060
  NULL
 
2061
};
 
2062
static const char *vote_arg_accessor(int i)
 
2063
{
 
2064
  return vote_args[i];
 
2065
}
 
2066
 
 
2067
/**************************************************************************
2149
2068
  Make or participate in a vote.
2150
 
******************************************************************/
2151
 
static bool vote_command(struct connection *caller, char *str,
2152
 
                         bool check)
 
2069
**************************************************************************/
 
2070
static bool vote_command(struct connection *caller, char *str, bool check)
2153
2071
{
2154
2072
  char buf[MAX_LEN_CONSOLE_LINE];
2155
 
  char *arg[3];
2156
 
  int ntokens = 0, i;
2157
 
  const char *usage = _("Undefined arguments. Usage: vote yes|no "
2158
 
                        "[vote number].");
 
2073
  char *arg[2];
 
2074
  int ntokens = 0, i = 0, which = -1;
 
2075
  enum m_pre_result match_result;
 
2076
  struct vote *pvote = NULL;
 
2077
  const char *usage = _("Invalid arguments. Usage: vote "
 
2078
                        "yes|no|abstain [vote number].");
2159
2079
  bool res = FALSE;
2160
2080
 
2161
 
  if (caller == NULL || caller->player == NULL) {
2162
 
    cmd_reply(CMD_VOTE, caller, C_FAIL, _("This command is client only."));
2163
 
    return FALSE;
2164
 
  } else if (caller->observer) {
2165
 
    cmd_reply(CMD_VOTE, caller, C_FAIL, _("Observers cannot vote."));
2166
 
    return FALSE;
2167
 
  } else if (S_S_RUNNING != server_state()) {
2168
 
    cmd_reply(CMD_VOTE, caller, C_FAIL, _("You can only vote in a "
2169
 
              "running game.  Use 'first' to become the game organizer "
2170
 
              "if there currently is none."));
2171
 
    return FALSE;
2172
 
  } else if (!str || strlen(str) == 0) {
2173
 
    int j = 0;
2174
 
 
2175
 
    for (i = 0; i < MAX_NUM_PLAYERS; i++) {
2176
 
      struct voting *vote = &votes[i];
2177
 
 
2178
 
      if (vote->command[0] != '\0') {
2179
 
        j++;
2180
 
        cmd_reply(CMD_VOTE, caller, C_COMMENT,
2181
 
                  _("Vote %d \"%s\": %d for, %d against"),
2182
 
                  vote->vote_no, vote->command, vote->yes, 
2183
 
                  vote->no);
2184
 
      }
2185
 
    }
2186
 
    if (j == 0) {
2187
 
      cmd_reply(CMD_VOTE, caller, C_COMMENT,
2188
 
                _("There are no votes going on."));
2189
 
    }
2190
 
    return FALSE; /* see below */
2191
 
  } if (check) {
2192
 
    return FALSE; /* cannot vote over having vote! */
 
2081
  if (check) {
 
2082
    /* This should never happen, since /vote must always be
 
2083
     * set to ALLOW_BASIC or less. But just in case... */
 
2084
    return FALSE;
2193
2085
  }
2194
2086
 
2195
2087
  sz_strlcpy(buf, str);
2196
2088
  ntokens = get_tokens(buf, arg, 2, TOKEN_DELIMITERS);
2197
2089
 
2198
 
  if (strcmp(arg[0], "yes") == 0
2199
 
      || strcmp(arg[0], "no") == 0) {
2200
 
    int which = -1;
2201
 
    struct voting *vote = NULL;
2202
 
 
2203
 
    if (ntokens == 1) {
2204
 
      /* Applies to last vote */
2205
 
      if (last_vote > -1) {
2206
 
        which = last_vote;
2207
 
      } else {
2208
 
        cmd_reply(CMD_VOTE, caller, C_FAIL, _("No legal last vote."));
2209
 
        goto cleanup;
2210
 
      }
2211
 
    } else {
2212
 
      if (sscanf(arg[1], "%d", &which) <= 0) {
2213
 
        cmd_reply(CMD_VOTE, caller, C_SYNTAX, _("Value must be integer."));
2214
 
        goto cleanup;
2215
 
      }
2216
 
    }
2217
 
    /* Ok, now try to find this vote */
2218
 
    for (i = 0; i < MAX_NUM_PLAYERS; i++) {
2219
 
      if (votes[i].vote_no == which) {
2220
 
        vote = &votes[i];
2221
 
      }
2222
 
    }
2223
 
    if (which > last_vote || !vote || vote->command[0] == '\0') {
2224
 
      cmd_reply(CMD_VOTE, caller, C_FAIL, _("No such vote (%d)."), which);
2225
 
      goto cleanup;
2226
 
    }
2227
 
    if (strcmp(arg[0], "yes") == 0) {
2228
 
      cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted for \"%s\""), 
2229
 
                vote->command);
2230
 
      vote->votes_cast[player_index(caller->player)] = VOTE_YES;
2231
 
    } else if (strcmp(arg[0], "no") == 0) {
2232
 
      cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted against \"%s\""), 
2233
 
                vote->command);
2234
 
      vote->votes_cast[player_index(caller->player)] = VOTE_NO;
2235
 
    }
2236
 
    check_vote(vote);
2237
 
  } else {
 
2090
  if (ntokens == 0) {
 
2091
    show_votes(caller);
 
2092
    goto CLEANUP;
 
2093
  } else if (!conn_can_vote(caller, NULL)) {
 
2094
    cmd_reply(CMD_VOTE, caller, C_FAIL,
 
2095
              _("You are not allowed to use this command."));
 
2096
    goto CLEANUP;
 
2097
  }
 
2098
 
 
2099
  match_result = match_prefix(vote_arg_accessor, VOTE_NUM, 0,
 
2100
                              mystrncasecmp, NULL, arg[0], &i);
 
2101
 
 
2102
  if (match_result == M_PRE_AMBIGUOUS) {
 
2103
    cmd_reply(CMD_VOTE, caller, C_SYNTAX,
 
2104
              _("The argument \"%s\" is ambigious."), arg[0]);
 
2105
    goto CLEANUP;
 
2106
  } else if (match_result > M_PRE_AMBIGUOUS) {
 
2107
    /* Failed */
2238
2108
    cmd_reply(CMD_VOTE, caller, C_SYNTAX, "%s", usage);
2239
 
    goto cleanup;
 
2109
    goto CLEANUP;
 
2110
  }
 
2111
 
 
2112
  if (ntokens == 1) {
 
2113
    /* Applies to last vote */
 
2114
    if (vote_number_sequence > 0 && get_vote_by_no(vote_number_sequence)) {
 
2115
      which = vote_number_sequence;
 
2116
    } else {
 
2117
      int num_votes = vote_list_size(vote_list);
 
2118
      if (num_votes == 0) {
 
2119
        cmd_reply(CMD_VOTE, caller, C_FAIL, _("There are no votes running."));
 
2120
      } else {
 
2121
        cmd_reply(CMD_VOTE, caller, C_FAIL, _("No legal last vote (%d %s)."),
 
2122
                  num_votes, PL_("other vote running", "other votes running",
 
2123
                                 num_votes));
 
2124
      }
 
2125
      goto CLEANUP;
 
2126
    }
 
2127
  } else {
 
2128
    if (sscanf(arg[1], "%d", &which) <= 0) {
 
2129
      cmd_reply(CMD_VOTE, caller, C_SYNTAX, _("Value must be an integer."));
 
2130
      goto CLEANUP;
 
2131
    }
 
2132
  }
 
2133
 
 
2134
  if (!(pvote = get_vote_by_no(which))) {
 
2135
    cmd_reply(CMD_VOTE, caller, C_FAIL, _("No such vote (%d)."), which);
 
2136
    goto CLEANUP;
 
2137
  }
 
2138
 
 
2139
  if (!conn_can_vote(caller, pvote)) {
 
2140
    cmd_reply(CMD_VOTE, caller, C_FAIL,
 
2141
              _("You are not allowed to vote on that."));
 
2142
    goto CLEANUP;
 
2143
  }
 
2144
 
 
2145
  if (i == VOTE_YES) {
 
2146
    cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted for \"%s\""),
 
2147
              pvote->cmdline);
 
2148
    connection_vote(caller, pvote, VOTE_YES);
 
2149
  } else if (i == VOTE_NO) {
 
2150
    cmd_reply(CMD_VOTE, caller, C_COMMENT, _("You voted against \"%s\""),
 
2151
              pvote->cmdline);
 
2152
    connection_vote(caller, pvote, VOTE_NO);
 
2153
  } else if (i == VOTE_ABSTAIN) {
 
2154
    cmd_reply(CMD_VOTE, caller, C_COMMENT,
 
2155
              _("You abstained from voting on \"%s\""), pvote->cmdline);
 
2156
    connection_vote(caller, pvote, VOTE_ABSTAIN);
 
2157
  } else {
 
2158
    assert(0);                  /* Must never happen */
2240
2159
  }
2241
2160
 
2242
2161
  res = TRUE;
2243
 
  cleanup:
2244
 
  for (i = 0; i < ntokens; i++) {
2245
 
    free(arg[i]);
2246
 
  }
 
2162
 
 
2163
CLEANUP:
 
2164
  free_tokens(arg, ntokens);
2247
2165
  return res;
2248
2166
}
2249
2167
 
 
2168
/**************************************************************************
 
2169
  Cancel a vote... /cancelvote <vote number>|all.
 
2170
**************************************************************************/
 
2171
static bool cancelvote_command(struct connection *caller,
 
2172
                               char *arg, bool check)
 
2173
{
 
2174
  struct vote *pvote = NULL;
 
2175
  int vote_no;
 
2176
 
 
2177
  if (check) {
 
2178
    /* This should never happen anyway, since /cancelvote
 
2179
     * is set to ALLOW_BASIC in both pregame and while the
 
2180
     * game is running. */
 
2181
    return FALSE;
 
2182
  }
 
2183
 
 
2184
  remove_leading_trailing_spaces(arg);
 
2185
 
 
2186
  if (arg[0] == '\0') {
 
2187
    if (caller == NULL) {
 
2188
      /* Server prompt */
 
2189
      cmd_reply(CMD_CANCELVOTE, caller, C_SYNTAX,
 
2190
                _("Missing argument <vote number> or "
 
2191
                  "the string \"all\"."));
 
2192
      return FALSE;
 
2193
    }
 
2194
    /* The caller cancel his/her own vote. */
 
2195
    if (!(pvote = get_vote_by_caller(caller))) {
 
2196
      cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
 
2197
                _("You don't have any vote going on."));
 
2198
      return FALSE;
 
2199
    }
 
2200
  } else if (mystrcasecmp(arg, "all") == 0) {
 
2201
    /* Cancel all votes (needs some privileges). */
 
2202
    if (vote_list_size(vote_list) == 0) {
 
2203
      cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
 
2204
                _("There isn't any vote going on."));
 
2205
      return FALSE;
 
2206
    } else if (!caller || conn_get_access(caller) >= ALLOW_ADMIN) {
 
2207
      clear_all_votes();
 
2208
      notify_conn(NULL, NULL, E_CHAT_MSG,
 
2209
                  _("Server: All votes have been removed."));
 
2210
      return TRUE;
 
2211
    } else {
 
2212
      cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
 
2213
                _("You are not allowed to use this command."));
 
2214
      return FALSE;
 
2215
    }
 
2216
  } else if (sscanf(arg, "%d", &vote_no) == 1) {
 
2217
    /* Cancel one particular vote (needs some privileges if the vote
 
2218
     * is not owned). */
 
2219
    if (!(pvote = get_vote_by_no(vote_no))) {
 
2220
      cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
 
2221
                _("No such vote (%d)."), vote_no);
 
2222
      return FALSE;
 
2223
    } else if (caller && conn_get_access(caller) < ALLOW_ADMIN
 
2224
               && caller->id != pvote->caller_id) {
 
2225
      cmd_reply(CMD_CANCELVOTE, caller, C_FAIL,
 
2226
                _("You are not allowed to cancel this vote (%d)."),
 
2227
                vote_no);
 
2228
      return FALSE;
 
2229
    }
 
2230
  } else {
 
2231
    cmd_reply(CMD_CANCELVOTE, caller, C_SYNTAX,
 
2232
              _("Usage: /cancelvote [<vote number>|all]"));
 
2233
    return FALSE;
 
2234
  }
 
2235
 
 
2236
  assert(pvote != NULL);
 
2237
 
 
2238
  if (caller) {
 
2239
    notify_team(conn_get_player(vote_get_caller(pvote)),
 
2240
                NULL, E_CHAT_MSG,
 
2241
                _("Server: %s cancelled the vote \"%s\" (number %d)."),
 
2242
                caller->username, pvote->cmdline, pvote->vote_no);
 
2243
  } else {
 
2244
    /* Server prompt */
 
2245
    notify_team(conn_get_player(vote_get_caller(pvote)),
 
2246
                NULL, E_CHAT_MSG,
 
2247
                _("Server: The vote \"%s\" (number %d) has been cancelled."),
 
2248
                pvote->cmdline, pvote->vote_no);
 
2249
  }
 
2250
  /* Make it after, prevent crashs about a free pointer (pvote). */
 
2251
  remove_vote(pvote);
 
2252
 
 
2253
  return TRUE;
 
2254
}
 
2255
 
2250
2256
/******************************************************************
2251
2257
  Turn on selective debugging.
2252
2258
******************************************************************/
2443
2449
******************************************************************/
2444
2450
static bool set_command(struct connection *caller, char *str, bool check)
2445
2451
{
2446
 
  char command[MAX_LEN_CONSOLE_LINE], arg[MAX_LEN_CONSOLE_LINE], *cptr_s, *cptr_d;
2447
 
  int val, cmd, i;
 
2452
  char *args[2], *arg;
 
2453
  int val, cmd, i, nargs;
2448
2454
  struct settings_s *op;
2449
2455
  bool do_update;
2450
2456
  char buffer[500];
2451
 
 
2452
 
  for (cptr_s = str; *cptr_s != '\0' && !is_ok_opt_name_char(*cptr_s);
2453
 
       cptr_s++) {
2454
 
    /* nothing */
2455
 
  }
2456
 
 
2457
 
  for(cptr_d=command;
2458
 
      *cptr_s != '\0' && is_ok_opt_name_char(*cptr_s);
2459
 
      cptr_s++, cptr_d++) {
2460
 
    *cptr_d=*cptr_s;
2461
 
  }
2462
 
  *cptr_d='\0';
2463
 
  
2464
 
  for (; *cptr_s != '\0' && is_ok_opt_name_value_sep_char(*cptr_s); cptr_s++) {
2465
 
    /* nothing */
2466
 
  }
2467
 
 
2468
 
  for (cptr_d = arg; *cptr_s != '\0' && is_ok_opt_value_char(*cptr_s); cptr_s++, cptr_d++)
2469
 
    *cptr_d=*cptr_s;
2470
 
  *cptr_d='\0';
2471
 
 
2472
 
  cmd = lookup_option(command);
2473
 
  if (cmd==-1) {
2474
 
    cmd_reply(CMD_SET, caller, C_SYNTAX,
2475
 
              _("Undefined argument.  Usage: set <option> <value>."));
2476
 
    return FALSE;
2477
 
  }
2478
 
  else if (cmd==-2) {
2479
 
    cmd_reply(CMD_SET, caller, C_SYNTAX,
2480
 
              _("Ambiguous option name."));
2481
 
    return FALSE;
 
2457
  bool ret = FALSE;
 
2458
 
 
2459
  /* '=' is also a valid delimiter for this function. */
 
2460
  nargs = get_tokens(str, args, ARRAY_SIZE(args), TOKEN_DELIMITERS "=");
 
2461
 
 
2462
  if (nargs < 2 || -1 == (cmd = lookup_option(args[0]))) {
 
2463
    cmd_reply(CMD_SET, caller, C_SYNTAX,
 
2464
              _("Undefined argument.  Usage: set <option> <value>."));
 
2465
    goto cleanup;
 
2466
  }
 
2467
  if (-2 == cmd) {
 
2468
    cmd_reply(CMD_SET, caller, C_SYNTAX, _("Ambiguous option name."));
 
2469
    goto cleanup;
2482
2470
  }
2483
2471
  if (!may_set_option(caller,cmd) && !check) {
2484
2472
     cmd_reply(CMD_SET, caller, C_FAIL,
2485
 
               _("You are not allowed to set this option."));
2486
 
    return FALSE;
 
2473
               _("You are not allowed to set this option."));
 
2474
    goto cleanup;
2487
2475
  }
2488
2476
  if (!setting_is_changeable(cmd)) {
2489
2477
    cmd_reply(CMD_SET, caller, C_BOUNCE,
2490
 
              _("This setting can't be modified after the game has started."));
2491
 
    return FALSE;
 
2478
              _("This setting can't be modified after the game has started."));
 
2479
    goto cleanup;
2492
2480
  }
2493
2481
 
 
2482
  arg = args[1];
2494
2483
  op = &settings[cmd];
2495
2484
 
2496
2485
  do_update = FALSE;
2500
2489
  case SSET_BOOL:
2501
2490
    if (sscanf(arg, "%d", &val) != 1) {
2502
2491
      cmd_reply(CMD_SET, caller, C_SYNTAX, _("Value must be an integer."));
2503
 
      return FALSE;
 
2492
      goto cleanup;
2504
2493
    }
2505
2494
    /* make sure the input string only contains digits */
2506
2495
    for (i = 0;; i++) {
2511
2500
        cmd_reply(CMD_SET, caller, C_SYNTAX,
2512
2501
                  _("The parameter %s should only contain digits 0-1."),
2513
2502
                  op->name);
2514
 
        return FALSE;
 
2503
        goto cleanup;
2515
2504
      }
2516
2505
    }
2517
2506
    if (val != 0 && val != 1) {
2518
2507
      cmd_reply(CMD_SET, caller, C_SYNTAX,
2519
2508
                _("Value out of range (minimum: 0, maximum: 1)."));
2520
 
      return FALSE;
 
2509
      goto cleanup;
2521
2510
    } else {
2522
2511
      const char *reject_message = NULL;
2523
2512
      bool b_val = (val != 0);
2525
2514
      if (op->bool_validate != NULL
2526
2515
          && !op->bool_validate(b_val, caller, &reject_message)) {
2527
2516
        cmd_reply(CMD_SET, caller, C_SYNTAX, "%s", reject_message);
2528
 
        return FALSE;
 
2517
        goto cleanup;
2529
2518
      }
2530
2519
 
2531
2520
      if (!check) {
2541
2530
  case SSET_INT:
2542
2531
    if (sscanf(arg, "%d", &val) != 1) {
2543
2532
      cmd_reply(CMD_SET, caller, C_SYNTAX, _("Value must be an integer."));
2544
 
      return FALSE;
 
2533
      goto cleanup;
2545
2534
    }
2546
2535
        /* make sure the input string only contains digits */
2547
2536
    for (i = 0;; i++) {
2553
2542
        cmd_reply(CMD_SET, caller, C_SYNTAX,
2554
2543
                  _("The parameter %s should only contain +- and 0-9."),
2555
2544
                  op->name);
2556
 
        return FALSE;
 
2545
        goto cleanup;
2557
2546
      }
2558
2547
    }
2559
2548
    if (val < op->int_min_value || val > op->int_max_value) {
2560
2549
      cmd_reply(CMD_SET, caller, C_SYNTAX,
2561
2550
                _("Value out of range (minimum: %d, maximum: %d)."),
2562
2551
                op->int_min_value, op->int_max_value);
2563
 
      return FALSE;
 
2552
      goto cleanup;
2564
2553
    } else {
2565
2554
      const char *reject_message = NULL;
2566
2555
 
2567
2556
      if (op->int_validate != NULL
2568
2557
          && !op->int_validate(val, caller, &reject_message)) {
2569
2558
        cmd_reply(CMD_SET, caller, C_SYNTAX, "%s", reject_message);
2570
 
        return FALSE;
 
2559
        goto cleanup;
2571
2560
      }
2572
2561
 
2573
2562
      if (!check) {
2584
2573
    if (strlen(arg) >= op->string_value_size) {
2585
2574
      cmd_reply(CMD_SET, caller, C_SYNTAX,
2586
2575
                _("String value too long.  Usage: set <option> <value>."));
2587
 
      return FALSE;
 
2576
      goto cleanup;
2588
2577
    } else {
2589
2578
      const char *reject_message = NULL;
2590
2579
 
2591
2580
      if (op->string_validate != NULL
2592
2581
          && !op->string_validate(arg, caller, &reject_message)) {
2593
2582
        cmd_reply(CMD_SET, caller, C_SYNTAX, "%s", reject_message);
2594
 
        return FALSE;
 
2583
        goto cleanup;
2595
2584
      }
2596
2585
 
2597
2586
      if (!check) {
2605
2594
    break;
2606
2595
  }
2607
2596
 
 
2597
  ret = TRUE;   /* Looks a success. */
 
2598
 
2608
2599
  if (!check && strlen(buffer) > 0 && sset_is_to_client(cmd)) {
2609
2600
    notify_conn(NULL, NULL, E_SETTING, "%s", buffer);
2610
2601
  }
2637
2628
    reset_all_start_commands();
2638
2629
    send_server_info_to_metaserver(META_INFO);
2639
2630
  }
2640
 
  return TRUE;
 
2631
 
 
2632
  cleanup:
 
2633
  free_tokens(args, nargs);
 
2634
  return ret;
2641
2635
}
2642
2636
 
2643
2637
/**************************************************************************
2912
2906
    send_diplomatic_meetings(pconn);
2913
2907
    send_packet_thaw_hint(pconn);
2914
2908
    dsend_packet_start_phase(pconn, game.info.phase);
 
2909
  } else if (S_S_OVER == server_state()) {
 
2910
    send_packet_freeze_hint(pconn);
 
2911
    send_all_info(pconn->self);
 
2912
    send_game_state(pconn->self, C_S_OVER);
 
2913
    send_packet_thaw_hint(pconn);
 
2914
    report_final_scores(pconn->self);
2915
2915
  } else {
2916
2916
    /* send changed player connection to everybody */
2917
2917
    send_game_info(game.est_connections);
2930
2930
              pconn->username);
2931
2931
  }
2932
2932
 
 
2933
  send_updated_vote_totals(NULL);
 
2934
 
2933
2935
  end:;
2934
2936
  /* free our args */
2935
2937
  for (i = 0; i < ntokens; i++) {
3033
3035
  }
3034
3036
 
3035
3037
  /* if we want to take while the game is running, reset the client */
3036
 
  if (S_S_RUNNING == server_state()) {
 
3038
  if (S_S_RUNNING <= server_state()) {
3037
3039
    send_game_state(pconn->self, C_S_PREPARING);
3038
3040
    send_rulesets(pconn->self);
3039
3041
    send_server_settings(pconn->self);
3050
3052
  if (pplayer) {
3051
3053
    conn_list_iterate(pplayer->connections, aconn) {
3052
3054
      if (!aconn->observer) {
3053
 
        if (S_S_RUNNING == server_state()) {
 
3055
        if (S_S_RUNNING <= server_state()) {
3054
3056
          send_game_state(aconn->self, C_S_PREPARING);
3055
3057
          send_rulesets(aconn->self);
3056
3058
          send_server_settings(aconn->self);
3100
3102
  }
3101
3103
 
3102
3104
  if (res) {
 
3105
    bool has_been_created = (pplayer == NULL);
 
3106
 
3103
3107
    /* Successfully attached */
3104
3108
    pplayer = pconn->player; /* In case pplayer was NULL. */
3105
3109
 
3110
3114
    }
3111
3115
 
3112
3116
    /* aitoggle the player back to human as necessary. */
3113
 
    if (pplayer->ai.control && game.info.auto_ai_toggle) {
 
3117
    if (pplayer->ai.control
 
3118
        && (game.info.auto_ai_toggle || has_been_created)) {
3114
3119
      toggle_ai_player_direct(NULL, pplayer);
3115
3120
    }
3116
3121
  }
3122
3127
    send_diplomatic_meetings(pconn);
3123
3128
    send_packet_thaw_hint(pconn);
3124
3129
    dsend_packet_start_phase(pconn, game.info.phase);
 
3130
  } else if (S_S_OVER == server_state()) {
 
3131
    send_packet_freeze_hint(pconn);
 
3132
    send_all_info(pconn->self);
 
3133
    send_game_state(pconn->self, C_S_OVER);
 
3134
    send_packet_thaw_hint(pconn);
 
3135
    report_final_scores(pconn->self);
3125
3136
  } else {
3126
3137
    /* send changed player connection to everybody */
3127
3138
    send_game_info(game.est_connections);
3143
3154
              pplayer->is_alive
3144
3155
              ? _("Alive")
3145
3156
              : _("Dead"));
 
3157
    send_updated_vote_totals(NULL);
3146
3158
  } else {
3147
3159
    cmd_reply(CMD_TAKE, caller, C_FAIL, _("%s failed to attach to any player."),
3148
3160
              pconn->username);
3218
3230
  }
3219
3231
 
3220
3232
  /* if we want to detach while the game is running, reset the client */
3221
 
  if (S_S_RUNNING == server_state()) {
 
3233
  if (S_S_RUNNING <= server_state()) {
3222
3234
    send_game_state(pconn->self, C_S_PREPARING);
3223
3235
    send_rulesets(pconn->self);
3224
3236
    send_server_settings(pconn->self);
3251
3263
    /* detach any observers */
3252
3264
    conn_list_iterate(pplayer->connections, aconn) {
3253
3265
      if (aconn->observer) {
3254
 
        if (S_S_RUNNING == server_state()) {
 
3266
        if (S_S_RUNNING <= server_state()) {
3255
3267
          send_rulesets(aconn->self);
3256
3268
          send_server_settings(aconn->self);
3257
3269
        }
3270
3282
  }
3271
3283
 
3272
3284
  if (pplayer && !pplayer->is_connected) {
 
3285
    cancel_connection_votes(pconn);
 
3286
    send_updated_vote_totals(NULL);
 
3287
 
3273
3288
    /* aitoggle the player if no longer connected. */
3274
3289
    if (game.info.auto_ai_toggle && !pplayer->ai.control) {
3275
3290
      toggle_ai_player_direct(NULL, pplayer);
3340
3355
  struct timer *loadtimer, *uloadtimer;  
3341
3356
  struct section_file file;
3342
3357
  char arg[MAX_LEN_PATH];
 
3358
  struct conn_list *global_observers;
3343
3359
 
3344
3360
  if (!filename || filename[0] == '\0') {
3345
3361
    cmd_reply(CMD_LOAD, caller, C_FAIL, _("Usage: load <game name>"));
3405
3421
 
3406
3422
  sz_strlcpy(srvarg.load_filename, arg);
3407
3423
 
 
3424
  /* Detach all connections when loading the game, preventing that some
 
3425
   * infos are sent to clients which have have the most of the datas
 
3426
   * uninitialized. */
 
3427
  global_observers = conn_list_new();
 
3428
  conn_list_iterate(game.est_connections, pconn) {
 
3429
    if (pconn->player) {
 
3430
      unattach_connection_from_player(pconn);
 
3431
    } else if (pconn->observer) {
 
3432
      conn_list_append(global_observers, pconn);
 
3433
      pconn->observer = FALSE;
 
3434
    }
 
3435
  } conn_list_iterate_end;
 
3436
 
3408
3437
  game_load(&file);
3409
3438
  section_file_check_unused(&file, arg);
3410
3439
  section_file_free(&file);
3427
3456
   * to connections that have the correct username. Any attachments
3428
3457
   * made before the game load are unattached. */
3429
3458
  conn_list_iterate(game.est_connections, pconn) {
3430
 
    if (pconn->player) {
3431
 
      unattach_connection_from_player(pconn);
3432
 
    }
3433
3459
    players_iterate(pplayer) {
3434
3460
      if (strcmp(pconn->username, pplayer->username) == 0) {
3435
3461
        attach_connection_to_player(pconn, pplayer);
3438
3464
      }
3439
3465
    } players_iterate_end;
3440
3466
  } conn_list_iterate_end;
 
3467
 
 
3468
  /* Reattach global observers. */
 
3469
  conn_list_iterate(global_observers, pconn) {
 
3470
    if (!pconn->player) {
 
3471
      /* May have been assigned to a player before. */
 
3472
      pconn->observer = TRUE;
 
3473
    }
 
3474
  } conn_list_iterate_end;
 
3475
  conn_list_free(global_observers);
 
3476
 
 
3477
  send_conn_info(game.est_connections, game.est_connections);
 
3478
 
3441
3479
  return TRUE;
3442
3480
}
3443
3481
 
3458
3496
             _("Current ruleset directory is \"%s\""), game.rulesetdir);
3459
3497
    return FALSE;
3460
3498
  }
3461
 
  if (S_S_INITIAL != server_state()) {
 
3499
  if (S_S_INITIAL != server_state() || !game.info.is_new_game) {
3462
3500
    cmd_reply(CMD_RULESETDIR, caller, C_FAIL,
3463
3501
              _("This setting can't be modified after the game has started."));
3464
3502
    return FALSE;
3555
3593
      *cptr_s, *cptr_d;
3556
3594
  int i;
3557
3595
  enum command_id cmd;
 
3596
  enum cmdlevel_id level;
3558
3597
 
3559
3598
  /* notify to the server console */
3560
3599
  if (!check && caller) {
3596
3635
    *cptr_d=*cptr_s;
3597
3636
  *cptr_d='\0';
3598
3637
 
 
3638
  cptr_s = skip_leading_spaces(cptr_s);
 
3639
 
 
3640
  /* keep this before we cut everything after a space */
 
3641
  sz_strlcpy(allargs, cptr_s);
 
3642
  cut_comment(allargs);
 
3643
 
 
3644
  sz_strlcpy(arg, cptr_s);
 
3645
  cut_comment(arg);
 
3646
 
 
3647
  i = strlen(arg) - 1;
 
3648
  while (i > 0 && my_isspace(arg[i])) {
 
3649
    arg[i--] = '\0';
 
3650
  }
 
3651
 
3599
3652
  cmd = command_named(command, FALSE);
3600
3653
  if (cmd == CMD_AMBIGUOUS) {
3601
3654
    cmd = command_named(command, TRUE);
3609
3662
    return FALSE;
3610
3663
  }
3611
3664
 
3612
 
  if (S_S_INITIAL != server_state()
3613
 
      && caller
3614
 
      && caller->player
3615
 
      && !caller->observer /* don't allow observers to ask votes */
3616
 
      && !check
3617
 
      && caller->access_level == ALLOW_INFO
3618
 
      && commands[cmd].level == ALLOW_CTRL) {
3619
 
    int idx = player_index(caller->player);
 
3665
  level = command_access_level(cmd);
 
3666
 
 
3667
  if (conn_can_vote(caller, NULL) && level == ALLOW_CTRL
 
3668
      && conn_get_access(caller) == ALLOW_BASIC && !check) {
 
3669
    struct vote *vote;
3620
3670
 
3621
3671
    /* If we already have a vote going, cancel it in favour of the new
3622
3672
     * vote command. You can only have one vote at a time. */
3623
 
    if (votes[idx].command[0] != '\0') {
 
3673
    if (get_vote_by_caller(caller)) {
3624
3674
      cmd_reply(CMD_VOTE, caller, C_COMMENT,
3625
 
                _("Your new vote canceled your previous vote."));
3626
 
      votes[idx].command[0] = '\0';
 
3675
                _("Your new vote cancelled your previous vote."));
3627
3676
    }
3628
3677
 
3629
3678
    /* Check if the vote command would succeed. */
3630
 
    if (handle_stdin_input(caller, full_command, TRUE)) {
3631
 
      last_vote++;
3632
 
      notify_conn(NULL, NULL, E_SETTING,
3633
 
                  _("New vote (number %d) by %s: %s."),
3634
 
                  last_vote,
3635
 
                  player_name(caller->player),
3636
 
                  full_command);
3637
 
      sz_strlcpy(votes[idx].command, full_command);
3638
 
      votes[idx].vote_no = last_vote;
3639
 
      memset(votes[idx].votes_cast, VOTE_NONE, sizeof(votes[idx].votes_cast));
3640
 
      votes[idx].votes_cast[idx] = VOTE_YES; /* vote on your own suggestion */
3641
 
      check_vote(&votes[idx]); /* update vote numbers, maybe auto-accept */
 
3679
    if (handle_stdin_input(caller, full_command, TRUE)
 
3680
        && (vote = vote_new(caller, allargs, cmd))) {
 
3681
      char votedesc[MAX_LEN_CONSOLE_LINE];
 
3682
      const struct player *teamplr;
 
3683
      const char *what;
 
3684
 
 
3685
      describe_vote(vote, votedesc, sizeof(votedesc));
 
3686
 
 
3687
      if (vote_is_team_only(vote)) {
 
3688
        what = _("New teamvote");
 
3689
        teamplr = conn_get_player(caller);
 
3690
      } else {
 
3691
        what = _("New vote");
 
3692
        teamplr = NULL;
 
3693
      }
 
3694
      notify_team(teamplr, NULL, E_CHAT_MSG,
 
3695
                  _("%s (number %d) by %s: %s"), what,
 
3696
                  vote->vote_no, caller->username, votedesc);
 
3697
 
 
3698
      /* Vote on your own suggestion. */
 
3699
      connection_vote(caller, vote, VOTE_YES);
3642
3700
      return TRUE;
 
3701
 
3643
3702
    } else {
3644
3703
      cmd_reply(CMD_VOTE, caller, C_FAIL,
3645
 
                _("Your new vote (\"%s\") was not legal or was not recognized."),
3646
 
                full_command);
 
3704
                _("Your new vote (\"%s\") was not "
 
3705
                  "legal or was not recognized."), full_command);
3647
3706
      return FALSE;
3648
3707
    }
3649
3708
  }
3650
 
  if (caller
3651
 
      && !(check && caller->access_level >= ALLOW_INFO 
3652
 
           && commands[cmd].level == ALLOW_CTRL)
3653
 
      && caller->access_level < commands[cmd].level) {
 
3709
 
 
3710
  if (caller && !(check && conn_get_access(caller) >= ALLOW_BASIC
 
3711
                  && level == ALLOW_CTRL)
 
3712
      && conn_get_access(caller) < level) {
3654
3713
    cmd_reply(cmd, caller, C_FAIL,
3655
3714
              _("You are not allowed to use this command."));
3656
3715
    return FALSE;
3657
3716
  }
3658
3717
 
3659
 
  cptr_s = skip_leading_spaces(cptr_s);
3660
 
  sz_strlcpy(arg, cptr_s);
3661
 
 
3662
 
  cut_comment(arg);
3663
 
 
3664
 
  /* keep this before we cut everything after a space */
3665
 
  sz_strlcpy(allargs, cptr_s);
3666
 
  cut_comment(allargs);
3667
 
 
3668
 
  i=strlen(arg)-1;
3669
 
  while(i>0 && my_isspace(arg[i]))
3670
 
    arg[i--]='\0';
3671
 
 
3672
 
  if (!check && commands[cmd].level > ALLOW_INFO) {
 
3718
  if (!check && level > ALLOW_INFO) {
3673
3719
    /*
3674
3720
     * this command will affect the game - inform all players
3675
3721
     *
3743
3789
    return wall(arg, check);
3744
3790
  case CMD_VOTE:
3745
3791
    return vote_command(caller, arg, check);
 
3792
  case CMD_CANCELVOTE:
 
3793
    return cancelvote_command(caller, arg, check);
3746
3794
  case CMD_READ_SCRIPT:
3747
3795
    return read_command(caller, arg, check);
3748
3796
  case CMD_WRITE_SCRIPT: