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