/* $Header: /cvsroot/fbmuck/fbmuck/src/predicates.c,v 1.8 2003/10/07 07:24:28 revar Exp $ */ /* * $Log: predicates.c,v $ * Revision 1.8 2003/10/07 07:24:28 revar * Fixed possible crasher bug with autostart programs. * * Revision 1.7 2002/09/08 23:07:19 sombre * Fixed memory leak when toading online players. * Fixed remove_prop bug so it will remove props ending in /. (bug #537744) * Fixed potential buffer overrun with the CHECKRETURN and ABORT_MPI macros. * Fixed @omessage bug where player names would not be prefixed on additional * newlines. (bug #562370) * Added IGNORING? ( d1 d2 -- i ) returns true if d1 is ignoring d2. * Added IGNORE_ADD ( d1 d2 -- ) adds d2 to d1's ignore list. * Added IGNORE_DEL ( d1 d2 -- ) removes d2 from d1's ignore list. * Added ARRAY_GET_IGNORELIST ( d -- a ) returns an array of d's ignores. * Added support for ignoring (gagging) players, ignores are mutual in that if * player A ignores player B, A will not hear B, and B will not hear A. * Added ignore_prop @tune to specify the directory the ignore list is held under, * if set blank ignore support is disabled, defaults to "@ignore/def". * Added max_ml4_preempt_count @tune to specify the maximum number of instructions * an mlevel4 (wizbitted) program may run before it is aborted, if set to 0 * no limit is imposed. Defaults to 0. * Added reserved_names @tune which when set to a smatch pattern will refuse any * object creations or renames which match said pattern. Defaults to "". * Added reserved_player_names @tune which when set to a smatch pattern will refuse * any player creations or renames which match said pattern. Defaults to "". * * Revision 1.6 2001/05/16 22:23:11 wog * Made ( and ) restricted to only player names. * * Revision 1.5 2001/05/16 22:14:34 wog * Prevented player names with ( or ) in them. * * Revision 1.4 2000/11/22 10:01:58 revar * Changed MPI from using Wizbit objects to give special permissions, to using * 'Blessed' properties. Blessed props have few permissions restrictions. * Added @bless and @unbless wizard commands. * Added BLESSPROP and UNBLESSPROP muf primitives. * Added {bless} {unbless} and {revoke} MPI commands. * Fixed {listprops} crasher bug. * * Revision 1.3 2000/06/15 18:35:11 revar * Prettified some code formatting slightly. * * Revision 1.2 2000/03/29 12:21:02 revar * Reformatted all code into consistent format. * Tabs are 4 spaces. * Indents are one tab. * Braces are generally K&R style. * Added ARRAY_DIFF, ARRAY_INTERSECT and ARRAY_UNION to man.txt. * Rewrote restart script as a bourne shell script. * * Revision 1.1.1.1 1999/12/16 03:23:29 revar * Initial Sourceforge checkin, fb6.00a29 * * Revision 1.1.1.1 1999/12/12 07:27:43 foxen * Initial FB6 CVS checkin. * * Revision 1.1 1996/06/12 02:47:32 foxen * Initial revision * * Revision 5.13 1994/03/14 12:20:58 foxen * Fb5.20 release checkpoint. * * Revision 5.12 1994/01/18 20:52:20 foxen * Version 5.15 release. * * Revision 5.11 1993/12/20 06:22:51 foxen * *** empty log message *** * * Revision 5.1 1993/12/17 00:07:33 foxen * initial revision. * * Revision 1.1 91/08/20 15:05:30 jearls * Initial revision * * Revision 1.2 91/03/24 01:19:30 lynx * added check for jump_ok or owned by owner of actions * * Revision 1.1 91/01/24 00:44:27 cks * changes for QUELL. * * Revision 1.0 91/01/22 20:54:34 cks * Initial revision * * Revision 1.8 90/09/18 08:01:39 rearl * Fixed a few broken things. * * Revision 1.7 90/09/16 04:42:42 rearl * Preparation code added for disk-based MUCK. * * Revision 1.6 90/09/10 02:22:30 rearl * Fixed some calls to pronoun_substitute. * * Revision 1.5 90/08/27 03:32:49 rearl * Major changes on several predicates, usage... * * Revision 1.4 90/08/15 03:07:34 rearl * Macroified some things. Took out #ifdef GENDER. * * Revision 1.3 90/08/06 02:46:30 rearl * Put can_link() back in. Added restricted() for flags. * With #define GOD_PRIV, sub-wizards can no longer set other * players to Wizard. * * Revision 1.2 90/08/02 18:54:04 rearl * Fixed controls() to return TRUE if exit is unlinked. Everyone * controls an unlinked exit. Got rid of can_link(). * * Revision 1.1 90/07/19 23:03:58 casie * Initial revision * * */ #include "copyright.h" #include "config.h" /* Predicates for testing various conditions */ #include <ctype.h> #include "db.h" #include "props.h" #include "interface.h" #include "params.h" #include "tune.h" #include "externs.h" int OkObj(dbref obj) { if (obj < 0 || obj >= db_top) { return 0; } if (Typeof(obj) == TYPE_GARBAGE) { return 0; } return 1; } int can_link_to(dbref who, object_flag_type what_type, dbref where) { if (where == HOME) return 1; if (where < 0 || where > db_top) return 0; switch (what_type) { case TYPE_EXIT: return (controls(who, where) || (FLAGS(where) & LINK_OK)); /* NOTREACHED */ break; case TYPE_PLAYER: return (Typeof(where) == TYPE_ROOM && (controls(who, where) || Linkable(where))); /* NOTREACHED */ break; case TYPE_ROOM: return ((Typeof(where) == TYPE_ROOM || Typeof(where) == TYPE_THING) && (controls(who, where) || Linkable(where))); /* NOTREACHED */ break; case TYPE_THING: return ( (Typeof(where) == TYPE_ROOM || Typeof(where) == TYPE_PLAYER || Typeof(where) == TYPE_THING) && (controls(who, where) || Linkable(where))); /* NOTREACHED */ break; case NOTYPE: return (controls(who, where) || (FLAGS(where) & LINK_OK) || (Typeof(where) != TYPE_THING && (FLAGS(where) & ABODE))); /* NOTREACHED */ break; } return 0; } int can_link(dbref who, dbref what) { return (controls(who, what) || ((Typeof(what) == TYPE_EXIT) && DBFETCH(what)->sp.exit.ndest == 0)); } /* * Revision 1.2 -- SECURE_TELEPORT * you can only jump with an action from rooms that you own * or that are jump_ok, and you cannot jump to players that are !jump_ok. */ int could_doit(int descr, dbref player, dbref thing) { dbref source, dest, owner; if (Typeof(thing) == TYPE_EXIT) { if (DBFETCH(thing)->sp.exit.ndest == 0) { return 0; } owner = OWNER(thing); source = DBFETCH(player)->location; dest = *(DBFETCH(thing)->sp.exit.dest); if (Typeof(dest) == TYPE_PLAYER) { dbref destplayer = dest; dest = DBFETCH(dest)->location; if (!(FLAGS(destplayer) & JUMP_OK) || (FLAGS(dest) & BUILDER)) { return 0; } } /* for actions */ if ((DBFETCH(thing)->location != NOTHING) && (Typeof(DBFETCH(thing)->location) != TYPE_ROOM)) { if ((Typeof(dest) == TYPE_ROOM || Typeof(dest) == TYPE_PLAYER) && (FLAGS(source) & BUILDER)) return 0; if (tp_secure_teleport && Typeof(dest) == TYPE_ROOM) { if ((dest != HOME) && (!controls(owner, source)) && ((FLAGS(source) & JUMP_OK) == 0)) { return 0; } } } } return (eval_boolexp(descr, player, GETLOCK(thing), thing)); } int test_lock(int descr, dbref player, dbref thing, const char *lockprop) { struct boolexp *lokptr; lokptr = get_property_lock(thing, lockprop); return (eval_boolexp(descr, player, lokptr, thing)); } int test_lock_false_default(int descr, dbref player, dbref thing, const char *lockprop) { struct boolexp *lok = get_property_lock(thing, lockprop); if (lok == TRUE_BOOLEXP) return 0; return (eval_boolexp(descr, player, lok, thing)); } int can_doit(int descr, dbref player, dbref thing, const char *default_fail_msg) { dbref loc; if ((loc = getloc(player)) == NOTHING) return 0; if (!Wizard(OWNER(player)) && Typeof(player) == TYPE_THING && (FLAGS(thing) & ZOMBIE)) { notify(player, "Sorry, but zombies can't do that."); return 0; } if (!could_doit(descr, player, thing)) { /* can't do it */ if (GETFAIL(thing)) { exec_or_notify_prop(descr, player, thing, MESGPROP_FAIL, "(@Fail)"); } else if (default_fail_msg) { notify(player, default_fail_msg); } if (GETOFAIL(thing) && !Dark(player)) { parse_oprop(descr, player, loc, thing, MESGPROP_OFAIL, PNAME(player), "(@Ofail)"); } return 0; } else { /* can do it */ if (GETSUCC(thing)) { exec_or_notify_prop(descr, player, thing, MESGPROP_SUCC, "(@Succ)"); } if (GETOSUCC(thing) && !Dark(player)) { parse_oprop(descr, player, loc, thing, MESGPROP_OSUCC, NAME(player), "(@Osucc)"); } return 1; } } int can_see(dbref player, dbref thing, int can_see_loc) { if (player == thing || Typeof(thing) == TYPE_EXIT || Typeof(thing) == TYPE_ROOM) return 0; if (can_see_loc) { switch (Typeof(thing)) { case TYPE_PROGRAM: return ((FLAGS(thing) & LINK_OK) || controls(player, thing)); case TYPE_PLAYER: if (tp_dark_sleepers) { return (!Dark(thing) && online(thing)); } default: return (!Dark(thing) || (controls(player, thing) && !(FLAGS(player) & STICKY))); } } else { /* can't see loc */ return (controls(player, thing) && !(FLAGS(player) & STICKY)); } } int controls(dbref who, dbref what) { dbref index; /* No one controls invalid objects */ if (what < 0 || what >= db_top) return 0; /* No one controls garbage */ if (Typeof(what) == TYPE_GARBAGE) return 0; if (Typeof(who) != TYPE_PLAYER) who = OWNER(who); /* Wizard controls everything else */ if (Wizard(who)) return 1; if (tp_realms_control) { /* Realm Owner controls everything under his environment. */ for (index = what; index != NOTHING; index = getloc(index)) { if ((OWNER(index) == who) && (Typeof(index) == TYPE_ROOM) && Wizard(index)) return 1; } } /* exits are also controlled by the owners of the source and destination */ /* ACTUALLY, THEY AREN'T. IT OPENS A BAD MPI SECURITY HOLE. */ /* * if (Typeof(what) == TYPE_EXIT) { * int i = DBFETCH(what)->sp.exit.ndest; * * while (i > 0) { * if (who == OWNER(DBFETCH(what)->sp.exit.dest[--i])) * return 1; * } * if (who == OWNER(DBFETCH(what)->location)) * return 1; * } */ /* owners control their own stuff */ return (who == OWNER(what)); } int restricted(dbref player, dbref thing, object_flag_type flag) { switch (flag) { case ABODE: return (!TrueWizard(OWNER(player)) && (Typeof(thing) == TYPE_PROGRAM)); /* NOTREACHED */ break; case ZOMBIE: if (Typeof(thing) == TYPE_PLAYER) return (!(Wizard(OWNER(player)))); if ((Typeof(thing) == TYPE_THING) && (FLAGS(OWNER(player)) & ZOMBIE)) return (!(Wizard(OWNER(player)))); return (0); case VEHICLE: if (Typeof(thing) == TYPE_PLAYER) return (!(Wizard(OWNER(player)))); if (tp_wiz_vehicles) { if (Typeof(thing) == TYPE_THING) return (!(Wizard(OWNER(player)))); } else { if ((Typeof(thing) == TYPE_THING) && (FLAGS(player) & VEHICLE)) return (!(Wizard(OWNER(player)))); } return (0); case DARK: if (!Wizard(OWNER(player))) { if (Typeof(thing) == TYPE_PLAYER) return (1); if (!tp_exit_darking && Typeof(thing) == TYPE_EXIT) return (1); if (!tp_thing_darking && Typeof(thing) == TYPE_THING) return (1); } return (0); /* NOTREACHED */ break; case QUELL: /* You cannot quell or unquell another wizard. */ return (TrueWizard(thing) && (thing != player) && (Typeof(thing) == TYPE_PLAYER)); /* NOTREACHED */ break; case MUCKER: case SMUCKER: case BUILDER: return (!Wizard(OWNER(player))); /* NOTREACHED */ break; case WIZARD: if (Wizard(OWNER(player))) { #ifdef GOD_PRIV return ((Typeof(thing) == TYPE_PLAYER) && !God(player)); #else /* !GOD_PRIV */ return 0; #endif /* GOD_PRIV */ } else return 1; /* NOTREACHED */ break; default: return 0; /* NOTREACHED */ break; } } int payfor(dbref who, int cost) { who = OWNER(who); if (Wizard(who)) { return 1; } else if (PLAYER_PENNIES(who) >= cost) { PLAYER_ADD_PENNIES(who, -cost); DBDIRTY(who); return 1; } else { return 0; } } int word_start(const char *str, const char let) { int chk; for (chk = 1; *str; str++) { if (chk && *str == let) return 1; chk = *str == ' '; } return 0; } int ok_name(const char *name) { return (name && *name && *name != LOOKUP_TOKEN && *name != REGISTERED_TOKEN && *name != NUMBER_TOKEN && !index(name, ARG_DELIMITER) && !index(name, AND_TOKEN) && !index(name, OR_TOKEN) && !index(name, '\r') && !index(name, ESCAPE_CHAR) && !word_start(name, NOT_TOKEN) && string_compare(name, "me") && string_compare(name, "home") && string_compare(name, "here") && ( !*tp_reserved_names || !equalstr((char*)tp_reserved_names, (char*)name) )); } int ok_player_name(const char *name) { const char *scan; if (!ok_name(name) || strlen(name) > PLAYER_NAME_LIMIT) return 0; for (scan = name; *scan; scan++) { if (!(isprint(*scan) && !isspace(*scan)) && *scan != '(' && *scan != ')') { /* was isgraph(*scan) */ return 0; } } /* Check the name isn't reserved */ if (*tp_reserved_player_names && equalstr((char*)tp_reserved_player_names, (char*)name)) return 0; /* lookup name to avoid conflicts */ return (lookup_player(name) == NOTHING); } int ok_password(const char *password) { const char *scan; if (*password == '\0') return 0; for (scan = password; *scan; scan++) { if (!(isprint(*scan) && !isspace(*scan))) { return 0; } } return 1; } int isancestor(dbref parent, dbref child) { while (child != NOTHING && child != parent) { child = getparent(child); } return child == parent; }