/* xenix.c */
#include "copyright.h"
/* Hacked by Lawrence Foard to make a Xenix interface for TinyMUD */
/* #include <stdio.h> */
#include <prototypes.h>
#include <sys/signal.h>
#include <stdio.h>
#include <sys_2.3/types.h>
#include <sys/file.h>
#include <sys/timeb.h>
#include <sys/times.h>
/* #include <signal.h> */
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/errno.h>
#include <ctype.h>
#include "db.h"
#include "interface.h"
#include "config.h"
#include "fifo.h"
char ccom[1204];
dbref cplr;
extern int errno;
int shutdown_flag = 0;
static const char *connect_fail = "Either that player does not exist, or has a different password.\n";
static const char *create_fail = "Either there is already a player with that name, or that name is illegal.\n";
static const char *flushed_message = "<Output Flushed>\n";
static const char *shutdown_message = "Going down - Bye\n";
/* size of user input and output buffers */
#define IBUF 1024
#define OBUF 4096
/* how many I/O descripters? */
#define MAXDES 32
/* max prefix+suffix length */
#define MAXSUF 100
void set_signals();
int bailout();
void shovechars();
void make_nonblocking();
void welcome_user();
void check_connect();
void parse_connect();
void close_sockets();
void dump_users();
void announce_connect();
void announce_disconnect();
void process_commands();
struct descriptor_data {
int descriptor;
int connected;
dbref player;
char output_prefix[MAXSUF];
char output_suffix[MAXSUF];
long connected_at;
long last_time;
FIFO in;
FIFO out;
};
struct descriptor_data des[MAXDES];
int topdes = 0;
#ifndef BOOLEXP_DEBUGGING
void main(argc, argv)
int argc;
char **argv;
{
char buff[100];
FILE *fi;
int a;
if (argc < 3) {
fprintf(stderr, "Usage: %s infile dumpfile [port]\n", *argv);
exit(1);
}
if (init_game(argv[1], argv[2]) < 0) {
fprintf(stderr, "Couldn't load %s!\n", argv[1]);
exit(2);
}
set_signals();
/* go do it */
if (!(fi = fopen("ports.dat", "r"))) {
fprintf(stderr, "ports.dat was not found\n");
exit(1);
}
while (fgets(buff, 99, fi)) {
int fd;
/* get rid of \n */
if (*buff)
buff[strlen(buff) - 1] = 0;
if ((fd = open(buff, O_RDWR)) == -1)
fprintf(stderr, "Warning-Couldn't open I/O device %s\n", buff);
else {
initializesock(&des[topdes++], fd);
fprintf(stderr, "Inited: %s\n", buff);
}
}
fclose(fi);
shovechars();
close_sockets();
dump_database();
exit(0);
}
#endif /* BOOLEXP_DEBUGGING */
void set_signals()
{
int dump_status(void);
/* we don't care about SIGPIPE, we notice it in select() and write() */
/* signal (SIGPIPE, SIG_IGN); */
/* standard termination signals */
signal(SIGINT, bailout);
signal(SIGTERM, bailout);
/* catch these because we might as well */
signal(SIGQUIT, bailout);
signal(SIGILL, bailout);
signal(SIGTRAP, bailout);
signal(SIGIOT, bailout);
signal(SIGEMT, bailout);
signal(SIGFPE, bailout);
signal(SIGBUS, bailout);
signal(SIGSEGV, bailout);
signal(SIGSYS, bailout);
signal(SIGTERM, bailout);
/* signal (SIGXCPU, bailout); */
/* signal (SIGXFSZ, bailout); */
/* signal (SIGVTALRM, bailout); */
signal(SIGUSR2, bailout);
/* status dumper (predates "WHO" command) */
signal(SIGUSR1, dump_status);
}
/* queue write */
void queue_write(d, buf, size)
struct descriptor_data *d;
char *buf;
int size;
{
fi_write(&d->out, buf, size);
}
void queue_string(d, str)
struct descriptor_data *d;
char *str;
{
fi_write(&d->out, str, strlen(str));
}
void raw_notify(player, msg)
dbref player;
const char *msg;
{
struct descriptor_data *d;
int a;
for (a = 0; a < topdes; a++) {
d = &des[a];
if (d->connected && d->player == player) {
queue_string(d, msg);
queue_write(d, "\n", 1);
}
}
}
/* Everything happens here.... */
void shovechars()
{
struct descriptor_data *d, *dnext;
int a = 0, b;
while (!shutdown_flag) {
/*
* The manual says Xenix has Select and the compiler claims it doesn't so
* I gave up and kludged it instead. If you can find the missing select
* call it would probably work alots better than this.
*/
/* wait 1 tenth of a second then poll the streams */
if (!test_top())
nap(100);
else
do_top() && do_top && do_top();
if (shutdown_flag)
break;
for (b = 0; b < topdes; b++) {
d = &des[b];
/* only check non connected streams every tenth poll */
if (!d->connected && a != 10)
continue;
if (!process_input(d)) {
fprintf(stderr, "pipe input error %d err %d\n", d->descriptor, errno);
/*
* shutdownsock(d); continue;
*/
}
if (!process_output(d)) {
fprintf(stderr, "pipe output error %d\n", errno);
/*
* shutdownsock(d); continue;
*/
}
}
if (a++ == 10)
a = 0;
process_commands();
dispatch();
}
}
void shutdownsock(d)
struct descriptor_data *d;
{
int dd;
if (d->connected) {
fprintf(stderr, "DISCONNECT descriptor %d player %s(%d)\n",
d->descriptor, db[d->player].name, d->player);
announce_disconnect(d->player);
} else {
fprintf(stderr, "DISCONNECT descriptor %d never connected\n",
d->descriptor);
}
fi_close(&d->in);
fi_close(&d->out);
initializesock(d, d->descriptor); /* restart stream */
}
initializesock(d, s)
struct descriptor_data *d;
int s;
{
d->descriptor = s;
d->connected = 0;
make_nonblocking(s);
*d->output_prefix = 0;
*d->output_suffix = 0;
d->last_time = 0;
fi_open(&d->in, MAX_INPUT);
fi_open(&d->out, MAX_OUTPUT);
welcome_user(d);
}
int process_output(d)
struct descriptor_data *d;
{
int cnt, hope;
char *buff;
if (!fi_readok(&d->out))
return (1);
/* write as much as possible */
if (!(hope = fi_rread(&d->out, &buff)))
return (1);
cnt = write(d->descriptor, buff, hope);
if (cnt < 0) {
/* flush fifo */
fi_flush(&d->out);
return (0);
}
fi_munch(&d->out, cnt);
/* if everything was written try to write some more */
return ((cnt == hope) ? process_output(d) : 1);
}
void make_nonblocking(s)
int s;
{
if (fcntl(s, F_SETFL, FNDELAY) == -1) {
perror("make_nonblocking: fcntl");
panic("FNDELAY fcntl failed");
}
}
void welcome_user(d)
struct descriptor_data *d;
{
queue_string(d, WELCOME_MESSAGE);
}
int process_input(d)
struct descriptor_data *d;
{
char buf[1024];
int got;
/* make sure we can accept more input first */
if (!fi_writeok(&d->in))
return (1);
got = read(d->descriptor, buf, sizeof buf);
if (got <= 0) {
/* if interrupted system call ignore error */
if ((errno == 5) || (errno == EINTR))
return 1;
else
return 0;
}
fi_write(&d->in, buf, got);
}
void process_commands()
{
int nprocessed;
struct descriptor_data *d, *dnext;
struct text_block *t;
char buff[1024];
int a;
for (a = 0; a < topdes; a++) {
d = &des[a];
if (fi_readok(&d->in) &&fi_gets(&d->in, buff, 1024)
&&!do_command(d, buff))
shutdownsock(d);
}
}
int do_command(d, command)
struct descriptor_data *d;
char *command;
{
if (!*command)
return (1);
if (!strcmp(command, QUIT_COMMAND)) {
return 0;
} else if (!strcmp(command, WHO_COMMAND)) {
if (d->output_prefix) {
queue_string(d, d->output_prefix);
queue_write(d, "\n", 1);
}
dump_users(d);
if (d->output_suffix) {
queue_string(d, d->output_suffix);
queue_write(d, "\n", 1);
}
} else if (!strncmp(command, PREFIX_COMMAND, strlen(PREFIX_COMMAND))) {
strcpy(d->output_prefix, command + strlen(PREFIX_COMMAND));
} else if (!strncmp(command, SUFFIX_COMMAND, strlen(SUFFIX_COMMAND))) {
strcpy(d->output_suffix, command + strlen(SUFFIX_COMMAND));
} else {
if (d->connected) {
if (*d->output_prefix) {
queue_string(d, d->output_prefix);
queue_write(d, "\n", 1);
}
strcpy(ccom, command);
cplr = d->player;
process_command(d->player, command);
if (*d->output_suffix) {
queue_string(d, d->output_suffix);
queue_write(d, "\n", 1);
}
} else {
check_connect(d, command);
}
}
return 1;
}
void check_connect(d, msg)
struct descriptor_data *d;
const char *msg;
{
char command[MAX_COMMAND_LEN];
char user[MAX_COMMAND_LEN];
char password[MAX_COMMAND_LEN];
dbref player;
parse_connect(msg, command, user, password);
if (!strncmp(command, "co", 2)) {
player = connect_player(user, password);
if (player == NOTHING) {
queue_string(d, connect_fail);
fprintf(stderr, "FAILED CONNECT %s on descriptor %d\n",
user, d->descriptor);
} else {
fprintf(stderr, "CONNECTED %s(%d) on descriptor %d\n",
db[player].name, player, d->descriptor);
d->connected = 1;
d->connected_at = time(0);
d->player = player;
do_look_around(player);
announce_connect(player);
}
} else if (!strncmp(command, "cr", 2)) {
player = create_player(user, password);
if (player == NOTHING) {
queue_string(d, create_fail);
fprintf(stderr, "FAILED CREATE %s on descriptor %d\n",
user, d->descriptor);
} else {
fprintf(stderr, "CREATED %s(%d) on descriptor %d\n",
db[player].name, player, d->descriptor);
d->connected = 1;
d->connected_at = time(0);
d->player = player;
do_look_around(player);
announce_connect(player);
}
} else {
welcome_user(d);
}
}
void parse_connect(msg, command, user, pass)
const char *msg;
char *command;
char *user;
char *pass;
{
char *p;
while (*msg && isascii(*msg) && isspace(*msg))
msg++;
p = command;
while (*msg && isascii(*msg) && !isspace(*msg))
*p++ = *msg++;
*p = '\0';
while (*msg && isascii(*msg) && isspace(*msg))
msg++;
p = user;
while (*msg && isascii(*msg) && !isspace(*msg))
*p++ = *msg++;
*p = '\0';
while (*msg && isascii(*msg) && isspace(*msg))
msg++;
p = pass;
while (*msg && isascii(*msg) && !isspace(*msg))
*p++ = *msg++;
*p = '\0';
}
void close_sockets()
{
struct descriptor_data *d, *dnext;
int a;
for (a = 0; a < topdes; a++) {
d = &des[a];
write(d->descriptor, shutdown_message, strlen(shutdown_message));
close(d->descriptor);
}
}
void emergency_shutdown()
{
close_sockets();
}
void boot_off(player)
dbref player;
{
struct descriptor_data *d;
int a;
for (a = 0; a < topdes; a++) {
d = &des[a];
if (d->connected && d->player == player)
shutdownsock(d);
}
}
int bailout(sig, code, scp)
int sig;
int code;
struct sigcontext *scp;
{
char message[1024];
sprintf(message, "BAILOUT: caught signal %d code %d", sig, code);
panic(message);
_exit(7);
return 0;
}
int dump_status()
{
/*
* struct descriptor_data *d; long now;
*
* (void) time (&now); fprintf (stderr, "STATUS REPORT:\n"); for (d =
* descriptor_list; d; d = d->next) { if (d->connected) { fprintf (stderr,
* "PLAYING descriptor %d player %s(%d)", d->descriptor,
* db[d->player].name, d->player);
*
* if (d->last_time) fprintf (stderr, " idle %d seconds\n", now -
* d->last_time); else fprintf (stderr, " never used\n"); } else { fprintf
* (stderr, "CONNECTING descriptor %d", d->descriptor); if (d->last_time)
* fprintf (stderr, " idle %d seconds\n", now - d->last_time); else fprintf
* (stderr, " never used\n"); } } return 0;
*/
}
void dump_users(e)
struct descriptor_data *e;
{
struct descriptor_data *d;
long now;
int a;
char buf[1024];
time(&now);
queue_string(e, "Player Name On For Idle\n");
for (a = 0; a < topdes; a++) {
d = &des[a];
if (d->connected) {
/*
* sprintf (buf, "%-16s %10s %4s", db[d->player].name,
* time_format_1(now - d->connected_at), time_format_2(now -
* d->last_time));
*/
sprintf(buf, "%s", db[d->player].name);
queue_string(e, buf);
queue_write(e, "\n", 1);
}
}
}
void announce_connect(player)
dbref player;
{
dbref loc;
char buf[BUFFER_LEN];
if ((loc = getloc(player)) == NOTHING)
return;
if (Dark(player) || Dark(loc))
return;
sprintf(buf, "%s has connected.", db[player].name);
notify_except(db[loc].contents, player, buf);
db[player].flags |= PLAYER_CONNECT;
}
void announce_disconnect(player)
dbref player;
{
dbref loc;
int num, a;
char buf[BUFFER_LEN];
if ((loc = getloc(player)) == NOTHING)
return;
if (Dark(player) || Dark(loc))
return;
sprintf(buf, "%s has disconnected.", db[player].name);
notify_except(db[loc].contents, player, buf);
for (num = a = 0; a < MAXDES; a++)
if (des[a].connected && (des[a].player == player))
num++;
if (num < 2)
db[player].flags &= ~PLAYER_CONNECT;
}