// netcommon.cpp // // $Id: netcommon.cpp,v 1.21 2000/09/18 18:26:24 sdennis 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 "externs.h" #include <time.h> #include "db.h" #include "mudconf.h" #include "file_c.h" #include "interface.h" #include "command.h" #include "alloc.h" #include "attrs.h" #include "mguests.h" #include "ansi.h" #include "mail.h" #include "powers.h" #include "alloc.h" #include "comsys.h" #include "svdreport.h" #include "functions.h" extern void FDECL(handle_prog, (DESC *, char *)); #ifdef WIN32 extern HANDLE CompletionPort; // IOs are queued up on this port extern OVERLAPPED lpo_aborted; // special to indicate a player has finished TCP IOs extern OVERLAPPED lpo_aborted_final; // Actually free the descriptor. extern OVERLAPPED lpo_shutdown; // special to indicate a player should do a shutdown #endif #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 /* * --------------------------------------------------------------------------- * * make_portlist: Make a list of ports for PORTS(). */ void make_portlist(dbref player, dbref target, char *buff, char **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'; } /* * --------------------------------------------------------------------------- * * update_quotas: Update timeslice quotas */ CLinearTimeAbsolute update_quotas(const CLinearTimeAbsolute& ltaLast, const CLinearTimeAbsolute& ltaCurrent) { if (ltaCurrent < ltaLast) return ltaCurrent; CLinearTimeDelta ltdDiff = ltaCurrent - ltaLast; CLinearTimeDelta ltdTimeSlice; ltdTimeSlice.SetMilliseconds(mudconf.timeslice); int nSlices = ltdDiff / ltdTimeSlice; int nExtraQuota = mudconf.cmd_quota_incr * nSlices; if (nExtraQuota > 0) { DESC *d; DESC_ITER_ALL(d) { d->quota += nExtraQuota; if (d->quota > mudconf.cmd_quota_max) d->quota = mudconf.cmd_quota_max; } } return ltaLast + ltdTimeSlice * nSlices; } /* raw_notify_html() -- raw_notify() without the newline */ void raw_notify_html(dbref player, const 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; DESC_ITER_PLAYER(player, d) { queue_string(d, msg); } } /* * --------------------------------------------------------------------------- * * raw_notify: write a message to a player */ void raw_notify(dbref player, const char *msg) { DESC *d; if (!msg || !*msg) return; if (mudstate.inpipe && (player == mudstate.poutobj)) { safe_str(msg, mudstate.poutnew, &mudstate.poutbufc); safe_str("\r\n", 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(dbref player) { DESC *d; if (mudstate.inpipe && (player == mudstate.poutobj)) { safe_str("\r\n", 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 */ void DCL_CDECL raw_broadcast(int inflags, char *fmt, ...) { if (!fmt || !*fmt) { return; } va_list ap; va_start(ap, fmt); char *buff = alloc_lbuf("raw_broadcast"); Tiny_vsnprintf(buff, LBUF_SIZE, fmt, ap); va_end(ap); DESC *d; DESC_ITER_CONN(d) { if ((Flags(d->player) & inflags) == inflags) { queue_string(d, buff); queue_write(d, "\r\n", 2); process_output(d, FALSE); } } free_lbuf(buff); } /* * --------------------------------------------------------------------------- * * clearstrings: clear out prefix and suffix strings */ void clearstrings(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; } } void add_to_output_queue(DESC *d, const char *b, int n) { TBLOCK *tp; int left; // Allocate an output buffer if needed. // if (d->output_head == NULL) { tp = (TBLOCK *)MEMALLOC(OUTPUT_BLOCK_SIZE); ISOUTOFMEMORY(tp); 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. // 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) { memcpy(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) { memcpy(tp->hdr.end, b, left); tp->hdr.end += left; tp->hdr.nchars += left; b += left; n -= left; } tp = (TBLOCK *)MEMALLOC(OUTPUT_BLOCK_SIZE); ISOUTOFMEMORY(tp); 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); } /* * --------------------------------------------------------------------------- * * queue_write: Add text to the output queue for the indicated descriptor. */ void queue_write(DESC *d, const char *b, int n) { TBLOCK *tp; char *buf; int left; if (n <= 0) return; if (d->output_size + n > mudconf.output_limit) process_output(d, FALSE); left = mudconf.output_limit - d->output_size - n; if (left < 0) { tp = d->output_head; if (tp == NULL) { STARTLOG(LOG_PROBLEMS, "QUE", "WRITE"); log_text((char *)"Flushing when output_head is null!"); ENDLOG; } else { STARTLOG(LOG_NET, "NET", "WRITE"); buf = alloc_lbuf("queue_write.LOG"); sprintf(buf, "[%d/%s] Output buffer overflow, %d chars discarded by ", d->descriptor, d->addr, tp->hdr.nchars); log_text(buf); free_lbuf(buf); 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; } MEMFREE(tp); } } add_to_output_queue(d, b, n); d->output_size += n; d->output_tot += n; #ifdef WIN32 if (platform == VER_PLATFORM_WIN32_NT && !(d->bWritePending) && !(d->bConnectionDropped)) { d->bCallProcessOutputLater = TRUE; } #endif } void queue_string(DESC *d, const char *s) { char *new0; if (!Ansi(d->player) && strchr(s, ESC_CHAR)) new0 = strip_ansi(s); else if (NoBleed(d->player)) new0 = normal_to_white(s); else new0 = (char *)s; queue_write(d, new0, strlen(new0)); } void freeqs(DESC *d) { TBLOCK *tb, *tnext; CBLK *cb, *cnext; tb = d->output_head; while (tb) { tnext = tb->hdr.nxt; MEMFREE(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(DESC *d) { dbref player; DESC *hdesc; player = d->player; hdesc = (DESC *)hashfindLEN(&player, sizeof(player), &mudstate.desc_htab); if (hdesc == NULL) { d->hashnext = NULL; hashaddLEN(&player, sizeof(player), (int *)d, &mudstate.desc_htab); } else { d->hashnext = hdesc; hashreplLEN(&player, sizeof(player), (int *)d, &mudstate.desc_htab); } } /* * --------------------------------------------------------------------------- * * desc_delhash: Remove a net descriptor from its player hash list. */ static void desc_delhash(DESC *d) { DESC *hdesc, *last; dbref player; player = d->player; last = NULL; hdesc = (DESC *)hashfindLEN(&player, sizeof(player), &mudstate.desc_htab); while (hdesc != NULL) { if (d == hdesc) { if (last == NULL) { if (d->hashnext == NULL) { hashdeleteLEN(&player, sizeof(player), &mudstate.desc_htab); } else { hashreplLEN(&player, sizeof(player), (int *)(d->hashnext), &mudstate.desc_htab); } } else { last->hashnext = d->hashnext; } break; } last = hdesc; hdesc = hdesc->hashnext; } d->hashnext = NULL; } void welcome_user(DESC *d) { if (d->host_info & H_REGISTRATION) fcache_dump(d, FC_CONN_REG); else fcache_dump(d, FC_CONN); } void save_command(DESC *d, CBLK *command) { command->hdr.nxt = NULL; if (d->input_tail == NULL) { d->input_head = command; // We have added our first command to an empty list. Go process it later. // scheduler.DeferImmediateTask(PRIORITY_SYSTEM, Task_ProcessCommand, d, 0); } else { d->input_tail->hdr.nxt = command; } d->input_tail = command; } static void set_userstring(char **userstring, const char *command) { while (Tiny_IsSpace[(unsigned char)*command]) command++; if (!*command) { if (*userstring != NULL) { free_lbuf(*userstring); *userstring = NULL; } } else { if (*userstring == NULL) { *userstring = alloc_lbuf("set_userstring"); } StringCopy(*userstring, command); } } static void parse_connect(const char *msg, char *command, char *user, char *pass) { char *p; if (strlen(msg) > MBUF_SIZE) { *command = '\0'; *user = '\0'; *pass = '\0'; return; } while (Tiny_IsSpace[(unsigned char)*msg]) { msg++; } p = command; while ( *msg && Tiny_IsASCII[(unsigned char)*msg] && !Tiny_IsSpace[(unsigned char)*msg]) { *p++ = *msg++; } *p = '\0'; while (Tiny_IsSpace[(unsigned char)*msg]) { msg++; } p = user; if (mudconf.name_spaces && (*msg == '\"')) { for (; *msg && (*msg == '\"' || Tiny_IsSpace[(unsigned char)*msg]); msg++) { // Nothing } while (*msg && *msg != '\"') { while (*msg && !Tiny_IsSpace[(unsigned char)*msg] && (*msg != '\"')) { *p++ = *msg++; } if (*msg == '\"') { break; } while (Tiny_IsSpace[(unsigned char)*msg]) { msg++; } if (*msg && (*msg != '\"')) { *p++ = ' '; } } for (; *msg && *msg == '\"'; msg++) ; } else { while ( *msg && Tiny_IsASCII[(unsigned char)*msg] && !Tiny_IsSpace[(unsigned char)*msg]) { *p++ = *msg++; } *p = '\0'; while (Tiny_IsSpace[(unsigned char)*msg]) { msg++; } p = pass; while ( *msg && Tiny_IsASCII[(unsigned char)*msg] && !Tiny_IsSpace[(unsigned char)*msg]) { *p++ = *msg++; } *p = '\0'; } } static void announce_connect(dbref player, DESC *d) { dbref loc, aowner, temp; dbref zone, obj; int aflags, 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); if (buf) { d->timeout = Tiny_atol(buf); if (d->timeout <= 0) { d->timeout = mudconf.idle_timeout; } } free_lbuf(buf); loc = Location(player); s_Connected(player); if (d->flags & DS_PUEBLOCLIENT) { s_Html(player); } raw_notify( player, tprintf("\n%sMOTD:%s %s\n", ANSI_HILITE, ANSI_NORMAL, mudconf.motd_msg)); if (Wizard(player)) { raw_notify( player, tprintf("%sWIZMOTD:%s %s\n", ANSI_HILITE, ANSI_NORMAL, mudconf.wizmotd_msg)); if (!(mudconf.control_flags & CF_LOGIN)) { raw_notify(player, "*** Logins are disabled."); } } buf = atr_get(player, A_LPAGE, &aowner, &aflags); if (*buf) { raw_notify(player, "Your PAGE LOCK is set. You may be unable to receive some pages."); } num = 0; DESC_ITER_PLAYER(player, dtemp) { num++; } // Reset vacation flag. // s_Flags2(player, Flags2(player) & ~VACATION); char *pRoomAnnounceFmt; char *pMonitorAnnounceFmt; if (num < 2) { pRoomAnnounceFmt = "%s has connected."; if (mudconf.have_comsys) { do_comconnect(player); } if (Dark(player)) { pMonitorAnnounceFmt = "GAME: %s has DARK-connected."; } else { pMonitorAnnounceFmt = "GAME: %s has connected."; } } else { pRoomAnnounceFmt = "%s has reconnected."; pMonitorAnnounceFmt = "GAME: %s has reconnected."; } sprintf(buf, pRoomAnnounceFmt, Name(player)); raw_broadcast(MONITOR, pMonitorAnnounceFmt, Name(player), 0, 0, 0, 0, 0); key = MSG_INV; if ( loc != NOTHING && !( Dark(player) && Wizard(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); if (Suspect(player)) { raw_broadcast(WIZARD, (char *)"[Suspect] %s has connected.", Name(player), 0, 0, 0, 0, 0); } if (d->host_info & H_SUSPECT) { raw_broadcast(WIZARD, (char *)"[Suspect site: %s] %s has connected.", d->addr, Name(player), 0, 0, 0, 0); } buf = atr_pget(player, A_ACONNECT, &aowner, &aflags); if (buf) { wait_que(player, player, 0, NOTHING, 0, buf, (char **)NULL, 0, NULL); } free_lbuf(buf); if (mudconf.master_room != NOTHING) { buf = atr_pget(mudconf.master_room, A_ACONNECT, &aowner, &aflags); if (buf) { wait_que( mudconf.master_room, player, 0, NOTHING, 0, buf, (char **)NULL, 0, NULL); } free_lbuf(buf); DOLIST(obj, Contents(mudconf.master_room)) { buf = atr_pget(obj, A_ACONNECT, &aowner, &aflags); if (buf) { wait_que( obj, player, 0, NOTHING, 0, buf, (char **)NULL, 0, NULL); } free_lbuf(buf); } } // Do the zone of the player's location's possible aconnect. // if ( mudconf.have_zones && ((zone = Zone(loc)) != NOTHING)) { switch (Typeof(zone)) { case TYPE_THING: buf = atr_pget(zone, A_ACONNECT, &aowner, &aflags); if (buf) { wait_que( zone, player, 0, NOTHING, 0, buf, (char **)NULL, 0, NULL); } free_lbuf(buf); break; case TYPE_ROOM: // check every object in the room for a connect action. // DOLIST(obj, Contents(zone)) { buf = atr_pget(obj, A_ACONNECT, &aowner, &aflags); if (buf) { wait_que(obj, player, 0, NOTHING, 0, buf, (char **)NULL, 0, NULL); } free_lbuf(buf); } break; default: log_text(tprintf("Invalid zone #%d for %s(#%d) has bad type %d", zone, Name(player), player, Typeof(zone))); } } CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); time_str = ltaNow.ReturnDateString(); record_login(player, 1, time_str, d->addr, d->username); look_in(player, Location(player), (LK_SHOWEXIT|LK_OBEYTERSE|LK_SHOWVRML)); mudstate.curr_enactor = temp; } void announce_disconnect(dbref player, DESC *d, const char *reason) { dbref loc, aowner, temp, zone, obj; int num, aflags, key; char *buf, *atr_temp; DESC *dtemp; char *argv[1]; if (Suspect(player)) { raw_broadcast(WIZARD, (char *)"[Suspect] %s has disconnected.", Name(player), 0, 0, 0, 0, 0); } if (d->host_info & H_SUSPECT) { raw_broadcast(WIZARD, (char *)"[Suspect site: %s] %s has disconnected.", d->addr, Name(d->player), 0, 0, 0, 0); } loc = Location(player); num = 0; DESC_ITER_PLAYER(player, dtemp) num++; temp = mudstate.curr_enactor; mudstate.curr_enactor = player; if (num < 2) { buf = alloc_mbuf("announce_disconnect.only"); sprintf(buf, "%s has disconnected.", Name(player)); key = MSG_INV; if ((loc != NOTHING) && !(Dark(player) && Wizard(player))) { key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST); } notify_check(player, player, buf, key); free_mbuf(buf); if (mudconf.have_mailer) { do_mail_purge(player); } raw_broadcast(MONITOR, (char *)"GAME: %s has disconnected.", Name(player), 0, 0, 0, 0, 0); c_Connected(player); if (mudconf.have_comsys) { do_comdisconnect(player); } argv[0] = (char *)reason; atr_temp = atr_pget(player, A_ADISCONNECT, &aowner, &aflags); if (*atr_temp) { wait_que(player, player, 0, NOTHING, 0, atr_temp, argv, 1, NULL); } free_lbuf(atr_temp); if (mudconf.master_room != NOTHING) { atr_temp = atr_pget(mudconf.master_room, A_ADISCONNECT, &aowner, &aflags); if (*atr_temp) { wait_que(mudconf.master_room, player, 0, NOTHING, 0, atr_temp, (char **)NULL, 0, NULL); } free_lbuf(atr_temp); DOLIST(obj, Contents(mudconf.master_room)) { atr_temp = atr_pget(obj, A_ADISCONNECT, &aowner, &aflags); if (*atr_temp) { wait_que(obj, player, 0, NOTHING, 0, atr_temp, (char **)NULL, 0, NULL); } free_lbuf(atr_temp); } } // Do the zone of the player's location's possible adisconnect. // if (mudconf.have_zones && ((zone = Zone(loc)) != NOTHING)) { switch (Typeof(zone)) { case TYPE_THING: atr_temp = atr_pget(zone, A_ADISCONNECT, &aowner, &aflags); if (*atr_temp) { wait_que(zone, player, 0, NOTHING, 0, atr_temp, (char **)NULL, 0, NULL); } free_lbuf(atr_temp); break; case TYPE_ROOM: // check every object in the room for a connect action. // DOLIST(obj, Contents(zone)) { atr_temp = atr_pget(obj, A_ADISCONNECT, &aowner, &aflags); if (*atr_temp) { wait_que(obj, player, 0, NOTHING, 0, atr_temp, (char **)NULL, 0, NULL); } free_lbuf(atr_temp); } break; default: log_text(tprintf("Invalid zone #%d for %s(#%d) has bad type %d", zone, Name(player), player, Typeof(zone))); } } 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); } } else { buf = alloc_mbuf("announce_disconnect.partial"); sprintf(buf, "%s has partially disconnected.", Name(player)); key = MSG_INV; if ((loc != NOTHING) && !(Dark(player) && Wizard(player))) { key |= (MSG_NBR | MSG_NBR_EXITS | MSG_LOC | MSG_FWDLIST); } notify_check(player, player, buf, key); raw_broadcast(MONITOR, (char *)"GAME: %s has partially disconnected.", Name(player), 0, 0, 0, 0, 0); free_mbuf(buf); } mudstate.curr_enactor = temp; desc_delhash(d); } int boot_off(dbref player, char *message) { DESC *d, *dnext; int count; count = 0; DESC_SAFEITER_PLAYER(player, d, dnext) { if (message && *message) { queue_string(d, message); queue_string(d, "\r\n"); } shutdownsock(d, R_BOOT); count++; } return count; } int boot_by_port(SOCKET port, int 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_string(d, message); queue_string(d, "\r\n"); } shutdownsock(d, R_BOOT); count++; } } return count; } /* * --------------------------------------------------------------------------- * * desc_reload: Reload parts of net descriptor that are based on db info. */ void desc_reload(dbref player) { DESC *d; char *buf; dbref aowner; FLAG aflags; DESC_ITER_PLAYER(player, d) { buf = atr_pget(player, A_TIMEOUT, &aowner, &aflags); if (buf) { d->timeout = Tiny_atol(buf); if (d->timeout <= 0) d->timeout = mudconf.idle_timeout; } free_lbuf(buf); } } /* * --------------------------------------------------------------------------- * * fetch_idle, fetch_connect: Return smallest idle time/largest connec time * * for a player (or -1 if not logged in) */ int fetch_idle(dbref target) { CLinearTimeDelta ltdResult; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); DESC *d; BOOL bFound = FALSE; DESC_ITER_PLAYER(target, d) { if (d->flags & DS_CONNECTED) { CLinearTimeDelta ltdIdle = ltaNow - d->last_time; if (!bFound || ltdIdle < ltdResult) { bFound = TRUE; ltdResult = ltdIdle; } } } if (bFound) { return ltdResult.ReturnSeconds(); } else { return -1; } } int fetch_connect(dbref target) { CLinearTimeDelta ltdResult; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); DESC *d; BOOL bFound = FALSE; DESC_ITER_PLAYER(target, d) { if (d->flags & DS_CONNECTED) { CLinearTimeDelta ltdConntime = ltaNow - d->connected_at; if (!bFound || ltdConntime < ltdResult) { bFound = TRUE; ltdResult = ltdConntime; } } } if (bFound) { return ltdResult.ReturnSeconds(); } else { return -1; } } void NDECL(check_idle) { DESC *d, *dnext; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); DESC_SAFEITER_ALL(d, dnext) { if (d->flags & DS_CONNECTED) { CLinearTimeDelta ltdIdle = ltaNow - d->last_time; if ((ltdIdle.ReturnSeconds() > d->timeout) && !Can_Idle(d->player)) { queue_string(d, "*** Inactivity Timeout ***\r\n"); shutdownsock(d, R_TIMEOUT); } else if ( mudconf.idle_wiz_dark && (ltdIdle.ReturnSeconds() > mudconf.idle_timeout) && Can_Idle(d->player) && !Dark(d->player)) { s_Flags(d->player, Flags(d->player) | DARK); d->flags |= DS_AUTODARK; } } else { CLinearTimeDelta ltdIdle = ltaNow - d->connected_at; if (ltdIdle.ReturnSeconds() > mudconf.conn_timeout) { queue_string(d, "*** Login Timeout ***\r\n"); shutdownsock(d, R_TIMEOUT); } } } } void check_events(void) { dbref thing, parent; int lev; CLinearTimeAbsolute ltaNow; ltaNow.GetLocal(); FIELDEDTIME ft; if (!ltaNow.ReturnFields(&ft)) { return; } // Resetting every midnight. // static int iLastHourChecked = 25; if (iLastHourChecked == 23 && ft.iHour < iLastHourChecked) { mudstate.events_flag &= ~ET_DAILY; } iLastHourChecked = ft.iHour; if ((ft.iHour == mudconf.events_daily_hour) && !(mudstate.events_flag & ET_DAILY)) { mudstate.events_flag |= ET_DAILY; DO_WHOLE_DB(thing) { if (Going(thing)) continue; ITER_PARENTS(thing, parent, lev) { if (Flags2(thing) & HAS_DAILY) { did_it(Owner(thing), thing, 0, NULL, 0, NULL, A_DAILY, (char **)NULL, 0); break; } } } } } #define MAX_TRIMMED_NAME_LENGTH 16 static char *trimmed_name(dbref player) { char *pName = Name(player); int nName = strlen(pName); if (nName <= MAX_TRIMMED_NAME_LENGTH) { return pName; } else { static char cbuff[MAX_TRIMMED_NAME_LENGTH+1]; memcpy(cbuff, pName, MAX_TRIMMED_NAME_LENGTH); cbuff[MAX_TRIMMED_NAME_LENGTH] = '\0'; return cbuff; } } static char *trimmed_site(char *szName) { static char buff[MBUF_SIZE]; unsigned int nLen = strlen(szName); if ( mudconf.site_chars <= 0 || nLen <= mudconf.site_chars) { return szName; } nLen = mudconf.site_chars; if (nLen > sizeof(buff)-1) { nLen = sizeof(buff)-1; } memcpy(buff, szName, nLen); buff[nLen] = '\0'; return buff; } static void dump_users(DESC *e, char *match, int key) { DESC *d; int count; char *buf, *fp, *sp, flist[4], slist[4]; dbref room_it; if (match) { while (Tiny_IsSpace[(unsigned char)*match]) match++; if (!*match) match = NULL; } if (e->flags & DS_PUEBLOCLIENT) queue_string(e, "<pre>"); buf = alloc_mbuf("dump_users"); if (key == CMD_SESSION) { queue_string(e, " "); queue_string(e, " Characters Input---- Characters Output---\r\n"); } queue_string(e, "Player Name On For Idle "); if (key == CMD_SESSION) { queue_string(e, "Port Pend Lost Total Pend Lost Total\r\n"); } else if ((e->flags & DS_CONNECTED) && (Wizard_Who(e->player)) && (key == CMD_WHO)) { queue_string(e, " Room Cmds Host\r\n"); } else { if (Wizard_Who(e->player)) queue_string(e, " "); else queue_string(e, " "); queue_string(e, mudstate.doing_hdr); queue_string(e, "\r\n"); } count = 0; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); DESC_ITER_CONN(d) { if (!Hidden(d->player) || (e->flags & DS_CONNECTED) & Wizard_Who(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'; } *fp = '\0'; *sp = '\0'; CLinearTimeDelta ltdConnected = ltaNow - d->connected_at; CLinearTimeDelta ltdLastTime = ltaNow - d->last_time; if ((e->flags & DS_CONNECTED) && Wizard_Who(e->player) && (key == CMD_WHO)) { sprintf(buf, "%-16s%9s %4s%-3s#%-6d%5d%3s%s\r\n", trimmed_name(d->player), time_format_1(ltdConnected.ReturnSeconds()), time_format_2(ltdLastTime.ReturnSeconds()), 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(ltdConnected.ReturnSeconds()), time_format_2(ltdLastTime.ReturnSeconds()), 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)) { sprintf(buf, "%-16s%9s %4s%-3s%s\r\n", trimmed_name(d->player), time_format_1(ltdConnected.ReturnSeconds()), time_format_2(ltdLastTime.ReturnSeconds()), flist, d->doing); } else { sprintf(buf, "%-16s%9s %4s %s\r\n", trimmed_name(d->player), time_format_1(ltdConnected.ReturnSeconds()), time_format_2(ltdLastTime.ReturnSeconds()), 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" : Tiny_ltoa_t(mudconf.max_players)); queue_string(e, buf); if (e->flags & DS_PUEBLOCLIENT) queue_string(e, "</pre>"); free_mbuf(buf); } char *MakeCanonicalDoing(char *pDoing, int *pnValidDoing, BOOL *pbValidDoing) { *pnValidDoing = 0; *pbValidDoing = FALSE; if (!pDoing) { return NULL; } // First, remove all '\r\n\t' from the string. // char *Buffer = RemoveSetOfCharacters(pDoing, "\r\n\t"); // Optimize/terminate any ANSI in the string. // int nVisualWidth; static char szFittedDoing[SIZEOF_DOING_STRING]; *pnValidDoing = ANSI_TruncateToField ( Buffer, SIZEOF_DOING_STRING, szFittedDoing, WIDTHOF_DOING_STRING, &nVisualWidth, FALSE ); *pbValidDoing = TRUE; return szFittedDoing; } // --------------------------------------------------------------------------- // do_doing: Set the doing string that appears in the WHO report. // Idea from R'nice@TinyTIM. // void do_doing(dbref player, dbref cause, int key, char *arg) { // Make sure there can be no embedded newlines from %r // static char *Empty = ""; char *szValidDoing = Empty; BOOL bValidDoing; int nValidDoing; if (arg) { szValidDoing = MakeCanonicalDoing(arg, &nValidDoing, &bValidDoing); if (!bValidDoing) { szValidDoing = Empty; nValidDoing = 0; } } if (key == DOING_MESSAGE) { int foundany = 0; DESC *d; DESC_ITER_PLAYER(player, d) { memcpy(d->doing, szValidDoing, nValidDoing+1); foundany = 1; } if (foundany) { if (!Quiet(player)) { notify(player, "Set."); } } else { notify(player, "Not connected."); } } else if (key == DOING_HEADER) { if (!(Can_Poll(player))) { notify(player, "Permission denied."); return; } if (nValidDoing == 0) { strcpy(mudstate.doing_hdr, "Doing"); } else { memcpy(mudstate.doing_hdr, szValidDoing, nValidDoing+1); } if (!Quiet(player)) { notify(player, "Set."); } } else { notify(player, tprintf("Poll: %s", mudstate.doing_hdr)); } } 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}, {NULL, 0, 0, 0} }; 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. */ for (cp = logout_cmdtable; cp->flag; cp++) { hashaddLEN(cp->name, strlen(cp->name), (int *)cp, &mudstate.logout_cmd_htab); } } static void failconn(const char *logcode, const char *logtype, const char *logreason, DESC *d, int disconnect_reason, dbref player, int filecache, char *motd_msg, char *command, char *user, char *password, char *cmdsave) { char *buff; STARTLOG(LOG_LOGIN | LOG_SECURITY, logcode, "RJCT"); buff = alloc_mbuf("failconn.LOG"); sprintf(buff, "[%d/%s] %s rejected to ", d->descriptor, d->addr, logtype); log_text(buff); free_mbuf(buff); if (player != NOTHING) log_name(player); else log_text(user); log_text((char *)" ("); log_text((char *)logreason); log_text((char *)")"); 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(DESC *d, char *msg) { char *command, *user, *password, *buff, *cmdsave; dbref player, aowner; int aflags, nplayers; 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); // At this point, command, user, and password are all less than // MBUF_SIZE. // if (!strncmp(command, "co", 2) || !strncmp(command, "cd", 2)) { if (string_prefix(user, mudconf.guest_prefix)) { if ( (d->host_info & H_GUEST) || ( !mudconf.allow_guest_from_registered_site && (d->host_info & H_REGISTRATION))) { // Someone from an IP with guest restrictions is // trying to use a guest account. Give them the blurb // most likely to have instructions about requesting a // character by other means and then fail this // connection. // // The guest 'power' is handled seperately further // down. // failconn("CONN", "Connect", "Guest Site Forbidden", d, R_GAMEDOWN, NOTHING, FC_CONN_REG, mudconf.downmotd_msg, command, user, password, cmdsave); return 0; } if ((mudconf.guest_char != NOTHING) && (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_prefix); } } // 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); if (player == NOTHING) { // Not a player, or wrong password. // queue_string(d, connect_fail); STARTLOG(LOG_LOGIN | LOG_SECURITY, "CON", "BAD"); buff = alloc_lbuf("check_conn.LOG.bad"); sprintf(buff, "[%d/%s] Failed connect to '%s'", d->descriptor, d->addr, user); log_text(buff); free_lbuf(buff); ENDLOG; 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 ( !strncmp(command, "cd", 2) && (Wizard(player) || God(player))) { s_Flags(player, Flags(player) | DARK); } // Make sure we don't have a guest from an unwanted host. // The majority of these are handled above. // // The following code handles the case where a staffer // (#1-only by default) has specifically given the guest 'power' // to an existing player. // // In this case, the player -already- has an account complete // with password. We still fail the connection to -this- player // but if the site isn't register_sited, this player can simply // auto-create another player. So, the procedure is not much // different from @newpassword'ing them. Oh well. We are just // following orders. ;) // if ( Guest(player) && ( (d->host_info & H_GUEST) || ( !mudconf.allow_guest_from_registered_site && (d->host_info & H_REGISTRATION)))) { 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"); buff = alloc_mbuf("check_conn.LOG.login"); sprintf(buff, "[%d/%s] Connected to ", d->descriptor, d->addr); log_text(buff); log_name_and_loc(player); free_mbuf(buff); ENDLOG; d->flags |= DS_CONNECTED; d->connected_at.GetUTC(); 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); if (*buff == '\0') 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); /* If stuck in an @prog, show the prompt */ if (d->program_data != NULL) queue_string(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)) { // 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_string(d, create_fail); STARTLOG(LOG_SECURITY | LOG_PCREATES, "CON", "BAD"); buff = alloc_lbuf("check_conn.LOG.badcrea"); sprintf(buff, "[%d/%s] Create of '%s' failed", d->descriptor, d->addr, user); log_text(buff); free_lbuf(buff); ENDLOG; } else { STARTLOG(LOG_LOGIN | LOG_PCREATES, "CON", "CREA"); buff = alloc_mbuf("check_conn.LOG.create"); sprintf(buff, "[%d/%s] Created ", d->descriptor, d->addr); log_text(buff); log_name(player); free_mbuf(buff); ENDLOG; move_object(player, mudconf.start_room); d->flags |= DS_CONNECTED; d->connected_at.GetUTC(); d->player = player; fcache_dump(d, FC_CREA_NEW); announce_connect(player, d); } } } else { welcome_user(d); STARTLOG(LOG_LOGIN | LOG_SECURITY, "CON", "BAD"); buff = alloc_mbuf("check_conn.LOG.bad"); msg[150] = '\0'; sprintf(buff, "[%d/%s] Failed connect: '%s'", d->descriptor, d->addr, msg); log_text(buff); free_mbuf(buff); ENDLOG; } free_lbuf(command); free_lbuf(user); free_lbuf(password); mudstate.debug_cmd = cmdsave; return 1; } int do_command(DESC *d, char *command, int first) { char *arg, *cmdsave; NAMETAB *cp; cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< do_command >"; d->last_time = mudstate.now; /* * Split off the command from the arguments */ arg = command; while (*arg && !Tiny_IsSpace[(unsigned char)*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 *)hashfindLEN(command, strlen(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_text(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, Tiny_atol(command + sizeof("Conn ID: ") - 1), n + 1); } } else if (!strncmp(command, "Kill ID: ", sizeof("Kill ID: ") - 1)) { do_killid(d, Tiny_atol(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 = Tiny_atol(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 // CONCENTRATE if (cp == NULL) { if (*arg) { // Restore nullified space // *--arg = ' '; } 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; process_command(d->player, d->player, 1, command, (char **)NULL, 0); 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_string(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_PUEBLOCLIENT: // 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_string(d, "\r\n"); break; default: { char buf[LBUF_SIZE * 2]; STARTLOG(LOG_BUGS, "BUG", "PARSE"); sprintf(buf, "Prefix command with no handler: '%s'", command); log_text(buf); ENDLOG; } } } if (!(cp->flag & CMD_NOxFIX)) { if (d->output_prefix) { queue_string(d, d->output_suffix); queue_write(d, "\r\n", 2); } } mudstate.debug_cmd = cmdsave; return 1; } void logged_out1(dbref player, dbref cause, int key, char *arg) { CLinearTimeAbsolute lsaNow; lsaNow.GetUTC(); DESC *d; DESC_ITER_PLAYER(player, d) { CLinearTimeDelta ltdIdle = lsaNow - d->last_time; int idletime = ltdIdle.ReturnSeconds(); 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_PUEBLOCLIENT: /* 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_string(d, "\r\n"); break; } } } void logged_out0(dbref player, dbref cause, int key) { logged_out1(player, cause, key, ""); } void Task_ProcessCommand(void *arg_voidptr, int arg_iInteger) { DESC *d = (DESC *)arg_voidptr; if (d) { CBLK *t = d->input_head; if (t) { if (d->quota > 0) { d->quota--; d->input_head = (CBLK *) t->hdr.nxt; if (d->input_head) { // There are still commands to process, so schedule another looksee. // scheduler.DeferImmediateTask(PRIORITY_SYSTEM, Task_ProcessCommand, d, 0); } else { d->input_tail = NULL; } d->input_size -= (strlen(t->cmd) + 1); if (d->program_data != NULL) handle_prog(d, t->cmd); else do_command(d, t->cmd, 1); free_lbuf(t); } else { // Don't bother looking for more quota until at least this much time has past. // CLinearTimeDelta ltd; ltd.SetMilliseconds(mudconf.timeslice); CLinearTimeAbsolute lsaWhen = mudstate.now + ltd; scheduler.DeferTask(lsaWhen, PRIORITY_SYSTEM, Task_ProcessCommand, d, 0); } } } } /* * --------------------------------------------------------------------------- * * site_check: Check for site flags in a site list. */ int site_check(struct in_addr host, SITE *site_list) { SITE *this0; for (this0 = site_list; this0; this0 = this0->next) { if ((host.s_addr & this0->mask.s_addr) == this0->address.s_addr) return this0->flag; } return 0; } /* * -------------------------------------------------------------------------- * * list_sites: Display information in a site list */ #define S_SUSPECT 1 #define S_ACCESS 2 static const char *stat_string(int strtype, int 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; } break; default: str = "Strange"; break; } return str; } static void list_sites(dbref player, SITE *site_list, const char *header_txt, int stat_type) { char *buff, *buff1, *str; SITE *this0; buff = alloc_mbuf("list_sites.buff"); buff1 = alloc_sbuf("list_sites.addr"); sprintf(buff, "----- %s -----", header_txt); notify(player, buff); notify(player, "Address Mask Status"); for (this0 = site_list; this0; this0 = this0->next) { str = (char *)stat_string(stat_type, this0->flag); StringCopy(buff1, inet_ntoa(this0->mask)); sprintf(buff, "%-20s %-20s %s", inet_ntoa(this0->address), buff1, str); notify(player, buff); } free_mbuf(buff); free_sbuf(buff1); } /* * --------------------------------------------------------------------------- * * list_siteinfo: List information about specially-marked sites. */ void list_siteinfo(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(dbref player, char *buff, char **bufc) { DESC *d; char *cp = *bufc; DESC_ITER_CONN(d) { if (!WizRoy(player) && Hidden(d->player)) { continue; } if (cp != *bufc) { safe_chr(' ', buff, bufc); } safe_chr('#', buff, bufc); safe_ltoa(d->player, buff, bufc, LBUF_SIZE-1); } } /* * --------------------------------------------------------------------------- * * 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(dbref player, char *name) { DESC *d; dbref found; found = NOTHING; DESC_ITER_CONN(d) { if (Good_obj(player) && !Wizard(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; } FUNCTION(fun_doing) { dbref victim = lookup_player(player, fargs[0], 1); if (victim == NOTHING) { safe_str("#-1 PLAYER DOES NOT EXIST", buff, bufc); return; } if (!Wizard_Who(player) && Hidden(victim)) { safe_str("#-1 NOT A CONNECTED PLAYER", buff, bufc); return; } for (DESC *d = descriptor_list; d; d = d->next) { if (d->player == victim) { safe_str(d->doing, buff, bufc); return; } } safe_str("#-1 NOT A CONNECTED PLAYER", buff, bufc); } FUNCTION(fun_poll) { safe_str(mudstate.doing_hdr, buff, bufc); } FUNCTION(fun_motd) { safe_str(mudconf.motd_msg, buff, bufc); } // fetch_cmds - Retrieve Player's number of commands entered. // int fetch_cmds(dbref target) { int sum = 0; BOOL bFound = FALSE; DESC *d; DESC_ITER_PLAYER(target, d) { sum += d->command_count; bFound = TRUE; } if (bFound) { return sum; } else { return -1; } } void ParseConnectionInfoString(char *pConnInfo, char *pFields[5]) { TINY_STRTOK_STATE tts; Tiny_StrTokString(&tts, pConnInfo); Tiny_StrTokControl(&tts, " "); for (int i = 0; i < 5; i++) { pFields[i] = Tiny_StrTokParse(&tts); } } void fetch_ConnectionInfoFields(dbref target, long anFields[4]) { dbref aowner; int aflags; char *pConnInfo = atr_get(target, A_CONNINFO, &aowner, &aflags); char *aFields[5]; ParseConnectionInfoString(pConnInfo, aFields); for (int i = 0; i < 4; i++) { long result; if (!aFields[i] || (result = Tiny_atol(aFields[i])) < 0) { result = 0; } anFields[i] = result; } free_lbuf(pConnInfo); } void put_ConnectionInfoFields ( dbref target, long anFields[4], CLinearTimeAbsolute <aLogout ) { char *pConnInfo = alloc_lbuf("put_CIF"); char *p = pConnInfo; for (int i = 0; i < 4; i++) { p += Tiny_ltoa(anFields[i], p); *p++ = ' '; } p += Tiny_i64toa(ltaLogout.ReturnSeconds(), p); *p++ = 0; atr_add_raw_LEN(target, A_CONNINFO, pConnInfo, p - pConnInfo); free_lbuf(pConnInfo); } long fetch_ConnectionInfoField(dbref target, int iField) { dbref aowner; int aflags; char *pConnInfo = atr_get(target, A_CONNINFO, &aowner, &aflags); char *aFields[5]; ParseConnectionInfoString(pConnInfo, aFields); long result; if (!aFields[iField] || (result = Tiny_atol(aFields[iField])) < 0) { result = 0; } free_lbuf(pConnInfo); return result; } #define CIF_LOGOUTTIME 4 CLinearTimeAbsolute fetch_logouttime(dbref target) { dbref aowner; int aflags; char *pConnInfo = atr_get(target, A_CONNINFO, &aowner, &aflags); char *aFields[5]; ParseConnectionInfoString(pConnInfo, aFields); CLinearTimeAbsolute lta; if (aFields[CIF_LOGOUTTIME]) { lta.SetSecondsString(aFields[CIF_LOGOUTTIME]); } else { lta.SetSeconds(0); } free_lbuf(pConnInfo); return lta; }