/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/interface.c,v 1.13 90/09/28 12:23:15 rearl Exp $ */ /* * $Log: interface.c,v $ * Revision 1.13 90/09/28 12:23:15 rearl * Fixed @boot bug! Finally! * * Revision 1.12 90/09/16 04:42:16 rearl * Preparation code added for disk-based MUCK. * * Revision 1.11 90/09/15 22:23:23 rearl * Fixed non-HOSTNAMES problem. Well, problems. * * Revision 1.10 90/09/13 06:25:47 rearl * Changed boot_off() a bit in hopes of finding the bug... * * Revision 1.9 90/09/10 02:19:00 rearl * Changed NL line termination to CR/LF pairs. * * Revision 1.8 90/09/04 18:43:55 rearl * Fixed bug with connecting players. * * Revision 1.7 90/08/27 03:27:03 rearl * Fixed dump_status logging. * * Revision 1.6 90/08/15 03:02:23 rearl * Took out #ifdef CONNECT_MESSAGES. * * Revision 1.5 90/08/02 18:46:38 rearl * Fixed calls to log functions. * * Revision 1.4 90/07/29 17:35:28 rearl * Some minor fix-ups, most notably, gives number of players connected * in the WHO list (dump_users()). * * Revision 1.3 90/07/23 14:52:33 casie * *** empty log message *** * * Revision 1.2 90/07/21 01:40:25 casie * corrected a bug with the log_status function call. * * Revision 1.1 90/07/19 23:03:42 casie * Initial revision * * */ #include "copyright.h" #include "config.h" #include <stdio.h> #include <sys/types.h> #include <sys/file.h> #include <signal.h> #include <sys/ioctl.h> #include <sys/wait.h> #include <fcntl.h> #include <sys/errno.h> #include <ctype.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include "db.h" #include "interface.h" #include "params.h" int shutdown_flag = 0; static const char *connect_fail = "Either that player does not exist, or has a different password.\r\n"; #ifndef REGISTRATION static const char *create_fail = "Either there is already a player with that name, or that name is illegal.\r\n"; #endif /* REGISTRATION */ static const char *flushed_message = "<Output Flushed>\r\n"; static const char *shutdown_message = "\r\n\r\n *** Shutdown now! Back to RL! ***\r\n\r\n"; static int sock; static int ndescriptors = 0; struct descriptor_data *descriptor_list = 0; void process_commands(); void shovechars(int); void shutdownsock(struct descriptor_data *); struct descriptor_data * initializesock(int, const char *); void make_nonblocking(int); void freeqs(struct descriptor_data *); void welcome_user(struct descriptor_data *); void check_connect(struct descriptor_data *, const char *); void close_sockets(); int boot_off(dbref); const char * addrout (long); void dump_users(struct descriptor_data *, char *); void set_signals(void); struct descriptor_data *new_connection(int); void parse_connect (const char *, char *, char *, char *); void set_userstring (char **, const char *); int do_command (struct descriptor_data *, char *); char * strsave (const char *); int make_socket(int); int queue_string(struct descriptor_data *, const char *); int queue_write(struct descriptor_data *, const char *, int); int process_output(struct descriptor_data *); int process_input(struct descriptor_data *); int bailout(int); void make_sigio(); void announce_connect(dbref); void announce_disconnect(dbref); char * time_format_1(long); char * time_format_2(long); void inc_gotio(); #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)) int check_awake(dbref player) { struct descriptor_data *d; int retval = 0; for(d = descriptor_list; d; d = d->next) { if (d->connected && d->player == player) retval++; } return retval; } #ifndef BOOLEXP_DEBUGGING void main(int argc, char **argv) { if (argc < 3) { fprintf (stderr, "Usage: %s infile dumpfile [port]\n", *argv); exit (1); } log_status("INIT: TinyMAGE %s starting.\n", "version"); sock=make_socket(argc>=4?atoi(argv[3]):TINYPORT); if (init_game (argv[1], argv[2]) < 0) { fprintf (stderr, "Couldn't load %s!\n", argv[1]); exit (2); } startup_time = time(NULL); set_signals (); #ifdef MUD_ID do_setuid(); #endif /* MUD_ID */ /* go do it */ shovechars (argc >= 4 ? atoi (argv[3]) : TINYPORT); close_sockets (); dump_database (); exit (0); } #endif /*BOOLEXP_DEBUGGING*/ void set_signals(void) { 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, (void *) bailout); signal (SIGTERM, (void *) bailout); /* catch these because we might as well */ signal (SIGQUIT, (void *) bailout); signal (SIGTRAP, (void *) bailout); signal (SIGIOT, (void *) bailout); signal (SIGEMT, (void *) bailout); signal (SIGFPE, (void *) bailout); signal (SIGBUS, (void *) bailout); signal (SIGSEGV, (void *) bailout); signal (SIGSYS, (void *) bailout); signal (SIGTERM, (void *) bailout); signal (SIGXCPU, (void *) bailout); signal (SIGXFSZ, (void *) bailout); signal (SIGVTALRM, (void *) bailout); signal (SIGUSR2, (void *) bailout); /* status dumper (predates "WHO" command) */ signal (SIGUSR1, (void *) dump_status); /* Okay, now set up the sigo thing to increment the GOTIO var.. */ { signal(SIGIO, (void *) inc_gotio); } } void inc_gotio() { gotio = 1; } int notify_internal(dbref player, const char *msg) { struct descriptor_data *d; int retval = 0; /* msg = get_uncompress(msg); */ for(d = descriptor_list; d; d = d->next) { if (d->connected && d->player == player) { if(msg) { queue_string(d, msg); queue_write(d, "\r\n", 2); } retval++; } } return retval; } struct timeval timeval_sub(struct timeval now, struct timeval then) { now.tv_sec -= then.tv_sec; now.tv_usec -= then.tv_usec; if (now.tv_usec < 0) { now.tv_usec += 1000000; now.tv_sec--; } return now; } int msec_diff(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(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(struct timeval last, struct timeval current) { int nslices; int cmds_per_time; struct descriptor_data *d; nslices = msec_diff (current, last) / COMMAND_TIME_MSEC; if (nslices > 0) { for (d = descriptor_list; d; d = d -> next) { if (d -> connected) { cmds_per_time = ((FLAGS(d->player) & INTERACTIVE) ? (COMMANDS_PER_TIME * 6) : COMMANDS_PER_TIME); } else { cmds_per_time = COMMANDS_PER_TIME; } d -> quota += cmds_per_time * nslices; if (d -> quota > COMMAND_BURST_SIZE) d -> quota = COMMAND_BURST_SIZE; } } return msec_add (last, nslices * COMMAND_TIME_MSEC); } int maxd; struct descriptor_data *newd; fd_set input_set, output_set; void shovechars(int port) { long now; struct timeval last_slice, current_time; struct timeval next_slice; struct timeval timeout, slice_timeout; struct descriptor_data *d, *dnext; int avail_descriptors; maxd = sock+1; gettimeofday(&last_slice, (struct timezone *) 0); avail_descriptors = getdtablesize() - 4; while (shutdown_flag == 0) { gettimeofday(¤t_time, (struct timezone *) 0); last_slice = update_quotas (last_slice, current_time); process_commands(); if (shutdown_flag) break; timeout.tv_sec = que_check()?0:1; /* changed from 1000 for objects. */ timeout.tv_usec = que_check()?10000:0; 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) FD_SET (sock, &input_set); for (d = descriptor_list; d; d=d->next) { if (d->input.head) timeout = slice_timeout; else FD_SET (d->descriptor, &input_set); if (d->output.head) FD_SET (d->descriptor, &output_set); } if (select (maxd, &input_set, &output_set, (fd_set *) 0, &timeout) < 0) { if (errno != EINTR) { perror ("select"); return; } } else { (void) time ((time_t *)&now); if (FD_ISSET (sock, &input_set)) { if (!(newd = new_connection (sock))) { if (errno && errno != EINTR && errno != EMFILE && errno != ENFILE) { perror ("new_connection"); return; } } 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->last_time = now; if (!process_input (d)) { shutdownsock (d); continue; } } if (FD_ISSET (d->descriptor, &output_set)) { if (!process_output (d)) { shutdownsock (d); } } } } } } struct descriptor_data *new_connection(int sock) { int newsock; struct sockaddr_in addr; int addr_len; char hostname[128]; addr_len = sizeof (addr); newsock = accept (sock, (struct sockaddr *) & addr, &addr_len); if (newsock < 0) { return 0; #ifdef LOCKOUT } else if(forbidden_site(ntohl(addr.sin_addr.s_addr))) { log_status("REFUSED: connection from %s(%d) on descriptor %d\n", addrout(ntohl (addr.sin_addr.s_addr)), ntohs(addr.sin_port), newsock); shutdown(newsock, 2); close(newsock); errno = 0; return 0; #endif /* LOCKOUT */ } else { strcpy (hostname, addrout (addr.sin_addr.s_addr)); log_status("ACCEPT: %s(%d) on descriptor %d\n", hostname, ntohs (addr.sin_port), newsock); return initializesock (newsock, hostname); } } const char *addrout(long a) { static char buf[32]; #ifdef HOSTNAMES struct hostent *he; he = gethostbyaddr(&a, sizeof(a), AF_INET); if (he) return he->h_name; else #endif /* HOSTNAMES */ a = ntohl(a); sprintf (buf, "%d.%d.%d.%d", (a >> 24) & 0xff, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff); return buf; } void clearstrings(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(struct descriptor_data *d) { if (d->connected) { log_status ("DISCONNECT: descriptor %d player %s(%d)\n", d->descriptor, NAME(d->player), d->player); announce_disconnect (d->player); } else { log_status ("DISCONNECT: descriptor %d never connected.\n", d->descriptor); } clearstrings (d); shutdown (d->descriptor, 2); close (d->descriptor); freeqs (d); *d->prev = d->next; if (d->next) d->next->prev = d->prev; FREE (d); ndescriptors--; } struct descriptor_data *initializesock(int s, const char *hostname) { struct descriptor_data *d; ndescriptors++; MALLOC(d, struct descriptor_data, 1); d->descriptor = s; d->connected = 0; make_nonblocking (s); make_sigio (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; d->hostname = alloc_string(hostname); if (descriptor_list) descriptor_list->prev = &d->next; d->next = descriptor_list; d->prev = &descriptor_list; descriptor_list = d; d->connected_at=time(NULL); welcome_user (d); return d; } int make_socket(int port) { int s; struct sockaddr_in server; int opt; s = socket (AF_INET, SOCK_STREAM, 0); if (s < 0) { perror ("creating stream socket"); exit (3); } opt = 1; if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof (opt)) < 0) { perror ("setsockopt"); exit (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); exit (4); } listen (s, 5); return s; } struct text_block *make_text_block(const 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 (struct text_block *t) { FREE (t->buf); FREE ((char *) t); } void add_to_queue(struct text_queue *q, const 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(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(struct descriptor_data *d, const char *b, int n) { int space; 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(struct descriptor_data *d, const char *s) { return queue_write (d, s, strlen (s)); } int process_output(struct descriptor_data *d) { struct text_block **qp, *cur; int cnt; 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(int s) { if (fcntl (s, F_SETFL, FNDELAY) == -1) { perror ("make_nonblocking: fcntl"); panic ("FNDELAY fcntl failed"); } } void make_sigio(int s) { if(fcntl(s,F_SETFL,FASYNC) == -1) { perror("make_sigo: fcntl"); panic("FASYNC fcntl failed."); } } void freeqs(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 goodbye_user(struct descriptor_data *d) { write (d->descriptor, LEAVE_MESSAGE, strlen (LEAVE_MESSAGE)); } char *strsave (const char *s) { char *p; MALLOC (p, char, strlen(s) + 1); if (p) strcpy (p, s); return p; } void save_command (struct descriptor_data *d, const char *command) { add_to_queue (&d->input, command, strlen(command)+1); } int process_input (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 (char **userstring, const char *command) { if (*userstring) { FREE(*userstring); *userstring = 0; } while (*command && isascii (*command) && isspace (*command)) command++; if (*command) *userstring = strsave (command); } void process_commands(void) { int nprocessed; struct descriptor_data *d; struct text_block *t; do { nprocessed = 0; for (d = descriptor_list; d; d = d->next) { if (d -> quota > 0 && (t = d -> input.head)) { d -> quota--; nprocessed++; if (!do_command (d, t -> start)) { 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); check_waits(); /* check the wait things. */ } int do_command (struct descriptor_data *d, char *command) { if (!strcmp (command, QUIT_COMMAND)) { goodbye_user (d); return 0; } else if (!strncmp (command, WHO_COMMAND, sizeof(WHO_COMMAND) - 1)) { if (d->output_prefix) { queue_string (d, d->output_prefix); queue_write (d, "\r\n", 2); } dump_users (d, command + sizeof(WHO_COMMAND) - 1); if (d->output_suffix) { queue_string (d, d->output_suffix); queue_write (d, "\r\n", 2); } } else if (!strncmp (command, PREFIX_COMMAND, sizeof (PREFIX_COMMAND) - 1)) { set_userstring (&d->output_prefix, command+sizeof(PREFIX_COMMAND) - 1); } else if (!strncmp (command, SUFFIX_COMMAND, sizeof (SUFFIX_COMMAND) - 1)) { set_userstring (&d->output_suffix, command+sizeof(SUFFIX_COMMAND) - 1); } else { if (d->connected) { if (d->output_prefix) { queue_string (d, d->output_prefix); queue_write (d, "\r\n", 2); } if(!string_compare(command, BREAK_COMMAND)) { FLAGS(d->player) |= HALTED; if(FLAGS(d->player)&INTERACTIVE) process_command (d->player, command, d->player, 0); } else if(FLAGS(d->player)&INTERACTIVE) { process_command (d->player, command, d->player, 0); } else if(!do_act(d->player, command, d->player)) { process_command (d->player, command, d->player, 0); } if (d->output_suffix) { queue_string (d, d->output_suffix); queue_write (d, "\r\n", 2); } } else { check_connect (d, command); } } return 1; } void interact_warn (dbref player) { char buf[BUFSIZ]; sprintf(buf, "*** %s ***", DBFETCH(player)->run ? "You are currently using a program. Use \"@Q\" to return to a more reasonable state of control." : (DBFETCH(player)->insert_mode ? "You are currently inserting MUF program text. Use \".\" to return to the editor, then \"quit\" if you wish to return to your regularly scheduled Muck universe." : "You are currently using the MUF program editor.")); notify(player, buf); } void check_connect (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)) { FILE *f; player = connect_player (user, password); if(f=fopen("data/nologin.txt","r")) { char buf[1024]; while(fgets(buf,sizeof(buf),f)) { queue_string(d,buf); } fclose(f); if(!Wizard(player)) player=NOTHING; } else if (player == NOTHING) { queue_string (d, connect_fail); log_status ("FAILED CONNECT %s on descriptor %d\n", user, d->descriptor); } if(player != NOTHING) { log_status ("CONNECTED: %s(%d) on descriptor %d\n", NAME(player), player, d->descriptor); d->connected = 1; d->connected_at = time(NULL); d->player = player; announce_connect (player); do_look_around (player); if(FLAGS(player)&INTERACTIVE) { interact_warn (player); } else { if(get_attr(GLOBAL_ENVIRONMENT, "Aconnect") && !Wizard(player)) trigobj(player, get_attr(GLOBAL_ENVIRONMENT, "Aconnect"), player); if(get_attr(player, "Aconnect")) trigobj(player, get_attr(player, "Aconnect"), player); } } } else if (!strncmp (command, "cr", 2)) { #ifndef REGISTRATION player = create_player (user, password); if (player == NOTHING) { queue_string (d, create_fail); log_status ("FAILED CREATE %s on descriptor %d\n", user, d->descriptor); } else { log_status ("CREATED %s(%d) on descriptor %d\n", NAME(player), player, d->descriptor); d->connected = 1; d->connected_at = time(NULL); d->player = player; announce_connect (player); do_look_around (player); } #else /* REGISTRATION */ queue_string (d, REG_MSG); log_status ("FAILED CREATE %s on descriptor %d\n", user, d->descriptor); #endif /* REGISTRATION */ } else { welcome_user (d); } } void parse_connect (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'; } int old_boot_off(dbref player) { struct descriptor_data *d; struct descriptor_data *next; for (d = descriptor_list; d; d = next) { next = d->next; if (d->connected && d->player == player) { process_output (d); shutdownsock(d); return 1; } } return 0; } int boot_loop(struct descriptor_data *d, dbref player) { if(!d) return 0; if(boot_loop(d->next,player)) return 1; if(d->connected && d->player == player) { process_output(d); shutdownsock(d); return 1; } return 0; } int dboot_loop(struct descriptor_data *d,int who) { if(!d) return 0; if(dboot_loop(d->next,who)) return 1; if(d->connected && d->descriptor == who) { process_output(d); shutdownsock(d); return 1; } return 0; } int dboot_off(int who) { return dboot_loop(descriptor_list,who);} int boot_off(dbref player) { return boot_loop(descriptor_list, player); } void close_sockets(void) { struct descriptor_data *d, *dnext; for (d = descriptor_list; d; d = dnext) { dnext = d->next; write (d->descriptor, shutdown_message, strlen (shutdown_message)); if (shutdown (d->descriptor, 2) < 0) perror ("shutdown"); close (d->descriptor); } close (sock); } void emergency_shutdown(void) { close_sockets(); } int bailout(int sig) { char message[1024]; sprintf (message, "BAILOUT: caught signal %d", sig); panic(message); _exit (7); return 0; } int dump_status(void) { struct descriptor_data *d; long now; char buf[BUFSIZ]; (void) time ((time_t *)&now); log_status ("STATUS REPORT:\n"); for (d = descriptor_list; d; d = d->next) { if (d->connected) { sprintf(buf, "PLAYING descriptor %d player %s(%d) from host %s, %s.\n", d->descriptor, NAME(d->player), d->player, d->hostname, (d->last_time) ? "idle %d seconds" : "never used"); } else { sprintf(buf, "CONNECTING descriptor %d from host %s, %s.\n", d->descriptor, d->hostname, (d->last_time) ? "idle %d seconds" : "never used"); } log_status (buf, now - d->last_time); } return 0; } void dump_users(struct descriptor_data *e, char *user) { struct descriptor_data *d; int wizard, players; long now; static char pbuf[BUFFER_LEN]; #ifdef GOD_MODE wizard = e->connected && God (e->player); #else /* All wizards may see extended WHO */ wizard = e->connected && Wizard (e->player); #endif /* GOD_MODE */ /* queue_string(e,"Sorry, who is broken. use small instead.\r\n"); return;*/ puts("1."); while (*user && isspace(*user)) user++; if (!*user) user = NULL; (void) time ((time_t *)&now); queue_string (e, (wizard) ? #ifdef HOSTNAMES "FD Player Name Location On For Idle Host\r\n" #else /* !HOSTNAMES */ "FD Player Name Location On For Idle Host\r\n" #endif /* HOSTNAMES */ : "Player Name On For Idle\r\n"); d = descriptor_list; players = 0; puts("2"); while (d) { if (d->connected && ++players && (!user || string_prefix(NAME(d->player), user))) { if (wizard) { puts("3"); #ifdef HOSTNAMES /* Don't print flags to save space */ sprintf(pbuf, "%.*s(#%d)", PLAYER_NAME_LIMIT, NAME(d->player), (int) d->player); #else /* !HOSTNAMES */ strcpy(pbuf, unparse_object(e->player, d->player)); #endif /* HOSTNAMES */ sprintf(buf,"%-3d%-*s [%6d] %10s %4s %-.26s\r\n", d->descriptor, PLAYER_NAME_LIMIT + #ifdef HOSTNAMES /* Ack! */ 9 #else /* !HOSTNAMES */ 19 #endif /* HOSTNAMES */ , pbuf, (int) DBFETCH(d->player)->location, time_format_1(now - d->connected_at), d->last_time?time_format_2(now - d->last_time):"--", d->hostname); } else { sprintf(buf, "%-*s %10s %4s\r\n", PLAYER_NAME_LIMIT, NAME(d->player), time_format_1(now - d->connected_at), time_format_2(now - d->last_time)); } queue_string (e, buf); puts("4"); if(wizard && !d->connected) { puts("5"); sprintf(buf,"%-3d%-*s [%6s] %10s %4s %s\r\n", d->descriptor, PLAYER_NAME_LIMIT + #ifdef HOSTNAMES 9 #else 19 #endif ,"","", time_format_1(now-d->connected_at), time_format_2(now-d->last_time), d->hostname); queue_string(e,buf); puts("6"); } } d = d->next; puts("7"); } puts("8"); sprintf(buf, "%d player%s %s connected. Uptime: %s\r\n", players, (players == 1) ? "" : "s", (players == 1) ? "is" : "are", time_format_1(now - startup_time)); /* add uptime to WHO */ puts("9"); queue_string (e, buf); puts("10"); } char *time_format_1(long dt) { register struct tm *delta; static char buf[BUFFER_LEN]; delta = gmtime((time_t *)&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(long dt) { register struct tm *delta; static char buf[BUFFER_LEN]; delta = gmtime((time_t *)&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(dbref player) { dbref loc; char buf[BUFFER_LEN]; global_trigger = player; if ((loc = getloc(player)) == NOTHING) return; if (Dark(player) || Dark(loc)) return; if(get_attr(player, "Oconnect")) sprintf(buf, "%s %s", NAME(player), get_attr(player, "Oconnect")); else sprintf(buf, "%s has connected.", NAME(player)); notify_except(DBFETCH(loc)->contents, player, buf); notify_except(DBFETCH(player)->contents, player, buf); } void announce_disconnect(dbref player) { dbref loc; char buf[BUFFER_LEN]; global_trigger=player; if ((loc = getloc(player)) == NOTHING) return; if (Dark(player) || Dark(loc)) return; if(get_attr(player, "Odisconnect")) sprintf(buf, "%s %s", NAME(player), get_attr(player, "Odisconnect")); else sprintf(buf, "%s has disconnected.", NAME(player)); notify_except(DBFETCH(loc)->contents, player, buf); notify_except(DBFETCH(player)->contents,player,buf); } #ifdef MUD_ID void do_setuid(char *name) { #include <pwd.h> struct passwd *pw; if ((pw = getpwnam(name)) == NULL) { log_status("can't get pwent for %s\n", name); exit(1); } if (setuid(pw->pw_uid) == -1) { log_status("can't setuid(%d): ", pw->pw_uid); perror("setuid"); exit(1); } } #endif /* MUD_ID */ void welcome_user(struct descriptor_data *d) { FILE *f; char buf[BUFFER_LEN]; if((f = fopen(WELC_FILE, "r")) == NULL) { queue_string (d, DEFAULT_WELCOME_MESSAGE); perror("spit_file: welcome.txt"); } else { while(fgets(buf, sizeof buf, f)) { queue_string(d, buf); } fclose(f); } } void do_dboot(dbref who,char *what) { if(!what || !*what) { notify(who, "Usage: @dboot <descriptor #>"); return; } if(!Wizard(who)) { notify(who,"Only a Wizard can boot someone off."); return; } dboot_off(atoi(what)); sprintf(buf, "Descriptor %d booted.", atoi(what)); notify(who, buf); } void db_loadsend(const char *msg) { struct descriptor_data *d; if (FD_ISSET (sock, &input_set)) { if (!(newd = new_connection (sock))) { if (errno && errno != EINTR && errno != EMFILE && errno != ENFILE) { perror ("new_connection"); return; } else { if (newd->descriptor >= maxd) maxd = newd->descriptor + 1; } } } for(d=descriptor_list;d;d=d->next) { queue_string(d,msg); queue_write(d,"\r\n",2); } }