/* 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 "config.h"
#include "db.h"
#include "interface.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;
}