#include "cool.h"
#include "string.h"
#include "netio.h"
#include "buf.h"
#include "netio_private.h"
#include "servers.h"
static const char *create_fail =
"Either there is already a player with that name, or that name is illegal.\r\n";
static const char *connect_fail =
"Either that player does not exist, or has a different password.\r\n";
static void check_connect (Player * p, char *msg);
static void stop_programming (Player * p);
static struct timeval msec2timeval (int msec);
static void player_command (Player * p, char *command);
void tell (Playerid player, const char *msg)
{
Player *p;
String *str;
for (p = players; p; p = p->next) {
if (p->connected && p->id == player) {
str = string_cpy (msg);
str = string_cat (str, "\r\n");
buf_add (&p->output, str);
break;
}
}
}
void boot (Playerid who)
{
Player *p;
for (p = players; p; p = p->next) {
if (p->connected && p->id == who) {
send (p->fd, DISCONNECT_MSG, strlen (DISCONNECT_MSG), 0);
disconnect_player (p->id);
remove_player (p);
break;
}
}
}
void player_command (Player * p, char *command)
{
if (!p->connected) {
check_connect (p, command);
} else if (p->isprogramming) {
if (!strcmp (command, ".")) {
stop_programming (p);
} else {
fprintf (p->progfile, "%s\n", command);
}
} else {
while (isspace ((int)*command)) {
command++;
}
p->parsing = 1;
parse (p->id, command);
}
}
void parse_done (Playerid player)
{
Player *p;
for (p = players; p; p = p->next) {
if (p->id == player) {
p->parsing = 0;
}
}
}
static Player *find_connect (Playerid player, Player * not)
{
Player *p;
for (p = players; p; p = p->next) {
if (p != not && p->connected && p->id == player) {
return p;
}
}
return 0;
}
static void check_connect (Player * p, char *msg)
{
char *command, *user, *password;
Playerid player;
Player *oldp;
parse_connect (msg, &command, &user, &password);
if (!strncmp (command, "co", 2)) {
player = connect_player (user, password);
if (player == NOTHING) {
send (p->fd, connect_fail, strlen (connect_fail), 0);
writelog ();
fprintf (stderr, "Player failed connect %s on descriptor %d\n",
user, p->fd);
} else if ((oldp = find_connect (player, p))) {
writelog ();
fprintf (stderr, "Player %s(#%d) transferred from fd %d to fd %d\n",
user, player, oldp->fd, p->fd);
p->connected = 1;
p->id = player;
send (oldp->fd, TRANSFER_MSG1, strlen (TRANSFER_MSG1), 0);
remove_player (oldp);
send (p->fd, TRANSFER_MSG2, strlen (TRANSFER_MSG2), 0);
send (p->fd, CONNECT_MSG, strlen (CONNECT_MSG), 0);
} else {
writelog ();
fprintf (stderr, "Player connected %s(#%d) on descriptor %d\n",
user, player, p->fd);
p->connected = 1;
p->id = player;
send (p->fd, CONNECT_MSG, strlen (CONNECT_MSG), 0);
}
} else if (!strncmp (command, "cr", 2) && !registration) {
player = create_player (user, password);
if (player == NOTHING) {
send (p->fd, create_fail, strlen (create_fail), 0);
writelog ();
fprintf (stderr, "Player failed create %s on descriptor %d\n",
user, p->fd);
} else {
writelog ();
fprintf (stderr, "Player created: %s(#%d) on descriptor %d\n",
user, player, p->fd);
p->connected = 1;
p->id = player;
send (p->fd, CONNECT_MSG, strlen (CONNECT_MSG), 0);
}
} else {
buf_add (&(p->output), string_cpy (welcome));
}
}
void parse_connect (char *msg, char **command, char **user, char **pass)
{
while (*msg && isascii (*msg) && isspace ((int)*msg)) /* skip whitespace */
msg++;
*command = msg;
while (*msg && isascii (*msg) && !isspace ((int)*msg)) /* skip command */
msg++;
if (*msg) {
*msg++ = '\0'; /* terminate cmd */
}
while (*msg && isascii (*msg) && isspace ((int)*msg)) /* skip whitespace */
msg++;
*user = msg;
while (*msg && isascii (*msg) && !isspace ((int)*msg)) /* skip user */
msg++;
if (*msg) {
*msg++ = '\0'; /* terminate user */
}
while (*msg && isascii (*msg) && isspace ((int)*msg)) /* skip whitespace */
msg++;
*pass = msg;
while (*msg && isascii (*msg) && !isspace ((int)*msg)) /* skip password */
msg++;
*msg = '\0'; /* terminate pass */
}
int start_programming (Playerid player, void **progwhat)
{
Player *p;
for (p = players; p; p = p->next) {
if (p->id == player) {
break;
}
}
if (!p) {
return -1;
}
sprintf (p->progfilename, "%s/%s_%d", PROGDIR, serv_id2name (0), player);
if (!(p->progfile = fopen (p->progfilename, "wb"))) {
writelog ();
fprintf (stderr, "Couldn't open programming temp file ");
perror (p->progfilename);
p->progfilename[0] = '\0';
return -2;
} else {
p->isprogramming = 1;
p->progwhat = (void *) progwhat;
return 0;
}
}
static Playerid progr; /* programmer */
static void stop_programming (Player * p)
{
fclose (p->progfile);
p->isprogramming = 0;
if (!(p->progfile = fopen (p->progfilename, "rb"))) {
writelog ();
perror (p->progfilename);
} else {
progr = p->id;
do_compile (p->id, p->progfile, p->progwhat);
fclose (p->progfile);
unlink (p->progfilename);
}
tell (p->id, "Exiting programming mode.");
p->progfilename[0] = '\0';
p->progfile = 0;
}
#define MSEC(T) (T.tv_sec * 1000 + T.tv_usec / 1000)
static struct timeval msec2timeval (int msec)
{
struct timeval r;
r.tv_sec = msec / 1000;
r.tv_usec = (msec % 1000) * 1000;
return r;
}
void queue_player_commands (struct timeval cur_time, struct timeval *timeout)
{
Player *p;
int msec_since_last;
static struct timeval last = { 0, 0 };
struct timeval new;
msec_since_last = MSEC (cur_time) - MSEC (last);
last = cur_time;
for (p = players; p; p = p->next) {
p->quota += msec_since_last;
if (p->quota > MAX_CMDS * MSEC_PER_CMD) {
p->quota = MAX_CMDS * MSEC_PER_CMD;
}
if (p->input.head && p->quota >= 0 && !p->parsing) {
player_command (p, p->input.head->str->str);
buf_delhead (&p->input);
if (!p->isprogramming) {
p->quota -= MSEC_PER_CMD;
}
}
if (p->input.head && p->quota < 0) {
/* return when quota is positive */
new = msec2timeval (-p->quota);
*timeout = (timercmp (&new, timeout, <))? new : *timeout;
}
}
}