#include <signal.h>
#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "config.h"
#include "sys_proto.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);
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) {
write(p->fd, DISCONNECT_MSG, strlen (DISCONNECT_MSG));
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(*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) {
write(p->fd, connect_fail, strlen(connect_fail));
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;
write(oldp->fd, TRANSFER_MSG1, strlen(TRANSFER_MSG1));
remove_player(oldp);
write(p->fd, TRANSFER_MSG2, strlen(TRANSFER_MSG2));
write(p->fd, CONNECT_MSG, strlen(CONNECT_MSG));
} else {
writelog();
fprintf(stderr, "Player connected %s(#%d) on descriptor %d\n",
user, player, p->fd);
p->connected = 1;
p->id = player;
write(p->fd, CONNECT_MSG, strlen(CONNECT_MSG));
}
} else if (!strncmp(command, "cr", 2) && !registration) {
player = create_player (user, password);
if (player == NOTHING) {
write(p->fd, create_fail, strlen(create_fail));
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;
write (p->fd, CONNECT_MSG, strlen (CONNECT_MSG));
}
} else {
write(p->fd, welcome, strlen(welcome));
}
}
void
parse_connect (char *msg, char **command, char **user, char **pass)
{
while (*msg && isascii(*msg) && isspace (*msg)) /* skip whitespace */
msg++;
*command = msg;
while (*msg && isascii(*msg) && !isspace (*msg)) /* skip command */
msg++;
if (*msg) {
*msg++ = '\0'; /* terminate cmd */
}
while (*msg && isascii(*msg) && isspace (*msg)) /* skip whitespace */
msg++;
*user = msg;
while (*msg && isascii(*msg) && !isspace (*msg)) /* skip user */
msg++;
if (*msg) {
*msg++ = '\0'; /* terminate user */
}
while (*msg && isascii(*msg) && isspace (*msg)) /* skip whitespace */
msg++;
*pass = msg;
while (*msg && isascii(*msg) && !isspace (*msg)) /* skip password */
msg++;
*msg = '\0'; /* terminate pass */
}
int
start_programming(Playerid player, GENPTR *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, "w"))) {
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, "r"))) {
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)
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;
}
}
}