/** Populate a ufun_attrib struct from an obj/attr pair. * \verbatim Given an attribute [<object>/]<name> pair (which may include #lambda), * fetch its value, owner (thing), and pe_flags, and store in the struct * pointed to by ufun * \endverbatim * \param attrstring The obj/name of attribute. * \param executor Dbref of the executing object. * \param ufun Pointer to an allocated ufun_attrib struct to fill in. * \param flags A bitwise or of desired UFUN_* flags. * \return 0 on failure, true on success. */ bool fetch_ufun_attrib(const char *attrstring, dbref executor, ufun_attrib * ufun, int flags) { char *thingname, *attrname; char astring[BUFFER_LEN]; ATTR *attrib; if (!ufun) return 0; ufun->contents[0] = '\0'; ufun->errmess = (char *) ""; ufun->thing = executor; ufun->pe_flags = PE_UDEFAULT; ufun->ufun_flags = flags; ufun->thing = executor; thingname = NULL; if (!attrstring) return 0; strncpy(astring, attrstring, BUFFER_LEN); /* Split obj/attr */ if ((flags & UFUN_OBJECT) && ((attrname = strchr(astring, '/')) != NULL)) { thingname = astring; *(attrname++) = '\0'; } else { attrname = astring; } if (thingname && (flags & UFUN_LAMBDA) && (strcasecmp(thingname, "#lambda") == 0 || strncasecmp(thingname, "#apply", 6) == 0)) { /* It's a lambda. */ ufun->ufun_flags &= ~UFUN_NAME; ufun->thing = executor; if (strcasecmp(thingname, "#lambda") == 0) mush_strncpy(ufun->contents, attrname, BUFFER_LEN); else { /* #apply */ char *ucb = ufun->contents; unsigned nargs = 1, n; thingname += 6; if (*thingname) nargs = parse_uinteger(thingname); /* Limit between 1 and 10 arguments (%0-%9) */ if (nargs == 0) nargs = 1; if (nargs > 10) nargs = 10; safe_str(attrname, ufun->contents, &ucb); safe_chr('(', ufun->contents, &ucb); for (n = 0; n < nargs; n++) { if (n > 0) safe_chr(',', ufun->contents, &ucb); safe_format(ufun->contents, &ucb, "%%%u", n); } safe_chr(')', ufun->contents, &ucb); *ucb = '\0'; } ufun->attrname[0] = '\0'; return 1; } if (thingname) { /* Attribute is on something else. */ ufun->thing = noisy_match_result(executor, thingname, NOTYPE, MAT_EVERYTHING); if (!GoodObject(ufun->thing)) { ufun->errmess = (char *) "#-1 INVALID OBJECT"; return 0; } } attrib = (ATTR *) atr_get(ufun->thing, upcasestr(attrname)); if (attrib && AF_Internal(attrib)) { /* Regardless of whether we're doing permission checks, we should * never be showing internal attributes here */ attrib = NULL; } /* An empty attrib is the same as no attrib. */ if (attrib == NULL) { if (flags & UFUN_REQUIRE_ATTR) { if (!(flags & UFUN_IGNORE_PERMS) && !Can_Examine(executor, ufun->thing)) ufun->errmess = e_atrperm; return 0; } else { mush_strncpy(ufun->attrname, attrname, ATTRIBUTE_NAME_LIMIT + 1); return 1; } } if (!(flags & UFUN_IGNORE_PERMS) && !Can_Read_Attr(executor, ufun->thing, attrib)) { ufun->errmess = e_atrperm; return 0; } if (!(flags & UFUN_IGNORE_PERMS) && !CanEvalAttr(executor, ufun->thing, attrib)) { ufun->errmess = e_perm; return 0; } /* DEBUG attributes */ if (AF_NoDebug(attrib)) ufun->pe_flags |= PE_NODEBUG; /* No_Debug overrides Debug */ else if (AF_Debug(attrib)) ufun->pe_flags |= PE_DEBUG; if (flags & UFUN_NAME) { if (attrib->flags & AF_NONAME) ufun->ufun_flags &= ~UFUN_NAME; else if (attrib->flags & AF_NOSPACE) ufun->ufun_flags |= UFUN_NAME_NOSPACE; } /* Populate the ufun object */ mush_strncpy(ufun->contents, atr_value(attrib), BUFFER_LEN); mush_strncpy(ufun->attrname, AL_NAME(attrib), ATTRIBUTE_NAME_LIMIT + 1); /* We're good */ return 1; }
/** User-defined verbs. * \verbatim * This implements the @verb command. * \endverbatim * \param executor the executor. * \param enactor the object causing this command to run. * \param arg1 the object to read verb attributes from. * \param argv the array of remaining arguments to the verb command. * \param queue_entry The queue entry \@verb is running in */ void do_verb(dbref executor, dbref enactor, char *arg1, char **argv, MQUE *queue_entry) { dbref victim; dbref actor; int i; PE_REGS *pe_regs = NULL; /* find the object that we want to read the attributes off * (the object that was the victim of the command) */ /* our victim object can be anything */ victim = match_result(executor, arg1, NOTYPE, MAT_EVERYTHING); if (!GoodObject(victim)) { notify(executor, T("What was the victim of the verb?")); return; } /* find the object that executes the action */ if (!argv || !argv[1] || !*argv[1]) { notify(executor, T("What do you want to do with the verb?")); return; } actor = match_result(executor, argv[1], NOTYPE, MAT_EVERYTHING); if (!GoodObject(actor)) { notify(executor, T("What do you want to do the verb?")); return; } /* Control check is fascist. * First check: we don't want <actor> to do something involuntarily. * Both victim and actor have to be controlled by the thing which did * the @verb (for speed we do a WIZARD check first), or: cause controls * actor plus the second check is passed. * Second check: we need read access to the attributes. * Either the player controls victim or the player * must be priviledged, or the victim has to be VISUAL. */ if (!(Wizard(executor) || (controls(executor, victim) && controls(executor, actor)) || ((controls(enactor, actor) && Can_Examine(executor, victim))))) { notify(executor, T("Permission denied.")); return; } /* We're okay. Send out messages. */ pe_regs = pe_regs_create(PE_REGS_ARG | PE_REGS_Q, "do_verb"); for (i = 0; i < MAX_STACK_ARGS; i++) { if (argv[i + 7]) { pe_regs_setenv_nocopy(pe_regs, i, argv[i + 7]); } } pe_regs_qcopy(pe_regs, queue_entry->pe_info->regvals); real_did_it(actor, victim, upcasestr(argv[2]), argv[3], upcasestr(argv[4]), argv[5], NULL, Location(actor), pe_regs, NA_INTER_HEAR, AN_SYS); /* Now we copy our args into the stack, and do the command. */ if (argv[6] && *argv[6]) queue_attribute_base(victim, upcasestr(argv[6]), actor, 0, pe_regs, (queue_entry->queue_type & QUEUE_EVENT)); pe_regs_free(pe_regs); }