/* This software is Copyright 1989, 1990, 1992, 1993 by various individuals. Please see the accompanying file COPYRIGHT for details. */ #include #include #include #include #include #include #include #include #include #include #include #include "db.h" #include "defs.h" #include "match.h" #include "ctype.h" #include "params.h" #include "config.h" #include "random.h" #include "strings.h" #include "externs.h" #include "property.h" #include "times-fix.h" #include "interface.h" #include "unused-arg.h" /* declarations */ static char *dumpfile = 0; static int epoch = 0; int alarm_triggered = 0; static int alarm_PANIC = 0; static int dump_warned = 0; int alarm_block = 0; int panicking = 0; /* timing stuff awozniak */ int total_alarm_miss = 0; int total_alarm_done = 0; int alarm_interval = INIT_ALARM_INTERVAL; time_t last_checkpoint; void time_keeper(void); static void fork_and_dump(void); void dump_database(void); void do_dump(dbref player, const char *newfile, UNUSED_ARG(const char *form)) { char buf[BUFFER_LEN]; if (PERMIT_DUMP(player)) { alarm_triggered = 1; if (*newfile && PERMIT_DUMPFILE(player)) { free(dumpfile); dumpfile = dup_string(newfile); sprintf(buf,"Dumping to file %s...",dumpfile); } else { sprintf(buf,"Dumping..."); } notify(player,buf); fork_and_dump(); } else { notify(player,"Sorry, you are in a no dumping zone."); } } void do_shutdown(dbref player) { if (PERMIT_SHUTDOWN(player)) { log_status("SHUTDOWN: by %s",unparse_object(player,player)); shutdown_flag = 1; } else { notify(player,"Your delusions of grandeur have been duly noted."); log_status("ILLEGAL SHUTDOWN: tried by %s",unparse_object(player,player)); } } static void alarm_handler(UNUSED_ARG(int sig)) { alarm_triggered = 1; total_alarm_done++; if(alarm_block) total_alarm_miss++; else time_keeper(); } static void dump_database_internal(void) { char tmpfile[2048]; int fd; FILE *f; #ifdef DB_SIZE_FILE FILE *sf; #else #define sf 0 #endif newcon_warn_set("Checkpointing database"); #if DUMP(HOLDSPACE) sprintf(tmpfile,"%s.#old#",dumpfile); unlink(tmpfile); #endif sprintf(tmpfile,"%s.#%d#",dumpfile,epoch-1); unlink(tmpfile); sprintf(tmpfile,"%s.#%d#",dumpfile,epoch); #ifdef DB_SIZE_FILE sf = fopen(DB_SIZE_FILE,"w"); #endif fd = open(tmpfile,O_WRONLY|O_CREAT|O_TRUNC,0666); if (fd < 0) { fprintf(stderr,"checkpoint: can't open %s: %s\n",tmpfile,strerror(errno)); } else { f = fdopen(fd,"w"); if (! f) { fprintf(stderr,"checkpoint: can't open %s: can't fdopen\n",tmpfile); close(fd); } else { db_write(f,sf); fclose(f); #ifdef DB_SIZE_FILE fclose(sf); #endif #if DUMP(HOLDSPACE) sprintf(tmpfile,"%s.#old#",dumpfile); if (link(dumpfile,tmpfile) < 0) { fprintf(stderr,"checkpoint: warning: can't link %s to %s: %s\n",tmpfile,dumpfile,strerror(errno)); } sprintf(tmpfile,"%s.#%d#",dumpfile,epoch); #endif if (rename(tmpfile,dumpfile) < 0) { fprintf(stderr,"checkpoint: warning: can't rename %s to %s: %s\n",tmpfile,dumpfile,strerror(errno)); } } } #if DUMP(HOLDSPACE) sprintf(tmpfile,"%s.#old#",MACRO_FILE); unlink(tmpfile); #endif sprintf(tmpfile,"%s.#%d#",MACRO_FILE,epoch-1); unlink(tmpfile); sprintf(tmpfile,"%s.#%d#",MACRO_FILE,epoch); fd = open(tmpfile,O_WRONLY|O_CREAT|O_TRUNC,0666); if (fd < 0) { fprintf(stderr,"checkpoint: can't open %s: %s\n",tmpfile,strerror(errno)); } else { f = fdopen(fd,"w"); if (! f) { fprintf(stderr,"checkpoint: can't open %s: can't fdopen\n",tmpfile); close(fd); } else { macrodump(macrotop,f); fclose(f); #if DUMP(HOLDSPACE) sprintf(tmpfile,"%s.#old#",MACRO_FILE); if (link(MACRO_FILE,tmpfile) < 0) { fprintf(stderr,"checkpoint: warning: can't link %s to %s: %s\n",tmpfile,MACRO_FILE,strerror(errno)); } sprintf(tmpfile,"%s.#%d#",MACRO_FILE,epoch); #endif if (rename(tmpfile,MACRO_FILE) < 0) { fprintf(stderr,"checkpoint: warning: can't rename %s to %s: %s\n",tmpfile,MACRO_FILE,strerror(errno)); } } } newcon_warn_set(0); #undef sf } static void takecore(void) __attribute__((__noreturn__)); static void takecore(void) { #ifdef RLIMIT_CORE { struct rlimit rl; getrlimit(RLIMIT_CORE,&rl); rl.rlim_cur = rl.rlim_max; setrlimit(RLIMIT_CORE,&rl); } #endif signal(SIGIOT, SIG_DFL); abort(); /* NOTREACHED */ } void panic(const char *message) { char panicfile[2048]; FILE *f; #ifdef DB_SIZE_FILE FILE *sf; #else #define sf 0 #endif int i; panicking = 1; log_status("PANIC: %s",message); fprintf(stderr,"PANIC: %s\n",message); for (i=0;i= 0) { cmdring_dump(i); close(i); } #endif sprintf(panicfile,"%s.PANIC",dumpfile); f = fopen(panicfile,"w"); if (! f) { perror("CANNOT OPEN PANIC FILE, YOU LOSE"); #ifdef NOCOREDUMP _exit(135); #else /* !NOCOREDUMP */ takecore(); #endif /* NOCOREDUMP */ } else { log_status("DUMPING: %s",panicfile); fprintf(stderr,"DUMPING: %s\n",panicfile); #ifdef DB_SIZE_FILE sf = fopen(DB_SIZE_FILE,"w"); #endif db_write(f,sf); fclose(f); #ifdef DB_SIZE_FILE fclose(sf); #endif log_status("DUMPING: %s (done)",panicfile); fprintf(stderr,"DUMPING: %s (done)\n",panicfile); #ifdef NOCOREDUMP _exit(136); #else /* !NOCOREDUMP */ takecore(); #endif /* NOCOREDUMP */ } #undef sf } void dump_database() { epoch++; log_status("DUMPING: %s.#%d#", dumpfile, epoch); dump_database_internal(); log_status("DUMPING: %s.#%d# (done)", dumpfile, epoch); } static void tell_all_online(const char *msg) { struct descriptor_data *d; for (d=descriptor_list;d;d=d->flink) { if (d->connected) { queue_string(d,msg); queue_write(d,"\r\n",2); process_output(d); /* ignore return value */ } } } void time_keeper() { static int last_dump = 0; static int last_daem = 0; static int last_setup = 0; static int current_time = 0; int current_water; if (!last_setup) { last_setup = 1; last_dump = curtm(); last_daem = curtm(); do_autostart_exits(); if (last_dump < 0) tell_all_online(""); /* shut up -Wunused */ } /* block alarms again! */ alarm_block = 1; current_time = curtm(); #if defined(DUMP_WARNING_MSG) && defined(DUMP_WARNING_INTERVAL) && defined(DUMP_INTERVAL) && (DUMP_INTERVAL > 0) && (DUMP_WARNING_INTERVAL > 0) && (DUMP_WARNING_INTERVAL < DUMP_INTERVAL) if ( (current_time-last_dump > DUMP_INTERVAL-DUMP_WARNING_INTERVAL) && !dump_warned ) { tell_all_online(DUMP_WARNING_MSG); dump_warned = 1; } #endif if ( (alarm_PANIC == 1) #if defined(DUMP_INTERVAL) && (DUMP_INTERVAL > 0) || ((current_time-last_dump) > DUMP_INTERVAL) #endif ) { fork_and_dump(); alarm_PANIC = 0; dump_warned = 0; last_dump = curtm(); } if ((current_time - last_daem) > DAEMON_INTERVAL) { launch_daemons(); last_daem = curtm(); } /* ok, check our timing. If miss/total exceeds high water, then we * need slow things down. if it's less than low water, we can speed * it up. In NO case should we exceed 1 alarm/sec */ if (total_alarm_done >= CHECK_RATE) /* reset checkers */ { current_water = total_alarm_miss * 100 / total_alarm_done; if ( (current_water >= HIGH_WATER) #if defined(DUMP_INTERVAL) && (DUMP_INTERVAL > 0) && (alarm_interval < DUMP_INTERVAL) #endif ) /* slow down! */ alarm_interval++; else if (current_water <= LOW_WATER && alarm_interval > 1) /* ok to speed up */ alarm_interval--; total_alarm_miss = 0; total_alarm_done = 0; } /* unblock alarms... */ alarm_block = 0; /* in the parent */ /* reset alarm */ alarm_triggered = 0; set_alarm(alarm_interval); } static void fork_and_dump() { #if DUMP(CHANGE_PID) || !DUMP(INLINE) int child; #endif #if !DUMP(INLINE) dbref i; char buf[BUFFER_LEN]; #endif #if DUMP(CHANGE_PID) child = fork(); if (child < 0) { perror("fork_and_dump: fork()"); } else if (child > 0) { exit(0); } createpidfile(); #endif last_checkpoint = curtm(); epoch ++; log_status("CHECKPOINTING: %s.#%d#",dumpfile,epoch); #ifdef DUMP_BEGIN_MSG tell_all_online(DUMP_BEGIN_MSG); #endif #if DUMP(INLINE) dump_database_internal(); #ifdef DUMP_END_MSG tell_all_online(DUMP_END_MSG); #endif #else /* if DUMP(INLINE) */ #if DUMP(VFORK) && !DUMP(IN_PARENT) child = vfork(); #else /* DUMP(VFORK) && !DUMP(IN_PARENT) */ child = fork(); #if DUMP(DOUBLE_FORK) if (child == 0) { child = fork(); if (child != 0) exit(0); } #endif /* DUMP(DOUBLE_FORK) */ #endif /* DUMP(VFORK) && !DUMP(IN_PARENT) */ if #if DUMP(IN_PARENT) (child > 0) #else /* DUMP(IN_PARENT) */ (child == 0) #endif /* DUMP(IN_PARENT) */ { /* the process that does the dump */ close(0); /* get that file descriptor back */ dump_database_internal(); _exit(0); /* !!! */ } else if (child < 0) { perror("fork_and_dump: fork()"); } else { sprintf(buf,"Server> Checkpointing database at %.24s",ctime(&last_checkpoint)); for (i=0;i 0) ; #ifdef AIX370 /* RESET the signal handler for AIX370 */ /* This may not be the best place to put this. */ signal(SIGCHLD,reaper); /* test modification by WOZ Jul 3 18:48 PDT 1991 */ #endif } int init_game(const char *infile, const char *outfile, int liststrings) { FILE *f; if (! liststrings) { f = fopen(MACRO_FILE,"r"); if (! f) { log_status("INIT: Macro storage file %s is damaged.",MACRO_FILE); } else { macroload(f); fclose(f); } } f = fopen(infile,"r"); if (! f) return(-1); /* ok, read it in */ if (! liststrings) { log_status("LOADING: %s",infile); fprintf(stderr,"LOADING: %s\n",infile); } if (db_read(f,liststrings) < 0) return(-1); if (liststrings) return(0); log_status("LOADING: %s (done)",infile); fprintf(stderr,"LOADING: %s (done)\n",infile); /* everything ok */ fclose(f); /* seed random number generator */ { unsigned long int seeds[3]; seeds[0] = getpid(); seeds[1] = curtm(); seeds[2] = gethostid(); seed_random(&seeds[0],sizeof(seeds)); } /* set up dumper */ free(dumpfile); dumpfile = dup_string(outfile); set_alarm_handler(alarm_handler); signal(SIGHUP,alarm_handler); signal(SIGCHLD,reaper); alarm_triggered = 0; set_alarm(alarm_interval); return(0); } typedef struct regfree REGFREE; struct regfree { REGFREE *link; void **vp; } ; static REGFREE *reglist = 0; void register_free(void **vp) { REGFREE *r; r = malloc(sizeof(REGFREE)); r->vp = vp; r->link = reglist; reglist = r; } static void free_registered(void) { REGFREE *r; while (reglist) { r = reglist; reglist = r->link; free(*r->vp); free(r); } } void free_game(void) { db_free(); prop_done(); free_drl_blocks(); close_str(); free_macros(); free(dumpfile); free_registered(); } static void do_move_time(dbref player, char *arg1, char *arg2) { struct tms ti; double start; double finish; double difference; SERIAL playser; char buf[BUFSIZ]; #ifdef NeXT extern void times(struct tms *); #endif playser = DBFETCH(player)->serial; times(&ti); start = ti.tms_utime + ti.tms_cutime; if (strlen(arg2)) { sprintf(buf,"%s = %s",arg1,arg2); process_command(player,buf); } else { process_command(player,arg1); } if (DBFETCH(player)->serial != playser) return; times(&ti); finish = ti.tms_utime + ti.tms_cutime; difference = (finish - start) / CLK_TCK; sprintf(buf,"That command took %f second%s.",difference,(difference==1)?"":"s"); notify(player,buf); } static int taptimevalid = 0; static const char *taptime(int longform) { static char tt_buf[64]; static char *tt_short; if (! taptimevalid) { struct timeval tv; time_t tt; struct tm *tm; gettimeofday(&tv,(struct timezone *)0); tt = tv.tv_sec; tm = localtime(&tt); strftime(&tt_buf[0],sizeof(tt_buf),"%b %d ",tm); tt_short = &tt_buf[strlen(&tt_buf[0])]; strftime(tt_short,sizeof(tt_buf)-(tt_short-&tt_buf[0]),"%H:%M:%S",tm); sprintf(tt_short+strlen(tt_short),".%03d",(int)(tv.tv_usec/1000)); taptimevalid = 1; } return(longform?&tt_buf[0]:tt_short); } static void maybetap( dbref dbr, dbref who, char *cmd, void (*fxn)(void *, char *), void *arg) { const char *p; struct propref *pr; char *prop; int bits; #define BIT_I 0x00000001 int n; int defprint; int printit; char buf[BUFFER_LEN]; if (! (FLAGS(dbr) & TAP)) return; pr = lookup_property(dbr,".t_filter",0); if (pr && ((propref_get_attr(pr) & PATTR_TYPE) == PTYPE_STRING)) { prop = propref_get_string(pr); } else { prop = 0; } if (prop) { if (*prop) { defprint = 0; p = prop; if (*p == '!') { defprint = 1; p ++; } printit = defprint; while (1) { while (*p && !Cisdigit(*p)) p ++; if (! *p) break; n = 0; bits = 0; while (*p && Cisdigit(*p)) n = (10 * n) + (*p++ - '0'); while (*p && !Cisspace(*p)) { switch (*p++) { case 'i': case 'I': bits |= BIT_I; break; } } /* XXX do something with bits & BIT_I? */ if (n == (int)who) { printit = !defprint; break; } } } else { printit = (who != dbr); } if (printit) { sprintf(&buf[0],"%s(%d/%s):%s%s", NAME(who), (int)DBFETCH(who)->location, taptime(Typeof(dbr)==TYPE_ROOM), (FLAGS(who)&INTERACTIVE) ? "[i] " : " ", cmd ); (*fxn)(arg,&buf[0]); } free(prop); } if (pr) propref_done(pr); #undef BIT_I } static void tap_to_player(void *dvp, char *line) { queue_string((struct descriptor_data *)dvp,line); queue_write((struct descriptor_data *)dvp,"\r\n",2); } static void tap_to_log(UNUSED_ARG(void *ignore), char *line) { log_command("%s\n",line); } /* use this only in do_builtin_command */ #define Matched(string) { if(!string_prefix((string), command)) return(0); } int do_builtin_command(dbref player, const char *command, char *args) { char *arg1; char *arg2; char *p; char *full_args; char xbuf[BUFSIZ]; arg1 = args; /* move over spaces */ while (*arg1 && Cisspace(*arg1)) arg1 ++; /* save full argument string for (eg) @wall */ snprintf(&xbuf[0],sizeof(xbuf),"%s",arg1); full_args = &xbuf[0]; /* find end of arg1, start of arg2 */ for (arg2=arg1;*arg2&&(*arg2!=ARG_DELIMITER);arg2++) ; /* truncate arg1 */ for (p=arg2-1;(p>=arg1)&&Cisspace(*p);p--) *p = '\0'; /* go past delimiter if present */ if (*arg2) *arg2++ = '\0'; while (*arg2 && Cisspace(*arg2)) arg2 ++; switch (command[0]) { case '@': switch (command[1]) { case '@': if (! TrueWizard(player)) return(0); do_debug(player,command+2,arg1,arg2); break; case 'a': case 'A': switch (command[2]) { case 'c': case 'C': Matched("@action"); do_action(player,arg1,arg2); break; case 't': case 'T': Matched("@attach"); do_attach(player,arg1,arg2); break; default: return(0); break; } break; case 'b': case 'B': switch (command[2]) { case 'a': case 'A': Matched("@backprops"); do_backprops(player,arg1); break; case 'o': case 'O': Matched("@boot"); do_boot(player,arg1); break; } break; case 'c': case 'C': switch (command[2]) { case 'h': case 'H': Matched("@chown"); do_chown(player,arg1,arg2); break; case 'r': case 'R': Matched("@create"); do_create(player,arg1,atoi(arg2)); break; case 'o': case 'O': switch (command[3]) { case 'n': case 'N': switch (command[4]) { case 't': case 'T': Matched("@contents"); do_contents(player,arg1,arg2); break; case 'f': case 'F': Matched("@config"); do_config(player); break; default: return(0); break; } break; default: return(0); break; } break; default: return(0); break; } break; case 'd': case 'D': switch (command[2]) { case 'b': case 'B': if (string_compare(command,"@dbck")) return(0); do_dbck(player,arg1); break; case 'e': case 'E': Matched("@describe"); do_describe(player,arg1,arg2); break; case 'i': case 'I': Matched("@dig"); do_dig(player,arg1,arg2); break; case 'r': case 'R': Matched("@drop"); do_drop_message(player,arg1,arg2); break; case 'u': case 'U': Matched("@dump"); do_dump(player,arg1,arg2); break; default: return(0); break; } break; case 'e': case 'E': switch (command[2]) { case 'd': case 'D': Matched("@edit"); do_edit(player,arg1); break; case 'x': case 'X': switch (command[3]) { case 'i': case 'I': Matched("@exits"); do_exits(player,arg1,arg2); break; case 'a': case 'A': Matched("@examine"); do_at_examine(player,arg1,arg2); break; default: return(0); break; } break; default: return(0); break; } break; case 'f': case 'F': switch (command[2]) { case 'a': case 'A': Matched("@fail"); do_fail(player,arg1,arg2); break; case 'i': case 'I': Matched("@find"); do_find(player,arg1); break; case 'o': case 'O': Matched("@force"); do_force(player,arg1,arg2); break; default: return(0); break; } break; case 'g': case 'G': Matched("@go"); do_daemon_go(player,arg1); break; case 'k': case 'K': Matched("@kill"); do_daemon_kill(player,arg1); break; case 'l': case 'L': switch (command[2]) { case 'i': case 'I': switch (command[3]) { case 'n': case 'N': Matched("@link"); do_link(player,arg1,arg2); break; case 's': case 'S': Matched("@list"); match_and_list(player,arg1,arg2); break; default: return(0); break; } break; case 'o': case 'O': Matched("@lock"); do_lock(player,arg1,arg2); break; default: return(0); break; } break; case 'm': case 'M': switch (command[2]) { case 'e': case 'E': Matched("@memused"); do_memused(player,arg1); break; case 'f': case 'F': Matched("@mfilesweep"); do_mfilesweep(player); break; default: return(0); break; } break; case 'n': case 'N': switch (command[2]) { case 'a': case 'A': Matched("@name"); do_name(player,arg1,arg2); break; case 'e': case 'E': switch (command[3]) { case 'w': case 'W': switch (command[4]) { case 'p': case 'P': switch (command[5]) { case 'a': case 'A': if (string_compare(command,"@newpassword")) return(0); do_newpassword(player,arg1,arg2); break; case 'w': case 'W': if (string_compare(command,"@newpwhash")) return(0); do_newpwhash(player,arg1,arg2); break; default: return(0); break; } break; default: return(0); break; } break; default: return(0); break; } break; #if 0 case 'p': case 'P': Matched("@nproperties"); do_nproperties(player,arg1,arg2); break; #endif case 's': case 'S': Matched("@nset"); do_nset(player,arg1,arg2); break; default: return(0); break; } break; case 'o': case 'O': switch (command[2]) { case 'd': case 'D': Matched("@odrop"); do_odrop(player,arg1,arg2); break; case 'f': case 'F': Matched("@ofail"); do_ofail(player,arg1,arg2); break; case 'p': case 'P': Matched("@open"); do_open(player,arg1,arg2); break; case 's': case 'S': Matched("@osuccess"); do_osuccess(player,arg1,arg2); break; case 'w': case 'W': Matched("@owned"); do_owned(player,arg1,arg2); break; default: return(0); break; } break; case 'p': case 'P': switch (command[2]) { case 'a': case 'A': Matched("@password"); do_password(player,arg1,arg2); break; #ifdef REGISTRATION case 'c': case 'C': Matched("@pcreate"); do_pcreate(player,arg1,arg2); break; #endif case 'r': case 'R': switch (command[3]) { case 'o': case 'O': switch (command[4]) { case 'p': case 'P': Matched("@properties"); do_properties(player,arg1,arg2); break; case 'g': case 'G': Matched("@prog"); do_prog(player,arg1); break; default: return(0); break; } break; default: return(0); break; } break; case 's': case 'S': Matched("@ps"); do_daemon_ps(player,arg1); break; default: return(0); break; } break; case 'r': case 'R': Matched("@recycle"); do_recycle(player,arg1); break; case 's': case 'S': switch (command[2]) { case 'e': case 'E': Matched("@set"); do_set(player,arg1,arg2); break; case 'h': case 'H': if (string_compare(command,"@shutdown")) return(0); do_shutdown(player); break; case 'o': case 'O': Matched("@sortprops"); do_sortprops(player); break; case 't': case 'T': Matched("@stats"); do_stats(player,arg1); break; case 'u': case 'U': Matched("@success"); do_success(player,arg1,arg2); break; default: return(0); break; } break; case 't': case 'T': switch (command[2]) { case 'e': case 'E': Matched("@teleport"); do_teleport(player,arg1,arg2); break; case 'i': case 'I': Matched("@time"); do_move_time(player,arg1,arg2); break; case 'o': case 'O': if (string_compare(command,"@toad")) return(0); do_toad(player,arg1,arg2); break; case 'r': case 'R': Matched("@trace"); do_trace(player,arg1,atoi(arg2)); break; default: return(0); break; } break; case 'u': case 'U': switch (command[2]) { case 'n': case 'N': switch (command[3]) { case 'l': case 'L': switch (command[4]) { case 'i': case 'I': Matched("@unlink"); do_unlink(player,arg1); break; case 'o': case 'O': Matched("@unlock"); do_unlock(player,arg1); break; default: return(0); break; } break; case 's': case 'S': if (string_compare(command,"@unsetall")) return(0); do_unsetall(player,arg1); break; default: return(0); break; } break; case 's': case 'S': Matched("@user"); do_player_setuid(player,arg1,arg2); break; default: return(0); break; } break; case 'w': case 'W': switch (command[2]) { case 'a': case 'A': Matched("@wall"); do_wall(player,full_args); break; case 'h': case 'H': Matched("@who"); dump_descriptors(player,arg1); break; default: return(0); break; } break; default: return(0); } break; case 'd': case 'D': Matched("drop"); do_drop(player,arg1); break; case 'e': case 'E': Matched("examine"); do_examine(player,arg1,arg2); break; case 'g': case 'G': switch (command[1]) { case 'e': case 'E': Matched("get"); do_get(player,arg1); break; case 'i': case 'I': Matched("give"); do_give(player,arg1,atoi(arg2)); break; case 'o': case 'O': Matched("goto"); do_move(player,arg1); break; case 'r': case 'R': Matched("gripe"); do_gripe(player,full_args); break; default: return(0); break; } break; case 'h': case 'H': Matched("help"); do_help(player,arg1,"help",HELP_INDEX,HELP_FILE); break; case 'i': case 'I': Matched("inventory"); do_inventory(player); break; case 'k': case 'K': Matched("kill"); do_kill(player,arg1,atoi(arg2)); break; case 'l': case 'L': Matched("look"); do_look_at(player,arg1); break; case 'm': case 'M': switch (command[1]) { case 'o': case 'O': Matched("move"); do_move(player,arg1); break; case 'a': case 'A': Matched("man"); do_help(player,arg1,"man",MAN_INDEX,MAN_FILE); break; default: return(0); break; } break; case 'n': case 'N': if (string_compare(command,"news")) return(0); do_help(player,arg1,"news",NEWS_INDEX,NEWS_FILE); break; case 'p': case 'P': switch (command[1]) { case 'a': case 'A': Matched("page"); do_page(player,arg1,arg2); break; case 'o': case 'O': Matched("pose"); do_pose(player,full_args); break; case 'u': case 'U': Matched("put"); do_drop(player,arg1); break; default: return(0); break; } break; case 'r': case 'R': switch (command[1]) { case 'e': case 'E': Matched("read"); do_look_at(player,arg1); break; case 'o': case 'O': Matched("rob"); do_rob(player,arg1); break; default: return(0); break; } break; case 's': case 'S': switch (command[1]) { case 'a': case 'A': Matched("say"); do_say(player,full_args); break; case 'c': case 'C': Matched("score"); do_score(player); break; default: return(0); break; } break; case 't': case 'T': switch (command[1]) { case 'a': case 'A': Matched("take"); do_get(player,arg1); break; case 'h': case 'H': Matched("throw"); do_drop(player,arg1); break; default: return(0); break; } break; case 'w': case 'W': #ifdef BUILTIN_WHO switch (command[1]) { case 'h': case 'H': switch (command[2]) { case 'i': case 'I': Matched("whisper"); do_whisper(player,arg1,arg2); break; case 'o': case 'O': Matched("who"); do_who(player,arg1,arg2); break; default: return(0); break; } break; default: return(0); break; } #else Matched("whisper"); do_whisper(player,arg1,arg2); #endif break; default: return(0); break; } return(1); } #undef Matched void process_command(dbref player, char *command) { char *arg1; struct propref *pr; struct descriptor_data *d; int cantap; if (!command) abort(); /* robustify player */ if ((player < 0) || (player >= db_top) || (Typeof(player) != TYPE_PLAYER)) { log_status("process_command: bad player %d",player); return; } pr = lookup_property(GLOBAL_ENVIRONMENT,"@no-tap",0); cantap = !pr; if (pr) propref_done(pr); taptimevalid = 0; if (cantap) { maybetap(GLOBAL_ENVIRONMENT,player,command,tap_to_log,0); for (d=descriptor_list;d;d=d->flink) { if (d->connected) { maybetap(d->player,player,command,tap_to_player,d); } } } if (FLAGS(player) & INTERACTIVE) { interactive(player,command); return; } while (*command && Cisspace(*command)) command ++; if (can_move(player,command) && ((*command != '!') || !TrueRoyalty(player))) { /* command is an exact match for an exit */ /* if (*command == '!') command++; */ do_move(player,command); } else { if (*command == '!') command ++; /* find arg1 -- move over command word */ for (arg1=command;*arg1&&!Cisspace(*arg1);arg1++) ; /* truncate command */ if (*arg1) *arg1++ = '\0'; if (! do_builtin_command(player,command,arg1)) { char huhmsg[256]; if (strlen(command) > 64) { sprintf(&huhmsg[0],"\"%.50s...\" unrecognized - type \"help\" for help.",command); } else { sprintf(&huhmsg[0],"\"%s\" unrecognized - type \"help\" for help.",command); } notify(player,&huhmsg[0]); #ifdef LOG_FAILED_COMMANDS if (! controls(player,DBFETCH(player)->location)) { log_status("HUH from %s(%d) in %s(%d)[%s]: %s %s", NAME(player), (int)player, NAME(DBFETCH(player)->location), (int)DBFETCH(player)->location, NAME(OWNER(DBFETCH(player)->location)), command, full_args); } #endif /* LOG_FAILED_COMMANDS */ } } }