/* flags.c */
/* Functions to cope with flags */
#include "config.h"
#ifdef I_SYS_TIME
#include <sys/time.h>
#else
#include <time.h>
#endif
#ifdef I_STRING
#include <string.h>
#else
#include <strings.h>
#endif
#ifdef I_STDLIB
#include <stdlib.h>
#endif
#include "conf.h"
#include "mushdb.h"
#include "externs.h"
#include "intrface.h"
#include "match.h"
#include "htab.h"
#include "confmagic.h"
extern void hide_player _((dbref player, int hide));
#define FLAG_HASH_SIZE 256
#define FLAG_HASH_MASK 255
typedef struct flag_info FLAG;
struct flag_info {
const char *name;
char letter;
int type;
int flag;
int perms;
int negate_perms;
FLAG *next;
};
typedef struct flag_entry FLAGENT;
struct flag_entry {
const char *name;
FLAG *entry;
FLAGENT *next;
};
typedef struct flag_alias FLAG_ALIAS;
struct flag_alias {
const char *alias;
const char *realname;
};
typedef struct power_info POWER;
struct power_info {
const char *name;
int flag;
POWER *next;
};
typedef struct power_alias POWER_ALIAS;
struct power_alias {
const char *alias;
const char *realname;
};
static FLAG *flag_hash_lookup _((const char *name));
static void flag_hash_insert _((const char *name, FLAG *entry));
void init_flag_hashtab _((void));
int can_set_flag _((dbref player, dbref thing, FLAG *flagp, int negate));
const char *unparse_flags _((dbref thing, dbref player));
const char *flag_description _((dbref player, dbref thing));
const char *togglemask_to_string _((int type, object_flag_type mask));
static FLAG *letter_to_flagptr _((char c, int type, int *toggle));
object_flag_type letter_to_flag _((char c, int type, int *toggle));
object_flag_type find_flag _((char *name, int type, int *toggle, int is_conf));
void decompile_flags _((dbref player, dbref thing, const char *name));
int convert_flags _((dbref player, char *s, object_flag_type *p_mask, object_flag_type *p_toggle, object_flag_type *p_type));
void set_flag _((dbref player, dbref thing, char *flag, int negate, int hear, int listener));
int handle_flaglists _((dbref player, char *name, char *fstr, int type));
int sees_flag _((dbref privs, dbref thing, char *name));
HASHTAB htab_flag;
/* Name Lettter Type Flag Perms Negate_Perm */
FLAG flag_table[] =
{
{"CHOWN_OK", 'C', NOTYPE, CHOWN_OK, F_ANY, F_ANY},
{"DARK", 'D', NOTYPE, DARK, F_ANY, F_ANY},
{"GOING", 'G', NOTYPE, GOING, F_INTERNAL, F_ANY},
{"HAVEN", 'H', NOTYPE, HAVEN, F_ANY, F_ANY},
{"INHERIT", 'I', NOTYPE, INHERIT, F_INHERIT, F_INHERIT},
{"LINK_OK", 'L', NOTYPE, LINK_OK, F_ANY, F_ANY},
{"OPAQUE", 'O', NOTYPE, OPAQUE, F_ANY, F_ANY},
{"QUIET", 'Q', NOTYPE, QUIET, F_ANY, F_ANY},
{"STICKY", 'S', NOTYPE, STICKY, F_ANY, F_ANY},
{"UNFINDABLE", 'U', NOTYPE, UNFIND, F_ANY, F_ANY},
{"VISUAL", 'V', NOTYPE, VISUAL, F_ANY, F_ANY},
{"WIZARD", 'W', NOTYPE, WIZARD, F_INHERIT | F_WIZARD,
F_INHERIT | F_WIZARD},
{"SAFE", 'X', NOTYPE, SAFE, F_ANY, F_ANY},
{"AUDIBLE", 'a', NOTYPE, AUDIBLE, F_ANY, F_ANY},
{"DEBUG", 'b', NOTYPE, DEBUGGING, F_ANY, F_ANY},
#ifdef USE_WARNINGS
{"NO_WARN", 'w', NOTYPE, NOWARN, F_ANY, F_ANY},
#endif
{"ENTER_OK", 'e', NOTYPE, ENTER_OK, F_ANY, F_ANY},
{"HALT", 'h', NOTYPE, HALT, F_ANY, F_ANY},
{"NO_COMMAND", 'n', NOTYPE, NO_COMMAND, F_ANY, F_ANY},
{"LIGHT", 'l', NOTYPE, LIGHT, F_ANY, F_ANY},
#ifdef ROYALTY_FLAG
{"ROYALTY", 'r', NOTYPE, ROYALTY, F_INHERIT | F_ROYAL,
F_INHERIT | F_ROYAL},
#endif
{"TRANSPARENT", 't', NOTYPE, TRANSPARENTED, F_ANY, F_ANY},
{"VERBOSE", 'v', NOTYPE, VERBOSE, F_ANY, F_ANY},
{"STARTUP", 'z', NOTYPE, STARTUP, F_INTERNAL,
F_INTERNAL},
{"ANSI", 'A', TYPE_PLAYER, PLAYER_ANSI, F_ANY, F_ANY},
#ifdef EXTENDED_ANSI
{"COLOR", 'C', TYPE_PLAYER, PLAYER_COLOR, F_ANY, F_ANY},
{"FORCE_WHITE", 'f', TYPE_PLAYER, PLAYER_FORCEWHITE, F_ANY, F_ANY},
#endif
{"MONITOR", 'M', TYPE_PLAYER, PLAYER_MONITOR, F_ROYAL, F_ANY},
{"NOSPOOF", 'N', TYPE_PLAYER, PLAYER_NOSPOOF, F_ANY, F_ANY},
{"ZONE", 'Z', TYPE_PLAYER, PLAYER_ZONE, F_ANY, F_ANY},
{"CONNECTED", 'c', TYPE_PLAYER, PLAYER_CONNECT, F_INTERNAL | F_MDARK,
F_INTERNAL | F_MDARK},
{"GAGGED", 'g', TYPE_PLAYER, PLAYER_GAGGED, F_WIZARD, F_WIZARD},
{"MYOPIC", 'm', TYPE_PLAYER, PLAYER_MYOPIC, F_ANY, F_ANY},
{"TERSE", 'x', TYPE_PLAYER, PLAYER_TERSE, F_ANY, F_ANY},
#ifdef JURY_OK
{"JURY_OK", 'j', TYPE_PLAYER, PLAYER_JURY, F_ROYAL, F_ROYAL},
{"JUDGE", 'J', TYPE_PLAYER, PLAYER_JUDGE, F_ROYAL, F_ROYAL},
#endif
#ifdef FIXED_FLAG
{"FIXED", 'F', TYPE_PLAYER, PLAYER_FIXED, F_WIZARD, F_WIZARD},
#endif
#ifdef ONLINE_REG
{"UNREGISTERED", '?', TYPE_PLAYER, PLAYER_UNREG, F_ROYAL, F_ROYAL},
#endif
#ifdef VACATION_FLAG
{"ON-VACATION", 'o', TYPE_PLAYER, PLAYER_VACATION, F_ANY, F_ANY},
#endif
{"SUSPECT", 's', TYPE_PLAYER, PLAYER_SUSPECT, F_WIZARD | F_MDARK,
F_WIZARD | F_MDARK},
{"MONITOR", 'M', TYPE_THING, THING_LISTEN, F_ANY, F_ANY},
{"DESTROY_OK", 'd', TYPE_THING, THING_DEST_OK, F_ANY, F_ANY},
{"PUPPET", 'p', TYPE_THING, THING_PUPPET, F_ANY, F_ANY},
{"NO_LEAVE", 'N', TYPE_THING, THING_NOLEAVE, F_ANY, F_ANY},
{"ABODE", 'A', TYPE_ROOM, ROOM_ABODE, F_ANY, F_ANY},
{"FLOATING", 'F', TYPE_ROOM, ROOM_FLOATING, F_ANY, F_ANY},
{"JUMP_OK", 'J', TYPE_ROOM, ROOM_JUMP_OK, F_ANY, F_ANY},
{"MONITOR", 'M', TYPE_ROOM, ROOM_LISTEN, F_ANY, F_ANY},
{"Z_TEL", 'Z', TYPE_ROOM, ROOM_Z_TEL, F_ANY, F_ANY},
{"NO_TEL", 'N', TYPE_ROOM, ROOM_NO_TEL, F_ANY, F_ANY},
#ifdef UNINSPECTED_FLAG
{"UNINSPECTED", 'u', TYPE_ROOM, ROOM_UNINSPECT, F_ROYAL, F_ROYAL},
#endif
{"CLOUDY", 'x', TYPE_EXIT, EXIT_CLOUDY, F_ANY, F_ANY},
{"ACCESSED", '\0', NOTYPE, ACCESSED, F_INTERNAL | F_DARK,
F_INTERNAL | F_DARK},
{"MARKED", '\0', NOTYPE, MARKED, F_INTERNAL | F_DARK,
F_INTERNAL | F_DARK},
{"GOING_TWICE", '\0', NOTYPE, GOING_TWICE, F_INTERNAL | F_DARK,
F_INTERNAL | F_DARK},
{NULL, '\0', 0, 0, 0, 0}
};
FLAG type_table[] =
{
{"PLAYER", 'P', TYPE_PLAYER, TYPE_PLAYER, F_INTERNAL,
F_INTERNAL},
{"ROOM", 'R', TYPE_ROOM, TYPE_ROOM, F_INTERNAL,
F_INTERNAL},
{"EXIT", 'E', TYPE_EXIT, TYPE_EXIT, F_INTERNAL,
F_INTERNAL},
{"THING", 'T', TYPE_THING, TYPE_THING, F_INTERNAL,
F_INTERNAL},
{NULL, '\0', 0, 0, 0, 0}
};
static FLAG_ALIAS flag_alias_tab[] =
{
{"CHOWN_O", "CHOWN_OK"},
{"CHOWN_", "CHOWN_OK"},
{"CHOWN", "CHOWN_OK"},
{"CHOW", "CHOWN_OK"},
{"CHO", "CHOWN_OK"},
{"CH", "CHOWN_OK"},
{"DAR", "DARK"},
{"DA", "DARK"},
{"GOIN", "GOING"},
{"GOI", "GOING"},
{"GO", "GOING"},
{"HAVE", "HAVEN"},
{"HAV", "HAVEN"},
{"INHERI", "INHERIT"},
{"INHER", "INHERIT"},
{"INHE", "INHERIT"},
{"INH", "INHERIT"},
{"IN", "INHERIT"},
{"I", "INHERIT"},
{"LINK_O", "LINK_OK"},
{"LINK_", "LINK_OK"},
{"LINK", "LINK_OK"},
{"LIN", "LINK_OK"},
{"OPAQU", "OPAQUE"},
{"OPAQ", "OPAQUE"},
{"OPA", "OPAQUE"},
{"OP", "OPAQUE"},
{"O", "OPAQUE"},
{"QUIE", "QUIET"},
{"QUI", "QUIET"},
{"QU", "QUIET"},
{"Q", "QUIET"},
{"STICK", "STICKY"},
{"STIC", "STICKY"},
{"STI", "STICKY"},
{"ST", "STICKY"},
{"UNFINDABL", "UNFINDABLE"},
{"UNFINDABL", "UNFINDABLE"},
{"UNFINDAB", "UNFINDABLE"},
{"UNFINDA", "UNFINDABLE"},
{"UNFIND", "UNFINDABLE"},
{"UNFIN", "UNFINDABLE"},
{"UNFI", "UNFINDABLE"},
{"UNF", "UNFINDABLE"},
{"UN", "UNFINDABLE"},
{"U", "UNFINDABLE"},
{"VISUA", "VISUAL"},
{"VISU", "VISUAL"},
{"VIS", "VISUAL"},
{"VI", "VISUAL"},
{"WIZAR", "WIZARD"},
{"WIZA", "WIZARD"},
{"WIZ", "WIZARD"},
{"WI", "WIZARD"},
{"W", "WIZARD"},
{"SAF", "SAFE"},
{"SA", "SAFE"},
{"AUDIBL", "AUDIBLE"},
{"AUDIB", "AUDIBLE"},
{"AUDI", "AUDIBLE"},
{"AUD", "AUDIBLE"},
{"AU", "AUDIBLE"},
{"DEBU", "DEBUG"},
{"DEB", "DEBUG"},
{"TRACE", "DEBUG"},
{"TRAC", "DEBUG"},
{"ENTER_O", "ENTER_OK"},
{"ENTER_", "ENTER_OK"},
{"ENTER", "ENTER_OK"},
{"ENTE", "ENTER_OK"},
{"ENT", "ENTER_OK"},
{"EN", "ENTER_OK"},
#ifdef USE_WARNINGS
{"NO_WAR", "NO_WARN"},
{"NO_WA", "NO_WARN"},
{"NO_W", "NO_WARN"},
{"NOWARN", "NO_WARN"},
{"NOWAR", "NO_WARN"},
{"NOWA", "NO_WARN"},
#endif
{"HAL", "HALT"},
{"NO_COMMAN", "NO_COMMAND"},
{"NO_COMMA", "NO_COMMAND"},
{"NO_COMM", "NO_COMMAND"},
{"NO_COM", "NO_COMMAND"},
{"NO_CO", "NO_COMMAND"},
{"NO_C", "NO_COMMAND"},
#ifdef ROYALTY_FLAG
{"ROYALT", "ROYALTY"},
{"ROYAL", "ROYALTY"},
{"ROYA", "ROYALTY"},
{"ROY", "ROYALTY"},
#endif
{"TRANSPAREN", "TRANSPARENT"},
{"TRANSPARE", "TRANSPARENT"},
{"TRANSPAR", "TRANSPARENT"},
{"TRANSPA", "TRANSPARENT"},
{"TRANSP", "TRANSPARENT"},
{"TRANS", "TRANSPARENT"},
{"TRAN", "TRANSPARENT"},
{"TRA", "TRANSPARENT"},
{"TR", "TRANSPARENT"},
{"VERBOS", "VERBOSE"},
{"VERBO", "VERBOSE"},
{"VERB", "VERBOSE"},
{"VER", "VERBOSE"},
{"VE", "VERBOSE"},
{"ANS", "ANSI"},
{"AN", "ANSI"},
{"LISTENER", "MONITOR"},
{"LISTENE", "MONITOR"},
{"LISTEN", "MONITOR"},
{"LISTE", "MONITOR"},
{"LIST", "MONITOR"},
{"LIS", "MONITOR"},
{"MONITO", "MONITOR"},
{"MONIT", "MONITOR"},
{"MONI", "MONITOR"},
{"MON", "MONITOR"},
{"MO", "MONITOR"},
{"NOSPOO", "NOSPOOF"},
{"NOSPO", "NOSPOOF"},
{"NOSP", "NOSPOOF"},
{"NOS", "NOSPOOF"},
{"ZON", "ZONE"},
{"ZO", "ZONE"},
{"Z", "ZONE"},
{"CONNECTE", "CONNECTED"},
{"CONNECT", "CONNECTED"},
{"CONNEC", "CONNECTED"},
{"CONNE", "CONNECTED"},
{"CONN", "CONNECTED"},
{"CON", "CONNECTED"},
{"CO", "CONNECTED"},
{"GAG", "GAGGED"},
{"MYOPI", "MYOPIC"},
{"MYOP", "MYOPIC"},
{"MYO", "MYOPIC"},
{"MY", "MYOPIC"},
{"TERS", "TERSE"},
{"TER", "TERSE"},
#ifdef EXTENDED_ANSI
{"COLOUR", "COLOR"},
{"COLOU", "COLOR"},
{"COLO", "COLOR"},
{"COL", "COLOR"},
{"FORCEWHITE", "FORCE_WHITE"},
{"WHITE", "FORCE_WHITE"},
{"WHIT", "FORCE_WHITE"},
{"WHI", "FORCE_WHITE"},
{"WEIRDANSI", "FORCE_WHITE"},
#endif
#ifdef JURY_OK
{"JURYOK", "JURY_OK"},
{"JURY", "JURY_OK"},
{"JUR", "JURY_OK"},
{"JUDG", "JUDGE"},
{"JUD", "JUDGE"},
#endif
#ifdef FIXED_FLAG
{"FIXE", "FIXED"},
{"FIX", "FIXED"},
{"FI", "FIXED"},
#endif
#ifdef ONLINE_REG
{"UNREGISTER", "UNREGISTERED"},
{"UNREGIST", "UNREGISTERED"},
{"UNREGIS", "UNREGISTERED"},
{"UNREGI", "UNREGISTERED"},
{"UNREG", "UNREGISTERED"},
{"UNRE", "UNREGISTERED"},
{"UNR", "UNREGISTERED"},
#endif
#ifdef VACATION_FLAG
{"ON-VACATI", "ON-VACATION"},
{"ON-VACAT", "ON-VACATION"},
{"ON-VACA", "ON-VACATION"},
{"ON-VAC", "ON-VACATION"},
{"ON-VA", "ON-VACATION"},
{"ON-V", "ON-VACATION"},
{"VACATION", "ON-VACATION"},
{"VACATIO", "ON-VACATION"},
{"VACATI", "ON-VACATION"},
{"VACAT", "ON-VACATION"},
{"VACA", "ON-VACATION"},
{"VAC", "ON-VACATION"},
#endif
{"SUSPEC", "SUSPECT"},
{"SUSPE", "SUSPECT"},
{"SUSP", "SUSPECT"},
{"SUS", "SUSPECT"},
{"SU", "SUSPECT"},
{"DEST_OK", "DESTROY_OK"},
{"DESTROY_O", "DESTROY_OK"},
{"DESTROY_", "DESTROY_OK"},
{"DESTROY", "DESTROY_OK"},
{"DESTRO", "DESTROY_OK"},
{"DESTR", "DESTROY_OK"},
{"DEST", "DESTROY_OK"},
{"DES", "DESTROY_OK"},
{"DE", "DESTROY_OK"},
{"PUPPE", "PUPPET"},
{"PUPP", "PUPPET"},
{"PUP", "PUPPET"},
{"PU", "PUPPET"},
{"P", "PUPPET"},
{"NO_LEAV", "NO_LEAVE"},
{"NO_LEA", "NO_LEAVE"},
{"NO_LE", "NO_LEAVE"},
{"NO_L", "NO_LEAVE"},
{"NOLEAVE", "NO_LEAVE"},
{"NOLEAV", "NO_LEAVE"},
{"NOLEA", "NO_LEAVE"},
{"NOLE", "NO_LEAVE"},
{"NOL", "NO_LEAVE"},
{"ABOD", "ABODE"},
{"ABO", "ABODE"},
{"AB", "ABODE"},
{"FLOATIN", "FLOATING"},
{"FLOATI", "FLOATING"},
{"FLOAT", "FLOATING"},
{"FLOA", "FLOATING"},
{"FLO", "FLOATING"},
{"FL", "FLOATING"},
{"F", "FLOATING"},
{"JUMP_O", "JUMP_OK"},
{"JUMP_", "JUMP_OK"},
{"JUMP", "JUMP_OK"},
{"JUM", "JUMP_OK"},
{"JU", "JUMP_OK"},
{"J", "JUMP_OK"},
{"NO_TE", "NO_TEL"},
{"NO_T", "NO_TEL"},
{"Z_TE", "Z_TEL"},
{"Z_T", "Z_TEL"},
#ifdef UNINSPECTED_FLAG
{"UNINSPECT", "UNINSPECTED"},
{"UNINSPEC", "UNINSPECTED"},
{"UNINSPE", "UNINSPECTED"},
{"UNINSP", "UNINSPECTED"},
{"UNINS", "UNINSPECTED"},
{"UNIN", "UNINSPECTED"},
{"UNI", "UNINSPECTED"},
#endif
{NULL, NULL}
};
/* Name Flag */
POWER power_table[] =
{
{"Announce", CAN_WALL},
{"Boot", CAN_BOOT},
{"Builder", CAN_BUILD},
{"Cemit", CEMIT},
{"Chat_Privs", CHAT_PRIVS},
{"Functions", GLOBAL_FUNCS},
{"Guest", IS_GUEST},
{"Halt", HALT_ANYTHING},
{"Hide", CAN_HIDE},
{"Idle", UNLIMITED_IDLE},
{"Immortal", NO_PAY | NO_QUOTA | UNKILLABLE},
{"Login", LOGIN_ANYTIME},
{"Long_Fingers", LONG_FINGERS},
{"No_Pay", NO_PAY},
{"No_Quota", NO_QUOTA},
{"Open_Anywhere", OPEN_ANYWHERE},
{"Pemit_All", PEMIT_ALL},
{"Player_Create", CREATE_PLAYER},
{"Poll", SET_POLL},
{"Queue", HUGE_QUEUE},
{"Quotas", CHANGE_QUOTAS},
{"Search", SEARCH_ALL},
{"See_All", SEE_ALL},
{"See_Queue", PS_ALL},
{"Tport_Anything", TEL_OTHER},
{"Tport_Anywhere", TEL_ANYWHERE},
{"Unkillable", UNKILLABLE},
{NULL, 0}
};
static POWER_ALIAS power_alias_tab[] =
{
{"@cemit", "Cemit"},
{"@wall", "Announce"},
{"wall", "Announce"},
{NULL, NULL}
};
/*---------------------------------------------------------------------------
* Flag hash table handlers
*/
static FLAG *
flag_hash_lookup(name)
const char *name;
{
FLAG *t;
t = (FLAG *) hashfind(strupper(name), &htab_flag);
if (t)
return t;
/* provided for backwards compatibility: type flag checking */
for (t = type_table; t->name != NULL; t++)
if (string_prefix(name, t->name))
return t;
return NULL;
}
static void
flag_hash_insert(name, entry)
const char *name;
FLAG *entry;
{
hashadd(name, (void *) entry, &htab_flag);
}
void
init_flag_hashtab()
{
FLAG *f;
FLAG_ALIAS *a;
hashinit(&htab_flag, 128);
/* do regular flags first */
for (f = flag_table; f->name; f++)
flag_hash_insert(f->name, f);
/* now add in the aliases */
for (a = flag_alias_tab; a->alias; a++) {
if ((f = flag_hash_lookup(a->realname)) != NULL)
flag_hash_insert(a->alias, (FLAG *) f);
else
fprintf(stderr,
"FLAG INIT: flag alias %s matches no known flag.\n",
a->alias);
}
}
/*---------------------------------------------------------------------------
* Other functions dealing with flags
*/
int
can_set_flag(player, thing, flagp, negate)
dbref player;
dbref thing;
FLAG *flagp;
int negate;
{
/* returns 1 if player can set a flag on thing. */
int myperms;
if (!flagp || !GoodObject(player) || !GoodObject(thing))
return 0;
myperms = negate ? flagp->negate_perms : flagp->perms;
if (myperms & F_INTERNAL)
return 0;
if ((flagp->type != NOTYPE) && (flagp->type != Typeof(thing)))
return 0;
if ((myperms & F_INHERIT) && !Wizard(player) &&
(!Inherit(player) || !Owns(player, thing)))
return 0;
/* You've got to *own* something (or be Wizard) to set it
* chown_ok or dest_ok. This prevents subversion of the
* zone-restriction on @chown and @dest
*/
if (((flagp->flag == CHOWN_OK) && (flagp->type == NOTYPE)) ||
((flagp->flag == THING_DEST_OK) && (flagp->type == TYPE_THING))) {
if (!Owns(player, thing) && !Wizard(player))
return 0;
else
return 1;
}
if (myperms & F_ANY)
return 1;
if ((myperms & F_WIZARD) && !Wizard(player))
return 0;
else if ((myperms & F_ROYAL) && !Hasprivs(player))
return 0;
else if ((myperms & F_GOD) && !God(player))
return 0;
/* Checking for the ZONE flag. If you set this, the player had
* better be @elocked!
*/
if ((flagp->type == TYPE_PLAYER) && (flagp->flag == PLAYER_ZONE) &&
!negate && (getlock(thing, Zone_Lock) == TRUE_BOOLEXP)) {
notify(player, "You must @elock before you can set a player ZONE");
return 0;
}
/* special case for the privileged flags. We do need to check
* for royalty setting flags on objects they don't own, because
* the controls check will not stop the flag set if the royalty
* player is in a zone. Also, only God can set the wizbit on
* players.
*/
if (Wizard(thing) && (flagp->flag == PLAYER_GAGGED) &&
(flagp->type == TYPE_PLAYER))
return 0; /* can't gag wizards/God */
if (God(player)) /* God can do (almost) anything) */
return 1;
/* Make sure we don't accidentally permission-check toggles when
* checking priv bits.
*/
if (flagp->type == NOTYPE) {
/* A wiz can set things he owns WIZ, but can't reset his own bit. */
if (flagp->flag == WIZARD) {
return (Wizard(player) && Owns(player, thing) &&
(Typeof(thing) != TYPE_PLAYER));
}
/* Wizards can set or unset anything royalty. Royalty can set anything
* they own royalty, but cannot reset their own bits. */
#ifdef ROYALTY_FLAG
if (flagp->flag == ROYALTY) {
return (!Guest(thing) && (Wizard(player) ||
(Royalty(player) && Owns(player, thing) &&
(Typeof(thing) != TYPE_PLAYER))));
}
#endif
}
return 1;
}
const char *
unparse_flags(thing, player)
dbref thing;
dbref player;
{
/* print out the flag symbols (letters) */
static char buf[BUFFER_LEN];
char *p;
static const char type_codes[] = "R-EP--*";
FLAG *f;
int t;
p = buf;
t = Typeof(thing);
if (t != TYPE_THING)
*p++ = type_codes[t];
/* get generic flags */
for (f = flag_table; f->type == NOTYPE; f++) {
if ((Flags(thing) & f->flag) && Can_See_Flag(player, thing, f))
*p++ = f->letter;
}
/* exits have no special flags. This may change in the future */
if (t == TYPE_EXIT || t == TYPE_GARBAGE) {
*p = '\0';
return buf;
}
/* go to beginning of list of flags for the type and print flags for
* that type.
*/
while (f->type != t)
f++;
for (; f->type == t; f++) {
if ((Toggles(thing) & f->flag) && Can_See_Flag(player, thing, f))
*p++ = f->letter;
}
*p = '\0';
return buf;
}
const char *
flag_description(player, thing)
dbref player;
dbref thing;
{
static char buf[BUFFER_LEN];
char fbuf[BUFFER_LEN];
char *bp;
FLAG *f;
int t;
t = Typeof(thing);
strcpy(buf, "Type: ");
switch (t) {
case TYPE_ROOM:
strcat(buf, "Room");
break;
case TYPE_EXIT:
strcat(buf, "Exit");
break;
case TYPE_THING:
strcat(buf, "Thing");
break;
case TYPE_PLAYER:
strcat(buf, "Player");
break;
default:
strcat(buf, "***UNKNOWN TYPE***");
break;
}
strcat(buf, " Flags:");
bp = fbuf;
/* get generic flags */
for (f = flag_table; f->type == NOTYPE; f++) {
if ((Flags(thing) & f->flag) && Can_See_Flag(player, thing, f)) {
safe_chr(' ', fbuf, &bp);
safe_str(f->name, fbuf, &bp);
}
}
/* go to beginning of list of flags for the type and print flags for
* that type.
*/
while ((f->type != t) && (f->type != NOTYPE))
f++;
for (; f->type == t; f++) {
if ((Toggles(thing) & f->flag) && Can_See_Flag(player, thing, f)) {
safe_chr(' ', fbuf, &bp);
safe_str(f->name, fbuf, &bp);
}
}
*bp = '\0';
/* no length checking needed. We're never going to have an overflow. */
sprintf(buf, "%s%s", buf, fbuf);
return buf;
}
/* Used to show the default toggle configuration from do_config_list */
const char *
togglemask_to_string(type, mask)
int type;
object_flag_type mask;
{
static char fbuf[BUFFER_LEN];
char *bp;
FLAG *f;
bp = fbuf;
f = flag_table;
while (f->type != type)
f++;
for (; f->type == type; f++) {
if (mask & f->flag) {
if (bp != fbuf)
safe_chr(' ', fbuf, &bp);
safe_str(f->name, fbuf, &bp);
}
}
*bp = '\0';
return fbuf;
}
#ifdef CAN_NEWSTYLE
static FLAG *
letter_to_flagptr(char c, int type, int *toggle)
#else
static FLAG *
letter_to_flagptr(c, type, toggle)
char c;
int type;
int *toggle;
#endif
{
/* convert letter to flag */
FLAG *f;
*toggle = 0;
/* try generic flags */
for (f = flag_table; f->type == NOTYPE; f++) {
if (c == f->letter)
return (f);
}
/* try type-specific flags */
*toggle = 1;
while ((f->type != type) && (f->type != NOTYPE))
f++;
for (; f->type != NOTYPE; f++) {
if (c == f->letter)
return (f);
}
return NULL;
}
#ifdef CAN_NEWSTYLE
object_flag_type
letter_to_flag(char c, int type, int *toggle)
#else
object_flag_type
letter_to_flag(c, type, toggle)
char c;
int type;
int *toggle;
#endif
{
FLAG *f = letter_to_flagptr(c, type, toggle);
if (f)
return (f->flag);
return -1;
}
object_flag_type
find_flag(name, type, toggle, is_conf)
char *name;
int type;
int *toggle;
int is_conf;
{
/* given a flag name and an object type, return a flag, and set the
* value of toggle to 0 if flag, 1 if toggle. We also check if it's
* a legal flag to set, if it's a conf flag set.
*/
FLAG *f;
*toggle = 0;
if ((f = flag_hash_lookup(upcasestr(name))) == NULL)
return -1;
if (is_conf && (f->perms == F_INTERNAL))
return -1;
if (f->type == NOTYPE) {
return f->flag;
} else {
*toggle = 1;
if (type != f->type) {
if (is_conf)
return -2;
else
return -1;
} else {
return f->flag;
}
}
return f->flag; /* NOTREACHED */
}
void
decompile_flags(player, thing, name)
dbref player;
dbref thing;
const char *name;
{
/* print out the flags for a decompile */
FLAG *f;
int t, ok;
t = Typeof(thing);
ok = !Suspect(thing);
/* do generic flags */
for (f = flag_table; f->type == NOTYPE; f++)
if ((Flags(thing) & f->flag) && !(f->perms & F_INTERNAL) &&
Can_See_Flag(player, thing, f))
notify(player, tprintf("@set %s = %s", name, f->name));
/* do normal flags */
while ((f->type != t) && (f->type != NOTYPE))
f++;
for (; f->type == t; f++)
if ((Toggles(thing) & f->flag) && Can_See_Flag(player, thing, f))
notify(player, tprintf("@set %s = %s", name, f->name));
}
void
decompile_powers(player, thing, name)
dbref player;
dbref thing;
const char *name;
{
/* print out the powers for a decompile */
POWER *p;
for (p = power_table; p->name; p++) {
/* Special case for immortal, which we don't show any more */
if (!strcasecmp(p->name, "immortal"))
continue;
if (Powers(thing) & p->flag)
notify(player, tprintf("@power %s = %s", name, p->name));
}
}
int
convert_flags(player, s, p_mask, p_toggle, p_type)
dbref player;
char *s;
object_flag_type *p_mask;
object_flag_type *p_toggle;
object_flag_type *p_type;
{
/* convert flags for search */
FLAG *f;
object_flag_type mask, toggle, type;
int done;
mask = toggle = 0;
type = NOTYPE;
while (s && *s) {
done = 0;
switch (*s) {
case 'P':
type = TYPE_PLAYER;
break;
case 'R':
type = TYPE_ROOM;
break;
case 'E':
type = TYPE_EXIT;
break;
default:
/* check generic flags first */
for (f = flag_table; (f->type == NOTYPE) && !done; f++) {
if (*s == f->letter) {
mask |= f->flag;
done = 1;
}
}
/* try type-specific flags */
/* if we have a type, start searching from that type */
if (!done && (type != NOTYPE))
while ((f->type != type) && (f->type != NOTYPE))
f++;
for (; !done && (f->type != NOTYPE); f++) {
if (*s == f->letter) {
/* if we don't have a type yet, we do now. If we do, we need
* to check for a conflict.
*/
if (type == NOTYPE) {
type = f->type;
toggle |= f->flag;
done = 1;
} else if (type != f->type) {
notify(player, tprintf("Type conflict with flag '%c'.", *s));
return 0;
} else {
/* We've got a match */
toggle |= f->flag;
done = 1;
}
}
}
/* if we get this far and still haven't found anything, error. */
if (!done) {
notify(player, tprintf("%c: unknown flag.", *s));
return 0;
}
}
s++;
}
*p_mask = mask;
*p_toggle = toggle;
*p_type = type;
return 1;
}
static FLAG mon_table[] =
{
{"MONITOR", 'M', TYPE_PLAYER, PLAYER_MONITOR, F_ROYAL},
{"MONITOR", 'M', TYPE_THING, THING_LISTEN, F_ANY},
{"MONITOR", 'M', TYPE_ROOM, ROOM_LISTEN, F_ANY},
{NULL, '\0', 0, 0, 0}
};
void
set_flag(player, thing, flag, negate, hear, listener)
dbref player;
dbref thing;
char *flag;
int negate;
int hear;
int listener;
{
/* attempt to set a flag on an object */
FLAG *f;
char tbuf1[BUFFER_LEN];
if ((f = flag_hash_lookup(strupper(flag))) == NULL) {
notify(player, "I don't recognize that flag.");
return;
}
/* HORRIBLE HACK: added to make MONITOR work. This needs to
* be fixed in the future, _somehow_...
*/
if (!strcmp(f->name, "MONITOR")) {
for (f = mon_table; f->name != NULL; f++)
if (Typeof(thing) == f->type)
break;
if (f->name == NULL) {
notify(player, "Permission denied.");
return;
}
}
if (!can_set_flag(player, thing, f, negate)) {
notify(player, "Permission denied.");
return;
}
/* The only players who can be Dark are wizards. */
if ((f->flag == DARK) && !negate && (f->type == NOTYPE) &&
Alive(thing) && !Wizard(thing)) {
notify(player, "Permission denied.");
return;
}
if (negate) {
if ((f->flag == GOING) && (f->type == NOTYPE)) {
/* This is, frankly, a bit of a hack. */
notify(player, "@set !GOING has been disabled. Use @undestroy instead.");
return;
}
/* remove the flag */
if (f->type == NOTYPE)
Flags(thing) &= ~(f->flag);
else
Toggles(thing) &= ~(f->flag);
/* log if necessary */
if ((f->flag == WIZARD) && (f->type == NOTYPE))
do_log(LT_WIZ, player, thing, "WIZFLAG RESET");
#ifdef ROYALTY_FLAG
else if ((f->flag == ROYALTY) && (f->type == NOTYPE))
do_log(LT_WIZ, player, thing, "ROYAL FLAG RESET");
#endif
else if ((f->flag == PLAYER_SUSPECT) && (f->type == TYPE_PLAYER))
do_log(LT_WIZ, player, thing, "SUSPECT FLAG RESET");
/* those who unDARK return to the WHO */
if ((f->flag == DARK) && (f->type == NOTYPE) &&
(Typeof(thing) == TYPE_PLAYER))
hide_player(thing, 0);
/* notify the area if something stops listening */
if ((Typeof(thing) == TYPE_THING) && (f->type == TYPE_THING) &&
(((f->flag == THING_PUPPET) && !listener && !Hearer(thing)) ||
((f->flag == THING_LISTEN) && !hear && !Listener(thing)))) {
sprintf(tbuf1, "%s is no longer listening.", Name(thing));
notify_except(Contents(Location(thing)), NOTHING, tbuf1);
}
if ((f->flag == AUDIBLE) && (f->type == NOTYPE)) {
switch (Typeof(thing)) {
case TYPE_EXIT:
if (Flags(Exits(thing)) & AUDIBLE) {
sprintf(tbuf1, "Exit %s is no longer broadcasting.", Name(thing));
notify_except(Contents(Exits(thing)), NOTHING, tbuf1);
}
break;
case TYPE_ROOM:
notify_except(Contents(thing), NOTHING,
"Audible exits in this room have been deactivated.");
break;
case TYPE_THING:
case TYPE_PLAYER:
notify_except(Contents(thing), thing,
"This room is no longer broadcasting.");
notify(thing, "Your contents can no longer be heard from outside.");
break;
}
}
if (((f->flag == QUIET) && (f->type == NOTYPE)) ||
(!Quiet(player) && !Quiet(thing)))
notify(player, "Flag reset.");
} else {
/* set the flag */
if (f->type == NOTYPE)
Flags(thing) |= f->flag;
else
Toggles(thing) |= f->flag;
/* log if necessary */
if ((f->flag == WIZARD) && (f->type == NOTYPE))
do_log(LT_WIZ, player, thing, "WIZFLAG SET");
#ifdef ROYALTY_FLAG
if ((f->flag == ROYALTY) && (f->type == NOTYPE))
do_log(LT_WIZ, player, thing, "ROYAL FLAG SET");
#endif
else if ((f->flag == PLAYER_SUSPECT) && (f->type == TYPE_PLAYER))
do_log(LT_WIZ, player, thing, "SUSPECT FLAG SET");
if ((f->flag == INHERIT) && GoodObject(Zone(thing))) {
notify(player, "Warning: Setting inherit flag on zoned object");
}
/* DARK players should be treated as logged out */
if ((f->flag == DARK) && (f->type == NOTYPE) &&
(Typeof(thing) == TYPE_PLAYER))
hide_player(thing, 1);
/* notify area if something starts listening */
if ((Typeof(thing) == TYPE_THING) && (f->type == TYPE_THING) &&
((f->flag == THING_PUPPET) || (f->flag == THING_LISTEN)) &&
!hear && !listener) {
sprintf(tbuf1, "%s is now listening.", Name(thing));
notify_except(Contents(Location(thing)), NOTHING, tbuf1);
}
/* notify for audible exits */
if ((f->flag == AUDIBLE) && (f->type == NOTYPE)) {
switch (Typeof(thing)) {
case TYPE_EXIT:
if (db[db[thing].exits].flags & AUDIBLE) {
sprintf(tbuf1, "Exit %s is now broadcasting.", Name(thing));
notify_except(Contents(Exits(thing)), NOTHING, tbuf1);
}
break;
case TYPE_ROOM:
notify_except(Contents(thing), NOTHING,
"Audible exits in this room have been activated.");
break;
case TYPE_PLAYER:
case TYPE_THING:
notify_except(Contents(thing), thing,
"This room is now broadcasting.");
notify(thing, "Your contents can now be heard from outside.");
break;
}
}
if (((f->flag == QUIET) && (f->flag == NOTYPE)) ||
(!Quiet(player) && !Quiet(thing)))
notify(player, "Flag set.");
}
}
int
handle_flaglists(player, name, fstr, type)
dbref player;
char *name;
char *fstr;
int type;
/* 0 for orflags, 1 for andflags */
{
char *s;
FLAG *fp;
int toggle, negate, temp;
int ret = type;
dbref it = match_thing(player, name);
toggle = negate = temp = 0;
if (it == NOTHING)
return 0;
for (s = fstr; *s; s++) {
/* Check for a negation sign. If we find it, we note it and
* increment the pointer to the next character.
*/
if (*s == '!') {
negate = 1;
s++;
} else {
negate = 0; /* It's important to clear this at appropriate times;
* else !Dc means (!D && !c), instead of (!D && c). */
}
if (!*s) {
/* We got a '!' that wasn't followed by a letter.
* Fail the check. */
return (type == 1) ? 0 : ret;
}
/* Find the flag. */
if ((fp = letter_to_flagptr(*s, Typeof(it), &toggle)) == NULL) {
/* Either we got a '!' that wasn't followed by a letter, or
* we couldn't find that flag. For AND, since we've failed
* a check, we can return false. Otherwise we just go on.
*/
if (type == 1)
return 0;
else
continue;
} else {
/* does the object have this flag? */
if ((!toggle && (Flags(it) & fp->flag)) ||
(toggle && (Toggles(it) & fp->flag) &&
Can_See_Flag(player, it, fp)))
temp = 1;
else
temp = 0;
if ((type == 1) && ((negate && temp) || (!negate && !temp))) {
/* Too bad there's no NXOR function...
* At this point we've either got a flag and we don't want
* it, or we don't have a flag and we want it. Since it's
* AND, we return false.
*/
return 0;
} else if ((type == 0) &&
((!negate && temp) || (negate && !temp))) {
/* We've found something we want, in an OR. We OR a
* true with the current value.
*/
ret |= 1;
}
/* Otherwise, we don't need to do anything. */
}
}
return (ret);
}
int
sees_flag(privs, thing, name)
dbref privs;
dbref thing;
char *name;
{
/* Does thing have the flag named name && can privs see it? */
FLAG *f;
int retval;
if ((f = flag_hash_lookup(upcasestr(name))) == NULL)
return 0;
if (f->type == NOTYPE) {
retval = Flags(thing) & f->flag;
} else {
if (Typeof(thing) != f->type) {
return 0;
} else {
retval = Toggles(thing) & f->flag;
}
}
return retval && Can_See_Flag(privs, thing, f);
}
const char *
power_description(thing)
dbref thing;
{
static char fbuf[BUFFER_LEN];
char *bp;
POWER *p;
bp = fbuf;
for (p = power_table; p->name; p++) {
/* Special case for immortal, which we don't show any more */
if (!strcasecmp(p->name, "immortal"))
continue;
if (Powers(thing) & p->flag) {
if (bp != fbuf)
safe_chr(' ', fbuf, &bp);
safe_str(p->name, fbuf, &bp);
}
}
*bp = '\0';
return fbuf;
}
object_flag_type
find_power(name)
const char *name;
{
POWER *p;
POWER_ALIAS *a;
for (p = power_table; p->name; p++) {
if (string_prefix(p->name, name))
return p->flag;
}
/* Check the alias table */
for (a = power_alias_tab; a->alias; a++) {
if (string_prefix(a->alias, name))
return find_power(a->realname);
}
/* Got nothing. Return -1 */
return -1;
}