mux/src/predicates.cpp

Go to the documentation of this file.
00001 // predicates.cpp
00002 //
00003 // $Id: predicates.cpp,v 1.78 2007/04/14 04:57:05 sdennis Exp $
00004 //
00005 
00006 #include "copyright.h"
00007 #include "autoconf.h"
00008 #include "config.h"
00009 #include "externs.h"
00010 
00011 #include <signal.h>
00012 
00013 #include "ansi.h"
00014 #include "attrs.h"
00015 #include "command.h"
00016 #include "interface.h"
00017 #include "powers.h"
00018 #ifdef REALITY_LVLS
00019 #include "levels.h"
00020 #endif /* REALITY_LVLS */
00021 
00022 char * DCL_CDECL tprintf(const char *fmt,...)
00023 {
00024     static char buff[LBUF_SIZE];
00025     va_list ap;
00026     va_start(ap, fmt);
00027     mux_vsnprintf(buff, LBUF_SIZE, fmt, ap);
00028     va_end(ap);
00029     return buff;
00030 }
00031 
00032 void DCL_CDECL safe_tprintf_str(char *str, char **bp, const char *fmt,...)
00033 {
00034     va_list ap;
00035     va_start(ap, fmt);
00036     size_t nAvailable = LBUF_SIZE - (*bp - str);
00037     size_t len = mux_vsnprintf(*bp, (int)nAvailable, fmt, ap);
00038     va_end(ap);
00039     *bp += len;
00040 }
00041 
00042 /* ---------------------------------------------------------------------------
00043  * insert_first, remove_first: Insert or remove objects from lists.
00044  */
00045 
00046 dbref insert_first(dbref head, dbref thing)
00047 {
00048     s_Next(thing, head);
00049     return thing;
00050 }
00051 
00052 dbref remove_first(dbref head, dbref thing)
00053 {
00054     if (head == thing)
00055     {
00056         return Next(thing);
00057     }
00058 
00059     dbref prev;
00060 
00061     DOLIST(prev, head)
00062     {
00063         if (Next(prev) == thing)
00064         {
00065             s_Next(prev, Next(thing));
00066             return head;
00067         }
00068     }
00069     return head;
00070 }
00071 
00072 /* ---------------------------------------------------------------------------
00073  * reverse_list: Reverse the order of members in a list.
00074  */
00075 
00076 dbref reverse_list(dbref list)
00077 {
00078     dbref newlist, rest;
00079 
00080     newlist = NOTHING;
00081     while (list != NOTHING)
00082     {
00083         rest = Next(list);
00084         s_Next(list, newlist);
00085         newlist = list;
00086         list = rest;
00087     }
00088     return newlist;
00089 }
00090 
00091 /* ---------------------------------------------------------------------------
00092  * member - indicate if thing is in list
00093  */
00094 
00095 bool member(dbref thing, dbref list)
00096 {
00097     DOLIST(list, list)
00098     {
00099         if (list == thing)
00100         {
00101             return true;
00102         }
00103     }
00104     return false;
00105 }
00106 
00107 bool could_doit(dbref player, dbref thing, int locknum)
00108 {
00109     if (thing == HOME)
00110     {
00111         return true;
00112     }
00113 
00114     // If nonplayer tries to get key, then no.
00115     //
00116     if (  !isPlayer(player)
00117        && Key(thing))
00118     {
00119         return false;
00120     }
00121     if (Pass_Locks(player))
00122     {
00123         return true;
00124     }
00125 
00126     dbref aowner;
00127     int   aflags;
00128     char *key = atr_get(thing, locknum, &aowner, &aflags);
00129     bool doit = eval_boolexp_atr(player, thing, thing, key);
00130     free_lbuf(key);
00131     return doit;
00132 }
00133 
00134 bool can_see(dbref player, dbref thing, bool can_see_loc)
00135 {
00136     // Don't show if all the following apply: Sleeping players should not be
00137     // seen.  The thing is a disconnected player.  The player is not a
00138     // puppet.
00139     //
00140     if (  mudconf.dark_sleepers
00141        && isPlayer(thing)
00142        && !Connected(thing)
00143        && !Puppet(thing))
00144     {
00145         return false;
00146     }
00147 
00148     // You don't see yourself or exits.
00149     //
00150     if (  player == thing
00151        || isExit(thing))
00152     {
00153         return false;
00154     }
00155 
00156     // If loc is not dark, you see it if it's not dark or you control it.  If
00157     // loc is dark, you see it if you control it.  Seeing your own dark
00158     // objects is controlled by mudconf.see_own_dark.  In dark locations, you
00159     // also see things that are LIGHT and !DARK.
00160     //
00161     if (can_see_loc)
00162     {
00163 #ifdef REALITY_LVLS
00164        return ((!Dark(thing) && IsReal(player, thing)) ||
00165 #else
00166         return (!Dark(thing) ||
00167 #endif /* REALITY_LVLS */
00168             (mudconf.see_own_dark && MyopicExam(player, thing)));
00169     }
00170     else
00171     {
00172 #ifdef REALITY_LVLS
00173         return ((Light(thing) && !Dark(thing) && IsReal(player, thing)) ||
00174 #else
00175         return ((Light(thing) && !Dark(thing)) ||
00176 #endif /* REALITY_LVLS */
00177             (mudconf.see_own_dark && MyopicExam(player, thing)));
00178     }
00179 }
00180 
00181 static bool pay_quota(dbref who, int cost)
00182 {
00183     // If no cost, succeed
00184     //
00185     if (cost <= 0)
00186     {
00187         return true;
00188     }
00189 
00190     // determine quota
00191     //
00192     dbref aowner;
00193     int aflags;
00194     char *quota_str = atr_get(Owner(who), A_RQUOTA, &aowner, &aflags);
00195     int quota = mux_atol(quota_str);
00196     free_lbuf(quota_str);
00197 
00198     // enough to build?  Wizards always have enough.
00199     //
00200     quota -= cost;
00201     if (  quota < 0
00202        && !Free_Quota(who)
00203        && !Free_Quota(Owner(who)))
00204     {
00205         return false;
00206     }
00207 
00208     // Dock the quota.
00209     //
00210     char buf[20];
00211     mux_ltoa(quota, buf);
00212     atr_add_raw(Owner(who), A_RQUOTA, buf);
00213 
00214     return true;
00215 }
00216 
00217 bool canpayfees(dbref player, dbref who, int pennies, int quota)
00218 {
00219     if (  !Wizard(who)
00220        && !Wizard(Owner(who))
00221        && !Free_Money(who)
00222        && !Free_Money(Owner(who))
00223        && (Pennies(Owner(who)) < pennies))
00224     {
00225         if (player == who)
00226         {
00227             notify(player, tprintf("Sorry, you don't have enough %s.",
00228                        mudconf.many_coins));
00229         }
00230         else
00231         {
00232             notify(player, tprintf("Sorry, that player doesn't have enough %s.",
00233                 mudconf.many_coins));
00234         }
00235         return false;
00236     }
00237     if (mudconf.quotas)
00238     {
00239         if (!pay_quota(who, quota))
00240         {
00241             if (player == who)
00242             {
00243                 notify(player, "Sorry, your building contract has run out.");
00244             }
00245             else
00246             {
00247                 notify(player,
00248                     "Sorry, that player's building contract has run out.");
00249             }
00250             return false;
00251         }
00252     }
00253     payfor(who, pennies);
00254     return true;
00255 }
00256 
00257 bool payfor(dbref who, int cost)
00258 {
00259     if (  Wizard(who)
00260        || Wizard(Owner(who))
00261        || Free_Money(who)
00262        || Free_Money(Owner(who)))
00263     {
00264         return true;
00265     }
00266     who = Owner(who);
00267     int tmp;
00268     if ((tmp = Pennies(who)) >= cost)
00269     {
00270         s_Pennies(who, tmp - cost);
00271         return true;
00272     }
00273     return false;
00274 }
00275 
00276 void add_quota(dbref who, int payment)
00277 {
00278     dbref aowner;
00279     int aflags;
00280     char buf[20];
00281 
00282     char *quota = atr_get(who, A_RQUOTA, &aowner, &aflags);
00283     mux_ltoa(mux_atol(quota) + payment, buf);
00284     free_lbuf(quota);
00285     atr_add_raw(who, A_RQUOTA, buf);
00286 }
00287 
00288 void giveto(dbref who, int pennies)
00289 {
00290     if (  Wizard(who)
00291        || Wizard(Owner(who))
00292        || Free_Money(who)
00293        || Free_Money(Owner(who)))
00294     {
00295         return;
00296     }
00297     who = Owner(who);
00298     s_Pennies(who, Pennies(who) + pennies);
00299 }
00300 
00301 // The following function validates that the object names (which will be
00302 // used for things and rooms, but not for players or exits) and generates
00303 // a canonical form of that name (with optimized ANSI).
00304 //
00305 char *MakeCanonicalObjectName(const char *pName, int *pnName, bool *pbValid)
00306 {
00307     static char Buf[MBUF_SIZE];
00308 
00309     *pnName = 0;
00310     *pbValid = false;
00311 
00312     if (!pName)
00313     {
00314         return NULL;
00315     }
00316 
00317     // Build up what the real name would be. If we pass all the
00318     // checks, this is what we will return as a result.
00319     //
00320     int nVisualWidth;
00321     int nBuf = ANSI_TruncateToField(pName, sizeof(Buf), Buf, MBUF_SIZE,
00322         &nVisualWidth, ANSI_ENDGOAL_NORMAL);
00323 
00324     // Disallow pure ANSI names. There must be at least -something-
00325     // visible.
00326     //
00327     if (nVisualWidth <= 0)
00328     {
00329         return NULL;
00330     }
00331 
00332     // Get the stripped version (Visible parts without color info).
00333     //
00334     size_t nStripped;
00335     char *pStripped = strip_ansi(Buf, &nStripped);
00336 
00337     // Do not allow LOOKUP_TOKEN, NUMBER_TOKEN, NOT_TOKEN, or SPACE
00338     // as the first character, or SPACE as the last character
00339     //
00340     if (  strchr("*!#", *pStripped)
00341        || mux_isspace(pStripped[0])
00342        || mux_isspace(pStripped[nStripped-1]))
00343     {
00344         return NULL;
00345     }
00346 
00347     // Only printable characters besides ARG_DELIMITER, AND_TOKEN,
00348     // and OR_TOKEN are allowed.
00349     //
00350     for (unsigned int i = 0; i < nStripped; i++)
00351     {
00352         if (!mux_ObjectNameSet(pStripped[i]))
00353         {
00354             return NULL;
00355         }
00356     }
00357 
00358     // Special names are specifically dis-allowed.
00359     //
00360     if (  (nStripped == 2 && memcmp("me", pStripped, 2) == 0)
00361        || (nStripped == 4 && (  memcmp("home", pStripped, 4) == 0
00362                              || memcmp("here", pStripped, 4) == 0)))
00363     {
00364         return NULL;
00365     }
00366 
00367     *pnName = nBuf;
00368     *pbValid = true;
00369     return Buf;
00370 }
00371 
00372 // The following function validates exit names.
00373 //
00374 char *MakeCanonicalExitName(const char *pName, int *pnName, bool *pbValid)
00375 {
00376     static char Buf[MBUF_SIZE];
00377     static char Out[MBUF_SIZE];
00378 
00379     *pnName = 0;
00380     *pbValid = false;
00381 
00382     if (!pName)
00383     {
00384         return NULL;
00385     }
00386 
00387     // Build the non-ANSI version so that we can parse for semicolons
00388     // safely.
00389     //
00390     char *pStripped = strip_ansi(pName);
00391     char *pBuf = Buf;
00392     safe_mb_str(pStripped, Buf, &pBuf);
00393     *pBuf = '\0';
00394 
00395     size_t nBuf = pBuf - Buf;
00396     pBuf = Buf;
00397 
00398     bool bHaveDisplay = false;
00399 
00400     char *pOut = Out;
00401 
00402     for (; nBuf;)
00403     {
00404         // Build (q,n) as the next segment.  Leave the the remaining segments as
00405         // (pBuf,nBuf).
00406         //
00407         char *q = strchr(pBuf, ';');
00408         size_t n;
00409         if (q)
00410         {
00411             *q = '\0';
00412             n = q - pBuf;
00413             q = pBuf;
00414             pBuf += n + 1;
00415             nBuf -= n + 1;
00416         }
00417         else
00418         {
00419             n = nBuf;
00420             q = pBuf;
00421             pBuf += nBuf;
00422             nBuf = 0;
00423         }
00424 
00425         if (bHaveDisplay)
00426         {
00427             // We already have the displayable name. We don't allow ANSI in
00428             // any segment but the first, so we can pull them directly from
00429             // the stripped buffer.
00430             //
00431             int  nN;
00432             bool bN;
00433             char *pN = MakeCanonicalObjectName(q, &nN, &bN);
00434             if (  bN
00435                && nN < MBUF_SIZE - (pOut - Out) - 1)
00436             {
00437                 safe_mb_chr(';', Out, &pOut);
00438                 safe_mb_str(pN, Out, &pOut);
00439             }
00440         }
00441         else
00442         {
00443             // We don't have the displayable name, yet. We know where the next
00444             // semicolon occurs, so we limit the visible width of the
00445             // truncation to that.  We should be picking up all the visible
00446             // characters leading up to the semicolon, but not including the
00447             // semi-colon.
00448             //
00449             int vw;
00450             ANSI_TruncateToField(pName, sizeof(Out), Out, n, &vw,
00451                 ANSI_ENDGOAL_NORMAL);
00452 
00453             // vw should always be equal to n, but we'll just make sure.
00454             //
00455             if ((size_t)vw == n)
00456             {
00457                 int  nN;
00458                 bool bN;
00459                 char *pN = MakeCanonicalObjectName(Out, &nN, &bN);
00460                 if (  bN
00461                    && nN <= MBUF_SIZE - 1)
00462                 {
00463                     safe_mb_str(pN, Out, &pOut);
00464                     bHaveDisplay = true;
00465                 }
00466             }
00467         }
00468     }
00469     if (bHaveDisplay)
00470     {
00471         *pnName = pOut - Out;
00472         *pbValid = true;
00473         *pOut = '\0';
00474         return Out;
00475     }
00476     else
00477     {
00478         return NULL;
00479     }
00480 }
00481 
00482 // The following function validates the player name. ANSI is not
00483 // allowed in player names. However, a player name must satisfy
00484 // the requirements of a regular name as well.
00485 //
00486 bool ValidatePlayerName(const char *pName)
00487 {
00488     if (!pName)
00489     {
00490         return false;
00491     }
00492     size_t nName = strlen(pName);
00493 
00494     // Verify that name is not empty, but not too long, either.
00495     //
00496     if (  nName <= 0
00497        || PLAYER_NAME_LIMIT <= nName)
00498     {
00499         return false;
00500     }
00501 
00502     // Do not allow LOOKUP_TOKEN, NUMBER_TOKEN, NOT_TOKEN, or SPACE
00503     // as the first character, or SPACE as the last character
00504     //
00505     if (  strchr("*!#", *pName)
00506        || mux_isspace(pName[0])
00507        || mux_isspace(pName[nName-1]))
00508     {
00509         return false;
00510     }
00511 
00512     if (  mudstate.bStandAlone
00513        || mudconf.name_spaces)
00514     {
00515         mux_PlayerNameSet[(unsigned char)' '] = 1;
00516     }
00517     else
00518     {
00519         mux_PlayerNameSet[(unsigned char)' '] = 0;
00520     }
00521 
00522     // Only printable characters besides ARG_DELIMITER, AND_TOKEN,
00523     // and OR_TOKEN are allowed.
00524     //
00525     for (unsigned int i = 0; i < nName; i++)
00526     {
00527         if (!mux_PlayerNameSet(pName[i]))
00528         {
00529             return false;
00530         }
00531     }
00532 
00533     // Special names are specifically dis-allowed.
00534     //
00535     if (  (nName == 2 && memcmp("me", pName, 2) == 0)
00536        || (nName == 4 && (  memcmp("home", pName, 4) == 0
00537                          || memcmp("here", pName, 4) == 0)))
00538     {
00539         return false;
00540     }
00541     return true;
00542 }
00543 
00544 bool ok_password(const char *password, const char **pmsg)
00545 {
00546     *pmsg = NULL;
00547 
00548     if (*password == '\0')
00549     {
00550         *pmsg = "Null passwords are not allowed.";
00551         return false;
00552     }
00553 
00554     const char *scan;
00555     int num_upper = 0;
00556     int num_special = 0;
00557     int num_lower = 0;
00558 
00559     for (scan = password; *scan; scan++)
00560     {
00561         if (  !mux_isprint(*scan)
00562            || mux_isspace(*scan))
00563         {
00564             *pmsg = "Illegal character in password.";
00565             return false;
00566         }
00567         if (mux_isupper(*scan))
00568         {
00569             num_upper++;
00570         }
00571         else if (mux_islower(*scan))
00572         {
00573             num_lower++;
00574         }
00575         else if (  *scan != '\''
00576                 && *scan != '-')
00577         {
00578             num_special++;
00579         }
00580     }
00581 
00582     if (  !mudstate.bStandAlone
00583        && mudconf.safer_passwords)
00584     {
00585         if (num_upper < 1)
00586         {
00587             *pmsg = "The password must contain at least one capital letter.";
00588             return false;
00589         }
00590         if (num_lower < 1)
00591         {
00592             *pmsg = "The password must contain at least one lowercase letter.";
00593             return false;
00594         }
00595         if (num_special < 1)
00596         {
00597             *pmsg = "The password must contain at least one number or a symbol other than the apostrophe or dash.";
00598             return false;
00599         }
00600     }
00601     return true;
00602 }
00603 
00604 /* ---------------------------------------------------------------------------
00605  * handle_ears: Generate the 'grows ears' and 'loses ears' messages.
00606  */
00607 
00608 void handle_ears(dbref thing, bool could_hear, bool can_hear)
00609 {
00610     char *buff, *bp;
00611     int gender;
00612     static const char *poss[5] =
00613     {"", "its", "her", "his", "their"};
00614 
00615     if (could_hear != can_hear)
00616     {
00617         buff = alloc_lbuf("handle_ears");
00618         strcpy(buff, Name(thing));
00619         if (isExit(thing))
00620         {
00621             for (bp = buff; *bp && *bp != ';'; bp++)
00622             {
00623                 ; // Nothing.
00624             }
00625             *bp = '\0';
00626         }
00627         gender = get_gender(thing);
00628 
00629         if (can_hear)
00630         {
00631             notify_check(thing, thing,
00632                          tprintf("%s grow%s ears and can now hear.",
00633                                  buff, (gender == 4) ? "" : "s"),
00634                          (MSG_ME | MSG_NBR | MSG_LOC | MSG_INV));
00635         }
00636         else
00637         {
00638             notify_check(thing, thing,
00639                          tprintf("%s lose%s %s ears and become%s deaf.",
00640                                  buff, (gender == 4) ? "" : "s",
00641                                  poss[gender], (gender == 4) ? "" : "s"),
00642                          (MSG_ME | MSG_NBR | MSG_LOC | MSG_INV));
00643         }
00644         free_lbuf(buff);
00645     }
00646 }
00647 
00648 // For lack of better place the @switch code is here.
00649 //
00650 void do_switch
00651 (
00652     dbref player,
00653     dbref caller,
00654     dbref enactor,
00655     int   key,
00656     char *expr,
00657     char *args[],
00658     int   nargs,
00659     char *cargs[],
00660     int   ncargs
00661 )
00662 {
00663     if (  !expr
00664        || nargs <= 0)
00665     {
00666         return;
00667     }
00668 
00669     if (key == SWITCH_DEFAULT)
00670     {
00671         if (mudconf.switch_df_all)
00672         {
00673             key = SWITCH_ANY;
00674         }
00675         else
00676         {
00677             key = SWITCH_ONE;
00678         }
00679     }
00680 
00681     // Now try a wild card match of buff with stuff in coms.
00682     //
00683     bool any = false;
00684     int a;
00685     char *buff, *bp, *str;
00686     buff = bp = alloc_lbuf("do_switch");
00687     CLinearTimeAbsolute lta;
00688     for (  a = 0;
00689               a < nargs - 1
00690            && args[a]
00691            && args[a + 1];
00692            a += 2)
00693     {
00694         bp = buff;
00695         str = args[a];
00696         mux_exec(buff, &bp, player, caller, enactor, EV_FCHECK | EV_EVAL | EV_TOP,
00697             &str, cargs, ncargs);
00698         *bp = '\0';
00699         if (wild_match(buff, expr))
00700         {
00701             char *tbuf = replace_tokens(args[a+1], NULL, NULL, expr);
00702             wait_que(player, caller, enactor, false, lta, NOTHING, 0,
00703                 tbuf, cargs, ncargs, mudstate.global_regs);
00704             free_lbuf(tbuf);
00705             if (key == SWITCH_ONE)
00706             {
00707                 free_lbuf(buff);
00708                 return;
00709             }
00710             any = true;
00711         }
00712     }
00713     free_lbuf(buff);
00714     if (  a < nargs
00715        && !any
00716        && args[a])
00717     {
00718         char *tbuf = replace_tokens(args[a], NULL, NULL, expr);
00719         wait_que(player, caller, enactor, false, lta, NOTHING, 0, tbuf,
00720             cargs, ncargs, mudstate.global_regs);
00721         free_lbuf(tbuf);
00722     }
00723 }
00724 
00725 // Also for lack of better place the @ifelse code is here.
00726 // Idea for @ifelse from ChaoticMUX.
00727 //
00728 void do_if
00729 (
00730     dbref player,
00731     dbref caller,
00732     dbref enactor,
00733     int   key,
00734     char *expr,
00735     char *args[],
00736     int   nargs,
00737     char *cargs[],
00738     int   ncargs
00739 )
00740 {
00741     UNUSED_PARAMETER(key);
00742 
00743     if (  !expr
00744        || nargs <= 0)
00745     {
00746         return;
00747     }
00748 
00749     char *buff, *bp;
00750     CLinearTimeAbsolute lta;
00751     buff = bp = alloc_lbuf("do_if");
00752 
00753     mux_exec(buff, &bp, player, caller, enactor, EV_FCHECK | EV_EVAL | EV_TOP,
00754         &expr, cargs, ncargs);
00755     *bp = '\0';
00756 
00757     int a = !xlate(buff);
00758     free_lbuf(buff);
00759 
00760     if (a < nargs)
00761     {
00762         wait_que(player, caller, enactor, false, lta, NOTHING, 0, args[a],
00763             cargs, ncargs, mudstate.global_regs);
00764     }
00765 }
00766 
00767 void do_addcommand
00768 (
00769     dbref player,
00770     dbref caller,
00771     dbref enactor,
00772     int   key,
00773     int   nargs,
00774     char *name,
00775     char *command
00776 )
00777 {
00778     UNUSED_PARAMETER(caller);
00779     UNUSED_PARAMETER(enactor);
00780     UNUSED_PARAMETER(key);
00781 
00782     // Validate command name.
00783     //
00784     char *pName = NULL;
00785     if (1 <= nargs)
00786     {
00787         char *pStripped = strip_ansi(name);
00788         pName = RemoveSetOfCharacters(pStripped, "\r\n\t ");
00789         mux_strlwr(pName);
00790     }
00791     if (  !pName
00792        || pName[0] == '\0'
00793        || (  pName[0] == '_'
00794           && pName[1] == '_'))
00795     {
00796         notify(player, "That is not a valid command name.");
00797         return;
00798     }
00799 
00800     // Validate object/attribute.
00801     //
00802     dbref thing;
00803     ATTR *pattr;
00804     if (  !parse_attrib(player, command, &thing, &pattr)
00805        || !pattr)
00806     {
00807         notify(player, "No such attribute.");
00808         return;
00809     }
00810     if (!See_attr(player, thing, pattr))
00811     {
00812         notify(player, NOPERM_MESSAGE);
00813         return;
00814     }
00815 
00816     CMDENT *old = (CMDENT *)hashfindLEN(pName, strlen(pName),
00817         &mudstate.command_htab);
00818 
00819     CMDENT *cmd;
00820     ADDENT *add, *nextp;
00821 
00822     if (  old
00823        && (old->callseq & CS_ADDED))
00824     {
00825         // Don't allow the same (thing,atr) in the list.
00826         //
00827         for (nextp = old->addent; nextp != NULL; nextp = nextp->next)
00828         {
00829             if (  nextp->thing == thing
00830                && nextp->atr == pattr->number)
00831             {
00832                 notify(player, tprintf("%s already added.", pName));
00833                 return;
00834             }
00835         }
00836 
00837         // Otherwise, add another (thing,atr) to the list.
00838         //
00839         add = (ADDENT *)MEMALLOC(sizeof(ADDENT));
00840         ISOUTOFMEMORY(add);
00841         add->thing = thing;
00842         add->atr = pattr->number;
00843         add->name = StringClone(pName);
00844         add->next = old->addent;
00845         old->addent = add;
00846     }
00847     else
00848     {
00849         if (old)
00850         {
00851             // Delete the old built-in (which will later be added back as
00852             // __name).
00853             //
00854             hashdeleteLEN(pName, strlen(pName), &mudstate.command_htab);
00855         }
00856 
00857         cmd = (CMDENT *)MEMALLOC(sizeof(CMDENT));
00858         ISOUTOFMEMORY(cmd);
00859         cmd->cmdname = StringClone(pName);
00860         cmd->switches = NULL;
00861         cmd->perms = 0;
00862         cmd->extra = 0;
00863         if (  old
00864            && (old->callseq & CS_LEADIN))
00865         {
00866             cmd->callseq = CS_ADDED|CS_ONE_ARG|CS_LEADIN;
00867         }
00868         else
00869         {
00870             cmd->callseq = CS_ADDED|CS_ONE_ARG;
00871         }
00872         cmd->hookmask = 0;
00873         add = (ADDENT *)MEMALLOC(sizeof(ADDENT));
00874         ISOUTOFMEMORY(add);
00875         add->thing = thing;
00876         add->atr = pattr->number;
00877         add->name = StringClone(pName);
00878         add->next = NULL;
00879         cmd->addent = add;
00880 
00881         hashaddLEN(pName, strlen(pName), cmd, &mudstate.command_htab);
00882 
00883         if (  old
00884            && strcmp(pName, old->cmdname) == 0)
00885         {
00886             // We are @addcommand'ing over a built-in command by its
00887             // unaliased name, therefore, we want to re-target all the
00888             // aliases.
00889             //
00890             char *p = tprintf("__%s", pName);
00891             hashdeleteLEN(p, strlen(p), &mudstate.command_htab);
00892             hashreplall(old, cmd, &mudstate.command_htab);
00893             hashaddLEN(p, strlen(p), old, &mudstate.command_htab);
00894         }
00895     }
00896 
00897     // We reset the one letter commands here so you can overload them.
00898     //
00899     set_prefix_cmds();
00900     notify(player, tprintf("Command %s added.", pName));
00901 }
00902 
00903 void do_listcommands(dbref player, dbref caller, dbref enactor, int key,
00904                      char *name)
00905 {
00906     UNUSED_PARAMETER(caller);
00907     UNUSED_PARAMETER(enactor);
00908     UNUSED_PARAMETER(key);
00909 
00910     CMDENT *old;
00911     ADDENT *nextp;
00912     bool didit = false;
00913 
00914     // Let's make this case insensitive...
00915     //
00916     mux_strlwr(name);
00917 
00918     if (*name)
00919     {
00920         old = (CMDENT *)hashfindLEN(name, strlen(name), &mudstate.command_htab);
00921 
00922         if (  old
00923            && (old->callseq & CS_ADDED))
00924         {
00925             // If it's already found in the hash table, and it's being added
00926             // using the same object and attribute...
00927             //
00928             for (nextp = old->addent; nextp != NULL; nextp = nextp->next)
00929             {
00930                 ATTR *ap = (ATTR *)atr_num(nextp->atr);
00931                 const char *pName = "(WARNING: Bad Attribute Number)";
00932                 if (ap)
00933                 {
00934                     pName = ap->name;
00935                 }
00936                 notify(player, tprintf("%s: #%d/%s", nextp->name, nextp->thing, pName));
00937             }
00938         }
00939         else
00940         {
00941             notify(player, tprintf("%s not found in command table.",name));
00942         }
00943         return;
00944     }
00945     else
00946     {
00947         char *pKeyName;
00948         int  nKeyName;
00949         for (old = (CMDENT *)hash_firstkey(&mudstate.command_htab, &nKeyName, &pKeyName);
00950              old != NULL;
00951              old = (CMDENT *)hash_nextkey(&mudstate.command_htab, &nKeyName, &pKeyName))
00952         {
00953             if (old->callseq & CS_ADDED)
00954             {
00955                 pKeyName[nKeyName] = '\0';
00956                 for (nextp = old->addent; nextp != NULL; nextp = nextp->next)
00957                 {
00958                     if (strcmp(pKeyName, nextp->name) != 0)
00959                     {
00960                         continue;
00961                     }
00962                     ATTR *ap = (ATTR *)atr_num(nextp->atr);
00963                     const char *pName = "(WARNING: Bad Attribute Number)";
00964                     if (ap)
00965                     {
00966                         pName = ap->name;
00967                     }
00968                     notify(player, tprintf("%s: #%d/%s", nextp->name,
00969                         nextp->thing, pName));
00970                     didit = true;
00971                 }
00972             }
00973         }
00974     }
00975     if (!didit)
00976     {
00977         notify(player, "No added commands found in command table.");
00978     }
00979 }
00980 
00981 void do_delcommand
00982 (
00983     dbref player,
00984     dbref caller,
00985     dbref enactor,
00986     int   key,
00987     int   nargs,
00988     char *name,
00989     char *command
00990 )
00991 {
00992     UNUSED_PARAMETER(caller);
00993     UNUSED_PARAMETER(enactor);
00994     UNUSED_PARAMETER(key);
00995     UNUSED_PARAMETER(nargs);
00996 
00997     if (!*name)
00998     {
00999         notify(player, "Sorry.");
01000         return;
01001     }
01002 
01003     dbref thing = NOTHING;
01004     int atr = NOTHING;
01005     ATTR *pattr;
01006     if (*command)
01007     {
01008         if (  !parse_attrib(player, command, &thing, &pattr)
01009            || !pattr)
01010         {
01011             notify(player, "No such attribute.");
01012             return;
01013         }
01014         if (!See_attr(player, thing, pattr))
01015         {
01016             notify(player, NOPERM_MESSAGE);
01017             return;
01018         }
01019         atr = pattr->number;
01020     }
01021 
01022     // Let's make this case insensitive...
01023     //
01024     mux_strlwr(name);
01025 
01026     CMDENT *old, *cmd;
01027     ADDENT *prev = NULL, *nextp;
01028     size_t nName = strlen(name);
01029     old = (CMDENT *)hashfindLEN(name, nName, &mudstate.command_htab);
01030 
01031     if (  old
01032        && (old->callseq & CS_ADDED))
01033     {
01034         char *p__Name = tprintf("__%s", name);
01035         size_t n__Name = strlen(p__Name);
01036 
01037         if (command[0] == '\0')
01038         {
01039             // Delete all @addcommand'ed associations with the given name.
01040             //
01041             for (prev = old->addent; prev != NULL; prev = nextp)
01042             {
01043                 nextp = prev->next;
01044                 MEMFREE(prev->name);
01045                 prev->name = NULL;
01046                 MEMFREE(prev);
01047                 prev = NULL;
01048             }
01049             hashdeleteLEN(name, nName, &mudstate.command_htab);
01050             cmd = (CMDENT *)hashfindLEN(p__Name, n__Name, &mudstate.command_htab);
01051             if (cmd)
01052             {
01053                 hashaddLEN(cmd->cmdname, strlen(cmd->cmdname), cmd,
01054                     &mudstate.command_htab);
01055                 if (strcmp(name, cmd->cmdname) != 0)
01056                 {
01057                     hashaddLEN(name, nName, cmd, &mudstate.command_htab);
01058                 }
01059 
01060                 hashdeleteLEN(p__Name, n__Name, &mudstate.command_htab);
01061                 hashaddLEN(p__Name, n__Name, cmd, &mudstate.command_htab);
01062                 hashreplall(old, cmd, &mudstate.command_htab);
01063             }
01064             else
01065             {
01066                 // TODO: Delete everything related to 'old'.
01067                 //
01068             }
01069             MEMFREE(old->cmdname);
01070             old->cmdname = NULL;
01071             MEMFREE(old);
01072             old = NULL;
01073             set_prefix_cmds();
01074             notify(player, "Done.");
01075         }
01076         else
01077         {
01078             // Remove only the (name,thing,atr) association.
01079             //
01080             for (nextp = old->addent; nextp != NULL; nextp = nextp->next)
01081             {
01082                 if (  nextp->thing == thing
01083                    && nextp->atr == atr)
01084                 {
01085                     MEMFREE(nextp->name);
01086                     nextp->name = NULL;
01087                     if (!prev)
01088                     {
01089                         if (!nextp->next)
01090                         {
01091                             hashdeleteLEN(name, nName, &mudstate.command_htab);
01092                             cmd = (CMDENT *)hashfindLEN(p__Name, n__Name,
01093                                 &mudstate.command_htab);
01094                             if (cmd)
01095                             {
01096                                 hashaddLEN(cmd->cmdname, strlen(cmd->cmdname),
01097                                     cmd, &mudstate.command_htab);
01098                                 if (strcmp(name, cmd->cmdname) != 0)
01099                                 {
01100                                     hashaddLEN(name, nName, cmd,
01101                                         &mudstate.command_htab);
01102                                 }
01103 
01104                                 hashdeleteLEN(p__Name, n__Name,
01105                                     &mudstate.command_htab);
01106                                 hashaddLEN(p__Name, n__Name, cmd,
01107                                     &mudstate.command_htab);
01108                                 hashreplall(old, cmd,
01109                                     &mudstate.command_htab);
01110                             }
01111                             MEMFREE(old->cmdname);
01112                             old->cmdname = NULL;
01113                             MEMFREE(old);
01114                             old = NULL;
01115                         }
01116                         else
01117                         {
01118                             old->addent = nextp->next;
01119                             MEMFREE(nextp);
01120                             nextp = NULL;
01121                         }
01122                     }
01123                     else
01124                     {
01125                         prev->next = nextp->next;
01126                         MEMFREE(nextp);
01127                         nextp = NULL;
01128                     }
01129                     set_prefix_cmds();
01130                     notify(player, "Done.");
01131                     return;
01132                 }
01133                 prev = nextp;
01134             }
01135             notify(player, "Command not found in command table.");
01136         }
01137     }
01138     else
01139     {
01140         notify(player, "Command not found in command table.");
01141     }
01142 }
01143 
01144 /*
01145  * @prog 'glues' a user's input to a command. Once executed, the first string
01146  * input from any of the doers's logged in descriptors, will go into
01147  * A_PROGMSG, which can be substituted in <command> with %0. Commands already
01148  * queued by the doer will be processed normally.
01149  */
01150 
01151 void handle_prog(DESC *d, char *message)
01152 {
01153     // Allow the player to pipe a command while in interactive mode.
01154     //
01155     if (*message == '|')
01156     {
01157         do_command(d, message + 1);
01158 
01159         if (d->program_data != NULL)
01160         {
01161             queue_string(d, tprintf("%s>%s ", ANSI_HILITE, ANSI_NORMAL));
01162 
01163             if (OPTION_YES == UsState(d, TELNET_EOR))
01164             {
01165                 // Use telnet protocol's EOR command to show prompt.
01166                 //
01167                 const char aEOR[2] = { NVT_IAC, NVT_EOR };
01168                 queue_write_LEN(d, aEOR, sizeof(aEOR));
01169             }
01170             else if (OPTION_YES != UsState(d, TELNET_SGA))
01171             {
01172                 // Use telnet protocol's GOAHEAD command to show prompt.
01173                 //
01174                 const char aGoAhead[2] = { NVT_IAC, NVT_GA };
01175                 queue_write_LEN(d, aGoAhead, sizeof(aGoAhead));
01176             }
01177         }
01178         return;
01179     }
01180     dbref aowner;
01181     int aflags, i;
01182     char *cmd = atr_get(d->player, A_PROGCMD, &aowner, &aflags);
01183     CLinearTimeAbsolute lta;
01184     wait_que(d->program_data->wait_enactor, d->player, d->player, false, lta,
01185         NOTHING, 0, cmd, (char **)&message, 1,
01186         (char **)d->program_data->wait_regs);
01187 
01188     // First, set 'all' to a descriptor we find for this player.
01189     //
01190     DESC *all = (DESC *)hashfindLEN(&(d->player), sizeof(d->player), &mudstate.desc_htab) ;
01191 
01192     if (all && all->program_data)
01193     {
01194         for (i = 0; i < MAX_GLOBAL_REGS; i++)
01195         {
01196             if (all->program_data->wait_regs[i])
01197             {
01198                 free_lbuf(all->program_data->wait_regs[i]);
01199                 all->program_data->wait_regs[i] = NULL;
01200             }
01201         }
01202 
01203         MEMFREE(all->program_data);
01204         all->program_data = NULL;
01205 
01206         // Set info for all player descriptors to NULL
01207         //
01208         DESC_ITER_PLAYER(d->player, all)
01209             all->program_data = NULL;
01210     }
01211     atr_clr(d->player, A_PROGCMD);
01212     free_lbuf(cmd);
01213 }
01214 
01215 void do_quitprog(dbref player, dbref caller, dbref enactor, int key, char *name)
01216 {
01217     UNUSED_PARAMETER(caller);
01218     UNUSED_PARAMETER(enactor);
01219     UNUSED_PARAMETER(key);
01220 
01221     dbref doer;
01222 
01223     if (*name)
01224     {
01225         doer = match_thing(player, name);
01226     }
01227     else
01228     {
01229         doer = player;
01230     }
01231 
01232     if (  !(  Prog(player)
01233            || Prog(Owner(player)))
01234        && player != doer)
01235     {
01236         notify(player, NOPERM_MESSAGE);
01237         return;
01238     }
01239     if (  !Good_obj(doer)
01240        || !isPlayer(doer))
01241     {
01242         notify(player, "That is not a player.");
01243         return;
01244     }
01245     if (!Connected(doer))
01246     {
01247         notify(player, "That player is not connected.");
01248         return;
01249     }
01250     DESC *d;
01251     bool isprog = false;
01252     DESC_ITER_PLAYER(doer, d)
01253     {
01254         if (d->program_data != NULL)
01255         {
01256             isprog = true;
01257         }
01258     }
01259 
01260     if (!isprog)
01261     {
01262         notify(player, "Player is not in an @program.");
01263         return;
01264     }
01265 
01266     d = (DESC *)hashfindLEN(&doer, sizeof(doer), &mudstate.desc_htab);
01267     int i;
01268 
01269     if (d && d->program_data)
01270     {
01271         for (i = 0; i < MAX_GLOBAL_REGS; i++)
01272         {
01273             if (d->program_data->wait_regs[i])
01274             {
01275                 free_lbuf(d->program_data->wait_regs[i]);
01276                 d->program_data->wait_regs[i] = NULL;
01277             }
01278         }
01279         MEMFREE(d->program_data);
01280         d->program_data = NULL;
01281 
01282         // Set info for all player descriptors to NULL.
01283         //
01284         DESC_ITER_PLAYER(doer, d)
01285         {
01286             d->program_data = NULL;
01287         }
01288     }
01289 
01290     atr_clr(doer, A_PROGCMD);
01291     notify(player, "@program cleared.");
01292     notify(doer, "Your @program has been terminated.");
01293 }
01294 
01295 void do_prog
01296 (
01297     dbref player,
01298     dbref caller,
01299     dbref enactor,
01300     int   key,
01301     int   nargs,
01302     char *name,
01303     char *command
01304 )
01305 {
01306     UNUSED_PARAMETER(caller);
01307     UNUSED_PARAMETER(enactor);
01308     UNUSED_PARAMETER(key);
01309     UNUSED_PARAMETER(nargs);
01310 
01311     if (  !name
01312        || !*name)
01313     {
01314         notify(player, "No players specified.");
01315         return;
01316     }
01317 
01318     dbref doer = match_thing(player, name);
01319     if (  !(  Prog(player)
01320            || Prog(Owner(player)))
01321        && player != doer)
01322     {
01323         notify(player, NOPERM_MESSAGE);
01324         return;
01325     }
01326     if (  !Good_obj(doer)
01327        || !isPlayer(doer))
01328     {
01329         notify(player, "That is not a player.");
01330         return;
01331     }
01332     if (!Connected(doer))
01333     {
01334         notify(player, "That player is not connected.");
01335         return;
01336     }
01337     char *msg = command;
01338     char *attrib = parse_to(&msg, ':', 1);
01339 
01340     if (msg && *msg)
01341     {
01342         notify(doer, msg);
01343     }
01344 
01345     dbref thing;
01346     ATTR *ap;
01347     if (!parse_attrib(player, attrib, &thing, &ap))
01348     {
01349         notify(player, NOMATCH_MESSAGE);
01350         return;
01351     }
01352     if (ap)
01353     {
01354         dbref aowner;
01355         int   aflags;
01356         int   lev;
01357         dbref parent;
01358         char *pBuffer = NULL;
01359         bool bFound = false;
01360         ITER_PARENTS(thing, parent, lev)
01361         {
01362             pBuffer = atr_get(parent, ap->number, &aowner, &aflags);
01363             if (pBuffer[0])
01364             {
01365                 bFound = true;
01366                 break;
01367             }
01368             free_lbuf(pBuffer);
01369         }
01370         if (bFound)
01371         {
01372             if (  (   God(player)
01373                   || !God(thing))
01374                && See_attr(player, thing, ap))
01375             {
01376                 atr_add_raw(doer, A_PROGCMD, pBuffer);
01377             }
01378             else
01379             {
01380                 notify(player, NOPERM_MESSAGE);
01381                 free_lbuf(pBuffer);
01382                 return;
01383             }
01384             free_lbuf(pBuffer);
01385         }
01386         else
01387         {
01388             notify(player, "Attribute not present on object.");
01389             return;
01390         }
01391     }
01392     else
01393     {
01394         notify(player, "No such attribute.");
01395         return;
01396     }
01397 
01398     // Check to see if the enactor already has an @prog input pending.
01399     //
01400     DESC *d;
01401     DESC_ITER_PLAYER(doer, d)
01402     {
01403         if (d->program_data != NULL)
01404         {
01405             notify(player, "Input already pending.");
01406             return;
01407         }
01408     }
01409 
01410     PROG *program = (PROG *)MEMALLOC(sizeof(PROG));
01411     ISOUTOFMEMORY(program);
01412     program->wait_enactor = player;
01413     for (int i = 0; i < MAX_GLOBAL_REGS; i++)
01414     {
01415         program->wait_regs[i] = alloc_lbuf("prog_regs");
01416         memcpy(program->wait_regs[i], mudstate.global_regs[i], mudstate.glob_reg_len[i]+1);
01417     }
01418 
01419     // Now, start waiting.
01420     //
01421     DESC_ITER_PLAYER(doer, d)
01422     {
01423         d->program_data = program;
01424 
01425         queue_string(d, tprintf("%s>%s ", ANSI_HILITE, ANSI_NORMAL));
01426 
01427         if (OPTION_YES == UsState(d, TELNET_EOR))
01428         {
01429             // Use telnet protocol's EOR command to show prompt.
01430             //
01431             const char aEOR[2] = { NVT_IAC, NVT_EOR };
01432             queue_write_LEN(d, aEOR, sizeof(aEOR));
01433         }
01434         else if (OPTION_YES != UsState(d, TELNET_SGA))
01435         {
01436             // Use telnet protocol's GOAHEAD command to show prompt.
01437             //
01438             const char aGoAhead[2] = { NVT_IAC, NVT_GA };
01439             queue_write_LEN(d, aGoAhead, sizeof(aGoAhead));
01440         }
01441     }
01442 }
01443 
01444 /* ---------------------------------------------------------------------------
01445  * do_restart: Restarts the game.
01446  */
01447 void do_restart(dbref executor, dbref caller, dbref enactor, int key)
01448 {
01449     UNUSED_PARAMETER(caller);
01450     UNUSED_PARAMETER(enactor);
01451     UNUSED_PARAMETER(key);
01452 
01453     if (!Can_SiteAdmin(executor))
01454     {
01455         notify(executor, NOPERM_MESSAGE);
01456         return;
01457     }
01458 
01459     bool bDenied = false;
01460 #ifndef WIN32
01461     if (mudstate.dumping)
01462     {
01463         notify(executor, "Dumping. Please try again later.");
01464         bDenied = true;
01465     }
01466 #endif // !WIN32
01467 
01468 
01469     if (!mudstate.bCanRestart)
01470     {
01471         notify(executor, "Server just started. Please try again in a few seconds.");
01472         bDenied = true;
01473     }
01474     if (bDenied)
01475     {
01476         STARTLOG(LOG_ALWAYS, "WIZ", "RSTRT");
01477         log_text("Restart requested but not executed by ");
01478         log_name(executor);
01479         ENDLOG;
01480         return;
01481     }
01482 
01483     raw_broadcast(0, "GAME: Restart by %s, please wait.", Name(Owner(executor)));
01484     STARTLOG(LOG_ALWAYS, "WIZ", "RSTRT");
01485     log_text("Restart by ");
01486     log_name(executor);
01487     ENDLOG;
01488 
01489     local_presync_database();
01490 
01491 #ifndef MEMORY_BASED
01492     al_store();
01493 #endif
01494     pcache_sync();
01495     dump_database_internal(DUMP_I_RESTART);
01496     SYNC;
01497     CLOSE;
01498 
01499 #ifdef WIN32 // WIN32
01500 
01501     WSACleanup();
01502     exit(12345678);
01503 
01504 #else // WIN32
01505 
01506     dump_restart_db();
01507 
01508     CleanUpSlaveSocket();
01509     CleanUpSlaveProcess();
01510 
01511     Log.StopLogging();
01512 
01513 #ifdef GAME_DOOFERMUX
01514     execl("bin/netmux", mudconf.mud_name, "-c", mudconf.config_file, "-p", mudconf.pid_file, NULL);
01515 #else
01516     execl("bin/netmux", "netmux", "-c", mudconf.config_file, "-p", mudconf.pid_file, NULL);
01517 #endif // GAME_DOOFERMUX
01518 #endif // !WIN32
01519 }
01520 
01521 /* ---------------------------------------------------------------------------
01522  * do_backup: Backs up and restarts the game
01523  * By Wadhah Al-Tailji (7-21-97), altailji@nmt.edu
01524  * Ported to MUX2 by Patrick Hill (7-5-2001), hellspawn@anomux.org
01525  */
01526 
01527 #ifdef WIN32
01528 
01529 void do_backup(dbref player, dbref caller, dbref enactor, int key)
01530 {
01531     UNUSED_PARAMETER(caller);
01532     UNUSED_PARAMETER(enactor);
01533     UNUSED_PARAMETER(key);
01534 
01535     notify(player, "This feature is not yet available on Win32-hosted MUX.");
01536 }
01537 
01538 #else // WIN32
01539 
01540 void do_backup(dbref player, dbref caller, dbref enactor, int key)
01541 {
01542 #ifndef WIN32
01543     if (mudstate.dumping)
01544     {
01545         notify(player, "Dumping. Please try again later.");
01546     }
01547 #endif // !WIN32
01548 
01549     raw_broadcast(0, "GAME: Backing up database. Please wait.");
01550     STARTLOG(LOG_ALWAYS, "WIZ", "BACK");
01551     log_text("Backup by ");
01552     log_name(player);
01553     ENDLOG;
01554 
01555 #ifdef MEMORY_BASED
01556     // Invoking _backupflat.sh with an argument prompts the backup script
01557     // to use it as the flatfile.
01558     //
01559     dump_database_internal(DUMP_I_FLAT);
01560     system(tprintf("./_backupflat.sh %s.FLAT 1>&2", mudconf.indb));
01561 #else // MEMORY_BASED
01562     // Invoking _backupflat.sh without an argument prompts the backup script
01563     // to use dbconvert itself.
01564     //
01565     dump_database_internal(DUMP_I_NORMAL);
01566     system(tprintf("./_backupflat.sh 1>&2"));
01567 #endif // MEMORY_BASED
01568     raw_broadcast(0, "GAME: Backup finished.");
01569 }
01570 #endif // WIN32
01571 
01572 /* ---------------------------------------------------------------------------
01573  * do_comment: Implement the @@ (comment) command. Very cpu-intensive :-)
01574  */
01575 
01576 void do_comment(dbref player, dbref caller, dbref enactor, int key)
01577 {
01578     UNUSED_PARAMETER(player);
01579     UNUSED_PARAMETER(caller);
01580     UNUSED_PARAMETER(enactor);
01581     UNUSED_PARAMETER(key);
01582 }
01583 
01584 static dbref promote_dflt(dbref old, dbref new0)
01585 {
01586     if (  old == NOPERM
01587        || new0 == NOPERM)
01588     {
01589         return NOPERM;
01590     }
01591     if (  old == AMBIGUOUS
01592        || new0 == AMBIGUOUS)
01593     {
01594         return AMBIGUOUS;
01595     }
01596     return NOTHING;
01597 }
01598 
01599 dbref match_possessed(dbref player, dbref thing, char *target, dbref dflt, bool check_enter)
01600 {
01601     // First, check normally.
01602     //
01603     if (Good_obj(dflt))
01604     {
01605         return dflt;
01606     }
01607 
01608     // Didn't find it directly.  Recursively do a contents check.
01609     //
01610     dbref result, result1;
01611     char *buff, *place, *s1, *d1, *temp;
01612     char *start = target;
01613     while (*target)
01614     {
01615         // Fail if no ' characters.
01616         //
01617         place = target;
01618         target = strchr(place, '\'');
01619         if (  target == NULL
01620            || !*target)
01621         {
01622             return dflt;
01623         }
01624 
01625         // If string started with a ', skip past it
01626         //
01627         if (place == target)
01628         {
01629             target++;
01630             continue;
01631         }
01632 
01633         // If next character is not an s or a space, skip past
01634         //
01635         temp = target++;
01636         if (!*target)
01637         {
01638             return dflt;
01639         }
01640         if (  *target != 's'
01641            && *target != 'S'
01642            && *target != ' ')
01643         {
01644             continue;
01645         }
01646 
01647         // If character was not a space make sure the following character is
01648         // a space.
01649         //
01650         if (*target != ' ')
01651         {
01652             target++;
01653             if (!*target)
01654             {
01655                 return dflt;
01656             }
01657             if (*target != ' ')
01658             {
01659                 continue;
01660             }
01661         }
01662 
01663         // Copy the container name to a new buffer so we can terminate it.
01664         //
01665         buff = alloc_lbuf("is_posess");
01666         for (s1 = start, d1 = buff; *s1 && (s1 < temp); *d1++ = (*s1++))
01667         {
01668             ; // Nothing.
01669         }
01670         *d1 = '\0';
01671 
01672         // Look for the container here and in our inventory.  Skip past if we
01673         // can't find it.
01674         //
01675         init_match(thing, buff, NOTYPE);
01676         if (player == thing)
01677         {
01678             match_neighbor();
01679             match_possession();
01680         }
01681         else
01682         {
01683             match_possession();
01684         }
01685         result1 = match_result();
01686 
01687         free_lbuf(buff);
01688         if (!Good_obj(result1))
01689         {
01690             dflt = promote_dflt(dflt, result1);
01691             continue;
01692         }
01693 
01694         // If we don't control it and it is either dark or opaque, skip past.
01695         //
01696         bool control = Controls(player, result1);
01697         if (  (  Dark(result1)
01698               || Opaque(result1))
01699            && !control)
01700         {
01701             dflt = promote_dflt(dflt, NOTHING);
01702             continue;
01703         }
01704 
01705         // Validate object has the ENTER bit set, if requested.
01706         //
01707         if (  check_enter
01708            && !Enter_ok(result1)
01709            && !control)
01710         {
01711             dflt = promote_dflt(dflt, NOPERM);
01712             continue;
01713         }
01714 
01715         // Look for the object in the container.
01716         //
01717         init_match(result1, target, NOTYPE);
01718         match_possession();
01719         result = match_result();
01720         result = match_possessed(player, result1, target, result, check_enter);
01721         if (Good_obj(result))
01722         {
01723             return result;
01724         }
01725         dflt = promote_dflt(dflt, result);
01726     }
01727     return dflt;
01728 }
01729 
01730 /* ---------------------------------------------------------------------------
01731  * parse_range: break up <what>,<low>,<high> syntax
01732  */
01733 
01734 void parse_range(char **name, dbref *low_bound, dbref *high_bound)
01735 {
01736     char *buff1 = *name;
01737     if (buff1 && *buff1)
01738     {
01739         *name = parse_to(&buff1, ',', EV_STRIP_TS);
01740     }
01741     if (buff1 && *buff1)
01742     {
01743         char *buff2 = parse_to(&buff1, ',', EV_STRIP_TS);
01744         if (buff1 && *buff1)
01745         {
01746             while (mux_isspace(*buff1))
01747             {
01748                 buff1++;
01749             }
01750 
01751             if (*buff1 == NUMBER_TOKEN)
01752             {
01753                 buff1++;
01754             }
01755 
01756             *high_bound = mux_atol(buff1);
01757             if (*high_bound >= mudstate.db_top)
01758             {
01759                 *high_bound = mudstate.db_top - 1;
01760             }
01761         }
01762         else
01763         {
01764             *high_bound = mudstate.db_top - 1;
01765         }
01766 
01767         while (mux_isspace(*buff2))
01768         {
01769             buff2++;
01770         }
01771 
01772         if (*buff2 == NUMBER_TOKEN)
01773         {
01774             buff2++;
01775         }
01776 
01777         *low_bound = mux_atol(buff2);
01778         if (*low_bound < 0)
01779         {
01780             *low_bound = 0;
01781         }
01782     }
01783     else
01784     {
01785         *low_bound = 0;
01786         *high_bound = mudstate.db_top - 1;
01787     }
01788 }
01789 
01790 bool parse_thing_slash(dbref player, char *thing, char **after, dbref *it)
01791 {
01792     // Get name up to '/'.
01793     //
01794     char *str = thing;
01795     while (  *str != '\0'
01796           && *str != '/')
01797     {
01798         str++;
01799     }
01800 
01801     // If no '/' in string, return failure.
01802     //
01803     if (*str == '\0')
01804     {
01805         *after = NULL;
01806         *it = NOTHING;
01807         return false;
01808     }
01809     *str++ = '\0';
01810     *after = str;
01811 
01812     // Look for the object.
01813     //
01814     init_match(player, thing, NOTYPE);
01815     match_everything(MAT_EXIT_PARENTS);
01816     *it = match_result();
01817 
01818     // Return status of search.
01819     //
01820     return Good_obj(*it);
01821 }
01822 
01823 bool get_obj_and_lock(dbref player, char *what, dbref *it, ATTR **attr, char *errmsg, char **bufc)
01824 {
01825     char *str, *tbuf;
01826     int anum;
01827 
01828     tbuf = alloc_lbuf("get_obj_and_lock");
01829     strcpy(tbuf, what);
01830     if (parse_thing_slash(player, tbuf, &str, it))
01831     {
01832         // <obj>/<lock> syntax, use the named lock.
01833         //
01834         if (!search_nametab(player, lock_sw, str, &anum))
01835         {
01836             free_lbuf(tbuf);
01837             safe_str("#-1 LOCK NOT FOUND", errmsg, bufc);
01838             return false;
01839         }
01840     }
01841     else
01842     {
01843         // Not <obj>/<lock>, do a normal get of the default lock.
01844         //
01845         *it = match_thing_quiet(player, what);
01846         if (!Good_obj(*it))
01847         {
01848             free_lbuf(tbuf);
01849             safe_match_result(*it, errmsg, bufc);
01850             return false;
01851         }
01852         anum = A_LOCK;
01853     }
01854 
01855     // Get the attribute definition, fail if not found.
01856     //
01857     free_lbuf(tbuf);
01858     *attr = atr_num(anum);
01859     if (!(*attr))
01860     {
01861         safe_str("#-1 LOCK NOT FOUND", errmsg, bufc);
01862         return false;
01863     }
01864     return true;
01865 }
01866 
01867 // ---------------------------------------------------------------------------
01868 // bCanReadAttr, bCanSetAttr: Verify permission to affect attributes.
01869 // ---------------------------------------------------------------------------
01870 
01871 bool bCanReadAttr(dbref executor, dbref target, ATTR *tattr, bool bCheckParent)
01872 {
01873     if (!tattr)
01874     {
01875         return false;
01876     }
01877 
01878     dbref aowner;
01879     int aflags;
01880 
01881     if (  !mudstate.bStandAlone
01882        && bCheckParent)
01883     {
01884         atr_pget_info(target, tattr->number, &aowner, &aflags);
01885     }
01886     else
01887     {
01888         atr_get_info(target, tattr->number, &aowner, &aflags);
01889     }
01890 
01891     int mAllow = AF_VISUAL;
01892     if (  (tattr->flags & mAllow)
01893        || (aflags & mAllow))
01894     {
01895         if (  mudstate.bStandAlone
01896            || tattr->number != A_DESC
01897            || mudconf.read_rem_desc
01898            || nearby(executor, target))
01899         {
01900             return true;
01901         }
01902     }
01903     int mDeny = 0;
01904     if (WizRoy(executor))
01905     {
01906         if (God(executor))
01907         {
01908             mDeny = AF_INTERNAL;
01909         }
01910         else
01911         {
01912             mDeny = AF_INTERNAL|AF_DARK;
01913         }
01914     }
01915     else if (  Owner(executor) == aowner
01916             || Examinable(executor, target))
01917     {
01918         mDeny = AF_INTERNAL|AF_DARK|AF_MDARK;
01919     }
01920     if (mDeny)
01921     {
01922         if (  (tattr->flags & mDeny)
01923            || (aflags & mDeny))
01924         {
01925             return false;
01926         }
01927         else
01928         {
01929             return true;
01930         }
01931     }
01932     return false;
01933 }
01934 
01935 bool bCanSetAttr(dbref executor, dbref target, ATTR *tattr)
01936 {
01937     if (!tattr)
01938     {
01939         return false;
01940     }
01941 
01942     int mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST;
01943     if (!God(executor))
01944     {
01945         if (God(target))
01946         {
01947             return false;
01948         }
01949         if (Wizard(executor))
01950         {
01951             mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST|AF_LOCK|AF_GOD;
01952         }
01953         else if (Controls(executor, target))
01954         {
01955             mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST|AF_LOCK|AF_WIZARD|AF_GOD;
01956         }
01957         else
01958         {
01959             return false;
01960         }
01961     }
01962 
01963     dbref aowner;
01964     int aflags;
01965     if (  (tattr->flags & mDeny)
01966 #ifdef FIRANMUX
01967        || Immutable(target)
01968 #endif
01969        || (  atr_get_info(target, tattr->number, &aowner, &aflags)
01970           && (aflags & mDeny)))
01971     {
01972         return false;
01973     }
01974     else
01975     {
01976         return true;
01977     }
01978 }
01979 
01980 bool bCanLockAttr(dbref executor, dbref target, ATTR *tattr)
01981 {
01982     if (!tattr)
01983     {
01984         return false;
01985     }
01986 
01987     int mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST;
01988     if (!God(executor))
01989     {
01990         if (God(target))
01991         {
01992             return false;
01993         }
01994         if (Wizard(executor))
01995         {
01996             mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST|AF_GOD;
01997         }
01998         else
01999         {
02000             mDeny = AF_INTERNAL|AF_IS_LOCK|AF_CONST|AF_WIZARD|AF_GOD;
02001         }
02002     }
02003 
02004     dbref aowner;
02005     int aflags;
02006     if (  (tattr->flags & mDeny)
02007        || !atr_get_info(target, tattr->number, &aowner, &aflags)
02008        || (aflags & mDeny))
02009     {
02010         return false;
02011     }
02012     else if (  Wizard(executor)
02013             || Owner(executor) == aowner)
02014     {
02015         return true;
02016     }
02017     else
02018     {
02019         return false;
02020     }
02021 }
02022 
02023 /* ---------------------------------------------------------------------------
02024  * where_is: Returns place where obj is linked into a list.
02025  * ie. location for players/things, source for exits, NOTHING for rooms.
02026  */
02027 
02028 dbref where_is(dbref what)
02029 {
02030     if (!Good_obj(what))
02031     {
02032         return NOTHING;
02033     }
02034 
02035     dbref loc;
02036     switch (Typeof(what))
02037     {
02038     case TYPE_PLAYER:
02039     case TYPE_THING:
02040         loc = Location(what);
02041         break;
02042 
02043     case TYPE_EXIT:
02044         loc = Exits(what);
02045         break;
02046 
02047     default:
02048         loc = NOTHING;
02049         break;
02050     }
02051     return loc;
02052 }
02053 
02054 /* ---------------------------------------------------------------------------
02055  * where_room: Return room containing player, or NOTHING if no room or
02056  * recursion exceeded.  If player is a room, returns itself.
02057  */
02058 
02059 dbref where_room(dbref what)
02060 {
02061     for (int count = mudconf.ntfy_nest_lim; count > 0; count--)
02062     {
02063         if (!Good_obj(what))
02064         {
02065             break;
02066         }
02067         if (isRoom(what))
02068         {
02069             return what;
02070         }
02071         if (!Has_location(what))
02072         {
02073             break;
02074         }
02075         what = Location(what);
02076     }
02077     return NOTHING;
02078 }
02079 
02080 bool locatable(dbref player, dbref it, dbref enactor)
02081 {
02082     // No sense if trying to locate a bad object
02083     //
02084     if (!Good_obj(it))
02085     {
02086         return false;
02087     }
02088 
02089     dbref loc_it = where_is(it);
02090 
02091     // Succeed if we can examine the target, if we are the target, if we can
02092     // examine the location, if a wizard caused the lookup, or if the target
02093     // caused the lookup.
02094     //
02095     if (  Examinable(player, it)
02096        || Find_Unfindable(player)
02097        || loc_it == player
02098        || (  loc_it != NOTHING
02099           && (  Examinable(player, loc_it)
02100              || loc_it == where_is(player)))
02101        || Wizard(enactor)
02102        || it == enactor)
02103     {
02104         return true;
02105     }
02106 
02107     dbref room_it = where_room(it);
02108     bool findable_room;
02109     if (Good_obj(room_it))
02110     {
02111         findable_room = Findable(room_it);
02112     }
02113     else
02114     {
02115         findable_room = true;
02116     }
02117 
02118     // Succeed if we control the containing room or if the target is findable
02119     // and the containing room is not unfindable.
02120     //
02121     if (  (  room_it != NOTHING
02122           && Examinable(player, room_it))
02123        || Find_Unfindable(player)
02124        || (  Findable(it)
02125           && findable_room))
02126     {
02127         return true;
02128     }
02129 
02130     // We can't do it.
02131     //
02132     return false;
02133 }
02134 
02135 /* ---------------------------------------------------------------------------
02136  * nearby: Check if thing is nearby player (in inventory, in same room, or
02137  * IS the room.
02138  */
02139 
02140 bool nearby(dbref player, dbref thing)
02141 {
02142     if (  !Good_obj(player)
02143        || !Good_obj(thing))
02144     {
02145         return false;
02146     }
02147     if (  Can_Hide(thing)
02148        && Hidden(thing)
02149        && !See_Hidden(player))
02150     {
02151         return false;
02152     }
02153     dbref thing_loc = where_is(thing);
02154     if (thing_loc == player)
02155     {
02156         return true;
02157     }
02158     dbref player_loc = where_is(player);
02159     if (  thing_loc == player_loc
02160        || thing == player_loc)
02161     {
02162         return true;
02163     }
02164     return false;
02165 }
02166 
02167 /*
02168  * ---------------------------------------------------------------------------
02169  * * exit_visible, exit_displayable: Is exit visible?
02170  */
02171 bool exit_visible(dbref exit, dbref player, int key)
02172 {
02173 #ifdef WOD_REALMS
02174     if (!mudstate.bStandAlone)
02175     {
02176         int iRealmDirective = DoThingToThingVisibility(player, exit,
02177             ACTION_IS_STATIONARY);
02178         if (REALM_DO_HIDDEN_FROM_YOU == iRealmDirective)
02179         {
02180             return false;
02181         }
02182     }
02183 #endif // WOD_REALMS
02184 
02185 #ifdef REALITY_LVLS
02186     if (!mudstate.bStandAlone)
02187     {
02188     if (!IsReal(player, exit))
02189        return 0;
02190     }
02191 #endif /* REALITY_LVLS */
02192 
02193     // Exam exit's location
02194     //
02195     if (  (key & VE_LOC_XAM)
02196        || Examinable(player, exit)
02197        || Light(exit))
02198     {
02199         return true;
02200     }
02201 
02202     // Dark location or base
02203     //
02204     if (  (key & (VE_LOC_DARK | VE_BASE_DARK))
02205        || Dark(exit))
02206     {
02207         return false;
02208     }
02209 
02210     // Default
02211     //
02212     return true;
02213 }
02214 
02215 // Exit visible to look
02216 //
02217 bool exit_displayable(dbref exit, dbref player, int key)
02218 {
02219     // Dark exit
02220     //
02221     if (Dark(exit))
02222     {
02223         return false;
02224     }
02225 
02226 #ifdef WOD_REALMS
02227     if (!mudstate.bStandAlone)
02228     {
02229         int iRealmDirective = DoThingToThingVisibility(player, exit,
02230             ACTION_IS_STATIONARY);
02231         if (REALM_DO_HIDDEN_FROM_YOU == iRealmDirective)
02232         {
02233             return false;
02234         }
02235     }
02236 #endif // WOD_REALMS
02237 
02238     // Light exit
02239     //
02240     if (Light(exit))
02241     {
02242         return true;
02243     }
02244 
02245     // Dark location or base.
02246     //
02247     if (key & (VE_LOC_DARK | VE_BASE_DARK))
02248     {
02249         return false;
02250     }
02251 
02252     // Default
02253     //
02254     return true;
02255 }
02256 
02257 /* ---------------------------------------------------------------------------
02258  * did_it: Have player do something to/with thing
02259  */
02260 
02261 void did_it(dbref player, dbref thing, int what, const char *def, int owhat,
02262             const char *odef, int awhat, char *args[], int nargs)
02263 {
02264     if (MuxAlarm.bAlarmed)
02265     {
02266         return;
02267     }
02268 
02269     char *d, *buff, *act, *charges, *bp, *str;
02270     dbref loc, aowner;
02271     int num, aflags;
02272 
02273     // If we need to call exec() from within this function, we first save
02274     // the state of the global registers, in order to avoid munging them
02275     // inappropriately. Do note that the restoration to their original
02276     // values occurs BEFORE the execution of the @a-attribute. Therefore,
02277     // any changing of setq() values done in the @-attribute and @o-attribute
02278     // will NOT be passed on. This prevents odd behaviors that result from
02279     // odd @verbs and so forth (the idea is to preserve the caller's control
02280     // of the global register values).
02281     //
02282 
02283     bool need_pres = false;
02284     char **preserve = NULL;
02285     int *preserve_len = NULL;
02286 
02287     // message to player.
02288     //
02289     if (what > 0)
02290     {
02291         d = atr_pget(thing, what, &aowner, &aflags);
02292         if (*d)
02293         {
02294             need_pres = true;
02295             preserve = PushPointers(MAX_GLOBAL_REGS);
02296             preserve_len = PushIntegers(MAX_GLOBAL_REGS);
02297             save_global_regs("did_it_save", preserve, preserve_len);
02298             buff = bp = alloc_lbuf("did_it.1");
02299             str = d;
02300             mux_exec(buff, &bp, thing, player, player,
02301                 EV_EVAL | EV_FIGNORE | EV_FCHECK | EV_TOP, &str, args, nargs);
02302             *bp = '\0';
02303             if (  (aflags & AF_HTML)
02304                && Html(player))
02305             {
02306                 safe_str("\r\n", buff, &bp);
02307                 *bp = '\0';
02308                 notify_html(player, buff);
02309             }
02310             else
02311             {
02312                 notify(player, buff);
02313             }
02314             free_lbuf(buff);
02315         }
02316         else if (def)
02317         {
02318             notify(player, def);
02319         }
02320         free_lbuf(d);
02321     }
02322     if (what < 0 && def)
02323     {
02324         notify(player, def);
02325     }
02326 
02327     // message to neighbors.
02328     //
02329     if (  owhat > 0
02330        && Has_location(player)
02331        && Good_obj(loc = Location(player)))
02332     {
02333         d = atr_pget(thing, owhat, &aowner, &aflags);
02334         if (*d)
02335         {
02336             if (!need_pres)
02337             {
02338                 need_pres = true;
02339                 preserve = PushPointers(MAX_GLOBAL_REGS);
02340                 preserve_len = PushIntegers(MAX_GLOBAL_REGS);
02341                 save_global_regs("did_it_save", preserve, preserve_len);
02342             }
02343             buff = bp = alloc_lbuf("did_it.2");
02344             str = d;
02345             mux_exec(buff, &bp, thing, player, player,
02346                      EV_EVAL | EV_FIGNORE | EV_FCHECK | EV_TOP, &str, args, nargs);
02347             *bp = '\0';
02348             if (*buff)
02349             {
02350 #ifdef REALITY_LVLS
02351                 notify_except2_rlevel(loc, player, player, thing, tprintf("%s %s", Name(player), buff));
02352 #else
02353                 notify_except2(loc, player, player, thing, tprintf("%s %s", Name(player), buff));
02354 #endif /* REALITY_LVLS */
02355             }
02356             free_lbuf(buff);
02357         }
02358         else if (odef)
02359         {
02360 #ifdef REALITY_LVLS
02361             notify_except2_rlevel(loc, player, player, thing, tprintf("%s %s", Name(player), odef));
02362 #else
02363             notify_except2(loc, player, player, thing, tprintf("%s %s", Name(player), odef));
02364 #endif /* REALITY_LVLS */
02365         }
02366         free_lbuf(d);
02367     }
02368     if (  owhat < 0
02369        && odef
02370        && Has_location(player)
02371        && Good_obj(loc = Location(player)))
02372     {
02373 #ifdef REALITY_LVLS
02374         notify_except2_rlevel(loc, player, player, thing, tprintf("%s %s", Name(player), odef));
02375 #else
02376         notify_except2(loc, player, player, thing, tprintf("%s %s", Name(player), odef));
02377 #endif /* REALITY_LVLS */
02378     }
02379 
02380     // If we preserved the state of the global registers, restore them.
02381     //
02382     if (need_pres)
02383     {
02384         restore_global_regs("did_it_restore", preserve, preserve_len);
02385         PopIntegers(preserve_len, MAX_GLOBAL_REGS);
02386         PopPointers(preserve, MAX_GLOBAL_REGS);
02387     }
02388 
02389     // do the action attribute.
02390     //
02391 #ifdef REALITY_LVLS
02392     if (awhat > 0 && IsReal(thing, player))
02393 #else
02394     if (awhat > 0)
02395 #endif /* REALITY_LVLS */
02396     {
02397         if (*(act = atr_pget(thing, awhat, &aowner, &aflags)))
02398         {
02399             charges = atr_pget(thing, A_CHARGES, &aowner, &aflags);
02400             if (*charges)
02401             {
02402                 num = mux_atol(charges);
02403                 if (num > 0)
02404                 {
02405                     buff = alloc_sbuf("did_it.charges");
02406                     mux_ltoa(num-1, buff);
02407                     atr_add_raw(thing, A_CHARGES, buff);
02408                     free_sbuf(buff);
02409                 }
02410                 else if (*(buff = atr_pget(thing, A_RUNOUT, &aowner, &aflags)))
02411                 {
02412                     free_lbuf(act);
02413                     act = buff;
02414                 }
02415                 else
02416                 {
02417                     free_lbuf(act);
02418                     free_lbuf(buff);
02419                     free_lbuf(charges);
02420                     return;
02421                 }
02422             }
02423             free_lbuf(charges);
02424             CLinearTimeAbsolute lta;
02425             wait_que(thing, player, player, false, lta, NOTHING, 0, act,
02426                 args, nargs, mudstate.global_regs);
02427         }
02428         free_lbuf(act);
02429     }
02430 }
02431 
02432 /* ---------------------------------------------------------------------------
02433  * do_verb: Command interface to did_it.
02434  */
02435 
02436 void do_verb(dbref executor, dbref caller, dbref enactor, int key,
02437              char *victim_str, char *args[], int nargs)
02438 {
02439     UNUSED_PARAMETER(caller);
02440     UNUSED_PARAMETER(key);
02441 
02442     // Look for the victim.
02443     //
02444     if (  !victim_str
02445        || !*victim_str)
02446     {
02447         notify(executor, "Nothing to do.");
02448         return;
02449     }
02450 
02451     // Get the victim.
02452     //
02453     init_match(executor, victim_str, NOTYPE);
02454     match_everything(MAT_EXIT_PARENTS);
02455     dbref victim = noisy_match_result();
02456     if (!Good_obj(victim))
02457     {
02458         return;
02459     }
02460 
02461     // Get the actor.  Default is my cause.
02462     //
02463     dbref actor;
02464     if (  nargs >= 1
02465        && args[0] && *args[0])
02466     {
02467         init_match(executor, args[0], NOTYPE);
02468         match_everything(MAT_EXIT_PARENTS);
02469         actor = noisy_match_result();
02470         if (!Good_obj(actor))
02471         {
02472             return;
02473         }
02474     }
02475     else
02476     {
02477         actor = enactor;
02478     }
02479 
02480     // Check permissions.  There are two possibilities:
02481     //
02482     //    1. Executor controls both victim and actor. In this case,
02483     //       victim runs his action list.
02484     //
02485     //    2. Executor controls actor. In this case victim does not run
02486     //       his action list and any attributes that executor cannot read
02487     //       from victim are defaulted.
02488     //
02489     if (!Controls(executor, actor))
02490     {
02491         notify_quiet(executor, "Permission denied,");
02492         return;
02493     }
02494 
02495     ATTR *ap;
02496     int what = -1;
02497     int owhat = -1;
02498     int awhat = -1;
02499     const char *whatd = NULL;
02500     const char *owhatd = NULL;
02501     int nxargs = 0;
02502     dbref aowner = NOTHING;
02503     int aflags = NOTHING;
02504     char *xargs[10];
02505 
02506     switch (nargs) // Yes, this IS supposed to fall through.
02507     {
02508     case 7:
02509         // Get arguments.
02510         //
02511         parse_arglist(victim, actor, actor, args[6], '\0',
02512             EV_STRIP_LS | EV_STRIP_TS, xargs, 10, (char **)NULL, 0, &nxargs);
02513 
02514     case 6:
02515         // Get action attribute.
02516         //
02517         ap = atr_str(args[5]);
02518         if (ap)
02519         {
02520             awhat = ap->number;
02521         }
02522 
02523     case 5:
02524         // Get others message default.
02525         //
02526         if (args[4] && *args[4])
02527         {
02528             owhatd = args[4];
02529         }
02530 
02531     case 4:
02532         // Get others message attribute.
02533         //
02534         ap = atr_str(args[3]);
02535         if (ap && (ap->number > 0))
02536         {
02537             owhat = ap->number;
02538         }
02539 
02540     case 3:
02541         // Get enactor message default.
02542         //
02543         if (args[2] && *args[2])
02544         {
02545             whatd = args[2];
02546         }
02547 
02548     case 2:
02549         // Get enactor message attribute.
02550         //
02551         ap = atr_str(args[1]);
02552         if (ap && (ap->number > 0))
02553         {
02554             what = ap->number;
02555         }
02556     }
02557 
02558     // If executor doesn't control both, enforce visibility restrictions.
02559     //
02560     if (!Controls(executor, victim))
02561     {
02562         ap = NULL;
02563         if (what != -1)
02564         {
02565             atr_get_info(victim, what, &aowner, &aflags);
02566             ap = atr_num(what);
02567         }
02568         if (  !ap
02569            || !bCanReadAttr(executor, victim, ap, false)
02570            || (  ap->number == A_DESC
02571               && !mudconf.read_rem_desc
02572               && !Examinable(executor, victim)
02573               && !nearby(executor, victim)))
02574         {
02575             what = -1;
02576         }
02577 
02578         ap = NULL;
02579         if (owhat != -1)
02580         {
02581             atr_get_info(victim, owhat, &aowner, &aflags);
02582             ap = atr_num(owhat);
02583         }
02584         if (  !ap
02585            || !bCanReadAttr(executor, victim, ap, false)
02586            || (  ap->number == A_DESC
02587               && !mudconf.read_rem_desc
02588               && !Examinable(executor, victim)
02589               && !nearby(executor, victim)))
02590         {
02591             owhat = -1;
02592         }
02593 
02594         awhat = 0;
02595     }
02596 
02597     // Go do it.
02598     //
02599     did_it(actor, victim, what, whatd, owhat, owhatd, awhat, xargs, nxargs);
02600 
02601     // Free user args.
02602     //
02603     for (int i = 0; i < nxargs; i++)
02604     {
02605         free_lbuf(xargs[i]);
02606     }
02607 }
02608 
02609 // --------------------------------------------------------------------------
02610 // OutOfMemory: handle an out of memory condition.
02611 //
02612 void OutOfMemory(const char *SourceFile, unsigned int LineNo)
02613 {
02614     Log.tinyprintf("%s(%u): Out of memory." ENDLINE, SourceFile, LineNo);
02615     Log.Flush();
02616     if (  !mudstate.bStandAlone
02617        && mudstate.bCanRestart)
02618     {
02619         do_restart(GOD, GOD, GOD, 0);
02620     }
02621     else
02622     {
02623         abort();
02624     }
02625 }
02626 
02627 // --------------------------------------------------------------------------
02628 // AssertionFailed: A logical assertion has failed.
02629 //
02630 bool AssertionFailed(const char *SourceFile, unsigned int LineNo)
02631 {
02632     Log.tinyprintf("%s(%u): Assertion failed." ENDLINE, SourceFile, LineNo);
02633     Log.Flush();
02634     if (  !mudstate.bStandAlone
02635        && mudstate.bCanRestart)
02636     {
02637         do_restart(GOD, GOD, GOD, 0);
02638     }
02639     else
02640     {
02641         abort();
02642     }
02643     return false;
02644 }

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