+++ /dev/null
-/**
- * \file console.c
- *
- * \brief Alternative main function for PennMUSH which runs on the console
- * instead of over the network.
- */
-
-#include "copyrite.h"
-#include "config.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#ifdef I_SYS_TYPES
-#include <sys/types.h>
-#endif
-#ifdef WIN32
-#define FD_SETSIZE 256
-#include <windows.h>
-#include <winsock.h>
-#include <io.h>
-#define EINTR WSAEINTR
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#define MAXHOSTNAMELEN 32
-#define LC_MESSAGES 6
-#else /* !WIN32 */
-#ifdef I_SYS_FILE
-#include <sys/file.h>
-#endif
-#ifdef I_SYS_TIME
-#include <sys/time.h>
-#endif
-#include <sys/ioctl.h>
-#include <errno.h>
-#ifdef I_SYS_SOCKET
-#include <sys/socket.h>
-#endif
-#ifdef I_NETINET_IN
-#include <netinet/in.h>
-#endif
-#ifdef I_NETDB
-#include <netdb.h>
-#endif
-#ifdef I_SYS_PARAM
-#include <sys/param.h>
-#endif
-#ifdef I_SYS_STAT
-#include <sys/stat.h>
-#endif
-#endif /* !WIN32 */
-#include <time.h>
-#ifdef I_SYS_WAIT
-#include <sys/wait.h>
-#endif
-#include <fcntl.h>
-#include <ctype.h>
-#include <signal.h>
-#include <string.h>
-#include <stdlib.h>
-#ifdef I_SYS_SELECT
-#include <sys/select.h>
-#endif
-#ifdef I_UNISTD
-#include <unistd.h>
-#endif
-#ifdef HAS_GETRLIMIT
-#include <sys/resource.h>
-#endif
-#include <limits.h>
-#ifdef I_FLOATINGPOINT
-#include <floatingpoint.h>
-#endif
-#include <locale.h>
-#ifdef __APPLE__
-#define LC_MESSAGES 6
-#define AUTORESTART
-#endif
-#include <setjmp.h>
-
-#include "conf.h"
-
-#include "externs.h"
-#include "chunk.h"
-#include "mushdb.h"
-#include "dbdefs.h"
-#include "flags.h"
-#include "lock.h"
-#include "help.h"
-#include "match.h"
-#include "ansi.h"
-#include "pueblo.h"
-#include "parse.h"
-#include "access.h"
-#include "command.h"
-#include "version.h"
-#include "patches.h"
-#include "mysocket.h"
-#include "ident.h"
-#include "strtree.h"
-#include "log.h"
-#include "pcre.h"
-#include "mymalloc.h"
-#include "extmail.h"
-#include "attrib.h"
-#include "game.h"
-#include "dbio.h"
-#include "confmagic.h"
-#ifdef HAS_WAITPID
-/** What does wait*() return? */
-#define WAIT_TYPE int
-#else
-#ifdef UNION_WAIT
-#define WAIT_TYPE union wait
-#else
-#define WAIT_TYPE int
-#endif
-#endif
-
-
-/* BSD 4.2 and maybe some others need these defined */
-#ifndef FD_ZERO
-/** An fd_set is 4 bytes */
-#define fd_set int
-/** Clear an fd_set */
-#define FD_ZERO(p) (*p = 0)
-/** Set a bit in an fd_set */
-#define FD_SET(n,p) (*p |= (1<<(n)))
-/** Clear a bit in an fd_set */
-#define FD_CLR(n,p) (*p &= ~(1<<(n)))
-/** Check a bit in an fd_set */
-#define FD_ISSET(n,p) (*p & (1<<(n)))
-#endif /* defines for BSD 4.2 */
-
-#ifdef HAS_GETRUSAGE
-void rusage_stats(void);
-#endif
-int que_next(void); /* from cque.c */
-
-void dispatch(void); /* from timer.c */
-dbref email_register_player(const char *name, const char *email, const char *host, const char *ip); /* from player.c */
-
-static int extrafd;
-int shutdown_flag = 0; /**< Is it time to shut down? */
-#ifdef CHAT_SYSTEM
-void chat_player_announce(dbref player, char *msg, int ungag);
-#endif /* CHAT_SYSTEM */
-
-static int login_number = 0;
-static int under_limit = 1;
-
-char cf_motd_msg[BUFFER_LEN]; /**< The message of the day */
-char cf_downmotd_msg[BUFFER_LEN]; /**< The down message */
-char cf_fullmotd_msg[BUFFER_LEN]; /**< The 'mush full' message */
-static char poll_msg[DOING_LEN];
-char confname[BUFFER_LEN]; /**< Name of the config file */
-char errlog[BUFFER_LEN]; /**< Name of the error log file */
-
-/* Default Connection flags for certain clients
- */
-static CLIENT_DEFAULTS client_maps[] = {
- {"TINYFUGUE", CONN_PROMPT},
- {NULL, -1}
-};
-
-
-/** Is this descriptor connected to a telnet-compatible terminal? */
-#define TELNET_ABLE(d) ((d)->conn_flags & (CONN_TELNET | CONN_TELNET_QUERY))
-
-
-/* When the mush gets a new connection, it tries sending a telnet
- * option negotiation code for setting client-side line-editing mode
- * to it. If it gets a reply, a flag in the descriptor struct is
- * turned on indicated telnet-awareness.
- *
- * If the reply indicates that the client supports linemode, further
- * instructions as to what linemode options are to be used is sent.
- * Those options: Client-side line editing, and expanding literal
- * client-side-entered tabs into spaces.
- *
- * Option negotation requests sent by the client are processed,
- * with the only one we confirm rather than refuse outright being
- * suppress-go-ahead, since a number of telnet clients try it.
- *
- * The character 255 is the telnet option escape character, so when it
- * is sent to a telnet-aware client by itself (Since it's also often y-umlaut)
- * it must be doubled to escape it for the client. This is done automatically,
- * and is the original purpose of adding telnet option support.
- */
-
-/* Telnet codes */
-#define IAC 255 /**< interpret as command: */
-#define GOAHEAD 249 /**< Go Ahead command */
-#define NOP 241 /**< no operation */
-#define AYT 246 /**< are you there? */
-#define DONT 254 /**< you are not to use option */
-#define DO 253 /**< please, you use option */
-#define WONT 252 /**< I won't use option */
-#define WILL 251 /**< I will use option */
-#define SB 250 /**< interpret as subnegotiation */
-#define SE 240 /**< end sub negotiation */
-#define TN_SGA 3 /**< Suppress go-ahead */
-#define TN_LINEMODE 34 /**< Line mode */
-#define TN_NAWS 31 /**< Negotiate About Window Size */
-#define TN_TTYPE 24 /**< Ask for termial type information */
-static void test_telnet(DESC *d);
-static void setup_telnet(DESC *d);
-static int handle_telnet(DESC *d, unsigned char **q, unsigned char *qend);
-static const char *empabb(dbref);
-static int do_su_exit(DESC *d);
-
-static const char *create_fail =
- "Either there is already a player with that name, or that name is illegal.";
-static const char *password_fail = "The password is invalid (or missing).";
-static const char *register_fail =
- "Unable to register that player with that email address.";
-static const char *register_success =
- "Registration successful! You will receive your password by email.";
-static const char *shutdown_message = "Going down - Bye";
-/** Where we save the descriptor info across reboots. */
-#define REBOOTFILE "reboot.db"
-
-#if 0
-/* For translation */
-static void dummy_msgs(void);
-static void
-dummy_msgs()
-{
- char *temp;
- temp = T("Either that player does not exist, or has a different password.");
- temp =
- T
- ("Either there is already a player with that name, or that name is illegal.");
- temp = T("The password is invalid (or missing).");
- temp = T("Unable to register that player with that email address.");
- temp = T("Registration successful! You will receive your password by email.");
- temp = T("Going down - Bye");
- temp = T("GAME: SSL connections must be dropped, sorry.");
-}
-
-#endif
-
-DESC *descriptor_list = NULL; /**< The linked list of descriptors */
-
-#ifdef WIN32
-static WSADATA wsadata;
-#endif
-int restarting = 0; /**< Are we restarting the server after a reboot? */
-int ndescriptors = 0;
-
-extern const unsigned char *tables;
-
-sig_atomic_t signal_shutdown_flag = 0; /**< Have we caught a shutdown signal? */
-sig_atomic_t signal_dump_flag = 0; /**< Have we caught a dump signal? */
-
-#ifdef HAS_GETRLIMIT
-static void init_rlimit(void);
-#endif
-#ifndef BOOLEXP_DEBUGGING
-#ifdef WIN32SERVICES
-void shutdown_checkpoint(void);
-void mainthread(int argc, char **argv);
-#else
-int main(int argc, char **argv);
-#endif
-#endif
-void set_signals(void);
-static struct timeval *timeval_sub(struct timeval *now, struct timeval *then);
-#ifdef WIN32
-/** Windows doesn't have gettimeofday(), so we implement it here */
-#define our_gettimeofday(now) win_gettimeofday((now))
-static void win_gettimeofday(struct timeval *now);
-#else
-/** A wrapper for gettimeofday() in case the system doesn't have it */
-#define our_gettimeofday(now) gettimeofday((now), (struct timezone *)NULL)
-#endif
-static long int msec_diff(struct timeval *now, struct timeval *then);
-static struct timeval *msec_add(struct timeval *t, int x);
-static void update_quotas(struct timeval *last, struct timeval *current);
-
-static void shovechars(void);
-
-static void clearstrings(DESC *d);
-
-/** A block of cached text. */
-typedef struct fblock {
- unsigned char *buff; /**< Pointer to the block as a string */
- size_t len; /**< Length of buff */
-} FBLOCK;
-
-/** The complete collection of cached text files. */
-struct fcache_entries {
- FBLOCK connect_fcache[2]; /**< connect.txt and connect.html */
- FBLOCK motd_fcache[2]; /**< motd.txt and motd.html */
- FBLOCK newuser_fcache[2]; /**< newuser.txt and newuser.html */
- FBLOCK register_fcache[2]; /**< register.txt and register.html */
- FBLOCK quit_fcache[2]; /**< quit.txt and quit.html */
- FBLOCK down_fcache[2]; /**< down.txt and down.html */
- FBLOCK full_fcache[2]; /**< full.txt and full.html */
- FBLOCK guest_fcache[2]; /**< guest.txt and guest.html */
-};
-
-void feed_snoop(DESC *, const char *, char );
-char is_snooped(DESC *);
-char set_snoop(dbref, DESC *);
-void clr_snoop(dbref, DESC *);
-void announce_connect(dbref player, int isnew, int num);
-void announce_disconnect(dbref player);
-void add_to_exit_path(DESC *d, dbref player);
-
-static struct fcache_entries fcache;
-static void fcache_dump(DESC *d, FBLOCK fp[2], const unsigned char *prefix);
-static int fcache_read(FBLOCK *cp, const char *filename);
-static void logout_sock(DESC *d);
-static void shutdownsock(DESC *d);
-static DESC *initializesock(int s, char *addr, char *ip, int use_ssl);
-int process_output(DESC *d);
-/* Notify.c */
-extern void free_text_block(struct text_block *t);
-extern void add_to_queue(struct text_queue *q, const unsigned char *b, int n);
-extern int queue_write(DESC *d, const unsigned char *b, int n);
-extern int queue_eol(DESC *d);
-extern int queue_newwrite(DESC *d, const unsigned char *b, int n);
-extern int queue_string(DESC *d, const char *s);
-extern int queue_string_eol(DESC *d, const char *s);
-extern void freeqs(DESC *d);
-static void welcome_user(DESC *d);
-static void dump_info(DESC *call_by);
-static void save_command(DESC *d, const unsigned char *command);
-static int process_input(DESC *d, int output_ready);
-static void process_input_helper(DESC *d, char *tbuf1, int got);
-static void set_userstring(unsigned char **userstring, const char *command);
-static void process_commands(void);
-static void parse_puebloclient(DESC *d, char *command);
-static int dump_messages(DESC *d, dbref player, int new);
-static int check_connect(DESC *d, const char *msg);
-static void parse_connect(const char *msg, char *command, char *user,
- char *pass);
-static void close_sockets(void);
-dbref find_player_by_desc(int port);
-static DESC *lookup_desc(dbref executor, const char *name);
-void NORETURN bailout(int sig);
-void WIN32_CDECL signal_shutdown(int sig);
-void WIN32_CDECL signal_dump(int sig);
-void reaper(int sig);
-extern Pid_t forked_dump_pid; /**< Process id of forking dump process */
-static void dump_users(DESC *call_by, char *match, int doing);
-static const char *time_format_1(long int dt);
-static const char *time_format_2(long int dt);
-
-void inactivity_check(void);
-void reopen_logs(void);
-void load_reboot_db(void);
-#ifdef HAS_GETRLIMIT
-static void
-init_rlimit(void)
-{
- /* Unlimit file descriptors. */
- /* Ultrix 4.4 and others may have getrlimit but may not be able to
- * change number of file descriptors
- */
-#ifdef RLIMIT_NOFILE
- struct rlimit *rlp;
-
- rlp = (struct rlimit *) malloc(sizeof(struct rlimit));
- if (getrlimit(RLIMIT_NOFILE, rlp)) {
- perror("init_rlimit: getrlimit()");
- free(rlp);
- return;
- }
- /* This check seems dumb, but apparently FreeBSD may return 0 for
- * the max # of descriptors!
- */
- if (rlp->rlim_max > rlp->rlim_cur) {
- rlp->rlim_cur = rlp->rlim_max;
- if (setrlimit(RLIMIT_NOFILE, rlp))
- perror("init_rlimit: setrlimit()");
- }
- free(rlp);
-#endif
- return;
-}
-#endif /* HAS_GETRLIMIT */
-
-#ifndef BOOLEXP_DEBUGGING
-#ifdef WIN32SERVICES
-/* Under WIN32, MUSH is a "service", so we just start a thread here.
- * The real "main" is in win32/services.c
- */
-void
-mainthread(int argc, char **argv)
-#else
-/** The main function.
- * \param argc number of arguments.
- * \param argv vector of arguments.
- * \return exit code.
- */
-int
-main(int argc, char **argv)
-#endif /* WIN32SERVICES */
-{
-#ifdef AUTORESTART
- FILE *id;
-#endif
- FILE *newerr;
-
- /* read the configuration file */
- if (argc < 2) {
- fprintf(stderr, "ERROR: Usage: %s /path/to/config_file\n", argv[0]);
- exit(2);
- }
-
-#ifdef WIN32
- {
- unsigned short wVersionRequested = MAKEWORD(1, 1);
- int err;
-
- /* Need to include library: wsock32.lib for Windows Sockets */
- err = WSAStartup(wVersionRequested, &wsadata);
- if (err) {
- printf(T("Error %i on WSAStartup\n"), err);
- exit(1);
- }
- }
-#endif /* WIN32 */
-
-#ifdef HAS_GETRLIMIT
- init_rlimit(); /* unlimit file descriptors */
-#endif
-
- /* These are FreeBSDisms to fix floating point exceptions */
-#ifdef HAS_FPSETROUND
- fpsetround(FP_RN);
-#endif
-#ifdef HAS_FPSETMASK
- fpsetmask(0L);
-#endif
-
- time(&mudtime);
-
- /* If we have setlocale, call it to set locale info
- * from environment variables
- */
-#ifdef HAS_SETLOCALE
- {
- char *loc;
- if ((loc = setlocale(LC_CTYPE, "")) == NULL)
- do_rawlog(LT_ERR, "Failed to set ctype locale from environment.");
- else
- do_rawlog(LT_ERR, "Setting ctype locale to %s", loc);
- if ((loc = setlocale(LC_TIME, "")) == NULL)
- do_rawlog(LT_ERR, "Failed to set time locale from environment.");
- else
- do_rawlog(LT_ERR, "Setting time locale to %s", loc);
- if ((loc = setlocale(LC_MESSAGES, "")) == NULL)
- do_rawlog(LT_ERR, "Failed to set messages locale from environment.");
- else
- do_rawlog(LT_ERR, "Setting messages locale to %s", loc);
- if ((loc = setlocale(LC_COLLATE, "")) == NULL)
- do_rawlog(LT_ERR, "Failed to set collate locale from environment.");
- else
- do_rawlog(LT_ERR, "Setting collate locale to %s", loc);
- }
-#endif
-#ifdef HAS_TEXTDOMAIN
- textdomain("pennmush");
-#endif
-#ifdef HAS_BINDTEXTDOMAIN
- bindtextdomain("pennmush", "../po");
-#endif
-
- /* Build the locale-dependant tables used by PCRE */
- tables = pcre_maketables();
-
-/* this writes a file used by the restart script to check for active mush */
-#ifdef AUTORESTART
- id = fopen("runid", "w");
- fprintf(id, "%d", getpid());
- fclose(id);
-#endif
-
- strncpy(confname, argv[1], BUFFER_LEN - 1);
- confname[BUFFER_LEN - 1] = '\0';
- init_game_config(confname);
-
- /* save a file descriptor */
- reserve_fd();
-#ifndef WIN32
- extrafd = open("/dev/null", O_RDWR);
-#endif
-
- /* decide if we're in @shutdown/reboot */
- restarting = 0;
- newerr = fopen(REBOOTFILE, "r");
- if (newerr) {
- restarting = 1;
- fclose(newerr);
- }
-
- init_qids();
- if (init_game_dbs() < 0) {
- do_rawlog(LT_ERR, T("ERROR: Couldn't load databases! Exiting."));
- exit(2);
- }
-
- init_game_postdb(confname);
-
- globals.database_loaded = 1;
-
- set_signals();
-
- /* go do it */
-#ifdef CSRI
-#ifdef CSRI_DEBUG
- mal_verify(1);
-#endif
-#ifdef CSRI_TRACE
- mal_leaktrace(1);
-#endif
-#endif
- load_reboot_db();
- shovechars();
-#ifdef CSRI
-#ifdef CSRI_DEBUG
- mal_verify(1);
-#endif
-#endif
-
- /* someone has told us to shut down */
-#ifdef WIN32SERVICES
- /* Keep service manager happy */
- shutdown_checkpoint();
-#endif
-
- shutdown_queues();
-
-#ifdef WIN32SERVICES
- /* Keep service manager happy */
- shutdown_checkpoint();
-#endif
-
- close_sockets();
- sql_shutdown();
-
-#ifdef WIN32SERVICES
- /* Keep service manager happy */
- shutdown_checkpoint();
-#endif
-
- dump_database();
-
- local_shutdown();
-
-#ifdef RPMODE_SYS
- rplog_shutdown();
-#endif
-
- end_all_logs();
-
-#ifdef CSRI
-#ifdef CSRI_PROFILESIZES
- mal_statsdump(stderr);
-#endif
-#ifdef CSRI_TRACE
- mal_dumpleaktrace(stderr);
-#endif
- fflush(stderr);
-#endif
-
-#ifdef WIN32SERVICES
- /* Keep service manager happy */
- shutdown_checkpoint();
-#endif
-
-#ifdef HAS_GETRUSAGE
- rusage_stats();
-#endif /* HAS_RUSAGE */
-
- do_rawlog(LT_ERR, T("MUSH shutdown completed."));
-
-#ifdef WIN32
-#ifdef WIN32SERVICES
- shutdown_checkpoint();
-#endif
- WSACleanup(); /* clean up */
-#else
-#ifdef __APPLE__
- unlink("runid");
-#endif
- exit(0);
-#endif
-}
-#endif /* BOOLEXP_DEBUGGING */
-
-/** Close and reopen the logfiles - called on SIGHUP */
-void
-reopen_logs(void)
-{
- FILE *newerr;
- /* close up the log files */
- end_all_logs();
- newerr = fopen(errlog, "a");
- if (!newerr) {
- fprintf(stderr,
- T("Unable to open %s. Error output continues to stderr.\n"),
- errlog);
- } else {
- if (!freopen(errlog, "a", stderr)) {
- printf(T("Ack! Failed reopening stderr!"));
- exit(1);
- }
- setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
- fclose(newerr);
- }
- start_all_logs();
-}
-
-/** Install our default signal handlers. */
-void
-set_signals(void)
-{
-
-#ifndef WIN32
- /* we don't care about SIGPIPE, we notice it in select() and write() */
- ignore_signal(SIGPIPE);
- install_sig_handler(SIGUSR2, signal_dump);
- install_sig_handler(SIGQUIT, signal_shutdown);
- install_sig_handler(SIGINT, signal_shutdown);
- install_sig_handler(SIGTERM, bailout);
-#else
- /* Win32 stuff:
- * No support for SIGUSR2 or SIGINT.
- * SIGTERM is never generated on NT-based Windows (according to MSDN)
- * MSVC++ will let you get away with installing a handler anyway,
- * but VS.NET will not. So if it's MSVC++, we give it a try.
- */
-#if _MSC_VER < 1200
- install_sig_handler(SIGTERM, bailout);
-#endif
-#endif
-
-#ifndef WIN32
- install_sig_handler(SIGCHLD, reaper);
-#endif
-
-}
-
-#ifdef WIN32
-/** Get the time using Windows function call.
- * Looks weird, but it works. :-P
- * \param now address to store timeval data.
- */
-static void
-win_gettimeofday(struct timeval *now)
-{
-
- FILETIME win_time;
-
- GetSystemTimeAsFileTime(&win_time);
- /* dwLow is in 100-s nanoseconds, not microseconds */
- now->tv_usec = win_time.dwLowDateTime % 10000000 / 10;
-
- /* dwLow contains at most 429 least significant seconds, since 32 bits maxint is 4294967294 */
- win_time.dwLowDateTime /= 10000000;
-
- /* Make room for the seconds of dwLow in dwHigh */
- /* 32 bits of 1 = 4294967295. 4294967295 / 429 = 10011578 */
- win_time.dwHighDateTime %= 10011578;
- win_time.dwHighDateTime *= 429;
-
- /* And add them */
- now->tv_sec = win_time.dwHighDateTime + win_time.dwLowDateTime;
-}
-
-#endif
-
-/** Return the difference between two timeval structs as a timeval struct.
- * \param now pointer to the timeval to subtract from.
- * \param then pointer to the timeval to subtract.
- * \return pointer to a statically allocated timeval of the difference.
- */
-static struct timeval *
-timeval_sub(struct timeval *now, struct timeval *then)
-{
- static struct timeval mytime;
- mytime.tv_sec = now->tv_sec;
- mytime.tv_usec = now->tv_usec;
-
- mytime.tv_sec -= then->tv_sec;
- mytime.tv_usec -= then->tv_usec;
- if (mytime.tv_usec < 0) {
- mytime.tv_usec += 1000000;
- mytime.tv_sec--;
- }
- return &mytime;
-}
-
-/** Return the difference between two timeval structs in milliseconds.
- * \param now pointer to the timeval to subtract from.
- * \param then pointer to the timeval to subtract.
- * \return milliseconds of difference between them.
- */
-static long int
-msec_diff(struct timeval *now, struct timeval *then)
-{
- long int secs = now->tv_sec - then->tv_sec;
- if (secs == 0)
- return (now->tv_usec - then->tv_usec) / 1000;
- else if (secs == 1)
- return (now->tv_usec + (1000000 - then->tv_usec)) / 100;
- else if (secs > 1)
- return (secs * 1000) + ((now->tv_usec + (1000000 - then->tv_usec)) / 1000);
- else
- return 0;
-}
-
-/** Add a given number of milliseconds to a timeval.
- * \param t pointer to a timeval struct.
- * \param x number of milliseconds to add to t.
- * \return address of static timeval struct representing the sum.
- */
-static struct timeval *
-msec_add(struct timeval *t, int x)
-{
- static struct timeval mytime;
- mytime.tv_sec = t->tv_sec;
- mytime.tv_usec = t->tv_usec;
- mytime.tv_sec += x / 1000;
- mytime.tv_usec += (x % 1000) * 1000;
- if (mytime.tv_usec >= 1000000) {
- mytime.tv_sec += mytime.tv_usec / 1000000;
- mytime.tv_usec = mytime.tv_usec % 1000000;
- }
- return &mytime;
-}
-
-/** Update each descriptor's allowed rate of issuing commands.
- * Players are rate-limited; they may only perform up to a certain
- * number of commands per time slice. This function is run periodically
- * to refresh each descriptor's available command quota based on how
- * many slices have passed since it was last updated.
- * \param last pointer to timeval struct of last time quota was updated.
- * \param current pointer to timeval struct of current time.
- */
-static void
-update_quotas(struct timeval *last, struct timeval *current)
-{
- int nslices;
- DESC *d;
- nslices = (int) msec_diff(current, last) / COMMAND_TIME_MSEC;
-
- if (nslices > 0) {
- for (d = descriptor_list; d; d = d->next) {
- d->quota += COMMANDS_PER_TIME * nslices;
- if (d->quota > COMMAND_BURST_SIZE)
- d->quota = COMMAND_BURST_SIZE;
- }
- }
-}
-
-static const char *empabb(dbref player) {
- static char str[4];
- ATTR *a;
- /*
- dbref start, end, last;
- */
- dbref start;
-
- memset(str, '\0', 4);
-
- if(!IsDivision(SDIV(player).object))
- goto bad_empabb_value;
- start = SDIV(player).object;
-
- /*
- for(last = end = start; GoodObject(end) && IsDivision(end) &&
- !has_flag_by_name(end, "EMPIRE", TYPE_DIVISION) ; last = end, end = SDIV(end).object)
- ;
- if(!has_flag_by_name(end, "EMPIRE", TYPE_DIVISION)) {
- if(end == NOTHING && IsDivision(last))
- end = last;
- else end = start;
- }
- */
- /* K, end is the empire we're grabbing this off of */
- a = atr_get(start, "ALIAS");
- if(!a)
- goto bad_empabb_value;
- strncpy(str, atr_value(a), 3);
- if(!str[0])
- goto bad_empabb_value;
- return str;
-
-
-bad_empabb_value:
- strncpy(str, "---", 3);
- return str;
-}
-
-
-static void
-shovechars()
-{
- /* this is the main game loop */
-
- fd_set input_set, output_set;
- time_t now;
- struct timeval last_slice, current_time, then;
- struct timeval next_slice, *returned_time;
- struct timeval timeout, slice_timeout;
- int found;
- int queue_timeout;
- DESC *d, *dnext;
- int input_ready, output_ready;
-
- d = initializesock(0, "localhost", "127.0.0.1", 0);
-
- our_gettimeofday(&last_slice);
-
- /* done. print message to the log */
- do_rawlog(LT_ERR, "RESTART FINISHED.");
-
- our_gettimeofday(&then);
-
- while (shutdown_flag == 0) {
- our_gettimeofday(¤t_time);
-
- update_quotas(&last_slice, ¤t_time);
- last_slice.tv_sec = current_time.tv_sec;
- last_slice.tv_usec = current_time.tv_usec;
-
- if (msec_diff(¤t_time, &then) >= 1000) {
- globals.on_second = 1;
- then.tv_sec = current_time.tv_sec;
- then.tv_usec = current_time.tv_usec;
- }
-
- process_commands();
-
- if (signal_shutdown_flag) {
- flag_broadcast(0, 0, T("GAME: Shutdown by external signal"));
- do_rawlog(LT_ERR, T("SHUTDOWN by external signal"));
-#ifdef AUTORESTART
- system("touch NORESTART");
-#endif
- shutdown_flag = 1;
- }
-
- if (signal_dump_flag) {
- globals.paranoid_dump = 0;
- do_rawlog(LT_CHECK, "DUMP by external signal");
- fork_and_dump(1);
- signal_dump_flag = 0;
- }
-
- if (shutdown_flag)
- break;
-
- /* test for events */
- dispatch();
-
- /* any queued robot commands waiting? */
- /* timeout.tv_sec used to be set to que_next(), the number of
- * seconds before something on the queue needed to run, but this
- * caused a problem with stuff that had to be triggered by alarm
- * signal every second, so we're reduced to what's below:
- */
- queue_timeout = que_next();
- timeout.tv_sec = queue_timeout ? 1 : 0;
- timeout.tv_usec = 0;
-
- returned_time = msec_add(&last_slice, COMMAND_TIME_MSEC);
- next_slice.tv_sec = returned_time->tv_sec;
- next_slice.tv_usec = returned_time->tv_usec;
-
- returned_time = timeval_sub(&next_slice, ¤t_time);
- slice_timeout.tv_sec = returned_time->tv_sec;
- slice_timeout.tv_usec = returned_time->tv_usec;
- /* Make sure slice_timeout cannot have a negative time. Better
- safe than sorry. */
- if (slice_timeout.tv_sec < 0)
- slice_timeout.tv_sec = 0;
- if (slice_timeout.tv_usec < 0)
- slice_timeout.tv_usec = 0;
-
- FD_ZERO(&input_set);
- FD_ZERO(&output_set);
- for (d = descriptor_list; d; d = d->next) {
- if (d->input.head) {
- timeout.tv_sec = slice_timeout.tv_sec;
- timeout.tv_usec = slice_timeout.tv_usec;
- } else {
- if(d->descriptor == 0)
- FD_SET(STDIN_FILENO, &input_set);
- else
- FD_SET(d->descriptor, &input_set);
- }
- if (d->output.head) {
- if(d->descriptor == 0)
- FD_SET(STDOUT_FILENO, &output_set);
- else
- FD_SET(d->descriptor, &output_set);
- }
- }
-
- found = select(2, &input_set, &output_set, (fd_set *) 0, &timeout);
- if (found < 0) {
-#ifdef WIN32
- if (found == SOCKET_ERROR && WSAGetLastError() != WSAEINTR)
-#else
- if (errno != EINTR)
-#endif
- {
- perror("select");
- return;
- }
- } else {
- /* if !found then time for robot commands */
-
- if (!found) {
- do_top(options.queue_chunk);
- continue;
- } else {
- do_top(options.active_q_chunk);
- }
- now = mudtime;
- for (d = descriptor_list; d; d = dnext) {
- dnext = d->next;
- if(d->descriptor == 0) {
- input_ready = FD_ISSET(STDIN_FILENO, &input_set);
- output_ready = FD_ISSET(STDOUT_FILENO, &output_set);
- } else {
- input_ready = FD_ISSET(d->descriptor, &input_set);
- output_ready = FD_ISSET(d->descriptor, &output_set);
- }
- if (input_ready) {
- if (!process_input(d, output_ready)) {
- shutdownsock(d);
- if(d->descriptor == 0)
- return;
- continue;
- }
- }
- if (output_ready) {
- if (!process_output(d)) {
- shutdownsock(d);
- if(d->descriptor == 0)
- return;
- }
- }
- }
- }
- }
-}
-
-static void
-clearstrings(DESC *d)
-{
- if (d->output_prefix) {
- mush_free((Malloc_t) d->output_prefix, "userstring");
- d->output_prefix = 0;
- }
- if (d->output_suffix) {
- mush_free((Malloc_t) d->output_suffix, "userstring");
- d->output_suffix = 0;
- }
-}
-
-/* Display a cached text file. If a prefix line was given,
- * display that line before the text file, but only if we've
- * got a text file to display
- */
-static void
-fcache_dump(DESC *d, FBLOCK fb[2], const unsigned char *prefix)
-{
- /* If we've got nothing nice to say, don't say anything */
- if (!fb[0].buff && !((d->conn_flags & CONN_HTML) && fb[1].buff))
- return;
- /* We've got something to say */
- if (prefix) {
- queue_newwrite(d, prefix, u_strlen(prefix));
- queue_eol(d);
- }
- if (d->conn_flags & CONN_HTML) {
- if (fb[1].buff)
- queue_newwrite(d, fb[1].buff, fb[1].len);
- else
- queue_write(d, fb[0].buff, fb[0].len);
- } else
- queue_write(d, fb[0].buff, fb[0].len);
-}
-
-
-static int
-fcache_read(FBLOCK *fb, const char *filename)
-{
- if (!fb || !filename)
- return -1;
-
- /* Free prior cache */
- if (fb->buff) {
- mush_free(fb->buff, "fcache_data");
- }
-
- fb->buff = NULL;
- fb->len = 0;
-
-#ifdef WIN32
- /* Win32 read code here */
- {
- HANDLE fh;
- BY_HANDLE_FILE_INFORMATION sb;
- DWORD r = 0;
-
-
- if ((fh = CreateFile(filename, GENERIC_READ, 0, NULL,
- OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
- return -1;
-
- if (!GetFileInformationByHandle(fh, &sb)) {
- CloseHandle(fh);
- return -1;
- }
-
- fb->len = sb.nFileSizeLow;
-
- if (!(fb->buff = mush_malloc(sb.nFileSizeLow, "fcache_data"))) {
- CloseHandle(fh);
- return -1;
- }
-
- if (!ReadFile(fh, fb->buff, sb.nFileSizeLow, &r, NULL) || fb->len != r) {
- CloseHandle(fh);
- mush_free(fb->buff, "fcache_data");
- fb->buff = NULL;
- return -1;
- }
-
- CloseHandle(fh);
-
- fb->len = sb.nFileSizeLow;
- return (int) fb->len;
- }
-#else
- /* Posix read code here */
- {
- int fd, n;
- struct stat sb;
-
- release_fd();
- if ((fd = open(filename, O_RDONLY, 0)) < 0) {
- do_log(LT_ERR, 0, 0, T("Couldn't open cached text file '%s'"), filename);
- reserve_fd();
- return -1;
- }
-
- if (fstat(fd, &sb) < 0) {
- do_log(LT_ERR, 0, 0, T("Couldn't get the size of text file '%s'"),
- filename);
- close(fd);
- reserve_fd();
- return -1;
- }
-
-
- if (!(fb->buff = mush_malloc(sb.st_size, "fcache_data"))) {
- do_log(LT_ERR, 0, 0, T("Couldn't allocate %d bytes of memory for '%s'!"),
- (int) sb.st_size, filename);
- close(fd);
- reserve_fd();
- return -1;
- }
-
- if ((n = read(fd, fb->buff, sb.st_size)) != sb.st_size) {
- do_log(LT_ERR, 0, 0, T("Couldn't read all of '%s'"), filename);
- close(fd);
- mush_free(fb->buff, "fcache_data");
- fb->buff = NULL;
- reserve_fd();
- return -1;
- }
-
- close(fd);
- reserve_fd();
- fb->len = sb.st_size;
- }
-#endif /* Posix read code */
-
- return fb->len;
-}
-
-/** Load all of the cached text files.
- * \param player the enactor.
- */
-void
-fcache_load(dbref player)
-{
- int conn, motd, new, reg, quit, down, full;
- int guest;
- int i;
-
- for (i = 0; i < (SUPPORT_PUEBLO ? 2 : 1); i++) {
- conn = fcache_read(&fcache.connect_fcache[i], options.connect_file[i]);
- motd = fcache_read(&fcache.motd_fcache[i], options.motd_file[i]);
- new = fcache_read(&fcache.newuser_fcache[i], options.newuser_file[i]);
- reg = fcache_read(&fcache.register_fcache[i], options.register_file[i]);
- quit = fcache_read(&fcache.quit_fcache[i], options.quit_file[i]);
- down = fcache_read(&fcache.down_fcache[i], options.down_file[i]);
- full = fcache_read(&fcache.full_fcache[i], options.full_file[i]);
- guest = fcache_read(&fcache.guest_fcache[i], options.guest_file[i]);
-
- if (player != NOTHING) {
- notify_format(player,
- T
- ("%s sizes: NewUser...%d Connect...%d Guest...%d Motd...%d Quit...%d Register...%d Down...%d Full...%d"),
- i ? "HTMLFile" : "File", new, conn, guest, motd, quit,
- reg, down, full);
- }
- }
-
-}
-
-/** Initialize all of the cached text files (at startup).
- */
-void
-fcache_init(void)
-{
- fcache_load(NOTHING);
-}
-
-static void
-logout_sock(DESC *d)
-{
- SU_PATH *path_entry;
-
- int n;
- char tbuf1[BUFFER_LEN];
-
- if (d->connected) {
- fcache_dump(d, fcache.quit_fcache, NULL);
- do_log(LT_CONN, 0, 0,
- T("[%d/%s/%s] Logout by %s(#%d) <Connection not dropped>"),
- d->descriptor, d->addr, d->ip, Name(d->player), d->player);
- if(d->last_time > 0) {
- d->idle_total += difftime(mudtime, d->last_time);
- d->unidle_times++;
- }
- snprintf(tbuf1, BUFFER_LEN-1, "%ld %ld %d %d", (mudtime - d->connected_at),
- d->idle_total, d->unidle_times, d->cmds);
- tbuf1[strlen(tbuf1)+1] = '\0';
- (void) atr_add(d->player, "LASTACTIVITY", tbuf1, GOD, NOTHING);
- announce_disconnect(d->player);
- do_mail_purge(d->player);
- if (MAX_LOGINS) {
- login_number--;
- if (!under_limit && (login_number < MAX_LOGINS)) {
- under_limit = 1;
- do_log(LT_CONN, 0, 0,
- T("Below maximum player limit of %d. Logins enabled."),
- MAX_LOGINS);
- }
- }
- } else {
- do_log(LT_CONN, 0, 0,
- T("[%d/%s/%s] Logout, never connected. <Connection not dropped>"),
- d->descriptor, d->addr, d->ip);
- }
- process_output(d); /* flush our old output */
- /* pretend we have a new connection */
- d->input_handler = do_command;
- d->connected = 0;
- d->output_prefix = 0;
- d->output_suffix = 0;
- d->output_size = 0;
- d->output.head = 0;
- d->player = 0;
- d->output.tail = &d->output.head;
- d->input.head = 0;
- d->input.tail = &d->input.head;
- d->raw_input = 0;
- d->raw_input_at = 0;
- d->quota = COMMAND_BURST_SIZE;
- d->last_time = mudtime;
- d->idle_total = 0;
- d->unidle_times = 0;
- d->cmds = 0;
- d->hide = 0;
- d->doing[0] = '\0';
- d->mailp = NULL;
- d->pinfo.object = NOTHING;
- d->pinfo.atr = NULL;
- d->pinfo.lock = 0;
- d->pinfo.function = NULL;
-
- while(d->su_exit_path) {
- path_entry = d->su_exit_path;
- d->su_exit_path = path_entry->next;
- mush_free(path_entry, "SU_EXIT_PATH");
- }
- welcome_user(d);
- for(n = 0; n < MAX_SNOOPS; n++)
- d->snooper[n] = -1;
-}
-
-/** Disconnect a descriptor.
- * This sends appropriate disconnection text, flushes output, and
- * then closes the associated socket.
- * \param d pointer to descriptor to disconnect.
- */
-static void
-shutdownsock(DESC *d)
-{
- char tbuf1[BUFFER_LEN];
- int i;
-
- if (d->connected) {
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Logout by %s(#%d)"),
- d->descriptor, d->addr, d->ip, Name(d->player), d->player);
- if (d->connected != 2) {
- fcache_dump(d, fcache.quit_fcache, NULL);
- /* Player was not allowed to log in from the connect screen */
- if(d->last_time > 0) {
- d->idle_total += difftime(mudtime, d->last_time);
- d->unidle_times++;
- }
- snprintf(tbuf1, BUFFER_LEN-1, "%ld %ld %d %d", (mudtime - d->connected_at),
- d->idle_total , d->unidle_times, d->cmds);
- tbuf1[strlen(tbuf1)+1] = '\0';
- (void) atr_add(d->player, "LASTACTIVITY", tbuf1, GOD, NOTHING);
- announce_disconnect(d->player);
- do_mail_purge(d->player);
- }
- if (MAX_LOGINS) {
- login_number--;
- if (!under_limit && (login_number < MAX_LOGINS)) {
- under_limit = 1;
- do_log(LT_CONN, 0, 0,
- T("Below maximum player limit of %d. Logins enabled."),
- MAX_LOGINS);
- }
- }
- } else {
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connection closed, never connected."),
- d->descriptor, d->addr, d->ip);
- }
- process_output(d);
- clearstrings(d);
- if(d->descriptor != 0) {
- shutdown(d->descriptor, 2);
- closesocket(d->descriptor);
- } else {
- freeqs(d);
- d->input_handler = do_command;
- d->connected = 0;
- d->connected_at = mudtime;
- d->output_prefix = 0;
- d->output_suffix = 0;
- d->output_size = 0;
- d->output.head = 0;
- d->player = 0;
- d->output.tail = &d->output.head;
- d->input.head = 0;
- d->input.tail = &d->input.head;
- d->raw_input = 0;
- d->raw_input_at = 0;
- d->quota = COMMAND_BURST_SIZE;
- d->last_time = mudtime;
- d->idle_total = 0;
- d->unidle_times = 0;
- d->cmds = 0;
- d->hide = 0;
- d->doing[0] = '\0';
- d->mailp = NULL;
- strncpy(d->addr, "localhost", 100);
- d->addr[99] = '\0';
- strncpy(d->ip, "127.0.0.1", 100);
- d->ip[99] = '\0';
- d->conn_flags = CONN_DEFAULT;
- d->input_chars = 0;
- d->output_chars = 0;
- d->ttype = mush_strdup("unknown", "terminal description");
- d->checksum[0] = '\0';
- d->su_exit_path = NULL;
- d->pinfo.object = NOTHING;
- d->pinfo.atr = NULL;
- d->pinfo.lock = 0;
- d->pinfo.function = NULL;
- d->width = 78;
- d->height = 24;
- welcome_user(d);
- for(i = 0; i < MAX_SNOOPS; i++)
- d->snooper[i] = -1;
- }
-
- if(d->descriptor != 0) {
- if (d->prev)
- d->prev->next = d->next;
- else /* d was the first one! */
- descriptor_list = d->next;
- if (d->next)
- d->next->prev = d->prev;
- }
-
- if(d->descriptor != 0) {
- freeqs(d);
- mush_free(d->ttype, "terminal description");
- mush_free((Malloc_t) d, "descriptor");
- }
-
- ndescriptors--;
-}
-
-/* ARGSUSED */
-static DESC *
-initializesock(int s, char *addr, char *ip, int use_ssl
- __attribute__ ((__unused__)))
-{
- DESC *d;
- int n;
-
- d = (DESC *) mush_malloc(sizeof(DESC), "descriptor");
- if (!d)
- mush_panic("Out of memory.");
- d->descriptor = s;
- d->input_handler = do_command;
- d->connected = 0;
- d->connected_at = mudtime;
- make_nonblocking(s);
- d->output_prefix = 0;
- d->output_suffix = 0;
- d->output_size = 0;
- d->output.head = 0;
- d->player = 0;
- d->output.tail = &d->output.head;
- d->input.head = 0;
- d->input.tail = &d->input.head;
- d->raw_input = 0;
- d->raw_input_at = 0;
- d->quota = COMMAND_BURST_SIZE;
- d->last_time = mudtime;
- d->idle_total = 0;
- d->unidle_times = 0;
- d->cmds = 0;
- d->hide = 0;
- d->doing[0] = '\0';
- d->mailp = NULL;
- strncpy(d->addr, addr, 100);
- d->addr[99] = '\0';
- strncpy(d->ip, ip, 100);
- d->ip[99] = '\0';
- d->conn_flags = CONN_DEFAULT;
- d->input_chars = 0;
- d->output_chars = 0;
- d->ttype = mush_strdup("unknown", "terminal description");
- d->checksum[0] = '\0';
- d->su_exit_path = NULL;
- d->pinfo.object = NOTHING;
- d->pinfo.atr = NULL;
- d->pinfo.lock = 0;
- d->pinfo.function = NULL;
-
- if (descriptor_list)
- descriptor_list->prev = d;
- d->next = descriptor_list;
- d->prev = NULL;
- descriptor_list = d;
-
- d->width = 78;
- d->height = 24;
- test_telnet(d);
- welcome_user(d);
- for(n = 0; n < MAX_SNOOPS; n++)
- d->snooper[n] = -1;
- return d;
-}
-
-/** Flush pending output for a descriptor.
- * This function actually sends the queued output over the descriptor's
- * socket.
- * \param d pointer to descriptor to send output to.
- * \retval 1 successfully flushed at least some output.
- * \retval 0 something failed, and the descriptor should probably be closed.
- */
-int
-process_output(DESC *d)
-{
- struct text_block **qp, *cur;
- int cnt;
-
- for (qp = &d->output.head; ((cur = *qp) != NULL);) {
- if(d->descriptor == 0)
- cnt = write(STDOUT_FILENO, cur->start, cur->nchars);
- else
- cnt = send(d->descriptor, cur->start, cur->nchars, 0);
- if (cnt < 0) {
-#ifdef WIN32
- if (cnt == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
-#else
-#ifdef EAGAIN
- if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
-#else
- if (errno == EWOULDBLOCK)
-#endif
-#endif
- return 1;
- return 0;
- }
- d->output_size -= cnt;
- d->output_chars += cnt;
- if (cnt == cur->nchars) {
- if (!cur->nxt)
- d->output.tail = qp;
- *qp = cur->nxt;
-#ifdef DEBUG
- do_rawlog(LT_ERR, "free_text_block(0x%x) at 2.", cur);
-#endif /* DEBUG */
- free_text_block(cur);
- continue; /* do not adv ptr */
- }
- cur->nchars -= cnt;
- cur->start += cnt;
- break;
- }
- return 1;
-}
-
-
-static void
-welcome_user(DESC *d)
-{
- if (SUPPORT_PUEBLO && !(d->conn_flags & CONN_HTML))
- queue_newwrite(d, (unsigned char *) PUEBLO_HELLO, strlen(PUEBLO_HELLO));
- fcache_dump(d, fcache.connect_fcache, NULL);
-}
-
-static void
-save_command(DESC *d, const unsigned char *command)
-{
- add_to_queue(&d->input, command, u_strlen(command) + 1);
-}
-
-static void
-test_telnet(DESC *d)
-{
- /* Use rfc 1184 to test telnet support, as it tries to set linemode
- with client-side editing. Good for Broken Telnet Programs. */
- if (d->descriptor != 0 && !TELNET_ABLE(d)) {
- /* IAC DO LINEMODE */
- unsigned char query[3] = "\xFF\xFD\x22";
- queue_newwrite(d, query, 3);
- d->conn_flags |= CONN_TELNET_QUERY;
- process_output(d);
- }
-}
-
-static void
-setup_telnet(DESC *d)
-{
- /* Win2k telnet doesn't do local echo by default,
- apparently. Unfortunately, there doesn't seem to be a telnet
- option for local echo, just remote echo. */
- d->conn_flags |= CONN_TELNET;
- if (d->conn_flags & CONN_TELNET_QUERY) {
- /* IAC DO NAWS IAC DO TERMINAL-TYPE */
- unsigned char extra_options[6] = "\xFF\xFD\x1F" "\xFF\xFD\x18";
- d->conn_flags &= ~CONN_TELNET_QUERY;
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Switching to Telnet mode."),
- d->descriptor, d->addr, d->ip);
- queue_newwrite(d, extra_options, 6);
- process_output(d);
- }
-}
-
-static int
-handle_telnet(DESC *d, unsigned char **q, unsigned char *qend)
-{
- int i;
-
- /* *(*q - q) == IAC at this point. */
- switch (**q) {
- case SB: /* Sub-option */
- if (*q >= qend)
- return -1;
- (*q)++;
- if (**q == TN_LINEMODE) {
- if ((*q + 2) >= qend)
- return -1;
- *q += 2;
- while (*q < qend && **q != SE)
- (*q)++;
- if (*q >= qend)
- return -1;
- } else if (**q == TN_NAWS) {
- /* Learn what size window the client is using. */
- union {
- short s;
- unsigned char bytes[2];
- } raw;
- if (*q >= qend)
- return -1;
- (*q)++;
- /* Width */
- if (**q == IAC) {
- raw.bytes[0] = IAC;
- if (*q >= qend)
- return -1;
- (*q)++;
- } else
- raw.bytes[0] = **q;
- if (*q >= qend)
- return -1;
- (*q)++;
- if (**q == IAC) {
- raw.bytes[1] = IAC;
- if (*q >= qend)
- return -1;
- (*q)++;
- } else
- raw.bytes[1] = **q;
- if (*q >= qend)
- return -1;
- (*q)++;
-
- d->width = ntohs(raw.s);
-
- /* Height */
- if (**q == IAC) {
- raw.bytes[0] = IAC;
- if (*q >= qend)
- return -1;
- (*q)++;
- } else
- raw.bytes[0] = **q;
- if (*q >= qend)
- return -1;
- (*q)++;
- if (**q == IAC) {
- raw.bytes[1] = IAC;
- if (*q >= qend)
- return -1;
- (*q)++;
- } else
- raw.bytes[1] = **q;
- if (*q >= qend)
- return -1;
- (*q)++;
- d->height = ntohs(raw.s);
-
- /* IAC SE */
- if (*q + 1 >= qend)
- return -1;
- (*q)++;
- } else if (**q == TN_TTYPE) {
- /* Read the terminal type: TERMINAL-TYPE IS blah IAC SE */
- char tbuf[BUFFER_LEN], *bp = tbuf;
- if (*q >= qend)
- return -1;
- (*q)++;
- /* Skip IS */
- if (*q >= qend)
- return -1;
- (*q)++;
-
- /* Read up to IAC SE */
- while (1) {
- if (*q >= qend)
- return -1;
- if (**q == IAC) {
- if (*q + 1 >= qend)
- return -1;
- if (*(*q + 1) == IAC) {
- safe_chr((char) IAC, tbuf, &bp);
- (*q)++;
- } else
- break;
- } else
- safe_chr(**q, tbuf, &bp);
- (*q)++;
- }
- while (*q < qend && **q != SE)
- (*q)++;
- *bp = '\0';
- mush_free(d->ttype, "terminal description");
- d->ttype = mush_strdup(tbuf, "terminal description");
- /* We have the terminal type, now set any defaults if we find 'em */
- for(i = 0 ; client_maps[i].terminal != NULL; i++)
- if(!strcmp(client_maps[i].terminal, d->ttype)) {
- d->conn_flags |= client_maps[i].flags;
- break;
- }
- } else {
- while (*q < qend && **q != SE)
- (*q)++;
- }
- break;
- case NOP: /* No-op */
- if (*q >= qend)
- return -1;
-#ifdef DEBUG_TELNET
- fprintf(stderr, "Got IAC NOP\n");
-#endif
- break;
- case AYT: /* Are you there? */
- if (*q >= qend)
- return -1;
- else {
- static unsigned char ayt_reply[] =
- "\r\n*** AYT received, I'm here ***\r\n";
- queue_newwrite(d, (unsigned char *) ayt_reply, u_strlen(ayt_reply));
- process_output(d);
- }
- break;
- case WILL: /* Client is willing to do something, or confirming */
- setup_telnet(d);
- if (*q >= qend)
- return -1;
- (*q)++;
-
- if (**q == TN_LINEMODE) {
- /* Set up our preferred linemode options. */
- /* IAC SB LINEMODE MODE (EDIT|SOFT_TAB) IAC SE */
- unsigned char reply[7] = "\xFF\xFA\x22\x01\x09\xFF\xF0";
- queue_newwrite(d, reply, 7);
-#ifdef DEBUG_TELNET
- fprintf(stderr, "Setting linemode options.\n");
-#endif
- } else if (**q == TN_TTYPE) {
- /* Ask for terminal type id: IAC SB TERMINAL-TYPE SEND IAC SEC */
- unsigned char reply[6] = "\xFF\xFA\x18\x01\xFF\xF0";
- queue_newwrite(d, reply, 6);
- } else if (**q == TN_SGA || **q == TN_NAWS) {
- /* This is good to be at. */
- } else { /* Refuse options we don't handle */
- unsigned char reply[3];
- reply[0] = IAC;
- reply[1] = DONT;
- reply[2] = **q;
- queue_newwrite(d, reply, sizeof reply);
- process_output(d);
- }
- break;
- case DO: /* Client is asking us to do something */
- setup_telnet(d);
- if (*q >= qend)
- return -1;
- (*q)++;
- if (**q == TN_LINEMODE) {
- } else if (**q == TN_SGA) {
- /* IAC WILL SGA IAC DO SGA */
- unsigned char reply[6] = "\xFF\xFB\x03\xFF\xFD\x03";
- queue_newwrite(d, reply, 6);
- process_output(d);
-#ifdef DEBUG_TELNET
- fprintf(stderr, "GOT IAC DO SGA, sending IAC WILL SGA IAG DO SGA\n");
-#endif
- } else {
- /* Stuff we won't do */
- unsigned char reply[3];
- reply[0] = IAC;
- reply[1] = WONT;
- reply[2] = (char) **q;
- queue_newwrite(d, reply, sizeof reply);
- process_output(d);
- }
- break;
- case WONT: /* Client won't do something we want. */
- case DONT: /* Client doesn't want us to do something */
- setup_telnet(d);
-#ifdef DEBUG_TELNET
- fprintf(stderr, "Got IAC %s 0x%x\n", **q == WONT ? "WONT" : "DONT",
- *(*q + 1));
-#endif
- if (*q + 1 >= qend)
- return -1;
- (*q)++;
- break;
- default: /* Also catches IAC IAC for a literal 255 */
- return 0;
- }
- return 1;
-}
-
-static void
-process_input_helper(DESC *d, char *tbuf1, int got)
-{
- unsigned char *p, *pend, *q, *qend;
-
- if (!d->raw_input) {
- d->raw_input =
- (unsigned char *) mush_malloc(sizeof(char) * MAX_COMMAND_LEN,
- "descriptor_raw_input");
- if (!d->raw_input)
- mush_panic("Out of memory");
- d->raw_input_at = d->raw_input;
- }
- p = d->raw_input_at;
- d->input_chars += got;
- pend = d->raw_input + MAX_COMMAND_LEN - 1;
- for (q = (unsigned char *) tbuf1, qend = (unsigned char *) tbuf1 + got;
- q < qend; q++) {
- if (*q == '\r') {
- /* A broken client (read: WinXP telnet) might send only CR, and not CRLF
- * so it's nice of us to try to handle this.
- */
- *p = '\0';
- if (p > d->raw_input)
- save_command(d, d->raw_input);
- p = d->raw_input;
- if (((q + 1) < qend) && (*(q + 1) == '\n'))
- q++; /* For clients that work */
- } else if (*q == '\n') {
- *p = '\0';
- if (p > d->raw_input)
- save_command(d, d->raw_input);
- p = d->raw_input;
- } else if (*q == '\b') {
- if (p > d->raw_input)
- p--;
- } else if ((unsigned char) *q == IAC) { /* Telnet option foo */
- if (q >= qend)
- break;
- q++;
- if (!TELNET_ABLE(d) || handle_telnet(d, &q, qend) == 0) {
- if (p < pend && isprint(*q))
- *p++ = *q;
- }
- } else if (p < pend && isprint(*q)) {
- *p++ = *q;
- }
- }
- if (p > d->raw_input) {
- d->raw_input_at = p;
- } else {
- mush_free((Malloc_t) d->raw_input, "descriptor_raw_input");
- d->raw_input = 0;
- d->raw_input_at = 0;
- }
-}
-
-/* ARGSUSED */
-static int
-process_input(DESC *d, int output_ready __attribute__ ((__unused__)))
-{
- int got = 0;
- char tbuf1[BUFFER_LEN];
-
- errno = 0;
-
- if(d->descriptor == 0)
- got = read(STDIN_FILENO, tbuf1, sizeof tbuf1);
- else
- got = recv(d->descriptor, tbuf1, sizeof tbuf1, 0);
-
- if (got <= 0) {
- /* At this point, select() says there's data waiting to be read from
- * the socket, but we shouldn't assume that read() will actually get it
- * and blindly act like a got of -1 is a disconnect-worthy error.
- */
-#ifdef EAGAIN
- if ((errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINTR))
-#else
- if ((errno == EWOULDBLOCK) || (errno == EINTR))
-#endif
- return 1;
- else
- return 0;
- }
-
- process_input_helper(d, tbuf1, got);
-
- return 1;
-}
-
-static void
-set_userstring(unsigned char **userstring, const char *command)
-{
- if (*userstring) {
- mush_free((Malloc_t) *userstring, "userstring");
- *userstring = NULL;
- }
- while (*command && isspace((unsigned char) *command))
- command++;
- if (*command)
- *userstring = (unsigned char *) mush_strdup(command, "userstring");
-}
-
-static void
-process_commands(void)
-{
- int nprocessed;
- DESC *cdesc, *dnext;
- struct text_block *t;
- int retval = 1;
-
- do {
- nprocessed = 0;
- for (cdesc = descriptor_list; cdesc;
- cdesc = (nprocessed > 0 && retval > 0) ? cdesc->next : dnext) {
- dnext = cdesc->next;
- if (cdesc->quota > 0 && (t = cdesc->input.head)) {
- cdesc->quota--;
- nprocessed++;
- start_cpu_timer();
- feed_snoop(cdesc,(const char *) t->start, 0);
- /* check AUNIDLE */
- if(options.idle_time && ((mudtime - cdesc->last_time) > options.idle_time)) {
- if(atr_get(cdesc->player, "AUNIDLE"))
- queue_attribute_noparent(cdesc->player, "AUNIDLE", cdesc->player);
- if(GoodObject(Division(cdesc->player)) && atr_get(Division(cdesc->player), "AUNIDLE"))
- queue_attribute(Division(cdesc->player), "AUNIDLE", cdesc->player);
- }
- retval = cdesc->input_handler(cdesc, (char *) t->start);
- reset_cpu_timer();
- if(retval == -1 && do_su_exit(cdesc))
- retval = 1;
-
- if (retval == 0) {
- shutdownsock(cdesc);
- } else if (retval == -1) {
- logout_sock(cdesc);
- } else {
- cdesc->input.head = t->nxt;
- if (!cdesc->input.head)
- cdesc->input.tail = &cdesc->input.head;
- if (t) {
-#ifdef DEBUG
- do_rawlog(LT_ERR, "free_text_block(0x%x) at 5.", t);
-#endif /* DEBUG */
- free_text_block(t);
- }
- }
- }
- }
- } while (nprocessed > 0);
-}
-
-/** Send a descriptor's output prefix */
-#define send_prefix(d) \
- if (d->output_prefix) { \
- queue_newwrite(d, d->output_prefix, u_strlen(d->output_prefix)); \
- queue_eol(d); \
- }
-
-/** Send a descriptor's output suffix */
-#define send_suffix(d) \
- if (d->output_suffix) { \
- queue_newwrite(d, d->output_suffix, u_strlen(d->output_suffix)); \
- queue_eol(d); \
- }
-
-int
-do_command(DESC *d, char *command)
-{
- int j;
-
- depth = 0;
-
- (d->cmds)++;
-
- if (!strcmp(command, IDLE_COMMAND))
- return 1;
- if(difftime(mudtime, d->last_time) >= 300) {
- d->idle_total += difftime(mudtime, d->last_time);
- d->unidle_times++;
- }
- d->last_time = mudtime;
- if (!strcmp(command, QUIT_COMMAND)) {
- return 0;
- } else if (!strcmp(command, LOGOUT_COMMAND)) {
- return -1;
- } else if (!strcmp(command, INFO_COMMAND)) {
- send_prefix(d);
- dump_info(d);
- send_suffix(d);
- } else if (!strncmp(command, WHO_COMMAND, strlen(WHO_COMMAND))) {
- send_prefix(d);
- dump_users(d, command + strlen(WHO_COMMAND), 0);
- send_suffix(d);
- } else if (!strncmp(command, DOING_COMMAND, strlen(DOING_COMMAND))) {
- send_prefix(d);
- dump_users(d, command + strlen(DOING_COMMAND), 1);
- send_suffix(d);
- } else if (!strncmp(command, SESSION_COMMAND, strlen(SESSION_COMMAND))) {
- send_prefix(d);
- dump_users(d, command + strlen(SESSION_COMMAND), 2);
- send_suffix(d);
- } else if (!strncmp(command, PREFIX_COMMAND, strlen(PREFIX_COMMAND))) {
- set_userstring(&d->output_prefix, command + strlen(PREFIX_COMMAND));
- } else if (!strncmp(command, SUFFIX_COMMAND, strlen(SUFFIX_COMMAND))) {
- set_userstring(&d->output_suffix, command + strlen(SUFFIX_COMMAND));
- } else if (!strncmp(command, "SCREENWIDTH", 11)) {
- d->width = parse_integer(command + 11);
- } else if (!strncmp(command, "SCREENHEIGHT", 12)) {
- d->height = parse_integer(command + 12);
- } else if (SUPPORT_PUEBLO
- && !strncmp(command, PUEBLO_COMMAND, strlen(PUEBLO_COMMAND))) {
- parse_puebloclient(d, command);
- if (!(d->conn_flags & CONN_HTML)) {
- queue_newwrite(d, (unsigned char *) PUEBLO_SEND, strlen(PUEBLO_SEND));
- process_output(d);
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Switching to Pueblo mode."),
- d->descriptor, d->addr, d->ip);
- d->conn_flags |= CONN_HTML;
- if (!d->connected)
- welcome_user(d);
- }
- } else {
- if (d->connected) {
- send_prefix(d);
- global_eval_context.cplr = d->player;
- strcpy(global_eval_context.ccom, command);
- strcpy(global_eval_context.ucom, "");
-
- /* Clear %0-%9 and r(0) - r(9) */
- for (j = 0; j < 10; j++)
- global_eval_context.wenv[j] = (char *) NULL;
- for (j = 0; j < NUMQ; j++)
- global_eval_context.renv[j][0] = '\0';
- global_eval_context.process_command_port = d->descriptor;
-
- process_command(d->player, command, d->player, d->player, 1);
- send_suffix(d);
- strcpy(global_eval_context.ccom, "");
- strcpy(global_eval_context.ucom, "");
- global_eval_context.cplr = NOTHING;
- } else {
- if (!check_connect(d, command))
- return 0;
- }
- }
- return 1;
-}
-
-static void
-parse_puebloclient(DESC *d, char *command)
-{
- const char *p, *end;
- if ((p = string_match(command, "md5="))) {
- /* Skip md5=" */
- p += 5;
- if ((end = strchr(p, '"'))) {
- if ((end > p) && ((end - p) <= PUEBLO_CHECKSUM_LEN)) {
- /* Got it! */
- strncpy(d->checksum, p, end - p);
- d->checksum[end - p] = '\0';
- }
- }
- }
-}
-
-static int
-dump_messages(DESC *d, dbref player, int isnew)
-{
- int is_hidden;
- int num = 0;
- DESC *tmpd;
-
- d->connected = 1;
- d->connected_at = mudtime;
- d->player = player;
- d->doing[0] = '\0';
-
- if (MAX_LOGINS) {
- /* check for exceeding max player limit */
- login_number++;
- if (under_limit && (login_number > MAX_LOGINS)) {
- under_limit = 0;
- do_rawlog(LT_CONN,
- T("Limit of %d players reached. Logins disabled.\n"),
- MAX_LOGINS);
- }
- }
- /* give players a message on connection */
- if (!options.login_allow || !under_limit ||
- (Guest(player) && !options.guest_allow)) {
- if (!options.login_allow) {
- fcache_dump(d, fcache.down_fcache, NULL);
- if (cf_downmotd_msg && *cf_downmotd_msg)
- raw_notify(player, cf_downmotd_msg);
- } else if (MAX_LOGINS && !under_limit) {
- fcache_dump(d, fcache.full_fcache, NULL);
- if (cf_fullmotd_msg && *cf_fullmotd_msg)
- raw_notify(player, cf_fullmotd_msg);
- }
- if (!Can_Login(player)) {
- /* when the connection has been refused, we want to update the
- * LASTFAILED info on the player
- */
- check_lastfailed(player, d->addr);
- return 0;
- }
- }
- d->mailp = find_exact_starting_point(player);
-
- /* check to see if this is a reconnect and also set DARK status */
- is_hidden = Can_Hide(player) && Dark(player);
- DESC_ITER_CONN(tmpd) {
- if (tmpd->player == player) {
- num++;
- if (is_hidden)
- tmpd->hide = 1;
- }
- }
- /* give permanent text messages */
- if (isnew)
- fcache_dump(d, fcache.newuser_fcache, NULL);
- if (num == 1)
- fcache_dump(d, fcache.motd_fcache, NULL);
- if (Guest(player))
- fcache_dump(d, fcache.guest_fcache, NULL);
-
- if (ModTime(player))
- notify_format(player, T("%ld failed connections since last login."),
- ModTime(player));
- ModTime(player) = (time_t) 0;
- announce_connect(player, isnew, num); /* broadcast connect message */
- check_last(player, d->addr, d->ip); /* set Last, Lastsite, give paycheck */
- /* Check folder 0, not silently (i.e. Report lack of mail, too) */
- queue_eol(d);
- if (command_check_byname(player, "@MAIL"))
- check_mail(player, 0, 0);
- set_player_folder(player, 0);
- do_look_around(player);
- if (Haven(player))
- notify(player, T("Your HAVEN flag is set. You cannot receive pages."));
- local_connect(player, isnew, num);
- return 1;
-}
-
-static int
-check_connect(DESC *d, const char *msg)
-{
- char command[MAX_COMMAND_LEN];
- char user[MAX_COMMAND_LEN];
- char password[MAX_COMMAND_LEN];
- char errbuf[BUFFER_LEN];
- dbref player;
-
- parse_connect(msg, command, user, password);
-
- if (string_prefix("connect", command)) {
- if ((player =
- connect_player(user, password, d->addr, d->ip, errbuf)) == NOTHING) {
- queue_string_eol(d, errbuf);
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed connect to '%s'."),
- d->descriptor, d->addr, d->ip, user);
- } else {
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connected to %s(#%d) in %s(#%d)"),
- d->descriptor, d->addr, d->ip, Name(player), player,
- Name(Location(player)), Location(player));
- /* Check if we're fake siting this guy.. */
- if(has_flag_by_name(player, "WEIRDSITE", TYPE_PLAYER)) {
- ATTR *a;
- a = atr_get(player, "LASTSITE");
- strncpy(d->addr, !a ? "localhost" : atr_value(a), 100);
- }
-
- if ((dump_messages(d, player, 0)) == 0) {
- d->connected = 2;
- return 0;
- }
- }
-
- } else if (!strcasecmp(command, "cd")) {
- if ((player =
- connect_player(user, password, d->addr, d->ip, errbuf)) == NOTHING) {
- queue_string_eol(d, errbuf);
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed connect to '%s'."),
- d->descriptor, d->addr, d->ip, user);
- } else {
- do_log(LT_CONN, 0, 0,
- T("[%d/%s/%s] Connected dark to %s(#%d) in %s(#%d)"),
- d->descriptor, d->addr, d->ip, Name(player), player,
- Name(Location(player)), Location(player));
- /* Set player dark */
- d->connected = 1;
- d->player = player;
- set_flag(player, player, "DARK", 0, 0, 0);
- if ((dump_messages(d, player, 0)) == 0) {
- d->connected = 2;
- return 0;
- }
- }
-
- } else if (!strcasecmp(command, "cv")) {
- if ((player =
- connect_player(user, password, d->addr, d->ip, errbuf)) == NOTHING) {
- queue_string_eol(d, errbuf);
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed connect to '%s'."),
- d->descriptor, d->addr, d->ip, user);
- } else {
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connected to %s(#%d) in %s(#%d)"),
- d->descriptor, d->addr, d->ip, Name(player), player,
- Name(Location(player)), Location(player));
- /* Set player !dark */
- d->connected = 1;
- d->player = player;
- set_flag(player, player, "DARK", 1, 0, 0);
- if ((dump_messages(d, player, 0)) == 0) {
- d->connected = 2;
- return 0;
- }
- }
-
- } else if (!strcasecmp(command, "ch")) {
- if ((player =
- connect_player(user, password, d->addr, d->ip, errbuf)) == NOTHING) {
- queue_string_eol(d, errbuf);
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed connect to '%s'."),
- d->descriptor, d->addr, d->ip, user);
- } else {
- do_log(LT_CONN, 0, 0,
- T("[%d/%s/%s] Connected hidden to %s(#%d) in %s(#%d)"),
- d->descriptor, d->addr, d->ip, Name(player), player,
- Name(Location(player)), Location(player));
- /* Set player hidden */
- d->connected = 1;
- d->player = player;
- if (Can_Hide(player))
- d->hide = 1;
- if ((dump_messages(d, player, 0)) == 0) {
- d->connected = 2;
- return 0;
- }
- }
-
- } else if (string_prefix("create", command)) {
- if (!Site_Can_Create(d->addr) || !Site_Can_Create(d->ip)) {
- fcache_dump(d, fcache.register_fcache, NULL);
- if (!Deny_Silent_Site(d->addr, AMBIGUOUS)
- && !Deny_Silent_Site(d->ip, AMBIGUOUS)) {
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Refused create for '%s'."),
- d->descriptor, d->addr, d->ip, user);
- }
- return 0;
- }
- if (!options.login_allow || !options.create_allow) {
- if (!options.login_allow)
- fcache_dump(d, fcache.down_fcache, NULL);
- else
- fcache_dump(d, fcache.register_fcache, NULL);
- do_rawlog(LT_CONN,
- "REFUSED CREATION for %s from %s on descriptor %d.\n",
- user, d->addr, d->descriptor);
- return 0;
- } else if (MAX_LOGINS && !under_limit) {
- fcache_dump(d, fcache.full_fcache, NULL);
- do_rawlog(LT_CONN,
- "REFUSED CREATION for %s from %s on descriptor %d.\n",
- user, d->addr, d->descriptor);
- return 0;
- }
- player = create_player(user, password, d->addr, d->ip);
- if (player == NOTHING) {
- queue_string_eol(d, T(create_fail));
- do_log(LT_CONN, 0, 0,
- T("[%d/%s/%s] Failed create for '%s' (bad name)."),
- d->descriptor, d->addr, d->ip, user);
- } else if (player == AMBIGUOUS) {
- queue_string_eol(d, T(password_fail));
- do_log(LT_CONN, 0, 0,
- T("[%d/%s/%s] Failed create for '%s' (bad password)."),
- d->descriptor, d->addr, d->ip, user);
- } else {
- do_log(LT_CONN, 0, 0, "[%d/%s/%s] Created %s(#%d)",
- d->descriptor, d->addr, d->ip, Name(player), player);
- if ((dump_messages(d, player, 1)) == 0) {
- d->connected = 2;
- return 0;
- }
- } /* successful player creation */
-
- } else if (string_prefix("register", command)) {
- if (!Site_Can_Register(d->addr) || !Site_Can_Register(d->ip)) {
- fcache_dump(d, fcache.register_fcache, NULL);
- if (!Deny_Silent_Site(d->addr, AMBIGUOUS)
- && !Deny_Silent_Site(d->ip, AMBIGUOUS)) {
- do_log(LT_CONN, 0, 0,
- T("[%d/%s/%s] Refused registration (bad site) for '%s'."),
- d->descriptor, d->addr, d->ip, user);
- }
- return 0;
- }
- if (!options.create_allow) {
- fcache_dump(d, fcache.register_fcache, NULL);
- do_rawlog(LT_CONN,
- "Refused registration (creation disabled) for %s from %s on descriptor %d.\n",
- user, d->addr, d->descriptor);
- return 0;
- }
- if ((player = email_register_player(user, password, d->addr, d->ip)) ==
- NOTHING) {
- queue_string_eol(d, T(register_fail));
- do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed registration for '%s'."),
- d->descriptor, d->addr, d->ip, user);
- } else {
- queue_string_eol(d, T(register_success));
- do_log(LT_CONN, 0, 0, "[%d/%s/%s] Registered %s(#%d) to %s",
- d->descriptor, d->addr, d->ip, Name(player), player, password);
- }
- /* Whether it succeeds or fails, leave them connected */
-
- } else {
- /* invalid command, just repeat login screen */
- welcome_user(d);
- }
- /* If they were in a program, get them back in it */
- if(InProg(d->player)) {
- queue_string(d, "Loading @Program onto Descriptor....\r\n");
- prog_load_desc(d);
- }
-
- return 1;
-}
-
-static void
-parse_connect(const char *msg1, char *command, char *user, char *pass)
-{
- unsigned char *p;
- unsigned const char *msg = (unsigned const char *) msg1;
-
- while (*msg && isspace(*msg))
- msg++;
- p = (unsigned char *) command;
- while (*msg && isprint(*msg) && !isspace(*msg))
- *p++ = *msg++;
- *p = '\0';
- while (*msg && isspace(*msg))
- msg++;
- p = (unsigned char *) user;
-
- if (PLAYER_NAME_SPACES && *msg == '\"') {
- for (; *msg && ((*msg == '\"') || isspace(*msg)); msg++) ;
- while (*msg && (*msg != '\"')) {
- while (*msg && !isspace(*msg) && (*msg != '\"'))
- *p++ = *msg++;
- if (*msg == '\"') {
- msg++;
- while (*msg && isspace(*msg))
- msg++;
- break;
- }
- while (*msg && isspace(*msg))
- msg++;
- if (*msg && (*msg != '\"'))
- *p++ = ' ';
- }
- } else
- while (*msg && isprint(*msg) && !isspace(*msg))
- *p++ = *msg++;
-
- *p = '\0';
- while (*msg && isspace(*msg))
- msg++;
- p = (unsigned char *) pass;
- while (*msg && isprint(*msg) && !isspace(*msg))
- *p++ = *msg++;
- *p = '\0';
-}
-
-static void
-close_sockets(void)
-{
- DESC *d, *dnext;
-
- for (d = descriptor_list; d; d = dnext) {
- dnext = d->next;
- if(d->descriptor == 0) {
- write(STDOUT_FILENO, T(shutdown_message), strlen(T(shutdown_message)));
- write(STDOUT_FILENO, "\r\n", 2);
- } else {
- send(d->descriptor, T(shutdown_message), strlen(T(shutdown_message)), 0);
- send(d->descriptor, "\r\n", 2, 0);
- if (shutdown(d->descriptor, 2) < 0)
- perror("shutdown");
- closesocket(d->descriptor);
- }
- }
-}
-
-/** Give everyone the boot.
- */
-void
-emergency_shutdown(void)
-{
- close_sockets();
-}
-
-/** Disconnect a descriptor.
- * \param d pointer to descriptor to disconnect.
- */
-void
-boot_desc(DESC *d)
-{
- shutdownsock(d);
-}
-
-/** Given a player dbref, return the player's first connected descriptor.
- * \param player dbref of player.
- * \return pointer to player's first connected descriptor, or NULL.
- */
-DESC *
-player_desc(dbref player)
-{
- DESC *d;
- for (d = descriptor_list; d; d = d->next) {
- if (d->connected && (d->player == player)) {
- return d;
- }
- }
- return (DESC *) NULL;
-}
-
-/** Page a specified socket.
- * \param player the enactor.
- * \param pc string containing port number to send message to.
- * \param message message to send.
- */
-void
-do_page_port(dbref player, const char *pc, const char *message)
-{
- int p, key;
- DESC *d;
- const char *gap;
- char tbuf[BUFFER_LEN], *tbp = tbuf;
- dbref target = NOTHING;
-
- if (!Admin(player)) {
- notify(player, T("Permission denied."));
- return;
- }
- p = atoi(pc);
- if (p <= 0) {
- notify(player, T("That's not a port number."));
- return;
- }
-
- if (!message || !*message) {
- notify(player, T("What do you want to page with?"));
- return;
- }
-
- gap = " ";
- switch (*message) {
- case SEMI_POSE_TOKEN:
- gap = "";
- case POSE_TOKEN:
- key = 1;
- break;
- default:
- key = 3;
- break;
- }
-
- d = port_desc(p);
- if (!d) {
- notify(player, T("That port's not active."));
- return;
- }
- if (d->connected)
- target = d->player;
- switch (key) {
- case 1:
- safe_format(tbuf, &tbp, T("From afar, %s%s%s"), Name(player), gap,
- message + 1);
- notify_format(player, T("Long distance to %s: %s%s%s"),
- target != NOTHING ? Name(target) :
- T("a connecting player"), Name(player), gap, message + 1);
- break;
- case 3:
- safe_format(tbuf, &tbp, T("%s pages: %s"), Name(player), message);
- notify_format(player, T("You paged %s with '%s'."),
- target != NOTHING ? Name(target) :
- T("a connecting player"), message);
- break;
- }
- *tbp = '\0';
- if (target != NOTHING)
- page_return(player, target, "Idle", "IDLE", NULL);
- if (Typeof(player) != TYPE_PLAYER && Nospoof(target))
- queue_string_eol(d, tprintf("[#%d] %s", player, tbuf));
- else
- queue_string_eol(d, tbuf);
-}
-
-
-/** Return an inactive descriptor, as long as there's more than
- * one descriptor connected. Used for boot/me.
- * \param player player to find an inactive descriptor for.
- * \return pointer to player's inactive descriptor, or NULL.
- */
-DESC *
-inactive_desc(dbref player)
-{
- DESC *d, *in = NULL;
- time_t now;
- int numd = 0;
- now = mudtime;
- DESC_ITER_CONN(d) {
- if (d->player == player) {
- numd++;
- if (now - d->last_time > 60)
- in = d;
- }
- }
- if (numd > 1)
- return in;
- else
- return (DESC *) NULL;
-}
-
-/** Given a port (a socket number), return the descriptor.
- * \param port port (socket file descriptor number).
- * \return pointer to descriptor associated with the port.
- */
-DESC *
-port_desc(int port)
-{
- DESC *d;
- for (d = descriptor_list; (d); d = d->next) {
- if (d->descriptor == port) {
- return d;
- }
- }
- return (DESC *) NULL;
-}
-
-/** Given a port, find the matching player dbref.
- * \param port (socket file descriptor number).
- * \return dbref of connected player using that port, or NOTHING.
- */
-dbref
-find_player_by_desc(int port)
-{
- DESC *d;
- for (d = descriptor_list; (d); d = d->next) {
- if (d->connected && (d->descriptor == port)) {
- return d->player;
- }
- }
-
- /* didn't find anything */
- return NOTHING;
-}
-
-
-#ifndef WIN32
-/** Handler for SIGINT. Note that we've received it, and reinstall.
- * \param sig signal caught.
- */
-void
-signal_shutdown(int sig __attribute__ ((__unused__)))
-{
- signal_shutdown_flag = 1;
- reload_sig_handler(SIGINT, signal_shutdown);
-}
-
-/** Handler for SIGUSR2. Note that we've received it, and reinstall
- * \param sig signal caught.
- */
-void
-signal_dump(int sig __attribute__ ((__unused__)))
-{
- signal_dump_flag = 1;
- reload_sig_handler(SIGUSR2, signal_dump);
-}
-#endif
-
-/** A general handler to puke and die.
- * \param sig signal caught.
- */
-void
-bailout(int sig)
-{
- mush_panicf(T("BAILOUT: caught signal %d"), sig);
-}
-
-#ifndef WIN32
-/** Reap child processes, notably info_slaves and forking dumps,
- * when we receive a SIGCHLD signal. Don't fear this function. :)
- * \param sig signal caught.
- */
-void
-reaper(int sig __attribute__ ((__unused__)))
-{
- WAIT_TYPE my_stat;
- Pid_t pid;
-
-#ifdef HAS_WAITPID
- while ((pid = waitpid(-1, &my_stat, WNOHANG)) > 0)
-#else
- while ((pid = wait3(&my_stat, WNOHANG, 0)) > 0)
-#endif
- {
- if (forked_dump_pid > -1 && pid == forked_dump_pid) {
- /* Most failures are handled by the forked mush already */
- if (WIFSIGNALED(my_stat)) {
- do_rawlog(LT_ERR, T("ERROR! forking dump exited with signal %d"),
- WTERMSIG(my_stat));
- } else if (WIFEXITED(my_stat) && WEXITSTATUS(my_stat) == 0) {
- time(&globals.last_dump_time);
- if (DUMP_NOFORK_COMPLETE && *DUMP_NOFORK_COMPLETE)
- flag_broadcast(0, 0, "%s", DUMP_NOFORK_COMPLETE);
-
- }
- forked_dump_pid = -1;
- }
- }
- reload_sig_handler(SIGCHLD, reaper);
-}
-#endif /* !WIN32 */
-
-
-static void
-dump_info(DESC *call_by)
-{
- int count = 0;
- DESC *d;
- queue_string_eol(call_by, tprintf("### Begin INFO %s", INFO_VERSION));
-
- /* Count connected players */
- for (d = descriptor_list; d; d = d->next) {
- if (d->connected) {
- if (!GoodObject(d->player))
- continue;
- if (COUNT_ALL || !Hidden(d) || call_by->player == d->player )
- count++;
- }
- }
- queue_string_eol(call_by, tprintf("Name: %s", options.mud_name));
- queue_string_eol(call_by,
- tprintf("Uptime: %s", show_time(globals.first_start_time, 0)));
- queue_string_eol(call_by, tprintf("Connected: %d", count));
- queue_string_eol(call_by, tprintf("Size: %d", db_top));
- queue_string_eol(call_by, tprintf("Version: CobraMUSH v%s [%s]", VERSION,
- VBRANCH));
-#ifdef PATCHES
- queue_string_eol(call_by, tprintf("Patches: %s", PATCHES));
-#endif
- queue_string_eol(call_by, "### End INFO");
-}
-
-static void
-dump_users(DESC *call_by, char *match, int doing)
- /* doing: 0 if normal WHO, 1 if DOING, 2 if SESSION */
-{
- DESC *d;
-#ifdef COLOREDWHO
- int tcount = 0;
-#endif
- int count = 0;
- time_t now;
- char tbuf1[BUFFER_LEN];
- char tbuf2[BUFFER_LEN];
- int csite;
-
- if (!GoodObject(call_by->player)) {
- do_log(LT_ERR, 0, 0, T("Bogus caller #%d of dump_users"), call_by->player);
- return;
- }
- while (*match && *match == ' ')
- match++;
- now = mudtime;
-
- /* If an admin types "DOING" it gives him the normal player WHO,
- * BUT flags are not shown. Privileged WHO does not show @doings.
- */
-
- if (SUPPORT_PUEBLO && (call_by->conn_flags & CONN_HTML)) {
- queue_newwrite(call_by, (unsigned char *) "<img xch_mode=html>", 19);
- queue_newwrite(call_by, (unsigned char *) "<PRE>", 5);
- }
-
- if ((doing == 1) || !call_by->player || !Priv_Who(call_by->player)) {
- if (poll_msg[0] == '\0')
- strcpy(poll_msg, "Doing");
- if (ShowAnsi(call_by->player))
- sprintf(tbuf2, "%s%-16s %4s %10s %6s %s%s\n", ANSI_HILITE,
- T("Player Name"), T("Aff"), T("On For"), T("Idle"), poll_msg, ANSI_NORMAL);
- else
- sprintf(tbuf2, "%-16s %4s %10s %6s %s\n",
- T("Player Name"), T("Aff"), T("On For"), T("Idle"), poll_msg);
- queue_string(call_by, tbuf2);
- } else if (doing == 2) {
- sprintf(tbuf2, "%s%-16s %6s %9s %5s %5s Des Sent Recv Pend%s\n", ShowAnsi(call_by->player) ? ANSI_HILITE :
- "", T("Player Name"), T("Loc #"), T("On For"), T("Idle"), T("Cmds"),
- ShowAnsi(call_by->player) ? ANSI_NORMAL : "");
- queue_string(call_by, tbuf2);
- } else {
- sprintf(tbuf2, "%s%-16s %6s %9s %5s %5s Des Host%s\n", ShowAnsi(call_by->player) ? ANSI_HILITE : "",
- T("Player Name"), T("Loc #"), T("On For"), T("Idle"), T("Cmds"), ShowAnsi(call_by->player) ? ANSI_NORMAL : "");
- queue_string(call_by, tbuf2);
- }
-
- for (d = descriptor_list; d; d = d->next) {
- if (d->connected) {
- if (!GoodObject(d->player))
- continue;
- if (COUNT_ALL || (!Hidden(d) || call_by->player == d->player
- || (call_by->player && Priv_Who(call_by->player)))) {
- count++;
-#ifdef COLOREDWHO
- tcount++;
-#endif
- }
- if (match && !(string_prefix(Name(d->player), match)))
- continue;
- csite = CanSee(call_by->player, d->player);
-
- if (call_by->connected && doing == 0 && call_by->player
- && Priv_Who(call_by->player)) {
- if (Hidden(d) && !csite)
- continue;
-
- sprintf(tbuf1, "%-16s %6s %9s %5s %4d %3d%c %s", tprintf("%s%s", Name(d->player), InProg(d->player) ? "(P)" : ""),
- Can_Locate(call_by->player, d->player) ? unparse_dbref(Location(d->player)) : "#-1",
- time_format_1(now - d->connected_at),
- time_format_2(now - d->last_time), csite ? d->cmds : 0,
- csite ? d->descriptor : 0,
- ' ',
- csite ? d->addr : "---");
- tbuf1[78] = '\0';
- if (Dark(d->player)) {
- tbuf1[71] = '\0';
- strcat(tbuf1, " (Dark)");
- } else if (Hidden(d)) {
- tbuf1[71] = '\0';
- strcat(tbuf1, " (Hide)");
- }
- } else if (call_by->connected && doing == 2 && call_by->player
- && Priv_Who(call_by->player)) {
- sprintf(tbuf1, "%-16s %6s %9s %5s %5d %3d%c %5lu %7lu %5d",
- tprintf("%s%s", Name(d->player), InProg(d->player) ? "(P)" : ""),
- Can_Locate(call_by->player, d->player) ? unparse_dbref(Location(d->player)) : "#-1",
- time_format_1(now - d->connected_at),
- time_format_2(now - d->last_time), csite ? d->cmds : 0,
- csite ? d->descriptor : 0,
- ' ',
-
- csite ? d->input_chars : 0, csite ? d->output_chars : 0,
- csite ? d->output_size : 0);
- } else {
- if (!Hidden(d)
- || call_by->player == d->player ||
- (call_by->player && Priv_Who(call_by->player) && (doing))) {
- sprintf(tbuf1, "%-16s %4s %10s %4s%c %s", tprintf("%s%s", Name(d->player), InProg(d->player) ? "(P)" : ""), empabb(d->player),
- time_format_1(now - d->connected_at),
- time_format_2(now - d->last_time),
- (Dark(d->player) ? 'D' : (Hidden(d) ? 'H' : ' '))
- , d->doing);
- }
- }
-
- if (!Hidden(d) || (call_by->player && Priv_Who(call_by->player))) {
-#ifdef COLOREDWHO
- if(ShowAnsiColor(call_by->player))
- queue_string(call_by, tprintf("%s%s%s%s%s", ANSI_NORMAL, (tcount % 2 ? "" : ANSI_HILITE),
- (tcount % 2 ? ANSI_CYAN : ANSI_WHITE),
- tbuf1, ANSI_NORMAL));
-
- else
-#endif
- queue_string(call_by, tbuf1);
- queue_newwrite(call_by, (unsigned char *) "\r\n", 2);
- }
- } else if (call_by->player && Priv_Who(call_by->player) && doing != 1
- && (!match || !*match)) {
-#ifdef COLOREDWHO
- tcount++;
-#endif
- if (doing == 0) {
- /* Privileged WHO for non-logged in connections */
- sprintf(tbuf1, "%-16s %6s %9s %5s %4d %3d%c %s", T("Connecting..."),
- "#-1",
- time_format_1(now - d->connected_at),
- time_format_2(now - d->last_time), d->cmds, d->descriptor,
- ' ',
-
- d->addr);
- tbuf1[78] = '\0';
- } else {
- /* SESSION for non-logged in connections */
- sprintf(tbuf1, "%-16s %5s %9s %5s %5d %3d%c %5lu %7lu %5d",
- T("Connecting..."), "#-1",
- time_format_1(now - d->connected_at),
- time_format_2(now - d->last_time), d->cmds, d->descriptor,
- ' ',
- d->input_chars, d->output_chars, d->output_size);
- }
-#ifdef COLOREDWHO
- if(ShowAnsiColor(call_by->player))
- queue_string(call_by, tprintf("%s%s%s%s%s", ANSI_NORMAL,tcount % 2 ? "" : ANSI_HILITE,
- tcount % 2 ? ANSI_CYAN : ANSI_WHITE, tbuf1, ANSI_NORMAL));
- else
-#endif
- queue_string(call_by, tbuf1);
- queue_newwrite(call_by, (unsigned char *) "\r\n", 2);
- }
- }
- switch (count) {
- case 0:
- strcpy(tbuf1, T("There are no players connected."));
- break;
- case 1:
- strcpy(tbuf1, T("There is 1 player connected."));
- break;
- default:
- sprintf(tbuf1, T("There are %d players connected."), count);
- break;
- }
-
-#ifdef COLOREDWHO
- if(ShowAnsiColor(call_by->player))
- queue_string(call_by, tprintf("%s%s%s%s%s", ANSI_NORMAL, (tcount+1) % 2 ? "" : ANSI_HILITE ,
- (tcount+1) % 2 ? ANSI_CYAN : ANSI_WHITE, tbuf1, ANSI_NORMAL));
- else
-#endif
- queue_string(call_by, tbuf1);
- if (SUPPORT_PUEBLO && (call_by->conn_flags & CONN_HTML)) {
- queue_newwrite(call_by, (unsigned char *) "\n</PRE>\n", 8);
- queue_newwrite(call_by, (unsigned char *) "<img xch_mode=purehtml>", 23);
- } else
- queue_newwrite(call_by, (unsigned char *) "\r\n", 2);
-}
-
-static const char *
-time_format_1(long dt)
-{
- register struct tm *delta;
- time_t holder; /* A hack for 64bit SGI */
- static char buf[64];
- if (dt < 0)
- dt = 0;
- holder = (time_t) dt;
- delta = gmtime(&holder);
- 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(long dt)
-{
- register struct tm *delta;
- static char buf[64];
- if (dt < 0)
- dt = 0;
-
- delta = gmtime((time_t *) & dt);
- if (delta->tm_yday > 0) {
- sprintf(buf, "%dd", delta->tm_yday);
- } else if (delta->tm_hour > 0) {
- sprintf(buf, "%dh", delta->tm_hour);
- } else if (delta->tm_min > 0) {
- sprintf(buf, "%dm", delta->tm_min);
- } else {
- sprintf(buf, "%ds", delta->tm_sec);
- }
- return buf;
-}
-
-/* connection messages
- * isnew: newly creaetd or not?
- * num: how many times connected?
- */
-void
-announce_connect(dbref player, int isnew, int num)
-{
- dbref loc;
- char tbuf1[BUFFER_LEN];
- dbref zone;
- dbref obj;
- int j;
-
- set_flag_internal(player, "CONNECTED");
-
- if (isnew) {
- /* A brand new player created. */
- sprintf(tbuf1, T("%s created."), Name(player));
- flag_broadcast(0, "MONITOR", "%s %s", T("GAME:"), tbuf1);
- }
-
- /* Redundant, but better for translators */
- if (Dark(player)) {
- sprintf(tbuf1, (num > 1) ? T("%s has DARK-reconnected.") :
- T("%s has DARK-connected."), Name(player));
- } else if (hidden(player)) {
- sprintf(tbuf1, (num > 1) ? T("%s has HIDDEN-reconnected.") :
- T("%s has HIDDEN-connected."), Name(player));
- } else {
- sprintf(tbuf1, (num > 1) ? T("%s has reconnected.") :
- T("%s has connected."), Name(player));
- }
-
- /* send out messages */
- if (!Dark(player))
- flag_broadcast(0, "MONITOR", "%s %s", T("GAME:"), tbuf1);
-
-#ifdef CHAT_SYSTEM
- if (ANNOUNCE_CONNECTS)
- chat_player_announce(player, tbuf1, (num == 1));
-#endif /* CHAT_SYSTEM */
-
- loc = Location(player);
- if (!GoodObject(loc)) {
- notify(player, T("You are nowhere!"));
- return;
- }
- orator = player;
-
- if (cf_motd_msg && *cf_motd_msg) {
- raw_notify(player, cf_motd_msg);
- }
- raw_notify(player, " ");
-
- if(ANNOUNCE_CONNECTS)
- notify_except(Contents(player), player, tbuf1, 0);
- /* added to allow player's inventory to hear a player connect */
- if(ANNOUNCE_CONNECTS)
- if(!Dark(player))
- notify_except(Contents(loc), player, tbuf1, NA_INTER_PRESENCE);
-
- /* clear the environment for possible actions */
- for (j = 0; j < 10; j++)
- global_eval_context.wnxt[j] = NULL;
- for (j = 0; j < NUMQ; j++)
- global_eval_context.rnxt[j] = NULL;
- strcpy(global_eval_context.ccom, "");
-
- /* do the person's personal connect action */
- (void) queue_attribute(player, "ACONNECT", player);
- if (ROOM_CONNECTS) {
- /* Do the room the player connected into */
- if (IsRoom(loc) || IsThing(loc)) {
- (void) queue_attribute(loc, "ACONNECT", player);
- }
- }
- /* do the person's division */
- if (GoodObject(SDIV(player).object))
- (void) queue_attribute(SDIV(player).object, "ACONNECT", player);
- /* do the zone of the player's location's possible aconnect */
- if ((zone = Zone(loc)) != NOTHING) {
- switch (Typeof(zone)) {
- case TYPE_THING:
- (void) queue_attribute(zone, "ACONNECT", player);
- break;
- case TYPE_ROOM:
- /* check every object in the room for a connect action */
- DOLIST(obj, Contents(zone)) {
- (void) queue_attribute(obj, "ACONNECT", player);
- }
- break;
- default:
- do_log(LT_ERR, 0, 0,
- T("Invalid zone #%d for %s(#%d) has bad type %d"), zone,
- Name(player), player, Typeof(zone));
- }
- }
- /* now try the master room */
- DOLIST(obj, Contents(MASTER_ROOM)) {
- (void) queue_attribute(obj, "ACONNECT", player);
- }
-}
-
-void
-announce_disconnect(dbref player)
-{
- dbref loc;
- int num;
- DESC *d;
- char tbuf1[BUFFER_LEN];
- dbref zone, obj;
- int j;
-
- loc = Location(player);
- if (!GoodObject(loc))
- return;
-
- orator = player;
-
- for (num = 0, d = descriptor_list; d; d = d->next)
- if (d->connected && (d->player == player))
- num++;
- if (num < 2) {
- sprintf(tbuf1, T("%s has disconnected."), Name(player));
-
- if (ANNOUNCE_CONNECTS) {
- if (!Dark(player))
- notify_except(Contents(loc), player, tbuf1, NA_INTER_PRESENCE);
- /* notify contents */
- notify_except(Contents(player), player, tbuf1, 0);
- }
-
- /* clear the environment for possible actions */
- for (j = 0; j < 10; j++)
- global_eval_context.wnxt[j] = NULL;
- for (j = 0; j < NUMQ; j++)
- global_eval_context.rnxt[j] = NULL;
- strcpy(global_eval_context.ccom, "");
-
- /* Setup all connect information as info to pass */
- (void) queue_attribute(player, "ADISCONNECT", player);
- /* do the person's division */
- if (GoodObject(SDIV(player).object))
- (void) queue_attribute(SDIV(player).object, "ACONNECT", player);
- if (ROOM_CONNECTS)
- if (IsRoom(loc) || IsThing(loc)) {
- (void) queue_attribute(loc, "ADISCONNECT", player);
- }
- /* do the zone of the player's location's possible adisconnect */
- if ((zone = Zone(loc)) != NOTHING) {
- switch (Typeof(zone)) {
- case TYPE_DIVISION:
- case TYPE_THING:
- (void) queue_attribute(zone, "ADISCONNECT", player);
- break;
- case TYPE_ROOM:
- /* check every object in the room for a connect action */
- DOLIST(obj, Contents(zone)) {
- (void) queue_attribute(obj, "ADISCONNECT", player);
- }
- break;
- default:
- do_log(LT_ERR, 0, 0,
- T("Invalid zone #%d for %s(#%d) has bad type %d"), zone,
- Name(player), player, Typeof(zone));
- }
- }
- /* now try the master room */
- DOLIST(obj, Contents(MASTER_ROOM)) {
- (void) queue_attribute(obj, "ADISCONNECT", player);
- }
- clear_flag_internal(player, "CONNECTED");
- (void) atr_add(player, "LASTLOGOUT", show_time(mudtime, 0), GOD, NOTHING);
- } else {
- /* note: when you partially disconnect, ADISCONNECTS are not executed */
- sprintf(tbuf1, T("%s has partially disconnected."), Name(player));
-
- if (ANNOUNCE_CONNECTS) {
- if (!Dark(player))
- notify_except(Contents(loc), player, tbuf1, NA_INTER_PRESENCE);
- /* notify contents */
- notify_except(Contents(player), player, tbuf1, 0);
- }
- }
-
-#ifdef CHAT_SYSTEM
- if (ANNOUNCE_CONNECTS)
- chat_player_announce(player, tbuf1, 0);
-#endif /* CHAT_SYSTEM */
-
- /* Monitor broadcasts */
- /* Redundant, but better for translators */
- if (Dark(player)) {
- sprintf(tbuf1, (num < 2) ? T("%s has DARK-disconnected.") :
- T("%s has partially DARK-disconnected."), Name(player));
- } else if (hidden(player)) {
- sprintf(tbuf1, (num < 2) ? T("%s has HIDDEN-disconnected.") :
- T("%s has partially HIDDEN-disconnected."), Name(player));
- } else {
- sprintf(tbuf1, (num < 2) ? T("%s has disconnected.") :
- T("%s has partially disconnected."), Name(player));
- }
- if (!Dark(player))
- flag_broadcast(0, "MONITOR", "%s %s", T("GAME:"), tbuf1);
- if(Guest(player)) { /* queue for destruction */
- set_flag_internal(player, "GOING");
- set_flag_internal(player, "GOING_TWICE");
- }
- local_disconnect(player, num);
-}
-
-/** Set an motd message.
- * \verbatim
- * This implements @motd.
- * \endverbatim
- * \param player the enactor.
- * \param key type of MOTD to set.
- * \param message text to set the motd to.
- */
-void
-do_motd(dbref player, enum motd_type key, const char *message)
-{
-
- if (!Site(player) && key != MOTD_LIST) {
- notify(player,
- T
- ("You may get 15 minutes of fame and glory in life, but not right now."));
- return;
- }
- switch (key) {
- case MOTD_MOTD:
- strcpy(cf_motd_msg, message);
- notify(player, T("Motd set."));
- break;
- case MOTD_DOWN:
- strcpy(cf_downmotd_msg, message);
- notify(player, T("Down motd set."));
- break;
- case MOTD_FULL:
- strcpy(cf_fullmotd_msg, message);
- notify(player, T("Full motd set."));
- break;
- case MOTD_LIST:
- notify_format(player, "MOTD: %s", cf_motd_msg);
- if (Site(player)) {
- notify_format(player, T("Down MOTD: %s"), cf_downmotd_msg);
- notify_format(player, T("Full MOTD: %s"), cf_fullmotd_msg);
- }
- }
-}
-
-/** Set a DOING message.
- * \verbatim
- * This implements @doing.
- * \endverbatim
- * \param player the enactor.
- * \param message the message to set.
- */
-void
-do_doing(dbref player, const char *message)
-{
- char buf[MAX_COMMAND_LEN];
- DESC *d;
- int i;
-
- if (!Connected(player)) {
- /* non-connected things have no need for a doing */
- notify(player, T("Why would you want to do that?"));
- return;
- }
- strncpy(buf, remove_markup(message, NULL), DOING_LEN - 1);
-
- /* now smash undesirable characters and truncate */
- for (i = 0; i < DOING_LEN; i++) {
- if ((buf[i] == '\r') || (buf[i] == '\n') ||
- (buf[i] == '\t') || (buf[i] == BEEP_CHAR))
- buf[i] = ' ';
- }
- buf[DOING_LEN - 1] = '\0';
-
- /* set it */
- for (d = descriptor_list; d; d = d->next)
- if (d->connected && (d->player == player))
- strcpy(d->doing, buf);
- if (strlen(message) >= DOING_LEN) {
- notify_format(player,
- T("Doing set. %zu characters lost."),
- strlen(message) - (DOING_LEN - 1));
- } else
- notify(player, T("Doing set."));
-}
-
-/** Set a poll message (which replaces "Doing" in the DOING output).
- * \verbatim
- * This implements @poll.
- * \endverbatim
- * \param player the enactor.
- * \param message the message to set.
- */
-void
-do_poll(dbref player, const char *message)
-{
- int i;
-
- if (!Change_Poll(player)) {
- notify(player, T("Who do you think you are, Gallup?"));
- return;
- }
- strncpy(poll_msg, remove_markup(message, NULL), DOING_LEN - 1);
- for (i = 0; i < DOING_LEN; i++) {
- if ((poll_msg[i] == '\r') || (poll_msg[i] == '\n') ||
- (poll_msg[i] == '\t') || (poll_msg[i] == BEEP_CHAR))
- poll_msg[i] = ' ';
- }
- poll_msg[DOING_LEN - 1] = '\0';
-
- if (strlen(message) >= DOING_LEN) {
- poll_msg[DOING_LEN - 1] = 0;
- notify_format(player,
- T("Poll set. %zu characters lost."),
- strlen(message) - (DOING_LEN - 1));
- } else
- notify(player, T("Poll set."));
- do_log(LT_WIZ, player, NOTHING, T("Poll Set to '%s'."), poll_msg);
-}
-
-/** Match the partial name of a connected player.
- * \param match string to match.
- * \return dbref of a unique connected player whose name partial-matches,
- * AMBIGUOUS, or NOTHING.
- */
-dbref
-short_page(const char *match)
-{
- DESC *d;
- dbref who1 = NOTHING;
- int count = 0;
-
- for (d = descriptor_list; d; d = d->next) {
- if (d->connected) {
- if (match && !string_prefix(Name(d->player), match))
- continue;
- if (!strcasecmp(Name(d->player), match)) {
- count = 1;
- who1 = d->player;
- break;
- }
- if (who1 == NOTHING || d->player != who1) {
- who1 = d->player;
- count++;
- }
- }
- }
-
- if (count > 1)
- return AMBIGUOUS;
- else if (count == 0)
- return NOTHING;
-
- return who1;
-}
-
-/** Match the partial name of a connected player the enactor can see.
- * \param player the enactor
- * \param match string to match.
- * \return dbref of a unique connected player whose name partial-matches,
- * AMBIGUOUS, or NOTHING.
- */
-dbref
-visible_short_page(dbref player, const char *match)
-{
- dbref target;
- target = short_page(match);
- if (Priv_Who(player) || !GoodObject(target))
- return target;
- if (Dark(target) || (hidden(target) && !nearby(player, target)))
- return NOTHING;
- return target;
-}
-
-/* LWHO() function - really belongs elsewhere but needs stuff declared here */
-
-FUNCTION(fun_nwho) {
-}
-
-/* ARGSUSED */
-FUNCTION(fun_lwho)
-{
- DESC *d;
- dbref victim;
- int first, powered = (*called_as == 'L') && Priv_Who(executor);
-
- first = 1;
- if(nargs && args[0] && *args[0]) {
- if(!powered) {
- safe_str(T(e_perm), buff, bp);
- return;
- }
-
- if( (victim = noisy_match_result(executor, args[0], NOTYPE, MAT_EVERYTHING)) == 0) {
- safe_str(T(e_notvis), buff, bp);
- return;
- }
- if(!controls(executor, victim)) {
- safe_str(T(e_perm), buff, bp);
- return;
- }
- if(!Priv_Who(victim))
- powered = 0;
- } else victim = executor;
-
- DESC_ITER_CONN(d) {
- if (!Hidden(d) || (powered && CanSee(victim,d->player))) {
- if (first)
- first = 0;
- else
- safe_chr(' ', buff, bp);
- safe_dbref(d->player, buff, bp);
- }
- }
-}
-
-
-/** Look up a DESC by character name or file descriptor.
- * \param executor the dbref of the object calling the function calling this.
- * \param name the name or descriptor to look up.
- * \retval a pointer to the proper DESC, or NULL
- */
-static DESC *
-lookup_desc(dbref executor, const char *name)
-{
- DESC *d;
-
- /* Given a file descriptor. See-all only. */
- if (is_strict_integer(name)) {
- int fd = parse_integer(name);
- DESC_ITER_CONN(d) {
- if (d->descriptor == fd) {
- if (Priv_Who(executor) || d->player == executor
- || (Inherit_Powers(executor) && Priv_Who(Owner(executor))))
- return d;
- else
- return NULL;
- }
- }
- return NULL;
- } else { /* Look up player name */
- DESC *match = NULL;
- dbref target = lookup_player(name);
- if (target == NOTHING) {
- target = match_result(executor, name, TYPE_PLAYER,
- MAT_ABSOLUTE | MAT_PLAYER | MAT_ME);
- }
- if (!GoodObject(target) || !Connected(target))
- return NULL;
- else {
- /* walk the descriptor list looking for a match of a dbref */
- DESC_ITER_CONN(d) {
- if ((d->player == target) &&
- (!Hidden(d) || Priv_Who(executor) ||
- (Inherit_Powers(executor) && Priv_Who(Owner(executor)))) &&
- (!match || (d->last_time > match->last_time)))
- match = d;
- }
- return match;
- }
- }
-}
-
-/** Return the conn time of the longest-connected connection of a player.
- * This function treats hidden connectios as nonexistent.
- * \param player dbref of player to get ip for.
- * \return connection time of player as an INT, or -1 if not found or hidden.
- */
-int
-most_conn_time(dbref player)
-{
- DESC *d, *match = NULL;
- DESC_ITER_CONN(d) {
- if ((d->player == player) && !Hidden(d) && (!match ||
- (d->connected_at >
- match->connected_at)))
- match = d;
- }
- if (match) {
- double result = difftime(mudtime, match->connected_at);
- return (int) result;
- } else
- return -1;
-}
-
-/** Return the conn time of the longest-connected connection of a player.
- * This function does includes hidden people.
- * \param player dbref of player to get ip for.
- * \return connection time of player as an INT, or -1 if not found.
- */
-int
-most_conn_time_priv(dbref player)
-{
- DESC *d, *match = NULL;
- DESC_ITER_CONN(d) {
- if ((d->player == player) && (!match ||
- (d->connected_at > match->connected_at)))
- match = d;
- }
- if (match) {
- double result = difftime(mudtime, match->connected_at);
- return (int) result;
- } else
- return -1;
-}
-
-/** Return the idle time of the least-idle connection of a player.
- * This function treats hidden connections as nonexistant.
- * \param player dbref of player to get time for.
- * \return idle time of player as an INT, or -1 if not found or hidden.
- */
-int
-least_idle_time(dbref player)
-{
- DESC *d, *match = NULL;
- DESC_ITER_CONN(d) {
- if ((d->player == player) && !Hidden(d) &&
- (!match || (d->last_time > match->last_time)))
- match = d;
- }
- if (match) {
- double result = difftime(mudtime, match->last_time);
- return (int) result;
- } else
- return -1;
-}
-
-/** Return the idle time of the least-idle connection of a player.
- * This function performs no permission checking.
- * \param player dbref of player to get time for.
- * \return idle time of player as an INT, or -1 if not found.
- */
-int
-least_idle_time_priv(dbref player)
-{
- DESC *d, *match = NULL;
- DESC_ITER_CONN(d) {
- if ((d->player == player) && (!match || (d->last_time > match->last_time)))
- match = d;
- }
- if (match) {
- double result = difftime(mudtime, match->last_time);
- return (int) result;
- } else
- return -1;
-}
-
-/** Return the ip address of the least-idle connection of a player.
- * This function performs no permission checking, and returns the
- * pointer from the descriptor itself (so don't destroy the result!)
- * \param player dbref of player to get ip for.
- * \return IP address of player as a string or NULL if not found.
- */
-char *
-least_idle_ip(dbref player)
-{
- DESC *d, *match = NULL;
- DESC_ITER_CONN(d) {
- if ((d->player == player) && (!match || (d->last_time > match->last_time)))
- match = d;
- }
- return match ? (match->ip) : NULL;
-}
-
-/** Return the hostname of the least-idle connection of a player.
- * This function performs no permission checking, and returns a static
- * string.
- * \param player dbref of player to get ip for.
- * \return hostname of player as a string or NULL if not found.
- */
-char *
-least_idle_hostname(dbref player)
-{
- DESC *d, *match = NULL;
- static char hostname[101];
- char *p;
-
- DESC_ITER_CONN(d) {
- if ((d->player == player) && (!match || (d->last_time > match->last_time)))
- match = d;
- }
- if (!match)
- return NULL;
- strcpy(hostname, match->addr);
- if ((p = strchr(hostname, '@'))) {
- p++;
- return p;
- } else
- return hostname;
-}
-
-/* ZWHO() function - really belongs in eval.c but needs stuff declared here */
-/* ARGSUSED */
-FUNCTION(fun_zwho)
-{
- DESC *d;
- dbref zone, victim;
- int first;
- int powered = (strcmp(called_as, "ZMWHO") && Priv_Who(executor) || (Inherit_Powers(executor) && Priv_Who(Owner(executor))));
- first = 1;
-
- zone = match_thing(executor, args[0]);
-
- if (nargs == 1) {
- victim = executor;
- } else if ((nargs == 2) && powered) {
- if ((victim = match_thing(executor, args[1])) == 0) {
- safe_str(T(e_match), buff, bp);
- return;
- }
- } else {
- safe_str(T(e_perm), buff, bp);
- return;
- }
-
- if (!GoodObject(zone) || !(eval_lock(victim, zone, Zone_Lock) || CanModify(victim,zone))) {
- safe_str(T(e_perm), buff, bp);
- return;
- }
- if ((getlock(zone, Zone_Lock) == TRUE_BOOLEXP) ||
- (IsPlayer(zone) && !(has_flag_by_name(zone, "SHARED", TYPE_PLAYER)))) {
- safe_str(T("#-1 INVALID ZONE."), buff, bp);
- return;
- }
-
- /* Use lowest privilege for victim */
- if (!Priv_Who(victim))
- powered = 0;
-
- DESC_ITER_CONN(d) {
- if (!Hidden(d) || powered) {
- if (Zone(Location(d->player)) == zone) {
- if (first) {
- first = 0;
- } else {
- safe_chr(' ', buff, bp);
- }
- safe_dbref(d->player, buff, bp);
- }
- }
- }
-}
-
-/* ARGSUSED */
-FUNCTION(fun_doing)
-{
- /* Gets a player's @doing */
- DESC *d = lookup_desc(executor, args[0]);
- if (d)
- safe_str(d->doing, buff, bp);
- else
- safe_str("#-1", buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_hostname)
-{
- /* Gets a player's hostname */
- DESC *d = lookup_desc(executor, args[0]);
- if (d && (d->player == executor || Site(executor)))
- safe_str(d->addr, buff, bp);
- else
- safe_str("#-1", buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_ipaddr)
-{
- /* Gets a player's IP address */
- DESC *d = lookup_desc(executor, args[0]);
- if (d && (d->player == executor || Site(executor)))
- safe_str(d->ip, buff, bp);
- else
- safe_str("#-1", buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_cmds)
-{
- /* Gets a player's IP address */
- DESC *d = lookup_desc(executor, args[0]);
- if (d && (d->player == executor || Site(executor)))
- safe_integer(d->cmds, buff, bp);
- else
- safe_integer(-1, buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_sent)
-{
- /* Gets a player's bytes sent */
- DESC *d = lookup_desc(executor, args[0]);
- if (d && (d->player == executor || Site(executor)))
- safe_integer(d->input_chars, buff, bp);
- else
- safe_integer(-1, buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_recv)
-{
- /* Gets a player's bytes received */
- DESC *d = lookup_desc(executor, args[0]);
- if (d && (d->player == executor || Site(executor)))
- safe_integer(d->output_chars, buff, bp);
- else
- safe_integer(-1, buff, bp);
-}
-
-FUNCTION(fun_poll)
-{
- /* Gets the current poll */
- if (poll_msg[0] == '\0')
- strcpy(poll_msg, "Doing");
-
- safe_str(poll_msg, buff, bp);
-}
-
-FUNCTION(fun_pueblo)
-{
- /* Return the status of the pueblo flag on the least idle descriptor we
- * find that matches the player's dbref.
- */
- DESC *match = lookup_desc(executor, args[0]);
- if (match)
- safe_boolean(match->conn_flags & CONN_HTML, buff, bp);
- else
- safe_str(T("#-1 NOT CONNECTED"), buff, bp);
-}
-
-FUNCTION(fun_ssl)
-{
- /* Return the status of the ssl flag on the least idle descriptor we
- * find that matches the player's dbref.
- */
- safe_boolean(0, buff, bp);
-}
-
-FUNCTION(fun_width)
-{
- DESC *match;
- if (!*args[0])
- safe_str(T("#-1 FUNCTION REQUIRES ONE ARGUMENT"), buff, bp);
- else if ((match = lookup_desc(executor, args[0])))
- safe_integer(match->width, buff, bp);
- else
- safe_str("78", buff, bp);
-}
-
-FUNCTION(fun_height)
-{
- DESC *match;
- if (!*args[0])
- safe_str(T("#-1 FUNCTION REQUIRES ONE ARGUMENT"), buff, bp);
- else if ((match = lookup_desc(executor, args[0])))
- safe_integer(match->height, buff, bp);
- else
- safe_str("24", buff, bp);
-}
-
-FUNCTION(fun_terminfo)
-{
- DESC *match;
- if (!*args[0])
- safe_str(T("#-1 FUNCTION REQUIRES ONE ARGUMENT"), buff, bp);
- else if ((match = lookup_desc(executor, args[0]))) {
- if (match->player == executor || Site(executor)) {
- safe_str(match->ttype, buff, bp);
- if (match->conn_flags & CONN_HTML)
- safe_str(" pueblo", buff, bp);
- if (match->conn_flags & CONN_TELNET)
- safe_str(" telnet", buff, bp);
- } else
- safe_str(T(e_perm), buff, bp);
- } else
- safe_str(T("#-1 NOT CONNECTED"), buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_idlesecs)
-{
- /* returns the number of seconds a player has been idle, using
- * their least idle connection
- */
-
- DESC *match = lookup_desc(executor, args[0]);
- if (match)
- safe_number(difftime(mudtime, match->last_time), buff, bp);
- else
- safe_str("-1", buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_idle_average) {
- DESC *match = lookup_desc(executor, args[0]);
- double idle_time;
-
- if(match) {
- idle_time = difftime(mudtime, match->last_time);
- if(idle_time >= 300)
- safe_number(((match->idle_total + idle_time) / (match->unidle_times+1)), buff, bp);
- else if(match->unidle_times == 0)
- safe_number(0, buff, bp);
- else
- safe_number((match->idle_total / match->unidle_times), buff, bp);
-
- } else
- safe_str("-1", buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_idle_total) {
- DESC *match = lookup_desc(executor, args[0]);
- double idle_time;
-
- if(match) {
- idle_time = difftime(mudtime, match->last_time);
- safe_number(idle_time >= 300 ? (match->idle_total+idle_time) : match->idle_total, buff, bp);
- } else
- safe_str("-1", buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_idle_times) {
- DESC *match = lookup_desc(executor, args[0]);
-
- if(match) {
- safe_number((difftime(mudtime, match->last_time) >= 300) ?
- (match->unidle_times+1) : match->unidle_times, buff, bp);
- } else
- safe_str("-1", buff, bp);
-}
-
-
-/* ARGSUSED */
-FUNCTION(fun_conn)
-{
- /* returns the number of seconds a player has been connected, using
- * their longest-connected descriptor
- */
-
- DESC *match = lookup_desc(executor, args[0]);
- if (match)
- safe_number(difftime(mudtime, match->connected_at), buff, bp);
- else
- safe_str("-1", buff, bp);
-}
-
-/* ARGSUSED */
-FUNCTION(fun_lports)
-{
- DESC *d;
- int first = 1;
-
- if (!Priv_Who(executor)
- && !(Inherit_Powers(executor) && Priv_Who(Owner(executor)))) {
- safe_str(T(e_perm), buff, bp);
- return;
- }
-
- DESC_ITER_CONN(d) {
- if (first)
- first = 0;
- else
- safe_chr(' ', buff, bp);
- safe_integer(d->descriptor, buff, bp);
- }
-}
-
-/* ARGSUSED */
-FUNCTION(fun_ports)
-{
- /* returns a list of the network descriptors that a player is
- * connected to
- */
-
- dbref target;
- DESC *d;
- int first;
-
- target = lookup_player(args[0]);
- if (target == NOTHING) {
- target = match_result(executor, args[0], TYPE_PLAYER,
- MAT_ABSOLUTE | MAT_PLAYER | MAT_ME);
- }
- if (target != executor && !Priv_Who(executor)
- && !(Inherit_Powers(executor) && Priv_Who(Owner(executor)))) {
- /* This should probably be a safe_str */
- notify(executor, T("Permission denied."));
- return;
- }
- if (!GoodObject(target) || !Connected(target)) {
- return;
- }
- /* Walk descriptor chain. */
- first = 1;
- DESC_ITER_CONN(d) {
- if (d->player == target) {
- if (first)
- first = 0;
- else
- safe_chr(' ', buff, bp);
- safe_integer(d->descriptor, buff, bp);
- }
- }
-}
-
-
-/** Hide or unhide a player.
- * Although hiding is a per-descriptor state, this function sets all of
- * a player's connected descriptors to be hidden.
- * \param player dbref of player to hide.
- * \param hide if 1, hide; if 0, unhide.
- */
-void
-hide_player(dbref player, int hide)
-{
- DESC *d;
- if (!Connected(player))
- return;
- if (!Can_Hide(player)) {
- notify(player, T("Permission denied."));
- return;
- }
- /* change status on WHO */
- if (Can_Hide(player)) {
- DESC_ITER_CONN(d) {
- if (d->player == player)
- d->hide = hide;
- }
- }
- if (hide)
- notify(player, T("You no longer appear on the WHO list."));
- else
- notify(player, T("You now appear on the WHO list."));
-}
-
-/** Perform the periodic check of inactive descriptors, and
- * disconnect them or autohide them as appropriate.
- */
-void
-inactivity_check(void)
-{
- DESC *d, *nextd;
- ATTR *a;
- char tbuf[BUFFER_LEN];
- time_t now, idle, idle_for, unconnected_idle;
- if (!INACTIVITY_LIMIT && !UNCONNECTED_LIMIT)
- return;
- now = mudtime;
- idle = INACTIVITY_LIMIT ? INACTIVITY_LIMIT : INT_MAX;
- unconnected_idle = UNCONNECTED_LIMIT ? UNCONNECTED_LIMIT : INT_MAX;
- for (d = descriptor_list; d; d = nextd) {
- nextd = d->next;
- idle_for = now - d->last_time;
- /* If they've been connected for 60 seconds without getting a telnet-option
- back, the client probably doesn't understand them */
- if ((d->conn_flags & CONN_TELNET_QUERY) && idle_for > 60)
- d->conn_flags &= ~CONN_TELNET_QUERY;
- if(d->connected && GoodObject(d->player) && ((a = atr_get(d->player, "IDLE_TIMEOUT"))!=NULL)) {
- memset(tbuf, '\0', BUFFER_LEN);
- strncpy(tbuf, atr_value(a), BUFFER_LEN-1);
- idle = atoi(tbuf);
- if(idle > 0)
- goto after_idle_atr_check;
- }
- idle = INACTIVITY_LIMIT ? INACTIVITY_LIMIT : INT_MAX;
-after_idle_atr_check:
- if ((d->connected) ? (idle_for > idle ) : (idle_for > unconnected_idle)) {
-
- if (!d->connected)
- shutdownsock(d);
- else if (!Can_Idle(d->player)) {
-
- queue_string(d, T("\n*** Inactivity timeout ***\n"));
- do_log(LT_CONN, 0, 0,
- T("[%d/%s/%s] Logout by %s(#%d) <Inactivity Timeout>"),
- d->descriptor, d->addr, d->ip, Name(d->player), d->player);
- boot_desc(d);
- } else if (Unfind(d->player)) {
-
- if ((Can_Hide(d->player)) && (!Hidden(d))) {
- queue_string(d,
- T
- ("\n*** Inactivity limit reached. You are now HIDDEN. ***\n"));
- d->hide = 1;
- }
- }
- }
- }
-}
-
-
-/** Given a player dbref, return the player's hidden status.
- * \param player dbref of player to check.
- * \retval 1 player is hidden.
- * \retval 0 player is not hidden.
- */
-int
-hidden(dbref player)
-{
- DESC *d;
- DESC_ITER_CONN(d) {
- if (d->player == player) {
- if (Hidden(d))
- return 1;
- else
- return 0;
- }
- }
- return 0;
-}
-
-
-/** Return the mailp of the player closest in db# to player,
- * or NULL if there's nobody on-line.
- * In the current mail system, mail is stored in a linked list, sorted
- * by recipient, which makes the most common operations (listing and reading
- * your mail) fast. When a player first connects, we store (on the
- * mailp element of their descriptor) a pointer to the beginning of
- * their part of the linked list. Rather than search the whole linked
- * list to find this location, we look at the mailp's of all the other
- * connected players, and find the mailp of the player whose dbref
- * is closest to the connecting player, and start our search from that
- * point. This scales up nicely - as a mushes get larger, the linked
- * list gets larger, but the more people connected at once, the faster
- * the search for a newly connecting player's first mail.
- * \param player player whose db# we want to get near.
- * \return pointer to first mail of connected player with db# closest to
- * player.
- */
-MAIL *
-desc_mail(dbref player)
-{
- DESC *d;
- int i;
- int diff = db_top;
- static MAIL *mp;
- mp = NULL;
- DESC_ITER_CONN(d) {
- i = abs(d->player - player);
- if (i == 0)
- return d->mailp;
- if ((i < diff) && d->mailp) {
- diff = i;
- mp = d->mailp;
- }
- }
- return mp;
-}
-
-/** Set a player's mail position on all their descriptors.
- * \param player player to set mail position for.
- * \param mp pointer to first mail in their list.
- */
-void
-desc_mail_set(dbref player, MAIL *mp)
-{
- DESC *d;
- DESC_ITER_CONN(d) {
- if (d->player == player)
- d->mailp = mp;
- }
-}
-
-/** Clear mail positions on all descriptors. Called from do_mail_nuke().
- */
-void
-desc_mail_clear(void)
-{
- DESC *d;
- DESC_ITER_CONN(d) {
- d->mailp = NULL;
- }
-}
-
-
-
-
-#ifdef SUN_OS
-/* SunOS's implementation of stdio breaks when you get a file descriptor
- * greater than 128. Brain damage, brain damage, brain damage!
- *
- * Our objective, therefore, is not to fix stdio, but to work around it,
- * so that performance degrades semi-gracefully when you are using a lot
- * of file descriptors.
- * Therefore, we'll save a file descriptor when we start up that is less
- * than 128, so that if we get a file descriptor that is >= 128, we can
- * use our own saved file descriptor instead. This is only one level of
- * defense; if you have more than 128 fd's in use, and you try two fopen's
- * before doing an fclose(), the second will fail.
- */
-
-FILE *
-fopen(file, mode)
- const char *file;
- const char *mode;
-{
-/* FILE *f; */
- int fd, rw, oflags = 0;
-/* char tbchar; */
- rw = (mode[1] == '+') || (mode[1] && (mode[2] == '+'));
- switch (*mode) {
- case 'a':
- oflags = O_CREAT | (rw ? O_RDWR : O_WRONLY);
- break;
- case 'r':
- oflags = rw ? O_RDWR : O_RDONLY;
- break;
- case 'w':
- oflags = O_TRUNC | O_CREAT | (rw ? O_RDWR : O_WRONLY);
- break;
- default:
- return (NULL);
- }
-/* SunOS fopen() doesn't use the 't' or 'b' flags. */
-
-
- fd = open(file, oflags, 0666);
- if (fd < 0)
- return NULL;
- /* My addition, to cope with SunOS brain damage! */
- if (fd >= 128) {
- close(fd);
- if ((extrafd < 128) && (extrafd >= 0)) {
- close(extrafd);
- fd = open(file, oflags, 0666);
- extrafd = -1;
- } else {
- return NULL;
- }
- }
- /* End addition. */
-
- return fdopen(fd, mode);
-}
-
-
-#undef fclose(x)
-int
-f_close(stream)
- FILE *stream;
-{
- int fd = fileno(stream);
- /* if extrafd is bad, and the fd we're closing is good, recycle the
- * fd into extrafd.
- */
- fclose(stream);
- if (((extrafd < 0)) && (fd >= 0) && (fd < 128)) {
- extrafd = open("/dev/null", O_RDWR);
- if (extrafd >= 128) {
- /* To our surprise, we didn't get a usable fd. */
- close(extrafd);
- extrafd = -1;
- }
- }
- return 0;
-}
-
-#define fclose(x) f_close(x)
-#endif /* SUN_OS */
-
-/** Dump the descriptor list to our REBOOTFILE so we can restore it on reboot.
- */
-void
-dump_reboot_db(void)
-{
- FILE *f;
- DESC *d;
- SU_PATH *exit_path;
- long flags = RDBF_SCREENSIZE | RDBF_TTYPE | RDBF_PUEBLO_CHECKSUM
- | RDBF_SU_EXIT_PATH;
- if (setjmp(db_err)) {
- flag_broadcast(0, 0, T("GAME: Error writing reboot database!"));
- exit(0);
- } else {
-
- f = fopen(REBOOTFILE, "w");
- /* This shouldn't happen */
- if (!f) {
- flag_broadcast(0, 0, T("GAME: Error writing reboot database!"));
- exit(0);
- }
- /* Write out the reboot db flags here */
- fprintf(f, "V%ld\n", flags);
- putref(f, 0);
- putref(f, 0);
- /* First, iterate through all descriptors to get to the end
- * we do this so the descriptor_list isn't reversed on reboot
- */
- for (d = descriptor_list; d && d->next; d = d->next) ;
- /* Second, we iterate backwards from the end of descriptor_list
- * which is now in the d variable.
- */
- for (; d != NULL; d = d->prev) {
- putref(f, d->descriptor);
- putref(f, d->connected_at);
- putref(f, d->hide);
- putref(f, d->cmds);
- putref(f, d->idle_total);
- putref(f, d->unidle_times);
- if (GoodObject(d->player))
- putref(f, d->player);
- else
- putref(f, -1);
- putref(f, d->last_time);
- if (d->output_prefix)
- putstring(f, (char *) d->output_prefix);
- else
- putstring(f, "__NONE__");
- if (d->output_suffix)
- putstring(f, (char *) d->output_suffix);
- else
- putstring(f, "__NONE__");
- putstring(f, d->addr);
- putstring(f, d->ip);
- putstring(f, d->doing);
- putref(f, d->conn_flags);
- putref(f, d->width);
- putref(f, d->height);
- putstring(f, d->ttype);
- putstring(f, d->checksum);
- for(exit_path = d->su_exit_path; exit_path; exit_path = exit_path->next)
- putref(f, exit_path->player);
- putref(f, NOTHING);
- } /* for loop */
-
- putref(f, 0);
- putstring(f, poll_msg);
- putref(f, globals.first_start_time);
- putref(f, globals.reboot_count);
- fclose(f);
- }
-}
-
-/** Load the descriptor list back from the REBOOTFILE on reboot.
- */
-void
-load_reboot_db(void)
-{
- FILE *f;
- DESC *d = NULL;
- DESC *closed = NULL, *nextclosed;
- int val;
- int n;
- const char *temp;
- char c;
- long flags = 0;
- char tbuf1[BUFFER_LEN];
- SU_PATH *epnext, *epprev;
- dbref exit_path;
- f = fopen(REBOOTFILE, "r");
- if (!f) {
- restarting = 0;
- return;
- }
- restarting = 1;
- /* Get the first line and see if it's a set of reboot db flags.
- * Those start with V<number>
- * If not, assume we're using the original format, in which the
- * sock appears first
- * */
- c = getc(f); /* Skip the V */
- if (c == 'V') {
- flags = getref(f);
- } else {
- ungetc(c, f);
- }
-
- val = getref(f);
- val = getref(f);
-
- while ((val = getref(f)) != 0) {
- ndescriptors++;
- d = (DESC *) mush_malloc(sizeof(DESC), "descriptor");
- d->descriptor = val;
- d->input_handler = do_command;
- d->connected_at = getref(f);
- d->hide = getref(f);
- d->cmds = getref(f);
- d->idle_total = getref(f);
- d->unidle_times = getref(f);
- d->player = getref(f);
- d->last_time = getref(f);
- d->pinfo.object = NOTHING;
- d->pinfo.atr = NULL;
- d->pinfo.lock = 0;
- d->pinfo.function = NULL;
- d->connected = GoodObject(d->player) ? 1 : 0;
- /* setup snooper array */
- for(n = 0; n < MAX_SNOOPS; n++)
- d->snooper[n] = -1;
-
- temp = getstring_noalloc(f);
- d->output_prefix = NULL;
- if (strcmp(temp, "__NONE__"))
- set_userstring(&d->output_prefix, temp);
- temp = getstring_noalloc(f);
- d->output_suffix = NULL;
- if (strcmp(temp, "__NONE__"))
- set_userstring(&d->output_suffix, temp);
- strcpy(d->addr, getstring_noalloc(f));
- strcpy(d->ip, getstring_noalloc(f));
- strcpy(d->doing, getstring_noalloc(f));
- d->conn_flags = getref(f);
- if (flags & RDBF_SCREENSIZE) {
- d->width = getref(f);
- d->height = getref(f);
- } else {
- d->width = 78;
- d->width = 24;
- }
- if (flags & RDBF_TTYPE)
- d->ttype = mush_strdup(getstring_noalloc(f), "terminal description");
- else
- d->ttype = mush_strdup("unknown", "terminal description");
- if (flags & RDBF_PUEBLO_CHECKSUM)
- strcpy(d->checksum, getstring_noalloc(f));
- else
- d->checksum[0] = '\0';
- d->su_exit_path = NULL;
- if (flags & RDBF_SU_EXIT_PATH) {
- exit_path = getref(f);
- while(GoodObject(exit_path)) {
- add_to_exit_path(d, exit_path);
- exit_path = getref(f);
- }
- epprev = NULL;
- while(d->su_exit_path) {
- epnext = d->su_exit_path->next;
- d->su_exit_path->next = epprev;
- epprev = d->su_exit_path;
- d->su_exit_path = epnext;
- }
- d->su_exit_path = epprev;
- }
- d->input_chars = 0;
- d->output_chars = 0;
- d->output_size = 0;
- d->output.head = 0;
- d->output.tail = &d->output.head;
- d->input.head = 0;
- d->input.tail = &d->input.head;
- d->raw_input = NULL;
- d->raw_input_at = NULL;
- d->quota = options.starting_quota;
- d->mailp = NULL;
- if (d->conn_flags & CONN_CLOSE_READY) {
- /* This isn't really an open descriptor, we're just tracking
- * it so we can announce the disconnect properly. Do so, but
- * don't link it into the descriptor list. Instead, keep a
- * separate list.
- */
- if (closed)
- closed->prev = d;
- d->next = closed;
- d->prev = NULL;
- closed = d;
- } else {
- if (descriptor_list)
- descriptor_list->prev = d;
- d->next = descriptor_list;
- d->prev = NULL;
- descriptor_list = d;
- if (d->connected && d->player && GoodObject(d->player) &&
- IsPlayer(d->player))
- set_flag_internal(d->player, "CONNECTED");
- else if ((!d->player || !GoodObject(d->player)) && d->connected) {
- d->connected = 0;
- d->player = 0;
- }
- /* If they were in a program, get them back into it */
- if(d->connected && InProg(d->player))
- prog_load_desc(d);
- }
- } /* while loop */
-
- /* Now announce disconnects of everyone who's not really here */
- while (closed) {
- nextclosed = closed->next;
- if(closed->last_time > 0) {
- closed->idle_total += difftime(mudtime, closed->last_time);
- closed->unidle_times++;
- }
-
- snprintf(tbuf1, BUFFER_LEN-1, "%ld %ld %d %d", (mudtime - closed->connected_at),
- closed->idle_total , closed->unidle_times, closed->cmds);
- tbuf1[strlen(tbuf1)+1] = '\0';
- (void) atr_add(closed->player, "LASTACTIVITY", tbuf1, GOD, NOTHING);
- announce_disconnect(closed->player);
- mush_free(closed, "descriptor");
- closed = nextclosed;
- }
-
- strcpy(poll_msg, getstring_noalloc(f));
- globals.first_start_time = getref(f);
- globals.reboot_count = getref(f) + 1;
- DESC_ITER_CONN(d) {
- d->mailp = find_exact_starting_point(d->player);
- }
-
- fclose(f);
- remove(REBOOTFILE);
- flag_broadcast(0, 0, T("GAME: Reboot finished."));
-}
-
-
-/* Syntax: @snoop[/list] [!]<descriptor>
- */
-COMMAND(cmd_snoop) {
- DESC *d;
- int descn, on, n, sn;
- char snooplist[MAX_SNOOPS][BUFFER_LEN];
- char buf[BUFFER_LEN], *bp;
-
- if(SW_ISSET(sw, SWITCH_LIST)) {
- descn = atoi(arg_left);
-
- bp = buf;
-
- d = port_desc(descn);
-
- if (LEVEL(player) <= 28) {
- notify(player, MSG_HUH);
- return;
- }
- /* make sure teh desc exists and they're connected (no spying on 'em at the connect screen!) */
- if(!d || (d && !IsPlayer(d->player))) {
- notify(player, "There is no one connected on that descriptor.");
- return;
- }
-
- for(sn = 0, n = 0; n < MAX_SNOOPS; n++)
- if(d->snooper[n] != -1) {
- memset(snooplist[sn], '\0', BUFFER_LEN);
- snprintf(snooplist[sn++], BUFFER_LEN-1, "%s", Name(d->snooper[n]));
- }
- *snooplist[sn] = '\0';
-
- for(n = 0; n < sn; n++) {
- if(n != 0)
- safe_str(", ", buf, &bp);
- if(n == (sn-1) && sn > 1)
- safe_str("& ", buf, &bp);
- safe_str(snooplist[n], buf, &bp);
- }
- *bp = '\0';
- notify_format(player, "%s is being snooped on by: %s", Name(d->player), buf);
-
- } else {
- if(*arg_left== '!') {
- on = 0;
- descn = atoi(arg_left+1);
- } else {
- descn = atoi(arg_left);
- on = 1;
- }
-
- d = port_desc(descn);
- if (LEVEL(player) <= 28) {
- notify(player, MSG_HUH);
- return;
- }
- /* make sure teh desc exists and they're connected (no spying on 'em at the connect screen!) */
- if(!d || (d && !IsPlayer(d->player))) {
- notify(player, "There is no one connected on that descriptor.");
- return;
- }
-
- if(on) {
- if((d->player == player)) {
- notify(player, "You can't snoop yourself.");
- return;
- }
-
- switch(set_snoop(player,d)) {
- case -1: /* Too Many */
- notify(player, "Sorry, can't snoop at this time.");
- return;
- case -2: /* Already Snoopin on 'em */
- notify(player, "You can only snoop one person at a time.");
- return;
- default:
- notify_format(player, T("Snoop now set on %s(%d)"), Name(d->player), descn);
- }
- } else {
- for(on = n = 0; n < MAX_SNOOPS; n++)
- if(d->snooper[n] == player) {
- d->snooper[n] = -1;
- on = 1;
- }
- notify(player, on ? "Snoop deactivated." : "Snooping Error.");
- }
- }
-}
-
-
-void feed_snoop(DESC *d, const char *s, char dir) {
- int n;
- char snstr[BUFFER_LEN];
-
-
- if(!d ||!d->connected)
- return;
- memset(snstr, '\0', BUFFER_LEN);
- strncpy(snstr, remove_markup(s, NULL), BUFFER_LEN-1);
- if(*s && !*snstr)
- return;
- for(n = 0; n < MAX_SNOOPS ; n++)
- if(!IsPlayer(d->snooper[n]))
- continue;
- else if(GoodObject(d->snooper[n]) && IsPlayer(d->snooper[n])) {
- if(dir == 1) /* player see's */
- notify_format((dbref) d->snooper[n], T("%s%s<-%s %s"), object_header(d->snooper[n],d->player), ANSI_BLUE,
- ANSI_NORMAL, snstr);
- else /* player types */
- notify_format((dbref) d->snooper[n], T("%s%s->%s %s%s"), object_header(d->snooper[n],d->player),
- ANSI_BLUE, ANSI_RED, snstr, ANSI_NORMAL);
- }
-
-}
-
-char is_snooped(DESC *d) {
- int n;
-
- for(n = 0; n < MAX_SNOOPS; n++)
- if(IsPlayer(d->snooper[n]))
- return 1;
- return 0;
-}
-
-
-char set_snoop(dbref plyr, DESC *d) {
- int n;
- /* take first available spot */
- for( n = 0; n < MAX_SNOOPS ; n++)
- if(d->snooper[n] == -1)
- break;
- else if(d->snooper[n] == plyr)
- return -2; /* they're already snooping */
- if(n == MAX_SNOOPS-1) /* too many snoopers on player */
- return -1;
- d->snooper[n] = plyr;
- return 1;
-}
-
-void clr_snoop(dbref plyr, DESC *d) {
- int n;
-
- for(n = 0; n < MAX_SNOOPS; n++)
- if(d->snooper[n] == plyr)
- d->snooper[n] = -1;
-}
-
-/* switch users */
-COMMAND(cmd_su) {
- DESC *d, *match = NULL;
- dbref target;
- int num = 0, is_hidden;
-
- /* Stage 1. Make sure arg_left exists */
- if(arg_left && *arg_left) {
- if(!strcasecmp(cmd->name, "@SD")) {
- target = match_result(player, arg_left, TYPE_DIVISION, MAT_EVERYTHING);
- if(!GoodObject(target) || Typeof(target) != TYPE_DIVISION) {
- notify(player, "No such division.");
- return;
- }
- /* Check to see if special conditions exist, where they can enter without a password */
- if(controls(player, target) /* condition 1: they control it */
- ) {
- add_to_div_exit_path(player, Division(player));
- Division(player) = target;
- notify_format(player, "You have switched into Division: %s", object_header(player, Division(player)));
- return;
- }
- /* get least idle desc */
- DESC_ITER_CONN(d)
- if ((d->player == player) && (!match || (d->last_time > match->last_time)))
- match = d;
- /* We're only entering using a password at this moment */
- queue_newwrite(match, (unsigned char *) tprintf(T("Password: %c%c"),
- IAC, GOAHEAD), 13);
- match->input_handler = password_handler;
- match->pinfo.object = target;
- match->pinfo.function = &pw_div_connect;
- match->pinfo.lock = 0x40;
- } else {
- target = lookup_player(arg_left);
- if(target == NOTHING) {
- notify(player, "No such player.");
- return;
- }
- do_log(LT_WIZ, player, target, "** @SU ATTEMPT **");
- /* get least idle desc */
- DESC_ITER_CONN(d)
- if ((d->player == player) && (!match || (d->last_time > match->last_time)))
- match = d;
- /* Step 2. Find if we can get in without a pass, if
- * we need a pass. Throw them into password_handler() internal
- * prompt
- */
- if(div_powover(player, target, "@SU")) {
- do_log(LT_WIZ, player, target, "** @SU SUCCESS **");
- /* Phase 3a. Put Guy in user */
- add_to_exit_path(match, player);
- announce_disconnect(player);
- match->player = target;
- match->mailp = find_exact_starting_point(target);
- is_hidden = Can_Hide(target) && Dark(target);
- DESC_ITER_CONN(d)
- if(d->player == player) {
- num++;
- if(is_hidden)
- d->hide = 1;
- }
-
- if(ModTime(target))
- notify_format(target, T("%ld failed connections since last login."), ModTime(target));
- announce_connect(target, 0, num);
- check_last(target, match->addr, match->ip); /* set last, lastsite, give paycheck */
- queue_eol(match);
- if(command_check_byname(target, "@MAIL"))
- check_mail(target, 0, 0);
- set_player_folder(target, 0);
- do_look_around(target);
- if(Haven(target))
- notify(player, T("Your HAVEN flag is set. You cannot receive pages."));
- } else {
- /* Part 3b. Put guy in password program */
- queue_newwrite(match, (unsigned char *) tprintf(T("Password: %c%c"),
- IAC, GOAHEAD), 13);
- match->input_handler = password_handler;
- match->pinfo.object = target;
- match->pinfo.function = &pw_player_connect;
- match->pinfo.lock = 0x40;
- }
- }
- } else {
- if(SW_ISSET(sw, SWITCH_LOGOUT)) {
- /* @sd/logout - check to see if there is any division @sd'ing history.. And backtrack us */
- ATTR *divrcd;
- char tbuf[BUFFER_LEN], *p_buf[BUFFER_LEN / 2], *tbp, sep[2];
- int cnt;
- dbref div_obj;
-
- divrcd = atr_get(player, "XYXX_DIVRCD");
- if(divrcd == NULL) {
- notify(player, "You have not switched into any divisions.");
- return;
- }
-
- cnt = list2arr(p_buf, BUFFER_LEN / 2, safe_atr_value(divrcd), ' ');
- if(cnt < 1) {
- notify(player, "You have not switched into any divisions.");
- return;
- }
-
- /* Set them into cnt-1 if its good */
- div_obj = parse_number(p_buf[cnt-1]);
- if(GoodObject(div_obj) && IsDivision(div_obj)) {
- Division(player) = div_obj;
- notify_format(player, "You haev been went back to your other division: %s", object_header(player, div_obj));
- }
-
- /* now chop off last one, and arr2list() */
- if(cnt == 1) { /* clear the attribute */
- atr_clr(player, "XYXX_DIVRCD", GOD);
- } else {
- memset(tbuf, '\0', BUFFER_LEN);
- tbp = tbuf;
- sep[0] = ' ';
- sep[1] = '\0';
- arr2list(p_buf, cnt-1, tbuf, &tbp, sep);
- /* Add the attribute back */
- (void) atr_add(player, "XYXX_DIVRCD", tbuf, GOD, NOTHING);
- }
- } else {
- notify(player, "Must specify what player you wish to @su into.");
- }
- }
-}
-
-void add_to_exit_path(DESC *d, dbref player) {
- SU_PATH *path_entry;
-
- if(!d)
- return;
-
- path_entry = (SU_PATH *) mush_malloc(sizeof(SU_PATH), "SU_PATH_ENTRY");
-
- path_entry->player = player;
- if(d->su_exit_path)
- path_entry->next = d->su_exit_path;
- else
- path_entry->next = NULL;
- d->su_exit_path = path_entry;
-}
-
-/* If they're logged in.. Log 'em out through their su path */
-static int do_su_exit(DESC *d) {
- DESC *c;
- SU_PATH *path_entry, *mark_path;
- int is_hidden, num = 0;
-
- if(d->su_exit_path) {
- path_entry = d->su_exit_path;
- while(path_entry)
- if(GoodObject(path_entry->player) && IsPlayer(path_entry->player))
- break;
- else { /* Guess the guy got nuked along the way.. free the spot */
- mark_path = path_entry;
- path_entry = path_entry->next;
- mush_free(mark_path, "SU_PATH_ENTRY");
- }
- if(!path_entry)
- return 0;
- d->su_exit_path = path_entry;
- /* Disconnect appearance */
- announce_disconnect(d->player);
- d->player = path_entry->player;
- /* Clear path_entry spot */
- d->su_exit_path = path_entry->next;
- mush_free(path_entry, "SU_PATH_ENTRY");
- d->mailp = find_exact_starting_point(d->player);
- is_hidden = Can_Hide(d->player) && Dark(d->player);
- DESC_ITER_CONN(c)
- if(c->player == d->player) {
- num++;
- if(is_hidden)
- c->hide = 1;
- }
- if(ModTime(d->player))
- notify_format(d->player, T("%ld failed connections since last login."), ModTime(d->player));
- announce_connect(d->player, 0, num);
- check_last(d->player, d->addr, d->ip); /* set last, lastsite, give paycheck */
- queue_eol(d);
- if(command_check_byname(d->player, "@MAIL"))
- check_mail(d->player, 0, 0);
- set_player_folder(d->player, 0);
- do_look_around(d->player);
- if(Haven(d->player))
- notify(d->player, T("Your HAVEN flag is set. You cannot receive pages."));
- return 1;
- } else return 0;
-}
-
-void
-close_ssl_connections(void)
-{
-}
-
-void
-kill_info_slave(void)
-{
-}
-