void display_flagtab(dbref player) { UTF8 *buf, *bp; FLAGNAMEENT *fp; bp = buf = alloc_lbuf("display_flagtab"); safe_str(T("Flags:"), buf, &bp); for (fp = gen_flag_names; fp->flagname; fp++) { FLAGBITENT *fbe = fp->fbe; if ( ( (fbe->listperm & CA_WIZARD) && !Wizard(player)) || ( (fbe->listperm & CA_GOD) && !God(player))) { continue; } safe_chr(' ', buf, &bp); safe_str(fp->flagname, buf, &bp); if (fbe->flaglett != ' ') { safe_chr('(', buf, &bp); if (!fp->bPositive) { safe_chr('!', buf, &bp); } safe_chr(fbe->flaglett, buf, &bp); safe_chr(')', buf, &bp); } } *bp = '\0'; notify(player, buf); free_lbuf(buf); }
/** Return a list of all available locks * \param buff the buffer * \param bp a pointer to the current position in the buffer. * \param name if not NULL, only show locks with this prefix */ void list_locks(char *buff, char **bp, const char *name) { lock_list **locks, *lk; bool first = 1; int nlocks = 0, n; locks = mush_calloc(htab_locks.entries, sizeof(lock_list), "lock.list"); for (lk = hash_firstentry(&htab_locks); lk; lk = hash_nextentry(&htab_locks)) { /* Skip those that don't match */ if (name && !string_prefix(lk->type, name)) continue; locks[nlocks++] = lk; } qsort(locks, nlocks, sizeof lk, lock_compare); for (n = 0; n < nlocks; n += 1) { if (first) { first = 0; } else { safe_chr(' ', buff, bp); } safe_str(strupper(locks[n]->type), buff, bp); } mush_free(locks, "lock.list"); }
/** Given a warning bitmask, return a string of warnings on it. * \param warns the warnings. * \return pointer to statically allocated string listing warnings. */ const char * unparse_warnings(warn_type warns) { static char tbuf1[BUFFER_LEN]; char *tp; int listsize, indexx; tp = tbuf1; /* Get the # of elements in checklist */ listsize = sizeof(checklist) / sizeof(tcheck); /* Point c at last non-null in checklist, and go backwards */ for (indexx = listsize - 2; warns && (indexx >= 0); indexx--) { warn_type the_flag = checklist[indexx].flag; if (!(the_flag & ~warns)) { /* Which is to say: * if the bits set on the_flag is a subset of the bits set on warns */ safe_str(checklist[indexx].name, tbuf1, &tp); safe_chr(' ', tbuf1, &tp); /* If we've got a flag which subsumes smaller ones, don't * list the smaller ones */ warns &= ~the_flag; } } *tp = '\0'; return tbuf1; }
/** Return a list of standard attributes. * This functions returns the list of standard attributes, separated by * spaces, in a statically allocated buffer. */ char * list_attribs(void) { ATTR *ap; const char *ptrs[BUFFER_LEN / 2]; static char buff[BUFFER_LEN]; char *bp; const char *name; int nptrs = -1, i; for (ap = ptab_firstentry_new(&ptab_attrib, &name); ap; ap = ptab_nextentry_new(&ptab_attrib, &name)) { if (strcmp(name, AL_NAME(ap))) continue; ptrs[++nptrs] = AL_NAME(ap); } bp = buff; if (nptrs >= 0) safe_str(ptrs[0], buff, &bp); for (i = 1; i < nptrs; i++) { safe_chr(' ', buff, &bp); safe_str(ptrs[i], buff, &bp); } *bp = '\0'; return buff; }
dbref absolute_nref(char *str) { char *p, *q, *buf, *bp; dbref *np, nref; /* * Global or local reference? Global references are automatically * * prepended with an additional underscore. i.e., #__foo_ is a global * * reference, and #_foo_ is a local reference. * * Our beginning and end underscores have already been stripped, so * * we would see only _foo or foo. * * * * We are not allowed to nibble our buffer, because we've got a * * pointer into the match string. Therefore we must copy it. * * If we're matching locally we copy the dbref of the owner first, * * which means that we then need to worry about buffer size. */ buf = alloc_lbuf("absolute_nref"); if (*str == '_') { for (p = buf, q = str; *q; p++, q++) { *p = tolower(*q); } *p = '\0'; } else { bp = buf; safe_ltos(buf, &bp, Owner(md.player), LBUF_SIZE); safe_chr('.', buf, &bp); for (q = str; *q; q++) { safe_chr(tolower(*q), buf, &bp); } *bp = '\0'; } np = (int *) hashfind(buf, &mudstate.nref_htab); if (np && Good_obj(*np)) { nref = *np; } else { nref = NOTHING; } free_lbuf(buf); return nref; }
// Transform CRLF runs to a space. // UTF8 *ConvertCRLFtoSpace(const UTF8 *pString) { static UTF8 buf[LBUF_SIZE]; UTF8 *bp = buf; // Skip any leading CRLF as well as non-ASCII. // while ( '\r' == *pString || '\n' == *pString || (0x80 & *pString) == 0x80) { pString++; } bool bFirst = true; while (*pString) { if (!bFirst) { safe_chr(' ', buf, &bp); } else { bFirst = false; } while ( *pString && '\r' != *pString && '\n' != *pString && (0x80 & *pString) == 0x00) { safe_chr(*pString, buf, &bp); pString++; } // Skip any CRLF. // while ( '\r' == *pString || '\n' == *pString || 0x80 == (0x80 & *pString)) { pString++; } } *bp = '\0'; return buf; }
/* Show the 'Obvious Exits' list for a room. Used in 'look' and 'examine'. * \param player The player looking * \param loc room whose exits we're showing * \param exit_name "Obvious Exits" string * \param pe_info the pe_info to use for evaluating EXITFORMAT and interact locks */ static void look_exits(dbref player, dbref loc, const char *exit_name, NEW_PE_INFO *pe_info) { dbref thing; char *tbuf1, *tbuf2, *nbuf; char *s1, *s2; char *p; int exit_count, this_exit, total_count; int texits; ufun_attrib ufun; PUEBLOBUFF; /* make sure location is a room */ if (!IsRoom(loc)) return; tbuf1 = (char *) mush_malloc(BUFFER_LEN, "string"); tbuf2 = (char *) mush_malloc(BUFFER_LEN, "string"); nbuf = (char *) mush_malloc(BUFFER_LEN, "string"); if (!tbuf1 || !tbuf2 || !nbuf) mush_panic("Unable to allocate memory in look_exits"); s1 = tbuf1; s2 = tbuf2; texits = exit_count = total_count = 0; this_exit = 1; if (fetch_ufun_attrib ("EXITFORMAT", loc, &ufun, UFUN_IGNORE_PERMS | UFUN_REQUIRE_ATTR)) { char *arg, *buff, *bp; PE_REGS *pe_regs = pe_regs_create(PE_REGS_ARG, "look_exits"); arg = (char *) mush_malloc(BUFFER_LEN, "string"); buff = (char *) mush_malloc(BUFFER_LEN, "string"); if (!arg || !buff) mush_panic("Unable to allocate memory in look_exits"); bp = arg; DOLIST(thing, Exits(loc)) { if (((Light(loc) || Light(thing)) || !(Dark(loc) || Dark(thing))) && can_interact(thing, player, INTERACT_SEE, pe_info)) { if (bp != arg) safe_chr(' ', arg, &bp); safe_dbref(thing, arg, &bp); } } *bp = '\0'; pe_regs_setenv_nocopy(pe_regs, 0, arg); call_ufun(&ufun, buff, player, player, pe_info, pe_regs); pe_regs_free(pe_regs); notify_by(loc, player, buff); mush_free(tbuf1, "string"); mush_free(tbuf2, "string"); mush_free(nbuf, "string"); mush_free(arg, "string"); mush_free(buff, "string"); return; }
void list_lock_flags(char *buff, char **bp) { int i; for (i = 0; lock_privs[i].name; i++) { if (lock_privs[i].letter) safe_chr(lock_privs[i].letter, buff, bp); } }
static UTF8 *munge_space_for_match(const UTF8 *name, size_t n) { static UTF8 buffer[LBUF_SIZE]; size_t i = 0; UTF8 *q = buffer; if (NULL != name) { // Remove Initial spaces. // while (mux_isspace(name[i])) { i++; } while (i < n) { while ( i < n && !mux_isspace(name[i])) { safe_chr(name[i], buffer, &q); i++; } while (mux_isspace(name[i])) { i++; } if (i < n) { safe_chr(' ', buffer, &q); } } } // Remove terminal spaces and terminate string. // *q = '\0'; return buffer; }
/** Display an access rule. * \param ap pointer to access rule. * \param rulenum access rule's number in the list. * \param who unused. * \param buff buffer to store output. * \param bp pointer into buff. * This function provides an appealing display of an access rule * in the list. */ void format_access(struct access *ap, int rulenum, dbref who __attribute__ ((__unused__)), char *buff, char **bp) { if (ap) { safe_format(buff, bp, T("Matched line %d: %s %s"), rulenum, ap->host, (ap->can & ACS_REGEXP) ? "(regexp)" : ""); safe_chr('\n', buff, bp); safe_format(buff, bp, T("Comment: %s"), ap->comment); safe_chr('\n', buff, bp); safe_str(T("Connections allowed by: "), buff, bp); if (ap->cant & ACS_CONNECT) safe_str(T("No one"), buff, bp); else if (ap->cant & ACS_ADMIN) safe_str(T("All but admin"), buff, bp); else if (ap->cant & ACS_WIZARD) safe_str(T("All but wizards"), buff, bp); else if (ap->cant & ACS_GOD) safe_str(T("All but God"), buff, bp); else safe_str(T("All"), buff, bp); safe_chr('\n', buff, bp); if (ap->cant & ACS_GUEST) safe_str(T("Guest connections are NOT allowed"), buff, bp); else safe_str(T("Guest connections are allowed"), buff, bp); safe_chr('\n', buff, bp); if (ap->cant & ACS_CREATE) safe_str(T("Creation is NOT allowed"), buff, bp); else safe_str(T("Creation is allowed"), buff, bp); safe_chr('\n', buff, bp); if (ap->can & ACS_REGISTER) safe_str(T("Email registration is allowed"), buff, bp); if (ap->can & ACS_SUSPECT) safe_str(T("Players connecting are set SUSPECT"), buff, bp); if (ap->can & ACS_DENY_SILENT) safe_str(T("Denied connections are not logged"), buff, bp); } else { safe_str(T("No matching access rule"), buff, bp); } }
/** Display the access list. * \param player enactor. * Sends the complete access list to the player. */ void do_list_access(dbref player) { struct access *ap; acsflag *c; char flaglist[BUFFER_LEN]; int rulenum = 0; char *bp; for (ap = access_top; ap; ap = ap->next) { rulenum++; if (ap->can != ACS_SITELOCK) { bp = flaglist; for (c = acslist; c->name; c++) { if (c->flag == ACS_DEFAULT) continue; if (ap->can & c->flag) { safe_chr(' ', flaglist, &bp); safe_str(c->name, flaglist, &bp); } if (c->toggle && (ap->cant & c->flag)) { safe_chr(' ', flaglist, &bp); safe_chr('!', flaglist, &bp); safe_str(c->name, flaglist, &bp); } } *bp = '\0'; notify_format(player, T("%3d SITE: %-20s DBREF: %-6s FLAGS:%s"), rulenum, ap->host, unparse_dbref(ap->who), flaglist); notify_format(player, T(" COMMENT: %s"), ap->comment ? ap->comment : ""); } else { notify(player, T ("---- @sitelock will add sites immediately below this line ----")); } } if (rulenum == 0) { notify(player, T("There are no access rules.")); } }
static void ShowPsLine(BQUE *tmp) { char *bufp = unparse_object(Show_Player, tmp->executor, false); if (tmp->IsTimed && (Good_obj(tmp->sem))) { CLinearTimeDelta ltd = tmp->waittime - Show_lsaNow; notify(Show_Player, tprintf("[#%d/%d]%s:%s", tmp->sem, ltd.ReturnSeconds(), bufp, tmp->comm)); } else if (tmp->IsTimed) { CLinearTimeDelta ltd = tmp->waittime - Show_lsaNow; notify(Show_Player, tprintf("[%d]%s:%s", ltd.ReturnSeconds(), bufp, tmp->comm)); } else if (Good_obj(tmp->sem)) { notify(Show_Player, tprintf("[#%d]%s:%s", tmp->sem, bufp, tmp->comm)); } else { notify(Show_Player, tprintf("%s:%s", bufp, tmp->comm)); } char *bp = bufp; if (Show_Key == PS_LONG) { for (int i = 0; i < tmp->nargs; i++) { if (tmp->env[i] != NULL) { safe_str("; Arg", bufp, &bp); safe_chr((char)(i + '0'), bufp, &bp); safe_str("='", bufp, &bp); safe_str(tmp->env[i], bufp, &bp); safe_chr('\'', bufp, &bp); } } *bp = '\0'; bp = unparse_object(Show_Player, tmp->enactor, false); notify(Show_Player, tprintf(" Enactor: %s%s", bp, bufp)); free_lbuf(bp); } free_lbuf(bufp); }
void list_lock_flags_long(char *buff, char **bp) { int i; int first = 1; for (i = 0; lock_privs[i].name; i++) { if (!first) safe_chr(' ', buff, bp); first = 0; safe_str(lock_privs[i].name, buff, bp); } }
static void ReportMatchedTopics(dbref executor, const UTF8 *topic, CHashTable *htab) { bool matched = false; UTF8 *topic_list = NULL; UTF8 *buffp = NULL; struct help_entry *htab_entry; for (htab_entry = (struct help_entry *)hash_firstentry(htab); htab_entry != NULL; htab_entry = (struct help_entry *)hash_nextentry(htab)) { mudstate.wild_invk_ctr = 0; if ( htab_entry->key && quick_wild(topic, htab_entry->key)) { if (!matched) { matched = true; topic_list = alloc_lbuf("help_write"); buffp = topic_list; } safe_str(htab_entry->key, topic_list, &buffp); safe_chr(' ', topic_list, &buffp); safe_chr(' ', topic_list, &buffp); } } if (!matched) { notify(executor, tprintf(T("No entry for \xE2\x80\x98%s\xE2\x80\x99."), topic)); } else { notify(executor, tprintf(T("Here are the entries which match \xE2\x80\x98%s\xE2\x80\x99:"), topic)); *buffp = '\0'; notify(executor, topic_list); free_lbuf(topic_list); } }
void display_flagtab( dbref player ) { char *buf, *bp; FLAGENT *fp; bp = buf = alloc_lbuf( "display_flagtab" ); safe_str( ( char * ) "Flags:", buf, &bp ); for( fp = gen_flags; fp->flagname; fp++ ) { if( ( fp->listperm & CA_WIZARD ) && !Wizard( player ) ) { continue; } if( ( fp->listperm & CA_GOD ) && !God( player ) ) { continue; } safe_chr( ' ', buf, &bp ); safe_str( ( char * ) fp->flagname, buf, &bp ); safe_chr( '(', buf, &bp ); safe_chr( fp->flaglett, buf, &bp ); safe_chr( ')', buf, &bp ); } *bp = '\0'; notify( player, buf ); free_lbuf( buf ); }
static void grep_add_attr(char *buff, char **bp, dbref player, int count, ATTR *attr, char *atrval) { if (buff) { if (count) safe_chr(' ', buff, bp); safe_str(AL_NAME(attr), buff, bp); } else { notify_format(player, "%s%s [#%d%s]:%s %s", ANSI_HILITE, AL_NAME(attr), Owner(AL_CREATOR(attr)), privs_to_letters(attr_privs_view, AL_FLAGS(attr)), ANSI_END, atrval); } }
/* Called when you issue localfunc() with the name of the function and args * */ void local_function(char *funcname, char *buff, char **bufcx, dbref player, dbref cause, char *fargs[], int nfargs, char *cargs[], int ncargs) { if ( !funcname || !*funcname ) { safe_str("#-1 NO FUNCTION", buff, bufcx); return; } if ( stricmp(funcname, "test") == 0 ) { safe_str("This was a test. Function: '", buff, bufcx); safe_str(funcname, buff, bufcx); safe_str("' First Arg: '", buff, bufcx); safe_str(fargs[0], buff, bufcx); safe_chr('\'', buff, bufcx); } else { safe_str("#-1 NO FUNCTION", buff, bufcx); } }
static void do_whichof(char *args[], int nargs, enum whichof_t flag, char *buff, char **bp, dbref executor, dbref caller, dbref enactor, PE_Info *pe_info, int isbool) { int j; char tbuf[BUFFER_LEN], *tp; char const *sp; char sep = ' '; int first = 1; tbuf[0] = '\0'; if (flag == DO_ALLOF) { /* The last arg is a delimiter. Parse it in place. */ char insep[BUFFER_LEN]; char *isep = insep; const char *arglast = args[nargs - 1]; process_expression(insep, &isep, &arglast, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info); *isep = '\0'; strcpy(args[nargs - 1], insep); if (!delim_check(buff, bp, nargs, args, nargs, &sep)) return; nargs--; } for (j = 0; j < nargs; j++) { tp = tbuf; sp = args[j]; process_expression(tbuf, &tp, &sp, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info); *tp = '\0'; if ((isbool && parse_boolean(tbuf)) || (!isbool && strlen(tbuf))) { if (!first) { safe_chr(sep, buff, bp); } else first = 0; safe_str(tbuf, buff, bp); if (flag == DO_FIRSTOF) return; } } if (flag == DO_FIRSTOF) safe_str(tbuf, buff, bp); }
/** Return a list of all available locks * \param buff the buffer * \param bp a pointer to the current position in the buffer */ void list_locks(char *buff, char **bp, const char *name) { char rbuff[BUFFER_LEN]; char *rp; int first = 1; const lock_list *ptr; rp = rbuff; for (ptr = lock_types; ptr->type != NULL; ptr++) { /* Skip those that don't match */ if (name && !string_prefix(ptr->type, name)) continue; if (first) { first = 0; } else { safe_chr(' ', rbuff, &rp); } safe_str(ptr->type, rbuff, &rp); } *rp = '\0'; /* We strupper it for consistency with the other * @list/foo and list(foo)s. */ safe_str(strupper(rbuff), buff, bp); }
/** Return a list of standard attributes. * This functions returns the list of standard attributes, separated by * spaces, in a statically allocated buffer. */ char * list_attribs(void) { ATTR *ap; const char *ptrs[BUFFER_LEN / 2]; static char buff[BUFFER_LEN]; char *bp; int nptrs = 0, i; ap = (ATTR *) ptab_firstentry(&ptab_attrib); ptrs[0] = ""; while (ap) { ptrs[nptrs++] = AL_NAME(ap); ap = (ATTR *) ptab_nextentry(&ptab_attrib); } bp = buff; safe_str(ptrs[0], buff, &bp); for (i = 1; i < nptrs; i++) { safe_chr(' ', buff, &bp); safe_str(ptrs[i], buff, &bp); } *bp = '\0'; return buff; }
void display_powertab(dbref player) { char *buf, *bp; POWERENT *fp; bp = buf = alloc_lbuf("display_powertab"); safe_str((char *) "Powers:", buf, &bp); for (fp = gen_powers; fp->powername; fp++) { if ((fp->listperm & CA_WIZARD) && !Wizard(player)) { continue; } if ((fp->listperm & CA_GOD) && !God(player)) { continue; } safe_chr(' ', buf, &bp); safe_str((char *) fp->powername, buf, &bp); } *bp = '\0'; notify(player, buf); free_lbuf(buf); }
static void give_thing (dbref giver, dbref recipient, int key, char *what) { dbref thing, loc; char *str, *sp; init_match(giver, what, TYPE_THING); match_possession(); match_me(); thing = match_result(); switch (thing) { case NOTHING: notify(giver, "You don't have that!"); return; case AMBIGUOUS: notify(giver, "I don't know which you mean!"); return; } if (thing == giver) { notify(giver, "You can't give yourself away!"); return; } if (((Typeof(thing) != TYPE_THING) && (Typeof(thing) != TYPE_PLAYER)) || !(Enter_ok(recipient) || controls(giver, recipient))) { notify(giver, "Permission denied."); return; } if ((Flags3(thing) & NOMOVE) && !Wizard(giver)) { notify(giver, "Permission denied."); return; } if (!could_doit(giver, thing, A_LGIVE,1)) { sp = str = alloc_lbuf("do_give.gfail"); safe_str((char *)"You can't give ", str, &sp); safe_str(Name(thing), str, &sp); safe_str((char *)" away.", str, &sp); *sp = '\0'; did_it(giver, thing, A_GFAIL, str, A_OGFAIL, NULL, A_AGFAIL, (char **)NULL, 0); free_lbuf(str); return; } if (!could_doit(thing, recipient, A_LRECEIVE,1)) { sp = str = alloc_lbuf("do_give.rfail"); safe_str(Name(recipient), str, &sp); safe_str((char *)" doesn't want ", str, &sp); safe_str(Name(thing), str, &sp); safe_chr('.', str, &sp); *sp = '\0'; did_it(giver, recipient, A_RFAIL, str, A_ORFAIL, NULL, A_ARFAIL, (char **)NULL, 0); free_lbuf(str); return; } loc = Location(giver); if ( !Good_obj(loc) || loc == NOTHING || loc == AMBIGUOUS || Recover(loc) || Going(loc) ) loc = giver; if (!could_doit(giver, loc, A_LGIVETO, 1)) { sp = str = alloc_lbuf("do_giveto.rfail"); safe_str((char *)"You can not give ", str, &sp); safe_str(Name(thing), str, &sp); safe_str((char *)" away at this location.", str, &sp); *sp = '\0'; notify(giver, str); free_lbuf(str); return; } move_via_generic(thing, recipient, giver, 0); divest_object(thing); if (!(key & GIVE_QUIET)) { str = alloc_lbuf("do_give.thing.ok"); strcpy(str, Name(giver)); notify_with_cause(recipient, giver, unsafe_tprintf("%s gave you %s.", str, Name(thing))); notify(giver, "Given."); notify_with_cause(thing, giver, unsafe_tprintf("%s gave you to %s.", str, Name(recipient))); free_lbuf(str); } else { notify(giver, "Given. (quiet)"); } did_it(giver, thing, A_DROP, NULL, A_ODROP, NULL, A_ADROP, (char **)NULL, 0); did_it(recipient, thing, A_SUCC, NULL, A_OSUCC, NULL, A_ASUCC, (char **)NULL, 0); }
static void unparse_boolexp1( dbref player, BOOLEXP *b, char outer_type, int format ) { ATTR *ap; char sep_ch; char *buff; if( b == TRUE_BOOLEXP ) { if( format == F_EXAMINE ) { safe_str( ( char * ) "*UNLOCKED*", boolexp_buf, &buftop ); } return; } switch( b->type ) { case BOOLEXP_AND: if( outer_type == BOOLEXP_NOT ) { safe_chr( '(', boolexp_buf, &buftop ); } unparse_boolexp1( player, b->sub1, b->type, format ); safe_chr( AND_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub2, b->type, format ); if( outer_type == BOOLEXP_NOT ) { safe_chr( ')', boolexp_buf, &buftop ); } break; case BOOLEXP_OR: if( outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND ) { safe_chr( '(', boolexp_buf, &buftop ); } unparse_boolexp1( player, b->sub1, b->type, format ); safe_chr( OR_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub2, b->type, format ); if( outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND ) { safe_chr( ')', boolexp_buf, &buftop ); } break; case BOOLEXP_NOT: safe_chr( '!', boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_INDIR: safe_chr( INDIR_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_IS: safe_chr( IS_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_CARRY: safe_chr( CARRY_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_OWNER: safe_chr( OWNER_TOKEN, boolexp_buf, &buftop ); unparse_boolexp1( player, b->sub1, b->type, format ); break; case BOOLEXP_CONST: if( !mudstate.standalone ) { switch( format ) { case F_QUIET: /* * Quiet output - for dumps and internal use. * Always #Num */ safe_str( ( char * ) unparse_object_quiet( player, b->thing ), boolexp_buf, &buftop ); break; case F_EXAMINE: /* * Examine output - informative. * * Name(#Num) or Name */ buff = unparse_object( player, b->thing, 0 ); safe_str( buff, boolexp_buf, &buftop ); free_lbuf( buff ); break; case F_DECOMPILE: /* * Decompile output - should be usable on * other MUSHes. *Name if player, Name if * thing, else #Num */ switch( Typeof( b->thing ) ) { case TYPE_PLAYER: safe_chr( '*', boolexp_buf, &buftop ); case TYPE_THING: safe_name( b->thing, boolexp_buf, &buftop ); break; default: safe_dbref( boolexp_buf, &buftop, b->thing ); break; } break; case F_FUNCTION: /* * Function output - must be usable by @lock * cmd. *Name if player, else #Num */ switch( Typeof( b->thing ) ) { case TYPE_PLAYER: safe_chr( '*', boolexp_buf, &buftop ); safe_name( b->thing, boolexp_buf, &buftop ); break; default: safe_dbref( boolexp_buf, &buftop, b->thing ); break; } } } else { safe_str( ( char * ) unparse_object_quiet( player, b->thing ), boolexp_buf, &buftop ); } break; case BOOLEXP_ATR: case BOOLEXP_EVAL: if( b->type == BOOLEXP_EVAL ) { sep_ch = '/'; } else { sep_ch = ':'; } ap = atr_num( b->thing ); if( ap && ap->number ) { safe_str( ( char * ) ap->name, boolexp_buf, &buftop ); } else { safe_ltos( boolexp_buf, &buftop, b->thing ); } safe_chr( sep_ch, boolexp_buf, &buftop ); safe_str( ( char * ) b->sub1, boolexp_buf, &buftop ); break; default: log_write_raw( 1, "ABORT! unparse.c, bad boolexp type in unparse_boolexp1().\n" ); abort(); break; } }
/** 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; }
/** Given a ufun, executor, enactor, PE_Info, and arguments for %0-%9, * call the ufun with appropriate permissions on values given for * wenv_args. The value returned is stored in the buffer pointed to * by ret, if given. * \param ufun The ufun_attrib that was initialized by fetch_ufun_attrib * \param ret If desired, a pointer to a buffer in which the results * of the process_expression are stored in. * \param caller The caller (%@). * \param enactor The enactor. (%#) * \param pe_info The pe_info passed to the FUNCTION * \param user_regs Other arguments that may want to be added. This nests BELOW * the pe_regs created by call_ufun. (It is checked first) * \param data a void pointer to extra data. Currently only used to pass the * name to use, when UFUN_NAME is given. * \retval 0 success * \retval 1 process_expression failed. (CPU time limit) */ bool call_ufun_int(ufun_attrib * ufun, char *ret, dbref caller, dbref enactor, NEW_PE_INFO *pe_info, PE_REGS *user_regs, void *data) { char rbuff[BUFFER_LEN]; char *rp, *np = NULL; int pe_ret; char const *ap; char old_attr[BUFFER_LEN]; int made_pe_info = 0; PE_REGS *pe_regs; PE_REGS *pe_regs_old; int pe_reg_flags = 0; /* Make sure we have a ufun first */ if (!ufun) return 1; if (!pe_info) { pe_info = make_pe_info("pe_info.call_ufun"); made_pe_info = 1; } else { strcpy(old_attr, pe_info->attrname); } pe_regs_old = pe_info->regvals; if (ufun->ufun_flags & UFUN_LOCALIZE) pe_reg_flags |= PE_REGS_Q; else { pe_reg_flags |= PE_REGS_NEWATTR; if (ufun->ufun_flags & UFUN_SHARE_STACK) pe_reg_flags |= PE_REGS_ARGPASS; } pe_regs = pe_regs_localize(pe_info, pe_reg_flags, "call_ufun"); rp = pe_info->attrname; if (*ufun->attrname == '\0') { safe_str("#LAMBDA", pe_info->attrname, &rp); safe_chr('/', pe_info->attrname, &rp); safe_str(ufun->contents, pe_info->attrname, &rp); } else { safe_dbref(ufun->thing, pe_info->attrname, &rp); safe_chr('/', pe_info->attrname, &rp); safe_str(ufun->attrname, pe_info->attrname, &rp); } *rp = '\0'; /* If the user doesn't care about the return of the expression, * then use our own rbuff. */ if (!ret) ret = rbuff; rp = ret; /* Anything the caller wants available goes on the bottom of the stack */ if (user_regs) { user_regs->prev = pe_info->regvals; pe_info->regvals = user_regs; } if (ufun->ufun_flags & UFUN_NAME) { char *name = (char *) data; if (!name || !*name) name = (char *) Name(enactor); safe_str(name, ret, &rp); if (!(ufun->ufun_flags & UFUN_NAME_NOSPACE)) safe_chr(' ', ret, &rp); np = rp; } /* And now, make the call! =) */ ap = ufun->contents; pe_ret = process_expression(ret, &rp, &ap, ufun->thing, caller, enactor, ufun->pe_flags, PT_DEFAULT, pe_info); *rp = '\0'; if ((ufun->ufun_flags & UFUN_NAME) && np == rp) { /* Attr was empty, so we take off the name again */ *ret = '\0'; } /* Restore call_ufun's pe_regs */ if (user_regs) { pe_info->regvals = user_regs->prev; } /* Restore the pe_regs stack. */ pe_regs_restore(pe_info, pe_regs); pe_regs_free(pe_regs); pe_info->regvals = pe_regs_old; if (!made_pe_info) { /* Restore the old attrname. */ strcpy(pe_info->attrname, old_attr); } else { free_pe_info(pe_info); } return pe_ret; }
/* * --------------------------------------------------------------------------- * * Return an lbuf pointing to the object name and possibly the db# and flags */ UTF8 *unparse_object(dbref player, dbref target, bool obey_myopic, bool bAddColor) { UTF8 *buf = alloc_lbuf("unparse_object"); if (NOPERM <= target && target < 0) { mux_strncpy(buf, aszSpecialDBRefNames[-target], LBUF_SIZE-1); } else if (!Good_obj(target)) { mux_sprintf(buf, LBUF_SIZE, T("*ILLEGAL*(#%d)"), target); } else { bool exam; if (obey_myopic) { exam = MyopicExam(player, target); } else { exam = Examinable(player, target); } // Leave and extra 100 bytes for the dbref and flags at the end and // color at the beginning if necessary.. // mux_field fldName = StripTabsAndTruncate( Moniker(target), buf, LBUF_SIZE-100, LBUF_SIZE-100); UTF8 *bp = buf + fldName.m_byte; #if defined(FIRANMUX) if ( fldName.m_column == fldName.m_byte && bAddColor) { // There is no color in the name, so look for @color, or highlight. // UTF8 *buf2 = alloc_lbuf("unparse_object.color"); UTF8 *bp2 = buf2; UTF8 *pLetters = AcquireColorLetters(player, target); if (NULL != pLetters) { safe_str(LettersToBinary(pLetters), buf2, &bp2); free_lbuf(pLetters); pLetters = NULL; } else { safe_str((UTF8 *)COLOR_INTENSE, buf2, &bp2); } *bp = '\0'; safe_str(buf, buf2, &bp2); safe_str((UTF8 *)COLOR_RESET, buf2, &bp2); // Swap buffers. // free_lbuf(buf); buf = buf2; bp = bp2; } #else UNUSED_PARAMETER(bAddColor); #endif // FIRANMUX if ( exam || (Flags(target) & (CHOWN_OK | JUMP_OK | LINK_OK | DESTROY_OK)) || (Flags2(target) & ABODE)) { // Show everything. // UTF8 *fp = decode_flags(player, &(db[target].fs)); safe_str(T("(#"), buf, &bp); safe_ltoa(target, buf, &bp); safe_str(fp, buf, &bp); safe_chr(')', buf, &bp); free_sbuf(fp); } *bp = '\0'; } return buf; }
void exec(char *buff, char **bufc, int tflags, dbref player, dbref cause, int eval, char **dstr, char *cargs[], int ncargs) { #define NFARGS 30 char *fargs[NFARGS]; char *preserve[MAX_GLOBAL_REGS]; char *tstr, *tbuf, *tbufc, *savepos, *atr_gotten, *start, *oldp, *savestr; char savec, ch, *str; char *realbuff = NULL, *realbp = NULL; dbref aowner; int at_space, nfargs, gender, i, j, alldone, feval; long aflags; int is_trace, is_top, save_count; int ansi; FUN *fp; UFUN *ufp; static const char *subj[5] = { "", "it", "she", "he", "they" }; static const char *poss[5] = { "", "its", "her", "his", "their" }; static const char *obj[5] = { "", "it", "her", "him", "them" }; static const char *absp[5] = { "", "its", "hers", "his", "theirs" }; if(*dstr == NULL) return; // dprintk("%d/%s", player, *dstr); at_space = 1; gender = -1; alldone = 0; ansi = 0; is_trace = Trace(player) && !(eval & EV_NOTRACE); is_top = 0; /* Extend the buffer if we need to. */ if(((*bufc) - buff) > (LBUF_SIZE - SBUF_SIZE)) { realbuff = buff; realbp = *bufc; buff = (char *) malloc(LBUF_SIZE); *bufc = buff; } oldp = start = *bufc; /* * If we are tracing, save a copy of the starting buffer */ savestr = NULL; if(is_trace) { is_top = tcache_empty(); savestr = alloc_lbuf("exec.save"); StringCopy(savestr, *dstr); } while (**dstr && !alldone) { switch (**dstr) { case ' ': /* * A space. Add a space if not compressing or if * * * * * * * previous char was not a space */ if(!(mudconf.space_compress && at_space) || (eval & EV_NO_COMPRESS)) { safe_chr(' ', buff, bufc); at_space = 1; } break; case '\\': /* * General escape. Add the following char without * * * * * special processing */ at_space = 0; (*dstr)++; if(**dstr) safe_chr(**dstr, buff, bufc); else (*dstr)--; break; case '[': /* * Function start. Evaluate the contents of the * * * * * square brackets as a function. If no closing * * * * * bracket, insert the [ and continue. */ at_space = 0; tstr = (*dstr)++; if(eval & EV_NOFCHECK) { safe_chr('[', buff, bufc); *dstr = tstr; break; } tbuf = parse_to(dstr, ']', 0); if(*dstr == NULL) { safe_chr('[', buff, bufc); *dstr = tstr; } else { str = tbuf; exec(buff, bufc, 0, player, cause, (eval | EV_FCHECK | EV_FMAND), &str, cargs, ncargs); (*dstr)--; } break; case '{': /* * Literal start. Insert everything up to the * * * * * terminating } without parsing. If no closing * * * * * brace, insert the { and continue. */ at_space = 0; tstr = (*dstr)++; tbuf = parse_to(dstr, '}', 0); if(*dstr == NULL) { safe_chr('{', buff, bufc); *dstr = tstr; } else { if(!(eval & EV_STRIP)) { safe_chr('{', buff, bufc); } /* * Preserve leading spaces (Felan) */ if(*tbuf == ' ') { safe_chr(' ', buff, bufc); tbuf++; } str = tbuf; exec(buff, bufc, 0, player, cause, (eval & ~(EV_STRIP | EV_FCHECK)), &str, cargs, ncargs); if(!(eval & EV_STRIP)) { safe_chr('}', buff, bufc); } (*dstr)--; } break; case '%': /* * Percent-replace start. Evaluate the chars * * * * following * and perform the appropriate * * * * substitution. */ at_space = 0; (*dstr)++; savec = **dstr; savepos = *bufc; switch (savec) { case '\0': /* * Null - all done */ (*dstr)--; break; case '|': /* piped command output */ safe_str(mudstate.pout, buff, bufc); break; case '%': /* * Percent - a literal % */ safe_chr('%', buff, bufc); break; case 'c': case 'C': (*dstr)++; if(!**dstr) (*dstr)--; ansi = 1; switch (**dstr) { case 'h': /* * hilite */ safe_str(ANSI_HILITE, buff, bufc); break; case 'i': /* * inverse */ safe_str(ANSI_INVERSE, buff, bufc); break; case 'f': /* * flash */ safe_str(ANSI_BLINK, buff, bufc); break; case 'u': /* underline */ safe_str(ANSI_UNDER, buff, bufc); break; case 'n': /* * normal */ safe_str(ANSI_NORMAL, buff, bufc); ansi = 0; break; case 'x': /* * black fg */ safe_str(ANSI_BLACK, buff, bufc); break; case 'r': /* * red fg */ safe_str(ANSI_RED, buff, bufc); break; case 'g': /* * green fg */ safe_str(ANSI_GREEN, buff, bufc); break; case 'y': /* * yellow fg */ safe_str(ANSI_YELLOW, buff, bufc); break; case 'b': /* * blue fg */ safe_str(ANSI_BLUE, buff, bufc); break; case 'm': /* * magenta fg */ safe_str(ANSI_MAGENTA, buff, bufc); break; case 'c': /* * cyan fg */ safe_str(ANSI_CYAN, buff, bufc); break; case 'w': /* * white fg */ safe_str(ANSI_WHITE, buff, bufc); break; case 'X': /* * black bg */ safe_str(ANSI_BBLACK, buff, bufc); break; case 'R': /* * red bg */ safe_str(ANSI_BRED, buff, bufc); break; case 'G': /* * green bg */ safe_str(ANSI_BGREEN, buff, bufc); break; case 'Y': /* * yellow bg */ safe_str(ANSI_BYELLOW, buff, bufc); break; case 'B': /* * blue bg */ safe_str(ANSI_BBLUE, buff, bufc); break; case 'M': /* * magenta bg */ safe_str(ANSI_BMAGENTA, buff, bufc); break; case 'C': /* * cyan bg */ safe_str(ANSI_BCYAN, buff, bufc); break; case 'W': /* * white bg */ safe_str(ANSI_BWHITE, buff, bufc); break; default: safe_chr(**dstr, buff, bufc); } break; case 'r': /* * Carriage return */ case 'R': safe_str((char *) "\r\n", buff, bufc); break; case 't': /* * Tab */ case 'T': safe_chr('\t', buff, bufc); break; case 'B': /* * Blank */ case 'b': safe_chr(' ', buff, bufc); break; case '0': /* * Command argument number N */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i = (**dstr - '0'); if((i < ncargs) && (cargs[i] != NULL)) safe_str(cargs[i], buff, bufc); break; case 'V': /* * Variable attribute */ case 'v': (*dstr)++; ch = ToUpper(**dstr); if(!**dstr) (*dstr)--; if((ch < 'A') || (ch > 'Z')) break; i = 100 + ch - 'A'; atr_gotten = atr_pget(player, i, &aowner, &aflags); safe_str(atr_gotten, buff, bufc); free_lbuf(atr_gotten); break; case 'Q': case 'q': (*dstr)++; i = (**dstr - '0'); if((i >= 0) && (i <= 9) && mudstate.global_regs[i]) { safe_str(mudstate.global_regs[i], buff, bufc); } if(!**dstr) (*dstr)--; break; case 'O': /* * Objective pronoun */ case 'o': if(gender < 0) gender = get_gender(cause); if(!gender) tbuf = Name(cause); else tbuf = (char *) obj[gender]; safe_str(tbuf, buff, bufc); break; case 'P': /* * Personal pronoun */ case 'p': if(gender < 0) gender = get_gender(cause); if(!gender) { safe_str(Name(cause), buff, bufc); safe_chr('s', buff, bufc); } else { safe_str((char *) poss[gender], buff, bufc); } break; case 'S': /* * Subjective pronoun */ case 's': if(gender < 0) gender = get_gender(cause); if(!gender) tbuf = Name(cause); else tbuf = (char *) subj[gender]; safe_str(tbuf, buff, bufc); break; case 'A': /* * Absolute posessive */ case 'a': /* * idea from Empedocles */ if(gender < 0) gender = get_gender(cause); if(!gender) { safe_str(Name(cause), buff, bufc); safe_chr('s', buff, bufc); } else { safe_str((char *) absp[gender], buff, bufc); } break; case '#': /* * Invoker DB number */ tbuf = alloc_sbuf("exec.invoker"); sprintf(tbuf, "#%ld", cause); safe_str(tbuf, buff, bufc); free_sbuf(tbuf); break; case '!': /* * Executor DB number */ tbuf = alloc_sbuf("exec.executor"); sprintf(tbuf, "#%ld", player); safe_str(tbuf, buff, bufc); free_sbuf(tbuf); break; case 'N': /* * Invoker name */ case 'n': safe_str(Name(cause), buff, bufc); break; case 'L': /* * Invoker location db# */ case 'l': if(!(eval & EV_NO_LOCATION)) { tbuf = alloc_sbuf("exec.exloc"); sprintf(tbuf, "#%ld", where_is(cause)); safe_str(tbuf, buff, bufc); free_sbuf(tbuf); } break; default: /* * Just copy */ safe_chr(**dstr, buff, bufc); } if(isupper(savec)) *savepos = ToUpper(*savepos); break; case '(': /* * Arglist start. See if what precedes is a function. If so, * execute it if we should. */ at_space = 0; if(!(eval & EV_FCHECK)) { safe_chr('(', buff, bufc); break; } /* * Load an sbuf with an uppercase version of the func name, and * see if the func exists. Trim trailing spaces from the name * if configured. */ **bufc = '\0'; tbufc = tbuf = alloc_sbuf("exec.tbuf"); safe_sb_str(oldp, tbuf, &tbufc); *tbufc = '\0'; if(mudconf.space_compress) { while ((--tbufc >= tbuf) && isspace(*tbufc)); tbufc++; *tbufc = '\0'; } for(tbufc = tbuf; *tbufc; tbufc++) *tbufc = ToLower(*tbufc); fp = (FUN *) hashfind(tbuf, &mudstate.func_htab); /* * If not a builtin func, check for global func */ ufp = NULL; if(fp == NULL) { ufp = (UFUN *) hashfind(tbuf, &mudstate.ufunc_htab); } /* * Do the right thing if it doesn't exist */ if(!fp && !ufp) { if(eval & EV_FMAND) { *bufc = oldp; safe_str((char *) "#-1 FUNCTION (", buff, bufc); safe_str(tbuf, buff, bufc); safe_str((char *) ") NOT FOUND", buff, bufc); alldone = 1; } else { safe_chr('(', buff, bufc); } free_sbuf(tbuf); eval &= ~EV_FCHECK; break; } free_sbuf(tbuf); /* * Get the arglist and count the number of args * Neg * * * * * * * # of args means catenate subsequent * args */ if(ufp) nfargs = NFARGS; else if(fp->nargs < 0) nfargs = -fp->nargs; else nfargs = NFARGS; tstr = *dstr; if(fp && (fp->flags & FN_NO_EVAL)) feval = (eval & ~EV_EVAL) | EV_STRIP_ESC; else feval = eval; *dstr = parse_arglist(player, cause, *dstr + 1, ')', feval, fargs, nfargs, cargs, ncargs); /* * If no closing delim, just insert the '(' and * * * * * * continue normally */ if(!*dstr) { *dstr = tstr; safe_chr(**dstr, buff, bufc); for(i = 0; i < nfargs; i++) if(fargs[i] != NULL) free_lbuf(fargs[i]); eval &= ~EV_FCHECK; break; } /* * Count number of args returned */ (*dstr)--; j = 0; for(i = 0; i < nfargs; i++) if(fargs[i] != NULL) j = i + 1; nfargs = j; /* * If it's a user-defined function, perform it now. */ if(ufp) { mudstate.func_nest_lev++; if(!check_access(player, ufp->perms)) { safe_str("#-1 PERMISSION DENIED", buff, &oldp); *bufc = oldp; } else { tstr = atr_get(ufp->obj, ufp->atr, &aowner, &aflags); if(ufp->flags & FN_PRIV) i = ufp->obj; else i = player; str = tstr; if(ufp->flags & FN_PRES) { for(j = 0; j < MAX_GLOBAL_REGS; j++) { if(!mudstate.global_regs[j]) preserve[j] = NULL; else { preserve[j] = alloc_lbuf("eval_regs"); StringCopy(preserve[j], mudstate.global_regs[j]); } } } exec(buff, &oldp, 0, i, cause, feval, &str, fargs, nfargs); *bufc = oldp; if(ufp->flags & FN_PRES) { for(j = 0; j < MAX_GLOBAL_REGS; j++) { if(preserve[j]) { if(!mudstate.global_regs[j]) mudstate.global_regs[j] = alloc_lbuf("eval_regs"); StringCopy(mudstate.global_regs[j], preserve[j]); free_lbuf(preserve[j]); } else { if(mudstate.global_regs[j]) *(mudstate.global_regs[i]) = '\0'; } } } free_lbuf(tstr); } /* * Return the space allocated for the args */ mudstate.func_nest_lev--; for(i = 0; i < nfargs; i++) if(fargs[i] != NULL) free_lbuf(fargs[i]); eval &= ~EV_FCHECK; break; } /* * If the number of args is right, perform the func. * Otherwise return an error message. Note * that parse_arglist returns zero args as one * null arg, so we have to handle that case * specially. */ if((fp->nargs == 0) && (nfargs == 1)) { if(!*fargs[0]) { free_lbuf(fargs[0]); fargs[0] = NULL; nfargs = 0; } } if((nfargs == fp->nargs) || (nfargs == -fp->nargs) || (fp->flags & FN_VARARGS)) { /* * Check recursion limit */ mudstate.func_nest_lev++; mudstate.func_invk_ctr++; if(mudstate.func_nest_lev >= mudconf.func_nest_lim) { safe_str("#-1 FUNCTION RECURSION LIMIT EXCEEDED", buff, bufc); } else if(mudstate.func_invk_ctr == mudconf.func_invk_lim) { safe_str("#-1 FUNCTION INVOCATION LIMIT EXCEEDED", buff, bufc); } else if(!check_access(player, fp->perms)) { safe_str("#-1 PERMISSION DENIED", buff, &oldp); *bufc = oldp; } else if(mudstate.func_invk_ctr < mudconf.func_invk_lim) { fp->fun(buff, &oldp, player, cause, fargs, nfargs, cargs, ncargs); *bufc = oldp; } else { **bufc = '\0'; } mudstate.func_nest_lev--; } else { *bufc = oldp; tstr = alloc_sbuf("exec.funcargs"); sprintf(tstr, "%d", fp->nargs); safe_str((char *) "#-1 FUNCTION (", buff, bufc); safe_str((char *) fp->name, buff, bufc); safe_str((char *) ") EXPECTS ", buff, bufc); safe_str(tstr, buff, bufc); safe_str((char *) " ARGUMENTS", buff, bufc); free_sbuf(tstr); } /* * Return the space allocated for the arguments */ for(i = 0; i < nfargs; i++) if(fargs[i] != NULL) free_lbuf(fargs[i]); eval &= ~EV_FCHECK; break; default: /* * A mundane character. Just copy it */ at_space = 0; safe_chr(**dstr, buff, bufc); } (*dstr)++; } /* * If we're eating spaces, and the last thing was a space, eat it * up. Complicated by the fact that at_space is initially * true. So check to see if we actually put something in the * buffer, too. */ if(mudconf.space_compress && at_space && !(eval & EV_NO_COMPRESS) && (start != *bufc)) (*bufc)--; /* * The ansi() function knows how to take care of itself. However, * if the player used a %c sub in the string, and hasn't yet * terminated the color with a %cn yet, we'll have to do it for * them. */ if(ansi == 1) safe_str(ANSI_NORMAL, buff, bufc); **bufc = '\0'; /* * Report trace information */ if(realbuff) { **bufc = '\0'; *bufc = realbp; safe_str(buff, realbuff, bufc); free(buff); buff = realbuff; } if(is_trace) { tcache_add(savestr, start); save_count = tcache_count - mudconf.trace_limit;; if(is_top || !mudconf.trace_topdown) tcache_finish(player); if(is_top && (save_count > 0)) { tbuf = alloc_mbuf("exec.trace_diag"); sprintf(tbuf, "%d lines of trace output discarded.", save_count); notify(player, tbuf); free_mbuf(tbuf); } } }
/** The whisper command. * \param player the enactor. * \param arg1 name of the object to whisper to. * \param arg2 message to whisper. * \param noisy if 1, others overhear that a whisper has occurred. * \param pe_info the pe_info for evaluating interact locks */ void do_whisper(dbref player, const char *arg1, const char *arg2, int noisy, NEW_PE_INFO *pe_info) { dbref who; int key; const char *gap; char *tbuf, *tp; char *p; dbref good[100]; int gcount = 0; const char *head; int overheard; char *current; const char **start; char sname[BUFFER_LEN]; if (!arg1 || !*arg1) { notify(player, T("Whisper to whom?")); return; } if (!arg2 || !*arg2) { notify(player, T("Whisper what?")); return; } tp = tbuf = (char *) mush_malloc(BUFFER_LEN, "string"); if (!tbuf) mush_panic("Unable to allocate memory in do_whisper"); overheard = 0; head = arg1; start = &head; /* Figure out what kind of message */ gap = " "; switch (*arg2) { case SEMI_POSE_TOKEN: gap = ""; case POSE_TOKEN: key = 1; arg2++; break; default: key = 2; break; } *tp = '\0'; /* Make up a list of good and bad names */ while (head && *head) { current = next_in_list(start); who = match_result(player, current, TYPE_PLAYER, MAT_NEAR_THINGS | MAT_CONTAINER); if (!GoodObject(who) || !can_interact(player, who, INTERACT_HEAR, pe_info)) { safe_chr(' ', tbuf, &tp); safe_str_space(current, tbuf, &tp); if (GoodObject(who)) notify_format(player, T("%s can't hear you."), AName(who, AN_SYS, NULL)); } else { /* A good whisper */ good[gcount++] = who; if (gcount >= 100) { notify(player, T("Too many people to whisper to.")); break; } } } *tp = '\0'; if (*tbuf) notify_format(player, T("Unable to whisper to:%s"), tbuf); if (!gcount) { mush_free(tbuf, "string"); return; } /* Drunk wizards... */ if (Dark(player)) noisy = 0; /* Set up list of good names */ tp = tbuf; safe_str(T(" to "), tbuf, &tp); for (who = 0; who < gcount; who++) { if (noisy && (get_random32(0, 100) < (uint32_t) WHISPER_LOUDNESS)) overheard = 1; safe_itemizer(who + 1, (who == gcount - 1), ",", T("and"), " ", tbuf, &tp); safe_str(AName(good[who], AN_SAY, NULL), tbuf, &tp); } *tp = '\0'; if (key == 1) { notify_format(player, (gcount > 1) ? T("%s sense: %s%s%s") : T("%s senses: %s%s%s"), tbuf + 4, AName(player, AN_SAY, NULL), gap, arg2); p = tprintf("You sense: %s%s%s", AName(player, AN_SAY, NULL), gap, arg2); } else { notify_format(player, T("You whisper, \"%s\"%s."), arg2, tbuf); p = tprintf(T("%s whispers%s: %s"), AName(player, AN_SAY, NULL), gcount > 1 ? tbuf : "", arg2); } strcpy(sname, AName(player, AN_SAY, NULL)); for (who = 0; who < gcount; who++) { notify_must_puppet(good[who], p); if (Location(good[who]) != Location(player)) overheard = 0; } if (overheard) { dbref first = Contents(Location(player)); if (!GoodObject(first)) return; p = tprintf(T("%s whispers%s."), sname, tbuf); DOLIST(first, first) { overheard = 1; for (who = 0; who < gcount; who++) { if ((first == player) || (first == good[who])) { overheard = 0; break; } } if (overheard) notify_noecho(first, p); } }
void reap_info_slave(void) { struct response_dgram resp; ssize_t len; char hostname[BUFFER_LEN], *hp; int n, count; if (info_slave_state != INFO_SLAVE_PENDING) { if (info_slave_state == INFO_SLAVE_DOWN) make_info_slave(); return; } len = recv(info_slave, &resp, sizeof resp, 0); if (len < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) return; else if (len < 0 || len != (int) sizeof resp) { penn_perror("reading info_slave response"); return; } /* okay, now we have some info! */ if (!FD_ISSET(resp.fd, &info_pending)) { /* Duplicate or spoof. Ignore. */ return; } FD_CLR(resp.fd, &info_pending); /* See if we have any other pending queries and change state if not. */ for (n = 0, count = 0; n < pending_max; n++) if (FD_ISSET(n, &info_pending)) count++; if (count == 0) { info_slave_state = INFO_SLAVE_READY; pending_max = 0; } hp = hostname; if (resp.ident[0]) { safe_str(resp.ident, hostname, &hp); safe_chr('@', hostname, &hp); } if (resp.hostname[0]) safe_str(resp.hostname, hostname, &hp); else safe_str(resp.ipaddr, hostname, &hp); *hp = '\0'; if (Forbidden_Site(resp.ipaddr) || Forbidden_Site(hostname)) { if (!Deny_Silent_Site(resp.ipaddr, AMBIGUOUS) || !Deny_Silent_Site(hostname, AMBIGUOUS)) { do_log(LT_CONN, 0, 0, "[%d/%s/%s] Refused connection.", resp.fd, hostname, resp.ipaddr); } shutdown(resp.fd, 2); closesocket(resp.fd); return; } do_log(LT_CONN, 0, 0, "[%d/%s/%s] Connection opened.", resp.fd, hostname, resp.ipaddr); set_keepalive(resp.fd); initializesock(resp.fd, hostname, resp.ipaddr, (resp.connected_to == SSLPORT)); }
/** Is name a valid new name for thing, when set by player? * \verbatim * Parses names and aliases for players/exits, validating each. If everything is valid, * the new name and alias are set into newname and newalias, with memory malloc'd as necessary. * For things/rooms, no parsing is done, and ok_name is called on the entire string to validate. * For players and exits, if name takes the format <name>; then newname is set to <name> and * newalias to ";", to signify that the existing alias should be cleared. If name contains a name and * valid aliases, newname and newalias are set accordingly. * \endverbatim * \param name the new name to set * \param player the player setting the name, for permission checks * \param thing object getting the name, or NOTHING for new objects * \param type type of object getting the name (necessary for new exits) * \param newname pointer to place the new name, once validated * \param newalias pointer to place the alias in, if any * \retval OPAE_SUCCESS name and any given aliases are valid * \retval OPAE_INVALID invalid name or aliases * \retval OPAE_TOOMANY too many aliases for player */ enum opa_error ok_object_name(char *name, dbref player, dbref thing, int type, char **newname, char **newalias) { char *bon, *eon; char nbuff[BUFFER_LEN], abuff[BUFFER_LEN]; char *ap = abuff; int aliases = 0; int empty = 0; strncpy(nbuff, name, BUFFER_LEN - 1); nbuff[BUFFER_LEN - 1] = '\0'; memset(abuff, 0, BUFFER_LEN); /* First, check for a quoted player name */ if (type == TYPE_PLAYER && *name == '"') { /* Quoted player name, no aliases allowed */ bon = nbuff; bon++; eon = bon; while (*eon && *eon != '"') eon++; if (*eon) *eon = '\0'; if (!ok_player_name(bon, player, thing)) return OPAE_INVALID; *newname = mush_strdup(bon, "name.newname"); return OPAE_SUCCESS; } if (type & (TYPE_THING | TYPE_ROOM)) { /* No aliases in the name */ if (!ok_name(nbuff, 0)) return OPAE_INVALID; *newname = mush_strdup(nbuff, "name.newname"); return OPAE_SUCCESS; } /* A player or exit name, with aliases allowed. * Possible things to parse: * <name> - just a new name * <name>; - new name with trailing ; to clear alias * <name>;<alias1>[;<aliasN>] - name with one or more aliases, separated by ; */ /* Validate name first */ bon = nbuff; if ((eon = strchr(bon, ALIAS_DELIMITER))) { *eon++ = '\0'; aliases++; } if (! (type == TYPE_PLAYER ? ok_player_name(bon, player, thing) : ok_name(bon, 1))) return OPAE_INVALID; *newname = mush_strdup(bon, "name.newname"); if (aliases) { /* We had aliases, so parse them */ while (eon) { if (empty) return OPAE_NULL; /* Null alias only valid as a single, final alias */ bon = eon; if ((eon = strchr(bon, ALIAS_DELIMITER))) { *eon++ = '\0'; } while (*bon && *bon == ' ') bon++; if (!*bon) { empty = 1; /* empty alias, should only happen if we have no proper aliases */ continue; } if (! (type == TYPE_PLAYER ? ok_player_name(bon, player, thing) : ok_name(bon, 1))) { *newalias = mush_strdup(bon, "name.newname"); /* So we can report the invalid alias */ return OPAE_INVALID; } if (aliases > 1) { safe_chr(ALIAS_DELIMITER, abuff, &ap); } safe_str(bon, abuff, &ap); aliases++; } } *ap = '\0'; if (aliases) { if (!Wizard(player) && type == TYPE_PLAYER && aliases > MAX_ALIASES) return OPAE_TOOMANY; if (*abuff) { /* We have actual aliases */ *newalias = mush_strdup(abuff, "name.newname"); } else { ap = abuff; safe_chr(ALIAS_DELIMITER, abuff, &ap); *ap = '\0'; /* We just want to clear the existing alias */ *newalias = mush_strdup(abuff, "name.newname"); } } return OPAE_SUCCESS; }