mux/src/conf.cpp

Go to the documentation of this file.
00001 // conf.cpp -- Set up configuration information and static data.
00002 //
00003 // $Id: conf.cpp,v 1.71 2006/05/18 18:43:44 sdennis Exp $
00004 //
00005 
00006 #include "copyright.h"
00007 #include "autoconf.h"
00008 #include "config.h"
00009 #include "externs.h"
00010 
00011 #include "attrs.h"
00012 #include "command.h"
00013 #include "interface.h"
00014 
00015 // ---------------------------------------------------------------------------
00016 // CONFPARM: Data used to find fields in CONFDATA.
00017 //
00018 typedef struct confparm
00019 {
00020     char *pname;            // parm name
00021     int (*interpreter)(int *vp, char *str, void *pExtra, UINT32 nExtra,
00022                        dbref player, char *cmd); // routine to interp parameter
00023     int flags;              // control flags
00024     int rperms;             // read permissino flags.
00025     int *loc;               // where to store value
00026     void *pExtra;           // extra pointer for interpreter
00027     UINT32 nExtra;          // extra data for interpreter
00028 } CONF;
00029 
00030 // ---------------------------------------------------------------------------
00031 // External symbols.
00032 //
00033 CONFDATA mudconf;
00034 STATEDATA mudstate;
00035 
00036 // ---------------------------------------------------------------------------
00037 // cf_init: Initialize mudconf to default values.
00038 //
00039 void cf_init(void)
00040 {
00041     int i;
00042 
00043     mudconf.indb = StringClone("netmux.db");
00044     mudconf.outdb = StringClone("");
00045     mudconf.crashdb = StringClone("");
00046     mudconf.game_dir = StringClone("");
00047     mudconf.game_pag = StringClone("");
00048     mudconf.mail_db   = StringClone("mail.db");
00049     mudconf.comsys_db = StringClone("comsys.db");
00050 
00051     mudconf.compress_db = false;
00052     mudconf.compress = StringClone("gzip");
00053     mudconf.uncompress = StringClone("gzip -d");
00054     mudconf.status_file = StringClone("shutdown.status");
00055     mudconf.max_cache_size = 1*1024*1024;
00056 
00057     mudconf.ports.n = 1;
00058     mudconf.ports.pi = (int *)MEMALLOC(sizeof(int));
00059     ISOUTOFMEMORY(mudconf.ports.pi);
00060     mudconf.ports.pi[0] = 2860;
00061 
00062     mudconf.init_size = 1000;
00063     mudconf.guest_char = -1;
00064     mudconf.guest_nuker = GOD;
00065     mudconf.number_guests = 30;
00066     mudconf.min_guests = 1;
00067     strcpy(mudconf.guest_prefix, "Guest");
00068     mudconf.guest_file     = StringClone("text/guest.txt");
00069     mudconf.conn_file      = StringClone("text/connect.txt");
00070     mudconf.creg_file      = StringClone("text/register.txt");
00071     mudconf.regf_file      = StringClone("text/create_reg.txt");
00072     mudconf.motd_file      = StringClone("text/motd.txt");
00073     mudconf.wizmotd_file   = StringClone("text/wizmotd.txt");
00074     mudconf.quit_file      = StringClone("text/quit.txt");
00075     mudconf.down_file      = StringClone("text/down.txt");
00076     mudconf.full_file      = StringClone("text/full.txt");
00077     mudconf.site_file      = StringClone("text/badsite.txt");
00078     mudconf.crea_file      = StringClone("text/newuser.txt");
00079     mudconf.motd_msg[0] = '\0';
00080     mudconf.wizmotd_msg[0] = '\0';
00081     mudconf.downmotd_msg[0] = '\0';
00082     mudconf.fullmotd_msg[0] = '\0';
00083     mudconf.dump_msg[0] = '\0';
00084     mudconf.postdump_msg[0] = '\0';
00085     mudconf.fixed_home_msg[0] = '\0';
00086     mudconf.fixed_tel_msg[0] = '\0';
00087     strcpy(mudconf.public_channel, "Public");
00088     strcpy(mudconf.public_channel_alias, "pub");
00089     strcpy(mudconf.guests_channel, "Guests");
00090     strcpy(mudconf.guests_channel_alias, "g");
00091     strcpy(mudconf.pueblo_msg, "</xch_mudtext><img xch_mode=html>");
00092     mudconf.art_rules = NULL;
00093     mudconf.indent_desc = false;
00094     mudconf.name_spaces = true;
00095 #ifndef WIN32
00096     mudconf.fork_dump = true;
00097     mudstate.dumping  = false;
00098     mudstate.dumper   = 0;
00099     mudstate.dumped   = 0;
00100     mudstate.write_protect = false;
00101 #endif
00102     mudconf.restrict_home = false;
00103     mudconf.have_comsys = true;
00104     mudconf.have_mailer = true;
00105     mudconf.have_zones = true;
00106     mudconf.paranoid_alloc = false;
00107     mudconf.sig_action = SA_DFLT;
00108     mudconf.max_players = -1;
00109     mudconf.dump_interval = 3600;
00110     mudconf.check_interval = 600;
00111     mudconf.events_daily_hour = 7;
00112     mudconf.dump_offset = 0;
00113     mudconf.check_offset = 300;
00114     mudconf.idle_timeout = 3600;
00115     mudconf.conn_timeout = 120;
00116     mudconf.idle_interval = 60;
00117     mudconf.retry_limit = 3;
00118     mudconf.output_limit = 16384;
00119     mudconf.paycheck = 0;
00120     mudconf.paystart = 0;
00121     mudconf.paylimit = 10000;
00122 #ifdef REALITY_LVLS
00123     mudconf.no_levels = 0;
00124     mudconf.def_room_rx = 1;
00125     mudconf.def_room_tx = ~(RLEVEL)0;
00126     mudconf.def_player_rx = 1;
00127     mudconf.def_player_tx = 1;
00128     mudconf.def_exit_rx = 1;
00129     mudconf.def_exit_tx = 1;
00130     mudconf.def_thing_rx = 1;
00131     mudconf.def_thing_tx = 1;
00132 #endif /* REALITY_LVLS */
00133     mudconf.start_quota = 20;
00134     mudconf.site_chars = 25;
00135     mudconf.payfind = 0;
00136     mudconf.digcost = 10;
00137     mudconf.linkcost = 1;
00138     mudconf.opencost = 1;
00139     mudconf.createmin = 10;
00140     mudconf.createmax = 505;
00141     mudconf.killmin = 10;
00142     mudconf.killmax = 100;
00143     mudconf.killguarantee = 100;
00144     mudconf.robotcost = 1000;
00145     mudconf.pagecost = 10;
00146     mudconf.searchcost = 100;
00147     mudconf.waitcost = 10;
00148     mudconf.machinecost = 64;
00149     mudconf.exit_quota = 1;
00150     mudconf.player_quota = 1;
00151     mudconf.room_quota = 1;
00152     mudconf.thing_quota = 1;
00153     mudconf.mail_expiration = 14;
00154     mudconf.queuemax = 100;
00155     mudconf.queue_chunk = 10;
00156     mudconf.active_q_chunk  = 10;
00157     mudconf.sacfactor       = 5;
00158     mudconf.sacadjust       = -1;
00159     mudconf.trace_limit     = 200;
00160 
00161     mudconf.autozone        = true;
00162     mudconf.use_hostname    = true;
00163     mudconf.clone_copy_cost = false;
00164     mudconf.dark_sleepers   = true;
00165     mudconf.ex_flags        = true;
00166     mudconf.exam_public     = true;
00167     mudconf.fascist_tport   = false;
00168     mudconf.idle_wiz_dark   = false;
00169     mudconf.match_mine      = true;
00170     mudconf.match_mine_pl   = true;
00171     mudconf.pemit_players   = false;
00172     mudconf.pemit_any       = false;
00173     mudconf.player_listen   = false;
00174     mudconf.pub_flags       = true;
00175     mudconf.quiet_look      = true;
00176     mudconf.quiet_whisper   = true;
00177     mudconf.quotas          = false;
00178     mudconf.read_rem_desc   = false;
00179     mudconf.read_rem_name   = false;
00180     mudconf.reset_players   = false;
00181     mudconf.robot_speak     = true;
00182     mudconf.safe_unowned    = false;
00183     mudconf.safer_passwords = false;
00184     mudconf.see_own_dark    = true;
00185     mudconf.sweep_dark      = false;
00186     mudconf.switch_df_all   = true;
00187     mudconf.terse_contents  = true;
00188     mudconf.terse_exits     = true;
00189     mudconf.terse_look      = true;
00190     mudconf.terse_movemsg   = true;
00191     mudconf.trace_topdown   = true;
00192     mudconf.use_http        = false;
00193 
00194     // -- ??? Running SC on a non-SC DB may cause problems.
00195     //
00196     mudconf.space_compress = true;
00197     mudconf.allow_guest_from_registered_site = true;
00198     mudconf.start_room = 0;
00199     mudconf.start_home = NOTHING;
00200     mudconf.default_home = NOTHING;
00201     mudconf.master_room = NOTHING;
00202 
00203     for (i = FLAG_WORD1; i <= FLAG_WORD3; i++)
00204     {
00205         mudconf.player_flags.word[i] = 0;
00206         mudconf.room_flags.word[i] = 0;
00207         mudconf.exit_flags.word[i] = 0;
00208         mudconf.thing_flags.word[i] = 0;
00209         mudconf.robot_flags.word[i] = 0;
00210     }
00211     mudconf.robot_flags.word[FLAG_WORD1] |= ROBOT;
00212 
00213     mudconf.vattr_flags = AF_ODARK;
00214     strcpy(mudconf.mud_name, "MUX");
00215     strcpy(mudconf.one_coin, "penny");
00216     strcpy(mudconf.many_coins, "pennies");
00217     mudconf.timeslice.SetSeconds(1);
00218     mudconf.cmd_quota_max = 100;
00219     mudconf.cmd_quota_incr = 1;
00220     mudconf.rpt_cmdsecs.SetSeconds(120);
00221     mudconf.max_cmdsecs.SetSeconds(60);
00222     mudconf.cache_tick_period.SetSeconds(30);
00223     mudconf.control_flags = 0xffffffff; // Everything for now...
00224     mudconf.log_options = LOG_ALWAYS | LOG_BUGS | LOG_SECURITY |
00225         LOG_NET | LOG_LOGIN | LOG_DBSAVES | LOG_CONFIGMODS |
00226         LOG_SHOUTS | LOG_STARTUP | LOG_WIZARD | LOG_SUSPECTCMDS |
00227         LOG_PROBLEMS | LOG_PCREATES | LOG_TIMEUSE;
00228     mudconf.log_info = LOGOPT_TIMESTAMP | LOGOPT_LOC;
00229     mudconf.markdata[0] = 0x01;
00230     mudconf.markdata[1] = 0x02;
00231     mudconf.markdata[2] = 0x04;
00232     mudconf.markdata[3] = 0x08;
00233     mudconf.markdata[4] = 0x10;
00234     mudconf.markdata[5] = 0x20;
00235     mudconf.markdata[6] = 0x40;
00236     mudconf.markdata[7] = 0x80;
00237     mudconf.func_nest_lim = 50;
00238     mudconf.func_invk_lim = 2500;
00239     mudconf.wild_invk_lim = 100000;
00240     mudconf.ntfy_nest_lim = 20;
00241     mudconf.lock_nest_lim = 20;
00242     mudconf.parent_nest_lim = 10;
00243     mudconf.zone_nest_lim = 20;
00244     mudconf.stack_limit = 50;
00245     mudconf.cache_names = true;
00246     mudconf.toad_recipient = -1;
00247     mudconf.eval_comtitle = true;
00248     mudconf.run_startup = true;
00249     mudconf.safe_wipe = false;
00250     mudconf.destroy_going_now = false;
00251     mudconf.nStackLimit = 10000;
00252     mudconf.hook_obj = NOTHING;
00253     mudconf.global_error_obj = NOTHING;
00254     mudconf.cache_pages = 40;
00255     mudconf.mail_per_hour = 50;
00256     mudconf.vattr_per_hour = 5000;
00257     mudconf.pcreate_per_hour = 100;
00258 
00259     mudstate.events_flag = 0;
00260     mudstate.bReadingConfiguration = false;
00261     mudstate.bCanRestart = false;
00262     mudstate.panicking = false;
00263     mudstate.logging = 0;
00264     mudstate.epoch = 0;
00265     mudstate.generation = 0;
00266     mudstate.curr_executor = NOTHING;
00267     mudstate.curr_enactor = NOTHING;
00268     mudstate.shutdown_flag  = false;
00269     mudstate.attr_next = A_USER_START;
00270     mudstate.debug_cmd = "< init >";
00271     mudstate.curr_cmd  = "< none >";
00272     strcpy(mudstate.doing_hdr, "Doing");
00273     mudstate.access_list = NULL;
00274     mudstate.suspect_list = NULL;
00275     mudstate.badname_head = NULL;
00276     mudstate.mstat_ixrss[0] = 0;
00277     mudstate.mstat_ixrss[1] = 0;
00278     mudstate.mstat_idrss[0] = 0;
00279     mudstate.mstat_idrss[1] = 0;
00280     mudstate.mstat_isrss[0] = 0;
00281     mudstate.mstat_isrss[1] = 0;
00282     mudstate.mstat_secs[0] = 0;
00283     mudstate.mstat_secs[1] = 0;
00284     mudstate.mstat_curr = 0;
00285     mudstate.iter_alist.data = NULL;
00286     mudstate.iter_alist.len = 0;
00287     mudstate.iter_alist.next = NULL;
00288     mudstate.mod_alist = NULL;
00289     mudstate.mod_alist_len = 0;
00290     mudstate.mod_size = 0;
00291     mudstate.mod_al_id = NOTHING;
00292     mudstate.olist = NULL;
00293     mudstate.min_size = 0;
00294     mudstate.db_top = 0;
00295     mudstate.db_size = 0;
00296     mudstate.mail_db_top = 0;
00297     mudstate.mail_db_size = 0;
00298     mudstate.freelist = NOTHING;
00299     mudstate.markbits = NULL;
00300     mudstate.func_nest_lev = 0;
00301     mudstate.func_invk_ctr = 0;
00302     mudstate.wild_invk_ctr = 0;
00303     mudstate.ntfy_nest_lev = 0;
00304     mudstate.train_nest_lev = 0;
00305     mudstate.lock_nest_lev = 0;
00306     mudstate.zone_nest_num = 0;
00307     mudstate.pipe_nest_lev = 0;
00308     mudstate.inpipe = false;
00309     mudstate.pout = NULL;
00310     mudstate.poutnew = NULL;
00311     mudstate.poutbufc = NULL;
00312     mudstate.poutobj = NOTHING;
00313     for (i = 0; i < MAX_GLOBAL_REGS; i++)
00314     {
00315         mudstate.global_regs[i] = NULL;
00316         mudstate.glob_reg_len[i] = 0;
00317     }
00318     mudstate.nObjEvalNest = 0;
00319     mudstate.in_loop = 0;
00320     mudstate.bStackLimitReached = false;
00321     mudstate.nStackNest = 0;
00322     mudstate.nHearNest  = 0;
00323     mudstate.aHelpDesc = NULL;
00324     mudstate.mHelpDesc = 0;
00325     mudstate.nHelpDesc = 0;
00326 }
00327 
00328 // ---------------------------------------------------------------------------
00329 // cf_log_notfound: Log a 'parameter not found' error.
00330 //
00331 void cf_log_notfound(dbref player, char *cmd, const char *thingname, char *thing)
00332 {
00333     if (mudstate.bReadingConfiguration)
00334     {
00335         STARTLOG(LOG_STARTUP, "CNF", "NFND");
00336         Log.tinyprintf("%s: %s %s not found", cmd, thingname, thing);
00337         ENDLOG;
00338     }
00339     else
00340     {
00341         notify(player, tprintf("%s %s not found", thingname, thing));
00342     }
00343 }
00344 
00345 // ---------------------------------------------------------------------------
00346 // cf_log_syntax: Log a syntax error.
00347 //
00348 void DCL_CDECL cf_log_syntax(dbref player, char *cmd, const char *fmt, ...)
00349 {
00350     va_list ap;
00351     va_start(ap, fmt);
00352 
00353     char *buf = alloc_lbuf("cf_log_syntax");
00354     mux_vsnprintf(buf, LBUF_SIZE, fmt, ap);
00355     if (mudstate.bReadingConfiguration)
00356     {
00357         STARTLOG(LOG_STARTUP, "CNF", "SYNTX")
00358         log_text(cmd);
00359         log_text(": ");
00360         log_text(buf);
00361         ENDLOG;
00362     }
00363     else
00364     {
00365         notify(player, buf);
00366     }
00367     free_lbuf(buf);
00368     va_end(ap);
00369 }
00370 
00371 // ---------------------------------------------------------------------------
00372 // cf_status_from_succfail: Return command status from succ and fail info
00373 //
00374 static int cf_status_from_succfail(dbref player, char *cmd, int success, int failure)
00375 {
00376     char *buff;
00377 
00378     // If any successes, return SUCCESS(0) if no failures or
00379     // PARTIAL_SUCCESS(1) if any failures.
00380     //
00381     if (success > 0)
00382         return ((failure == 0) ? 0 : 1);
00383 
00384     // No successes.  If no failures indicate nothing done. Always return
00385     // FAILURE(-1)
00386     //
00387     if (failure == 0)
00388     {
00389         if (mudstate.bReadingConfiguration)
00390         {
00391             STARTLOG(LOG_STARTUP, "CNF", "NDATA")
00392             buff = alloc_lbuf("cf_status_from_succfail.LOG");
00393             sprintf(buff, "%s: Nothing to set", cmd);
00394             log_text(buff);
00395             free_lbuf(buff);
00396             ENDLOG
00397         }
00398         else
00399         {
00400             notify(player, "Nothing to set");
00401         }
00402     }
00403     return -1;
00404 }
00405 
00406 //---------------------------------------------------------------------------
00407 // cf_rlevel
00408 //
00409 
00410 #ifdef REALITY_LVLS
00411 
00412 CF_HAND(cf_rlevel)
00413 {
00414     CONFDATA *mc = (CONFDATA *)vp;
00415     int i;
00416 
00417     if(mc->no_levels >= 32)
00418         return 1;
00419     for(i=0; *str && !mux_isspace[*str]; ++str)
00420         if(i < 8)
00421             mc->reality_level[mc->no_levels].name[i++] = *str;
00422     mc->reality_level[mc->no_levels].name[i] = '\0';
00423     mc->reality_level[mc->no_levels].value = 1;
00424     strcpy(mc->reality_level[mc->no_levels].attr, "DESC");
00425     for(; *str && mux_isspace[*str]; ++str);
00426     for(i=0; *str && mux_isdigit[*str]; ++str)
00427         i = i * 10 + (*str - '0');
00428     if(i)
00429         mc->reality_level[mc->no_levels].value = (RLEVEL) i;
00430     for(; *str && mux_isspace[*str]; ++str);
00431     if(*str)
00432         strncpy(mc->reality_level[mc->no_levels].attr, str, 32);
00433     mc->no_levels++;
00434     return 0;
00435 }
00436 #endif /* REALITY_LVLS */
00437 
00438 // ---------------------------------------------------------------------------
00439 // cf_int_array: Setup array of integers.
00440 //
00441 static CF_HAND(cf_int_array)
00442 {
00443     UNUSED_PARAMETER(pExtra);
00444     UNUSED_PARAMETER(player);
00445     UNUSED_PARAMETER(cmd);
00446 
00447     int *aPorts = (int *)MEMALLOC(nExtra*sizeof(int));
00448     ISOUTOFMEMORY(aPorts);
00449     unsigned int nPorts = 0;
00450 
00451     char *p;
00452     MUX_STRTOK_STATE tts;
00453     mux_strtok_src(&tts, str);
00454     mux_strtok_ctl(&tts, " \t\n\r");
00455     while ((p = mux_strtok_parse(&tts)) != NULL)
00456     {
00457         int unused;
00458         if (is_integer(p, &unused))
00459         {
00460             aPorts[nPorts++] = mux_atol(p);
00461             if (nPorts >= nExtra)
00462             {
00463                 break;
00464             }
00465         }
00466     }
00467 
00468     IntArray *pia = (IntArray *)vp;
00469     if (nPorts)
00470     {
00471         if (pia->pi)
00472         {
00473             MEMFREE(pia->pi);
00474             pia->pi = NULL;
00475         }
00476         pia->pi = (int *)MEMALLOC(nPorts * sizeof(int));
00477         ISOUTOFMEMORY(pia->pi);
00478         pia->n = nPorts;
00479         for (unsigned int i = 0; i < nPorts; i++)
00480         {
00481             pia->pi[i] = aPorts[i];
00482         }
00483     }
00484     MEMFREE(aPorts);
00485     return 0;
00486 }
00487 
00488 // ---------------------------------------------------------------------------
00489 // cf_int: Set integer parameter.
00490 //
00491 static CF_HAND(cf_int)
00492 {
00493     UNUSED_PARAMETER(pExtra);
00494     UNUSED_PARAMETER(nExtra);
00495     UNUSED_PARAMETER(player);
00496     UNUSED_PARAMETER(cmd);
00497 
00498     // Copy the numeric value to the parameter.
00499     //
00500     *vp = mux_atol(str);
00501     return 0;
00502 }
00503 
00504 // ---------------------------------------------------------------------------
00505 // cf_dbref: Set dbref parameter....looking for an ignoring the leading '#'.
00506 //
00507 static CF_HAND(cf_dbref)
00508 {
00509     UNUSED_PARAMETER(pExtra);
00510     UNUSED_PARAMETER(nExtra);
00511     UNUSED_PARAMETER(player);
00512     UNUSED_PARAMETER(cmd);
00513 
00514     char *p = str;
00515     while (mux_isspace(*p))
00516     {
00517         p++;
00518     }
00519     if (*p == '#')
00520     {
00521         p++;
00522     }
00523 
00524     // Copy the numeric value to the parameter.
00525     //
00526     *vp = mux_atol(p);
00527     return 0;
00528 }
00529 
00530 // ---------------------------------------------------------------------------
00531 // cf_seconds: Set CLinearTimeDelta in units of seconds.
00532 //
00533 static CF_HAND(cf_seconds)
00534 {
00535     UNUSED_PARAMETER(pExtra);
00536     UNUSED_PARAMETER(nExtra);
00537     UNUSED_PARAMETER(player);
00538     UNUSED_PARAMETER(cmd);
00539 
00540     CLinearTimeDelta *pltd = (CLinearTimeDelta *)vp;
00541     pltd->SetSecondsString(str);
00542     return 0;
00543 }
00544 
00545 // ---------------------------------------------------------------------------
00546 // cf_bool: Set boolean parameter.
00547 //
00548 static NAMETAB bool_names[] =
00549 {
00550     {"true",    1,  0,  true},
00551     {"false",   1,  0,  false},
00552     {"yes",     1,  0,  true},
00553     {"no",      1,  0,  false},
00554     {"1",       1,  0,  true},
00555     {"0",       1,  0,  false},
00556     {NULL,      0,  0,  0}
00557 };
00558 
00559 static CF_HAND(cf_bool)
00560 {
00561     UNUSED_PARAMETER(pExtra);
00562     UNUSED_PARAMETER(nExtra);
00563 
00564     int i;
00565     if (!search_nametab(GOD, bool_names, str, &i))
00566     {
00567         cf_log_notfound(player, cmd, "Value", str);
00568         return -1;
00569     }
00570     bool *pb = (bool *)vp;
00571     *pb = isTRUE(i);
00572     return 0;
00573 }
00574 
00575 // ---------------------------------------------------------------------------
00576 // cf_option: Select one option from many choices.
00577 //
00578 static CF_HAND(cf_option)
00579 {
00580     UNUSED_PARAMETER(nExtra);
00581 
00582     int i;
00583     if (!search_nametab(GOD, (NAMETAB *)pExtra, str, &i))
00584     {
00585         cf_log_notfound(player, cmd, "Value", str);
00586         return -1;
00587     }
00588     *vp = i;
00589     return 0;
00590 }
00591 
00592 // ---------------------------------------------------------------------------
00593 // cf_string: Set string parameter.
00594 //
00595 static CF_HAND(cf_string)
00596 {
00597     UNUSED_PARAMETER(pExtra);
00598 
00599     char *pc = (char *)vp;
00600 
00601     // The following should never happen because extra is always a non-zero
00602     // constant in the config table.
00603     //
00604     if (nExtra <= 0)
00605     {
00606         return 1;
00607     }
00608 
00609     // Copy the string to the buffer if it is not too big.
00610     //
00611     int retval = 0;
00612     unsigned int nStr = strlen(str);
00613     if (nStr >= nExtra)
00614     {
00615         nStr = nExtra - 1;
00616         if (mudstate.bReadingConfiguration)
00617         {
00618             STARTLOG(LOG_STARTUP, "CNF", "NFND");
00619             Log.tinyprintf("%s: String truncated", cmd);
00620             ENDLOG;
00621         }
00622         else
00623         {
00624             notify(player, "String truncated");
00625         }
00626         retval = 1;
00627     }
00628     memcpy(pc, str, nStr+1);
00629     pc[nStr] = '\0';
00630 
00631     if (pc == mudconf.mud_name)
00632     {
00633         // We are changing the name of the MUD. Form a prefix from the
00634         // mudname and let the logger know.
00635         //
00636         char *buff = alloc_sbuf("cf_string.prefix");
00637         char *p = buff;
00638         char *q = strip_ansi(mudconf.mud_name);
00639         size_t nLen = 0;
00640         while (  *q
00641               && nLen < SBUF_SIZE)
00642         {
00643             if (mux_isalnum(*q))
00644             {
00645                 *p++ = *q;
00646                 nLen++;
00647             }
00648             q++;
00649         }
00650         *p = '\0';
00651         Log.SetPrefix(buff);
00652         free_sbuf(buff);
00653     }
00654     return retval;
00655 }
00656 
00657 // ---------------------------------------------------------------------------
00658 // cf_string_dyn: Set string parameter using dynamically allocated memory.
00659 //
00660 static CF_HAND(cf_string_dyn)
00661 {
00662     UNUSED_PARAMETER(pExtra);
00663 
00664     char **ppc = (char **)vp;
00665 
00666     // Allocate memory for buffer and copy string to it. If nExtra is non-zero,
00667     // then there is a size limitation as well.
00668     //
00669     int retval = 0;
00670     unsigned int nStr = strlen(str);
00671     if (nExtra && nStr >= nExtra)
00672     {
00673         nStr = nExtra - 1;
00674         if (mudstate.bReadingConfiguration)
00675         {
00676             STARTLOG(LOG_STARTUP, "CNF", "NFND");
00677             Log.tinyprintf("%s: String truncated", cmd);
00678             ENDLOG;
00679         }
00680         else
00681         {
00682             notify(player, "String truncated");
00683         }
00684         retval = 1;
00685     }
00686     char *confbuff = StringCloneLen(str, nStr);
00687 
00688     // Free previous memory for buffer.
00689     //
00690     if (*ppc != NULL)
00691     {
00692         MEMFREE(*ppc);
00693     }
00694     *ppc = confbuff;
00695 
00696     return retval;
00697 }
00698 
00699 // ---------------------------------------------------------------------------
00700 // cf_alias: define a generic hash table alias.
00701 //
00702 static CF_HAND(cf_alias)
00703 {
00704     UNUSED_PARAMETER(pExtra);
00705     UNUSED_PARAMETER(nExtra);
00706 
00707     MUX_STRTOK_STATE tts;
00708     mux_strtok_src(&tts, str);
00709     mux_strtok_ctl(&tts, " \t=,");
00710     char *alias = mux_strtok_parse(&tts);
00711     char *orig = mux_strtok_parse(&tts);
00712 
00713     if (orig)
00714     {
00715         mux_strlwr(orig);
00716         void *cp = hashfindLEN(orig, strlen(orig), (CHashTable *) vp);
00717         if (cp == NULL)
00718         {
00719             mux_strupr(orig);
00720             cp = hashfindLEN(orig, strlen(orig), (CHashTable *) vp);
00721             if (cp == NULL)
00722             {
00723                 cf_log_notfound(player, cmd, "Entry", orig);
00724                 return -1;
00725             }
00726         }
00727         if (!hashfindLEN(alias, strlen(alias), (CHashTable *) vp))
00728         {
00729             hashaddLEN(alias, strlen(alias), cp, (CHashTable *) vp);
00730         }
00731         return 0;
00732     }
00733     return -1;
00734 }
00735 
00736 // ---------------------------------------------------------------------------
00737 // cf_flagalias: define a flag alias.
00738 //
00739 static CF_HAND(cf_flagalias)
00740 {
00741     UNUSED_PARAMETER(vp);
00742     UNUSED_PARAMETER(pExtra);
00743     UNUSED_PARAMETER(nExtra);
00744 
00745     MUX_STRTOK_STATE tts;
00746     mux_strtok_src(&tts, str);
00747     mux_strtok_ctl(&tts, " \t=,");
00748     char *alias = mux_strtok_parse(&tts);
00749     char *orig = mux_strtok_parse(&tts);
00750 
00751     bool success = false;
00752     int  nName;
00753     bool bValid;
00754     void *cp;
00755     char *pName = MakeCanonicalFlagName(orig, &nName, &bValid);
00756     if (bValid)
00757     {
00758         cp = hashfindLEN(pName, nName, &mudstate.flags_htab);
00759         if (cp)
00760         {
00761             pName = MakeCanonicalFlagName(alias, &nName, &bValid);
00762             if (bValid)
00763             {
00764                 if (!hashfindLEN(pName, nName, &mudstate.flags_htab))
00765                 {
00766                     hashaddLEN(pName, nName, cp, &mudstate.flags_htab);
00767                     success = true;
00768                }
00769             }
00770         }
00771     }
00772     if (!success)
00773     {
00774         cf_log_notfound(player, cmd, "Flag", orig);
00775     }
00776     return (success ? 0 : -1);
00777 }
00778 
00779 // ---------------------------------------------------------------------------
00780 // cf_poweralias: define a power alias.
00781 //
00782 static CF_HAND(cf_poweralias)
00783 {
00784     UNUSED_PARAMETER(vp);
00785     UNUSED_PARAMETER(pExtra);
00786     UNUSED_PARAMETER(nExtra);
00787 
00788     MUX_STRTOK_STATE tts;
00789     mux_strtok_src(&tts, str);
00790     mux_strtok_ctl(&tts, " \t=,");
00791     char *alias = mux_strtok_parse(&tts);
00792     char *orig = mux_strtok_parse(&tts);
00793 
00794     bool success = false;
00795     int  nName;
00796     bool bValid;
00797     void *cp;
00798     char *pName = MakeCanonicalFlagName(orig, &nName, &bValid);
00799     if (bValid)
00800     {
00801         cp = hashfindLEN(pName, nName, &mudstate.powers_htab);
00802         if (cp)
00803         {
00804             pName = MakeCanonicalFlagName(alias, &nName, &bValid);
00805             if (bValid)
00806             {
00807                 hashaddLEN(pName, nName, cp, &mudstate.powers_htab);
00808                 success = true;
00809             }
00810         }
00811     }
00812     if (!success)
00813     {
00814         cf_log_notfound(player, cmd, "Power", orig);
00815     }
00816     return (success ? 0 : -1);
00817 }
00818 
00819 #if 0
00820 // ---------------------------------------------------------------------------
00821 // cf_or_in_bits: OR in bits from namelist to a word.
00822 //
00823 static CF_HAND(cf_or_in_bits)
00824 {
00825     UNUSED_PARAMETER(nExtra);
00826 
00827     int f, success, failure;
00828 
00829     // Walk through the tokens.
00830     //
00831     success = failure = 0;
00832     MUX_STRTOK_STATE tts;
00833     mux_strtok_src(&tts, str);
00834     mux_strtok_ctl(&tts, " \t");
00835     char *sp = mux_strtok_parse(&tts);
00836     while (sp != NULL)
00837     {
00838         // Set the appropriate bit.
00839         //
00840         if (search_nametab(GOD, (NAMETAB *)pExtra, sp, &f))
00841         {
00842             *vp |= f;
00843             success++;
00844         }
00845         else
00846         {
00847             cf_log_notfound(player, cmd, "Entry", sp);
00848             failure++;
00849         }
00850 
00851         // Get the next token.
00852         //
00853         sp = mux_strtok_parse(&tts);
00854     }
00855     return cf_status_from_succfail(player, cmd, success, failure);
00856 }
00857 #endif
00858 
00859 // ---------------------------------------------------------------------------
00860 // cf_modify_bits: set or clear bits in a flag word from a namelist.
00861 //
00862 CF_HAND(cf_modify_bits)
00863 {
00864     UNUSED_PARAMETER(nExtra);
00865 
00866     int f, success, failure;
00867     bool negate;
00868 
00869     // Walk through the tokens.
00870     //
00871     success = failure = 0;
00872     MUX_STRTOK_STATE tts;
00873     mux_strtok_src(&tts, str);
00874     mux_strtok_ctl(&tts, " \t");
00875     char *sp = mux_strtok_parse(&tts);
00876     while (sp != NULL)
00877     {
00878         // Check for negation.
00879         //
00880         negate = false;
00881         if (*sp == '!')
00882         {
00883             negate = true;
00884             sp++;
00885         }
00886 
00887         // Set or clear the appropriate bit.
00888         //
00889         if (search_nametab(GOD, (NAMETAB *)pExtra, sp, &f))
00890         {
00891             if (negate)
00892                 *vp &= ~f;
00893             else
00894                 *vp |= f;
00895             success++;
00896         }
00897         else
00898         {
00899             cf_log_notfound(player, cmd, "Entry", sp);
00900             failure++;
00901         }
00902 
00903         // Get the next token.
00904         //
00905         sp = mux_strtok_parse(&tts);
00906     }
00907     return cf_status_from_succfail(player, cmd, success, failure);
00908 }
00909 
00910 #if 0
00911 // ---------------------------------------------------------------------------
00912 // cf_set_bits: Clear flag word and then set specified bits from namelist.
00913 //
00914 static CF_HAND(cf_set_bits)
00915 {
00916     UNUSED_PARAMETER(nExtra);
00917 
00918     int f, success, failure;
00919 
00920     // Walk through the tokens
00921     //
00922     success = failure = 0;
00923     *vp = 0;
00924 
00925     MUX_STRTOK_STATE tts;
00926     mux_strtok_src(&tts, str);
00927     mux_strtok_ctl(&tts, " \t");
00928     char *sp = mux_strtok_parse(&tts);
00929     while (sp != NULL)
00930     {
00931         // Set the appropriate bit.
00932         //
00933         if (search_nametab(GOD, (NAMETAB *)pExtra, sp, &f))
00934         {
00935             *vp |= f;
00936             success++;
00937         }
00938         else
00939         {
00940             cf_log_notfound(player, cmd, "Entry", sp);
00941             failure++;
00942         }
00943 
00944         // Get the next token.
00945         //
00946         sp = mux_strtok_parse(&tts);
00947     }
00948     return cf_status_from_succfail(player, cmd, success, failure);
00949 }
00950 #endif
00951 
00952 // ---------------------------------------------------------------------------
00953 // cf_set_flags: Clear flag word and then set from a flags htab.
00954 //
00955 static CF_HAND(cf_set_flags)
00956 {
00957     UNUSED_PARAMETER(pExtra);
00958     UNUSED_PARAMETER(nExtra);
00959 
00960     int success, failure;
00961 
00962     // Walk through the tokens.
00963     //
00964     success = failure = 0;
00965     MUX_STRTOK_STATE tts;
00966     mux_strtok_src(&tts, str);
00967     mux_strtok_ctl(&tts, " \t");
00968     char *sp = mux_strtok_parse(&tts);
00969     FLAGSET *fset = (FLAGSET *) vp;
00970 
00971     while (sp != NULL)
00972     {
00973         // Canonical Flag Name.
00974         //
00975         int  nName;
00976         bool bValid;
00977         char *pName = MakeCanonicalFlagName(sp, &nName, &bValid);
00978         FLAGNAMEENT *fp = NULL;
00979         if (bValid)
00980         {
00981             fp = (FLAGNAMEENT *)hashfindLEN(pName, nName, &mudstate.flags_htab);
00982         }
00983         if (fp != NULL)
00984         {
00985             // Set the appropriate bit.
00986             //
00987             if (success == 0)
00988             {
00989                 for (int i = FLAG_WORD1; i <= FLAG_WORD3; i++)
00990                 {
00991                     (*fset).word[i] = 0;
00992                 }
00993             }
00994             FLAGBITENT *fbe = fp->fbe;
00995             if (fp->bPositive)
00996             {
00997                 (*fset).word[fbe->flagflag] |= fbe->flagvalue;
00998             }
00999             else
01000             {
01001                 (*fset).word[fbe->flagflag] &= ~(fbe->flagvalue);
01002             }
01003             success++;
01004         }
01005         else
01006         {
01007             cf_log_notfound(player, cmd, "Entry", sp);
01008             failure++;
01009         }
01010 
01011         // Get the next token
01012         //
01013         sp = mux_strtok_parse(&tts);
01014     }
01015     if ((success == 0) && (failure == 0))
01016     {
01017         for (int i = FLAG_WORD1; i <= FLAG_WORD3; i++)
01018         {
01019             (*fset).word[i] = 0;
01020         }
01021         return 0;
01022     }
01023     if (success > 0)
01024     {
01025         return ((failure == 0) ? 0 : 1);
01026     }
01027     return -1;
01028 }
01029 
01030 // ---------------------------------------------------------------------------
01031 // cf_badname: Disallow use of player name/alias.
01032 //
01033 static CF_HAND(cf_badname)
01034 {
01035     UNUSED_PARAMETER(vp);
01036     UNUSED_PARAMETER(pExtra);
01037     UNUSED_PARAMETER(player);
01038     UNUSED_PARAMETER(cmd);
01039 
01040     if (nExtra)
01041     {
01042         badname_remove(str);
01043     }
01044     else
01045     {
01046         badname_add(str);
01047     }
01048     return 0;
01049 }
01050 
01051 typedef struct
01052 {
01053     int    nShift;
01054     UINT32 maxValue;
01055     size_t maxOctLen;
01056     size_t maxDecLen;
01057     size_t maxHexLen;
01058 } DECODEIPV4;
01059 
01060 static bool DecodeN(int nType, size_t len, const char *p, in_addr_t *pu32)
01061 {
01062     static DECODEIPV4 DecodeIPv4Table[4] =
01063     {
01064         { 8,         255UL,  3,  3, 2 },
01065         { 16,      65535UL,  6,  5, 4 },
01066         { 24,   16777215UL,  8,  8, 6 },
01067         { 32, 4294967295UL, 11, 10, 8 }
01068     };
01069 
01070     *pu32  = (*pu32 << DecodeIPv4Table[nType].nShift) & 0xFFFFFFFFUL;
01071     if (len == 0)
01072     {
01073         return false;
01074     }
01075     in_addr_t ul = 0;
01076     in_addr_t ul2;
01077     if (  len >= 3
01078        && p[0] == '0'
01079        && mux_tolower(p[1]) == 'x')
01080     {
01081         // Hexadecimal Path
01082         //
01083         // Skip the leading zeros.
01084         //
01085         p += 2;
01086         len -= 2;
01087         while (*p == '0' && len)
01088         {
01089             p++;
01090             len--;
01091         }
01092         if (len > DecodeIPv4Table[nType].maxHexLen)
01093         {
01094             return false;
01095         }
01096         while (len)
01097         {
01098             unsigned char ch = mux_tolower(*p);
01099             ul2 = ul;
01100             ul  = (ul << 4) & 0xFFFFFFFFUL;
01101             if (ul < ul2)
01102             {
01103                 // Overflow
01104                 //
01105                 return false;
01106             }
01107             if ('0' <= ch && ch <= '9')
01108             {
01109                 ul |= ch - '0';
01110             }
01111             else if ('a' <= ch && ch <= 'f')
01112             {
01113                 ul |= ch - 'a';
01114             }
01115             else
01116             {
01117                 return false;
01118             }
01119             p++;
01120             len--;
01121         }
01122     }
01123     else if (len >= 1 && p[0] == '0')
01124     {
01125         // Octal Path
01126         //
01127         // Skip the leading zeros.
01128         //
01129         p++;
01130         len--;
01131         while (*p == '0' && len)
01132         {
01133             p++;
01134             len--;
01135         }
01136         if (len > DecodeIPv4Table[nType].maxOctLen)
01137         {
01138             return false;
01139         }
01140         while (len)
01141         {
01142             unsigned char ch = *p;
01143             ul2 = ul;
01144             ul  = (ul << 3) & 0xFFFFFFFFUL;
01145             if (ul < ul2)
01146             {
01147                 // Overflow
01148                 //
01149                 return false;
01150             }
01151             if ('0' <= ch && ch <= '7')
01152             {
01153                 ul |= ch - '0';
01154             }
01155             else
01156             {
01157                 return false;
01158             }
01159             p++;
01160             len--;
01161         }
01162     }
01163     else
01164     {
01165         // Decimal Path
01166         //
01167         if (len > DecodeIPv4Table[nType].maxDecLen)
01168         {
01169             return false;
01170         }
01171         while (len)
01172         {
01173             unsigned char ch = *p;
01174             ul2 = ul;
01175             ul  = (ul * 10) & 0xFFFFFFFFUL;
01176             if (ul < ul2)
01177             {
01178                 // Overflow
01179                 //
01180                 return false;
01181             }
01182             ul2 = ul;
01183             if ('0' <= ch && ch <= '9')
01184             {
01185                 ul += ch - '0';
01186             }
01187             else
01188             {
01189                 return false;
01190             }
01191             if (ul < ul2)
01192             {
01193                 // Overflow
01194                 //
01195                 return false;
01196             }
01197             p++;
01198             len--;
01199         }
01200     }
01201     if (ul > DecodeIPv4Table[nType].maxValue)
01202     {
01203         return false;
01204     }
01205     *pu32 |= ul;
01206     return true;
01207 }
01208 
01209 // ---------------------------------------------------------------------------
01210 // MakeCanonicalIPv4: inet_addr() does not do reasonable checking for sane
01211 // syntax on all platforms. On certain operating systems, if passed less than
01212 // four octets, it will cause a segmentation violation. Furthermore, there is
01213 // confusion between return values for valid input "255.255.255.255" and
01214 // return values for invalid input (INADDR_NONE as -1). To overcome these
01215 // problems, it appears necessary to re-implement inet_addr() with a different
01216 // interface.
01217 //
01218 // n8.n8.n8.n8  Class A format. 0 <= n8 <= 255.
01219 //
01220 // Supported Berkeley IP formats:
01221 //
01222 //    n8.n8.n16  Class B 128.net.host format. 0 <= n16 <= 65535.
01223 //    n8.n24     Class A net.host format. 0 <= n24 <= 16777215.
01224 //    n32        Single 32-bit number. 0 <= n32 <= 4294967295.
01225 //
01226 // Each element may be expressed in decimal, octal or hexadecimal. '0' is the
01227 // octal prefix. '0x' or '0X' is the hexadecimal prefix. Otherwise the number
01228 // is taken as decimal.
01229 //
01230 //    08  Octal
01231 //    0x8 Hexadecimal
01232 //    0X8 Hexadecimal
01233 //    8   Decimal
01234 //
01235 static bool MakeCanonicalIPv4(const char *str, in_addr_t *pnIP)
01236 {
01237     *pnIP = 0;
01238     if (!str)
01239     {
01240         return false;
01241     }
01242 
01243     // Skip leading spaces.
01244     //
01245     const char *q = str;
01246     while (*q == ' ')
01247     {
01248         q++;
01249     }
01250 
01251     const char *p = strchr(q, '.');
01252     int n = 0;
01253     while (p)
01254     {
01255         // Decode
01256         //
01257         n++;
01258         if (n > 3)
01259         {
01260             return false;
01261         }
01262         if (!DecodeN(0, p-q, q, pnIP))
01263         {
01264             return false;
01265         }
01266         q = p + 1;
01267         p = strchr(q, '.');
01268     }
01269 
01270     // Decode last element.
01271     //
01272     size_t len = strlen(q);
01273     if (!DecodeN(3-n, len, q, pnIP))
01274     {
01275         return false;
01276     }
01277     *pnIP = htonl(*pnIP);
01278     return true;
01279 }
01280 
01281 // Given a host-ordered mask, this function will determine whether it is a
01282 // valid one. Valid masks consist of a N-bit sequence of '1' bits followed by
01283 // a (32-N)-bit sequence of '0' bits, where N is 0 to 32.
01284 //
01285 static bool isValidSubnetMask(in_addr_t ulMask)
01286 {
01287     in_addr_t ulTest = 0xFFFFFFFFUL;
01288     for (int i = 0; i <= 32; i++)
01289     {
01290         if (ulMask == ulTest)
01291         {
01292             return true;
01293         }
01294         ulTest = (ulTest << 1) & 0xFFFFFFFFUL;
01295     }
01296     return false;
01297 }
01298 
01299 // ---------------------------------------------------------------------------
01300 // cf_site: Update site information
01301 
01302 static CF_HAND(cf_site)
01303 {
01304     UNUSED_PARAMETER(pExtra);
01305 
01306     SITE **ppv = (SITE **)vp;
01307     struct in_addr addr_num, mask_num;
01308     in_addr_t ulMask, ulNetBits;
01309 
01310     char *addr_txt;
01311     char *mask_txt = strchr(str, '/');
01312     if (!mask_txt)
01313     {
01314         // Standard IP range and netmask notation.
01315         //
01316         MUX_STRTOK_STATE tts;
01317         mux_strtok_src(&tts, str);
01318         mux_strtok_ctl(&tts, " \t=,");
01319         addr_txt = mux_strtok_parse(&tts);
01320         mask_txt = NULL;
01321         if (addr_txt)
01322         {
01323             mask_txt = mux_strtok_parse(&tts);
01324         }
01325         if (!addr_txt || !*addr_txt || !mask_txt || !*mask_txt)
01326         {
01327             cf_log_syntax(player, cmd, "Missing host address or mask.", "");
01328             return -1;
01329         }
01330         if (  !MakeCanonicalIPv4(mask_txt, &ulNetBits)
01331            || !isValidSubnetMask(ulMask = ntohl(ulNetBits)))
01332         {
01333             cf_log_syntax(player, cmd, "Malformed mask address: %s", mask_txt);
01334             return -1;
01335         }
01336         mask_num.s_addr = ulNetBits;
01337     }
01338     else
01339     {
01340         // RFC 1517, 1518, 1519, 1520: CIDR IP prefix notation
01341         //
01342         addr_txt = str;
01343         *mask_txt++ = '\0';
01344         if (!is_integer(mask_txt, NULL))
01345         {
01346             cf_log_syntax(player, cmd, "Mask field (%s) in CIDR IP prefix is not numeric.", mask_txt);
01347             return -1;
01348         }
01349         int mask_bits = mux_atol(mask_txt);
01350         if (  mask_bits < 0
01351            || 32 < mask_bits)
01352         {
01353             cf_log_syntax(player, cmd, "Mask bits (%d) in CIDR IP prefix out of range.", mask_bits);
01354             return -1;
01355         }
01356         else
01357         {
01358             // << [0,31] works. << 32 is problematic on some systems.
01359             //
01360             ulMask = 0;
01361             if (mask_bits > 0)
01362             {
01363                 ulMask = (0xFFFFFFFFUL << (32 - mask_bits)) & 0xFFFFFFFFUL;
01364             }
01365             mask_num.s_addr = htonl(ulMask);
01366         }
01367     }
01368     if (!MakeCanonicalIPv4(addr_txt, &ulNetBits))
01369     {
01370         cf_log_syntax(player, cmd, "Malformed host address: %s", addr_txt);
01371         return -1;
01372     }
01373     addr_num.s_addr = ulNetBits;
01374     in_addr_t ulAddr = ntohl(addr_num.s_addr);
01375 
01376     if (ulAddr & ~ulMask)
01377     {
01378         // The given subnet address contains 'one' bits which are outside
01379         // the given subnet mask. If we don't clear these bits, they will
01380         // interfere with the subnet tests in site_check. The subnet spec
01381         // would be defunct and useless.
01382         //
01383         cf_log_syntax(player, cmd, "Non-zero host address bits outside the subnet mask (fixed): %s %s", addr_txt, mask_txt);
01384         ulAddr &= ulMask;
01385         addr_num.s_addr = htonl(ulAddr);
01386     }
01387 
01388     SITE *head = *ppv;
01389 
01390     // Parse the access entry and allocate space for it.
01391     //
01392     SITE *site = (SITE *)MEMALLOC(sizeof(SITE));
01393     ISOUTOFMEMORY(site);
01394 
01395     // Initialize the site entry.
01396     //
01397     site->address.s_addr = addr_num.s_addr;
01398     site->mask.s_addr = mask_num.s_addr;
01399     site->flag = nExtra;
01400     site->next = NULL;
01401 
01402     // Link in the entry. Link it at the start if not initializing, at the
01403     // end if initializing. This is so that entries in the config file are
01404     // processed as you would think they would be, while entries made while
01405     // running are processed first.
01406     //
01407     if (mudstate.bReadingConfiguration)
01408     {
01409         if (head == NULL)
01410         {
01411             *ppv = site;
01412         }
01413         else
01414         {
01415             SITE *last;
01416             for (last = head; last->next; last = last->next)
01417             {
01418                 // Nothing
01419             }
01420             last->next = site;
01421         }
01422     }
01423     else
01424     {
01425         site->next = head;
01426         *ppv = site;
01427     }
01428     return 0;
01429 }
01430 
01431 // ---------------------------------------------------------------------------
01432 // cf_helpfile, cf_raw_helpfile: Add help files and their corresponding
01433 // command.
01434 //
01435 static int add_helpfile(dbref player, char *cmd, char *str, bool bRaw)
01436 {
01437     // Parse the two arguments.
01438     //
01439     MUX_STRTOK_STATE tts;
01440     mux_strtok_src(&tts, str);
01441     mux_strtok_ctl(&tts, " \t\n\r");
01442 
01443     char *pCmdName = mux_strtok_parse(&tts);
01444     char *pBase = mux_strtok_parse(&tts);
01445     if (pBase == NULL)
01446     {
01447         cf_log_syntax(player, cmd, "Missing path for helpfile %s", pCmdName);
01448         return -1;
01449     }
01450     if (  pCmdName[0] == '_'
01451        && pCmdName[1] == '_')
01452     {
01453         cf_log_syntax(player, cmd,
01454             "Helpfile %s would conflict with the use of @addcommand.",
01455             pCmdName);
01456         return -1;
01457     }
01458     if (SBUF_SIZE <= strlen(pBase))
01459     {
01460         cf_log_syntax(player, cmd, "Helpfile '%s' filename too long", pBase);
01461         return -1;
01462     }
01463 
01464     // Allocate an empty place in the table of help file hashes.
01465     //
01466     if (mudstate.aHelpDesc == NULL)
01467     {
01468         mudstate.mHelpDesc = 4;
01469         mudstate.nHelpDesc = 0;
01470         mudstate.aHelpDesc = (HELP_DESC *)MEMALLOC(sizeof(HELP_DESC)
01471             *mudstate.mHelpDesc);
01472         ISOUTOFMEMORY(mudstate.aHelpDesc);
01473     }
01474     else if (mudstate.mHelpDesc <= mudstate.nHelpDesc)
01475     {
01476         int newsize = mudstate.mHelpDesc + 4;
01477         HELP_DESC *q = (HELP_DESC *)MEMALLOC(sizeof(HELP_DESC)*newsize);
01478         ISOUTOFMEMORY(q);
01479         memset(q, 0, sizeof(HELP_DESC)*newsize);
01480         memcpy(q, mudstate.aHelpDesc, sizeof(HELP_DESC)*mudstate.mHelpDesc);
01481         MEMFREE(mudstate.aHelpDesc);
01482         mudstate.aHelpDesc = q;
01483         mudstate.mHelpDesc = newsize;
01484     }
01485 
01486     // Build HELP_DESC
01487     //
01488     HELP_DESC *pDesc = mudstate.aHelpDesc + mudstate.nHelpDesc;
01489     pDesc->CommandName = StringClone(pCmdName);
01490     pDesc->ht = NULL;
01491     pDesc->pBaseFilename = StringClone(pBase);
01492     pDesc->bEval = !bRaw;
01493 
01494     // Build up Command Entry.
01495     //
01496     CMDENT_ONE_ARG *cmdp = (CMDENT_ONE_ARG *)MEMALLOC(sizeof(CMDENT_ONE_ARG));
01497     ISOUTOFMEMORY(cmdp);
01498 
01499     cmdp->callseq = CS_ONE_ARG;
01500     cmdp->cmdname = StringClone(pCmdName);
01501     cmdp->extra = mudstate.nHelpDesc;
01502     cmdp->handler = do_help;
01503     cmdp->hookmask = 0;
01504     cmdp->perms = CA_PUBLIC;
01505     cmdp->switches = NULL;
01506 
01507     // TODO: If a command is deleted with one or both of the two
01508     // hashdeleteLEN() calls below, what guarantee do we have that parts of
01509     // the command weren't dynamically allocated.  This might leak memory.
01510     //
01511     char *p = cmdp->cmdname;
01512     hashdeleteLEN(p, strlen(p), &mudstate.command_htab);
01513     hashaddLEN(p, strlen(p), cmdp, &mudstate.command_htab);
01514 
01515     p = tprintf("__%s", cmdp->cmdname);
01516     hashdeleteLEN(p, strlen(p), &mudstate.command_htab);
01517     hashaddLEN(p, strlen(p), cmdp, &mudstate.command_htab);
01518 
01519     mudstate.nHelpDesc++;
01520 
01521     return 0;
01522 }
01523 
01524 static CF_HAND(cf_helpfile)
01525 {
01526     UNUSED_PARAMETER(vp);
01527     UNUSED_PARAMETER(pExtra);
01528     UNUSED_PARAMETER(nExtra);
01529 
01530     return add_helpfile(player, cmd, str, false);
01531 }
01532 
01533 static CF_HAND(cf_raw_helpfile)
01534 {
01535     UNUSED_PARAMETER(vp);
01536     UNUSED_PARAMETER(pExtra);
01537     UNUSED_PARAMETER(nExtra);
01538 
01539     return add_helpfile(player, cmd, str, true);
01540 }
01541 
01542 // @hook: run softcode before or after running a hardcode command, or softcode access.
01543 // Original idea from TinyMUSH 3, code from RhostMUSH.
01544 // Used with express permission of RhostMUSH developers.
01545 // Bludgeoned into MUX by Jake Nelson 7/2002.
01546 //
01547 static NAMETAB hook_names[] =
01548 {
01549     {"after",      3, 0, HOOK_AFTER},
01550     {"before",     3, 0, HOOK_BEFORE},
01551     {"fail",       3, 0, HOOK_AFAIL},
01552     {"ignore",     3, 0, HOOK_IGNORE},
01553     {"igswitch",   3, 0, HOOK_IGSWITCH},
01554     {"permit",     3, 0, HOOK_PERMIT},
01555     {NULL,         0, 0, 0}
01556 };
01557 
01558 static CF_HAND(cf_hook)
01559 {
01560     UNUSED_PARAMETER(pExtra);
01561     UNUSED_PARAMETER(nExtra);
01562     UNUSED_PARAMETER(player);
01563     UNUSED_PARAMETER(cmd);
01564 
01565     char *hookcmd, *hookptr, playbuff[201];
01566     int hookflg;
01567     CMDENT *cmdp;
01568 
01569     int retval = -1;
01570     memset(playbuff, '\0', sizeof(playbuff));
01571     strncpy(playbuff, str, 200);
01572     MUX_STRTOK_STATE tts;
01573     mux_strtok_src(&tts, playbuff);
01574     mux_strtok_ctl(&tts, " \t");
01575     hookcmd = mux_strtok_parse(&tts);
01576     if (hookcmd != NULL)
01577     {
01578        cmdp = (CMDENT *)hashfindLEN(hookcmd, strlen(hookcmd), &mudstate.command_htab);
01579     }
01580     else
01581     {
01582        return retval;
01583     }
01584     if (!cmdp)
01585     {
01586        return retval;
01587     }
01588 
01589     *vp = cmdp->hookmask;
01590     strncpy(playbuff, str, 200);
01591     hookptr = mux_strtok_parse(&tts);
01592     while (hookptr != NULL)
01593     {
01594        if (  hookptr[0] == '!'
01595           && hookptr[1] != '\0')
01596        {
01597           if (search_nametab(GOD, hook_names, hookptr+1, &hookflg))
01598           {
01599              retval = 0;
01600              *vp = *vp & ~hookflg;
01601           }
01602        }
01603        else
01604        {
01605           if (search_nametab(GOD, hook_names, hookptr, &hookflg))
01606           {
01607              retval = 0;
01608              *vp = *vp | hookflg;
01609           }
01610        }
01611        hookptr = mux_strtok_parse(&tts);
01612     }
01613     cmdp->hookmask = *vp;
01614     return retval;
01615 }
01616 
01617 // ---------------------------------------------------------------------------
01618 // cf_include: Read another config file.  Only valid during startup.
01619 //
01620 static CF_HAND(cf_include)
01621 {
01622     UNUSED_PARAMETER(vp);
01623     UNUSED_PARAMETER(pExtra);
01624     UNUSED_PARAMETER(nExtra);
01625 
01626     if (!mudstate.bReadingConfiguration)
01627     {
01628         return -1;
01629     }
01630 
01631     FILE *fp = fopen(str, "rb");
01632     if (fp == NULL)
01633     {
01634         cf_log_notfound(player, cmd, "Config file", str);
01635         return -1;
01636     }
01637     DebugTotalFiles++;
01638 
01639     char *buf = alloc_lbuf("cf_include");
01640     fgets(buf, LBUF_SIZE, fp);
01641     while (!feof(fp))
01642     {
01643         char *zp = buf;
01644 
01645         // Remove comments.  Anything after the '#' is a comment except if it
01646         // matches:  whitespace + '#' + digit.
01647         //
01648         while (*zp != '\0')
01649         {
01650             if (  *zp == '#'
01651                && (  zp <= buf
01652                   || !mux_isspace(zp[-1])
01653                   || !mux_isdigit(zp[1])))
01654             {
01655                 // Found a comment.
01656                 //
01657                 *zp = '\0';
01658             }
01659             else
01660             {
01661                 zp++;
01662             }
01663         }
01664 
01665         // Trim trailing spaces.
01666         //
01667         while (  buf < zp
01668               && mux_isspace(zp[-1]))
01669         {
01670             *(--zp) = '\0';
01671         }
01672 
01673         // Process line.
01674         //
01675         char *cp = buf;
01676 
01677         // Trim leading spaces.
01678         //
01679         while (mux_isspace(*cp))
01680         {
01681             cp++;
01682         }
01683 
01684         // Skip over command.
01685         //
01686         char *ap;
01687         for (ap = cp; *ap && !mux_isspace(*ap); ap++)
01688         {
01689             ; // Nothing.
01690         }
01691 
01692         // Terminate command.
01693         //
01694         if (*ap)
01695         {
01696             *ap++ = '\0';
01697         }
01698 
01699         // Skip spaces between command and argument.
01700         //
01701         while (mux_isspace(*ap))
01702         {
01703             ap++;
01704         }
01705 
01706         if (*cp)
01707         {
01708             cf_set(cp, ap, player);
01709         }
01710         fgets(buf, LBUF_SIZE, fp);
01711     }
01712     free_lbuf(buf);
01713     if (fclose(fp) == 0)
01714     {
01715         DebugTotalFiles--;
01716     }
01717     return 0;
01718 }
01719 
01720 // ---------------------------------------------------------------------------
01721 // conftable: Table for parsing the configuration file.
01722 
01723 static CONF conftable[] =
01724 {
01725     {"access",                    cf_access,      CA_GOD,    CA_DISABLED, NULL,                            access_nametab,     0},
01726     {"alias",                     cf_cmd_alias,   CA_GOD,    CA_DISABLED, (int *)&mudstate.command_htab,   0,                  0},
01727     {"allow_guest_from_registered_site", cf_bool, CA_GOD,    CA_WIZARD,   (int *)&mudconf.allow_guest_from_registered_site, NULL,     1},
01728     {"article_rule",              cf_art_rule,    CA_GOD,    CA_DISABLED, (int *)&mudconf.art_rules,       NULL,               0},
01729     {"attr_access",               cf_attr_access, CA_GOD,    CA_DISABLED, NULL,                            attraccess_nametab, 0},
01730     {"attr_alias",                cf_alias,       CA_GOD,    CA_DISABLED, (int *)&mudstate.attr_name_htab, 0,                  0},
01731     {"attr_cmd_access",           cf_acmd_access, CA_GOD,    CA_DISABLED, NULL,                            access_nametab,     0},
01732     {"autozone",                  cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.autozone,        NULL,               0},
01733     {"bad_name",                  cf_badname,     CA_GOD,    CA_DISABLED, NULL,                            NULL,               0},
01734     {"badsite_file",              cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.site_file,       NULL, SIZEOF_PATHNAME},
01735     {"cache_names",               cf_bool,        CA_STATIC, CA_GOD,      (int *)&mudconf.cache_names,     NULL,               0},
01736     {"cache_pages",               cf_int,         CA_STATIC, CA_WIZARD,   &mudconf.cache_pages,            NULL,               0},
01737     {"cache_tick_period",         cf_seconds,     CA_GOD,    CA_WIZARD,   (int *)&mudconf.cache_tick_period, NULL,             0},
01738     {"check_interval",            cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.check_interval,         NULL,               0},
01739     {"check_offset",              cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.check_offset,           NULL,               0},
01740     {"clone_copies_cost",         cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.clone_copy_cost, NULL,               0},
01741     {"command_quota_increment",   cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.cmd_quota_incr,         NULL,               0},
01742     {"command_quota_max",         cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.cmd_quota_max,          NULL,               0},
01743     {"compress_program",          cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.compress,        NULL, SIZEOF_PATHNAME},
01744     {"compression",               cf_bool,        CA_GOD,    CA_GOD,      (int *)&mudconf.compress_db,     NULL,               0},
01745     {"comsys_database",           cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.comsys_db,       NULL, SIZEOF_PATHNAME},
01746     {"config_access",             cf_cf_access,   CA_GOD,    CA_DISABLED, NULL,                            access_nametab,     0},
01747     {"conn_timeout",              cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.conn_timeout,           NULL,               0},
01748     {"connect_file",              cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.conn_file,       NULL, SIZEOF_PATHNAME},
01749     {"connect_reg_file",          cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.creg_file,       NULL, SIZEOF_PATHNAME},
01750     {"lag_limit",                 cf_seconds,     CA_GOD,    CA_WIZARD,   (int *)&mudconf.max_cmdsecs,     NULL,               0},
01751     {"crash_database",            cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.crashdb,         NULL, SIZEOF_PATHNAME},
01752     {"create_max_cost",           cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.createmax,              NULL,               0},
01753     {"create_min_cost",           cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.createmin,              NULL,               0},
01754     {"dark_sleepers",             cf_bool,        CA_GOD,    CA_WIZARD,   (int *)&mudconf.dark_sleepers,   NULL,               0},
01755     {"default_home",              cf_dbref,       CA_GOD,    CA_PUBLIC,   &mudconf.default_home,           NULL,               0},
01756     {"destroy_going_now",         cf_bool,        CA_GOD,    CA_WIZARD,   (int *)&mudconf.destroy_going_now, NULL,               0},
01757     {"dig_cost",                  cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.digcost,                NULL,               0},
01758     {"down_file",                 cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.down_file,       NULL, SIZEOF_PATHNAME},
01759     {"down_motd_message",         cf_string,      CA_GOD,    CA_WIZARD,   (int *)mudconf.downmotd_msg,     NULL,       GBUF_SIZE},
01760     {"dump_interval",             cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.dump_interval,          NULL,               0},
01761     {"dump_message",              cf_string,      CA_GOD,    CA_WIZARD,   (int *)mudconf.dump_msg,         NULL,             128},
01762     {"dump_offset",               cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.dump_offset,            NULL,               0},
01763     {"earn_limit",                cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.paylimit,               NULL,               0},
01764     {"eval_comtitle",             cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.eval_comtitle,   NULL,               0},
01765     {"events_daily_hour",         cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.events_daily_hour,      NULL,               0},
01766     {"examine_flags",             cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.ex_flags,        NULL,               0},
01767     {"examine_public_attrs",      cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.exam_public,     NULL,               0},
01768     {"exit_flags",                cf_set_flags,   CA_GOD,    CA_DISABLED, (int *)&mudconf.exit_flags,      NULL,               0},
01769     {"exit_quota",                cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.exit_quota,             NULL,               0},
01770     {"fascist_teleport",          cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.fascist_tport,   NULL,               0},
01771     {"find_money_chance",         cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.payfind,                NULL,               0},
01772     {"fixed_home_message",        cf_string,      CA_STATIC, CA_PUBLIC,   (int *)mudconf.fixed_home_msg,   NULL,             128},
01773     {"fixed_tel_message",         cf_string,      CA_STATIC, CA_PUBLIC,   (int *)mudconf.fixed_tel_msg,    NULL,             128},
01774     {"flag_access",               cf_flag_access, CA_GOD,    CA_DISABLED, NULL,                            NULL,               0},
01775     {"flag_alias",                cf_flagalias,   CA_GOD,    CA_DISABLED, NULL,                            NULL,               0},
01776     {"flag_name",                 cf_flag_name,   CA_GOD,    CA_DISABLED, NULL,                            NULL,               0},
01777     {"forbid_site",               cf_site,        CA_GOD,    CA_DISABLED, (int *)&mudstate.access_list,    NULL,     H_FORBIDDEN},
01778 #ifndef WIN32
01779     {"fork_dump",                 cf_bool,        CA_GOD,    CA_WIZARD,   (int *)&mudconf.fork_dump,       NULL,               0},
01780 #endif
01781     {"full_file",                 cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.full_file,       NULL, SIZEOF_PATHNAME},
01782     {"full_motd_message",         cf_string,      CA_GOD,    CA_WIZARD,   (int *)mudconf.fullmotd_msg,     NULL,       GBUF_SIZE},
01783     {"function_access",           cf_func_access, CA_GOD,    CA_DISABLED, NULL,                            access_nametab,     0},
01784     {"function_alias",            cf_alias,       CA_GOD,    CA_DISABLED, (int *)&mudstate.func_htab,      NULL,               0},
01785     {"function_invocation_limit", cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.func_invk_lim,          NULL,               0},
01786     {"function_recursion_limit",  cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.func_nest_lim,          NULL,               0},
01787     {"game_dir_file",             cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.game_dir,        NULL, SIZEOF_PATHNAME},
01788     {"game_pag_file",             cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.game_pag,        NULL, SIZEOF_PATHNAME},
01789     {"global_error_obj",          cf_dbref,       CA_GOD,    CA_GOD,      &mudconf.global_error_obj,       NULL,               0},
01790     {"good_name",                 cf_badname,     CA_GOD,    CA_DISABLED, NULL,                            NULL,               1},
01791     {"guest_char_num",            cf_dbref,       CA_STATIC, CA_WIZARD,   &mudconf.guest_char,             NULL,               0},
01792     {"guest_file",                cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.guest_file,      NULL, SIZEOF_PATHNAME},
01793     {"guest_nuker",               cf_dbref,       CA_GOD,    CA_WIZARD,   &mudconf.guest_nuker,            NULL,               0},
01794     {"guest_prefix",              cf_string,      CA_STATIC, CA_PUBLIC,   (int *)mudconf.guest_prefix,     NULL,              32},
01795     {"guest_site",                cf_site,        CA_GOD,    CA_DISABLED, (int *)&mudstate.access_list,    NULL,         H_GUEST},
01796     {"guests_channel",            cf_string,      CA_STATIC, CA_PUBLIC,   (int *)mudconf.guests_channel,   NULL,              32},
01797     {"guests_channel_alias",      cf_string,      CA_STATIC, CA_PUBLIC,   (int *)mudconf.guests_channel_alias, NULL,          32},
01798     {"have_comsys",               cf_bool,        CA_STATIC, CA_PUBLIC,   (int *)&mudconf.have_comsys,     NULL,               0},
01799     {"have_mailer",               cf_bool,        CA_STATIC, CA_PUBLIC,   (int *)&mudconf.have_mailer,     NULL,               0},
01800     {"have_zones",                cf_bool,        CA_STATIC, CA_PUBLIC,   (int *)&mudconf.have_zones,      NULL,               0},
01801     {"helpfile",                  cf_helpfile,    CA_STATIC, CA_DISABLED, NULL,                            NULL,               0},
01802     {"hook_cmd",                  cf_hook,        CA_GOD,    CA_GOD,      &mudconf.hook_cmd,               NULL,               0},
01803     {"hook_obj",                  cf_dbref,       CA_GOD,    CA_GOD,      &mudconf.hook_obj,               NULL,               0},
01804     {"hostnames",                 cf_bool,        CA_GOD,    CA_WIZARD,   (int *)&mudconf.use_hostname,    NULL,               0},
01805     {"idle_interval",             cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.idle_interval,          NULL,               0},
01806     {"idle_timeout",              cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.idle_timeout,           NULL,               0},
01807     {"idle_wiz_dark",             cf_bool,        CA_GOD,    CA_WIZARD,   (int *)&mudconf.idle_wiz_dark,   NULL,               0},
01808     {"include",                   cf_include,     CA_STATIC, CA_DISABLED, NULL,                            NULL,               0},
01809     {"indent_desc",               cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.indent_desc,     NULL,               0},
01810     {"initial_size",              cf_int,         CA_STATIC, CA_WIZARD,   &mudconf.init_size,              NULL,               0},
01811     {"input_database",            cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.indb,            NULL, SIZEOF_PATHNAME},
01812     {"kill_guarantee_cost",       cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.killguarantee,          NULL,               0},
01813     {"kill_max_cost",             cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.killmax,                NULL,               0},
01814     {"kill_min_cost",             cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.killmin,                NULL,               0},
01815     {"lag_maximum",               cf_seconds,     CA_GOD,    CA_WIZARD,   (int *)&mudconf.rpt_cmdsecs,     NULL,               0},
01816     {"link_cost",                 cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.linkcost,               NULL,               0},
01817     {"list_access",               cf_ntab_access, CA_GOD,    CA_DISABLED, (int *)list_names,               access_nametab,     0},
01818     {"lock_recursion_limit",      cf_int,         CA_WIZARD, CA_PUBLIC,   &mudconf.lock_nest_lim,          NULL,               0},
01819     {"log",                       cf_modify_bits, CA_GOD,    CA_DISABLED, &mudconf.log_options,            logoptions_nametab, 0},
01820     {"log_options",               cf_modify_bits, CA_GOD,    CA_DISABLED, &mudconf.log_info,               logdata_nametab,    0},
01821     {"logout_cmd_access",         cf_ntab_access, CA_GOD,    CA_DISABLED, (int *)logout_cmdtable,          access_nametab,     0},
01822     {"logout_cmd_alias",          cf_alias,       CA_GOD,    CA_DISABLED, (int *)&mudstate.logout_cmd_htab,NULL,               0},
01823     {"look_obey_terse",           cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.terse_look,      NULL,               0},
01824     {"machine_command_cost",      cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.machinecost,            NULL,               0},
01825     {"mail_database",             cf_string_dyn,  CA_GOD,    CA_GOD,      (int *)&mudconf.mail_db,         NULL, SIZEOF_PATHNAME},
01826     {"mail_expiration",           cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.mail_expiration,        NULL,               0},
01827     {"mail_per_hour",             cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.mail_per_hour,          NULL,               0},
01828     {"master_room",               cf_dbref,       CA_GOD,    CA_WIZARD,   &mudconf.master_room,            NULL,               0},
01829     {"match_own_commands",        cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.match_mine,      NULL,               0},
01830     {"max_cache_size",            cf_int,         CA_GOD,    CA_GOD,      (int *)&mudconf.max_cache_size,  NULL,               0},
01831     {"max_players",               cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.max_players,            NULL,               0},
01832     {"min_guests",                cf_int,         CA_STATIC, CA_GOD,      (int *)&mudconf.min_guests,      NULL,               0},
01833     {"money_name_plural",         cf_string,      CA_GOD,    CA_PUBLIC,   (int *)mudconf.many_coins,       NULL,              32},
01834     {"money_name_singular",       cf_string,      CA_GOD,    CA_PUBLIC,   (int *)mudconf.one_coin,         NULL,              32},
01835     {"motd_file",                 cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.motd_file,       NULL, SIZEOF_PATHNAME},
01836     {"motd_message",              cf_string,      CA_GOD,    CA_WIZARD,   (int *)mudconf.motd_msg,         NULL,       GBUF_SIZE},
01837     {"mud_name",                  cf_string,      CA_GOD,    CA_PUBLIC,   (int *)mudconf.mud_name,         NULL,              32},
01838     {"newuser_file",              cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.crea_file,       NULL, SIZEOF_PATHNAME},
01839     {"nositemon_site",            cf_site,        CA_GOD,    CA_DISABLED, (int *)&mudstate.access_list,    NULL,     H_NOSITEMON},
01840     {"notify_recursion_limit",    cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.ntfy_nest_lim,          NULL,               0},
01841     {"number_guests",             cf_int,         CA_STATIC, CA_WIZARD,   &mudconf.number_guests,          NULL,               0},
01842     {"open_cost",                 cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.opencost,               NULL,               0},
01843     {"output_database",           cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.outdb,           NULL, SIZEOF_PATHNAME},
01844     {"output_limit",              cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.output_limit,           NULL,               0},
01845     {"page_cost",                 cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.pagecost,               NULL,               0},
01846     {"paranoid_allocate",         cf_bool,        CA_GOD,    CA_WIZARD,   (int *)&mudconf.paranoid_alloc,  NULL,               0},
01847     {"parent_recursion_limit",    cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.parent_nest_lim,        NULL,               0},
01848     {"paycheck",                  cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.paycheck,               NULL,               0},
01849     {"pemit_any_object",          cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.pemit_any,       NULL,               0},
01850     {"pemit_far_players",         cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.pemit_players,   NULL,               0},
01851     {"permit_site",               cf_site,        CA_GOD,    CA_DISABLED, (int *)&mudstate.access_list,    NULL,               0},
01852     {"player_flags",              cf_set_flags,   CA_GOD,    CA_DISABLED, (int *)&mudconf.player_flags,    NULL,               0},
01853     {"player_listen",             cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.player_listen,   NULL,               0},
01854     {"player_match_own_commands", cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.match_mine_pl,   NULL,               0},
01855     {"player_name_spaces",        cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.name_spaces,     NULL,               0},
01856     {"player_queue_limit",        cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.queuemax,               NULL,               0},
01857     {"player_quota",              cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.player_quota,           NULL,               0},
01858     {"player_starting_home",      cf_dbref,       CA_GOD,    CA_PUBLIC,   &mudconf.start_home,             NULL,               0},
01859     {"player_starting_room",      cf_dbref,       CA_GOD,    CA_PUBLIC,   &mudconf.start_room,             NULL,               0},
01860     {"port",                      cf_int_array,   CA_STATIC, CA_PUBLIC,   (int *)&mudconf.ports,           NULL, MAX_LISTEN_PORTS},
01861     {"postdump_message",          cf_string,      CA_GOD,    CA_WIZARD,   (int *)mudconf.postdump_msg,     NULL,             128},
01862     {"power_alias",               cf_poweralias,  CA_GOD,    CA_DISABLED, NULL,                            NULL,               0},
01863     {"pcreate_per_hour",          cf_int,         CA_STATIC, CA_PUBLIC,   (int *)&mudconf.pcreate_per_hour,NULL,               0},
01864     {"public_channel",            cf_string,      CA_STATIC, CA_PUBLIC,   (int *)mudconf.public_channel,   NULL,              32},
01865     {"public_channel_alias",      cf_string,      CA_STATIC, CA_PUBLIC,   (int *)mudconf.public_channel_alias, NULL,          32},
01866     {"public_flags",              cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.pub_flags,       NULL,               0},
01867     {"pueblo_message",            cf_string,      CA_GOD,    CA_WIZARD,   (int *)mudconf.pueblo_msg,       NULL,       GBUF_SIZE},
01868     {"queue_active_chunk",        cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.active_q_chunk,         NULL,               0},
01869     {"queue_idle_chunk",          cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.queue_chunk,            NULL,               0},
01870     {"quiet_look",                cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.quiet_look,      NULL,               0},
01871     {"quiet_whisper",             cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.quiet_whisper,   NULL,               0},
01872     {"quit_file",                 cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.quit_file,       NULL, SIZEOF_PATHNAME},
01873     {"quotas",                    cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.quotas,          NULL,               0},
01874     {"raw_helpfile",              cf_raw_helpfile,CA_STATIC, CA_DISABLED, NULL,                            NULL,               0},
01875     {"read_remote_desc",          cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.read_rem_desc,   NULL,               0},
01876     {"read_remote_name",          cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.read_rem_name,   NULL,               0},
01877     {"register_create_file",      cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.regf_file,       NULL, SIZEOF_PATHNAME},
01878     {"register_site",             cf_site,        CA_GOD,    CA_DISABLED, (int *)&mudstate.access_list,    NULL,  H_REGISTRATION},
01879     {"reset_players",             cf_bool,        CA_GOD,    CA_DISABLED, (int *)&mudconf.reset_players,   NULL,               0},
01880     {"restrict_home",             cf_bool,        CA_GOD,    CA_DISABLED, (int *)&mudconf.restrict_home,   NULL,               0},
01881     {"retry_limit",               cf_int,         CA_GOD,    CA_WIZARD,   &mudconf.retry_limit,            NULL,               0},
01882     {"robot_cost",                cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.robotcost,              NULL,               0},
01883     {"robot_flags",               cf_set_flags,   CA_GOD,    CA_DISABLED, (int *)&mudconf.robot_flags,     NULL,               0},
01884     {"robot_speech",              cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.robot_speak,     NULL,               0},
01885     {"room_flags",                cf_set_flags,   CA_GOD,    CA_DISABLED, (int *)&mudconf.room_flags,      NULL,               0},
01886     {"room_quota",                cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.room_quota,             NULL,               0},
01887     {"run_startup",               cf_bool,        CA_STATIC, CA_WIZARD,   (int *)&mudconf.run_startup,     NULL,               0},
01888     {"sacrifice_adjust",          cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.sacadjust,              NULL,               0},
01889     {"sacrifice_factor",          cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.sacfactor,              NULL,               0},
01890     {"safe_wipe",                 cf_bool,        CA_GOD,    CA_WIZARD,   (int *)&mudconf.safe_wipe,       NULL,               0},
01891     {"safer_passwords",           cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.safer_passwords, NULL,               0},
01892     {"search_cost",               cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.searchcost,             NULL,               0},
01893     {"see_owned_dark",            cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.see_own_dark,    NULL,               0},
01894     {"signal_action",             cf_option,      CA_STATIC, CA_GOD,      &mudconf.sig_action,             sigactions_nametab, 0},
01895     {"site_chars",                cf_int,         CA_GOD,    CA_WIZARD,   (int *)&mudconf.site_chars,      NULL,               0},
01896     {"space_compress",            cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.space_compress,  NULL,               0},
01897     {"stack_limit",               cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.stack_limit,            NULL,               0},
01898     {"starting_money",            cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.paystart,               NULL,               0},
01899     {"starting_quota",            cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.start_quota,            NULL,               0},
01900     {"status_file",               cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.status_file,     NULL, SIZEOF_PATHNAME},
01901     {"suspect_site",              cf_site,        CA_GOD,    CA_DISABLED, (int *)&mudstate.suspect_list,   NULL,       H_SUSPECT},
01902     {"sweep_dark",                cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.sweep_dark,      NULL,               0},
01903     {"switch_default_all",        cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.switch_df_all,   NULL,               0},
01904     {"terse_shows_contents",      cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.terse_contents,  NULL,               0},
01905     {"terse_shows_exits",         cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.terse_exits,     NULL,               0},
01906     {"terse_shows_move_messages", cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.terse_movemsg,   NULL,               0},
01907     {"thing_flags",               cf_set_flags,   CA_GOD,    CA_DISABLED, (int *)&mudconf.thing_flags,     NULL,               0},
01908     {"thing_quota",               cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.thing_quota,            NULL,               0},
01909     {"timeslice",                 cf_seconds,     CA_GOD,    CA_PUBLIC,   (int *)&mudconf.timeslice,       NULL,               0},
01910     {"toad_recipient",            cf_dbref,       CA_GOD,    CA_WIZARD,   &mudconf.toad_recipient,         NULL,               0},
01911     {"trace_output_limit",        cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.trace_limit,            NULL,               0},
01912     {"trace_topdown",             cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.trace_topdown,   NULL,               0},
01913     {"trust_site",                cf_site,        CA_GOD,    CA_DISABLED, (int *)&mudstate.suspect_list,   NULL,               0},
01914     {"uncompress_program",        cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.uncompress,      NULL, SIZEOF_PATHNAME},
01915     {"unowned_safe",              cf_bool,        CA_GOD,    CA_PUBLIC,   (int *)&mudconf.safe_unowned,    NULL,               0},
01916     {"use_http",                  cf_bool,        CA_STATIC, CA_PUBLIC,   (int *)&mudconf.use_http,        NULL,               0},
01917     {"user_attr_access",          cf_modify_bits, CA_GOD,    CA_DISABLED, &mudconf.vattr_flags,            attraccess_nametab, 0},
01918     {"user_attr_per_hour",        cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.vattr_per_hour,         NULL,               0},
01919     {"wait_cost",                 cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.waitcost,               NULL,               0},
01920     {"wizard_motd_file",          cf_string_dyn,  CA_STATIC, CA_GOD,      (int *)&mudconf.wizmotd_file,    NULL, SIZEOF_PATHNAME},
01921     {"wizard_motd_message",       cf_string,      CA_GOD,    CA_WIZARD,   (int *)mudconf.wizmotd_msg,      NULL,       GBUF_SIZE},
01922     {"zone_recursion_limit",      cf_int,         CA_GOD,    CA_PUBLIC,   &mudconf.zone_nest_lim,          NULL,               0},
01923 #ifdef REALITY_LVLS
01924     {"reality_level",             cf_rlevel,      CA_STATIC, CA_GOD,      (int *)&mudconf,                 NULL,               0},
01925     {"def_room_rx",               cf_int,         CA_WIZARD, CA_PUBLIC,   (int *)&mudconf.def_room_rx,     NULL,               0},
01926     {"def_room_tx",               cf_int,         CA_WIZARD, CA_PUBLIC,   (int *)&mudconf.def_room_tx,     NULL,               0},
01927     {"def_player_rx",             cf_int,         CA_WIZARD, CA_PUBLIC,   (int *)&mudconf.def_player_rx,   NULL,               0},
01928     {"def_player_tx",             cf_int,         CA_WIZARD, CA_PUBLIC,   (int *)&mudconf.def_player_tx,   NULL,               0},
01929     {"def_exit_rx",               cf_int,         CA_WIZARD, CA_PUBLIC,   (int *)&mudconf.def_exit_rx,     NULL,               0},
01930     {"def_exit_tx",               cf_int,         CA_WIZARD, CA_PUBLIC,   (int *)&mudconf.def_exit_tx,     NULL,               0},
01931     {"def_thing_rx",              cf_int,         CA_WIZARD, CA_PUBLIC,   (int *)&mudconf.def_thing_rx,    NULL,               0},
01932     {"def_thing_tx",              cf_int,         CA_WIZARD, CA_PUBLIC,   (int *)&mudconf.def_thing_tx,    NULL,               0},
01933 #endif /* REALITY_LVLS */
01934     { NULL,                       NULL,           0,         0,           NULL,                            NULL,               0}
01935 };
01936 
01937 // ---------------------------------------------------------------------------
01938 // cf_cf_access: Set access on config directives
01939 //
01940 CF_HAND(cf_cf_access)
01941 {
01942     UNUSED_PARAMETER(vp);
01943 
01944     CONF *tp;
01945     char *ap;
01946 
01947     for (ap = str; *ap && !mux_isspace(*ap); ap++)
01948     {
01949         ; // Nothing
01950     }
01951     if (*ap)
01952     {
01953         *ap++ = '\0';
01954     }
01955 
01956     for (tp = conftable; tp->pname; tp++)
01957     {
01958         if (!strcmp(tp->pname, str))
01959         {
01960             // Cannot modify parameters set CA_STATIC.
01961             //
01962             if (  tp->flags & CA_STATIC
01963                && !mudstate.bReadingConfiguration)
01964             {
01965                 notify(player, NOPERM_MESSAGE);
01966                 STARTLOG(LOG_CONFIGMODS, "CFG", "PERM");
01967                 log_name(player);
01968                 log_text(" tried to change access to static param: ");
01969                 log_text(tp->pname);
01970                 ENDLOG;
01971                 return -1;
01972             }
01973             return cf_modify_bits(&tp->flags, ap, pExtra, nExtra, player, cmd);
01974         }
01975     }
01976     cf_log_notfound(player, cmd, "Config directive", str);
01977     return -1;
01978 }
01979 
01980 // ---------------------------------------------------------------------------
01981 // cf_set: Set config parameter.
01982 //
01983 int cf_set(char *cp, char *ap, dbref player)
01984 {
01985     CONF *tp;
01986     int i;
01987     char *buff = 0;
01988 
01989     // Search the config parameter table for the command. If we find
01990     // it, call the handler to parse the argument.
01991     //
01992     for (tp = conftable; tp->pname; tp++)
01993     {
01994         if (!strcmp(tp->pname, cp))
01995         {
01996             if (  !mudstate.bReadingConfiguration
01997                && !check_access(player, tp->flags))
01998             {
01999                 notify(player, NOPERM_MESSAGE);
02000                 return -1;
02001             }
02002             if (!mudstate.bReadingConfiguration)
02003             {
02004                 buff = alloc_lbuf("cf_set");
02005                 strcpy(buff, ap);
02006             }
02007             i = tp->interpreter(tp->loc, ap, tp->pExtra, tp->nExtra, player, cp);
02008             if (!mudstate.bReadingConfiguration)
02009             {
02010                 STARTLOG(LOG_CONFIGMODS, "CFG", "UPDAT");
02011                 log_name(player);
02012                 log_text(" entered config directive: ");
02013                 log_text(cp);
02014                 log_text(" with args '");
02015                 log_text(buff);
02016                 log_text("'.  Status: ");
02017                 switch (i)
02018                 {
02019                 case 0:
02020                     log_text("Success.");
02021                     break;
02022 
02023                 case 1:
02024                     log_text("Partial success.");
02025                     break;
02026 
02027                 case -1:
02028                     log_text("Failure.");
02029                     break;
02030 
02031                 default:
02032                     log_text("Strange.");
02033                 }
02034                 ENDLOG;
02035                 free_lbuf(buff);
02036             }
02037             return i;
02038         }
02039     }
02040 
02041     // Config directive not found.  Complain about it.
02042     //
02043     cf_log_notfound(player, "Set", "Config directive", cp);
02044     return -1;
02045 }
02046 
02047 // Validate important dbrefs.
02048 //
02049 void ValidateConfigurationDbrefs(void)
02050 {
02051     static dbref *Table[] =
02052     {
02053         &mudconf.default_home,
02054         &mudconf.guest_char,
02055         &mudconf.guest_nuker,
02056         &mudconf.master_room,
02057         &mudconf.start_home,
02058         &mudconf.start_room,
02059         0
02060     };
02061 
02062     for (int i = 0; Table[i]; i++)
02063     {
02064         if (*Table[i] != NOTHING)
02065         {
02066             if (*Table[i] < 0 || mudstate.db_top <= *Table[i])
02067             {
02068                 *Table[i] = NOTHING;
02069             }
02070         }
02071     }
02072 }
02073 
02074 // ---------------------------------------------------------------------------
02075 // do_admin: Command handler to set config params at runtime
02076 //
02077 void do_admin
02078 (
02079     dbref executor,
02080     dbref caller,
02081     dbref enactor,
02082     int   extra,
02083     int   nargs,
02084     char *kw,
02085     char *value
02086 )
02087 {
02088     UNUSED_PARAMETER(caller);
02089     UNUSED_PARAMETER(enactor);
02090     UNUSED_PARAMETER(extra);
02091     UNUSED_PARAMETER(nargs);
02092 
02093     int i = cf_set(kw, value, executor);
02094     if ((i >= 0) && !Quiet(executor))
02095     {
02096         notify(executor, "Set.");
02097     }
02098     ValidateConfigurationDbrefs();
02099 }
02100 
02101 // ---------------------------------------------------------------------------
02102 // cf_read: Read in config parameters from named file
02103 //
02104 static struct
02105 {
02106     char **pFilename;
02107     char *pSuffix;
02108 } DefaultSuffixes[]
02109 =
02110 {
02111     { &mudconf.outdb,    ".out" },
02112     { &mudconf.crashdb,  ".CRASH" },
02113     { &mudconf.game_dir, ".dir" },
02114     { &mudconf.game_pag, ".pag" },
02115     { 0, 0 }
02116 };
02117 
02118 int cf_read(void)
02119 {
02120     int retval;
02121 
02122     mudstate.bReadingConfiguration = true;
02123     retval = cf_include(NULL, mudconf.config_file, (void *)0, 0, 0, "init");
02124     mudstate.bReadingConfiguration = false;
02125 
02126     // Fill in missing DB file names.
02127     //
02128     unsigned int nInDB = strlen(mudconf.indb);
02129     for (int i = 0; DefaultSuffixes[i].pFilename; i++)
02130     {
02131         char **p = DefaultSuffixes[i].pFilename;
02132         if (**p == '\0')
02133         {
02134             // The filename is an empty string so we should construct
02135             // a default filename.
02136             //
02137             char *pSuffix = DefaultSuffixes[i].pSuffix;
02138             int nSuffix = strlen(pSuffix);
02139             char *buff = (char *)MEMALLOC(nInDB + nSuffix + 1);
02140             ISOUTOFMEMORY(buff);
02141             memcpy(buff, mudconf.indb, nInDB);
02142             memcpy(buff + nInDB, pSuffix, nSuffix+1);
02143             MEMFREE(*p);
02144             *p = buff;
02145         }
02146     }
02147     return retval;
02148 }
02149 
02150 // ---------------------------------------------------------------------------
02151 // list_cf_access: List access to config directives.
02152 //
02153 void list_cf_access(dbref player)
02154 {
02155     CONF *tp;
02156     char *buff;
02157 
02158     buff = alloc_mbuf("list_cf_access");
02159     for (tp = conftable; tp->pname; tp++)
02160     {
02161         if (God(player) || check_access(player, tp->flags))
02162         {
02163             sprintf(buff, "%s:", tp->pname);
02164             listset_nametab(player, access_nametab, tp->flags, buff, true);
02165         }
02166     }
02167     free_mbuf(buff);
02168 }
02169 
02170 // ---------------------------------------------------------------------------
02171 // cf_display: Given a config parameter by name, return its value in some
02172 // sane fashion.
02173 //
02174 void cf_display(dbref player, char *param_name, char *buff, char **bufc)
02175 {
02176     CONF *tp;
02177 
02178     for (tp = conftable; tp->pname; tp++)
02179     {
02180         if (!mux_stricmp(tp->pname, param_name))
02181         {
02182             if (check_access(player, tp->rperms))
02183             {
02184                 if (tp->interpreter == cf_int)
02185                 {
02186                     safe_ltoa(*(tp->loc), buff, bufc);
02187                     return;
02188                 }
02189                 else if (tp->interpreter == cf_dbref)
02190                 {
02191                     safe_chr('#', buff, bufc);
02192                     safe_ltoa(*(tp->loc), buff, bufc);
02193                     return;
02194                 }
02195                 else if (tp->interpreter == cf_bool)
02196                 {
02197                     bool *pb = (bool *)tp->loc;
02198                     safe_bool(*pb, buff, bufc);
02199                     return;
02200                 }
02201                 else if (tp->interpreter == cf_string)
02202                 {
02203                     safe_str((char *)tp->loc, buff, bufc);
02204                     return;
02205                 }
02206                 else if (tp->interpreter == cf_string_dyn)
02207                 {
02208                     safe_str(*(char **)tp->loc, buff, bufc);
02209                     return;
02210                 }
02211                 else if (tp->interpreter == cf_int_array)
02212                 {
02213                     IntArray *pia = (IntArray *)(tp->loc);
02214                     ITL itl;
02215                     ItemToList_Init(&itl, buff, bufc);
02216                     for (int i = 0; i < pia->n; i++)
02217                     {
02218                         if (!ItemToList_AddInteger(&itl, pia->pi[i]))
02219                         {
02220                             break;
02221                         }
02222                     }
02223                     ItemToList_Final(&itl);
02224                     return;
02225                 }
02226                 else if (tp->interpreter == cf_seconds)
02227                 {
02228                     CLinearTimeDelta *pltd = (CLinearTimeDelta *)(tp->loc);
02229                     safe_str(pltd->ReturnSecondsString(7), buff, bufc);
02230                     return;
02231                 }
02232             }
02233             safe_noperm(buff, bufc);
02234             return;
02235         }
02236     }
02237     safe_nomatch(buff, bufc);
02238 }
02239 
02240 // ---------------------------------------------------------------------------
02241 // cf_list: List all config options the player can read.
02242 //
02243 void cf_list(dbref player, char *buff, char **bufc)
02244 {
02245     CONF *tp;
02246     ITL itl;
02247     ItemToList_Init(&itl, buff, bufc);
02248 
02249     for (tp = conftable; tp->pname; tp++)
02250     {
02251         if (check_access(player, tp->rperms))
02252         {
02253             if (!ItemToList_AddString(&itl, tp->pname))
02254             {
02255                 break;
02256             }
02257         }
02258     }
02259     ItemToList_Final(&itl);
02260     return;
02261 }

Generated on Mon May 28 04:40:08 2007 for MUX by  doxygen 1.4.7