/* This software is Copyright 1989, 1990, 1992, 1993 by various individuals. Please see the accompanying file COPYRIGHT for details. */ #include #include "db.h" #include "defs.h" #include "inst.h" #include "match.h" #include "ctype.h" #include "config.h" #include "params.h" #include "externs.h" #include "strings.h" #include "strings.h" #include "property.h" #include "interface.h" #include "unused-arg.h" static PROPATTR prop_who(dbref player, dbref thing) { return(PPERM_PICKWHO(God(player),Wizard(player),Royalty(player),player==OWNER(thing))); } static dbref match_controlled(dbref player, const char *name) { dbref match; struct match_data md; init_match(player,name,NOTYPE,&md); match_everything(&md); match = noisy_match_result(&md); if ((match != NOTHING) && !controls(player,match)) { notify(player,"Permission denied."); return(NOTHING); } return(match); } void do_name(dbref player, const char *name, char *newname) { dbref thing; char *password; thing = match_controlled(player,name); if (thing != NOTHING) { /* check for bad name */ if (*newname == '\0') { notify(player,"Give it what new name?"); return; } if (!PERMIT_RENAME(player,thing)) { notify(player,"You are not allowed to rename that."); return; } /* check for renaming a player */ if (Typeof(thing) == TYPE_PLAYER) { /* split off password */ for (password=newname;*password&&!Cisspace(*password);password++) ; /* eat whitespace */ if (*password) { *password++ = '\0'; /* terminate name */ while (*password && Cisspace(*password)) password++; } if (! Wizard(player)) { /* check for null password */ if (!*password) { notify(player,"You must specify a password to change a player name."); notify(player,"E.g.: name player = newname password"); return; } else if (check_password(password,thing)) { notify(player,"Incorrect password."); return; } } if (string_compare(newname,NAME(thing)) && !ok_player_name(newname)) { notify(player,"You can't give a player that name."); return; } /* everything ok, notify */ log_status("NAME CHANGE: %s(#%d) to %s",NAME(thing),(int)thing,newname); delete_player(thing); if (NAME(thing)) free((void *) NAME(thing)); NAME(thing) = dup_string(newname); add_player(thing); notify(player,"Name set."); return; } else { if (!ok_name(newname)) { notify(player,"That is not a reasonable name."); return; } } /* everything ok, change the name */ if(NAME(thing)) free((void *) NAME(thing)); NAME(thing) = dup_string(newname); notify(player,"Name set."); DBDIRTY(thing); } } #ifdef TIMESTAMPS #define SETFIELDHELP DBFETCH(thing)->time_modified = curtm(); #else #define SETFIELDHELP /* nothing */ #endif #define SETFIELDCMD(Cname,field,msg) \ void Cname(dbref player, const char *name, const char *new) \ { \ dbref thing; \ \ thing = match_controlled(player,name); \ if (thing != NOTHING) \ { free_str(DBFETCH(thing)->field); \ DBSTORE(thing,field,store_str(new)); \ notify(player,msg); \ SETFIELDHELP \ } \ } SETFIELDCMD(do_describe,description,"Description set.") SETFIELDCMD(do_fail,fail_message,"Message set.") SETFIELDCMD(do_success,succ_message,"Message set.") SETFIELDCMD(do_drop_message,drop_message,"Message set.") SETFIELDCMD(do_osuccess,osuccess,"Message set.") SETFIELDCMD(do_ofail,ofail,"Message set.") SETFIELDCMD(do_odrop,odrop,"Message set.") #undef SETFIELDCMD #undef SETFIELDHELP void do_lock(dbref player, const char *name, const char *keyname) { dbref thing; struct boolexp *key; struct match_data md; init_match(player,name,NOTYPE,&md); match_everything(&md); thing = match_result(&md); switch (thing) { case NOTHING: notify(player,"I don't see what you want to lock!"); return; break; case AMBIGUOUS: notify(player,"I don't know which one you want to lock!"); return; break; default: if (!controls(player,thing)) { notify(player,"You can't lock that!"); return; } break; } key = parse_boolexp(player,keyname); if (key == TRUE_BOOLEXP) { notify(player,"I don't understand that key."); } else { #ifdef TIMESTAMPS DBFETCH(thing)->time_modified = curtm(); #endif /* everything ok, do it */ remove_backlocks_parse(thing,DBFETCH(thing)->key); free_boolexp(DBFETCH(thing)->key); DBSTORE(thing,key,key); add_backlocks_parse(thing,DBFETCH(thing)->key); notify(player,"Locked."); } } void do_unlock(dbref player, const char *name) { dbref thing; thing = match_controlled(player,name); if (thing != NOTHING) { remove_backlocks_parse(thing,DBFETCH(thing)->key); free_boolexp(DBFETCH(thing)->key); DBSTORE(thing,key,TRUE_BOOLEXP); notify(player,"Unlocked."); } } void do_unlink(dbref player, const char *name) { dbref xit; int exitdest; struct match_data md; init_match(player,name,TYPE_EXIT,&md); match_all_exits(&md); match_here(&md); if (Royalty(player)) match_absolute(&md); xit = match_result(&md); switch (xit) { case NOTHING: notify(player,"Unlink what?"); break; case AMBIGUOUS: notify(player,"I don't know which one you mean!"); break; default: if (!controls(player,xit)) { notify(player,"Permission denied."); } else { switch (Typeof(xit)) { case TYPE_EXIT: if (DBFETCH(xit)->sp.exit.ndest != 0) { for ( exitdest=0; exitdestsp.exit.ndest; exitdest++ ) { remove_backlinks (xit,DBFETCH(xit)->sp.exit.dest[exitdest]); } if (!Wizard(player)) { add_pennies(OWNER(xit),LINK_COST,"@unlink"); } } DBSTORE(xit,sp.exit.ndest,0); if (DBFETCH(xit)->sp.exit.dest) { free(DBFETCH(xit)->sp.exit.dest); DBSTORE(xit,sp.exit.dest,0); } notify(player,"Unlinked."); break; case TYPE_ROOM: remove_backlinks(xit,DBFETCH(xit)->sp.room.dropto); DBSTORE(xit,sp.room.dropto,NOTHING); notify(player,"Dropto removed."); break; default: notify(player,"You can't unlink that!"); break; } } break; } } void do_chown(dbref player, const char *name, const char *newowner) { dbref thing; dbref owner; struct match_data md; if (!*name) { notify(player,"You must specify what you want to take ownership of."); return; } init_match(player,name,NOTYPE,&md); match_everything(&md); thing = noisy_match_result(&md); if (thing == NOTHING) return; if (*newowner && string_compare(newowner,"me")) { owner = lookup_player(newowner); if (owner == NOTHING) { notify(player,"I couldn't find that player."); return; } } else { owner = player; } if (!Wizard(player) && (player != owner)) { notify(player,"Only wizards can transfer ownership to others."); return; } if (OWNER(thing) == owner) { if (player == owner) { notify(player,"You already own that."); } else { notify(player,"That player already owns that thing."); } return; } if ( !Wizard(player) && ( !(FLAGS(thing) & OWNABLE) || (Typeof(thing) == TYPE_DAEMON) ) ) { notify(player,"You can't take possession of that."); return; } switch (Typeof(thing)) { case TYPE_ROOM: if (!Wizard(player) && (DBFETCH(player)->location != thing)) { notify(player,"You can't chown rooms you're not in."); return; } remove_ownerlist(thing); OWNER(thing) = owner; add_ownerlist(thing); break; case TYPE_THING: if (!Wizard(player) && (DBFETCH(thing)->location != player)) { notify(player,"You aren't carrying that."); return; } remove_ownerlist(thing); OWNER(thing) = owner; add_ownerlist(thing); break; case TYPE_PLAYER: notify(player,"Players always own themselves."); return; break; case TYPE_EXIT: case TYPE_PROGRAM: remove_ownerlist(thing); OWNER(thing) = owner; add_ownerlist(thing); break; case TYPE_DAEMON: if ( DBFETCH(owner)->sp.player.daemons >= (TrueWizard(owner) ? MAX_WIZ_DAEMONS : MAX_DAEMONS) ) { notify(player,"Warning: new owner will own too many daemons."); } DBFETCH(owner)->sp.player.daemons ++; DBFETCH(OWNER(thing))->sp.player.daemons --; remove_ownerlist(thing); OWNER(thing) = owner; add_ownerlist(thing); break; case TYPE_GARBAGE: notify(player,"No one wants to own garbage."); return; break; } if (owner == player) { notify(player,"Owner changed to you."); } else { char buf[BUFFER_LEN]; sprintf(&buf[0],"Owner changed to %s.",unparse_object(player,owner)); notify(player,buf); } DBDIRTY(thing); } /* Note: Gender code taken out. All gender references are now to be handled by property lists... Setting of flags and property code done here. Note that the PROP_DELIMITER identifies when you're setting a property. A @set =: will clear all properties [no longer, now it points you to @unsetall]. A @set =name: will remove that property. A @set =name:value will add that property or replace it. */ void do_set(dbref player, const char *name, const char *flag) { dbref thing; const char *p; object_flag_type f; struct propref *pr; PROPATTR perm; /* find thing */ thing = match_controlled(player,name); if (thing == NOTHING) return; #ifdef TIMESTAMPS DBFETCH(thing)->time_modified = curtm(); #endif /* Check to see if it's a property reference */ /* if this gets changed, please also modify boolexp.c */ if (index(flag,PROP_DELIMITER)) { /* copy the string so we can muck with it */ char *name; char *value; char *x; /* to preserve string location so we can free it */ char *temp; perm = prop_who(player,thing); name = dup_string(flag); value = index(name,PROP_DELIMITER); x = name; while (*name && Cisspace(*name)) name ++; if (*name == PROP_DELIMITER) { if (strlen(name) > 1) { notify(player,"Invalid property name."); } else { notify(player,"Use @unsetall to remove all properties."); } return; } /* get rid of trailing spaces */ for (temp=value-1;Cisspace(*temp);temp--) ; *++temp = '\0'; value ++; /* move to next character */ while (*value && Cisspace(*value)) value ++; if (!*value) { pr = lookup_property(thing,name,0); if (pr) { if (propref_get_attr(pr) & perm & PPERM_HOW_C & PPERM_BIT_D) { propref_remove(pr); notify(player,"Property removed."); } else { if (propref_get_attr(pr) & perm & PPERM_HOW_C & PPERM_BIT_X) { notify(player,"Permission denied."); } else { notify(player,"Property removed."); } propref_done(pr); } } else { notify(player,"Property removed."); } } else { pr = create_property_compat(thing,name); if (propref_get_attr(pr) & perm & PPERM_HOW_C & PPERM_BIT_W) { propref_set_type_and_value(pr,PTYPE_STRING,value); notify(player,"Property set."); } else { notify(player,"Permission denied."); } propref_remove_nil_or_done(pr); } free(x); return; } /* move p past NOT_TOKEN if present */ for (p=flag;*p&&((*p==NOT_TOKEN)||Cisspace(*p));p++) ; /* identify flag */ if (*p == '\0') { notify(player,"You must specify a flag or property to set."); return; } f = lookup_flag_by_name(p,thing); if (f == 0) { notify(player,"I don't recognize that flag."); return; } /* check for restricted flag */ if (restricted(player,thing,f)) { notify(player,"Permission denied."); return; } /* check for stupidity */ if ((f & WIZARD) && (*flag == NOT_TOKEN) && (thing == player) && !God(player)) { notify(player,"You cannot remove your own wizbit."); return; } if ((f & ROYALTY) && (*flag == NOT_TOKEN) && (thing == player) && !Wizard(player)) { notify(player,"You cannot remove your own royalty bit."); return; } /* else everything is ok, do the set */ if (*flag == NOT_TOKEN) { /* reset the flag */ FLAGS(thing) &= ~f; DBDIRTY(thing); notify(player,"Flag reset."); } else { /* set the flag */ FLAGS(thing) |= f; DBDIRTY(thing); notify(player,"Flag set."); } } static int filter_unsetall(struct propref *pr, void *permvp) { return( ( propref_get_attr(pr) & (*(PROPATTR *)permvp) ) != *(PROPATTR *)permvp); } void do_unsetall(dbref player, const char *name) { dbref thing; PROPATTR perm; if (!name || !*name) { notify(player,"@unsetall what?"); return; } thing = match_controlled(player,name); if (thing == NOTHING) return; #ifdef TIMESTAMPS DBFETCH(thing)->time_modified = curtm(); #endif perm = prop_who(player,thing) & PPERM_HOW_C & (PPERM_BIT_F|PPERM_BIT_D); plist_filter(&DBFETCH(thing)->properties,filter_unsetall,&perm); DBDIRTY(thing); notify(player,"All properties removed."); } /* * @nset thing=name:operation * operation is (optional abbreviation-expansions in [ ]) * * r[emove] * remove the property * s[tring]= * set the property to have as a string value * d[bref]= * set the property to have as a dbref value * p[ermissions]= * where is a permissions spec, consisting of zero * or more items separated by commas. Each item consists * of a "who" letter, a "how" letter, a "what" letter, and * an operation character. The "who" letter must be one * of OYZA (Owner, roYal, wiZard, Anyone else), the "how" * letter one of CML (Command line, Muf, and Lock test), * the "what" letter one of XRWDFP (eXistence test, Read, * Write, Delete, Find when scanning the list, and change * Permissions), and the operation character one of +- * (add or remove the described permission). * q[uery] * print out verbose information about the property * * When the "string" or "dbref" operation creates a property, its * permissions are set to the default for the property name, such as * would be used by @set. If the property already exists, its * permissions are left unchanged. */ void do_nset(dbref player, const char *name, const char *rest) { dbref thing; struct match_data md; PROPATTR permwho; char *restfree; char *propname; char *opstring; char *eqstring; char *cp; struct propref *pr; if (!name || !rest || !*name || !*rest) { notify(player,"Usage: @nset thing=name:operation"); return; } init_match(player,name,NOTYPE,&md); match_everything(&md); thing = noisy_match_result(&md); if (thing == NOTHING) return; restfree = dup_string(rest); propname = restfree; opstring = index(restfree,PROP_DELIMITER); if ((opstring == 0) || (opstring == propname)) { notify(player,"You must specify a property and operation."); goto donefree; } for (cp=opstring-1;Cisspace(*cp);cp--) ; cp[1] = '\0'; do opstring ++; while (*opstring && Cisspace(*opstring)); eqstring = opstring; while (*eqstring && !Cisspace(*eqstring) && (*eqstring != '=')) eqstring ++; if (*eqstring == '=') { *eqstring++ = '\0'; while (*eqstring && Cisspace(*eqstring)) eqstring ++; } else if (*eqstring) { *eqstring++ = '\0'; while (*eqstring && Cisspace(*eqstring)) eqstring ++; if (*eqstring) { if (*eqstring != '=') { badop:; notify(player,"Invalid operation."); goto donefree; } do eqstring ++; while (*eqstring && Cisspace(*eqstring)); } else { eqstring = 0; } } else { eqstring = 0; } permwho = prop_who(player,thing); switch (opstring[0]) { case 'r': case 'R': if (!string_prefix("remove",opstring)) goto badop; pr = lookup_property(thing,propname,0); if (pr) { PROPATTR perm; perm = propref_get_attr(pr); if (perm & permwho & PPERM_HOW_C & PPERM_BIT_D) { propref_remove(pr); notify(player,"Property removed."); } else { if (perm & permwho & PPERM_HOW_C & PPERM_BIT_X) { notify(player,"Permission denied."); } else { notify(player,"Property removed."); } propref_done(pr); } } break; case 's': case 'S': if (!string_prefix("string",opstring)) goto badop; pr = create_property_compat(thing,propname); if (propref_get_attr(pr) & permwho & PPERM_HOW_C & PPERM_BIT_W) { propref_set_type_and_value(pr,PTYPE_STRING,eqstring); notify(player,"Property set."); } else { notify(player,"Permission denied."); } propref_remove_nil_or_done(pr); break; case 'd': case 'D': { dbref dbr; struct match_data md; if (!string_prefix("dbref",opstring)) goto badop; if (!strcmp(eqstring,"#-1")) { dbr = NOTHING; } else { init_match(player,eqstring,NOTYPE,&md); match_everything(&md); dbr = noisy_match_result(&md); if (dbr == NOTHING) { notify(player,"I don't know what you want in the property."); goto donefree; } if ((dbr < 0) || (dbr >= db_top) || (Typeof(dbr) == TYPE_GARBAGE)) { notify(player,"That's garbage."); goto donefree; } } pr = create_property_compat(thing,propname); if (propref_get_attr(pr) & permwho & PPERM_HOW_C & PPERM_BIT_W) { propref_set_type_and_value(pr,PTYPE_DBREF,dbr); notify(player,"Property set."); } else { notify(player,"Permission denied."); } propref_remove_nil_or_done(pr); } break; case 'p': case 'P': { PROPATTR who; PROPATTR how; PROPATTR what; PROPATTR set; PROPATTR clr; PROPATTR *which; PROPATTR perm; if (!string_prefix("permissions",opstring)) goto badop; set = 0; clr = 0; who = 0; how = 0; what = 0; which = 0; #define DUPCHAR(tag) do { notify(player,"Multiple `"tag"' characters."); goto donefree; } while (0) for (;;eqstring++) { switch (*eqstring) { case 'o': case 'O': if (who) DUPCHAR("who"); who = PPERM_WHO_O; break; case 'y': case 'Y': if (who) DUPCHAR("who"); who = PPERM_WHO_R; break; case 'z': case 'Z': if (who) DUPCHAR("who"); who = PPERM_WHO_W; break; case 'a': case 'A': if (who) DUPCHAR("who"); who = PPERM_WHO_A; break; case 'c': case 'C': if (how) DUPCHAR("how"); how = PPERM_HOW_C; break; case 'm': case 'M': if (how) DUPCHAR("how"); how = PPERM_HOW_M; break; case 'l': case 'L': if (how) DUPCHAR("how"); how = PPERM_HOW_L; break; case 'x': case 'X': if (what)DUPCHAR("what");what= PPERM_BIT_X; break; case 'r': case 'R': if (what)DUPCHAR("what");what= PPERM_BIT_R; break; case 'w': case 'W': if (what)DUPCHAR("what");what= PPERM_BIT_W; break; case 'd': case 'D': if (what)DUPCHAR("what");what= PPERM_BIT_D; break; case 'f': case 'F': if (what)DUPCHAR("what");what= PPERM_BIT_F; break; case 'p': case 'P': if (what)DUPCHAR("what");what= PPERM_BIT_C; break; case '+': if (which) DUPCHAR("operation"); which = &set; break; case '-': if (which) DUPCHAR("operation"); which = &clr; break; case ',': case '\0': if (who && how && what && which) { *which |= who & how & what; if (*eqstring == '\0') goto out; /* break 2 */ who = 0; how = 0; what = 0; which = 0; } else { notify(player,"Incomplete permissions specification"); goto donefree; } break; default: if (! Cisspace(*eqstring)) { notify(player,"Unrecognized permissions character"); goto donefree; } break; } } out:; pr = lookup_property(thing,propname,0); perm = pr ? propref_get_attr(pr) : 0; if (perm & permwho & PPERM_HOW_C & PPERM_BIT_C) { propref_set_perms(pr,(perm&~clr)|set); notify(player,"Permissions changed."); } else if (perm & permwho & PPERM_HOW_C & PPERM_BIT_X) { notify(player,"Permission denied."); } else { notify(player,"Property not found."); } propref_done(pr); } break; case 'q': case 'Q': if (!string_prefix("query",opstring)) goto badop; pr = lookup_property(thing,propname,0); if (pr) { PROPATTR perm; perm = propref_get_attr(pr); if (perm & permwho & PPERM_HOW_C & PPERM_BIT_X) { char *buf; const char *pref; const char *val; char *vfree; static const PROPATTR who[] = { PPERM_WHO_O, PPERM_WHO_R, PPERM_WHO_W, PPERM_WHO_A }; static const PROPATTR how[] = { PPERM_HOW_C, PPERM_HOW_M, PPERM_HOW_L }; static const PROPATTR what[] = { PPERM_BIT_X, PPERM_BIT_R, PPERM_BIT_W, PPERM_BIT_D, PPERM_BIT_F, PPERM_BIT_C }; static const char whatchar[] = "xrwdfc"; int iwho; int ihow; int iwhat; PROPATTR bit; char *bp; bp = propref_get_name(pr); buf = malloc(64+strlen(bp)+1); sprintf(buf,"Dbref #%d, name %s",(int)thing,bp); notify(player,buf); free(buf); if (perm & permwho & PPERM_HOW_C & PPERM_BIT_R) { switch (perm & PATTR_TYPE) { case PTYPE_NIL: pref = "Nil value"; vfree = 0; val = 0; break; case PTYPE_STRING: pref = "String value: "; vfree = propref_get_string(pr); val = vfree; break; case PTYPE_DBREF: pref = "Dbref value: "; vfree = 0; val = unparse_object(player,propref_get_dbref(pr)); break; case PTYPE_ANYVAL: { struct inst i; i = propref_get_anyval(pr); pref = "Anyval value: "; vfree = 0; val = insttotext(&i); } break; default: panic("bad property type bits"); break; } buf = malloc(strlen(pref)+strlen(val)+1); sprintf(buf,"%s%s",pref,val); if (vfree) free(vfree); notify(player,buf); free(buf); } notify(player,"Permissions: /---owner---\\/---royal---\\/---wizard--\\/anyone else\\"); notify(player," ccccccmmmmmmlccccccmmmmmmlccccccmmmmmmlccccccmmmmmml"); buf = malloc(80); bp = buf; strcpy(bp," "); bp += 13; for (iwho=0;iwho<(sizeof(who)/sizeof(who[0]));iwho++) { for (ihow=0;ihow<(sizeof(how)/sizeof(how[0]));ihow++) { for (iwhat=0;iwhat<(sizeof(what)/sizeof(what[0]));iwhat++) { bit = who[iwho] & how[ihow] & what[iwhat]; if (bit) { *bp++ = (perm & bit) ? whatchar[iwhat] : '-'; } } } } *bp = '\0'; notify(player,buf); free(buf); } else { notify(player,"Property not found."); } propref_done(pr); } else { notify(player,"Property not found."); } break; default: goto badop; break; } donefree:; free(restfree); }