/* bsd.c */
/* $Id: bsd.c,v 1.35 1993/12/19 17:59:49 nils Exp $ */
#include "config.h"
#include "externs.h"
time_t now;
#if defined(SYSV) || defined(HPUX) || defined(SYSV_MAYBE)
# define mklinebuf(fp) setvbuf(fp, NULL, _IOLBF, 0)
#else
# define mklinebuf(fp) setlinebuf(fp)
#endif
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <fcntl.h>
#include <sys/errno.h>
#include <sys/signal.h>
#include "interface.h"
#include <netdb.h>
#include <ctype.h>
/* #include <netinet/in.h> ? */
/* #include <sys/socket.h> */
extern int errno;
extern int reserved;
#define DEF_MODE 0644
static char *def_db_in = DEF_DB_IN;
static char *def_db_out = DEF_DB_OUT;
static char *def_logfile = DEF_LOGFILE;
static int tinyport = TINYPORT;
int shutdown_flag = 0;
int exit_status = 136; /* we will change this when we set
* shutdown_flag to 1... */
int sig_caught = 0;
time_t muse_up_time;
static char *connect_fail = "Either that player does not exist, or has a different password.\n";
#ifndef WCREAT
static char *create_fail = "Either there is already a player with that name, or that name is illegal.\n";
#endif
static char *flushed_message = "<Output Flushed>\n";
static char *shutdown_message = "Going down - Bye\n";
static char *get_password = "Please enter password:\n\373\001";
static char *got_password = "\374\001";
struct descriptor_data *descriptor_list = 0;
static int sock;
int ndescriptors = 0;
char ccom[1024];
dbref cplr;
int guest_free[NUMBER_GUESTS];
static void check_connect P((struct descriptor_data *, char *));
static void parse_connect P((char *, char *, char *, char *));
static void set_userstring P((char **, char *));
static int do_command P((struct descriptor_data *, char *));
static char *strsave P((char *));
static int process_input P((struct descriptor_data *));
#define MALLOC(result, type, number) do { \
if (!((result) = (type *) malloc ((number) * sizeof (type)))) \
panic("Out of memory"); \
} while (0)
#define FREE(x) (free((void *) x))
void main(argc, argv)
int argc;
char *argv[];
{
init_args(argc, argv);
init_io();
printf("--------------------------------\n");
printf("MUSE online (pid=%d)\n", getpid());
init_attributes();
init_mail();
if ( init_game(def_db_in, def_db_out) < 0 ) {
log_error(tprintf("Couldn't load %s!", def_db_in));
exit_nicely(136);
}
set_signals();
save_muse_pid();
time(&muse_up_time);
/* main engine call */
shovechars(tinyport);
log_important("Shutting down normally");
close_sockets();
do_haltall(1);
dump_database();
free_database();
free_mail();
free_hash();
close(sock);
if ( sig_caught > 0 )
log_important(tprintf("Shutting down due to signal %d", sig_caught));
exit_nicely(exit_status);
}
void save_muse_pid()
{
FILE *fp;
struct stat statbuf;
if (stat(MUSE_PID_FILE,&statbuf)>=0) {
/* it already exists! */
log_error("muse pid file already exists!");
exit_nicely(136);
}
unlink(MUSE_PID_FILE);
if ( (fp = fopen(MUSE_PID_FILE, "w")) != NULL ) {
fprintf(fp, "%d\n", getpid());
fclose(fp);
}
}
void remove_muse_pid()
{
FILE *fp;
char buf1[20], buf2[20];
close(reserved);
if (!(fp = fopen(MUSE_PID_FILE, "r"))) {
perror("muse pid file");
log_error("can't open muse pid file!");
return;
}
fgets(buf1, 20, fp);
sprintf(buf2, "%d\n", getpid());
if (strcmp(buf1, buf2)) {
log_error(tprintf("muse pid file doesn't contain me(%d)!",getpid()));
fclose(fp);
return;
}
fclose(fp);
unlink(MUSE_PID_FILE);
reserved = open("/dev/null", O_RDWR, 0);
}
void init_args(argc, argv)
int argc;
char *argv[];
{
/* change default input database? */
if ( argc > 1 )
--argc, def_db_in = *++argv;
/* change default dump database? */
if ( argc > 1 )
--argc, def_db_out = *++argv;
/* change default log file? */
if ( argc > 1 )
--argc, def_logfile = *++argv;
/* change port number? */
if ( argc > 1 )
--argc, tinyport = atoi(*++argv);
}
void init_io()
{
#ifndef fileno
/* sometimes it's #defined in stdio.h */
extern int fileno P((FILE *));
#endif
int fd;
/* close standard input */
fclose(stdin);
/* open a link to the log file */
fd = open(def_logfile, O_WRONLY | O_CREAT | O_APPEND, DEF_MODE);
if ( fd < 0 ) {
perror("open()");
log_error(tprintf("error opening %s for writing", def_logfile));
exit_nicely(136);
}
/* attempt to convert standard output to logfile */
close(fileno(stdout));
if ( dup2(fd, fileno(stdout)) == -1 ) {
perror("dup2()");
log_error("error converting standard output to logfile");
}
mklinebuf(stdout);
/* attempt to convert standard error to logfile */
close(fileno(stderr));
if ( dup2(fd, fileno(stderr)) == -1 ) {
perror("dup2()");
printf("error converting standard error to logfile\n");
}
mklinebuf(stderr);
/* this logfile reference is no longer needed */
close(fd);
/* save a file descriptor */
reserved = open("/dev/null",O_RDWR, 0);
}
int floating_x;
void handle_exception()
{
floating_x = 1;
}
void set_signals()
{
/* we don't care about SIGPIPE, we notice it in select() and write() */
signal(SIGPIPE, SIG_IGN);
#ifdef SYSV
signal (SIGCLD, SIG_IGN);
#endif
/* standard termination signals */
signal (SIGINT, 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);
* want a core dump for now!! */
/* status dumper (predates "WHO" command) */
signal(SIGUSR1, dump_status);
signal (SIGHUP, sig_handler);
signal (SIGTERM, sig_handler);
signal (SIGEMT, handle_exception);
}
void sig_handler(sig)
int sig;
{
sig_caught = sig;
if(sig == 15)
exit_status = 0;
else
exit_status = 1;
shutdown_flag = 1;
}
void raw_notify(player,msg)
dbref player;
char *msg;
{
struct descriptor_data *d;
if (!(db[player].flags & PLAYER_CONNECT))
return;
for(d = descriptor_list; d; d = d->next) {
if (d->state==CONNECTED && d->player == player) {
queue_string(d, msg);
queue_write(d, "\n", 1);
}
}
}
struct timeval timeval_sub(now,then)
struct timeval now;
struct timeval then;
{
now.tv_sec -= then.tv_sec;
now.tv_usec -= then.tv_usec;
while (now.tv_usec < 0) {
now.tv_usec += 1000000;
now.tv_sec--;
}
if(now.tv_sec<0) now.tv_sec = 0; /* aack! */
return now;
}
int msec_diff(now,then)
struct timeval now;
struct timeval then;
{
return ((now.tv_sec - then.tv_sec) * 1000
+ (now.tv_usec - then.tv_usec) / 1000);
}
struct timeval msec_add(t,x)
struct timeval t;
int x;
{
t.tv_sec += x / 1000;
t.tv_usec += (x % 1000) * 1000;
if (t.tv_usec >= 1000000) {
t.tv_sec += t.tv_usec / 1000000;
t.tv_usec = t.tv_usec % 1000000;
}
return t;
}
struct timeval update_quotas(last,current)
struct timeval last;
struct timeval current;
{
int nslices;
struct descriptor_data *d;
nslices = msec_diff (current, last) / COMMAND_TIME_MSEC;
if (nslices > 0) {
for (d = descriptor_list; d; d = d -> next) {
d -> quota += COMMANDS_PER_TIME * nslices;
if (d -> quota > COMMAND_BURST_SIZE)
d -> quota = COMMAND_BURST_SIZE;
}
}
return msec_add (last, nslices * COMMAND_TIME_MSEC);
}
int need_more_proc;
int maxd;
void shovechars(port)
int port;
{
fd_set input_set, output_set;
struct timeval last_slice, current_time;
struct timeval next_slice;
struct timeval timeout, slice_timeout;
int found;
struct descriptor_data *d, *dnext;
struct descriptor_data *newd;
int avail_descriptors;
log_io(tprintf("Starting up on port %d",port));
sock = make_socket (port);
maxd = sock+1;
gettimeofday(&last_slice, (struct timezone *) 0);
avail_descriptors = getdtablesize() - 5;
#ifdef USE_RWHO
rwhocli_setup(RWHO_SERVER,RWHO_PASSWORD,MUSE_NAME,BASE_VERSION);
#endif
while (shutdown_flag == 0) {
gettimeofday(¤t_time, (struct timezone *) 0);
last_slice = update_quotas (last_slice, current_time);
if (loading_db) {
process_commands();
if (shutdown_flag)
break;
/* test for events */
dispatch();
} else {
load_more_db();
}
/* any queued robot commands waiting? */
timeout.tv_sec = (need_more_proc||test_top()) ? 0 : 100;
need_more_proc=0;
timeout.tv_usec = 5;
next_slice = msec_add (last_slice, COMMAND_TIME_MSEC);
slice_timeout = timeval_sub (next_slice, current_time);
FD_ZERO (&input_set);
FD_ZERO (&output_set);
if (ndescriptors < avail_descriptors && sock>=0)
FD_SET (sock, &input_set);
for (d = descriptor_list; d; d=dnext) {
dnext = d->next;
if(d->cstatus&C_REMOTE && d->output.head) {
if(!process_output(d))
shutdownsock(d);
need_more_proc=1;
}
}
for (d = descriptor_list; d; d=d->next)
if(!(d->cstatus&C_REMOTE)) {
if (d->input.head)
timeout = slice_timeout;
else
FD_SET (d->descriptor, &input_set);
if (d->output.head && (d->state!=CONNECTED || d->player>0))
FD_SET (d->descriptor, &output_set);
}
if ((found=select (maxd, &input_set, &output_set,
(fd_set *) 0, &timeout)) < 0) {
if (errno != EINTR) {
perror ("select");
/* return;*/ /* naw.. stay up. */
}
} else {
/* if !found then time for robot commands */
if (loading_db && !found) {
if(do_top() && do_top())
do_top();
continue;
}
(void) time (&now);
if (sock>=0 && FD_ISSET (sock, &input_set)) {
if (!(newd = new_connection (sock))) {
if (errno
&& errno != EINTR
&& errno != EMFILE
&& errno != ENFILE) {
perror ("new_connection");
/* return;*/ /* naw.. stay up. */
}
} else {
if (newd->descriptor >= maxd)
maxd = newd->descriptor + 1;
}
}
for (d = descriptor_list; d; d=dnext) {
dnext=d->next;
if (FD_ISSET (d->descriptor, &input_set) && !(d->cstatus&C_REMOTE))
if (!process_input (d))
shutdownsock(d);
}
for (d = descriptor_list; d; d = dnext) {
dnext = d->next;
if(d->cstatus&C_REMOTE)
process_output(d);
}
for (d = descriptor_list; d; d = dnext) {
dnext = d->next;
if(!(d->cstatus&C_REMOTE)
&& (FD_ISSET (d->descriptor, &output_set)))
if (!process_output(d))
shutdownsock(d);
}
for (d = descriptor_list; d; d = dnext) {
dnext = d->next;
if(d->cstatus&C_REMOTE &&
!d->parent)
shutdownsock(d);
}
}
}
}
struct descriptor_data *new_connection(sock)
int sock;
{
int newsock;
struct sockaddr_in addr;
int addr_len;
addr_len = sizeof (addr);
newsock = accept (sock, (struct sockaddr *) & addr, &addr_len);
if (newsock < 0) {
if(errno==EALREADY) { /* screwy sysv buf. */
static int k=0;
if(k++>50) {
log_error("Killin' EALREADY. restartin' socket.");
puts("Killin' EALREADY. restartin' socket.");
close(sock);
sock = make_socket(4201);
k=0;
}
}
return 0;
#ifdef LOCKOUT
} else if(forbidden_site(ntohl(addr.sin_addr.s_addr))) {
log_io(tprintf("REFUSED CONNECTION from %s(%d) on descriptor %d",
addrout(addr.sin_addr.s_addr),
ntohs(addr.sin_port), newsock));
shutdown(newsock, 0);
close(newsock);
errno = 0;
return 0;
#endif /* LOCKOUT */
} else {
struct hostent *hent;
char buff[100];
time_t tt;
hent = gethostbyaddr (&(addr.sin_addr.s_addr),
sizeof (addr.sin_addr.s_addr), AF_INET);
if (hent)
strcpy (buff, hent->h_name);
else {
extern char *inet_ntoa();
strcpy(buff, inet_ntoa(addr.sin_addr.s_addr));
}
tt = time(NULL);
log_io(tprintf("USER CONNECT: des: %d host %s time: %s", newsock,buff,ctime(&tt)));
return initializesock (newsock, &addr,buff);
}
}
char *addrout(a)
long a;
{
#ifdef HOST_NAME
extern char *inet_ntoa();
struct hostent *he;
a = htonl(a);
he = gethostbyaddr(&a,sizeof(a),AF_INET);
if (he)
return he->h_name;
else
return inet_ntoa(a);
#else
/* return inet_ntoa(a);*/
return "OOPS";
#endif /* HOST_NAME */
}
void clearstrings(d)
struct descriptor_data *d;
{
if (d->output_prefix) {
FREE(d->output_prefix);
d->output_prefix = 0;
}
if (d->output_suffix) {
FREE(d->output_suffix);
d->output_suffix = 0;
}
}
void shutdownsock(d)
struct descriptor_data *d;
{
int count;
dbref guest_player;
struct descriptor_data *sd;
/* if this is a guest player, save his reference # */
guest_player = NOTHING;
if (d->state == CONNECTED)
if(d->player>0)
if(Guest(d->player))
guest_player = d->player;
if (d->state == CONNECTED) {
if(d->player>0) {
log_io (tprintf("DISCONNECT descriptor %d player %s(%d)",
d->descriptor, db[d->player].name, d->player));
announce_disconnect(d->player);
}
} else {
log_io (tprintf("DISCONNECT descriptor %d never connected",
d->descriptor));
}
clearstrings(d);
if(!(d->cstatus&C_REMOTE)) {
shutdown(d->descriptor, 0);
close(d->descriptor);
} else {
register struct descriptor_data *k;
for(k=descriptor_list; k; k=k->next)
if(k->parent==d)
k->parent = 0;
}
freeqs(d);
*d->prev = d->next;
if (d->next)
d->next->prev = d->prev;
if(!(d->cstatus&C_REMOTE))
ndescriptors--;
FREE(d);
/* if this is a guest account and the
last to disconnect from it, kill it */
if ( guest_player != NOTHING ) {
count = 0;
for (sd = descriptor_list; sd; sd = sd->next) {
if (sd->state == CONNECTED && sd->player == guest_player)
++count;
}
if ( count == 0 )
destroy_guest(guest_player);
}
}
void rwho_setupfd(player,fd)
dbref player;
int fd;
{
struct descriptor_data *d;
ndescriptors++;
MALLOC(d, struct descriptor_data, 1);
d->descriptor = fd;
d->concid = make_concid();
d->cstatus = 0;
d->parent = 0;
d->state = CONNECTED;
make_nonblocking(fd);
d->player = -player;
d->output_prefix=0;
d->output_suffix=0;
d->output_size=0;
d->output.head=0;
d->output.tail = &d->output.head;
d->input.head = 0;
d->input.tail = &d->input.head;
d->raw_input = 0;
d->raw_input_at = 0;
d->quota=COMMAND_BURST_SIZE;
d->last_time=0;
/* d->address=inet_addr("127.0.0.1"); * localhost. cuz. */
strcpy(d->addr,"RWHO");
if (descriptor_list)
descriptor_list->prev = &d->next;
d->next = descriptor_list;
d->prev = &descriptor_list;
d->edit_buff = NULL;
descriptor_list = d;
if (fd >= maxd)
maxd = fd + 1;
}
struct descriptor_data *initializesock(s,a,addr)
int s;
struct sockaddr_in *a;
char *addr;
{
struct descriptor_data *d;
/*fprintf(stderr,"3\n");fflush(stderr);*/
ndescriptors++;
MALLOC(d, struct descriptor_data, 1);
d->descriptor = s;
d->concid = make_concid();
d->cstatus = 0;
d->parent = 0;
d->state = WAITCONNECT;
make_nonblocking (s);
d->output_prefix = 0;
d->output_suffix = 0;
d->output_size = 0;
d->output.head = 0;
d->output.tail = &d->output.head;
d->input.head = 0;
d->input.tail = &d->input.head;
d->raw_input = 0;
d->raw_input_at = 0;
d->quota = COMMAND_BURST_SIZE;
d->last_time = 0;
strncpy(d->addr,addr,50);
d->address = *a; /* added 5/3/90 SCG */
if (descriptor_list)
descriptor_list->prev = &d->next;
d->next = descriptor_list;
d->prev = &descriptor_list;
d->edit_buff = NULL;
descriptor_list = d;
welcome_user (d);
return d;
}
int make_socket(port)
int port;
{
int s;
struct sockaddr_in server;
int opt;
s = socket (AF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror (tprintf("creating stream socket on port %d",port));
#ifndef RESOCK
exit_status = 1; /* try again. */
shutdown_flag = 1;
#endif
return -1;
}
opt = 1;
if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
(char *) &opt, sizeof (opt)) < 0) {
perror ("setsockopt");
#ifndef RESOCK
shutdown_flag = 1;
exit_status = 1;
#endif
close(s);
return -1;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons (port);
if (bind (s, (struct sockaddr *) & server, sizeof (server))) {
perror ("binding stream socket");
close (s);
#ifndef RESOCK
shutdown_flag = 1;
exit_status = 1;
#endif
return -1;
}
listen (s, 5);
return s;
}
struct text_block *make_text_block(s,n)
char *s;
int n;
{
struct text_block *p;
MALLOC(p, struct text_block, 1);
MALLOC(p->buf, char, n);
bcopy (s, p->buf, n);
p->nchars = n;
p->start = p->buf;
p->nxt = 0;
return p;
}
void free_text_block (t)
struct text_block *t;
{
FREE (t->buf);
FREE ((char *) t);
}
void add_to_queue(q,b,n)
struct text_queue *q;
char *b;
int n;
{
struct text_block *p;
if (n == 0) return;
p = make_text_block (b, n);
p->nxt = 0;
*q->tail = p;
q->tail = &p->nxt;
}
int flush_queue(q,n)
struct text_queue *q;
int n;
{
struct text_block *p;
int really_flushed = 0;
n += strlen(flushed_message);
while (n > 0 && (p = q->head)) {
n -= p->nchars;
really_flushed += p->nchars;
q->head = p->nxt;
free_text_block (p);
}
p = make_text_block(flushed_message, strlen(flushed_message));
p->nxt = q->head;
q->head = p;
if (!p->nxt)
q->tail = &p->nxt;
really_flushed -= p->nchars;
return really_flushed;
}
int queue_write(d,b,n)
struct descriptor_data *d;
char *b;
int n;
{
int space;
if (d->cstatus & C_REMOTE)
need_more_proc=1;
space = MAX_OUTPUT - d->output_size - n;
if (space < 0)
d->output_size -= flush_queue(&d->output, -space);
add_to_queue (&d->output, b, n);
d->output_size += n;
return n;
}
int queue_string(d,s)
struct descriptor_data *d;
char *s;
{
return queue_write (d, s, strlen (s));
}
int process_output(d)
struct descriptor_data *d;
{
struct text_block **qp, *cur;
int cnt;
if(d->cstatus&C_REMOTE) {
static char buf[10];
static char obuf[2048];
int buflen;
int k,j;
sprintf(buf,"%d ",d->concid);
buflen=strlen(buf);
bcopy(buf,obuf,buflen);
j=buflen;
for(qp= &d->output.head;(cur= *qp);) {
need_more_proc=1;
for(k=0;k<cur->nchars;k++) {
obuf[j++]=cur->start[k];
if(cur->start[k]=='\n') {
if(d->parent)
queue_write(d->parent,obuf,j);
bcopy(buf,obuf,buflen);
j=buflen;
}
}
d->output_size -= cur->nchars;
if(!cur->nxt)
d->output.tail=qp;
*qp = cur->nxt;
free_text_block(cur);
}
if(j>buflen)
queue_write(d,obuf+buflen,j-buflen);
return 1;
} else {
for (qp = &d->output.head; (cur = *qp);) {
cnt = write (d->descriptor, cur -> start, cur -> nchars);
if (cnt < 0) {
if (errno == EWOULDBLOCK)
return 1;
return 0;
}
d->output_size -= cnt;
if (cnt == cur -> nchars) {
if (!cur -> nxt)
d->output.tail = qp;
*qp = cur -> nxt;
free_text_block (cur);
continue; /* do not adv ptr */
}
cur -> nchars -= cnt;
cur -> start += cnt;
break;
}
}
return 1;
}
void make_nonblocking(s)
int s;
{
if (fcntl (s, F_SETFL, FNDELAY) == -1) {
perror ("make_nonblocking: fcntl");
panic ("FNDELAY fcntl failed");
}
}
void freeqs(d)
struct descriptor_data *d;
{
struct text_block *cur, *next;
cur = d->output.head;
while (cur) {
next = cur -> nxt;
free_text_block (cur);
cur = next;
}
d->output.head = 0;
d->output.tail = &d->output.head;
cur = d->input.head;
while (cur) {
next = cur -> nxt;
free_text_block (cur);
cur = next;
}
d->input.head = 0;
d->input.tail = &d->input.head;
if (d->raw_input)
FREE (d->raw_input);
d->raw_input = 0;
d->raw_input_at = 0;
}
void welcome_user(d)
struct descriptor_data *d;
{
connect_message(d, WELCOME_MSG_FILE,0);
}
void connect_message(d, filename, direct)
struct descriptor_data *d;
char *filename;
int direct;
{
int n, fd;
char buf[512];
close(reserved);
if ( (fd = open(filename, O_RDONLY, 0)) != -1 ) {
while ( (n = read(fd, buf, 512)) > 0 )
queue_write(d, buf, n);
close(fd);
queue_write(d, "\n", 1);
}
reserved=open("/dev/null", O_RDWR, 0);
if(direct) {
process_output(d);
}
}
char *strsave (s)
char *s;
{
char *p;
MALLOC (p, char, strlen(s) + 1);
if (p)
strcpy (p, s);
return p;
}
void save_command (d,command)
struct descriptor_data *d;
char *command;
{
add_to_queue (&d->input, command, strlen(command)+1);
}
int process_input (d)
struct descriptor_data *d;
{
char buf[1024];
int got;
char *p, *pend, *q, *qend;
got = read (d->descriptor, buf, sizeof buf);
if (got <= 0)
return 0;
if (!d->raw_input) {
MALLOC(d->raw_input,char,MAX_COMMAND_LEN);
d->raw_input_at = d->raw_input;
}
p = d->raw_input_at;
pend = d->raw_input + MAX_COMMAND_LEN - 1;
for (q=buf, qend = buf + got; q < qend; q++) {
if (*q == '\n') {
*p = '\0';
if (p >= d->raw_input)
save_command (d, d->raw_input);
p = d->raw_input;
} else if (p < pend && isascii (*q) && isprint (*q)) {
*p++ = *q;
}
}
if(p > d->raw_input) {
d->raw_input_at = p;
} else {
FREE(d->raw_input);
d->raw_input = 0;
d->raw_input_at = 0;
}
return 1;
}
void set_userstring (userstring,command)
char **userstring;
char *command;
{
if (*userstring) {
FREE(*userstring);
*userstring = 0;
}
while (*command && isascii (*command) && isspace (*command))
command++;
if (*command)
*userstring = strsave (command);
}
void process_commands()
{
int nprocessed;
struct descriptor_data *d, *dnext;
struct text_block *t;
do {
nprocessed = 0;
for (d = descriptor_list; d; d = dnext) {
dnext = d->next;
if (d -> quota > 0 && (t = d -> input.head)) {
nprocessed++;
if (!do_command(d, t -> start)) {
connect_message(d,LEAVE_MSG_FILE,1);
shutdownsock(d);
} else {
d -> input.head = t -> nxt;
if (!d -> input.head)
d -> input.tail = &d -> input.head;
free_text_block (t);
}
}
}
} while (nprocessed > 0);
}
int do_command (d,command)
struct descriptor_data *d;
char *command;
{
d->last_time = now;
d->quota--;
depth=0;
if (!*command && !(d->player<0 && d->state==CONNECTED))
return 1;
if (d->state == CONNECTED && d->player > 0) {
static char buf[2048];
sprintf(buf,"%05d: %s",d->player,command);
log_typed(buf);
}
if (!strcmp (command, QUIT_COMMAND)) {
return 0;
} else if(!strncmp (command, "I wanna be a concentrator... my password is ",
sizeof ("I wanna be a concentrator... my password is ")
-1)) {
do_becomeconc(d,command+sizeof("I wanna be a concentrator... my password is ")-1);
} else if (! strncmp(command, WHO_COMMAND, sizeof(WHO_COMMAND))
&& d->state != CONNECTED) {
if (d->output_prefix) {
queue_string (d, d->output_prefix);
queue_write (d, "\n", 1);
}
dump_users (NOTHING,NULL,NULL,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))) {
set_userstring (&d->output_prefix, command+strlen(PREFIX_COMMAND));
} else if (!strncmp (command, SUFFIX_COMMAND, strlen (SUFFIX_COMMAND))) {
set_userstring (&d->output_suffix, command+strlen(SUFFIX_COMMAND));
} else
if (d->cstatus & C_CCONTROL) {
if(!strcmp(command, "Gimmie a new concid"))
do_makeid(d);
else if(!strncmp(command, "I wanna connect concid ",
sizeof ("I wanna connect concid ")-1)) {
char *m,*n;
m=command+sizeof("I wanna connect concid ")-1;
n=strchr(m,' ');
if(!n)
queue_string(d,"Usage: I wanna connect concid <id> <hostname>\n");
else
do_connectid(d,atoi
(command+
sizeof ("I wanna connect concid ")-1),n);
} else if(!strncmp(command, "I wanna kill concid ",
sizeof ("I wanna kill concid ")-1))
do_killid(d,
atoi(command+
sizeof ("I wanna kill concid ")-1));
else {
char *k;
k=strchr(command,' ');
if(!k)
queue_string(d,"Huh???\r\n");
else {
struct descriptor_data *l;
int j;
*k = '\0';
j=atoi(command);
for(l=descriptor_list;l;l=l->next) {
if(l->concid==j)
break;
}
if(!l)
queue_string(d,"I don't know that concid.\r\n");
else {
k++;
if(!do_command(l,k)) {
connect_message(l,LEAVE_MSG_FILE,1);
shutdownsock(l);
}
}
}
}
} else {
if (d->state == CONNECTED) {
if (d->output_prefix) {
queue_string (d, d->output_prefix);
queue_write (d, "\n", 1);
}
cplr=d->player;
if(d->player>0) {
strcpy(ccom,command);
if (d->edit_buff == NULL)
process_command (d->player, command,NOTHING);
else
edit_command(d, d->player, command);
} else
notify(-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;
char *msg;
{
extern NALLOC *glurp;
char *p;
char command[MAX_COMMAND_LEN];
char user[MAX_COMMAND_LEN];
char password[MAX_COMMAND_LEN];
#ifdef EMAIL_CREATE
char email[MAX_COMMAND_LEN];
#endif
dbref player;
if (d->state == WAITPASS) {
/* msg contains the password. */
char *foobuf = na_alloc(glurp, MAX_COMMAND_LEN);
sprintf(foobuf,"connect %s %s",d->charname, msg);
free(d->charname);
queue_string(d,got_password);
d->state = WAITCONNECT;
msg = foobuf;
}
parse_connect (msg, command, user, password
#ifdef EMAIL_CREATE
,email
#endif
);
if (!strncmp (command, "co", 2)) {
if ( string_prefix(user, GUEST_PREFIX) ) {
if ( (p = make_guest(d)) == NULL )
return;
strcpy(user, p);
strcpy(password, GUEST_PREFIX);
}
player = connect_player (user, password);
if (player == NOTHING && !*password) {
/* hmm. bet they want to type it in seperately. */
queue_string(d, get_password);
d->state = WAITPASS;
d->charname = malloc(strlen(user)+1);
strcpy(d->charname, user);
return;
} else if (player == NOTHING) {
queue_string (d, connect_fail);
log_io (tprintf("FAILED CONNECT %s on descriptor %d",
user, d->descriptor));
} else {
log_io (tprintf("CONNECTED %s(%d) on descriptor %d",
db[player].name, player, d->descriptor));
if (d->state == WAITPASS)
queue_string(d, got_password);
d->state = CONNECTED;
d->connected_at = time(0);
d->player = player;
/* give players a message on connection */
connect_message(d, CONNECT_MSG_FILE,0);
announce_connect(player);
do_look_around(player);
/* XXX might want to add check for haven here. */
if(Guest(player))
notify(player, tprintf(
"Welcome to %s; your name is %s",
MUSE_NAME, db[player].name));
}
}
else if (!strncmp (command, "cr", 2)) {
#ifdef WCREAT
connect_message(d, REGISTER_MSG_FILE, 0);
#else /* WCREAT */
#ifdef EMAIL_CREATE
if(!email || !strcmp(email,"")) {
queue_string(d,"You need to specify an email address.\n");
queue_string(d,"Try: create <name> <password> <email address>.\n");
} else
#endif
{
player = create_player (user, password,CLASS_VISITOR);
if (player == NOTHING) {
queue_string (d, create_fail);
log_io (tprintf("FAILED CREATE %s on descriptor %d",
user, d->descriptor));
} else {
log_io (tprintf("CREATED %s(%d) on descriptor %d",
db[player].name, player, d->descriptor));
#ifdef EMAIL_CREATE
atr_add(player,A_EMAIL,email);
#endif
d->connected = 1;
d->connected_at = time(0);
d->player = player;
/* give new players a special message */
connect_message(d, NEW_CONNECT_MSG_FILE, 0);
/* connect_message(d, CONNECT_MSG_FILE); */
announce_connect(player);
do_look_around(player);
}
}
#endif /* WCREAT */
} else
welcome_user (d);
if (d->state == WAITPASS) {
d->state = WAITCONNECT;
queue_string(d, got_password);
}
}
void parse_connect (msg,command,user,pass
#ifdef EMAIL_CREATE
,email
#endif
)
char *msg;
char *command;
char *user;
char *pass;
#ifdef EMAIL_CREATE
char *email;
#endif
{
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';
#ifdef EMAIL_CREATE
while (*msg && isascii(*msg) && isspace(*msg))
msg++;
p=email;
while (*msg && isascii(*msg) && !isspace(*msg))
*p++ = *msg++;
*p = '\0';
#endif
}
void mark_free(n)
int n;
{
guest_free[n-1] = 1;
}
/* this algorithm can be changed later to accomodate an unlimited
number of guests. currently, it supports a limited number. */
char *make_guest(d)
struct descriptor_data *d;
{
int i;
dbref player;
char name[50];
static int need_init = 1;
/* make sure flags are initialized */
if ( need_init ) {
need_init = 0;
for ( i = 0; i < NUMBER_GUESTS; i++ )
guest_free[i] = 1;
}
/* locate a free guest id - mark it non free */
for ( i = 0; i < NUMBER_GUESTS; i++ )
if ( guest_free[i] )
break;
if ( i == NUMBER_GUESTS ) {
queue_string(d, "All guest ID's are busy; please try again later.\n");
return NULL;
}
sprintf(name, "%s%d", GUEST_PREFIX, i+1);
player = create_guest(name, GUEST_PREFIX);
guest_free[i] = 0;
if ( player == NOTHING ) {
queue_string(d, "Error creating guest ID, please try again later.\n");
log_error(tprintf("Error creating guest ID. '%s' already exists.",
name));
return NULL;
}
return db[player].name;
}
void close_sockets()
{
struct descriptor_data *d, *dnext;
/* shutdown_flag = 1; * just in case. so announce_disconnect
* does'nt reset the PLAYER_CONNECT
* flags. */
for (d = descriptor_list; d; d = dnext) {
dnext = d->next;
if(!(d->cstatus&C_REMOTE)) {
write (d->descriptor, shutdown_message, strlen (shutdown_message));
process_output(d);
shutdownsock(d);
}
}
}
void emergency_shutdown()
{
log_error("Emergency shutdown.");
shutdown_flag = 1;
exit_status = 136;
close_sockets();
}
int boot_off(player)
dbref player;
{
struct descriptor_data *d;
for (d = descriptor_list; d; d = d->next) {
if (d->state == CONNECTED && d->player == player) {
process_output (d);
shutdownsock(d);
return 1;
}
}
return 0;
}
signal_type bailout(sig)
int sig;
{
char message[1024];
sprintf (message, "BAILOUT: caught signal %d", sig);
panic(message);
exit_nicely (136);
#ifdef void_signal_type
return;
#else
return 0;
#endif
}
signal_type dump_status(int i)
{
struct descriptor_data *d;
long now;
now = time (NULL);
fprintf (stderr, "STATUS REPORT:\n");
for (d = descriptor_list; d; d = d->next) {
if (d->state == 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");
}
}
#ifdef void_signal_type
return;
#else
return 0;
#endif
}
extern char *wholev();
#define WHO_BUF_SIZ 300
#define DEF_SCR_COLS 78 /* must be less than WHO_BUF_SIZ */
#define MIN_SEC_SPC 2
#define MIN_GRP_SPC 4
#define DEF_WHO_FLAGS "Nfoitd" /* close to the old WHO output format */
#define DEF_WHO_ALIAS "" /* what people see if no alias is set */
#define W_NAME 0x001
#define W_ALIAS 0x002
#define W_FLAGS 0x004
#define W_ONFOR 0x008
#define W_IDLE 0x010
#define W_CLASS 0x020
#define W_HOST 0x040
#define W_TALENT 0x080
#define W_DOING 0x100
static char who_flags[] = "nafoichtd";
static char *who_fmt_small[] = {
"%-10.10s ", "%-10.10s ", "%-4.4s ",
"%9.9s ", "%4.4s ", "%-5.5s ", "%-20.20s ", "%-15.15s ",
"%-15.15s "
};
static int who_sizes_small[] = { 10, 10, 3, 9, 4, 5, 20, 15, 15 };
static char *who_fmt_large[] = {
"%-16.16s ", "%-16.16s ", "%-4.4s ", "%9.9s ", "%4.4s ", "%-13.13s ",
#ifdef BRACKET_HOST
"%-32.32s ", "%-15.15s ", "%-15.15s " };
static int who_sizes_large[] = { 16, 16, 3, 9, 4, 13, 32, 15, 15 };
char who_bh_buf[33];
#else /* BRACKET_HOST */
"%-30.30s ", "%-15.15s ", "%-15.15s " };
static int who_sizes_large[] = { 16, 16, 3, 9, 4, 13, 30, 15, 15 };
#endif /* BRACKET_HOST */
#define WHO_SIZE 9
static int who_sizes[WHO_SIZE];
static char *who_fmt[WHO_SIZE];
void dump_users(w,arg1,arg2,k)
dbref w;
char *arg1, *arg2;
struct descriptor_data *k; /* if non-zero, use k instead of w */
{
char *p, *b, *names;
char buf[WHO_BUF_SIZ+1];
struct descriptor_data *d;
char fbuf[5], flags[WHO_SIZE+1];
int done, pow_who, hidden = 0, see_player;
int i, j, ni, bit, bits, num_secs, scr_cols, hc, header;
int grp, grp_len, num_grps, total_count, hidden_count;
dbref who, nl_size, *name_list;
strcpy(flags,DEF_WHO_FLAGS);
/* setup special data */
names = "";
scr_cols = DEF_SCR_COLS;
if( ! k ) {
if( Typeof(w) != TYPE_PLAYER && ! payfor(w, 50) ) {
notify(w, "You don't have enough pennies.");
return;
}
if ( *(p = atr_get(w, A_COLUMNS)) != '\0' ) {
scr_cols = atoi(p);
if ( scr_cols > WHO_BUF_SIZ+1 )
scr_cols = WHO_BUF_SIZ;
}
if ( *(p = atr_get(w, A_WHOFLAGS)) != '\0' ) {
*flags = '\0';
strncat(flags, p, WHO_SIZE);
}
/* in case this value used, we must process
names before atr_get is called again */
if ( *(p = atr_get(w, A_WHONAMES)) != '\0' )
names = p;
}
/* override data */
if ( arg1 != NULL )
if ( *arg1 != '\0' ) {
*flags = '\0';
strncat(flags, arg1, WHO_SIZE);
}
if ( arg2 != NULL )
if ( *arg2 != '\0' )
names = arg2;
/* Check for power to distinguish class names */
pow_who = ( k ) ? 0 : has_pow(w, NOTHING, POW_WHO);
/* process flags */
bits = 0;
grp_len = 0;
num_secs = 0;
for ( p = flags; *p != '\0'; p++ ) {
for ( i = 0, bit = 1; i < WHO_SIZE; i++, bit <<= 1 )
if ( to_lower(*p) == who_flags[i] ) {
++num_secs;
bits |= bit;
if ( islower(*p) ) {
who_sizes[i] = who_sizes_small[i];
who_fmt[i] = who_fmt_small[i];
}
else {
who_sizes[i] = who_sizes_large[i];
who_fmt[i] = who_fmt_large[i];
}
grp_len += who_sizes[i];
break;
}
if ( i == WHO_SIZE ) {
sprintf(buf, "%c: bad who flag.%s", (int) *p, (k) ? "\n" : "");
if ( k )
queue_string(k, buf);
else
notify(w, buf);
return;
}
}
/* process names (before atr_get called that overwrites static buffer) */
if ( *names == '\0' ) {
/* avoid error msg in lookup_players() for missing name list */
nl_size = 0;
name_list = &nl_size;
}
else {
name_list = lookup_players((k) ? NOTHING : w, names);
if (!name_list[0])
return; /* we tried, but no users matched. */
}
/* add in min section spacing */
grp_len += (num_secs - 1) * MIN_SEC_SPC;
/* calc # of groups */
num_grps = ((scr_cols - grp_len) / (grp_len + MIN_GRP_SPC)) + 1;
if ( num_grps < 1 )
num_grps = 1;
/* calc header size based on see-able users */
for ( hc = 0, d = descriptor_list; d; d = d->next ) {
if ( d->state != CONNECTED || d->player <= 0 )
continue;
if (*atr_get(d->player, A_LHIDE)) {
if (k)
continue;
if (!controls(w,d->player,POW_WHO) && !could_doit(w,d->player,A_LHIDE))
continue;
}
if ( name_list[0] > 0 ) {
for ( i = 1; i <= name_list[0]; i++ )
if ( d->player == name_list[i] )
break;
if ( i > name_list[0] )
continue;
}
if ( ++hc >= num_grps )
break;
}
/* process names or, (if no names requested) loop once for all names */
b = buf;
grp = 1;
header = 1;
ni = 1;
who = NOTHING;
done = 0;
total_count = hidden_count = 0;
while ( !done ) {
/* if a player is on the names list, process them */
if ( ni <= name_list[0] )
who = name_list[ni++];
/* if no names left on list, this is final run through loop */
if ( ni > name_list[0] )
done = 1;
/* Build output lines and print them */
d = descriptor_list;
while ( d ) {
if ( !header ) {
/* skip records that aren't in use */
/* if name list, skip those not on list */
if ( d->state!=CONNECTED || d->player <= 0 ||
( who != NOTHING && who != d->player) ) {
d = d->next;
continue;
}
/* handle hidden players, keep track of player counts */
hidden = 0;
see_player = 1;
if (k?*atr_get(d->player,A_LHIDE):!could_doit(w,d->player,A_LHIDE)) {
hidden = 1;
see_player = !k && controls(w, d->player, POW_WHO);
}
/* do counts */
if ( see_player || name_list[0] == 0 ) {
++total_count;
if ( hidden )
++hidden_count;
}
if ( !see_player ) {
d = d->next;
continue;
}
}
/* build output line */
for ( i = 0, bit = 1; i < WHO_SIZE; i++, bit <<= 1 ) {
switch ( bits & bit ) {
case W_NAME:
p = header ? "Name" : db[d->player].name;
break;
case W_ALIAS:
if ( header )
p = "Alias";
else if ( *(p = atr_get(d->player, A_ALIAS)) == '\0' )
p = DEF_WHO_ALIAS;
break;
case W_FLAGS:
if ( header )
p = "Flg";
else {
fbuf[0] = (hidden) ? 'h' : ' ';
fbuf[1] = (k?*atr_get(d->player,A_LPAGE):
!could_doit(w,d->player,A_LPAGE)) ? 'H' : ' ';
fbuf[2] = (db[d->player].flags & PLAYER_NO_WALLS) ? 'N' : ' ';
fbuf[3] = (db[d->player].flags & PLAYER_NEWBIE) ? 'n' : ' ';
fbuf[4] = '\0';
p = fbuf;
}
break;
case W_TALENT:
if ( header )
p = "Talent";
else
p=atr_get(d->player,A_TALENT);
break;
case W_DOING:
if (header)
p = "Doing";
else
p=atr_get(d->player,A_DOING);
break;
case W_ONFOR:
p = header ? "On For" : time_format_1(now - d->connected_at);
break;
case W_IDLE:
p = header ? "Idle" : time_format_2(now - d->last_time);
break;
case W_CLASS:
if ( header )
p = "Class";
else
if(pow_who)
p = wholev(d->player,(who_sizes[i]>who_sizes_small[i]),pow_who);
else
p = "?";
break;
case W_HOST:
p = "?";
if ( header )
p = "Hostname";
else if ( !k )
if ( has_pow(w, d->player, POW_HOST) ) {
p = d->addr;
#ifdef BRACKET_HOST
if ( who_sizes[i] > who_sizes_small[i] ) {
who_bh_buf[0] = '[';
for ( j = 1, p = d->addr; j <= 30 && *p != '\0'; j++, p++ )
who_bh_buf[j] = *p;
who_bh_buf[j++] = ']';
who_bh_buf[j] = '\0';
p = who_bh_buf;
}
#endif /* BRACKET_HOST */
}
break;
default:
continue;
}
sprintf(b, who_fmt[i], p);
b += who_sizes[i] + 2;
}
b -= 2;
if ( header )
--hc;
if ( (!header && ++grp <= num_grps) || (header && hc) ) {
/* make space between groups */
strcpy(b, " ");
b += 4;
}
else {
/* trim excess spaces */
while ( *--b == ' ' )
;
/* print output line */
if ( k ) {
*++b = '\n';
*++b = '\0';
queue_string(k, buf);
}
else {
*++b = '\0';
notify(w, buf);
}
/* reset for new line */
grp = 1;
b = buf;
}
if ( header ) {
if ( grp == 1 && hc <= 0 )
hc = header = 0;
}
else
d = d->next;
}
}
/* print last line (if incomplete) */
if ( grp > 1 ) {
/* trim extra spaces */
while ( *--b == ' ' )
;
if ( k ) {
*++b = '\n';
*++b = '\0';
queue_string(k, buf);
}
else {
*++b = '\0';
notify(w, buf);
}
}
b = buf;
if ( hidden_count > 0 ) {
sprintf(b, "Hidden Users%s: %d ",
( name_list[0] > 0 ) ? " Found" : "", hidden_count);
b = b + strlen(b);
}
sprintf(b, "Total Users%s: %d.",
( name_list[0] > 0 ) ? " Found" : "", total_count);
if ( k ) {
queue_string(k, "---\n");
queue_string(k, buf);
queue_string(k, "\n");
}
else {
notify(w, "---");
notify(w, buf);
}
}
char *time_format_1(dt)
time_t dt;
{
struct tm *delta;
static char buf[64];
if(dt < 0) dt = 0;
delta = gmtime(&dt);
if (delta->tm_yday > 0) {
sprintf(buf, "%dd %02d:%02d",
delta->tm_yday, delta->tm_hour, delta->tm_min);
} else {
sprintf(buf, "%02d:%02d",
delta->tm_hour, delta->tm_min);
}
return buf;
}
char *time_format_2(dt)
time_t dt;
{
register struct tm *delta;
static char buf[64];
if(dt < 0) dt = 0;
delta = gmtime(&dt);
if (delta->tm_yday > 0) {
sprintf(buf, "%dd", delta->tm_yday);
} else if (delta->tm_hour > 0) {
sprintf(buf, "%dh", delta->tm_hour);
} else if (delta->tm_min > 0) {
sprintf(buf, "%dm", delta->tm_min);
} else {
sprintf(buf, "%ds", delta->tm_sec);
}
return buf;
}
void announce_connect(player)
dbref player;
{
dbref loc;
char buf[BUFFER_LEN];
extern dbref speaker;
char *s, t[30]; /* we put this here instead of in connect_player cuz we gotta */
time_t tt; /* notify the player and the descriptor isn't set up yet then */
int connect_again = db[player].flags&PLAYER_CONNECT;
#ifdef USE_RWHO
time_t tv;
rwhocli_userlogin(tprintf("%d@%s",player,RWHO_MUSE_NAME),db[player].name,tv);
#endif
if ((loc = getloc(player)) == NOTHING) return;
if (connect_again)
sprintf(buf, "%s has reconnected.", db[player].name);
else
sprintf(buf, "%s has connected.", db[player].name);
/* added to allow player's inventory to hear a player connect */
speaker=player;
notify_in(player, player, buf);
if (!IS(loc,TYPE_ROOM,ROOM_AUDITORIUM))
notify_in(loc, player, buf);
db[player].flags|=PLAYER_CONNECT;
db[player].flags&=~HAVEN;
if (!Guest(player)) {
time(&tt);
strcpy(t,ctime(&tt));
t[strlen(t)-1]=0;
tt=atol(atr_get(player,A_LAST));
if ( tt == 0L )
s = "no previous login";
else {
s = ctime(&tt);
s[strlen(s)-1]=0;
if ((strncmp(t, s, 10) != 0) &&
power(player, POW_MEMBER) && db[player].owner == player) {
giveto(player, PAY_CHECK);
notify(player, tprintf("You collect %d credits.", PAY_CHECK));
}
}
notify(player,tprintf("Last login: %s", s));
time(&tt);
sprintf(buf, "%ld", tt);
atr_add(player,A_LAST,buf);
check_mail(player);
}
if (!connect_again) {
dbref thing;
dbref zone;
dbref who=player;
int depth;
int find=0;
did_it(who, who, NULL, NULL, A_OCONN, NULL, A_ACONN);
did_it(who, db[who].location, NULL, NULL, NULL, NULL, A_ACONN);
zone=db[0].zone;
if (Typeof(db[who].location) == TYPE_ROOM) {
zone=db[db[who].location].zone;
} else {
thing = db[who].location;
for (depth = 10; depth && (find != 1); depth--, thing = db[thing].location)
if (Typeof(thing) == TYPE_ROOM) {
zone=db[thing].zone;
find=1;
}
}
if ((db[0].zone != zone) && (Typeof(db[0].zone) != TYPE_PLAYER))
did_it(who, db[0].zone, NULL, NULL, NULL, NULL, A_ACONN);
if (Typeof(zone) != TYPE_PLAYER)
did_it(who, zone, NULL, NULL, NULL, NULL, A_ACONN);
if ((thing = db[who].contents) != NOTHING) {
DOLIST(thing,thing) {
if(Typeof(thing) != TYPE_PLAYER) {
did_it(who, thing, NULL, NULL, NULL, NULL, A_ACONN);
}
}
}
if ((thing = db[db[who].location].contents) != NOTHING) {
DOLIST(thing,thing) {
if(Typeof(thing) != TYPE_PLAYER) {
did_it(who, thing, NULL, NULL, NULL, NULL, A_ACONN);
}
}
}
}
}
void announce_disconnect(player)
dbref player;
{
dbref loc;
int num;
char buf[BUFFER_LEN];
struct descriptor_data *d;
extern dbref speaker;
int partial_disconnect;
if(player<0) return;
for(num=0,d=descriptor_list;d;d=d->next)
if (d->state==CONNECTED && (d->player>0) && (d->player==player))
num++;
if (num<2 && !shutdown_flag) {
db[player].flags&=~PLAYER_CONNECT;
atr_add(player,A_IT,"");
partial_disconnect = 0;
} else
partial_disconnect = 1;
#ifdef USE_RWHO
rwhocli_userlogout(tprintf("%d@%s",player,RWHO_MUSE_NAME));
#endif
if ((loc = getloc(player)) != NOTHING) {
if (partial_disconnect)
sprintf(buf, "%s has partially disconnected.", db[player].name);
else
sprintf(buf, "%s has disconnected.", db[player].name);
speaker=player;
/* added to allow player's inventory to hear a player connect */
notify_in(player, player, buf);
if(!IS(loc,TYPE_ROOM,ROOM_AUDITORIUM))
notify_in(loc, player, buf);
if (!partial_disconnect) {
dbref zone;
dbref thing;
dbref who=player;
int depth;
int find=0;
did_it(who, who, NULL, NULL, A_ODISC, NULL, A_ADISC);
did_it(who, db[who].location, NULL, NULL, NULL, NULL, A_ADISC);
zone=db[0].zone;
if (Typeof(db[who].location) == TYPE_ROOM) {
zone=db[db[who].location].zone;
} else {
thing = db[who].location;
for (depth = 10; depth && (find != 1); depth--, thing = db[thing].location)
if (Typeof(thing) == TYPE_ROOM) {
zone=db[thing].zone;
find=1;
}
}
if ((db[0].zone != zone) && (Typeof(db[0].zone) != TYPE_PLAYER))
did_it(who, db[0].zone, NULL, NULL, NULL, NULL, A_ADISC);
if (Typeof(zone) != TYPE_PLAYER)
did_it(who, zone, NULL, NULL, NULL, NULL, A_ADISC);
if ((thing = db[who].contents) != NOTHING) {
DOLIST(thing,thing) {
if(Typeof(thing) != TYPE_PLAYER) {
did_it(who, thing, NULL, NULL, NULL, NULL, A_ADISC);
}
}
}
if ((thing = db[db[who].location].contents) != NOTHING) {
DOLIST(thing,thing) {
if(Typeof(thing) != TYPE_PLAYER) {
did_it(who, thing, NULL, NULL, NULL, NULL, A_ADISC);
}
}
}
}
}
}
#if defined(HPUX) || defined(SYSV)
#include <unistd.h>
int getdtablesize()
{
return (int) sysconf(_SC_OPEN_MAX);
}
#endif
#ifdef SYSV
void setlinebuf(x)
FILE *x;
{
setbuf(x,NULL);
}
int vfork()
{
return fork();
}
#endif
struct ctrace_int {
struct descriptor_data *des;
struct ctrace_int **children;
};
static struct ctrace_int *internal_ctrace(parent)
struct descriptor_data *parent;
{
struct descriptor_data *k;
struct ctrace_int *op;
extern NALLOC *glurp;
int nchild;
op=na_alloc(glurp,sizeof(struct ctrace_int));
op->des=parent;
if(parent && !(parent->cstatus&C_CCONTROL)) {
op->children=na_alloc(glurp,sizeof(struct ctrace_int *));
op->children[0]=0;
} else {
for(nchild=0,k=descriptor_list;k;k=k->next)
if(k->parent == parent)
nchild++;
op->children=na_alloc(glurp,sizeof(struct ctrace_int *)*(nchild+1));
for(nchild=0,k=descriptor_list;k;k=k->next)
if(k->parent==parent) {
op->children[nchild]=internal_ctrace(k);
nchild++; }
op->children[nchild]=0; }
return op;
}
static void ctrace_notify_internal(player,d,dep)
dbref player;
struct ctrace_int *d;
int dep;
{
char buf[2000];
int j,k;
for(j=0;j<dep;j++)
buf[j]='.';
if(d->des && dep) {
sprintf(buf+j,"%s descriptor: %d, concid: %d, host: %s",
(d->des->state==CONNECTED)
?(tprintf("\"%s\"",unparse_object(player,d->des->player)))
:((d->des->cstatus&C_CCONTROL)
?"<Concentrator Control>"
:"<Unconnected>"),
d->des->descriptor, d->des->concid,
d->des->addr);
notify(player,buf);
}
for(k=0;d->children[k];k++)
ctrace_notify_internal(player,d->children[k],dep+1);
}
void do_ctrace(player)
dbref player;
{
struct ctrace_int *dscs;
if(!power(player,POW_HOST)) {
notify(player,"Sorry.");
return;
}
dscs=internal_ctrace(0);
ctrace_notify_internal(player,dscs,0);
}
#ifdef RESOCK
void resock()
{
log_io("resocking...");
close(sock);
sock = make_socket(TINYPORT);
log_io("resocking done");
}
#endif