/* netcommon.c */ /* $Id: netcommon.c,v 1.81 2002/10/10 23:56:47 rmg Exp $ */ /* This file contains routines used by the networking code that do not * depend on the implementation of the networking code. The network-specific * portions of the descriptor data structure are not used. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "alloc.h" /* required by mudconf */ #include "flags.h" /* required by mudconf */ #include "htab.h" /* required by mudconf */ #include "mudconf.h" /* required by code */ #include "db.h" /* required by externs */ #include "externs.h" /* required by interface */ #include "interface.h" /* required by code */ #include "file_c.h" /* required by code */ #include "command.h" /* required by code */ #include "attrs.h" /* required by code */ #include "ansi.h" /* required by code */ #include "powers.h" /* required by code */ #include "match.h" /* required by code */ extern int FDECL(process_output, (DESC * d)); extern void FDECL(handle_prog, (DESC *, char *)); extern void FDECL(record_login, (dbref, int, char *, char *, char *)); extern dbref FDECL(connect_player, (char *, char *, char *, char *, char *)); extern char * FDECL(make_guest, (DESC *)); extern const char *conn_reasons[]; extern const char *conn_messages[]; #ifdef CONCENTRATE extern void FDECL(do_becomeconc, (DESC *, char *)); extern void FDECL(do_makeid, (DESC *)); extern void FDECL(do_connectid, (DESC *, long int, char *)); extern void FDECL(do_killid, (DESC *, long int)); #endif /* --------------------------------------------------------------------------- * timeval_sub: return difference between two times as a timeval */ struct timeval timeval_sub(now, then) struct timeval now, 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; } /* --------------------------------------------------------------------------- * msec_diff: return difference between two times in milliseconds */ int msec_diff(now, then) struct timeval now, then; { return ((now.tv_sec - then.tv_sec) * 1000 + (now.tv_usec - then.tv_usec) / 1000); } /* --------------------------------------------------------------------------- * msec_add: add milliseconds to a timeval */ 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; } /* --------------------------------------------------------------------------- * update_quotas: Update timeslice quotas */ struct timeval update_quotas(last, current) struct timeval last, current; { int nslices; DESC *d; nslices = msec_diff(current, last) / mudconf.timeslice; if (nslices > 0) { DESC_ITER_ALL(d) { d->quota += mudconf.cmd_quota_incr * nslices; if (d->quota > mudconf.cmd_quota_max) d->quota = mudconf.cmd_quota_max; } } return msec_add(last, nslices * mudconf.timeslice); } #ifdef PUEBLO_SUPPORT /* raw_notify_html() -- raw_notify() without the newline */ void raw_notify_html(player, msg) dbref player; char *msg; { DESC *d; if (!msg || !*msg) return; if (mudstate.inpipe && (player == mudstate.poutobj)) { safe_str(msg, mudstate.poutnew, &mudstate.poutbufc); return; } if (!Connected(player)) return; if (!Html(player)) /* Don't splooge HTML at a non-HTML player. */ return; DESC_ITER_PLAYER(player, d) { queue_string(d, msg); } } #endif /* --------------------------------------------------------------------------- * raw_notify: write a message to a player */ void raw_notify(player, msg) dbref player; char *msg; { DESC *d; if (!msg || !*msg) return; if (mudstate.inpipe && (player == mudstate.poutobj)) { safe_str(msg, mudstate.poutnew, &mudstate.poutbufc); safe_crlf(mudstate.poutnew, &mudstate.poutbufc); return; } if (!Connected(player)) return; DESC_ITER_PLAYER(player, d) { queue_string(d, msg); queue_write(d, "\r\n", 2); } } void raw_notify_newline(player) dbref player; { DESC *d; if (mudstate.inpipe && (player == mudstate.poutobj)) { safe_crlf(mudstate.poutnew, &mudstate.poutbufc); return; } if (!Connected(player)) return; DESC_ITER_PLAYER(player, d) { queue_write(d, "\r\n", 2); } } /* --------------------------------------------------------------------------- * raw_broadcast: Send message to players who have indicated flags */ #if defined(__STDC__) && defined(STDC_HEADERS) void raw_broadcast(int inflags, char *template,...) #else void raw_broadcast(va_alist) va_dcl #endif { #ifdef HAVE_VSNPRINTF char buff[LBUF_SIZE]; #else char buff[20000]; #endif DESC *d; int test_flag, which_flag, p_flag; va_list ap; #if defined(__STDC__) && defined(STDC_HEADERS) va_start(ap, template); #else int inflags; char *template; va_start(ap); inflags = va_arg(ap, int); template = va_arg(ap, char *); #endif if (!template || !*template) return; #ifdef HAVE_VSNPRINTF vsnprintf(buff, LBUF_SIZE, template, ap); #else vsprintf(buff, template, ap); #endif /* Note that this use of the flagwords precludes testing for * type in this function. (Not that this matters, since we * look at connected descriptors, which must be players.) */ test_flag = inflags & ~(FLAG_WORD2 | FLAG_WORD3); if (inflags & FLAG_WORD2) which_flag = 2; else if (inflags & FLAG_WORD3) which_flag = 3; else which_flag = 1; DESC_ITER_CONN(d) { switch (which_flag) { case 1: p_flag = Flags(d->player); break; case 2: p_flag = Flags2(d->player); break; case 3: p_flag = Flags3(d->player); break; default: p_flag = Flags(d->player); } /* If inflags is 0, broadcast to everyone */ if ((p_flag & test_flag) || (!test_flag)) { queue_string(d, buff); queue_write(d, "\r\n", 2); process_output(d); } } va_end(ap); } /* --------------------------------------------------------------------------- * clearstrings: clear out prefix and suffix strings */ void clearstrings(d) DESC *d; { if (d->output_prefix) { free_lbuf(d->output_prefix); d->output_prefix = NULL; } if (d->output_suffix) { free_lbuf(d->output_suffix); d->output_suffix = NULL; } } /* --------------------------------------------------------------------------- * queue_write: Add text to the output queue for the indicated descriptor. */ void queue_write(d, b, n) DESC *d; const char *b; int n; { int left; TBLOCK *tp; if (n <= 0) return; if (d->output_size + n > mudconf.output_limit) process_output(d); left = mudconf.output_limit - d->output_size - n; if (left < 0) { tp = d->output_head; if (tp == NULL) { STARTLOG(LOG_PROBLEMS, "QUE", "WRITE") log_printf("Flushing when output_head is null!"); ENDLOG } else { STARTLOG(LOG_NET, "NET", "WRITE") log_printf("[%d/%s] Output buffer overflow, %d chars discarded by ", d->descriptor, d->addr, tp->hdr.nchars); log_name(d->player); ENDLOG d->output_size -= tp->hdr.nchars; d->output_head = tp->hdr.nxt; d->output_lost += tp->hdr.nchars; if (d->output_head == NULL) d->output_tail = NULL; XFREE(tp, "queue_write.tp"); } } /* Allocate an output buffer if needed */ if (d->output_head == NULL) { tp = (TBLOCK *) XMALLOC(OUTPUT_BLOCK_SIZE, "queue_write"); tp->hdr.nxt = NULL; tp->hdr.start = tp->data; tp->hdr.end = tp->data; tp->hdr.nchars = 0; d->output_head = tp; d->output_tail = tp; } else { tp = d->output_tail; } /* Now tp points to the last buffer in the chain */ d->output_size += n; d->output_tot += n; do { /* See if there is enough space in the buffer to hold the * string. If so, copy it and update the pointers.. */ left = OUTPUT_BLOCK_SIZE - (tp->hdr.end - (char *)tp + 1); if (n <= left) { strncpy(tp->hdr.end, b, n); tp->hdr.end += n; tp->hdr.nchars += n; n = 0; } else { /* It didn't fit. Copy what will fit and then * allocate * another buffer and retry. */ if (left > 0) { strncpy(tp->hdr.end, b, left); tp->hdr.end += left; tp->hdr.nchars += left; b += left; n -= left; } tp = (TBLOCK *) XMALLOC(OUTPUT_BLOCK_SIZE, "queue_write.2"); tp->hdr.nxt = NULL; tp->hdr.start = tp->data; tp->hdr.end = tp->data; tp->hdr.nchars = 0; d->output_tail->hdr.nxt = tp; d->output_tail = tp; } } while (n > 0); } INLINE void queue_string(d, s) DESC *d; const char *s; { char *new; if (s) { if (!mudconf.ansi_colors) { queue_write(d, s, strlen(s)); } else { if (!Ansi(d->player) && strchr(s, ESC_CHAR)) new = strip_ansi(s); else if (NoBleed(d->player)) new = normal_to_white(s); else new = (char *) s; queue_write(d, new, strlen(new)); } } } INLINE void queue_rawstring(d, s) DESC *d; const char *s; { if (s) queue_write(d, s, strlen(s)); } void freeqs(d) DESC *d; { TBLOCK *tb, *tnext; CBLK *cb, *cnext; tb = d->output_head; while (tb) { tnext = tb->hdr.nxt; XFREE(tb, "freeqs.tb"); tb = tnext; } d->output_head = NULL; d->output_tail = NULL; cb = d->input_head; while (cb) { cnext = (CBLK *) cb->hdr.nxt; free_lbuf(cb); cb = cnext; } d->input_head = NULL; d->input_tail = NULL; if (d->raw_input) free_lbuf(d->raw_input); d->raw_input = NULL; d->raw_input_at = NULL; } /* --------------------------------------------------------------------------- * desc_addhash: Add a net descriptor to its player hash list. */ void desc_addhash(d) DESC *d; { dbref player; DESC *hdesc; player = d->player; hdesc = (DESC *) nhashfind((int)player, &mudstate.desc_htab); if (hdesc == NULL) { d->hashnext = NULL; nhashadd((int)player, (int *)d, &mudstate.desc_htab); } else { d->hashnext = hdesc; nhashrepl((int)player, (int *)d, &mudstate.desc_htab); } } /* --------------------------------------------------------------------------- * desc_delhash: Remove a net descriptor from its player hash list. */ static void desc_delhash(d) DESC *d; { DESC *hdesc, *last; dbref player; player = d->player; last = NULL; hdesc = (DESC *) nhashfind((int)player, &mudstate.desc_htab); while (hdesc != NULL) { if (d == hdesc) { if (last == NULL) { if (d->hashnext == NULL) { nhashdelete((int)player, &mudstate.desc_htab); } else { nhashrepl((int)player, (int *)d->hashnext, &mudstate.desc_htab); } } else { last->hashnext = d->hashnext; } break; } last = hdesc; hdesc = hdesc->hashnext; } d->hashnext = NULL; } void welcome_user(d) DESC *d; { #ifdef PUEBLO_SUPPORT queue_rawstring(d, PUEBLO_SUPPORT_MSG); #endif if (d->host_info & H_REGISTRATION) fcache_dump(d, FC_CONN_REG); else fcache_dump(d, FC_CONN); } void save_command(d, command) DESC *d; CBLK *command; { command->hdr.nxt = NULL; if (d->input_tail == NULL) d->input_head = command; else d->input_tail->hdr.nxt = command; d->input_tail = command; } static void set_userstring(userstring, command) char **userstring; const char *command; { while (*command && isascii(*command) && isspace(*command)) command++; if (!*command) { if (*userstring != NULL) { free_lbuf(*userstring); *userstring = NULL; } } else { if (*userstring == NULL) { *userstring = alloc_lbuf("set_userstring"); } strcpy(*userstring, command); } } static void parse_connect(msg, command, user, pass) const char *msg; char *command, *user, *pass; { char *p; if (strlen(msg) > MBUF_SIZE) { *command = '\0'; *user = '\0'; *pass = '\0'; return; } 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; if (mudconf.name_spaces && (*msg == '\"')) { for (; *msg && (*msg == '\"' || isspace(*msg)); msg++) ; while (*msg && *msg != '\"') { while (*msg && !isspace(*msg) && (*msg != '\"')) *p++ = *msg++; if (*msg == '\"') break; while (*msg && isspace(*msg)) msg++; if (*msg && (*msg != '\"')) *p++ = ' '; } for (; *msg && *msg == '\"'; msg++) ; } else 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'; } static const char *time_format_1(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 %02d:%02d", delta->tm_yday, delta->tm_hour, delta->tm_min); } else { sprintf(buf, "%02d:%02d", delta->tm_hour, delta->tm_min); } return buf; } static const 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; } static void announce_connattr(player, loc, reason, num, attr) dbref player, loc; const char *reason; int num, attr; { dbref aowner, obj, zone; int aflags, alen; char *buf; char *argv[2]; argv[0] = (char *)reason; argv[1] = alloc_sbuf("announce_connchange.num"); sprintf(argv[1], "%d", num); buf = atr_pget(player, attr, &aowner, &aflags, &alen); if (*buf) wait_que(player, player, 0, NOTHING, 0, buf, argv, 2, NULL); free_lbuf(buf); if (Good_loc(mudconf.master_room) && mudconf.use_global_aconn) { buf = atr_pget(mudconf.master_room, attr, &aowner, &aflags, &alen); if (*buf) wait_que(mudconf.master_room, player, 0, NOTHING, 0, buf, argv, 2, NULL); free_lbuf(buf); DOLIST(obj, Contents(mudconf.master_room)) { if (!mudconf.global_aconn_uselocks || could_doit(player, obj, A_LUSE)) { buf = atr_pget(obj, attr, &aowner, &aflags, &alen); if (*buf) { wait_que(obj, player, 0, NOTHING, 0, buf, argv, 2, NULL); } free_lbuf(buf); } } } /* do the zone of the player's location's possible a(dis)connect */ if (mudconf.have_zones && ((zone = Zone(loc)) != NOTHING)) { switch (Typeof(zone)) { case TYPE_THING: buf = atr_pget(zone, attr, &aowner, &aflags, &alen); if (*buf) { wait_que(zone, player, 0, NOTHING, 0, buf, argv, 2, NULL); } free_lbuf(buf); break; case TYPE_ROOM: /* check every object in the room for a (dis)connect * action */ DOLIST(obj, Contents(zone)) { buf = atr_pget(obj, attr, &aowner, &aflags, &alen); if (*buf) { wait_que(obj, player, 0, NOTHING, 0, buf, argv, 2, NULL); } free_lbuf(buf); } break; default: STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG") log_printf("Invalid zone #%d for ", zone); log_name(player); log_printf(" has bad type %d", Typeof(zone)); ENDLOG } } free_sbuf(argv[1]); } static void announce_connect(player, d, reason) dbref player; DESC *d; const char *reason; { dbref loc, aowner, temp; int aflags, alen, num, key, count; char *buf, *time_str; DESC *dtemp; desc_addhash(d); count = 0; DESC_ITER_CONN(dtemp) count++; if (mudstate.record_players < count) mudstate.record_players = count; buf = atr_pget(player, A_TIMEOUT, &aowner, &aflags, &alen); d->timeout = atoi(buf); if (d->timeout <= 0) d->timeout = mudconf.idle_timeout; free_lbuf(buf); loc = Location(player); s_Connected(player); #ifdef PUEBLO_SUPPORT if (d->flags & DS_PUEBLOCLIENT) { s_Html(player); } #endif if (*mudconf.motd_msg) { if (mudconf.ansi_colors) { raw_notify(player, tprintf("\n%sMOTD:%s %s\n", ANSI_HILITE, ANSI_NORMAL, mudconf.motd_msg)); } else { raw_notify(player, tprintf("\nMOTD: %s\n", mudconf.motd_msg)); } } if (Wizard(player)) { if (*mudconf.wizmotd_msg) { if (mudconf.ansi_colors) { raw_notify(player, tprintf("%sWIZMOTD:%s %s\n", ANSI_HILITE, ANSI_NORMAL, mudconf.wizmotd_msg)); } else { raw_notify(player, tprintf("WIZMOTD: %s\n", mudconf.wizmotd_msg)); } } if (!(mudconf.control_flags & CF_LOGIN)) { raw_notify(player, "*** Logins are disabled."); } } buf = atr_get(player, A_LPAGE, &aowner, &aflags, &alen); if (*buf) { raw_notify(player, "REMINDER: Your PAGE LOCK is set. You may be unable to receive some pages."); } if (Dark(player)) { raw_notify(player, "REMINDER: You are set DARK."); } num = 0; DESC_ITER_PLAYER(player, dtemp) num++; /* Reset vacation flag */ s_Flags2(player, Flags2(player) & ~VACATION); if (num < 2) { sprintf(buf, "%s has connected.", Name(player)); if (Hidden(player)) { raw_broadcast(WATCHER | FLAG_WORD2, (char *)"GAME: %s has DARK-connected.", Name(player)); } else { raw_broadcast(WATCHER | FLAG_WORD2, (char *)"GAME: %s has connected.", Name(player)); } } else { sprintf(buf, "%s has reconnected.", Name(player)); raw_broadcast(WATCHER | FLAG_WORD2, (char *)"GAME: %s has reconnected.", Name(player)); } key = MSG_INV; if ((loc != NOTHING) && !(Hidden(player) && Can_Hide(player))) key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST); temp = mudstate.curr_enactor; mudstate.curr_enactor = player; notify_check(player, player, buf, key); free_lbuf(buf); CALL_ALL_MODULES(announce_connect, (player, reason, num)); if (Suspect(player)) { raw_broadcast(WIZARD, (char *)"[Suspect] %s has connected.", Name(player)); } if (d->host_info & H_SUSPECT) { raw_broadcast(WIZARD, (char *)"[Suspect site: %s] %s has connected.", d->addr, Name(player)); } announce_connattr(player, loc, reason, num, A_ACONNECT); time_str = ctime(&mudstate.now); time_str[strlen(time_str) - 1] = '\0'; record_login(player, 1, time_str, d->addr, d->username); #ifdef PUEBLO_SUPPORT look_in(player, Location(player), (LK_SHOWEXIT | LK_OBEYTERSE | LK_SHOWVRML)); #else look_in(player, Location(player), (LK_SHOWEXIT | LK_OBEYTERSE)); #endif mudstate.curr_enactor = temp; } void announce_disconnect(player, d, reason) dbref player; DESC *d; const char *reason; { dbref loc, temp; int num, key; char *buf; DESC *dtemp; if (Suspect(player)) { raw_broadcast(WIZARD, (char *)"[Suspect] %s has disconnected.", Name(player)); } if (d->host_info & H_SUSPECT) { raw_broadcast(WIZARD, (char *)"[Suspect site: %s] %s has disconnected.", d->addr, Name(d->player)); } loc = Location(player); num = -1; DESC_ITER_PLAYER(player, dtemp) num++; temp = mudstate.curr_enactor; mudstate.curr_enactor = player; if (num < 1) { buf = alloc_mbuf("announce_disconnect.only"); sprintf(buf, "%s has disconnected.", Name(player)); key = MSG_INV; if ((loc != NOTHING) && !(Hidden(player) && Can_Hide(player))) key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST); notify_check(player, player, buf, key); free_mbuf(buf); raw_broadcast(WATCHER | FLAG_WORD2, (char *)"GAME: %s has disconnected.", Name(player)); /* Must reset flags before we do module stuff. */ c_Connected(player); #ifdef PUEBLO_SUPPORT c_Html(player); #endif } else { buf = alloc_mbuf("announce_disconnect.partial"); sprintf(buf, "%s has partially disconnected.", Name(player)); key = MSG_INV; if ((loc != NOTHING) && !(Hidden(player) && Can_Hide(player))) key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST); notify_check(player, player, buf, key); raw_broadcast(WATCHER | FLAG_WORD2, (char *)"GAME: %s has partially disconnected.", Name(player)); free_mbuf(buf); } CALL_ALL_MODULES(announce_disconnect, (player, reason, num)); announce_connattr(player, loc, reason, num, A_ADISCONNECT); if (num < 1) { if (d->flags & DS_AUTODARK) { s_Flags(d->player, Flags(d->player) & ~DARK); d->flags &= ~DS_AUTODARK; } if (Guest(player)) s_Flags(player, Flags(player) | DARK); } mudstate.curr_enactor = temp; desc_delhash(d); } int boot_off(player, message) dbref player; char *message; { DESC *d, *dnext; int count; count = 0; DESC_SAFEITER_PLAYER(player, d, dnext) { if (message && *message) { queue_rawstring(d, message); queue_write(d, "\r\n", 2); } shutdownsock(d, R_BOOT); count++; } return count; } int boot_by_port(port, no_god, message) int port, no_god; char *message; { DESC *d, *dnext; int count; count = 0; DESC_SAFEITER_ALL(d, dnext) { if ((d->descriptor == port) && (!no_god || !God(d->player))) { if (message && *message) { queue_rawstring(d, message); queue_write(d, "\r\n", 2); } shutdownsock(d, R_BOOT); count++; } } return count; } /* --------------------------------------------------------------------------- * desc_reload: Reload parts of net descriptor that are based on db info. */ void desc_reload(player) dbref player; { DESC *d; char *buf; dbref aowner; int aflags, alen; DESC_ITER_PLAYER(player, d) { buf = atr_pget(player, A_TIMEOUT, &aowner, &aflags, &alen); d->timeout = atoi(buf); if (d->timeout <= 0) d->timeout = mudconf.idle_timeout; free_lbuf(buf); } } /* --------------------------------------------------------------------------- * fetch_idle, fetch_connect: Return smallest idle time/largest connect time * for a player (or -1 if not logged in) */ int fetch_idle(target, port_num) dbref target; int port_num; { DESC *d; int result, idletime; result = -1; if (port_num < 0) { DESC_ITER_PLAYER(target, d) { idletime = (mudstate.now - d->last_time); if ((result == -1) || (idletime < result)) result = idletime; } } else { DESC_ITER_CONN(d) { if (d->descriptor == port_num) { idletime = (mudstate.now - d->last_time); if ((result == -1) || (idletime < result)) result = idletime; return result; } } } return result; } int fetch_connect(target, port_num) dbref target; int port_num; { DESC *d; int result, conntime; result = -1; if (port_num < 0) { DESC_ITER_PLAYER(target, d) { conntime = (mudstate.now - d->connected_at); if (conntime > result) result = conntime; } } else { DESC_ITER_CONN(d) { if (d->descriptor == port_num) { conntime = (mudstate.now - d->connected_at); if (conntime > result) result = conntime; return result; } } } return result; } void NDECL(check_idle) { DESC *d, *dnext; time_t idletime; DESC_SAFEITER_ALL(d, dnext) { if (d->flags & DS_CONNECTED) { idletime = mudstate.now - d->last_time; if ((idletime > d->timeout) && !Can_Idle(d->player)) { queue_rawstring(d, "*** Inactivity Timeout ***\r\n"); shutdownsock(d, R_TIMEOUT); } else if (mudconf.idle_wiz_dark && (idletime > mudconf.idle_timeout) && Can_Idle(d->player) && Can_Hide(d->player) && !Hidden(d->player)) { raw_notify(d->player, "*** Inactivity AutoDark ***"); s_Flags(d->player, Flags(d->player) | DARK); d->flags |= DS_AUTODARK; } } else { idletime = mudstate.now - d->connected_at; #ifdef CONCENTRATE if ((idletime > mudconf.conn_timeout) && !(d->cstatus & C_CCONTROL)) { #else if (idletime > mudconf.conn_timeout) { #endif /* CONCENTRATE */ queue_rawstring(d, "*** Login Timeout ***\r\n"); shutdownsock(d, R_TIMEOUT); } } } } static char *trimmed_name(player) dbref player; { static char cbuff[18]; if (strlen(Name(player)) <= 16) return Name(player); strncpy(cbuff, Name(player), 16); cbuff[16] = '\0'; return cbuff; } static char *trimmed_site(name) char *name; { static char buff[MBUF_SIZE]; if (((int)strlen(name) <= mudconf.site_chars) || (mudconf.site_chars == 0)) return name; strncpy(buff, name, mudconf.site_chars); buff[mudconf.site_chars + 1] = '\0'; return buff; } static void dump_users(e, match, key) DESC *e; char *match; int key; { DESC *d; int count; char *buf, *fp, *sp, flist[4], slist[4]; dbref room_it; while (match && *match && isspace(*match)) match++; if (!match || !*match) match = NULL; #ifdef PUEBLO_SUPPORT if ((e->flags & DS_PUEBLOCLIENT) && (Html(e->player))) queue_string(e, "<pre>"); #endif buf = alloc_mbuf("dump_users"); if (key == CMD_SESSION) { queue_rawstring(e, " "); queue_rawstring(e, " Characters Input---- Characters Output---\r\n"); } queue_rawstring(e, "Player Name On For Idle "); if (key == CMD_SESSION) { queue_rawstring(e, "Port Pend Lost Total Pend Lost Total\r\n"); } else if ((e->flags & DS_CONNECTED) && (Wizard_Who(e->player)) && (key == CMD_WHO)) { queue_rawstring(e, " Room Cmds Host\r\n"); } else { if (Wizard_Who(e->player) || See_Hidden(e->player)) queue_string(e, " "); else queue_string(e, " "); queue_string(e, mudstate.doing_hdr); queue_string(e, "\r\n"); } count = 0; DESC_ITER_CONN(d) { if (!Hidden(d->player) || ((e->flags & DS_CONNECTED) && See_Hidden(e->player))) { count++; if (match && !(string_prefix(Name(d->player), match))) continue; if ((key == CMD_SESSION) && !(Wizard_Who(e->player) && (e->flags & DS_CONNECTED)) && (d->player != e->player)) continue; /* Get choice flags for wizards */ fp = flist; sp = slist; if ((e->flags & DS_CONNECTED) && Wizard_Who(e->player)) { if (Hidden(d->player)) { if (d->flags & DS_AUTODARK) *fp++ = 'd'; else *fp++ = 'D'; } if (!Findable(d->player)) { *fp++ = 'U'; } else { room_it = where_room(d->player); if (Good_obj(room_it)) { if (Hideout(room_it)) *fp++ = 'u'; } else { *fp++ = 'u'; } } if (Suspect(d->player)) *fp++ = '+'; if (d->host_info & H_FORBIDDEN) *sp++ = 'F'; if (d->host_info & H_REGISTRATION) *sp++ = 'R'; if (d->host_info & H_SUSPECT) *sp++ = '+'; if (d->host_info & H_GUEST) *sp++ = 'G'; } else if ((e->flags & DS_CONNECTED) && See_Hidden(e->player)) { if (Hidden(d->player)) { if (d->flags & DS_AUTODARK) *fp++ = 'd'; else *fp++ = 'D'; } } *fp = '\0'; *sp = '\0'; if ((e->flags & DS_CONNECTED) && Wizard_Who(e->player) && (key == CMD_WHO)) { sprintf(buf, "%-16s%9s %4s%-3s#%-6d%5d%3s%-25s\r\n", trimmed_name(d->player), time_format_1(mudstate.now - d->connected_at), time_format_2(mudstate.now - d->last_time), flist, Location(d->player), d->command_count, slist, trimmed_site(((d->username[0] != '\0') ? tprintf("%s@%s", d->username, d->addr) : d->addr))); } else if (key == CMD_SESSION) { sprintf(buf, "%-16s%9s %4s%5d%5d%6d%10d%6d%6d%10d\r\n", trimmed_name(d->player), time_format_1(mudstate.now - d->connected_at), time_format_2(mudstate.now - d->last_time), d->descriptor, d->input_size, d->input_lost, d->input_tot, d->output_size, d->output_lost, d->output_tot); } else if (Wizard_Who(e->player) || See_Hidden(e->player)) { sprintf(buf, "%-16s%9s %4s%-3s%s\r\n", trimmed_name(d->player), time_format_1(mudstate.now - d->connected_at), time_format_2(mudstate.now - d->last_time), flist, d->doing); } else { sprintf(buf, "%-16s%9s %4s %s\r\n", trimmed_name(d->player), time_format_1(mudstate.now - d->connected_at), time_format_2(mudstate.now - d->last_time), d->doing); } queue_string(e, buf); } } /* sometimes I like the ternary operator.... */ sprintf(buf, "%d Player%slogged in, %d record, %s maximum.\r\n", count, (count == 1) ? " " : "s ", mudstate.record_players, (mudconf.max_players == -1) ? "no" : tprintf("%d", mudconf.max_players)); queue_rawstring(e, buf); #ifdef PUEBLO_SUPPORT if ((e->flags & DS_PUEBLOCLIENT) && (Html(e->player))) queue_string(e, "</pre>"); #endif free_mbuf(buf); } static void dump_info(call_by) DESC *call_by; { DESC *d; char *temp; int count = 0; queue_rawstring(call_by, "### Begin INFO 1\r\n"); queue_rawstring(call_by, tprintf("Name: %s\r\n", mudconf.mud_name)); temp = (char *) ctime(&mudstate.start_time); temp[strlen(temp) - 1] = '\0'; queue_rawstring(call_by, tprintf("Uptime: %s\r\n", temp)); DESC_ITER_CONN(d) { if (!Hidden(d->player) || ((call_by->flags & DS_CONNECTED) && See_Hidden(call_by->player))) count++; } queue_rawstring(call_by, tprintf("Connected: %d\r\n", count)); queue_rawstring(call_by, tprintf("Size: %d\r\n", mudstate.db_top)); queue_rawstring(call_by, tprintf("Version: %s\r\n", mudstate.short_ver)); queue_rawstring(call_by, "### End INFO\r\n"); } /* --------------------------------------------------------------------------- * do_doing: Set the doing string that appears in the WHO report. * Idea from R'nice@TinyTIM. */ static int sane_doing(arg, buff) char *arg, *buff; { char *p, *bp; int over = 0; for (p = arg; *p; p++) if ((*p == '\t') || (*p == '\r') || (*p == '\n')) *p = ' '; bp = buff; if (!mudconf.ansi_colors || !strchr(arg, ESC_CHAR)) { over = safe_copy_str_fn(arg, buff, &bp, DOING_LEN - 1); } else { over = safe_copy_str_fn(arg, buff, &bp, DOING_LEN - 5); strcpy(bp, ANSI_NORMAL); } return over; } void do_doing(player, cause, key, arg) dbref player, cause; int key; char *arg; { DESC *d; int foundany, over; over = 0; if (key & DOING_HEADER) { if (!(Can_Poll(player))) { notify(player, NOPERM_MESSAGE); return; } if (!arg || !*arg) { StringCopy(mudstate.doing_hdr, "Doing"); over = 0; } else { over = sane_doing(arg, mudstate.doing_hdr); } if (over) { notify(player, tprintf("Warning: %d characters lost.", over)); } if (!Quiet(player) && !(key & DOING_QUIET)) notify(player, "Set."); } else if (key & DOING_POLL) { notify(player, tprintf("Poll: %s", mudstate.doing_hdr)); } else { foundany = 0; DESC_ITER_PLAYER(player, d) { over = sane_doing(arg, d->doing); foundany = 1; } if (foundany) { if (over) { notify(player, tprintf("Warning: %d characters lost.", over)); } if (!Quiet(player) && !(key & DOING_QUIET) ) notify(player, "Set."); } else { notify(player, "Not connected."); } } } /* *INDENT-OFF* */ NAMETAB logout_cmdtable[] = { {(char *)"DOING", 5, CA_PUBLIC, CMD_DOING}, {(char *)"LOGOUT", 6, CA_PUBLIC, CMD_LOGOUT}, {(char *)"OUTPUTPREFIX",12, CA_PUBLIC, CMD_PREFIX|CMD_NOxFIX}, {(char *)"OUTPUTSUFFIX",12, CA_PUBLIC, CMD_SUFFIX|CMD_NOxFIX}, {(char *)"QUIT", 4, CA_PUBLIC, CMD_QUIT}, {(char *)"SESSION", 7, CA_PUBLIC, CMD_SESSION}, {(char *)"WHO", 3, CA_PUBLIC, CMD_WHO}, {(char *)"PUEBLOCLIENT", 12, CA_PUBLIC, CMD_PUEBLOCLIENT}, {(char *)"INFO", 4, CA_PUBLIC, CMD_INFO}, {NULL, 0, 0, 0}}; /* *INDENT-ON* */ void NDECL(init_logout_cmdtab) { NAMETAB *cp; /* Make the htab bigger than the number of entries so that we find * things on the first check. Remember that the admin can add * aliases. */ hashinit(&mudstate.logout_cmd_htab, 3 * HASH_FACTOR, HT_STR); for (cp = logout_cmdtable; cp->flag; cp++) hashadd(cp->name, (int *)cp, &mudstate.logout_cmd_htab, 0); } static void failconn(logcode, logtype, logreason, d, disconnect_reason, player, filecache, motd_msg, command, user, password, cmdsave) const char *logcode, *logtype, *logreason; char *motd_msg, *command, *user, *password, *cmdsave; DESC *d; int disconnect_reason, filecache; dbref player; { STARTLOG(LOG_LOGIN | LOG_SECURITY, logcode, "RJCT") log_printf("[%d/%s] %s rejected to ", d->descriptor, d->addr, logtype); if (player != NOTHING) log_name(player); else log_printf("%s", user); log_printf(" (%s)", logreason); ENDLOG fcache_dump(d, filecache); if (*motd_msg) { queue_string(d, motd_msg); queue_write(d, "\r\n", 2); } free_lbuf(command); free_lbuf(user); free_lbuf(password); shutdownsock(d, disconnect_reason); mudstate.debug_cmd = cmdsave; return; } static const char *connect_fail = "Either that player does not exist, or has a different password.\r\n"; static const char *create_fail = "Either there is already a player with that name, or that name is illegal.\r\n"; static int check_connect(d, msg) DESC *d; char *msg; { char *command, *user, *password, *buff, *cmdsave; dbref player, aowner; int aflags, alen, nplayers, reason; DESC *d2; char *p; cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< check_connect >"; /* Hide the password length from SESSION */ d->input_tot -= (strlen(msg) + 1); /* Crack the command apart */ command = alloc_lbuf("check_conn.cmd"); user = alloc_lbuf("check_conn.user"); password = alloc_lbuf("check_conn.pass"); parse_connect(msg, command, user, password); if (!strncmp(command, "co", 2) || !strncmp(command, "cd", 2)) { if ((string_prefix(user, mudconf.guest_basename)) && Good_obj(mudconf.guest_char) && (mudconf.control_flags & CF_LOGIN)) { if ((p = make_guest(d)) == NULL) { queue_string(d, "All guests are tied up, please try again later.\n"); free_lbuf(command); free_lbuf(user); free_lbuf(password); return 0; } StringCopy(user, p); StringCopy(password, mudconf.guest_password); } /* See if this connection would exceed the max #players */ if (mudconf.max_players < 0) { nplayers = mudconf.max_players - 1; } else { nplayers = 0; DESC_ITER_CONN(d2) nplayers++; } player = connect_player(user, password, d->addr, d->username, inet_ntoa((d->address).sin_addr)); if (player == NOTHING) { /* Not a player, or wrong password */ queue_rawstring(d, connect_fail); STARTLOG(LOG_LOGIN | LOG_SECURITY, "CON", "BAD") log_printf("[%d/%s] Failed connect to '%s'", d->descriptor, d->addr, user); ENDLOG user[3800] = '\0'; if (--(d->retries_left) <= 0) { free_lbuf(command); free_lbuf(user); free_lbuf(password); shutdownsock(d, R_BADLOGIN); mudstate.debug_cmd = cmdsave; return 0; } } else if (((mudconf.control_flags & CF_LOGIN) && (nplayers < mudconf.max_players)) || WizRoy(player) || God(player)) { if (Guest(player)) { reason = R_GUEST; } else if (!strncmp(command, "cd", 2) && (Wizard(player) || God(player))) { s_Flags(player, Flags(player) | DARK); reason = R_DARK; } else { reason = R_CONNECT; } /* First make sure we don't have a guest from a bad host. */ if (Guest(player) && (d->host_info & H_GUEST)) { failconn("CON", "Connect", "Guest Site Forbidden", d, R_GAMEDOWN, player, FC_CONN_SITE, mudconf.downmotd_msg, command, user, password, cmdsave); return 0; } /* Logins are enabled, or wiz or god */ STARTLOG(LOG_LOGIN, "CON", "LOGIN") log_printf("[%d/%s] %s ", d->descriptor, d->addr, conn_reasons[reason]); log_name_and_loc(player); ENDLOG d->flags |= DS_CONNECTED; d->connected_at = time(NULL); d->player = player; /* Check to see if the player is currently running * an @program. If so, drop the new descriptor into * it. */ DESC_ITER_PLAYER(player, d2) { if (d2->program_data != NULL) { d->program_data = d2->program_data; break; } } /* Give the player the MOTD file and the settable * MOTD message(s). Use raw notifies so the * player doesn't try to match on the text. */ if (Guest(player)) { fcache_dump(d, FC_CONN_GUEST); } else { buff = atr_get(player, A_LAST, &aowner, &aflags, &alen); if (!*buff) fcache_dump(d, FC_CREA_NEW); else fcache_dump(d, FC_MOTD); if (Wizard(player)) fcache_dump(d, FC_WIZMOTD); free_lbuf(buff); } announce_connect(player, d, conn_messages[reason]); /* If stuck in an @prog, show the prompt */ if (d->program_data != NULL) queue_rawstring(d, "> \377\371"); } else if (!(mudconf.control_flags & CF_LOGIN)) { failconn("CON", "Connect", "Logins Disabled", d, R_GAMEDOWN, player, FC_CONN_DOWN, mudconf.downmotd_msg, command, user, password, cmdsave); return 0; } else { failconn("CON", "Connect", "Game Full", d, R_GAMEFULL, player, FC_CONN_FULL, mudconf.fullmotd_msg, command, user, password, cmdsave); return 0; } } else if (!strncmp(command, "cr", 2)) { reason = R_CREATE; /* Enforce game down */ if (!(mudconf.control_flags & CF_LOGIN)) { failconn("CRE", "Create", "Logins Disabled", d, R_GAMEDOWN, NOTHING, FC_CONN_DOWN, mudconf.downmotd_msg, command, user, password, cmdsave); return 0; } /* Enforce max #players */ if (mudconf.max_players < 0) { nplayers = mudconf.max_players; } else { nplayers = 0; DESC_ITER_CONN(d2) nplayers++; } if (nplayers > mudconf.max_players) { /* Too many players on, reject the attempt */ failconn("CRE", "Create", "Game Full", d, R_GAMEFULL, NOTHING, FC_CONN_FULL, mudconf.fullmotd_msg, command, user, password, cmdsave); return 0; } if (d->host_info & H_REGISTRATION) { fcache_dump(d, FC_CREA_REG); } else { player = create_player(user, password, NOTHING, 0, 0); if (player == NOTHING) { queue_rawstring(d, create_fail); STARTLOG(LOG_SECURITY | LOG_PCREATES, "CON", "BAD") log_printf("[%d/%s] Create of '%s' failed", d->descriptor, d->addr, user); ENDLOG } else { STARTLOG(LOG_LOGIN | LOG_PCREATES, "CON", "CREA") log_printf("[%d/%s] %s ", d->descriptor, d->addr, conn_reasons[reason]); log_name(player); ENDLOG move_object(player, (Good_loc(mudconf.start_room) ? mudconf.start_room : 0)); d->flags |= DS_CONNECTED; d->connected_at = time(NULL); d->player = player; fcache_dump(d, FC_CREA_NEW); announce_connect(player, d, conn_messages[R_CREATE]); } } } else { welcome_user(d); STARTLOG(LOG_LOGIN | LOG_SECURITY, "CON", "BAD") log_printf("[%d/%s] Failed connect: '%s'", d->descriptor, d->addr, msg); ENDLOG msg[150] = '\0'; } free_lbuf(command); free_lbuf(user); free_lbuf(password); mudstate.debug_cmd = cmdsave; return 1; } int do_command(d, command, first) DESC *d; char *command; int first; { char *arg, *cmdsave, *log_cmdbuf; NAMETAB *cp; long begin_time, used_time; cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< do_command >"; /* Split off the command from the arguments */ arg = command; while (*arg && !isspace(*arg)) arg++; if (*arg) *arg++ = '\0'; /* Look up the command. If we don't find it, turn it over to the * normal logged-in command processor or to create/connect */ if (!(d->flags & DS_CONNECTED)) { cp = (NAMETAB *) hashfind(command, &mudstate.logout_cmd_htab); } else cp = NULL; #ifdef CONCENTRATE if (*arg) *--arg = ' '; /* * restore nullified space */ if (!strncmp(command, "New Conn Pass: ", sizeof("New Conn Pass ") - 1)) { do_becomeconc(d, command + sizeof("New Conn Pass: ") - 1); return 1; } else if (((d->cstatus & C_REMOTE) || (d->cstatus & C_CCONTROL)) && first) { if (!strncmp(command, "CONC ", sizeof("CONC ") - 1)) log_printf("%s", command); else if (!strcmp(command, "New ID")) { do_makeid(d); } else if (!strncmp(command, "Conn ID: ", sizeof("Conn ID: ") - 1)) { char *m, *n; m = command + sizeof("Conn ID: ") - 1; n = strchr(m, ' '); if (!n) queue_string(d, "Usage: Conn ID: <id> <hostname>\n"); else do_connectid(d, atoi(command + sizeof("Conn ID: ") - 1), n + 1); } else if (!strncmp(command, "Kill ID: ", sizeof("Kill ID: ") - 1)) do_killid(d, atoi(command + sizeof("Kill ID: ") - 1)); else { char *k; k = strchr(command, ' '); if (!k) return 1; 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, 0)) { return 0; } } } } return 1; } if (*arg) arg++; #endif if (cp == NULL) { if (*arg) *--arg = ' '; /* restore nullified space */ if (d->flags & DS_CONNECTED) { d->command_count++; if (d->output_prefix) { queue_string(d, d->output_prefix); queue_write(d, "\r\n", 2); } mudstate.curr_player = d->player; mudstate.curr_enactor = d->player; Free_RegData(mudstate.rdata); mudstate.rdata = NULL; #ifndef NO_LAG_CHECK begin_time = time(NULL); #endif /* NO_LAG_CHECK */ mudstate.cmd_invk_ctr = 0; log_cmdbuf = process_command(d->player, d->player, 1, command, (char **)NULL, 0); #ifndef NO_LAG_CHECK used_time = time(NULL) - begin_time; if (used_time >= mudconf.max_cmdsecs) { STARTLOG(LOG_PROBLEMS, "CMD", "CPU") log_name_and_loc(d->player); log_printf(" entered command taking %ld secs: %s", used_time, log_cmdbuf); ENDLOG } #endif /* NO_LAG_CHECK */ mudstate.curr_cmd = (char *) ""; if (d->output_suffix) { queue_string(d, d->output_suffix); queue_write(d, "\r\n", 2); } mudstate.debug_cmd = cmdsave; return 1; } else { mudstate.debug_cmd = cmdsave; return (check_connect(d, command)); } } /* The command was in the logged-out command table. Perform prefix * and suffix processing, and invoke the command handler. */ d->command_count++; if (!(cp->flag & CMD_NOxFIX)) { if (d->output_prefix) { queue_string(d, d->output_prefix); queue_write(d, "\r\n", 2); } } if ((!check_access(d->player, cp->perm)) || ((cp->perm & CA_PLAYER) && !(d->flags & DS_CONNECTED))) { queue_rawstring(d, "Permission denied.\r\n"); } else { mudstate.debug_cmd = cp->name; switch (cp->flag & CMD_MASK) { case CMD_QUIT: shutdownsock(d, R_QUIT); mudstate.debug_cmd = cmdsave; return 0; case CMD_LOGOUT: shutdownsock(d, R_LOGOUT); break; case CMD_WHO: dump_users(d, arg, CMD_WHO); break; case CMD_DOING: dump_users(d, arg, CMD_DOING); break; case CMD_SESSION: dump_users(d, arg, CMD_SESSION); break; case CMD_PREFIX: set_userstring(&d->output_prefix, arg); break; case CMD_SUFFIX: set_userstring(&d->output_suffix, arg); break; case CMD_INFO: dump_info(d); break; case CMD_PUEBLOCLIENT: #ifdef PUEBLO_SUPPORT /* Set the descriptor's flag */ d->flags |= DS_PUEBLOCLIENT; /* If we're already connected, set the player's flag */ if (d->player) { s_Html(d->player); } queue_rawstring(d, mudconf.pueblo_msg); queue_write(d, "\r\n", 2); fcache_dump(d, FC_CONN_HTML); STARTLOG(LOG_LOGIN, "CON", "HTML") log_printf("[%d/%s] PuebloClient enabled.", d->descriptor, d->addr); ENDLOG #else queue_rawstring(d, "Sorry. This MUSH does not have Pueblo support enabled.\r\n"); #endif break; default: STARTLOG(LOG_BUGS, "BUG", "PARSE") log_printf("Prefix command with no handler: '%s'", command); ENDLOG } } if (!(cp->flag & CMD_NOxFIX)) { if (d->output_suffix) { queue_string(d, d->output_suffix); queue_write(d, "\r\n", 2); } } mudstate.debug_cmd = cmdsave; return 1; } void logged_out(player, cause, key, arg) dbref player, cause; int key; char *arg; { DESC *d; int idletime; DESC_ITER_PLAYER(player, d) { idletime = (mudstate.now - d->last_time); switch (key) { case CMD_QUIT: if (idletime == 0) { shutdownsock(d, R_QUIT); return; } break; case CMD_LOGOUT: if (idletime == 0) { shutdownsock(d, R_LOGOUT); return; } break; case CMD_WHO: if (idletime == 0) { dump_users(d, arg, CMD_WHO); return; } break; case CMD_DOING: if (idletime == 0) { dump_users(d, arg, CMD_DOING); return; } break; case CMD_SESSION: if (idletime == 0) { dump_users(d, arg, CMD_SESSION); return; } break; case CMD_PREFIX: if (idletime == 0) { set_userstring(&d->output_prefix, arg); return; } break; case CMD_SUFFIX: if (idletime == 0) { set_userstring(&d->output_suffix, arg); return; } break; case CMD_INFO: if (idletime == 0) { dump_info(d); return; } break; case CMD_PUEBLOCLIENT: #ifdef PUEBLO_SUPPORT /* Set the descriptor's flag */ d->flags |= DS_PUEBLOCLIENT; /* If we're already connected, set the player's flag */ if (d->player) { s_Html(d->player); } queue_string(d, mudconf.pueblo_msg); queue_write(d, "\r\n", 2); fcache_dump(d, FC_CONN_HTML); STARTLOG(LOG_LOGIN, "CON", "HTML") log_printf("[%d/%s] PuebloClient enabled.", d->descriptor, d->addr); ENDLOG #else queue_string(d, "Sorry. This MUSH does not have Pueblo support enabled.\r\n"); #endif break; } } } void NDECL(process_commands) { int nprocessed; DESC *d, *dnext; CBLK *t; char *cmdsave; cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"process_commands"; do { nprocessed = 0; DESC_SAFEITER_ALL(d, dnext) { if (d->quota > 0 && (t = d->input_head)) { d->quota--; nprocessed++; d->input_head = (CBLK *) t->hdr.nxt; if (!d->input_head) d->input_tail = NULL; d->input_size -= (strlen(t->cmd) + 1); STARTLOG(LOG_KBCOMMANDS, "CMD", "KBRD") log_printf("[%d/%s] Cmd: %s", d->descriptor, d->addr, t->cmd); ENDLOG d->last_time = mudstate.now; if (d->program_data != NULL) handle_prog(d, t->cmd); else do_command(d, t->cmd, 1); free_lbuf(t); } } } while (nprocessed > 0); mudstate.debug_cmd = cmdsave; } /* --------------------------------------------------------------------------- * site_check: Check for site flags in a site list. */ int site_check(host, site_list) struct in_addr host; SITE *site_list; { SITE *this; for (this = site_list; this; this = this->next) { if ((host.s_addr & this->mask.s_addr) == this->address.s_addr) return this->flag; } return 0; } /* -------------------------------------------------------------------------- * list_sites: Display information in a site list */ #define S_SUSPECT 1 #define S_ACCESS 2 static const char *stat_string(strtype, flag) int strtype, flag; { const char *str; switch (strtype) { case S_SUSPECT: if (flag) str = "Suspected"; else str = "Trusted"; break; case S_ACCESS: switch (flag) { case H_FORBIDDEN: str = "Forbidden"; break; case H_REGISTRATION: str = "Registration"; break; case H_GUEST: str = "NoGuest"; break; case 0: str = "Unrestricted"; break; default: str = "Strange"; } break; default: str = "Strange"; } return str; } static unsigned int mask_to_prefix(mask_num) unsigned int mask_num; { unsigned int i, result, tmp; /* The number of bits in the mask is equal to the number of left * shifts before it becomes zero. Binary search for that number. */ for (i = 16, result = 0; i && mask_num; i >>= 1) if ((tmp = (mask_num << i))) { result |= i; mask_num = tmp; } if (mask_num) result++; return result; } static void list_sites(player, site_list, header_txt, stat_type) dbref player; SITE *site_list; const char *header_txt; int stat_type; { char *buff, *str, *maskaddr; SITE *this; unsigned int bits; buff = alloc_mbuf("list_sites.buff"); sprintf(buff, "----- %s -----", header_txt); notify(player, buff); notify(player, "IP Prefix Mask Status"); for (this = site_list; this; this = this->next) { str = (char *) stat_string(stat_type, this->flag); bits = mask_to_prefix(ntohl(this->mask.s_addr)); /* special-case 0, can't shift by 32 */ if ((bits == 0 && htonl(0) == this->mask.s_addr) || htonl(0xFFFFFFFFU << (32 - bits)) == this->mask.s_addr) { sprintf(buff, "%-17s /%-16d %s", inet_ntoa(this->address), bits, str); } else { /* Deal with bizarre stuff not along CIDRized boundaries. * inet_ntoa() points to a static buffer, so we've got to * allocate something temporary. */ maskaddr = alloc_mbuf("list_sites.mask"); strcpy(maskaddr, inet_ntoa(this->mask)); sprintf(buff, "%-17s %-17s %s", inet_ntoa(this->address), maskaddr, str); free_mbuf(maskaddr); } notify(player, buff); } free_mbuf(buff); } /* --------------------------------------------------------------------------- * list_siteinfo: List information about specially-marked sites. */ void list_siteinfo(player) dbref player; { list_sites(player, mudstate.access_list, "Site Access", S_ACCESS); list_sites(player, mudstate.suspect_list, "Suspected Sites", S_SUSPECT); } /* --------------------------------------------------------------------------- * make_ulist: Make a list of connected user numbers for the LWHO function. */ void make_ulist(player, buff, bufc) dbref player; char *buff, **bufc; { char *cp; DESC *d; cp = *bufc; DESC_ITER_CONN(d) { if (!See_Hidden(player) && Hidden(d->player)) continue; if (cp != *bufc) safe_chr(' ', buff, bufc); safe_chr('#', buff, bufc); safe_ltos(buff, bufc, d->player); } } /* --------------------------------------------------------------------------- * make_portlist: Make a list of ports for PORTS(). */ void make_portlist(player, target, buff, bufc) dbref player; dbref target; char *buff, **bufc; { DESC *d; int i = 0; DESC_ITER_CONN(d) { if (d->player == target) { safe_str(tprintf("%d ", d->descriptor), buff, bufc); i = 1; } } if (i) (*bufc)--; **bufc = '\0'; } /* --------------------------------------------------------------------------- * make_sessioninfo: Return information about a port, for SESSION(). * List of numbers: command_count input_tot output_tot */ void make_sessioninfo(player, target, port_num, buff, bufc) dbref player, target; int port_num; char *buff, **bufc; { DESC *d; DESC_ITER_CONN(d) { if ((d->descriptor == port_num) || (d->player == target)) { if (Wizard_Who(player) || Controls(player, d->player)) { safe_str(tprintf("%d %d %d", d->command_count, d->input_tot, d->output_tot), buff, bufc); return; } else { notify_quiet(player, NOPERM_MESSAGE); safe_str((char *) "-1 -1 -1", buff, bufc); return; } } } /* Not found, return error. */ safe_str((char *) "-1 -1 -1", buff, bufc); } /* --------------------------------------------------------------------------- * get_doing: Return the DOING string of a player. */ char *get_doing(target, port_num) dbref target; int port_num; { DESC *d; if (port_num < 0) { DESC_ITER_PLAYER(target, d) { return d->doing; } } else { DESC_ITER_CONN(d) { if (d->descriptor == port_num) return d->doing; } } return NULL; } /* --------------------------------------------------------------------------- * get_programmer: Get the dbref of the controlling programmer, if any. */ dbref get_programmer(target) dbref target; { DESC *d; DESC_ITER_CONN(d) { if ((d->player == target) && (d->program_data != NULL)) return (d->program_data->wait_cause); } return NOTHING; } /* --------------------------------------------------------------------------- * find_connected_name: Resolve a playername from the list of connected * players using prefix matching. We only return a match if the prefix * was unique. */ dbref find_connected_name(player, name) dbref player; char *name; { DESC *d; dbref found; found = NOTHING; DESC_ITER_CONN(d) { if (Good_obj(player) && !See_Hidden(player) && Hidden(d->player)) continue; if (!string_prefix(Name(d->player), name)) continue; if ((found != NOTHING) && (found != d->player)) return NOTHING; found = d->player; } return found; } /* --------------------------------------------------------------------------- * find_connected_ambiguous: Resolve a playername from the list of connected * players using prefix matching. If the prefix is non-unique, we return * the AMBIGUOUS token; if it does not exist, we return the NOTHING token. * was unique. */ dbref find_connected_ambiguous(player, name) dbref player; char *name; { DESC *d; dbref found; found = NOTHING; DESC_ITER_CONN(d) { if (Good_obj(player) && !See_Hidden(player) && Hidden(d->player)) continue; if (!string_prefix(Name(d->player), name)) continue; if ((found != NOTHING) && (found != d->player)) return AMBIGUOUS; found = d->player; } return found; }