static int sanc_cmd(void) { struct nstr_item ni; struct natstr nat; int first = 1; if (!opt_BLITZ) { pr_id(player, C_BADCMD, "Command %s not found\n", player->argp[0]); return RET_FAIL; } snxtitem_all(&ni, EF_NATION); while (nxtitem(&ni, &nat)) { if (nat.nat_stat != STAT_SANCT) continue; if (first) { pr_id(player, C_DATA, "The following countries are still in sanctuary:\n"); first = 0; } pr_id(player, C_DATA, "%s\n", nat.nat_cnam); } if (first) pr_id(player, C_CMDOK, "There are no countries in sanctuary\n"); else pr_id(player, C_CMDOK, "\n"); return RET_OK; }
/*ARGSUSED*/ void player_login(void *ud) { time_t deadline; char buf[128]; char space[128]; int res, ac, cmd, prev_state; player->proc = empth_self(); pr_id(player, C_INIT, "Empire server ready\n"); for (;;) { deadline = player_io_deadline(player, 0); if (io_outputwaiting(player->iop)) { if (io_output(player->iop, deadline) <= 0) break; continue; } if (io_gets(player->iop, buf, sizeof(buf)) < 0) { res = io_input(player->iop, deadline); if (res <= 0) break; continue; } journal_input(buf); ac = parse(buf, space, player->argp, NULL, NULL, NULL); if (ac <= 0) { pr_id(player, C_BADCMD, "Can't parse command\n"); continue; } cmd = comtch(player->argp[0], login_coms, 0); if (cmd < 0) { pr_id(player, C_BADCMD, "Command %s not found\n", player->argp[0]); continue; } switch (login_coms[cmd].c_addr()) { case RET_OK: break; case RET_FAIL: break; case RET_SYN: pr_id(player, C_BADCMD, "Usage %s\n", login_coms[cmd].c_form); break; default: break; } } prev_state = player->state; player->state = PS_SHUTDOWN; if (prev_state == PS_PLAYING) empth_rwlock_unlock(shutdown_lock); pr_id(player, C_EXIT, "so long...\n"); player_delete(player); empth_exit(); /*NOTREACHED*/ }
static int play_cmd(void) { struct player *other; natid cnum; struct natstr *natp; char **ap; char buf[128]; ap = player->argp; if (*++ap) { strncpy(player->userid, *ap, sizeof(player->userid) - 1); player->userid[sizeof(player->userid) - 1] = '\0'; player->authenticated = 0; } if (*++ap) { if (natbyname(*ap, &cnum) < 0) { pr_id(player, C_CMDERR, "country %s does not exist\n", *ap); return RET_FAIL; } } if (*++ap) { if (!natpass(cnum, *ap)) { pr_id(player, C_CMDERR, "password bad, logging entry\n"); logerror("%s tried country #%d with %s", praddr(player), cnum, *ap); return RET_FAIL; } player->cnum = cnum; player->authenticated = 1; } if (!may_play()) return RET_FAIL; other = getplayer(player->cnum); if (other) { natp = getnatp(player->cnum); if (natp->nat_stat != STAT_VIS) { pr_id(player, C_EXIT, "country in use by %s\n", praddr(other)); } else { pr_id(player, C_EXIT, "country in use\n"); } return RET_FAIL; } snprintf(buf, sizeof(buf), "Play#%d", player->cnum); logerror("%s logged in as country #%d", praddr(player), player->cnum); journal_login(); empth_set_name(empth_self(), buf); pr_id(player, C_INIT, "%d\n", CLIENTPROTO); empth_rwlock_rdlock(shutdown_lock); player->state = PS_PLAYING; player_main(player); journal_logout(); logerror("%s logged out, country #%d", praddr(player), player->cnum); if (!io_eof(player->iop) && !io_error(player->iop)) io_set_eof(player->iop); return RET_OK; }
static int options_cmd(void) { /* * The option mechanism allows arbitrary string values, but so far * all options are flags in struct player. Should be easy to * generalize if needed. */ struct logoptstr { char *name; int val; }; static struct logoptstr login_opts[] = { { "utf-8", PF_UTF8 }, { NULL, 0 } }; char **ap; char *p; int opt; unsigned i; if (!player->argp[1]) { for (i = 0; login_opts[i].name; ++i) pr_id(player, C_DATA, "%s=%d\n", login_opts[i].name, (player->flags & login_opts[i].val) != 0); pr_id(player, C_CMDOK, "\n"); return RET_OK; } for (ap = player->argp+1; *ap; ++ap) { p = strchr(*ap, '='); if (p) *p++ = 0; opt = stmtch(*ap, login_opts, offsetof(struct logoptstr, name), sizeof(struct logoptstr)); if (opt < 0) { pr_id(player, C_BADCMD, "Option %s not found\n", *ap); return RET_FAIL; } if (!p || atoi(p)) player->flags |= login_opts[opt].val; else player->flags &= ~login_opts[opt].val; } pr_id(player, C_CMDOK, "Accepted\n"); return RET_OK; }
static int coun_cmd(void) { natid cnum; if (!player->argp[1]) return RET_SYN; if (natbyname(player->argp[1], &cnum) < 0) { pr_id(player, C_CMDERR, "country %s does not exist\n", player->argp[1]); return RET_FAIL; } player->cnum = cnum; player->authenticated = 0; pr_id(player, C_CMDOK, "country name %s\n", player->argp[1]); return 0; }
static int user_cmd(void) { if (!player->argp[1]) return RET_SYN; strncpy(player->userid, player->argp[1], sizeof(player->userid) - 1); player->userid[sizeof(player->userid) - 1] = '\0'; pr_id(player, C_CMDOK, "hello %s\n", player->userid); return RET_OK; }
static int pass_cmd(void) { if (!player->argp[1]) return RET_SYN; if (player->cnum == NATID_BAD) { pr_id(player, C_CMDERR, "need country first\n"); return RET_FAIL; } if (!natpass(player->cnum, player->argp[1])) { pr_id(player, C_CMDERR, "password bad, logging entry\n"); logerror("%s tried country #%d with %s", praddr(player), player->cnum, player->argp[1]); return RET_FAIL; } player->authenticated = 1; pr_id(player, C_CMDOK, "password ok\n"); logerror("%s using country #%d", praddr(player), player->cnum); return RET_OK; }
static int kill_cmd(void) { struct player *other; if (!may_play()) return RET_FAIL; other = getplayer(player->cnum); if (!other) { pr_id(player, C_EXIT, "country not in use\n"); return RET_FAIL; } logerror("%s killed country #%d", praddr(player), player->cnum); pr_flash(other, "Disconnected by %s\n", praddr(player)); io_set_eof(other->iop); other->aborted = 1; other->may_sleep = PLAYER_SLEEP_NEVER; empth_wakeup(other->proc); pr_id(player, C_EXIT, "terminated %s's connection\n", praddr(other)); return RET_OK; }
static int may_play(void) { struct natstr *np; if (player->cnum == NATID_BAD || !player->authenticated) { pr_id(player, C_CMDERR, "need country and password\n"); return 0; } /* TODO strstr() cheesy, compare IP against IP/BITS ... */ np = getnatp(player->cnum); if (np->nat_stat == STAT_GOD && *privip && !strstr(privip, player->hostaddr)) { logerror("Deity login from untrusted host attempted by %s", praddr(player)); logerror("To allow this, add %s to econfig key privip", player->hostaddr); pr_id(player, C_EXIT, "Deity login not allowed from this IP!" " See log for help on how to allow it.\n"); return 0; } return 1; }
/* * Prompt for a line of non-command, UTF-8 input. * Send C_FLUSH prompt @prompt to the current player. * Read a line of input into @buf[@size], replacing funny characters by * '?'. The result is UTF-8. * This may block for input, yielding the processor. Flush buffered * output when blocking, to make sure player sees the prompt. * Return number of bytes in @buf[], not counting the terminating 0, * or -1 on error. */ int uprmptrd(char *prompt, char *buf, int size) { int r; if (CANT_HAPPEN(!prompt)) prompt = "? "; pr_id(player, C_FLUSH, "%s\n", prompt); if ((r = recvclient(buf, size)) < 0) return r; time(&player->curup); if (*buf == 0) return 1; if (player->flags & PF_UTF8) return copy_utf8_no_funny(buf, buf); return copy_ascii_no_funny(buf, buf); }
static int client_cmd(void) { int i, sz; char *p, *end; if (!player->argp[1]) return RET_SYN; p = player->client; end = player->client + sizeof(player->client) - 1; for (i = 1; player->argp[i]; ++i) { if (i > 1) *p++ = ' '; sz = strlen(player->argp[i]); sz = MIN(sz, end - p); memcpy(p, player->argp[i], sz); p += sz; } *p = 0; pr_id(player, C_CMDOK, "talking to %s\n", player->client); return RET_OK; }
/* * Send a command prompt to the current player. */ void prprompt(int min, int btu) { pr_id(player, C_PROMPT, "%d %d\n", min, btu); }
/* * Send script execute request @file to the current player. * @file is UTF-8, but non-ASCII characters can occur only if the * player sent them. Therefore, it is also user text. */ void prexec(char *file) { pr_id(player, C_EXECUTE, "%s\n", file); }
/* * Send redirection request @redir to the current player. * @redir is UTF-8, but non-ASCII characters can occur only if the * player sent them. Therefore, it is also user text. */ void prredir(char *redir) { pr_id(player, *redir == '>' ? C_REDIR : C_PIPE, "%s\n", redir); }