00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <config.h>
00037
00038 #include "com.h"
00039 #include "empio.h"
00040 #include "empthread.h"
00041 #include "file.h"
00042 #include "match.h"
00043 #include "misc.h"
00044 #include "nat.h"
00045 #include "nsc.h"
00046 #include "optlist.h"
00047 #include "player.h"
00048 #include "proto.h"
00049 #include "prototypes.h"
00050
00051 static int client_cmd(void);
00052 static int coun_cmd(void);
00053 static int kill_cmd(void);
00054 static int options_cmd(void);
00055 static int pass_cmd(void);
00056 static int play_cmd(void);
00057 static int quit_cmd(void);
00058 static int sanc_cmd(void);
00059 static int user_cmd(void);
00060
00061 static struct cmndstr login_coms[] = {
00062 {"client client-id...", 0, client_cmd, 0, 0},
00063 {"coun country", 0, coun_cmd, 0, 0},
00064 {"kill", 0, kill_cmd, 0, 0},
00065 {"options option=value...", 0, options_cmd, 0, 0},
00066 {"pass password", 0, pass_cmd, 0, 0},
00067 {"play [user [country [password]]]", 0, play_cmd, 0, 0},
00068 {"quit", 0, quit_cmd, 0, 0},
00069 {"sanc", 0, sanc_cmd, 0, 0},
00070 {"user name", 0, user_cmd, 0, 0},
00071 {0, 0, 0, 0, 0}
00072 };
00073
00074
00075 void
00076 player_login(void *ud)
00077 {
00078 char buf[128];
00079 char space[128];
00080 int ac;
00081 int cmd;
00082
00083 player->proc = empth_self();
00084
00085 pr_id(player, C_INIT, "Empire server ready\n");
00086
00087 while (!io_eof(player->iop) && !io_error(player->iop)
00088 && player->state != PS_SHUTDOWN) {
00089 io_output(player->iop, IO_WAIT);
00090 if (io_gets(player->iop, buf, sizeof(buf)) < 0) {
00091 io_input(player->iop, IO_WAIT);
00092 continue;
00093 }
00094 ac = parse(buf, space, player->argp, NULL, NULL, NULL);
00095 cmd = comtch(player->argp[0], login_coms, 0);
00096 if (cmd < 0) {
00097 pr_id(player, C_BADCMD, "Command %s not found\n", player->argp[0]);
00098 continue;
00099 }
00100 switch (login_coms[cmd].c_addr()) {
00101 case RET_OK:
00102 break;
00103 case RET_FAIL:
00104 break;
00105 case RET_SYN:
00106 pr_id(player, C_BADCMD, "Usage %s\n", login_coms[cmd].c_form);
00107 break;
00108 default:
00109 break;
00110 }
00111 }
00112 player->state = PS_SHUTDOWN;
00113 if (!io_eof(player->iop)) {
00114 pr_id(player, C_EXIT, "so long...\n");
00115 io_noblocking(player->iop, 0);
00116 while (io_output(player->iop, IO_WAIT) > 0) ;
00117 }
00118 player_delete(player);
00119 empth_exit();
00120
00121 }
00122
00123 static int
00124 client_cmd(void)
00125 {
00126 int i, sz;
00127 char *p, *end;
00128
00129 if (!player->argp[1])
00130 return RET_SYN;
00131
00132 p = player->client;
00133 end = player->client + sizeof(player->client) - 1;
00134 for (i = 1; player->argp[i]; ++i) {
00135 if (i > 1)
00136 *p++ = ' ';
00137 sz = strlen(player->argp[i]);
00138 sz = MIN(sz, end - p);
00139 memcpy(p, player->argp[i], sz);
00140 p += sz;
00141 }
00142 *p = 0;
00143 pr_id(player, C_CMDOK, "talking to %s\n", player->client);
00144 return RET_OK;
00145 }
00146
00147 static int
00148 user_cmd(void)
00149 {
00150 if (!player->argp[1])
00151 return RET_SYN;
00152 strncpy(player->userid, player->argp[1], sizeof(player->userid) - 1);
00153 player->userid[sizeof(player->userid) - 1] = '\0';
00154 pr_id(player, C_CMDOK, "hello %s\n", player->userid);
00155 return RET_OK;
00156 }
00157
00158 static int
00159 sanc_cmd(void)
00160 {
00161 struct nstr_item ni;
00162 struct natstr nat;
00163 int first = 1;
00164
00165 if (!opt_BLITZ) {
00166 pr_id(player, C_BADCMD, "Command %s not found\n", player->argp[0]);
00167 return RET_FAIL;
00168 }
00169
00170 snxtitem_all(&ni, EF_NATION);
00171 while (nxtitem(&ni, &nat)) {
00172 if (nat.nat_stat != STAT_SANCT)
00173 continue;
00174 if (first) {
00175 pr_id(player, C_DATA,
00176 "The following countries are still in sanctuary:\n");
00177 first = 0;
00178 }
00179 pr_id(player, C_DATA, "%s\n", nat.nat_cnam);
00180 }
00181 if (first)
00182 pr_id(player, C_CMDOK, "There are no countries in sanctuary\n");
00183 else
00184 pr_id(player, C_CMDOK, "\n");
00185 return RET_OK;
00186 }
00187
00188 static int
00189 coun_cmd(void)
00190 {
00191 natid cnum;
00192
00193 if (!player->argp[1])
00194 return RET_SYN;
00195 if (natbyname(player->argp[1], &cnum) < 0) {
00196 pr_id(player, C_CMDERR, "country %s does not exist\n", player->argp[1]);
00197 return RET_FAIL;
00198 }
00199 player->cnum = cnum;
00200 player->authenticated = 0;
00201 pr_id(player, C_CMDOK, "country name %s\n", player->argp[1]);
00202 return 0;
00203 }
00204
00205 static int
00206 pass_cmd(void)
00207 {
00208 if (!player->argp[1])
00209 return RET_SYN;
00210 if (player->cnum == 255) {
00211 pr_id(player, C_CMDERR, "need country first\n");
00212 return RET_FAIL;
00213 }
00214 if (!natpass(player->cnum, player->argp[1])) {
00215 pr_id(player, C_CMDERR, "password bad, logging entry\n");
00216 logerror("%s tried country #%d with %s",
00217 praddr(player), player->cnum, player->argp[1]);
00218 return RET_FAIL;
00219 }
00220 player->authenticated = 1;
00221 pr_id(player, C_CMDOK, "password ok\n");
00222 logerror("%s using country #%d", praddr(player), player->cnum);
00223 return RET_OK;
00224 }
00225
00226 static int
00227 options_cmd(void)
00228 {
00229
00230
00231
00232
00233
00234 struct logoptstr {
00235 char *name;
00236 int val;
00237 };
00238 static struct logoptstr login_opts[] = {
00239 { "utf-8", PF_UTF8 },
00240 { NULL, 0 }
00241 };
00242 char **ap;
00243 char *p;
00244 int opt;
00245 unsigned i;
00246
00247 if (!player->argp[1]) {
00248 for (i = 0; login_opts[i].name; ++i)
00249 pr_id(player, C_DATA, "%s=%d\n",
00250 login_opts[i].name,
00251 (player->flags & login_opts[i].val) != 0);
00252 pr_id(player, C_CMDOK, "\n");
00253 return RET_OK;
00254 }
00255
00256 for (ap = player->argp+1; *ap; ++ap) {
00257 p = strchr(*ap, '=');
00258 if (p)
00259 *p++ = 0;
00260 opt = stmtch(*ap, login_opts,
00261 offsetof(struct logoptstr, name),
00262 sizeof(struct logoptstr));
00263 if (opt < 0) {
00264 pr_id(player, C_BADCMD, "Option %s not found\n", *ap);
00265 return RET_FAIL;
00266 }
00267 if (!p || atoi(p))
00268 player->flags |= login_opts[opt].val;
00269 else
00270 player->flags &= ~login_opts[opt].val;
00271 }
00272
00273 pr_id(player, C_CMDOK, "Accepted\n");
00274
00275 return RET_OK;
00276 }
00277
00278 static int
00279 may_play(void)
00280 {
00281 struct natstr *np;
00282
00283 if (player->cnum == 255 || !player->authenticated) {
00284 pr_id(player, C_CMDERR, "need country and password\n");
00285 return 0;
00286 }
00287
00288 np = getnatp(player->cnum);
00289 if (np->nat_stat == STAT_GOD && *privip
00290 && !strstr(privip, player->hostaddr)) {
00291 logerror("Deity login from untrusted host attempted by %s",
00292 praddr(player));
00293 logerror("To allow this, add %s to econfig key privip",
00294 player->hostaddr);
00295 pr_id(player, C_EXIT,
00296 "Deity login not allowed from this IP!"
00297 " See log for help on how to allow it.\n");
00298 return 0;
00299 }
00300 return 1;
00301 }
00302
00303 static int
00304 play_cmd(void)
00305 {
00306 struct player *other;
00307 natid cnum;
00308 struct natstr *natp;
00309 char **ap;
00310
00311 ap = player->argp;
00312 if (*++ap) {
00313 strncpy(player->userid, *ap, sizeof(player->userid) - 1);
00314 player->userid[sizeof(player->userid) - 1] = '\0';
00315 player->authenticated = 0;
00316 }
00317 if (*++ap) {
00318 if (natbyname(*ap, &cnum) < 0) {
00319 pr_id(player, C_CMDERR, "country %s does not exist\n", *ap);
00320 return RET_FAIL;
00321 }
00322 }
00323 if (*++ap) {
00324 if (!natpass(cnum, *ap)) {
00325 pr_id(player, C_CMDERR, "password bad, logging entry\n");
00326 logerror("%s tried country #%d with %s",
00327 praddr(player), cnum, *ap);
00328 return RET_FAIL;
00329 }
00330 player->cnum = cnum;
00331 player->authenticated = 1;
00332 }
00333 if (!may_play())
00334 return RET_FAIL;
00335 other = getplayer((natid)player->cnum);
00336 if (other) {
00337 natp = getnatp(player->cnum);
00338 if (natp->nat_stat != STAT_VIS) {
00339 pr_id(player, C_EXIT, "country in use by %s\n", praddr(other));
00340 } else {
00341 pr_id(player, C_EXIT, "country in use\n");
00342 }
00343 return RET_FAIL;
00344 }
00345 logerror("%s logged in as country #%d", praddr(player), player->cnum);
00346 pr_id(player, C_INIT, "%d\n", CLIENTPROTO);
00347 player_main(player);
00348 logerror("%s logged out, country #%d", praddr(player), player->cnum);
00349 player->state = PS_SHUTDOWN;
00350 return RET_OK;
00351 }
00352
00353 static int
00354 kill_cmd(void)
00355 {
00356 struct player *other;
00357
00358 if (!may_play())
00359 return RET_FAIL;
00360 other = getplayer(player->cnum);
00361 if (!other) {
00362 pr_id(player, C_EXIT, "country not in use\n");
00363 return RET_FAIL;
00364 }
00365 logerror("%s killed country #%d", praddr(player), player->cnum);
00366 io_shutdown(other->iop, IO_READ | IO_WRITE);
00367 pr_id(player, C_EXIT, "closed socket of offending job\n");
00368 return RET_OK;
00369 }
00370
00371 static int
00372 quit_cmd(void)
00373 {
00374 pr_id(player, C_EXIT, "so long\n");
00375 io_shutdown(player->iop, IO_READ);
00376 return RET_OK;
00377 }