mux/src/db.cpp

Go to the documentation of this file.
00001 // db.cpp
00002 //
00003 // $Id: db.cpp,v 1.81 2006/09/05 23:42:17 sdennis Exp $
00004 //
00005 // MUX 2.4
00006 // Copyright (C) 1998 through 2004 Solid Vertical Domains, Ltd. All
00007 // rights not explicitly given are reserved.
00008 //
00009 #include "copyright.h"
00010 #include "autoconf.h"
00011 #include "config.h"
00012 #include "externs.h"
00013 
00014 #include "attrs.h"
00015 #include "command.h"
00016 #include "comsys.h"
00017 #include "interface.h"
00018 #include "powers.h"
00019 #include "vattr.h"
00020 #include "ansi.h"
00021 
00022 #ifndef O_ACCMODE
00023 #define O_ACCMODE   (O_RDONLY|O_WRONLY|O_RDWR)
00024 #endif // O_ACCMODE
00025 
00026 OBJ *db = NULL;
00027 
00028 typedef struct atrcount ATRCOUNT;
00029 struct atrcount
00030 {
00031     dbref thing;
00032     int count;
00033 };
00034 
00035 // list of attributes
00036 //
00037 ATTR attr[] =
00038 {
00039     {"Aahear",      A_AAHEAR,   AF_ODARK | AF_NOPROG},
00040     {"Aclone",      A_ACLONE,   AF_ODARK | AF_NOPROG},
00041     {"Aconnect",    A_ACONNECT, AF_ODARK | AF_NOPROG},
00042     {"Adesc",       A_ADESC,    AF_ODARK | AF_NOPROG},
00043     {"Adfail",      A_ADFAIL,   AF_ODARK | AF_NOPROG},
00044     {"Adisconnect", A_ADISCONNECT, AF_ODARK | AF_NOPROG},
00045     {"Adrop",       A_ADROP,    AF_ODARK | AF_NOPROG},
00046     {"Aefail",      A_AEFAIL,   AF_ODARK | AF_NOPROG},
00047     {"Aenter",      A_AENTER,   AF_ODARK | AF_NOPROG},
00048     {"Afail",       A_AFAIL,    AF_ODARK | AF_NOPROG},
00049     {"Agfail",      A_AGFAIL,   AF_ODARK | AF_NOPROG},
00050     {"Ahear",       A_AHEAR,    AF_ODARK | AF_NOPROG},
00051     {"Akill",       A_AKILL,    AF_ODARK | AF_NOPROG},
00052     {"Aleave",      A_ALEAVE,   AF_ODARK | AF_NOPROG},
00053     {"Alfail",      A_ALFAIL,   AF_ODARK | AF_NOPROG},
00054     {"Alias",       A_ALIAS,    AF_NOPROG | AF_NOCMD | AF_NOCLONE | AF_PRIVATE | AF_CONST | AF_VISUAL},
00055     {"Allowance",   A_ALLOWANCE, AF_MDARK | AF_NOPROG | AF_WIZARD},
00056     {"Amail",       A_AMAIL,    AF_ODARK | AF_NOPROG},
00057     {"Amhear",      A_AMHEAR,   AF_ODARK | AF_NOPROG},
00058     {"Amove",       A_AMOVE,    AF_ODARK | AF_NOPROG},
00059     {"Apay",        A_APAY,     AF_ODARK | AF_NOPROG},
00060     {"Arfail",      A_ARFAIL,   AF_ODARK | AF_NOPROG},
00061     {"Asucc",       A_ASUCC,    AF_ODARK | AF_NOPROG},
00062     {"Atfail",      A_ATFAIL,   AF_ODARK | AF_NOPROG},
00063     {"Atport",      A_ATPORT,   AF_ODARK | AF_NOPROG},
00064     {"Atofail",     A_ATOFAIL,  AF_ODARK | AF_NOPROG},
00065     {"Aufail",      A_AUFAIL,   AF_ODARK | AF_NOPROG},
00066     {"Ause",        A_AUSE,     AF_ODARK | AF_NOPROG},
00067     {"Away",        A_AWAY,     AF_ODARK | AF_NOPROG},
00068     {"Charges",     A_CHARGES,  AF_ODARK | AF_NOPROG},
00069     {"CmdCheck",    A_CMDCHECK, AF_DARK | AF_NOPROG | AF_NOCMD | AF_NOCLONE | AF_PRIVATE | AF_CONST},
00070     {"Comment",     A_COMMENT,  AF_MDARK | AF_WIZARD},
00071     {"ConFormat",   A_CONFORMAT, AF_ODARK | AF_NOPROG},
00072     {"Cost",        A_COST,     AF_ODARK | AF_NOPROG},
00073     {"Created",     A_CREATED,  AF_GOD | AF_VISUAL | AF_NOPROG | AF_NOCMD},
00074     {"Daily",       A_DAILY,    AF_ODARK | AF_NOPROG},
00075     {"Desc",        A_DESC,     AF_VISUAL | AF_NOPROG},
00076     {"DefaultLock", A_LOCK,     AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00077     {"DescFormat",  A_DESCFORMAT, AF_ODARK | AF_NOPROG},
00078     {"Destroyer",   A_DESTROYER, AF_MDARK | AF_WIZARD | AF_NOPROG},
00079     {"Dfail",       A_DFAIL,    AF_ODARK | AF_NOPROG},
00080     {"Drop",        A_DROP,     AF_ODARK | AF_NOPROG},
00081     {"DropLock",    A_LDROP,    AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00082     {"Ealias",      A_EALIAS,   AF_ODARK | AF_NOPROG},
00083     {"Efail",       A_EFAIL,    AF_ODARK | AF_NOPROG},
00084     {"Enter",       A_ENTER,    AF_ODARK | AF_NOPROG},
00085     {"EnterLock",   A_LENTER,   AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00086     {"ExitFormat",  A_EXITFORMAT, AF_ODARK | AF_NOPROG},
00087     {"ExitTo",      A_EXITVARDEST, AF_ODARK | AF_NOPROG | AF_WIZARD},
00088     {"Fail",        A_FAIL,     AF_ODARK | AF_NOPROG},
00089     {"Filter",      A_FILTER,   AF_ODARK | AF_NOPROG},
00090     {"Forwardlist", A_FORWARDLIST, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_CONST},
00091     {"GetFromLock", A_LGET,     AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00092     {"Gfail",       A_GFAIL,    AF_ODARK | AF_NOPROG},
00093     {"GiveLock",    A_LGIVE,    AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00094     {"Idesc",       A_IDESC,    AF_ODARK | AF_NOPROG},
00095     {"Idle",        A_IDLE,     AF_ODARK | AF_NOPROG},
00096     {"IdleTimeout", A_IDLETMOUT, AF_ODARK | AF_NOPROG},
00097     {"Infilter",    A_INFILTER, AF_ODARK | AF_NOPROG},
00098     {"Inprefix",    A_INPREFIX, AF_ODARK | AF_NOPROG},
00099     {"Kill",        A_KILL,     AF_ODARK | AF_NOPROG},
00100     {"Lalias",      A_LALIAS,   AF_ODARK | AF_NOPROG},
00101     {"Last",        A_LAST,     AF_WIZARD | AF_NOCMD | AF_NOPROG | AF_NOCLONE},
00102     {"Lastpage",    A_LASTPAGE, AF_INTERNAL | AF_NOCMD | AF_NOPROG | AF_GOD | AF_PRIVATE},
00103     {"Lastsite",    A_LASTSITE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_NOCLONE | AF_GOD},
00104     {"LastIP",      A_LASTIP,   AF_ODARK | AF_NOPROG | AF_NOCMD | AF_GOD},
00105     {"Leave",       A_LEAVE,    AF_ODARK | AF_NOPROG},
00106     {"LeaveLock",   A_LLEAVE,   AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00107     {"Lfail",       A_LFAIL,    AF_ODARK | AF_NOPROG},
00108     {"LinkLock",    A_LLINK,    AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00109     {"Listen",      A_LISTEN,   AF_ODARK | AF_NOPROG},
00110     {"Logindata",   A_LOGINDATA, AF_MDARK | AF_NOPROG | AF_NOCMD | AF_CONST},
00111     {"Mailcurf",    A_MAILCURF, AF_MDARK | AF_WIZARD | AF_NOPROG | AF_NOCLONE},
00112     {"Mailflags",   A_MAILFLAGS, AF_MDARK | AF_WIZARD | AF_NOPROG | AF_NOCLONE},
00113     {"Mailfolders", A_MAILFOLDERS, AF_MDARK | AF_WIZARD | AF_NOPROG | AF_NOCLONE},
00114     {"MailLock",    A_LMAIL,    AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00115     {"Mailmsg",     A_MAILMSG,  AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL},
00116     {"Mailsub",     A_MAILSUB,  AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL},
00117     {"Mailsucc",    A_MAIL,     AF_ODARK | AF_NOPROG},
00118     {"Mailto",      A_MAILTO,   AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL},
00119     {"Mfail",       A_MFAIL,    AF_ODARK | AF_NOPROG},
00120     {"Modified",    A_MODIFIED, AF_GOD | AF_VISUAL | AF_NOPROG | AF_NOCMD},
00121     {"Moniker",     A_MONIKER,  AF_ODARK | AF_NOPROG | AF_NOCMD | AF_CONST},
00122     {"Move",        A_MOVE,     AF_ODARK | AF_NOPROG},
00123     {"Name",        A_NAME,     AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL},
00124     {"NameFormat",  A_NAMEFORMAT, AF_ODARK | AF_NOPROG | AF_WIZARD},
00125     {"Odesc",       A_ODESC,    AF_ODARK | AF_NOPROG},
00126     {"Odfail",      A_ODFAIL,   AF_ODARK | AF_NOPROG},
00127     {"Odrop",       A_ODROP,    AF_ODARK | AF_NOPROG},
00128     {"Oefail",      A_OEFAIL,   AF_ODARK | AF_NOPROG},
00129     {"Oenter",      A_OENTER,   AF_ODARK | AF_NOPROG},
00130     {"Ofail",       A_OFAIL,    AF_ODARK | AF_NOPROG},
00131     {"Ogfail",      A_OGFAIL,   AF_ODARK | AF_NOPROG},
00132     {"Okill",       A_OKILL,    AF_ODARK | AF_NOPROG},
00133     {"Oleave",      A_OLEAVE,   AF_ODARK | AF_NOPROG},
00134     {"Olfail",      A_OLFAIL,   AF_ODARK | AF_NOPROG},
00135     {"Omove",       A_OMOVE,    AF_ODARK | AF_NOPROG},
00136     {"Opay",        A_OPAY,     AF_ODARK | AF_NOPROG},
00137     {"OpenLock",    A_LOPEN,    AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00138     {"Orfail",      A_ORFAIL,   AF_ODARK | AF_NOPROG},
00139     {"Osucc",       A_OSUCC,    AF_ODARK | AF_NOPROG},
00140     {"Otfail",      A_OTFAIL,   AF_ODARK | AF_NOPROG},
00141     {"Otport",      A_OTPORT,   AF_ODARK | AF_NOPROG},
00142     {"Otofail",     A_OTOFAIL,  AF_ODARK | AF_NOPROG},
00143     {"Oufail",      A_OUFAIL,   AF_ODARK | AF_NOPROG},
00144     {"Ouse",        A_OUSE,     AF_ODARK | AF_NOPROG},
00145     {"Oxenter",     A_OXENTER,  AF_ODARK | AF_NOPROG},
00146     {"Oxleave",     A_OXLEAVE,  AF_ODARK | AF_NOPROG},
00147     {"Oxtport",     A_OXTPORT,  AF_ODARK | AF_NOPROG},
00148     {"PageLock",    A_LPAGE,    AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00149     {"ParentLock",  A_LPARENT,  AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00150     {"Pay",         A_PAY,      AF_ODARK | AF_NOPROG},
00151     {"Prefix",      A_PREFIX,   AF_ODARK | AF_NOPROG},
00152     {"ProgCmd",     A_PROGCMD,  AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL},
00153     {"QueueMax",    A_QUEUEMAX, AF_MDARK | AF_WIZARD | AF_NOPROG},
00154     {"Quota",       A_QUOTA,    AF_MDARK | AF_NOPROG | AF_GOD | AF_NOCMD | AF_NOCLONE},
00155     {"ReceiveLock", A_LRECEIVE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00156     {"Reject",      A_REJECT,   AF_ODARK | AF_NOPROG},
00157     {"Rfail",       A_RFAIL,    AF_ODARK | AF_NOPROG},
00158     {"Rquota",      A_RQUOTA,   AF_MDARK | AF_NOPROG | AF_GOD | AF_NOCMD | AF_NOCLONE},
00159     {"Runout",      A_RUNOUT,   AF_ODARK | AF_NOPROG},
00160     {"SayString",   A_SAYSTRING, AF_ODARK | AF_NOPROG},
00161     {"Semaphore",   A_SEMAPHORE, AF_ODARK | AF_NOPROG | AF_WIZARD | AF_NOCMD | AF_NOCLONE},
00162     {"Sex",         A_SEX,      AF_VISUAL | AF_NOPROG},
00163     {"Signature",   A_SIGNATURE, AF_ODARK | AF_NOPROG},
00164     {"SpeechMod",   A_SPEECHMOD, AF_ODARK | AF_NOPROG},
00165     {"SpeechLock",  A_LSPEECH,  AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00166     {"Startup",     A_STARTUP,  AF_ODARK | AF_NOPROG},
00167     {"Succ",        A_SUCC,     AF_ODARK | AF_NOPROG},
00168     {"TeloutLock",  A_LTELOUT,  AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00169     {"Tfail",       A_TFAIL,    AF_ODARK | AF_NOPROG},
00170     {"Timeout",     A_TIMEOUT,  AF_MDARK | AF_NOPROG | AF_WIZARD},
00171     {"Tport",       A_TPORT,    AF_ODARK | AF_NOPROG},
00172     {"TportLock",   A_LTPORT,   AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00173     {"Tofail",      A_TOFAIL,   AF_ODARK | AF_NOPROG},
00174     {"Ufail",       A_UFAIL,    AF_ODARK | AF_NOPROG},
00175     {"Use",         A_USE,      AF_ODARK | AF_NOPROG},
00176     {"UseLock",     A_LUSE,     AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00177     {"UserLock",    A_LUSER,    AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK},
00178     {"VA",          A_VA,       AF_ODARK},
00179     {"VB",          A_VA + 1,   AF_ODARK},
00180     {"VC",          A_VA + 2,   AF_ODARK},
00181     {"VD",          A_VA + 3,   AF_ODARK},
00182     {"VE",          A_VA + 4,   AF_ODARK},
00183     {"VF",          A_VA + 5,   AF_ODARK},
00184     {"VG",          A_VA + 6,   AF_ODARK},
00185     {"VH",          A_VA + 7,   AF_ODARK},
00186     {"VI",          A_VA + 8,   AF_ODARK},
00187     {"VJ",          A_VA + 9,   AF_ODARK},
00188     {"VK",          A_VA + 10,  AF_ODARK},
00189     {"VL",          A_VA + 11,  AF_ODARK},
00190     {"VM",          A_VA + 12,  AF_ODARK},
00191     {"VN",          A_VA + 13,  AF_ODARK},
00192     {"VO",          A_VA + 14,  AF_ODARK},
00193     {"VP",          A_VA + 15,  AF_ODARK},
00194     {"VQ",          A_VA + 16,  AF_ODARK},
00195     {"VR",          A_VA + 17,  AF_ODARK},
00196     {"VS",          A_VA + 18,  AF_ODARK},
00197     {"VT",          A_VA + 19,  AF_ODARK},
00198     {"VU",          A_VA + 20,  AF_ODARK},
00199     {"VV",          A_VA + 21,  AF_ODARK},
00200     {"VW",          A_VA + 22,  AF_ODARK},
00201     {"VX",          A_VA + 23,  AF_ODARK},
00202     {"VY",          A_VA + 24,  AF_ODARK},
00203     {"VZ",          A_VA + 25,  AF_ODARK},
00204     {"VRML_URL",    A_VRML_URL, AF_ODARK | AF_NOPROG},
00205     {"HTDesc",      A_HTDESC,   AF_NOPROG},
00206     // Added by D.Piper (del@doofer.org) 2000-APR
00207     //
00208     {"Reason",      A_REASON,   AF_PRIVATE | AF_MDARK | AF_NOPROG | AF_NOCMD | AF_GOD},
00209 #ifdef GAME_DOOFERMUX
00210     {"RegInfo",     A_REGINFO,  AF_PRIVATE | AF_MDARK | AF_NOPROG | AF_NOCMD | AF_WIZARD},
00211 #endif // GAME_DOOFERMUX
00212     {"ConnInfo",    A_CONNINFO, AF_PRIVATE | AF_MDARK | AF_NOPROG | AF_NOCMD | AF_GOD},
00213     {"*Password",   A_PASS,     AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL},
00214     {"*Privileges", A_PRIVS,    AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL},
00215     {"*Money",      A_MONEY,    AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL},
00216 #ifdef REALITY_LVLS
00217     {"Rlevel",         A_RLEVEL,        AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL},
00218 #endif /* REALITY_LVLS */
00219     {NULL,          0,          0}
00220 };
00221 
00222 char *aszSpecialDBRefNames[1-NOPERM] =
00223 {
00224     "", "*NOTHING*", "*AMBIGUOUS*", "*HOME*", "*NOPERMISSION*"
00225 };
00226 
00227 /* ---------------------------------------------------------------------------
00228  * fwdlist_set, fwdlist_clr: Manage cached forwarding lists
00229  */
00230 
00231 void fwdlist_set(dbref thing, FWDLIST *ifp)
00232 {
00233     FWDLIST *fp, *xfp;
00234     int i;
00235 
00236     // If fwdlist is null, clear.
00237     //
00238     if (!ifp || (ifp->count <= 0))
00239     {
00240         fwdlist_clr(thing);
00241         return;
00242     }
00243 
00244     // Copy input forwardlist to a correctly-sized buffer.
00245     //
00246     fp = (FWDLIST *)MEMALLOC(sizeof(int) * ((ifp->count) + 1));
00247     ISOUTOFMEMORY(fp);
00248 
00249     for (i = 0; i < ifp->count; i++)
00250     {
00251         fp->data[i] = ifp->data[i];
00252     }
00253     fp->count = ifp->count;
00254 
00255     // Replace an existing forwardlist, or add a new one.
00256     //
00257     xfp = fwdlist_get(thing);
00258     if (xfp)
00259     {
00260         MEMFREE(xfp);
00261         xfp = NULL;
00262         hashreplLEN(&thing, sizeof(thing), fp, &mudstate.fwdlist_htab);
00263     }
00264     else
00265     {
00266         hashaddLEN(&thing, sizeof(thing), fp, &mudstate.fwdlist_htab);
00267     }
00268 }
00269 
00270 void fwdlist_clr(dbref thing)
00271 {
00272     // If a forwardlist exists, delete it
00273     //
00274     FWDLIST *xfp = fwdlist_get(thing);
00275     if (xfp)
00276     {
00277         MEMFREE(xfp);
00278         xfp = NULL;
00279         hashdeleteLEN(&thing, sizeof(thing), &mudstate.fwdlist_htab);
00280     }
00281 }
00282 
00283 /* ---------------------------------------------------------------------------
00284  * fwdlist_load: Load text into a forwardlist.
00285  */
00286 
00287 int fwdlist_load(FWDLIST *fp, dbref player, char *atext)
00288 {
00289     dbref target;
00290     char *tp, *bp, *dp;
00291     bool fail;
00292 
00293     int count = 0;
00294     int errors = 0;
00295     bp = tp = alloc_lbuf("fwdlist_load.str");
00296     strcpy(tp, atext);
00297     do
00298     {
00299         // Skip spaces.
00300         //
00301         for (; mux_isspace(*bp); bp++)
00302         {
00303             ; // Nothing.
00304         }
00305 
00306         // Remember string.
00307         //
00308         for (dp = bp; *bp && !mux_isspace(*bp); bp++)
00309         {
00310             ; // Nothing.
00311         }
00312 
00313         // Terminate string.
00314         //
00315         if (*bp)
00316         {
00317             *bp++ = '\0';
00318         }
00319 
00320         if (  *dp++ == '#'
00321            && mux_isdigit(*dp))
00322         {
00323             target = mux_atol(dp);
00324             if (mudstate.bStandAlone)
00325             {
00326                 fail = !Good_obj(target);
00327             }
00328             else
00329             {
00330                 fail = (  !Good_obj(target)
00331                        || (  !God(player)
00332                           && !Controls(player, target)
00333                           && (  !Link_ok(target)
00334                              || !could_doit(player, target, A_LLINK))));
00335             }
00336             if (fail)
00337             {
00338                 if (!mudstate.bStandAlone)
00339                 {
00340                     notify(player,
00341                         tprintf("Cannot forward to #%d: Permission denied.",
00342                         target));
00343                 }
00344                 errors++;
00345             }
00346             else
00347             {
00348                 if (count < 1000)
00349                 {
00350                     fp->data[count++] = target;
00351                 }
00352             }
00353         }
00354     } while (*bp);
00355     free_lbuf(tp);
00356     fp->count = count;
00357     return errors;
00358 }
00359 
00360 /* ---------------------------------------------------------------------------
00361  * fwdlist_rewrite: Generate a text string from a FWDLIST buffer.
00362  */
00363 
00364 int fwdlist_rewrite(FWDLIST *fp, char *atext)
00365 {
00366     int count = 0;
00367     atext[0] = '\0';
00368 
00369     if (fp && fp->count)
00370     {
00371         char *bp = atext;
00372         ITL pContext;
00373         ItemToList_Init(&pContext, atext, &bp, '#');
00374         for (int i = 0; i < fp->count; i++)
00375         {
00376             if (  Good_obj(fp->data[i])
00377                && ItemToList_AddInteger(&pContext, fp->data[i]))
00378             {
00379                 count++;
00380             }
00381         }
00382         ItemToList_Final(&pContext);
00383     }
00384     return count;
00385 }
00386 
00387 /* ---------------------------------------------------------------------------
00388  * fwdlist_ck:  Check a list of dbref numbers to forward to for AUDIBLE
00389  */
00390 bool fwdlist_ck(dbref player, dbref thing, int anum, char *atext)
00391 {
00392     UNUSED_PARAMETER(anum);
00393 
00394     if (mudstate.bStandAlone)
00395     {
00396         return true;
00397     }
00398 
00399     FWDLIST *fp;
00400     int count = 0;
00401 
00402     if (atext && *atext)
00403     {
00404         fp = (FWDLIST *) alloc_lbuf("fwdlist_ck.fp");
00405         fwdlist_load(fp, player, atext);
00406     }
00407     else
00408     {
00409         fp = NULL;
00410     }
00411 
00412     // Set the cached forwardlist.
00413     //
00414     fwdlist_set(thing, fp);
00415     count = fwdlist_rewrite(fp, atext);
00416     if (fp)
00417     {
00418         free_lbuf(fp);
00419     }
00420     return ((count > 0) || !atext || !*atext);
00421 }
00422 
00423 FWDLIST *fwdlist_get(dbref thing)
00424 {
00425     static FWDLIST *fp = NULL;
00426     if (mudstate.bStandAlone)
00427     {
00428         if (!fp)
00429         {
00430             fp = (FWDLIST *) alloc_lbuf("fwdlist_get");
00431         }
00432         dbref aowner;
00433         int   aflags;
00434         char *tp = atr_get(thing, A_FORWARDLIST, &aowner, &aflags);
00435         fwdlist_load(fp, GOD, tp);
00436         free_lbuf(tp);
00437     }
00438     else
00439     {
00440         fp = (FWDLIST *) hashfindLEN(&thing, sizeof(thing),
00441             &mudstate.fwdlist_htab);
00442     }
00443     return fp;
00444 }
00445 
00446 // ---------------------------------------------------------------------------
00447 // Name, PureName, Moniker, s_Moniker, and s_Name: Get or set object's
00448 // various names.
00449 //
00450 const char *Name(dbref thing)
00451 {
00452     if (thing < 0)
00453     {
00454         return aszSpecialDBRefNames[-thing];
00455     }
00456 
00457     dbref aowner;
00458     int aflags;
00459 #ifdef MEMORY_BASED
00460     static char tbuff[LBUF_SIZE];
00461     atr_get_str(tbuff, thing, A_NAME, &aowner, &aflags);
00462     return tbuff;
00463 #else // MEMORY_BASED
00464     if (!db[thing].name)
00465     {
00466         size_t len;
00467         char *pName = atr_get_LEN(thing, A_NAME, &aowner, &aflags, &len);
00468         db[thing].name = StringCloneLen(pName, len);
00469         free_lbuf(pName);
00470     }
00471     return db[thing].name;
00472 #endif // MEMORY_BASED
00473 }
00474 
00475 const char *PureName(dbref thing)
00476 {
00477     if (thing < 0)
00478     {
00479         return aszSpecialDBRefNames[-thing];
00480     }
00481 
00482     dbref aowner;
00483     int aflags;
00484 
00485     char *pName, *pPureName;
00486     if (mudconf.cache_names)
00487     {
00488         if (!db[thing].purename)
00489         {
00490             size_t nName;
00491             size_t nPureName;
00492 #ifdef MEMORY_BASED
00493             pName = atr_get_LEN(thing, A_NAME, &aowner, &aflags, &nName);
00494             pPureName = strip_ansi(pName, &nPureName);
00495             free_lbuf(pName);
00496             db[thing].purename = StringCloneLen(pPureName, nPureName);
00497 #else // MEMORY_BASED
00498             if (!db[thing].name)
00499             {
00500                 pName = atr_get_LEN(thing, A_NAME, &aowner, &aflags, &nName);
00501                 db[thing].name = StringCloneLen(pName, nName);
00502                 free_lbuf(pName);
00503             }
00504             else
00505             {
00506                 nName = strlen(db[thing].name);
00507             }
00508             pName = db[thing].name;
00509             pPureName = strip_ansi(pName, &nPureName);
00510             if (nPureName == nName)
00511             {
00512                 db[thing].purename = pName;
00513             }
00514             else
00515             {
00516                 db[thing].purename = StringCloneLen(pPureName, nPureName);
00517             }
00518 #endif // MEMORY_BASED
00519         }
00520         return db[thing].purename;
00521     }
00522     pName = atr_get(thing, A_NAME, &aowner, &aflags);
00523     pPureName = strip_ansi(pName);
00524     free_lbuf(pName);
00525     return pPureName;
00526 }
00527 
00528 const char *Moniker(dbref thing)
00529 {
00530     if (thing < 0)
00531     {
00532         return aszSpecialDBRefNames[-thing];
00533     }
00534     if (db[thing].moniker)
00535     {
00536         return db[thing].moniker;
00537     }
00538 
00539     // Compare accent-stripped, ansi-stripped version of @moniker against
00540     // accent-stripped, ansi-stripped version of @name.
00541     //
00542     const char *pPureName = strip_accents(PureName(thing));
00543     char *pPureNameCopy = StringClone(pPureName);
00544 
00545     size_t nMoniker;
00546     dbref  aowner;
00547     int    aflags;
00548     char *pMoniker = atr_get_LEN(thing, A_MONIKER, &aowner, &aflags,
00549         &nMoniker);
00550     char *pPureMoniker = strip_accents(strip_ansi(pMoniker));
00551 
00552     const char *pReturn = NULL;
00553     static char tbuff[LBUF_SIZE];
00554     if (strcmp(pPureNameCopy, pPureMoniker) == 0)
00555     {
00556         // The stripped version of @moniker is the same as the stripped
00557         // version of @name, so (possibly cache and) use the unstripped
00558         // version of @moniker.
00559         //
00560         if (mudconf.cache_names)
00561         {
00562 #ifdef MEMORY_BASED
00563             db[thing].moniker = StringCloneLen(pMoniker, nMoniker);
00564 #else // MEMORY_BASED
00565             if (strcmp(pMoniker, Name(thing)) == 0)
00566             {
00567                 db[thing].moniker = db[thing].name;
00568             }
00569             else
00570             {
00571                 db[thing].moniker = StringCloneLen(pMoniker, nMoniker);
00572             }
00573 #endif // MEMORY_BASED
00574             pReturn = db[thing].moniker;
00575         }
00576         else
00577         {
00578             memcpy(tbuff, pMoniker, nMoniker+1);
00579             pReturn = tbuff;
00580         }
00581     }
00582     else
00583     {
00584         // @moniker can't be used, so instead reflect @name (whether it
00585         // contains ANSI color and accents or not).
00586         //
00587 #ifdef MEMORY_BASED
00588         if (mudconf.cache_names)
00589         {
00590             db[thing].moniker = StringClone(Name(thing));
00591             pReturn = db[thing].moniker;
00592         }
00593         else
00594         {
00595             pReturn = Name(thing);
00596         }
00597 #else // MEMORY_BASED
00598         if (mudconf.cache_names)
00599         {
00600             db[thing].moniker = db[thing].name;
00601             pReturn = db[thing].moniker;
00602         }
00603         else
00604         {
00605             pReturn = Name(thing);
00606         }
00607 #endif // MEMORY_BASED
00608     }
00609     free_lbuf(pMoniker);
00610     MEMFREE(pPureNameCopy);
00611 
00612     return pReturn;
00613 }
00614 
00615 void s_Name(dbref thing, const char *s)
00616 {
00617     atr_add_raw(thing, A_NAME, s);
00618 #ifndef MEMORY_BASED
00619     if (db[thing].name)
00620     {
00621         if (mudconf.cache_names)
00622         {
00623             if (db[thing].name == db[thing].purename)
00624             {
00625                 db[thing].purename = NULL;
00626             }
00627             if (db[thing].name == db[thing].moniker)
00628             {
00629                 db[thing].moniker = NULL;
00630             }
00631         }
00632         MEMFREE(db[thing].name);
00633         db[thing].name = NULL;
00634     }
00635     if (s)
00636     {
00637         db[thing].name = StringClone(s);
00638     }
00639 #endif // !MEMORY_BASED
00640     if (mudconf.cache_names)
00641     {
00642         if (db[thing].purename)
00643         {
00644             MEMFREE(db[thing].purename);
00645             db[thing].purename = NULL;
00646         }
00647         if (db[thing].moniker)
00648         {
00649             MEMFREE(db[thing].moniker);
00650             db[thing].moniker = NULL;
00651         }
00652     }
00653 }
00654 
00655 void s_Moniker(dbref thing, const char *s)
00656 {
00657     atr_add_raw(thing, A_MONIKER, s);
00658     if (mudconf.cache_names)
00659     {
00660 #ifndef MEMORY_BASED
00661         if (db[thing].name == db[thing].moniker)
00662         {
00663             db[thing].moniker = NULL;
00664         }
00665 #endif // !MEMORY_BASED
00666         if (db[thing].moniker)
00667         {
00668             MEMFREE(db[thing].moniker);
00669             db[thing].moniker = NULL;
00670         }
00671     }
00672 }
00673 
00674 void s_Pass(dbref thing, const char *s)
00675 {
00676     atr_add_raw(thing, A_PASS, s);
00677 }
00678 
00679 /* ---------------------------------------------------------------------------
00680  * do_attrib: Manage user-named attributes.
00681  */
00682 
00683 void do_attribute
00684 (
00685     dbref executor,
00686     dbref caller,
00687     dbref enactor,
00688     int   key,
00689     int   nargs,
00690     char *aname,
00691     char *value
00692 )
00693 {
00694     UNUSED_PARAMETER(caller);
00695     UNUSED_PARAMETER(enactor);
00696     UNUSED_PARAMETER(nargs);
00697 
00698     // Look up the user-named attribute we want to play with.
00699     //
00700     int nName;
00701     bool bValid;
00702     ATTR *va;
00703     char *pName = MakeCanonicalAttributeName(aname, &nName, &bValid);
00704     if (bValid)
00705     {
00706         va = (ATTR *)vattr_find_LEN(pName, nName);
00707         if (!va)
00708         {
00709             bValid = false;
00710         }
00711     }
00712 
00713     if (!bValid)
00714     {
00715         notify(executor, "No such user-named attribute.");
00716         return;
00717     }
00718 
00719     int f;
00720     char *sp;
00721     ATTR *va2;
00722     bool negate, success;
00723 
00724     switch (key)
00725     {
00726     case ATTRIB_ACCESS:
00727 
00728         // Modify access to user-named attribute
00729         //
00730         mux_strupr(value);
00731         MUX_STRTOK_STATE tts;
00732         mux_strtok_src(&tts, value);
00733         mux_strtok_ctl(&tts, " ");
00734         sp = mux_strtok_parse(&tts);
00735         success = false;
00736         while (sp != NULL)
00737         {
00738             // Check for negation.
00739             //
00740             negate = false;
00741             if (*sp == '!')
00742             {
00743                 negate = true;
00744                 sp++;
00745             }
00746 
00747             // Set or clear the appropriate bit.
00748             //
00749             if (search_nametab(executor, attraccess_nametab, sp, &f))
00750             {
00751                 success = true;
00752                 if (negate)
00753                     va->flags &= ~f;
00754                 else
00755                     va->flags |= f;
00756             }
00757             else
00758             {
00759                 notify(executor, tprintf("Unknown permission: %s.", sp));
00760             }
00761 
00762             // Get the next token.
00763             //
00764             sp = mux_strtok_parse(&tts);
00765         }
00766         if (success && !Quiet(executor))
00767             notify(executor, "Attribute access changed.");
00768         break;
00769 
00770     case ATTRIB_RENAME:
00771 
00772         {
00773             // Save the old name for use later.
00774             //
00775             char OldName[SBUF_SIZE];
00776             int nOldName = nName;
00777             memcpy(OldName, pName, nName+1);
00778 
00779             // Make sure the new name doesn't already exist. This checks
00780             // the built-in and user-defined data structures.
00781             //
00782             va2 = atr_str(value);
00783             if (va2)
00784             {
00785                 notify(executor, "An attribute with that name already exists.");
00786                 return;
00787             }
00788             pName = MakeCanonicalAttributeName(value, &nName, &bValid);
00789             if (!bValid || vattr_rename_LEN(OldName, nOldName, pName, nName) == NULL)
00790                 notify(executor, "Attribute rename failed.");
00791             else
00792                 notify(executor, "Attribute renamed.");
00793         }
00794         break;
00795 
00796     case ATTRIB_DELETE:
00797 
00798         // Remove the attribute.
00799         //
00800         vattr_delete_LEN(pName, nName);
00801         notify(executor, "Attribute deleted.");
00802         break;
00803     }
00804 }
00805 
00806 /* ---------------------------------------------------------------------------
00807  * do_fixdb: Directly edit database fields
00808  */
00809 
00810 void do_fixdb
00811 (
00812     dbref executor,
00813     dbref caller,
00814     dbref enactor,
00815     int   key,
00816     int   nargs,
00817     char *arg1,
00818     char *arg2
00819 )
00820 {
00821     UNUSED_PARAMETER(caller);
00822     UNUSED_PARAMETER(enactor);
00823     UNUSED_PARAMETER(nargs);
00824 
00825     init_match(executor, arg1, NOTYPE);
00826     match_everything(0);
00827     dbref thing = noisy_match_result();
00828     if (thing == NOTHING)
00829     {
00830         return;
00831     }
00832 
00833     dbref res = NOTHING;
00834     switch (key)
00835     {
00836     case FIXDB_OWNER:
00837     case FIXDB_LOC:
00838     case FIXDB_CON:
00839     case FIXDB_EXITS:
00840     case FIXDB_NEXT:
00841         init_match(executor, arg2, NOTYPE);
00842         match_everything(0);
00843         res = noisy_match_result();
00844         break;
00845     case FIXDB_PENNIES:
00846         res = mux_atol(arg2);
00847         break;
00848     }
00849 
00850     char *pValidName;
00851     switch (key)
00852     {
00853     case FIXDB_OWNER:
00854 
00855         s_Owner(thing, res);
00856         if (!Quiet(executor))
00857             notify(executor, tprintf("Owner set to #%d", res));
00858         break;
00859 
00860     case FIXDB_LOC:
00861 
00862         s_Location(thing, res);
00863         if (!Quiet(executor))
00864             notify(executor, tprintf("Location set to #%d", res));
00865         break;
00866 
00867     case FIXDB_CON:
00868 
00869         s_Contents(thing, res);
00870         if (!Quiet(executor))
00871             notify(executor, tprintf("Contents set to #%d", res));
00872         break;
00873 
00874     case FIXDB_EXITS:
00875 
00876         s_Exits(thing, res);
00877         if (!Quiet(executor))
00878             notify(executor, tprintf("Exits set to #%d", res));
00879         break;
00880 
00881     case FIXDB_NEXT:
00882 
00883         s_Next(thing, res);
00884         if (!Quiet(executor))
00885             notify(executor, tprintf("Next set to #%d", res));
00886         break;
00887 
00888     case FIXDB_PENNIES:
00889 
00890         s_Pennies(thing, res);
00891         if (!Quiet(executor))
00892             notify(executor, tprintf("Pennies set to %d", res));
00893         break;
00894 
00895     case FIXDB_NAME:
00896 
00897         if (isPlayer(thing))
00898         {
00899             if (!ValidatePlayerName(arg2))
00900             {
00901                 notify(executor, "That's not a good name for a player.");
00902                 return;
00903             }
00904             pValidName = arg2;
00905             if (lookup_player(NOTHING, pValidName, false) != NOTHING)
00906             {
00907                 notify(executor, "That name is already in use.");
00908                 return;
00909             }
00910             STARTLOG(LOG_SECURITY, "SEC", "CNAME");
00911             log_name(thing),
00912             log_text(" renamed to ");
00913             log_text(pValidName);
00914             ENDLOG;
00915             if (Suspect(executor))
00916             {
00917                 raw_broadcast(WIZARD, "[Suspect] %s renamed to %s",
00918                     Name(thing), pValidName);
00919             }
00920             delete_player_name(thing, Name(thing));
00921             s_Name(thing, pValidName);
00922             add_player_name(thing, pValidName);
00923         }
00924         else
00925         {
00926             int nTmp;
00927             bool bValid;
00928             pValidName = MakeCanonicalObjectName(arg2, &nTmp, &bValid);
00929             if (!bValid)
00930             {
00931                 notify(executor, "That is not a reasonable name.");
00932                 return;
00933             }
00934             s_Name(thing, pValidName);
00935         }
00936         if (!Quiet(executor))
00937         {
00938             notify(executor, tprintf("Name set to %s", pValidName));
00939         }
00940         break;
00941     }
00942 }
00943 
00944 // MakeCanonicalAttributeName
00945 //
00946 // See stringutil.cpp for valid characters used here..
00947 //
00948 // We truncate the attribute name to a length of SBUF_SIZE-1, if
00949 // necessary, but we will validate the remaining characters anyway.
00950 //
00951 // NOTE: Refer to init_attrtab() where it directly manipulates
00952 // mux_AttrNameSet to allow the attribute name: "*Password".
00953 //
00954 char *MakeCanonicalAttributeName(const char *pName, int *pnName, bool *pbValid)
00955 {
00956     static char Buffer[SBUF_SIZE];
00957 
00958     if (  !pName
00959        || !mux_AttrNameInitialSet(*pName))
00960     {
00961         *pnName = 0;
00962         *pbValid = false;
00963         return NULL;
00964     }
00965     int nLeft = SBUF_SIZE-1;
00966     char *p = Buffer;
00967     while (*pName && nLeft)
00968     {
00969         if (!mux_AttrNameSet(*pName))
00970         {
00971             *pnName = 0;
00972             *pbValid = false;
00973             return Buffer;
00974         }
00975         *p = mux_toupper(*pName);
00976         p++;
00977         pName++;
00978         nLeft--;
00979     }
00980     *p = '\0';
00981 
00982     // Continue to validate remaining characters even though
00983     // we aren't going to use them. This helps to ensure that
00984     // softcode will run in the future if we increase the
00985     // size of SBUF_SIZE.
00986     //
00987     while (*pName)
00988     {
00989         if (!mux_AttrNameSet(*pName))
00990         {
00991             *pnName = 0;
00992             *pbValid = false;
00993             return Buffer;
00994         }
00995         pName++;
00996     }
00997 
00998     // Length of truncated result.
00999     //
01000     *pnName = p - Buffer;
01001     *pbValid = true;
01002     return Buffer;
01003 }
01004 
01005 // MakeCanonicalAttributeCommand
01006 //
01007 char *MakeCanonicalAttributeCommand(const char *pName, int *pnName, bool *pbValid)
01008 {
01009     if (!pName)
01010     {
01011         *pnName = 0;
01012         *pbValid = false;
01013         return NULL;
01014     }
01015 
01016     static char Buffer[SBUF_SIZE];
01017     int nLeft = SBUF_SIZE-2;
01018     char *p = Buffer;
01019 
01020     *p++ = '@';
01021     while (*pName && nLeft)
01022     {
01023         *p = mux_tolower(*pName);
01024         p++;
01025         pName++;
01026         nLeft--;
01027     }
01028     *p = '\0';
01029 
01030     // Length of result.
01031     //
01032     *pnName = p - Buffer;
01033 
01034     // Is the result valid?
01035     //
01036     *pbValid = (*pnName > 1);
01037 
01038     // Pointer to result
01039     //
01040     return Buffer;
01041 }
01042 
01043 /* ---------------------------------------------------------------------------
01044  * init_attrtab: Initialize the attribute hash tables.
01045  */
01046 
01047 void init_attrtab(void)
01048 {
01049     ATTR *a;
01050 
01051     // We specifically allow the '*' character at server
01052     // initialization because it's part of the A_PASS attribute
01053     // name.
01054     //
01055     const unsigned char star = '*';
01056     mux_AttrNameSet[star] = true;
01057     mux_AttrNameInitialSet[star] = true;
01058     for (a = attr; a->number; a++)
01059     {
01060         int nLen;
01061         bool bValid;
01062         char *buff = MakeCanonicalAttributeName(a->name, &nLen, &bValid);
01063         if (!bValid)
01064         {
01065             continue;
01066         }
01067         anum_extend(a->number);
01068         anum_set(a->number, a);
01069         hashaddLEN(buff, nLen, a, &mudstate.attr_name_htab);
01070     }
01071     mux_AttrNameInitialSet[star] = false;
01072     mux_AttrNameSet[star] = false;
01073 }
01074 
01075 /* ---------------------------------------------------------------------------
01076  * atr_str: Look up an attribute by name.
01077  */
01078 
01079 ATTR *atr_str(char *s)
01080 {
01081     // Make attribute name canonical.
01082     //
01083     int nBuffer;
01084     bool bValid;
01085     char *buff = MakeCanonicalAttributeName(s, &nBuffer, &bValid);
01086     if (!bValid)
01087     {
01088         return NULL;
01089     }
01090 
01091     // Look for a predefined attribute.
01092     //
01093     ATTR *a = (ATTR *)hashfindLEN(buff, nBuffer, &mudstate.attr_name_htab);
01094     if (a != NULL)
01095     {
01096         return a;
01097     }
01098 
01099     // Nope, look for a user attribute.
01100     //
01101     a = vattr_find_LEN(buff, nBuffer);
01102     return a;
01103 }
01104 
01105 /* ---------------------------------------------------------------------------
01106  * anum_extend: Grow the attr num lookup table.
01107  */
01108 
01109 ATTR **anum_table = NULL;
01110 int anum_alc_top = 0;
01111 
01112 void anum_extend(int newtop)
01113 {
01114     ATTR **anum_table2;
01115     int delta, i;
01116 
01117     if (mudstate.bStandAlone)
01118     {
01119         delta = 1000;
01120     }
01121     else
01122     {
01123         delta = mudconf.init_size;
01124     }
01125     if (newtop <= anum_alc_top)
01126     {
01127         return;
01128     }
01129     if (newtop < anum_alc_top + delta)
01130     {
01131         newtop = anum_alc_top + delta;
01132     }
01133     if (anum_table == NULL)
01134     {
01135         anum_table = (ATTR **) MEMALLOC((newtop + 1) * sizeof(ATTR *));
01136         ISOUTOFMEMORY(anum_table);
01137         for (i = 0; i <= newtop; i++)
01138         {
01139             anum_table[i] = NULL;
01140         }
01141     }
01142     else
01143     {
01144         anum_table2 = (ATTR **) MEMALLOC((newtop + 1) * sizeof(ATTR *));
01145         ISOUTOFMEMORY(anum_table2);
01146         for (i = 0; i <= anum_alc_top; i++)
01147         {
01148             anum_table2[i] = anum_table[i];
01149         }
01150         for (i = anum_alc_top + 1; i <= newtop; i++)
01151         {
01152             anum_table2[i] = NULL;
01153         }
01154         MEMFREE((char *)anum_table);
01155         anum_table = anum_table2;
01156     }
01157     anum_alc_top = newtop;
01158 }
01159 
01160 // --------------------------------------------------------------------------
01161 // atr_num: Look up an attribute by number.
01162 //
01163 ATTR *atr_num(int anum)
01164 {
01165     if (anum > anum_alc_top)
01166     {
01167         return NULL;
01168     }
01169     return  anum_get(anum);
01170 }
01171 
01172 static void SetupThrottle(dbref executor)
01173 {
01174     CLinearTimeAbsolute tNow;
01175     CLinearTimeDelta    ltdHour;
01176 
01177     ltdHour.SetSeconds(60*60);
01178     tNow.GetUTC();
01179 
01180     db[executor].tThrottleExpired = tNow + ltdHour;
01181     s_ThAttrib(executor, mudconf.vattr_per_hour);
01182     s_ThMail(executor, mudconf.mail_per_hour);
01183 }
01184 
01185 static void SetupGlobalThrottle(void)
01186 {
01187     CLinearTimeAbsolute tNow;
01188     CLinearTimeDelta    ltdHour;
01189 
01190     ltdHour.SetSeconds(60*60);
01191     tNow.GetUTC();
01192 
01193     mudstate.tThrottleExpired = tNow + ltdHour;
01194     mudstate.pcreates_this_hour = mudconf.pcreate_per_hour;
01195 }
01196 
01197 bool ThrottlePlayerCreate(void)
01198 {
01199     if (0 < mudstate.pcreates_this_hour)
01200     {
01201         mudstate.pcreates_this_hour--;
01202         return false;
01203     }
01204     CLinearTimeAbsolute tNow;
01205     tNow.GetUTC();
01206     if (mudstate.tThrottleExpired <= tNow)
01207     {
01208         SetupGlobalThrottle();
01209         return false;
01210     }
01211     return true;
01212 }
01213 
01214 bool ThrottleAttributeNames(dbref executor)
01215 {
01216     if (0 < ThAttrib(executor))
01217     {
01218         s_ThAttrib(executor, ThAttrib(executor)-1);
01219         return false;
01220     }
01221     CLinearTimeAbsolute tNow;
01222     tNow.GetUTC();
01223     if (db[executor].tThrottleExpired <= tNow)
01224     {
01225         SetupThrottle(executor);
01226         return false;
01227     }
01228     return true;
01229 }
01230 
01231 bool ThrottleMail(dbref executor)
01232 {
01233     if (0 < ThMail(executor))
01234     {
01235         s_ThMail(executor, ThMail(executor)-1);
01236         return false;
01237     }
01238     CLinearTimeAbsolute tNow;
01239     tNow.GetUTC();
01240     if (db[executor].tThrottleExpired <= tNow)
01241     {
01242         SetupThrottle(executor);
01243         return false;
01244     }
01245     return true;
01246 }
01247 
01248 /* ---------------------------------------------------------------------------
01249  * mkattr: Lookup attribute by name, creating if needed.
01250  */
01251 
01252 int mkattr(dbref executor, char *buff)
01253 {
01254     ATTR *ap = atr_str(buff);
01255     if (!ap)
01256     {
01257         // Unknown attribute name, create a new one.
01258         //
01259         int nName;
01260         bool bValid;
01261         char *pName = MakeCanonicalAttributeName(buff, &nName, &bValid);
01262         ATTR *va;
01263         if (bValid)
01264         {
01265             if (  !Wizard(executor)
01266                && ThrottleAttributeNames(executor))
01267             {
01268                 return -1;
01269             }
01270             int aflags = mudconf.vattr_flags;
01271             if (pName[0] == '_')
01272             {
01273                 // An attribute that begins with an underline is
01274                 // hidden from mortals and only changeable by
01275                 // WIZARDs.
01276                 //
01277                 aflags |=  AF_MDARK | AF_WIZARD;
01278             }
01279             va = vattr_alloc_LEN(pName, nName, aflags);
01280             if (va && va->number)
01281             {
01282                 return va->number;
01283             }
01284         }
01285         return -1;
01286     }
01287     else if (ap->number)
01288     {
01289         return ap->number;
01290     }
01291     return -1;
01292 }
01293 
01294 #ifndef MEMORY_BASED
01295 
01296 /* ---------------------------------------------------------------------------
01297  * al_decode: Fetch an attribute number from an alist.
01298  */
01299 
01300 static int al_decode(char **app)
01301 {
01302     char *ap = *app;
01303 
01304     int atrnum = 0, atrshft = 0;
01305     for (;;)
01306     {
01307         int ch = *ap++;
01308         int bits = ch & 0x7F;
01309 
01310         if (atrshft > 0)
01311             atrnum |= (bits << atrshft);
01312         else
01313             atrnum = bits;
01314 
01315         if ((ch & 0x80) == 0)
01316         {
01317             *app = ap;
01318             return atrnum;
01319         }
01320         atrshft += 7;
01321     }
01322 }
01323 
01324 // ---------------------------------------------------------------------------
01325 // al_code: Store an attribute number in an alist
01326 //
01327 // Because A_LIST are attributes, too. We cannot generate a '\0', otherwise
01328 // the size of an A_LIST cannot be determined with strlen. Fortunately, the
01329 // following routine only genreates a '\0' in the atrnum == 0 case (which is
01330 // never used).
01331 //
01332 static char *al_code(char *ap, int atrnum)
01333 {
01334     int bits;
01335     for (;;)
01336     {
01337         bits = atrnum & 0x7F;
01338         if (atrnum <= 0x7F)
01339         {
01340             break;
01341         }
01342         atrnum >>= 7;
01343         bits |= 0x80;
01344         *ap++ = (char)bits;
01345     }
01346     *ap++ = (char)bits;
01347     return ap;
01348 }
01349 
01350 #endif // MEMORY_BASED
01351 
01352 /* ---------------------------------------------------------------------------
01353  * Commer: check if an object has any $-commands in its attributes.
01354  */
01355 
01356 bool Commer(dbref thing)
01357 {
01358     if (mudstate.bfNoCommands.IsSet(thing))
01359     {
01360         // We already know that there are no commands on this thing.
01361         //
01362         return false;
01363     }
01364     else if (mudstate.bfCommands.IsSet(thing))
01365     {
01366         // We already know that there are definitely commands on this thing.
01367         //
01368         return true;
01369     }
01370 
01371     bool bFoundListens = false;
01372 
01373     char *as;
01374     atr_push();
01375     char *buff = alloc_lbuf("Commer");
01376     for (int atr = atr_head(thing, &as); atr; atr = atr_next(&as))
01377     {
01378         ATTR *ap = atr_num(atr);
01379         if (  !ap
01380            || (ap->flags & AF_NOPROG))
01381         {
01382             continue;
01383         }
01384 
01385         int   aflags;
01386         dbref aowner;
01387 
01388         atr_get_str(buff, thing, atr, &aowner, &aflags);
01389 
01390         if (aflags & AF_NOPROG)
01391         {
01392             continue;
01393         }
01394 
01395         if (  AMATCH_CMD != buff[0]
01396            && AMATCH_LISTEN != buff[0])
01397         {
01398             continue;
01399         }
01400 
01401         // Search for unescaped ':'
01402         //
01403         char *s = strchr(buff+1, ':');
01404         if (!s)
01405         {
01406             continue;
01407         }
01408 
01409         if (AMATCH_CMD == buff[0])
01410         {
01411             free_lbuf(buff);
01412             atr_pop();
01413             mudstate.bfCommands.Set(thing);
01414             if (bFoundListens)
01415             {
01416                 mudstate.bfListens.Set(thing);
01417                 mudstate.bfNoListens.Clear(thing);
01418             }
01419             return true;
01420         }
01421         else // AMATCH_LISTEN == buff[0]
01422         {
01423             bFoundListens = true;
01424         }
01425     }
01426     free_lbuf(buff);
01427     atr_pop();
01428     mudstate.bfNoCommands.Set(thing);
01429     if (bFoundListens)
01430     {
01431         mudstate.bfListens.Set(thing);
01432         mudstate.bfNoListens.Clear(thing);
01433     }
01434     else
01435     {
01436         mudstate.bfNoListens.Set(thing);
01437         mudstate.bfListens.Clear(thing);
01438     }
01439     return false;
01440 }
01441 
01442 // routines to handle object attribute lists
01443 //
01444 
01445 #ifndef MEMORY_BASED
01446 /* ---------------------------------------------------------------------------
01447  * al_fetch, al_store, al_add, al_delete: Manipulate attribute lists
01448  */
01449 
01450 // al_extend: Get more space for attributes, if needed
01451 //
01452 static void al_extend(char **buffer, size_t *bufsiz, size_t len, bool copy)
01453 {
01454     if (len > *bufsiz)
01455     {
01456         int newsize = len + ATR_BUF_CHUNK;
01457         char *tbuff = (char *)MEMALLOC(newsize);
01458         ISOUTOFMEMORY(tbuff);
01459         if (*buffer)
01460         {
01461             if (copy)
01462             {
01463                 memcpy(tbuff, *buffer, *bufsiz);
01464             }
01465             MEMFREE(*buffer);
01466             *buffer = NULL;
01467         }
01468         *buffer = tbuff;
01469         *bufsiz = newsize;
01470     }
01471 }
01472 
01473 // al_store: Write modified attribute list
01474 //
01475 void al_store(void)
01476 {
01477     if (mudstate.mod_al_id != NOTHING)
01478     {
01479         if (mudstate.mod_alist_len)
01480         {
01481             atr_add_raw_LEN(mudstate.mod_al_id, A_LIST, mudstate.mod_alist, mudstate.mod_alist_len);
01482         }
01483         else
01484         {
01485             atr_clr(mudstate.mod_al_id, A_LIST);
01486         }
01487     }
01488     mudstate.mod_al_id = NOTHING;
01489 }
01490 
01491 // al_fetch: Load attribute list
01492 //
01493 static char *al_fetch(dbref thing)
01494 {
01495     // We only need fetch if we change things.
01496     //
01497     if (mudstate.mod_al_id == thing)
01498     {
01499         return mudstate.mod_alist;
01500     }
01501 
01502     // Save old list, then fetch and set up the attribute list.
01503     //
01504     al_store();
01505     size_t len;
01506     const char *astr = atr_get_raw_LEN(thing, A_LIST, &len);
01507     if (astr)
01508     {
01509         al_extend(&mudstate.mod_alist, &mudstate.mod_size, len+1, false);
01510         memcpy(mudstate.mod_alist, astr, len+1);
01511         mudstate.mod_alist_len = len;
01512     }
01513     else
01514     {
01515         al_extend(&mudstate.mod_alist, &mudstate.mod_size, 1, false);
01516         *mudstate.mod_alist = '\0';
01517         mudstate.mod_alist_len = 0;
01518     }
01519     mudstate.mod_al_id = thing;
01520     return mudstate.mod_alist;
01521 }
01522 
01523 // al_add: Add an attribute to an attribute list
01524 //
01525 static bool al_add(dbref thing, int attrnum)
01526 {
01527     char *abuf = al_fetch(thing);
01528     char *cp = abuf;
01529     int anum;
01530 
01531     // See if attr is in the list.  If so, exit (need not do anything).
01532     //
01533     while (*cp)
01534     {
01535         anum = al_decode(&cp);
01536         if (anum == attrnum)
01537         {
01538             return true;
01539         }
01540     }
01541 
01542     // The attribute isn't there, so we need to try to add it.
01543     //
01544     int iPosition = cp - abuf;
01545 
01546     // If we are too large for an attribute
01547     //
01548     if (iPosition + ATR_BUF_INCR >= LBUF_SIZE)
01549     {
01550         return false;
01551     }
01552 
01553     // Extend it.
01554     //
01555     al_extend(&mudstate.mod_alist, &mudstate.mod_size, (iPosition + ATR_BUF_INCR), true);
01556     if (mudstate.mod_alist != abuf)
01557     {
01558         // extend returned different buffer, re-position the end
01559         //
01560         cp = mudstate.mod_alist + iPosition;
01561     }
01562 
01563     // Add the new attribute on to the end.
01564     //
01565     cp = al_code(cp, attrnum);
01566     *cp = '\0';
01567     mudstate.mod_alist_len = cp - mudstate.mod_alist;
01568     return true;
01569 }
01570 
01571 // al_delete: Remove an attribute from an attribute list
01572 //
01573 static void al_delete(dbref thing, int attrnum)
01574 {
01575     int anum;
01576     char *abuf, *cp, *dp;
01577 
01578     // If trying to modify List attrib, return.  Otherwise, get the attribute list.
01579     //
01580     if (attrnum == A_LIST)
01581     {
01582         return;
01583     }
01584     abuf = al_fetch(thing);
01585     if (!abuf)
01586     {
01587         return;
01588     }
01589 
01590     cp = abuf;
01591     while (*cp)
01592     {
01593         dp = cp;
01594         anum = al_decode(&cp);
01595         if (anum == attrnum)
01596         {
01597             while (*cp)
01598             {
01599                 anum = al_decode(&cp);
01600                 dp = al_code(dp, anum);
01601             }
01602             *dp = '\0';
01603             mudstate.mod_alist_len = dp - mudstate.mod_alist;
01604             return;
01605         }
01606     }
01607     return;
01608 }
01609 
01610 static DCL_INLINE void makekey(dbref thing, int atr, Aname *abuff)
01611 {
01612     abuff->object = thing;
01613     abuff->attrnum = atr;
01614     return;
01615 }
01616 #endif // !MEMORY_BASED
01617 
01618 /* ---------------------------------------------------------------------------
01619  * atr_encode: Encode an attribute string.
01620  */
01621 
01622 static char *atr_encode(char *iattr, dbref thing, dbref owner, int flags, int atr)
01623 {
01624     UNUSED_PARAMETER(atr);
01625 
01626     // If using the default owner and flags (almost all attributes will),
01627     // just store the string.
01628     //
01629     if (((owner == Owner(thing)) || (owner == NOTHING)) && !flags)
01630         return iattr;
01631 
01632     // Encode owner and flags into the attribute text.
01633     //
01634     if (owner == NOTHING)
01635         owner = Owner(thing);
01636     return tprintf("%c%d:%d:%s", ATR_INFO_CHAR, owner, flags, iattr);
01637 }
01638 
01639 // atr_decode_flags_owner: Decode the owner and flags (if present) and
01640 // return a pointer to the attribute text.
01641 //
01642 static const char *atr_decode_flags_owner(const char *iattr, dbref *owner, int *flags)
01643 {
01644     // See if the first char of the attribute is the special character
01645     //
01646     *flags = 0;
01647     if (*iattr != ATR_INFO_CHAR)
01648     {
01649         return iattr;
01650     }
01651 
01652     // It has the special character, crack the attr apart.
01653     //
01654     const char *cp = iattr + 1;
01655 
01656     // Get the attribute owner
01657     //
01658     bool neg = false;
01659     if (*cp == '-')
01660     {
01661         neg = true;
01662         cp++;
01663     }
01664     int tmp_owner = 0;
01665     unsigned int ch = *cp;
01666     while (mux_isdigit(ch))
01667     {
01668         cp++;
01669         tmp_owner = 10*tmp_owner + (ch-'0');
01670         ch = *cp;
01671     }
01672     if (neg)
01673     {
01674         tmp_owner = -tmp_owner;
01675     }
01676 
01677     // If delimiter is not ':', just return attribute
01678     //
01679     if (*cp++ != ':')
01680     {
01681         return iattr;
01682     }
01683 
01684     // Get the attribute flags.
01685     //
01686     int tmp_flags = 0;
01687     ch = *cp;
01688     while (mux_isdigit(ch))
01689     {
01690         cp++;
01691         tmp_flags = 10*tmp_flags + (ch-'0');
01692         ch = *cp;
01693     }
01694 
01695     // If delimiter is not ':', just return attribute.
01696     //
01697     if (*cp++ != ':')
01698     {
01699         return iattr;
01700     }
01701 
01702     // Get the attribute text.
01703     //
01704     if (tmp_owner != NOTHING)
01705     {
01706         *owner = tmp_owner;
01707     }
01708     *flags = tmp_flags;
01709     return cp;
01710 }
01711 
01712 // ---------------------------------------------------------------------------
01713 // atr_decode: Decode an attribute string.
01714 //
01715 static void atr_decode_LEN(const char *iattr, int nLen, char *oattr,
01716                            dbref thing, dbref *owner, int *flags, size_t *pLen)
01717 {
01718     // Default the owner
01719     //
01720     *owner = Owner(thing);
01721 
01722     // Parse for owner and flags
01723     //
01724     const char *cp = atr_decode_flags_owner(iattr, owner, flags);
01725 
01726     // Get the attribute text.
01727     //
01728     *pLen = nLen - (cp - iattr);
01729     if (oattr)
01730     {
01731         memcpy(oattr, cp, (*pLen) + 1);
01732     }
01733 }
01734 
01735 /* ---------------------------------------------------------------------------
01736  * atr_clr: clear an attribute in the list.
01737  */
01738 
01739 void atr_clr(dbref thing, int atr)
01740 {
01741 #ifdef MEMORY_BASED
01742 
01743     if (  !db[thing].nALUsed
01744        || !db[thing].pALHead)
01745     {
01746         return;
01747     }
01748 
01749     mux_assert(0 <= db[thing].nALUsed);
01750 
01751     // Binary search for the attribute.
01752     //
01753     int lo = 0;
01754     int mid;
01755     int hi = db[thing].nALUsed - 1;
01756     ATRLIST *list = db[thing].pALHead;
01757     while (lo <= hi)
01758     {
01759         mid = ((hi - lo) >> 1) + lo;
01760         if (list[mid].number > atr)
01761         {
01762             hi = mid - 1;
01763         }
01764         else if (list[mid].number < atr)
01765         {
01766             lo = mid + 1;
01767         }
01768         else // (list[mid].number == atr)
01769         {
01770             MEMFREE(list[mid].data);
01771             list[mid].data = NULL;
01772             db[thing].nALUsed--;
01773             if (mid != db[thing].nALUsed)
01774             {
01775                 memmove( list + mid,
01776                          list + mid + 1,
01777                          (db[thing].nALUsed - mid) * sizeof(ATRLIST));
01778             }
01779             break;
01780         }
01781     }
01782 #else // MEMORY_BASED
01783     Aname okey;
01784 
01785     makekey(thing, atr, &okey);
01786     cache_del(&okey);
01787     al_delete(thing, atr);
01788 #endif // MEMORY_BASED
01789 
01790     switch (atr)
01791     {
01792     case A_STARTUP:
01793 
01794         db[thing].fs.word[FLAG_WORD1] &= ~HAS_STARTUP;
01795         break;
01796 
01797     case A_DAILY:
01798 
01799         db[thing].fs.word[FLAG_WORD2] &= ~HAS_DAILY;
01800         break;
01801 
01802     case A_FORWARDLIST:
01803 
01804         db[thing].fs.word[FLAG_WORD2] &= ~HAS_FWDLIST;
01805         if (!mudstate.bStandAlone)
01806         {
01807             // We should clear the hashtable, too.
01808             //
01809             fwdlist_clr(thing);
01810         }
01811         break;
01812 
01813     case A_LISTEN:
01814 
01815         db[thing].fs.word[FLAG_WORD2] &= ~HAS_LISTEN;
01816         break;
01817 
01818     case A_TIMEOUT:
01819 
01820         desc_reload(thing);
01821         break;
01822 
01823     case A_QUEUEMAX:
01824 
01825         pcache_reload(thing);
01826         break;
01827 
01828     default:
01829 
01830         // Since this could overwrite an existing ^-Command or $-Command, we
01831         // longer assert that the object has one.
01832         //
01833         mudstate.bfListens.Clear(thing);
01834         mudstate.bfCommands.Clear(thing);
01835         break;
01836     }
01837 }
01838 
01839 /* ---------------------------------------------------------------------------
01840  * atr_add_raw, atr_add: add attribute of type atr to list
01841  */
01842 
01843 void atr_add_raw_LEN(dbref thing, int atr, const char *szValue, int nValue)
01844 {
01845     if (  !szValue
01846        || '\0' == szValue[0])
01847     {
01848         atr_clr(thing, atr);
01849         return;
01850     }
01851 
01852 #ifdef MEMORY_BASED
01853     ATRLIST *list;
01854     bool found = false;
01855     int hi, lo, mid;
01856     char *text = StringCloneLen(szValue, nValue);
01857 
01858     if (!db[thing].pALHead)
01859     {
01860         db[thing].nALAlloc = INITIAL_ATRLIST_SIZE;
01861         list = (ATRLIST *)MEMALLOC(db[thing].nALAlloc*sizeof(ATRLIST));
01862         ISOUTOFMEMORY(list);
01863         db[thing].pALHead  = list;
01864         db[thing].nALUsed  = 1;
01865         list[0].number = atr;
01866         list[0].data = text;
01867         list[0].size = nValue + 1;
01868         found = true;
01869     }
01870     else
01871     {
01872         // Binary search for the attribute
01873         //
01874         lo = 0;
01875         hi = db[thing].nALUsed - 1;
01876 
01877         list = db[thing].pALHead;
01878         while (lo <= hi)
01879         {
01880             mid = ((hi - lo) >> 1) + lo;
01881             if (list[mid].number > atr)
01882             {
01883                 hi = mid - 1;
01884             }
01885             else if (list[mid].number < atr)
01886             {
01887                 lo = mid + 1;
01888             }
01889             else // if (list[mid].number == atr)
01890             {
01891                 MEMFREE(list[mid].data);
01892                 list[mid].data = text;
01893                 list[mid].size = nValue + 1;
01894                 found = true;
01895                 break;
01896             }
01897         }
01898 
01899         if (!found)
01900         {
01901             // We didn't find it, and lo == hi + 1.  The attribute should be
01902             // inserted between (0,hi) and (lo,nALUsed-1).
01903             //
01904             if (db[thing].nALUsed < db[thing].nALAlloc)
01905             {
01906                 memmove( list + lo + 1,
01907                          list + lo,
01908                          (db[thing].nALUsed - lo) * sizeof(ATRLIST));
01909             }
01910             else
01911             {
01912                 // Expand the list.
01913                 //
01914                 db[thing].nALAlloc += ATRLIST_CHUNK;
01915                 list = (ATRLIST *)MEMALLOC(db[thing].nALAlloc
01916                      * sizeof(ATRLIST));
01917                 ISOUTOFMEMORY(list);
01918 
01919                 // Copy bottom part.
01920                 //
01921                 if (lo > 0)
01922                 {
01923                     memcpy(list, db[thing].pALHead, lo * sizeof(ATRLIST));
01924                 }
01925     
01926                 // Copy top part.
01927                 //
01928                 if (lo < db[thing].nALUsed)
01929                 {
01930                     memcpy( list + lo + 1,
01931                             db[thing].pALHead + lo,
01932                             (db[thing].nALUsed - lo) * sizeof(ATRLIST));
01933                 }
01934                 MEMFREE(db[thing].pALHead);
01935                 db[thing].pALHead = list;
01936             }
01937             db[thing].nALUsed++;
01938             list[lo].data = text;
01939             list[lo].number = atr;
01940             list[lo].size = nValue + 1;
01941         }
01942     }
01943 
01944 #else // MEMORY_BASED
01945 
01946     if (nValue > LBUF_SIZE-1)
01947     {
01948         nValue = LBUF_SIZE-1;
01949     }
01950 
01951     Aname okey;
01952     makekey(thing, atr, &okey);
01953     if (atr == A_LIST)
01954     {
01955         // A_LIST is never compressed and it's never listed within itself.
01956         //
01957         cache_put(&okey, szValue, nValue+1);
01958     }
01959     else
01960     {
01961         if (!al_add(thing, atr))
01962         {
01963             return;
01964         }
01965         cache_put(&okey, szValue, nValue+1);
01966     }
01967 #endif // MEMORY_BASED
01968 
01969     switch (atr)
01970     {
01971     case A_STARTUP:
01972 
01973         db[thing].fs.word[FLAG_WORD1] |= HAS_STARTUP;
01974         break;
01975 
01976     case A_DAILY:
01977 
01978         db[thing].fs.word[FLAG_WORD2] |= HAS_DAILY;
01979         break;
01980 
01981     case A_FORWARDLIST:
01982 
01983         db[thing].fs.word[FLAG_WORD2] |= HAS_FWDLIST;
01984         break;
01985 
01986     case A_LISTEN:
01987 
01988         db[thing].fs.word[FLAG_WORD2] |= HAS_LISTEN;
01989         break;
01990 
01991     case A_TIMEOUT:
01992 
01993         desc_reload(thing);
01994         break;
01995 
01996     case A_QUEUEMAX:
01997 
01998         pcache_reload(thing);
01999         break;
02000     }
02001 }
02002 
02003 void atr_add_raw(dbref thing, int atr, const char *szValue)
02004 {
02005     atr_add_raw_LEN(thing, atr, szValue, szValue ? strlen(szValue) : 0);
02006 }
02007 
02008 void atr_add(dbref thing, int atr, char *buff, dbref owner, int flags)
02009 {
02010     set_modified(thing);
02011 
02012     if (!buff || !*buff)
02013     {
02014         atr_clr(thing, atr);
02015     }
02016     else
02017     {
02018         switch (buff[0])
02019         {
02020         case AMATCH_LISTEN:
02021 
02022             // Since this could be a ^-Command, we no longer assert that the
02023             // object has none.
02024             //
02025             mudstate.bfNoListens.Clear(thing);
02026             break;
02027 
02028         case AMATCH_CMD:
02029 
02030             // Since this could be a $-Command, we no longer assert that the
02031             // object has none.
02032             //
02033             mudstate.bfNoCommands.Clear(thing);
02034             break;
02035         }
02036 
02037         // Since this could overwrite an existing ^-Command or $-Command, we
02038         // longer assert that the object has one.
02039         //
02040         mudstate.bfListens.Clear(thing);
02041         mudstate.bfCommands.Clear(thing);
02042 
02043         char *tbuff = atr_encode(buff, thing, owner, flags, atr);
02044         atr_add_raw(thing, atr, tbuff);
02045     }
02046 }
02047 
02048 void atr_set_flags(dbref thing, int atr, dbref flags)
02049 {
02050     dbref aowner;
02051     int aflags;
02052     char *buff = atr_get(thing, atr, &aowner, &aflags);
02053     atr_add(thing, atr, buff, aowner, flags);
02054     free_lbuf(buff);
02055 }
02056 
02057 /* ---------------------------------------------------------------------------
02058  * get_atr,atr_get_raw, atr_get_str, atr_get: Get an attribute from the database.
02059  */
02060 
02061 int get_atr(char *name)
02062 {
02063     ATTR *ap = atr_str(name);
02064 
02065     if (!ap)
02066         return 0;
02067     if (!(ap->number))
02068         return -1;
02069     return ap->number;
02070 }
02071 
02072 #ifdef MEMORY_BASED
02073 const char *atr_get_raw_LEN(dbref thing, int atr, size_t *pLen)
02074 {
02075     if (!Good_obj(thing))
02076     {
02077         return NULL;
02078     }
02079 
02080     // Binary search for the attribute.
02081     //
02082     ATRLIST *list = db[thing].pALHead;
02083     if (!list)
02084     {
02085         return NULL;
02086     }
02087 
02088     int lo = 0;
02089     int hi = db[thing].nALUsed - 1;
02090     int mid;
02091     while (lo <= hi)
02092     {
02093         mid = ((hi - lo) >> 1) + lo;
02094         if (list[mid].number > atr)
02095         {
02096             hi = mid - 1;
02097         }
02098         else if (list[mid].number < atr)
02099         {
02100             lo = mid + 1;
02101         }
02102         else // if (list[mid].number == atr)
02103         {
02104             *pLen = list[mid].size - 1;
02105             return list[mid].data;
02106         }
02107     }
02108     *pLen = 0;
02109     return NULL;
02110 }
02111 
02112 #else // MEMORY_BASED
02113 
02114 const char *atr_get_raw_LEN(dbref thing, int atr, size_t *pLen)
02115 {
02116     Aname okey;
02117 
02118     makekey(thing, atr, &okey);
02119     int nLen;
02120     const char *a = cache_get(&okey, &nLen);
02121     nLen = a ? (nLen-1) : 0;
02122     *pLen = nLen;
02123     return a;
02124 }
02125 #endif // MEMORY_BASED
02126 
02127 const char *atr_get_raw(dbref thing, int atr)
02128 {
02129     size_t Len;
02130     return atr_get_raw_LEN(thing, atr, &Len);
02131 }
02132 
02133 char *atr_get_str_LEN(char *s, dbref thing, int atr, dbref *owner, int *flags,
02134     size_t *pLen)
02135 {
02136     const char *buff = atr_get_raw_LEN(thing, atr, pLen);
02137     if (!buff)
02138     {
02139         *owner = Owner(thing);
02140         *flags = 0;
02141         *pLen = 0;
02142         *s = '\0';
02143     }
02144     else
02145     {
02146         atr_decode_LEN(buff, *pLen, s, thing, owner, flags, pLen);
02147     }
02148     return s;
02149 }
02150 
02151 char *atr_get_str(char *s, dbref thing, int atr, dbref *owner, int *flags)
02152 {
02153     size_t nLen;
02154     return atr_get_str_LEN(s, thing, atr, owner, flags, &nLen);
02155 }
02156 
02157 char *atr_get_LEN(dbref thing, int atr, dbref *owner, int *flags, size_t *pLen)
02158 {
02159     char *buff = alloc_lbuf("atr_get");
02160     return atr_get_str_LEN(buff, thing, atr, owner, flags, pLen);
02161 }
02162 
02163 char *atr_get_real(dbref thing, int atr, dbref *owner, int *flags,
02164     const char *file, const int line)
02165 {
02166     size_t nLen;
02167     char *buff = pool_alloc_lbuf("atr_get", file, line);
02168     return atr_get_str_LEN(buff, thing, atr, owner, flags, &nLen);
02169 }
02170 
02171 bool atr_get_info(dbref thing, int atr, dbref *owner, int *flags)
02172 {
02173     size_t nLen;
02174     const char *buff = atr_get_raw_LEN(thing, atr, &nLen);
02175     if (!buff)
02176     {
02177         *owner = Owner(thing);
02178         *flags = 0;
02179         return false;
02180     }
02181     atr_decode_LEN(buff, nLen, NULL, thing, owner, flags, &nLen);
02182     return true;
02183 }
02184 
02185 char *atr_pget_str_LEN(char *s, dbref thing, int atr, dbref *owner, int *flags, size_t *pLen)
02186 {
02187     dbref parent;
02188     int lev;
02189     ATTR *ap;
02190     const char *buff;
02191 
02192     ITER_PARENTS(thing, parent, lev)
02193     {
02194         buff = atr_get_raw_LEN(parent, atr, pLen);
02195         if (buff && *buff)
02196         {
02197             atr_decode_LEN(buff, *pLen, s, thing, owner, flags, pLen);
02198             if (  lev == 0
02199                || !(*flags & AF_PRIVATE))
02200             {
02201                 return s;
02202             }
02203         }
02204         if (  lev == 0
02205            && Good_obj(Parent(parent)))
02206         {
02207             ap = atr_num(atr);
02208             if (!ap || ap->flags & AF_PRIVATE)
02209             {
02210                 break;
02211             }
02212         }
02213     }
02214     *owner = Owner(thing);
02215     *flags = 0;
02216     *s = '\0';
02217     *pLen = 0;
02218     return s;
02219 }
02220 
02221 char *atr_pget_str(char *s, dbref thing, int atr, dbref *owner, int *flags)
02222 {
02223     size_t nLen;
02224     return atr_pget_str_LEN(s, thing, atr, owner, flags, &nLen);
02225 }
02226 
02227 char *atr_pget_LEN(dbref thing, int atr, dbref *owner, int *flags, size_t *pLen)
02228 {
02229     char *buff = alloc_lbuf("atr_pget");
02230     return atr_pget_str_LEN(buff, thing, atr, owner, flags, pLen);
02231 }
02232 
02233 char *atr_pget_real(dbref thing, int atr, dbref *owner, int *flags,
02234     const char *file, const int line)
02235 {
02236     size_t nLen;
02237     char *buff = pool_alloc_lbuf("atr_pget", file, line);
02238     return atr_pget_str_LEN(buff, thing, atr, owner, flags, &nLen);
02239 }
02240 
02241 bool atr_pget_info(dbref thing, int atr, dbref *owner, int *flags)
02242 {
02243     dbref parent;
02244     int lev;
02245     ATTR *ap;
02246 
02247     ITER_PARENTS(thing, parent, lev)
02248     {
02249         size_t nLen;
02250         const char *buff = atr_get_raw_LEN(parent, atr, &nLen);
02251         if (buff && *buff)
02252         {
02253             atr_decode_LEN(buff, nLen, NULL, thing, owner, flags, &nLen);
02254             if ((lev == 0) || !(*flags & AF_PRIVATE))
02255             {
02256                 return true;
02257             }
02258         }
02259         if ((lev == 0) && Good_obj(Parent(parent)))
02260         {
02261             ap = atr_num(atr);
02262             if (!ap || ap->flags & AF_PRIVATE)
02263                 break;
02264         }
02265     }
02266     *owner = Owner(thing);
02267     *flags = 0;
02268     return false;
02269 }
02270 
02271 /* ---------------------------------------------------------------------------
02272  * atr_free: Reset all attributes of an object.
02273  */
02274 
02275 void atr_free(dbref thing)
02276 {
02277 #ifdef MEMORY_BASED
02278     if (db[thing].pALHead)
02279     {
02280         MEMFREE(db[thing].pALHead);
02281     }
02282     db[thing].pALHead  = NULL;
02283     db[thing].nALAlloc = 0;
02284     db[thing].nALUsed  = 0;
02285 #else // MEMORY_BASED
02286     char *as;
02287     atr_push();
02288     for (int atr = atr_head(thing, &as); atr; atr = atr_next(&as))
02289     {
02290         atr_clr(thing, atr);
02291     }
02292     atr_pop();
02293     if (mudstate.mod_al_id == thing)
02294     {
02295         al_store(); // remove from cache
02296     }
02297     atr_clr(thing, A_LIST);
02298 #endif // MEMORY_BASED
02299 
02300     mudstate.bfCommands.Clear(thing);
02301     mudstate.bfNoCommands.Set(thing);
02302     mudstate.bfListens.Clear(thing);
02303     mudstate.bfNoListens.Set(thing);
02304 }
02305 
02306 /* ---------------------------------------------------------------------------
02307  * atr_cpy: Copy all attributes from one object to another.
02308  */
02309 
02310 void atr_cpy(dbref dest, dbref source, bool bInternal)
02311 {
02312     dbref owner = Owner(dest);
02313 
02314     char *as;
02315     atr_push();
02316     for (int atr = atr_head(source, &as); atr; atr = atr_next(&as))
02317     {
02318         int   aflags;
02319         dbref aowner;
02320         char *buf = atr_get(source, atr, &aowner, &aflags);
02321 
02322         if (!(aflags & AF_LOCK))
02323         {
02324             // Change owner.
02325             //
02326             aowner = owner;
02327         }
02328 
02329         ATTR *at = atr_num(atr);
02330         if (  atr
02331            && at)
02332         {
02333             if (  !(at->flags & (AF_INTERNAL|AF_NOCLONE))
02334                && (  bInternal
02335                   || God(owner)
02336                   || (  !God(dest)
02337                      && !(aflags & AF_LOCK)
02338                      && (  (  Controls(owner, dest)
02339                            && !(at->flags & (AF_WIZARD|AF_GOD))
02340                            && !(aflags & (AF_WIZARD|AF_GOD)))
02341                         || (  Wizard(owner)
02342                            && !(at->flags & AF_GOD))))))
02343             {
02344                 // Only set attrs that owner has perm to set.
02345                 //
02346                 atr_add(dest, atr, buf, aowner, aflags);
02347             }
02348         }
02349         free_lbuf(buf);
02350     }
02351     atr_pop();
02352 }
02353 
02354 /* ---------------------------------------------------------------------------
02355  * atr_chown: Change the ownership of the attributes of an object to the
02356  * current owner if they are not locked.
02357  */
02358 
02359 void atr_chown(dbref obj)
02360 {
02361     dbref owner = Owner(obj);
02362 
02363     char *as;
02364     atr_push();
02365     for (int atr = atr_head(obj, &as); atr; atr = atr_next(&as))
02366     {
02367         int   aflags;
02368         dbref aowner;
02369         char *buf = atr_get(obj, atr, &aowner, &aflags);
02370         if (  aowner != owner
02371            && !(aflags & AF_LOCK))
02372         {
02373             atr_add(obj, atr, buf, owner, aflags);
02374         }
02375         free_lbuf(buf);
02376     }
02377     atr_pop();
02378 }
02379 
02380 /* ---------------------------------------------------------------------------
02381  * atr_next: Return next attribute in attribute list.
02382  */
02383 
02384 int atr_next(char **attrp)
02385 {
02386 #ifdef MEMORY_BASED
02387     ATRCOUNT *atr;
02388 
02389     if (!attrp || !*attrp)
02390     {
02391         return 0;
02392     }
02393     else
02394     {
02395         atr = (ATRCOUNT *) * attrp;
02396         if (atr->count >= db[atr->thing].nALUsed)
02397         {
02398             MEMFREE(atr);
02399             atr = NULL;
02400             return 0;
02401         }
02402         atr->count++;
02403         return db[atr->thing].pALHead[atr->count - 1].number;
02404     }
02405 
02406 #else // MEMORY_BASED
02407     if (!*attrp || !**attrp)
02408     {
02409         return 0;
02410     }
02411     else
02412     {
02413         return al_decode(attrp);
02414     }
02415 #endif // MEMORY_BASED
02416 }
02417 
02418 /* ---------------------------------------------------------------------------
02419  * atr_push, atr_pop: Push and pop attr lists.
02420  */
02421 
02422 void atr_push(void)
02423 {
02424 #ifndef MEMORY_BASED
02425     ALIST *new_alist = (ALIST *) alloc_sbuf("atr_push");
02426     new_alist->data = mudstate.iter_alist.data;
02427     new_alist->len = mudstate.iter_alist.len;
02428     new_alist->next = mudstate.iter_alist.next;
02429 
02430     mudstate.iter_alist.data = NULL;
02431     mudstate.iter_alist.len = 0;
02432     mudstate.iter_alist.next = new_alist;
02433 #endif // !MEMORY_BASED
02434 }
02435 
02436 void atr_pop(void)
02437 {
02438 #ifndef MEMORY_BASED
02439     ALIST *old_alist = mudstate.iter_alist.next;
02440 
02441     if (mudstate.iter_alist.data)
02442     {
02443         MEMFREE(mudstate.iter_alist.data);
02444         mudstate.iter_alist.data = NULL;
02445     }
02446     if (old_alist)
02447     {
02448         mudstate.iter_alist.data = old_alist->data;
02449         mudstate.iter_alist.len = old_alist->len;
02450         mudstate.iter_alist.next = old_alist->next;
02451         char *cp = (char *)old_alist;
02452         free_sbuf(cp);
02453     }
02454     else
02455     {
02456         mudstate.iter_alist.data = NULL;
02457         mudstate.iter_alist.len = 0;
02458         mudstate.iter_alist.next = NULL;
02459     }
02460 #endif // !MEMORY_BASED
02461 }
02462 
02463 /* ---------------------------------------------------------------------------
02464  * atr_head: Returns the head of the attr list for object 'thing'
02465  */
02466 
02467 int atr_head(dbref thing, char **attrp)
02468 {
02469 #ifdef MEMORY_BASED
02470     if (db[thing].nALUsed)
02471     {
02472         ATRCOUNT *atr = (ATRCOUNT *) MEMALLOC(sizeof(ATRCOUNT));
02473         ISOUTOFMEMORY(atr);
02474         atr->thing = thing;
02475         atr->count = 1;
02476         *attrp = (char *)atr;
02477         return db[thing].pALHead[0].number;
02478     }
02479     return 0;
02480 #else // MEMORY_BASED
02481     const char *astr;
02482     size_t alen;
02483 
02484     // Get attribute list.  Save a read if it is in the modify atr list
02485     //
02486     if (thing == mudstate.mod_al_id)
02487     {
02488         astr = mudstate.mod_alist;
02489         alen = mudstate.mod_alist_len;
02490     }
02491     else
02492     {
02493         astr = atr_get_raw_LEN(thing, A_LIST, &alen);
02494     }
02495 
02496     // If no list, return nothing.
02497     //
02498     if (!alen)
02499     {
02500         return 0;
02501     }
02502 
02503     // Set up the list and return the first entry.
02504     //
02505     al_extend(&mudstate.iter_alist.data, &mudstate.iter_alist.len, alen+1, false);
02506     memcpy(mudstate.iter_alist.data, astr, alen+1);
02507     *attrp = mudstate.iter_alist.data;
02508     return atr_next(attrp);
02509 #endif // MEMORY_BASED
02510 }
02511 
02512 
02513 /* ---------------------------------------------------------------------------
02514  * db_grow: Extend the struct database.
02515  */
02516 
02517 #define SIZE_HACK   1   // So mistaken refs to #-1 won't die.
02518 
02519 static void initialize_objects(dbref first, dbref last)
02520 {
02521     dbref thing;
02522 
02523     for (thing = first; thing < last; thing++)
02524     {
02525         s_Owner(thing, GOD);
02526         s_Flags(thing, FLAG_WORD1, (TYPE_GARBAGE | GOING));
02527         s_Powers(thing, 0);
02528         s_Powers2(thing, 0);
02529         s_Location(thing, NOTHING);
02530         s_Contents(thing, NOTHING);
02531         s_Exits(thing, NOTHING);
02532         s_Link(thing, NOTHING);
02533         s_Next(thing, NOTHING);
02534         s_Zone(thing, NOTHING);
02535         s_Parent(thing, NOTHING);
02536         s_Stack(thing, NULL);
02537         db[thing].cpu_time_used.Set100ns(0);
02538         db[thing].tThrottleExpired.Set100ns(0);
02539         s_ThAttrib(thing, 0);
02540         s_ThMail(thing, 0);
02541 
02542 #ifdef MEMORY_BASED
02543         db[thing].pALHead  = NULL;
02544         db[thing].nALAlloc = 0;
02545         db[thing].nALUsed  = 0;
02546 #else
02547         db[thing].name = NULL;
02548 #endif // MEMORY_BASED
02549         db[thing].purename = NULL;
02550         db[thing].moniker = NULL;
02551     }
02552 }
02553 
02554 void db_grow(dbref newtop)
02555 {
02556     mudstate.bfCommands.Resize(newtop);
02557     mudstate.bfNoCommands.Resize(newtop);
02558     mudstate.bfListens.Resize(newtop);
02559     mudstate.bfNoListens.Resize(newtop);
02560 
02561     int delta;
02562     if (mudstate.bStandAlone)
02563     {
02564         delta = 1000;
02565     }
02566     else
02567     {
02568         delta = mudconf.init_size;
02569     }
02570 
02571     // Determine what to do based on requested size, current top and size.
02572     // Make sure we grow in reasonable-sized chunks to prevent frequent
02573     // reallocations of the db array.
02574     //
02575     // If requested size is smaller than the current db size, ignore it.
02576     //
02577     if (newtop <= mudstate.db_top)
02578     {
02579         return;
02580     }
02581 
02582     // If requested size is greater than the current db size but smaller
02583     // than the amount of space we have allocated, raise the db size and
02584     // initialize the new area.
02585     //
02586     if (newtop <= mudstate.db_size)
02587     {
02588         initialize_objects(mudstate.db_top, newtop);
02589         mudstate.db_top = newtop;
02590         return;
02591     }
02592 
02593     // Grow by a minimum of delta objects
02594     //
02595     int newsize;
02596     if (newtop <= mudstate.db_size + delta)
02597     {
02598         newsize = mudstate.db_size + delta;
02599     }
02600     else
02601     {
02602         newsize = newtop;
02603     }
02604 
02605     // Enforce minimum database size
02606     //
02607     if (newsize < mudstate.min_size)
02608     {
02609         newsize = mudstate.min_size + delta;
02610     }
02611 
02612     // Grow the db array
02613     //
02614 
02615     // NOTE: There is always one copy of 'db' around that isn't freed even
02616     // just before the process terminates. We rely (quite safely) on the OS
02617     // to reclaim the memory.
02618     //
02619     OBJ *newdb = (OBJ *)MEMALLOC((newsize + SIZE_HACK) * sizeof(OBJ));
02620     ISOUTOFMEMORY(newdb);
02621     if (db)
02622     {
02623         // An old struct database exists. Copy it to the new buffer.
02624         //
02625         db -= SIZE_HACK;
02626         memcpy(newdb, db, (mudstate.db_top + SIZE_HACK) * sizeof(OBJ));
02627         MEMFREE(db);
02628     }
02629     else
02630     {
02631         // Creating a brand new struct database. Fill in the 'reserved' area
02632         // in case it is referenced.
02633         //
02634         db = newdb;
02635         initialize_objects(0, SIZE_HACK);
02636     }
02637     db = newdb + SIZE_HACK;
02638     newdb = NULL;
02639 
02640     initialize_objects(mudstate.db_top, newtop);
02641     mudstate.db_top = newtop;
02642     mudstate.db_size = newsize;
02643 
02644     // Grow the db mark buffer.
02645     //
02646     int marksize = (newsize + 7) >> 3;
02647     MARKBUF *newmarkbuf = (MARKBUF *)MEMALLOC(marksize);
02648     ISOUTOFMEMORY(newmarkbuf);
02649     memset(newmarkbuf, 0, marksize);
02650     if (mudstate.markbits)
02651     {
02652         marksize = (newtop + 7) >> 3;
02653         memcpy(newmarkbuf, mudstate.markbits, marksize);
02654         MEMFREE(mudstate.markbits);
02655     }
02656     mudstate.markbits = newmarkbuf;
02657 }
02658 
02659 void db_free(void)
02660 {
02661     char *cp;
02662 
02663     if (db != NULL)
02664     {
02665         db -= SIZE_HACK;
02666         cp = (char *)db;
02667         MEMFREE(cp);
02668         cp = NULL;
02669         db = NULL;
02670     }
02671     mudstate.db_top = 0;
02672     mudstate.db_size = 0;
02673     mudstate.freelist = NOTHING;
02674 }
02675 
02676 void db_make_minimal(void)
02677 {
02678     db_free();
02679     db_grow(1);
02680     s_Name(0, "Limbo");
02681     s_Flags(0, FLAG_WORD1, TYPE_ROOM);
02682     s_Flags(0, FLAG_WORD2, 0);
02683     s_Flags(0, FLAG_WORD3, 0);
02684     s_Powers(0, 0);
02685     s_Powers2(0, 0);
02686     s_Location(0, NOTHING);
02687     s_Exits(0, NOTHING);
02688     s_Link(0, NOTHING);
02689     s_Parent(0, NOTHING);
02690     s_Zone(0, NOTHING);
02691     s_Pennies(0, 0);
02692     s_Owner(0, 1);
02693 
02694     // should be #1
02695     //
02696     load_player_names();
02697     const char *pmsg;
02698     dbref obj = create_player("Wizard", "potrzebie", NOTHING, false, &pmsg);
02699     s_Flags(obj, FLAG_WORD1, Flags(obj) | WIZARD);
02700     s_Powers(obj, 0);
02701     s_Powers2(obj, 0);
02702     s_Pennies(obj, 1000);
02703 
02704     // Manually link to Limbo, just in case
02705     //
02706     s_Location(obj, 0);
02707     s_Next(obj, NOTHING);
02708     s_Contents(0, obj);
02709     s_Link(obj, 0);
02710 }
02711 
02712 dbref parse_dbref(const char *s)
02713 {
02714     // Enforce completely numeric dbrefs
02715     //
02716     const char *p = s;
02717     if (p[0])
02718     {
02719         do
02720         {
02721             if (!mux_isdigit(*p))
02722             {
02723                 return NOTHING;
02724             }
02725             p++;
02726         } while (*p);
02727     }
02728     else
02729     {
02730         return NOTHING;
02731     }
02732     int x = mux_atol(s);
02733     return ((x >= 0) ? x : NOTHING);
02734 }
02735 
02736 
02737 void putref(FILE *f, dbref ref)
02738 {
02739     char buf[SBUF_SIZE];
02740     int n = mux_ltoa(ref, buf);
02741     buf[n] = '\n';
02742     fwrite(buf, sizeof(char), n+1, f);
02743 }
02744 
02745 // Code 0 - Any byte.
02746 // Code 1 - NUL  (0x00)
02747 // Code 2 - '"'  (0x22)
02748 // Code 3 - '\\' (0x5C)
02749 // Code 4 - 'e'  (0x65) or 'E' (0x45)
02750 // Code 5 - 'n'  (0x6E) or 'N' (0x4E)
02751 // Code 6 - 'r'  (0x72) or 'R' (0x52)
02752 // Code 7 - 't'  (0x74) or 'T' (0x54)
02753 //
02754 static const unsigned char decode_table[256] =
02755 {
02756     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02757     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02758     0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02759     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02760     0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0,
02761     0, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,
02762     0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0,
02763     0, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02764     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02765     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02766     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02767     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02768     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02769     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02770     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02771     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
02772 };
02773 
02774 #define STATE_START     0
02775 #define STATE_HAVE_ESC  1
02776 
02777 
02778 // Action 0 - Emit X.
02779 // Action 1 - Get a Buffer.
02780 // Action 2 - Emit X. Move to START state.
02781 // Action 3 - Terminate parse.
02782 // Action 4 - Move to ESC state.
02783 // Action 5 - Emit ESC (0x1B). Move to START state.
02784 // Action 6 - Emit LF  (0x0A). Move to START state.
02785 // Action 7 - Emit CR  (0x0D). Move to START state.
02786 // Action 8 - Emit TAB (0x09). Move to START state.
02787 //
02788 
02789 static const int action_table[2][8] =
02790 {
02791 //   Any  '\0' '"'  '\\' 'e'  'n'  'r'  't'
02792     { 0,   1,   3,   4,   0,   0,   0,   0}, // STATE_START
02793     { 2,   1,   2,   2,   5,   6,   7,   8}  // STATE_HAVE_ESC
02794 };
02795 
02796 char *getstring_noalloc(FILE *f, int new_strings)
02797 {
02798     static char buf[2*LBUF_SIZE + 20];
02799     int c = fgetc(f);
02800     if (new_strings && c == '"')
02801     {
02802         int nBufferLeft = sizeof(buf)-10;
02803         int iState = STATE_START;
02804         char *pOutput = buf;
02805         for (;;)
02806         {
02807             // Fetch up to and including the next LF.
02808             //
02809             char *pInput = pOutput + 6;
02810             if (fgets(pInput, nBufferLeft, f) == NULL)
02811             {
02812                 // EOF or ERROR.
02813                 //
02814                 *pOutput = 0;
02815                 return buf;
02816             }
02817 
02818             int nOutput = 0;
02819 
02820             // De-escape this data. removing the '\\' prefixes.
02821             // Terminate when you hit a '"'.
02822             //
02823             for (;;)
02824             {
02825                 char ch = *pInput++;
02826                 if (iState == STATE_START)
02827                 {
02828                     if (decode_table[(unsigned char)ch] == 0)
02829                     {
02830                         // As long as decode_table[*p] is 0, just keep copying the characters.
02831                         //
02832                         char *p = pOutput;
02833                         do
02834                         {
02835                             *pOutput++ = ch;
02836                             ch = *pInput++;
02837                         } while (decode_table[(unsigned char)ch] == 0);
02838                         nOutput = pOutput - p;
02839                     }
02840                 }
02841                 int iAction = action_table[iState][decode_table[(unsigned char)ch]];
02842                 if (iAction <= 2)
02843                 {
02844                     if (iAction == 1)
02845                     {
02846                         // Get Buffer and remain in the current state.
02847                         //
02848                         break;
02849                     }
02850                     else
02851                     {
02852                         // iAction == 2
02853                         // Emit X and move to START state.
02854                         //
02855                         *pOutput++ = ch;
02856                         nOutput++;
02857                         iState = STATE_START;
02858                     }
02859                 }
02860                 else if (iAction == 3)
02861                 {
02862                     // Terminate parsing.
02863                     //
02864                     *pOutput = 0;
02865                     return buf;
02866                 }
02867                 else if (iAction == 4)
02868                 {
02869                     // Move to ESC state.
02870                     //
02871                     iState = STATE_HAVE_ESC;
02872                 }
02873                 else if (iAction == 5)
02874                 {
02875                     *pOutput++ = ESC_CHAR;
02876                     nOutput++;
02877                     iState = STATE_START;
02878                 }
02879                 else if (iAction == 6)
02880                 {
02881                     *pOutput++ = '\n';
02882                     nOutput++;
02883                     iState = STATE_START;
02884                 }
02885                 else if (iAction == 7)
02886                 {
02887                     *pOutput++ = '\r';
02888                     nOutput++;
02889                     iState = STATE_START;
02890                 }
02891                 else
02892                 {
02893                     // if (iAction == 8)
02894                     *pOutput++ = '\t';
02895                     nOutput++;
02896                     iState = STATE_START;
02897                 }
02898             }
02899 
02900             nBufferLeft -= nOutput;
02901 
02902             // Do we have any more room?
02903             //
02904             if (nBufferLeft <= 0)
02905             {
02906                 *pOutput = 0;
02907                 return buf;
02908             }
02909         }
02910     }
02911     else
02912     {
02913         ungetc(c, f);
02914 
02915         char *p = buf;
02916         for (;;)
02917         {
02918             // Fetch up to and including the next LF.
02919             //
02920             if (fgets(p, LBUF_SIZE, f) == NULL)
02921             {
02922                 // EOF or ERROR.
02923                 //
02924                 p[0] = 0;
02925             }
02926             else
02927             {
02928                 // How much data did we fetch?
02929                 //
02930                 int nLine = strlen(p);
02931                 if (nLine >= 2)
02932                 {
02933                     if (p[nLine-2] == '\r')
02934                     {
02935                         // Line is continued on the next line.
02936                         //
02937                         p += nLine;
02938                         continue;
02939                     }
02940 
02941                     // Eat '\n'
02942                     //
02943                     p[nLine-1] = '\0';
02944                 }
02945             }
02946             return buf;
02947         }
02948     }
02949 }
02950 
02951 // Code 0 - Any byte.
02952 // Code 1 - NUL (0x00)
02953 // Code 2 - '"' (0x22)
02954 // Code 3 - '\\' (0x5C)
02955 //
02956 static const unsigned char encode_table[256] =
02957 {
02958     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02959     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02960     0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02961     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02962     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02963     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,
02964     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02965     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02966     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02967     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02968     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02969     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02970     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02971     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02972     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02973     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
02974 };
02975 
02976 void putstring(FILE *f, const char *pRaw)
02977 {
02978     static char aBuffer[2*LBUF_SIZE+4];
02979     char *pBuffer = aBuffer;
02980 
02981     // Always leave room for four characters. One at the beginning and
02982     // three on the end. '\\"\n' or '\""\n'
02983     //
02984     *pBuffer++ = '"';
02985 
02986     if (pRaw)
02987     {
02988         for (;;)
02989         {
02990             char ch;
02991             while ((ch = encode_table[(unsigned char)*pRaw]) == 0)
02992             {
02993                 *pBuffer++ = *pRaw++;
02994             }
02995             if (ch == 1)
02996             {
02997                 break;
02998             }
02999             *pBuffer++ = '\\';
03000             *pBuffer++ = *pRaw++;
03001         }
03002     }
03003 
03004     *pBuffer++ = '"';
03005     *pBuffer++ = '\n';
03006 
03007     fwrite(aBuffer, sizeof(char), pBuffer - aBuffer, f);
03008 }
03009 
03010 int getref(FILE *f)
03011 {
03012     static char buf[SBUF_SIZE];
03013     fgets(buf, sizeof(buf), f);
03014     return mux_atol(buf);
03015 }
03016 
03017 void free_boolexp(BOOLEXP *b)
03018 {
03019     if (b == TRUE_BOOLEXP)
03020         return;
03021 
03022     switch (b->type)
03023     {
03024     case BOOLEXP_AND:
03025     case BOOLEXP_OR:
03026         free_boolexp(b->sub1);
03027         free_boolexp(b->sub2);
03028         free_bool(b);
03029         break;
03030     case BOOLEXP_NOT:
03031     case BOOLEXP_CARRY:
03032     case BOOLEXP_IS:
03033     case BOOLEXP_OWNER:
03034     case BOOLEXP_INDIR:
03035         free_boolexp(b->sub1);
03036         free_bool(b);
03037         break;
03038     case BOOLEXP_CONST:
03039         free_bool(b);
03040         break;
03041     case BOOLEXP_ATR:
03042     case BOOLEXP_EVAL:
03043         MEMFREE(b->sub1);
03044         b->sub1 = NULL;
03045         free_bool(b);
03046         break;
03047     }
03048 }
03049 
03050 static BOOLEXP *dup_bool(BOOLEXP *b)
03051 {
03052     if (b == TRUE_BOOLEXP)
03053         return (TRUE_BOOLEXP);
03054 
03055     BOOLEXP *r = alloc_bool("dup_bool");
03056     switch (r->type = b->type)
03057     {
03058     case BOOLEXP_AND:
03059     case BOOLEXP_OR:
03060         r->sub2 = dup_bool(b->sub2);
03061     case BOOLEXP_NOT:
03062     case BOOLEXP_CARRY:
03063     case BOOLEXP_IS:
03064     case BOOLEXP_OWNER:
03065     case BOOLEXP_INDIR:
03066         r->sub1 = dup_bool(b->sub1);
03067     case BOOLEXP_CONST:
03068         r->thing = b->thing;
03069         break;
03070     case BOOLEXP_EVAL:
03071     case BOOLEXP_ATR:
03072         r->thing = b->thing;
03073         r->sub1 = (BOOLEXP *)StringClone((char *)b->sub1);
03074         break;
03075     default:
03076         Log.WriteString("Bad bool type!" ENDLINE);
03077         return TRUE_BOOLEXP;
03078     }
03079     return (r);
03080 }
03081 
03082 #ifndef MEMORY_BASED
03083 int init_dbfile(char *game_dir_file, char *game_pag_file, int nCachePages)
03084 {
03085     if (mudstate.bStandAlone)
03086     {
03087         Log.tinyprintf("Opening (%s,%s)" ENDLINE, game_dir_file, game_pag_file);
03088     }
03089     int cc = cache_init(game_dir_file, game_pag_file, nCachePages);
03090     if (cc != HF_OPEN_STATUS_ERROR)
03091     {
03092         if (mudstate.bStandAlone)
03093         {
03094             Log.tinyprintf("Done opening (%s,%s)." ENDLINE, game_dir_file,
03095                 game_pag_file);
03096         }
03097         else
03098         {
03099             STARTLOG(LOG_ALWAYS, "INI", "LOAD");
03100             Log.tinyprintf("Using game db files: (%s,%s).", game_dir_file,
03101                 game_pag_file);
03102             ENDLOG;
03103         }
03104         db_free();
03105     }
03106     return cc;
03107 }
03108 #endif // !MEMORY_BASED
03109 
03110 // check_zone - checks back through a zone tree for control.
03111 //
03112 bool check_zone_handler(dbref player, dbref thing, bool bPlayerCheck)
03113 {
03114     mudstate.zone_nest_num++;
03115 
03116     if (  !mudconf.have_zones
03117        || !Good_obj(Zone(thing))
03118        || mudstate.zone_nest_num >= mudconf.zone_nest_lim
03119        || isPlayer(thing) != bPlayerCheck)
03120     {
03121         mudstate.zone_nest_num = 0;
03122         return false;
03123     }
03124 
03125     // If the zone doesn't have an enterlock, DON'T allow control.
03126     //
03127     if (  atr_get_raw(Zone(thing), A_LENTER)
03128        && could_doit(player, Zone(thing), A_LENTER))
03129     {
03130         mudstate.zone_nest_num = 0;
03131         return true;
03132     }
03133     else if (thing == Zone(thing))
03134     {
03135         return false;
03136     }
03137     return check_zone_handler(player, Zone(thing), false);
03138 }
03139 
03140 // This function releases:
03141 //
03142 //  1. comsys resources associated with an object.
03143 //  2. @mail resources associated with an object.
03144 //
03145 void ReleaseAllResources(dbref obj)
03146 {
03147     if (mudconf.have_comsys)
03148     {
03149         do_comdisconnect(obj);
03150         do_clearcom(obj, obj, obj, 0);
03151         do_channelnuke(obj);
03152         del_comsys(obj);
03153     }
03154     if (mudconf.have_mailer)
03155     {
03156         do_mail_clear(obj, NULL);
03157         do_mail_purge(obj);
03158         malias_cleanup(obj);
03159     }
03160 }
03161 
03162 #ifndef WIN32
03163 /* ---------------------------------------------------------------------------
03164  * dump_restart_db: Writes out socket information.
03165  */
03166 void dump_restart_db(void)
03167 {
03168     FILE *f;
03169     DESC *d;
03170     int version = 2;
03171 
03172     f = fopen("restart.db", "wb");
03173     fprintf(f, "+V%d\n", version);
03174     putref(f, nMainGamePorts);
03175     for (int i = 0; i < nMainGamePorts; i++)
03176     {
03177         putref(f, aMainGamePorts[i].port);
03178         putref(f, aMainGamePorts[i].socket);
03179     }
03180     putref(f, mudstate.start_time.ReturnSeconds());
03181     putstring(f, mudstate.doing_hdr);
03182     putref(f, mudstate.record_players);
03183     DESC_ITER_ALL(d)
03184     {
03185         putref(f, d->descriptor);
03186         putref(f, d->flags);
03187         putref(f, d->connected_at.ReturnSeconds());
03188         putref(f, d->command_count);
03189         putref(f, d->timeout);
03190         putref(f, d->host_info);
03191         putref(f, d->player);
03192         putref(f, d->last_time.ReturnSeconds());
03193         putref(f, d->raw_input_state);
03194         putref(f, d->nvt_sga_him_state);
03195         putref(f, d->nvt_sga_us_state);
03196         putref(f, d->nvt_eor_him_state);
03197         putref(f, d->nvt_eor_us_state);
03198         putref(f, d->nvt_naws_him_state);
03199         putref(f, d->nvt_naws_us_state);
03200         putref(f, d->height);
03201         putref(f, d->width);
03202         putstring(f, d->output_prefix);
03203         putstring(f, d->output_suffix);
03204         putstring(f, d->addr);
03205         putstring(f, d->doing);
03206         putstring(f, d->username);
03207     }
03208     putref(f, 0);
03209 
03210     fclose(f);
03211 }
03212 
03213 void load_restart_db(void)
03214 {
03215     DESC *d;
03216     DESC *p;
03217 
03218     int val;
03219     char *temp, buf[8];
03220 
03221     FILE *f = fopen("restart.db", "r");
03222     if (!f)
03223     {
03224         mudstate.restarting = false;
03225         return;
03226     }
03227     DebugTotalFiles++;
03228     mudstate.restarting = true;
03229 
03230     fgets(buf, 3, f);
03231     mux_assert(strncmp(buf, "+V", 2) == 0);
03232     int version = getref(f);
03233     if (  1 == version
03234        || 2 == version)
03235     {
03236         // Version 1 started on 2001-DEC-03
03237         // Version 2 started on 2005-NOV-08
03238         //
03239         nMainGamePorts = getref(f);
03240         for (int i = 0; i < nMainGamePorts; i++)
03241         {
03242             aMainGamePorts[i].port   = getref(f);
03243             mux_assert(aMainGamePorts[i].port > 0);
03244             aMainGamePorts[i].socket = getref(f);
03245             if (maxd <= aMainGamePorts[i].socket)
03246             {
03247                 maxd = aMainGamePorts[i].socket + 1;
03248             }
03249         }
03250     }
03251     else
03252     {
03253         // The restart file, restart.db, has a version other than 1.  You
03254         // cannot @restart from the previous version to the new version.  Use
03255         // @shutdown instead.
03256         //
03257         mux_assert(0);
03258     }
03259     DebugTotalSockets += nMainGamePorts;
03260 
03261     mudstate.start_time.SetSeconds(getref(f));
03262     strcpy(mudstate.doing_hdr, getstring_noalloc(f, true));
03263     mudstate.record_players = getref(f);
03264     if (mudconf.reset_players)
03265     {
03266         mudstate.record_players = 0;
03267     }
03268 
03269     while ((val = getref(f)) != 0)
03270     {
03271         ndescriptors++;
03272         DebugTotalSockets++;
03273         d = alloc_desc("restart");
03274         d->descriptor = val;
03275         d->flags = getref(f);
03276         d->connected_at.SetSeconds(getref(f));
03277         d->command_count = getref(f);
03278         d->timeout = getref(f);
03279         d->host_info = getref(f);
03280         d->player = getref(f);
03281         d->last_time.SetSeconds(getref(f));
03282         if (2 == version)
03283         {
03284             d->raw_input_state    = getref(f);
03285             d->nvt_sga_him_state  = getref(f);
03286             d->nvt_sga_us_state   = getref(f);
03287             d->nvt_eor_him_state  = getref(f);
03288             d->nvt_eor_us_state   = getref(f);
03289             d->nvt_naws_him_state = getref(f);
03290             d->nvt_naws_us_state  = getref(f);
03291             d->height = getref(f);
03292             d->width = getref(f);
03293         }
03294         else
03295         {
03296             d->raw_input_state    = NVT_IS_NORMAL;
03297             d->nvt_sga_him_state  = OPTION_NO;
03298             d->nvt_sga_us_state   = OPTION_NO;
03299             d->nvt_eor_him_state  = OPTION_NO;
03300             d->nvt_eor_us_state   = OPTION_NO;
03301             d->nvt_naws_him_state = OPTION_NO;
03302             d->nvt_naws_us_state  = OPTION_NO;
03303             d->height = 24;
03304             d->width = 78;
03305         }
03306 
03307         temp = getstring_noalloc(f, true);
03308         if (*temp)
03309         {
03310             d->output_prefix = alloc_lbuf("set_userstring");
03311             strcpy(d->output_prefix, temp);
03312         }
03313         else
03314         {
03315             d->output_prefix = NULL;
03316         }
03317         temp = getstring_noalloc(f, true);
03318         if (*temp)
03319         {
03320             d->output_suffix = alloc_lbuf("set_userstring");
03321             strcpy(d->output_suffix, temp);
03322         }
03323         else
03324         {
03325             d->output_suffix = NULL;
03326         }
03327 
03328         strcpy(d->addr, getstring_noalloc(f, true));
03329         strcpy(d->doing, getstring_noalloc(f, true));
03330         strcpy(d->username, getstring_noalloc(f, true));
03331 
03332         d->output_size = 0;
03333         d->output_tot = 0;
03334         d->output_lost = 0;
03335         d->output_head = NULL;
03336         d->output_tail = NULL;
03337         d->input_head = NULL;
03338         d->input_tail = NULL;
03339         d->input_size = 0;
03340         d->input_tot = 0;
03341         d->input_lost = 0;
03342         d->raw_input = NULL;
03343         d->raw_input_at = NULL;
03344         d->nOption = 0;
03345         d->quota = mudconf.cmd_quota_max;
03346         d->program_data = NULL;
03347         d->hashnext = NULL;
03348 
03349         if (descriptor_list)
03350         {
03351             for (p = descriptor_list; p->next; p = p->next) ;
03352             d->prev = &p->next;
03353             p->next = d;
03354             d->next = NULL;
03355         }
03356         else
03357         {
03358             d->next = descriptor_list;
03359             d->prev = &descriptor_list;
03360             descriptor_list = d;
03361         }
03362 
03363         if (maxd <= d->descriptor)
03364         {
03365             maxd = d->descriptor + 1;
03366         }
03367         desc_addhash(d);
03368         if (isPlayer(d->player))
03369         {
03370             s_Connected(d->player);
03371         }
03372     }
03373 
03374     DESC_ITER_CONN(d)
03375     {
03376         if (!isPlayer(d->player))
03377         {
03378             shutdownsock(d, R_QUIT);
03379         }
03380     }
03381 
03382     if (fclose(f) == 0)
03383     {
03384         DebugTotalFiles--;
03385     }
03386     remove("restart.db");
03387     raw_broadcast(0, "GAME: Restart finished.");
03388 }
03389 #endif // !WIN32
03390 
03391 #ifdef WIN32
03392 
03393 int ReplaceFile(char *old_name, char *new_name)
03394 {
03395     DeleteFile(new_name);
03396     if (MoveFile(old_name, new_name))
03397     {
03398         return 0;
03399     }
03400     else
03401     {
03402         Log.tinyprintf("MoveFile %s to %s fails with GetLastError() of %d" ENDLINE,
03403             old_name, new_name, GetLastError());
03404     }
03405     return -1;
03406 }
03407 
03408 void RemoveFile(char *name)
03409 {
03410     DeleteFile(name);
03411 }
03412 
03413 #else // WIN32
03414 
03415 int ReplaceFile(char *old_name, char *new_name)
03416 {
03417     if (rename(old_name, new_name) == 0)
03418     {
03419         return 0;
03420     }
03421     else
03422     {
03423         Log.tinyprintf("rename %s to %s fails with errno of %s(%d)" ENDLINE, old_name, new_name, strerror(errno), errno);
03424     }
03425     return -1;
03426 }
03427 
03428 void RemoveFile(char *name)
03429 {
03430     unlink(name);
03431 }
03432 #endif // WIN32
03433 

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