/* * db.c */ #include "copyright.h" #include "config.h" #include <sys/file.h> #include <sys/stat.h> #define __DB_C #include "mudconf.h" #include "config.h" #include "externs.h" #include "db.h" #include "attrs.h" #include "vattr.h" #include "match.h" #include "alloc.h" #include "powers.h" #include "interface.h" #include "flags.h" #include "p.comsys.h" #include "mmdb.h" #ifndef O_ACCMODE #define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) #endif /* * Restart definitions */ #define RS_CONCENTRATE 0x00000002 #define RS_RECORD_PLAYERS 0x00000004 #define RS_NEW_STRINGS 0x00000008 #define RS_HUDKEY 0x00000010 OBJ *db = NULL; NAME *names = NULL; NAME *purenames = NULL; int corrupt; extern void desc_addhash(DESC *); extern void del_commac(dbref); extern void do_clear_macro(dbref player, char *s); #ifdef TEST_MALLOC int malloc_count = 0; #endif /* * * TEST_MALLOC */ extern VATTR *vattr_rename(char *, char *); typedef struct atrcount ATRCOUNT; struct atrcount { dbref thing; int count; }; /* * #define GNU_MALLOC_TEST 1 */ #ifdef GNU_MALLOC_TEST extern unsigned int malloc_sbrk_used; /* Amount of data space used now */ #endif /* * Check routine forward declaration. */ extern int fwdlist_ck(int, dbref, dbref, int, char *); extern void pcache_reload(dbref); extern void desc_reload(dbref); /* * list of attributes */ ATTR attr[] = { {"Aahear", A_AAHEAR, AF_ODARK, NULL}, {"Aclone", A_ACLONE, AF_ODARK, NULL}, {"Aconnect", A_ACONNECT, AF_ODARK, NULL}, {"Adesc", A_ADESC, AF_ODARK, NULL}, {"Adfail", A_ADFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Adisconnect", A_ADISCONNECT, AF_ODARK, NULL}, {"Adrop", A_ADROP, AF_ODARK, NULL}, {"Aefail", A_AEFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Aenter", A_AENTER, AF_ODARK, NULL}, {"Afail", A_AFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Agfail", A_AGFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Ahear", A_AHEAR, AF_ODARK, NULL}, {"Akill", A_AKILL, AF_ODARK, NULL}, {"Aleave", A_ALEAVE, AF_ODARK, NULL}, {"Alfail", A_ALFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Alias", A_ALIAS, AF_NOPROG | AF_NOCMD | AF_GOD, NULL}, {"Allowance", A_ALLOWANCE, AF_MDARK | AF_NOPROG | AF_WIZARD, NULL}, {"Amail", A_AMAIL, AF_ODARK | AF_NOPROG, NULL}, {"Amhear", A_AMHEAR, AF_ODARK, NULL}, {"Amove", A_AMOVE, AF_ODARK, NULL}, {"Apay", A_APAY, AF_ODARK, NULL}, {"Arfail", A_ARFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Asucc", A_ASUCC, AF_ODARK, NULL}, {"Atfail", A_ATFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Atport", A_ATPORT, AF_ODARK | AF_NOPROG, NULL}, {"Atofail", A_ATOFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Aufail", A_AUFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Ause", A_AUSE, AF_ODARK, NULL}, {"Away", A_AWAY, AF_ODARK | AF_NOPROG, NULL}, {"Buildcoord", A_BUILDCOORD, AF_MDARK | AF_WIZARD, NULL}, {"Buildentrance", A_BUILDENTRANCE, AF_MDARK | AF_WIZARD, NULL}, {"Buildlinks", A_BUILDLINKS, AF_MDARK | AF_WIZARD, NULL}, {"Charges", A_CHARGES, AF_ODARK | AF_NOPROG, NULL}, {"Comment", A_COMMENT, AF_MDARK | AF_WIZARD, NULL}, {"Contactoptions", A_CONTACTOPT, AF_ODARK, NULL}, {"Cost", A_COST, AF_ODARK, NULL}, {"Daily", A_DAILY, AF_ODARK, NULL}, {"HHourly", A_HOURLY, AF_MDARK, NULL}, {"Desc", A_DESC, AF_NOPROG, NULL}, {"DefaultLock", A_LOCK, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Destroyer", A_DESTROYER, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL}, {"Dfail", A_DFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Drop", A_DROP, AF_ODARK | AF_NOPROG, NULL}, {"DropLock", A_LDROP, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Ealias", A_EALIAS, AF_ODARK | AF_NOPROG, NULL}, {"Efail", A_EFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Enter", A_ENTER, AF_ODARK, NULL}, {"EnterLock", A_LENTER, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Faction", A_FACTION, AF_MDARK | AF_WIZARD, NULL}, {"Fail", A_FAIL, AF_ODARK | AF_NOPROG, NULL}, {"Filter", A_FILTER, AF_ODARK | AF_NOPROG, NULL}, {"Forwardlist", A_FORWARDLIST, AF_ODARK | AF_NOPROG, fwdlist_ck}, {"Gfail", A_GFAIL, AF_ODARK | AF_NOPROG, NULL}, {"GiveLock", A_LGIVE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Heatchars", A_HEATCHARS, AF_ODARK, NULL}, {"Idesc", A_IDESC, AF_ODARK | AF_NOPROG, NULL}, {"Idle", A_IDLE, AF_ODARK | AF_NOPROG, NULL}, {"Infilter", A_INFILTER, AF_ODARK | AF_NOPROG, NULL}, {"Inprefix", A_INPREFIX, AF_ODARK | AF_NOPROG, NULL}, {"Job", A_JOB, AF_MDARK | AF_WIZARD, NULL}, {"Kill", A_KILL, AF_ODARK, NULL}, {"Lalias", A_LALIAS, AF_ODARK | AF_NOPROG, NULL}, {"Last", A_LAST, AF_WIZARD | AF_NOCMD | AF_NOPROG, NULL}, {"Lastname", A_LASTNAME, AF_WIZARD | AF_NOPROG | AF_MDARK, NULL}, {"Lastpage", A_LASTPAGE, AF_INTERNAL | AF_NOCMD | AF_NOPROG | AF_GOD | AF_PRIVATE, NULL}, {"Lastsite", A_LASTSITE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_GOD, NULL}, {"Leave", A_LEAVE, AF_ODARK, NULL}, {"LeaveLock", A_LLEAVE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Lfail", A_LFAIL, AF_ODARK | AF_NOPROG, NULL}, {"LinkLock", A_LLINK, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Listen", A_LISTEN, AF_ODARK, NULL}, {"Logindata", A_LOGINDATA, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, {"LRSheight", A_LRSHEIGHT, AF_ODARK, NULL}, {"Unused1", A_UNUSED1, AF_WIZARD | AF_MDARK, NULL}, {"Mailcurf", A_MAILCURF, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL}, {"Mailflags", A_MAILFLAGS, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL}, {"Mailfolders", A_MAILFOLDERS, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL}, {"Mailmsg", A_MAILMSG, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, {"Mailsub", A_MAILSUB, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, {"Mailsucc", A_MAIL, AF_ODARK | AF_NOPROG, NULL}, {"Mailto", A_MAILTO, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, {"Mapcolor", A_MAPCOLOR, AF_ODARK, NULL}, {"Mapvis", A_MAPVIS, AF_MDARK | AF_WIZARD, NULL}, {"Mechdesc", A_MECHDESC, AF_MDARK, NULL}, {"Mechname", A_MECHNAME, AF_MDARK, NULL}, {"Mechstatus", A_MECHSTATUS, AF_MDARK | AF_WIZARD, NULL}, {"Mechtype", A_MECHTYPE, AF_MDARK, NULL}, {"MechPrefID", A_MECHPREFID, AF_MDARK | AF_WIZARD, NULL}, {"Mechskills", A_MECHSKILLS, AF_MDARK, NULL}, {"Mwtemplate", A_MWTEMPLATE, AF_MDARK, NULL}, {"Move", A_MOVE, AF_ODARK, NULL}, {"Name", A_NAME, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, {"Odesc", A_ODESC, AF_ODARK | AF_NOPROG, NULL}, {"Odfail", A_ODFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Odrop", A_ODROP, AF_ODARK | AF_NOPROG, NULL}, {"Oefail", A_OEFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Oenter", A_OENTER, AF_ODARK, NULL}, {"Ofail", A_OFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Ogfail", A_OGFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Okill", A_OKILL, AF_ODARK, NULL}, {"Amechdest", A_AMECHDEST, AF_MDARK, NULL}, {"Oleave", A_OLEAVE, AF_ODARK, NULL}, {"Olfail", A_OLFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Omove", A_OMOVE, AF_ODARK, NULL}, {"Opay", A_OPAY, AF_ODARK, NULL}, {"Orfail", A_ORFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Osucc", A_OSUCC, AF_ODARK | AF_NOPROG, NULL}, {"Otfail", A_OTFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Otport", A_OTPORT, AF_ODARK | AF_NOPROG, NULL}, {"Otofail", A_OTOFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Oufail", A_OUFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Ouse", A_OUSE, AF_ODARK, NULL}, {"Oxenter", A_OXENTER, AF_ODARK, NULL}, {"Oxleave", A_OXLEAVE, AF_ODARK, NULL}, {"Oxtport", A_OXTPORT, AF_ODARK | AF_NOPROG, NULL}, {"PageLock", A_LPAGE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"ParentLock", A_LPARENT, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Pay", A_PAY, AF_ODARK, NULL}, {"PCequip", A_PCEQUIP, AF_MDARK, NULL}, {"Pilot", A_PILOTNUM, AF_MDARK, NULL}, {"Prefix", A_PREFIX, AF_ODARK | AF_NOPROG, NULL}, {"ProgCmd", A_PROGCMD, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, {"QueueMax", A_QUEUEMAX, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL}, {"Quota", A_QUOTA, AF_MDARK | AF_NOPROG | AF_GOD | AF_NOCMD, NULL}, {"Ranknum", A_RANKNUM, AF_MDARK | AF_WIZARD, NULL}, {"ReceiveLock", A_LRECEIVE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Reject", A_REJECT, AF_ODARK | AF_NOPROG, NULL}, {"Rfail", A_RFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Rquota", A_RQUOTA, AF_MDARK | AF_NOPROG | AF_GOD | AF_NOCMD, NULL}, {"Runout", A_RUNOUT, AF_ODARK, NULL}, {"Semaphore", A_SEMAPHORE, AF_ODARK | AF_NOPROG | AF_WIZARD | AF_NOCMD, NULL}, {"Sex", A_SEX, AF_NOPROG, NULL}, {"Signature", A_SIGNATURE, AF_ODARK | AF_NOPROG, NULL}, {"SpeechLock", A_LSPEECH, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Startup", A_STARTUP, AF_ODARK, NULL}, {"Succ", A_SUCC, AF_ODARK | AF_NOPROG, NULL}, {"Tacsize", A_TACSIZE, AF_ODARK, NULL}, {"TeloutLock", A_LTELOUT, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Tfail", A_TFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Timeout", A_TIMEOUT, AF_MDARK | AF_NOPROG | AF_WIZARD, NULL}, {"Tport", A_TPORT, AF_ODARK | AF_NOPROG, NULL}, {"TportLock", A_LTPORT, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"Tofail", A_TOFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Tz", A_TZ, AF_NOPROG, NULL}, {"Ufail", A_UFAIL, AF_ODARK | AF_NOPROG, NULL}, {"Use", A_USE, AF_ODARK, NULL}, {"UseLock", A_LUSE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"UserLock", A_LUSER, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK, NULL}, {"VA", A_VA, AF_ODARK, NULL}, {"VB", A_VA + 1, AF_ODARK, NULL}, {"VC", A_VA + 2, AF_ODARK, NULL}, {"VD", A_VA + 3, AF_ODARK, NULL}, {"VE", A_VA + 4, AF_ODARK, NULL}, {"VF", A_VA + 5, AF_ODARK, NULL}, {"VG", A_VA + 6, AF_ODARK, NULL}, {"VH", A_VA + 7, AF_ODARK, NULL}, {"VI", A_VA + 8, AF_ODARK, NULL}, {"VJ", A_VA + 9, AF_ODARK, NULL}, {"VK", A_VA + 10, AF_ODARK, NULL}, {"VL", A_VA + 11, AF_ODARK, NULL}, {"VM", A_VA + 12, AF_ODARK, NULL}, {"VN", A_VA + 13, AF_ODARK, NULL}, {"VO", A_VA + 14, AF_ODARK, NULL}, {"VP", A_VA + 15, AF_ODARK, NULL}, {"VQ", A_VA + 16, AF_ODARK, NULL}, {"VR", A_VA + 17, AF_ODARK, NULL}, {"VS", A_VA + 18, AF_ODARK, NULL}, {"VT", A_VA + 19, AF_ODARK, NULL}, {"VU", A_VA + 20, AF_ODARK, NULL}, {"VV", A_VA + 21, AF_ODARK, NULL}, {"VW", A_VA + 22, AF_ODARK, NULL}, {"VX", A_VA + 23, AF_ODARK, NULL}, {"VY", A_VA + 24, AF_ODARK, NULL}, {"VZ", A_VA + 25, AF_ODARK, NULL}, {"Xtype", A_XTYPE, AF_MDARK | AF_WIZARD, NULL}, {"*Password", A_PASS, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, {"*Privileges", A_PRIVS, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, {"*Money", A_MONEY, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, {"Techtime", A_TECHTIME, AF_MDARK | AF_WIZARD, NULL}, {"*EconParts", A_ECONPARTS, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL}, #if 1 #define PLSTAT_MODE (AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL) #else #define PLSTAT_MODE (AF_MDARK|AF_WIZARD) #endif {"PLHEALTH", A_HEALTH, PLSTAT_MODE, NULL}, {"PLATTRS", A_ATTRS, PLSTAT_MODE, NULL}, {"PLADVS", A_ADVS, PLSTAT_MODE, NULL}, {"PLSKILLS", A_SKILLS, PLSTAT_MODE, NULL}, {NULL, 0, 0, NULL} }; /* * --------------------------------------------------------------------------- * * fwdlist_set, fwdlist_clr: Manage cached forwarding lists */ void fwdlist_set(dbref thing, FWDLIST * ifp) { FWDLIST *fp, *xfp; int i; /* * If fwdlist is null, clear */ if(!ifp || (ifp->count <= 0)) { fwdlist_clr(thing); return; } /* * Copy input forwardlist to a correctly-sized buffer */ fp = (FWDLIST *) XMALLOC(sizeof(int) * ((ifp->count) + 1), "fwdlist_set"); for(i = 0; i < ifp->count; i++) { fp->data[i] = ifp->data[i]; } fp->count = ifp->count; /* * Replace an existing forwardlist, or add a new one */ xfp = fwdlist_get(thing); if(xfp) { XFREE(xfp, "fwdlist_set"); nhashrepl(thing, (int *) fp, &mudstate.fwdlist_htab); } else { nhashadd(thing, (int *) fp, &mudstate.fwdlist_htab); } } void fwdlist_clr(dbref thing) { FWDLIST *xfp; /* * If a forwardlist exists, delete it */ xfp = fwdlist_get(thing); if(xfp) { XFREE(xfp, "fwdlist_clr"); nhashdelete(thing, &mudstate.fwdlist_htab); } } /* * --------------------------------------------------------------------------- * * fwdlist_load: Load text into a forwardlist. */ int fwdlist_load(FWDLIST * fp, dbref player, char *atext) { dbref target; char *tp, *bp, *dp; int count, errors, fail; count = 0; errors = 0; bp = tp = alloc_lbuf("fwdlist_load.str"); StringCopy(tp, atext); do { for(; *bp && isspace(*bp); bp++); /* * skip spaces */ for(dp = bp; *bp && !isspace(*bp); bp++); /* * remember * * * * * * * * * * * * * * string */ if(*bp) *bp++ = '\0'; /* * terminate string */ if((*dp++ == '#') && isdigit(*dp)) { target = atoi(dp); fail = (!Good_obj(target) || (!God(player) && !controls(player, target) && (!Link_ok(target) || !could_doit(player, target, A_LLINK)))); if(fail) { notify_printf(player, "Cannot forward to #%d: Permission denied.", target); errors++; } else { fp->data[count++] = target; } } } while (*bp); free_lbuf(tp); fp->count = count; return errors; } /* * --------------------------------------------------------------------------- * * fwdlist_rewrite: Generate a text string from a FWDLIST buffer. */ int fwdlist_rewrite(FWDLIST * fp, char *atext) { char *tp, *bp; int i, count; if(fp && fp->count) { count = fp->count; tp = alloc_sbuf("fwdlist_rewrite.errors"); bp = atext; for(i = 0; i < fp->count; i++) { if(Good_obj(fp->data[i])) { sprintf(tp, "#%d ", fp->data[i]); safe_str(tp, atext, &bp); } else { count--; } } *bp = '\0'; free_sbuf(tp); } else { count = 0; *atext = '\0'; } return count; } /* * --------------------------------------------------------------------------- * * fwdlist_ck: Check a list of dbref numbers to forward to for AUDIBLE */ int fwdlist_ck(int key, dbref player, dbref thing, int anum, char *atext) { FWDLIST *fp; int count; count = 0; if(atext && *atext) { fp = (FWDLIST *) alloc_lbuf("fwdlist_ck.fp"); fwdlist_load(fp, player, atext); } else { fp = NULL; } /* * Set the cached forwardlist */ fwdlist_set(thing, fp); count = fwdlist_rewrite(fp, atext); if(fp) free_lbuf(fp); return ((count > 0) || !atext || !*atext); } FWDLIST *fwdlist_get(dbref thing) { FWDLIST *fp; fp = ((FWDLIST *) nhashfind(thing, &mudstate.fwdlist_htab)); return fp; } static char *set_string(char **ptr, char *new) { /* * if pointer not null unalloc it */ if(*ptr) XFREE(*ptr, "set_string"); /* * if new string is not null allocate space for it and copy it */ if(!new) /* * * || !*new */ return (*ptr = NULL); /* * Check with GAC about this */ *ptr = (char *) XMALLOC(strlen(new) + 1, "set_string"); StringCopy(*ptr, new); return (*ptr); } /* * --------------------------------------------------------------------------- * * Name, s_Name: Get or set an object's name. */ INLINE char *Name(dbref thing) { dbref aowner; int aflags; char *buff; static char *tbuff[MBUF_SIZE]; char buffer[MBUF_SIZE]; if(mudconf.cache_names) { if(thing > mudstate.db_top || thing < 0) { return "#-1 INVALID DBREF"; } if(!purenames[thing]) { buff = atr_get(thing, A_NAME, &aowner, &aflags); strip_ansi_r(buffer, buff, MBUF_SIZE); set_string(&purenames[thing], buffer); free_lbuf(buff); } } atr_get_str((char *) tbuff, thing, A_NAME, &aowner, &aflags); return ((char *) tbuff); } INLINE char *PureName(dbref thing) { dbref aowner; int aflags; char *buff; static char *tbuff[LBUF_SIZE]; if(mudconf.cache_names) { if(thing > mudstate.db_top || thing < 0) { return "#-1 INVALID DBREF"; } if(!purenames[thing]) { buff = atr_get(thing, A_NAME, &aowner, &aflags); set_string(&purenames[thing], strip_ansi(buff)); free_lbuf(buff); } return purenames[thing]; } atr_get_str((char *) tbuff, thing, A_NAME, &aowner, &aflags); return (strip_ansi((char *) tbuff)); } INLINE void s_Name(dbref thing, char *s) { /* Truncate the name if we have to */ if(s && (strlen(s) > MBUF_SIZE)) s[MBUF_SIZE] = '\0'; atr_add_raw(thing, A_NAME, (char *) s); if(mudconf.cache_names) { set_string(&purenames[thing], strip_ansi((char *) s)); } } void s_Pass(dbref thing, const char *s) { atr_add_raw(thing, A_PASS, (char *) s); } /* * --------------------------------------------------------------------------- * * do_attrib: Manage user-named attributes. */ extern NAMETAB attraccess_nametab[]; void do_attribute(dbref player, dbref cause, int key, char *aname, char *value) { int success, negate, f; char *buff, *sp, *p, *q; VATTR *va; ATTR *va2; /* * Look up the user-named attribute we want to play with */ buff = alloc_sbuf("do_attribute"); for(p = buff, q = aname; *q && ((p - buff) < (SBUF_SIZE - 1)); p++, q++) *p = ToUpper(*q); *p = '\0'; va = (VATTR *) vattr_find(buff); if(!va) { notify(player, "No such user-named attribute."); free_sbuf(buff); return; } switch (key) { case ATTRIB_ACCESS: /* * Modify access to user-named attribute */ for(sp = value; *sp; sp++) *sp = ToUpper(*sp); sp = strtok(value, " "); success = 0; while (sp != NULL) { /* * Check for negation */ negate = 0; if(*sp == '!') { negate = 1; sp++; } /* * Set or clear the appropriate bit */ f = search_nametab(player, attraccess_nametab, sp); if(f > 0) { success = 1; if(negate) va->flags &= ~f; else va->flags |= f; } else { notify_printf(player, "Unknown permission: %s.", sp); } /* * Get the next token */ sp = strtok(NULL, " "); } if(success && !Quiet(player)) notify(player, "Attribute access changed."); break; case ATTRIB_RENAME: /* * Make sure the new name doesn't already exist */ va2 = atr_str(value); if(va2) { notify(player, "An attribute with that name already exists."); free_sbuf(buff); return; } if(vattr_rename(va->name, value) == NULL) notify(player, "Attribute rename failed."); else notify(player, "Attribute renamed."); break; case ATTRIB_DELETE: /* * Remove the attribute */ vattr_delete(buff); notify(player, "Attribute deleted."); break; } free_sbuf(buff); return; } /* * --------------------------------------------------------------------------- * * do_fixdb: Directly edit database fields */ void do_fixdb(dbref player, dbref cause, int key, char *arg1, char *arg2) { dbref thing, res; init_match(player, arg1, NOTYPE); match_everything(0); thing = noisy_match_result(); if(thing == NOTHING) return; res = NOTHING; switch (key) { case FIXDB_OWNER: case FIXDB_LOC: case FIXDB_CON: case FIXDB_EXITS: case FIXDB_NEXT: init_match(player, arg2, NOTYPE); match_everything(0); res = noisy_match_result(); break; case FIXDB_PENNIES: res = atoi(arg2); break; } switch (key) { case FIXDB_OWNER: s_Owner(thing, res); if(!Quiet(player)) notify_printf(player, "Owner set to #%d", res); break; case FIXDB_LOC: s_Location(thing, res); if(!Quiet(player)) notify_printf(player, "Location set to #%d", res); break; case FIXDB_CON: s_Contents(thing, res); if(!Quiet(player)) notify_printf(player, "Contents set to #%d", res); break; case FIXDB_EXITS: s_Exits(thing, res); if(!Quiet(player)) notify_printf(player, "Exits set to #%d", res); break; case FIXDB_NEXT: s_Next(thing, res); if(!Quiet(player)) notify_printf(player, "Next set to #%d", res); break; case FIXDB_PENNIES: s_Pennies(thing, res); if(!Quiet(player)) notify_printf(player, "Pennies set to %d", res); break; case FIXDB_NAME: if(Typeof(thing) == TYPE_PLAYER) { if(!ok_player_name(arg2)) { notify(player, "That's not a good name for a player."); return; } if(lookup_player(NOTHING, arg2, 0) != NOTHING) { notify(player, "That name is already in use."); return; } STARTLOG(LOG_SECURITY, "SEC", "CNAME") { log_name(thing), log_text((char *) " renamed to "); log_text(arg2); ENDLOG; } if(Suspect(player)) { send_channel("Suspect", "%s renamed to %s", Name(thing), arg2); } delete_player_name(thing, Name(thing)); s_Name(thing, arg2); add_player_name(thing, arg2); } else { if(!ok_name(arg2)) { notify(player, "Warning: That is not a reasonable name."); } s_Name(thing, arg2); } if(!Quiet(player)) notify_printf(player, "Name set to %s", arg2); break; } } /* * --------------------------------------------------------------------------- * * init_attrtab: Initialize the attribute hash tables. */ void init_attrtab(void) { ATTR *a; char *buff, *p, *q; hashinit(&mudstate.attr_name_htab, 512); buff = alloc_sbuf("init_attrtab"); for(a = attr; a->number; a++) { anum_extend(a->number); anum_set(a->number, a); for(p = buff, q = (char *) a->name; *q; p++, q++) *p = ToUpper(*q); *p = '\0'; hashadd(buff, (int *) a, &mudstate.attr_name_htab); } free_sbuf(buff); } /* * --------------------------------------------------------------------------- * * atr_str: Look up an attribute by name. */ ATTR *atr_str(char *s) { char *buff, *p, *q; ATTR *a; VATTR *va; static ATTR tattr; if(!s || !*s) { return (NULL); } /* * Convert the buffer name to lowercase */ buff = alloc_sbuf("atr_str"); for(p = buff, q = s; *q && ((p - buff) < (SBUF_SIZE - 1)); p++, q++) *p = ToUpper(*q); *p = '\0'; /* * Look for a predefined attribute */ a = (ATTR *) hashfind(buff, &mudstate.attr_name_htab); if(a != NULL) { free_sbuf(buff); return a; } /* * Nope, look for a user attribute */ va = (VATTR *) vattr_find(buff); free_sbuf(buff); /* * If we got one, load tattr and return a pointer to it. */ if(va != NULL) { tattr.name = va->name; tattr.number = va->number; tattr.flags = va->flags; tattr.check = NULL; return &tattr; } /* * All failed, return NULL */ return NULL; } /* * --------------------------------------------------------------------------- * * anum_extend: Grow the attr num lookup table. */ ATTR **anum_table = NULL; int anum_alc_top = 0; void anum_extend(int newtop) { ATTR **anum_table2; int delta, i; delta = mudconf.init_size; if(newtop <= anum_alc_top) return; if(newtop < anum_alc_top + delta) newtop = anum_alc_top + delta; if(anum_table == NULL) { anum_table = (ATTR **) malloc((newtop + 1) * sizeof(ATTR *)); for(i = 0; i <= newtop; i++) anum_table[i] = NULL; } else { anum_table2 = (ATTR **) malloc((newtop + 1) * sizeof(ATTR *)); for(i = 0; i <= anum_alc_top; i++) anum_table2[i] = anum_table[i]; for(i = anum_alc_top + 1; i <= newtop; i++) anum_table2[i] = NULL; free((char *) anum_table); anum_table = anum_table2; } anum_alc_top = newtop; } /* * --------------------------------------------------------------------------- * * atr_num: Look up an attribute by number. */ ATTR *atr_num(int anum) { VATTR *va; static ATTR tattr; /* * Look for a predefined attribute */ if(anum < A_USER_START) return anum_get(anum); if(anum >= anum_alc_top) return NULL; /* * It's a user-defined attribute, we need to copy data */ va = (VATTR *) anum_get(anum); if(va != NULL) { tattr.name = va->name; tattr.number = va->number; tattr.flags = va->flags; tattr.check = NULL; return &tattr; } /* * All failed, return NULL */ return NULL; } /* * --------------------------------------------------------------------------- * * mkattr: Lookup attribute by name, creating if needed. */ int mkattr(char *buff) { ATTR *ap; VATTR *va; if(!(ap = atr_str(buff))) { /* * Unknown attr, create a new one */ va = vattr_alloc(buff, mudconf.vattr_flags); if(!va || !(va->number)) return -1; return va->number; } if(!(ap->number)) return -1; return ap->number; } /* * --------------------------------------------------------------------------- * * Commer: check if an object has any $-commands in its attributes. */ int Commer(dbref thing) { char *s, *as, c; int attr, aflags; dbref aowner; ATTR *ap; for(attr = atr_head(thing, &as); attr; attr = atr_next(&as)) { ap = atr_num(attr); if(!ap || (ap->flags & AF_NOPROG)) continue; s = atr_get(thing, attr, &aowner, &aflags); c = *s; free_lbuf(s); if((c == '$') && !(aflags & AF_NOPROG)) { return 1; } } return 0; } /* * routines to handle object attribute lists */ /* * --------------------------------------------------------------------------- * * atr_encode: Encode an attribute string. */ static char *atr_encode(char *iattr, dbref thing, dbref owner, int flags, int atr) { /* * If using the default owner and flags (almost all attributes will), * * * * * * * just store the string. */ if(((owner == Owner(thing)) || (owner == NOTHING)) && !flags) return iattr; /* * Encode owner and flags into the attribute text */ if(owner == NOTHING) owner = Owner(thing); return tprintf("%c%d:%d:%s", ATR_INFO_CHAR, owner, flags, iattr); } /* * --------------------------------------------------------------------------- * * atr_decode: Decode an attribute string. */ static void atr_decode(char *iattr, char *oattr, dbref thing, dbref * owner, int *flags, int atr) { char *cp; int neg; /* * See if the first char of the attribute is the special character */ if(*iattr == ATR_INFO_CHAR) { /* * It is, crack the attr apart */ cp = &iattr[1]; /* * Get the attribute owner */ *owner = 0; neg = 0; if(*cp == '-') { neg = 1; cp++; } while (isdigit(*cp)) { *owner = (*owner * 10) + (*cp++ - '0'); } if(neg) *owner = 0 - *owner; /* * If delimiter is not ':', just return attribute */ if(*cp++ != ':') { *owner = Owner(thing); *flags = 0; if(oattr) { StringCopy(oattr, iattr); } return; } /* * Get the attribute flags */ *flags = 0; while (isdigit(*cp)) { *flags = (*flags * 10) + (*cp++ - '0'); } /* * If delimiter is not ':', just return attribute */ if(*cp++ != ':') { *owner = Owner(thing); *flags = 0; if(oattr) { StringCopy(oattr, iattr); } } /* * Get the attribute text */ if(oattr) { StringCopy(oattr, cp); } if(*owner == NOTHING) *owner = Owner(thing); } else { /* * Not the special character, return normal info */ *owner = Owner(thing); *flags = 0; if(oattr) { StringCopy(oattr, iattr); } } } /* * --------------------------------------------------------------------------- * * atr_clr: clear an attribute in the list. */ void atr_clr(dbref thing, int atr) { ATRLIST *list; int hi, lo, mid; if(!db[thing].at_count || !db[thing].ahead) return; if(db[thing].at_count < 0) abort(); /* * Binary search for the attribute. */ lo = 0; hi = db[thing].at_count - 1; list = db[thing].ahead; while (lo <= hi) { mid = ((hi - lo) >> 1) + lo; if(list[mid].number == atr) { free(list[mid].data); db[thing].at_count -= 1; if(mid != db[thing].at_count) bcopy((char *) (list + mid + 1), (char *) (list + mid), (db[thing].at_count - mid) * sizeof(ATRLIST)); break; } else if(list[mid].number > atr) { hi = mid - 1; } else { lo = mid + 1; } } switch (atr) { case A_STARTUP: s_Flags(thing, Flags(thing) & ~HAS_STARTUP); break; case A_DAILY: s_Flags2(thing, Flags2(thing) & ~HAS_DAILY); break; case A_HOURLY: s_Flags2(thing, Flags2(thing) & ~HAS_HOURLY); break; case A_FORWARDLIST: s_Flags2(thing, Flags2(thing) & ~HAS_FWDLIST); break; case A_LISTEN: s_Flags2(thing, Flags2(thing) & ~HAS_LISTEN); break; case A_TIMEOUT: desc_reload(thing); break; case A_QUEUEMAX: pcache_reload(thing); break; } } /* * --------------------------------------------------------------------------- * * atr_add_raw, atr_add: add attribute of type atr to list */ void atr_add_raw(dbref thing, int atr, char *buff) { ATRLIST *list; char *text; int found = 0; int hi, lo, mid; if(!buff || !*buff) { atr_clr(thing, atr); return; } if(strlen(buff) >= LBUF_SIZE) { buff[LBUF_SIZE - 1] = '\0'; } if((text = (char *) malloc(strlen(buff) + 1)) == NULL) { return; } StringCopy(text, buff); if(!db[thing].ahead) { if((list = (ATRLIST *) malloc(sizeof(ATRLIST))) == NULL) { free(text); return; } db[thing].ahead = list; db[thing].at_count = 1; list[0].number = atr; list[0].data = text; list[0].size = strlen(text) + 1; found = 1; } else { /* * Binary search for the attribute */ lo = 0; hi = db[thing].at_count - 1; list = db[thing].ahead; while (lo <= hi) { mid = ((hi - lo) >> 1) + lo; if(list[mid].number == atr) { free(list[mid].data); list[mid].data = text; list[mid].size = strlen(text) + 1; found = 1; break; } else if(list[mid].number > atr) { hi = mid - 1; } else { lo = mid + 1; } } if(!found) { /* * If we got here, we didn't find it, so lo = hi + 1, * and the attribute should be inserted between them. */ list = (ATRLIST *) realloc(db[thing].ahead, (db[thing].at_count + 1) * sizeof(ATRLIST)); if(!list) return; /* * Move the stuff upwards one slot */ if(lo < db[thing].at_count) bcopy((char *) (list + lo), (char *) (list + lo + 1), (db[thing].at_count - lo) * sizeof(ATRLIST)); list[lo].data = text; list[lo].number = atr; list[lo].size = strlen(text) + 1; db[thing].at_count++; db[thing].ahead = list; } } switch (atr) { case A_STARTUP: s_Flags(thing, Flags(thing) | HAS_STARTUP); break; case A_DAILY: s_Flags2(thing, Flags2(thing) | HAS_DAILY); break; case A_HOURLY: s_Flags2(thing, Flags2(thing) | HAS_HOURLY); break; case A_FORWARDLIST: s_Flags2(thing, Flags2(thing) | HAS_FWDLIST); break; case A_LISTEN: s_Flags2(thing, Flags2(thing) | HAS_LISTEN); break; case A_TIMEOUT: desc_reload(thing); break; case A_QUEUEMAX: pcache_reload(thing); break; } } void atr_add(dbref thing, int atr, char *buff, dbref owner, int flags) { char *tbuff; if(!buff || !*buff) { atr_clr(thing, atr); } else { tbuff = atr_encode(buff, thing, owner, flags, atr); atr_add_raw(thing, atr, tbuff); } } void atr_set_owner(dbref thing, int atr, dbref owner) { dbref aowner; int aflags; char *buff; buff = atr_get(thing, atr, &aowner, &aflags); atr_add(thing, atr, buff, owner, aflags); free_lbuf(buff); } void atr_set_flags(dbref thing, int atr, dbref flags) { dbref aowner; int aflags; char *buff; buff = atr_get(thing, atr, &aowner, &aflags); atr_add(thing, atr, buff, aowner, flags); free_lbuf(buff); } /* * --------------------------------------------------------------------------- * * get_atr,atr_get_raw, atr_get_str, atr_get: Get an attribute from the database. */ int get_atr(char *name) { ATTR *ap; if(!(ap = atr_str(name))) return 0; if(!(ap->number)) return -1; return ap->number; } char *atr_get_raw(dbref thing, int atr) { int lo, mid, hi; ATRLIST *list; if(thing < 0) return NULL; /* * Binary search for the attribute */ lo = 0; hi = db[thing].at_count - 1; list = db[thing].ahead; if(!list) return NULL; while (lo <= hi) { mid = ((hi - lo) >> 1) + lo; if(list[mid].number == atr) { return list[mid].data; } else if(list[mid].number > atr) { hi = mid - 1; } else { lo = mid + 1; } } return NULL; } char *atr_get_str(char *s, dbref thing, int atr, dbref * owner, int *flags) { char *buff; buff = atr_get_raw(thing, atr); if(!buff) { *owner = Owner(thing); *flags = 0; *s = '\0'; } else { atr_decode(buff, s, thing, owner, flags, atr); } return s; } char *atr_get(dbref thing, int atr, dbref * owner, int *flags) { char *buff; buff = alloc_lbuf("atr_get"); return atr_get_str(buff, thing, atr, owner, flags); } int atr_get_info(dbref thing, int atr, dbref * owner, int *flags) { char *buff; buff = atr_get_raw(thing, atr); if(!buff) { *owner = Owner(thing); *flags = 0; return 0; } atr_decode(buff, NULL, thing, owner, flags, atr); return 1; } char *atr_pget_str(char *s, dbref thing, int atr, dbref * owner, int *flags) { char *buff; dbref parent; int lev; ATTR *ap; ITER_PARENTS(thing, parent, lev) { buff = atr_get_raw(parent, atr); if(buff && *buff) { atr_decode(buff, s, thing, owner, flags, atr); if((lev == 0) || !(*flags & AF_PRIVATE)) return s; } if((lev == 0) && Good_obj(Parent(parent))) { ap = atr_num(atr); if(!ap || ap->flags & AF_PRIVATE) break; } } *owner = Owner(thing); *flags = 0; *s = '\0'; return s; } char *atr_pget(dbref thing, int atr, dbref * owner, int *flags) { char *buff; buff = alloc_lbuf("atr_pget"); return atr_pget_str(buff, thing, atr, owner, flags); } int atr_pget_info(dbref thing, int atr, dbref * owner, int *flags) { char *buff; dbref parent; int lev; ATTR *ap; ITER_PARENTS(thing, parent, lev) { buff = atr_get_raw(parent, atr); if(buff && *buff) { atr_decode(buff, NULL, thing, owner, flags, atr); if((lev == 0) || !(*flags & AF_PRIVATE)) return 1; } if((lev == 0) && Good_obj(Parent(parent))) { ap = atr_num(atr); if(!ap || ap->flags & AF_PRIVATE) break; } } *owner = Owner(thing); *flags = 0; return 0; } /* * --------------------------------------------------------------------------- * * atr_free: Return all attributes of an object. */ void atr_free(dbref thing) { free(db[thing].ahead); db[thing].ahead = NULL; } /* * garbage collect an attribute list */ void atr_collect(dbref thing) { /* * Nada. gdbm takes care of us. I hope ;-) */ } /* * --------------------------------------------------------------------------- * * atr_cpy: Copy all attributes from one object to another. Takes the * * player argument to ensure that only attributes that COULD be set by * * the player are copied. */ void atr_cpy(dbref player, dbref dest, dbref source) { int attr, aflags; dbref owner, aowner; char *as, *buf; ATTR *at; owner = Owner(dest); for(attr = atr_head(source, &as); attr; attr = atr_next(&as)) { buf = atr_get(source, attr, &aowner, &aflags); if(!(aflags & AF_LOCK)) aowner = owner; /* * chg owner */ at = atr_num(attr); if(attr && at) { if(Write_attr(owner, dest, at, aflags)) /* * Only set attrs that owner has perm to set */ atr_add(dest, attr, buf, aowner, aflags); } free_lbuf(buf); } } /* * --------------------------------------------------------------------------- * * atr_chown: Change the ownership of the attributes of an object to the * * current owner if they are not locked. */ void atr_chown(dbref obj) { int attr, aflags; dbref owner, aowner; char *as, *buf; owner = Owner(obj); for(attr = atr_head(obj, &as); attr; attr = atr_next(&as)) { buf = atr_get(obj, attr, &aowner, &aflags); if((aowner != owner) && !(aflags & AF_LOCK)) atr_add(obj, attr, buf, owner, aflags); free_lbuf(buf); } } /* * --------------------------------------------------------------------------- * * atr_next: Return next attribute in attribute list. */ int atr_next(char **attrp) { ATRCOUNT *atr; if(!attrp || !*attrp) { return 0; } else { atr = (ATRCOUNT *) * attrp; if(atr->count > db[atr->thing].at_count) { free(atr); return 0; } atr->count++; return db[atr->thing].ahead[atr->count - 2].number; } } /* * --------------------------------------------------------------------------- * * atr_head: Returns the head of the attr list for object 'thing' */ int atr_head(dbref thing, char **attrp) { ATRCOUNT *atr; if(db[thing].at_count) { atr = (ATRCOUNT *) malloc(sizeof(ATRCOUNT)); atr->thing = thing; atr->count = 2; *attrp = (char *) atr; return db[thing].ahead[0].number; } return 0; } /* * --------------------------------------------------------------------------- * * db_grow: Extend the struct database. */ #define SIZE_HACK 1 /* * * So mistaken refs to #-1 won't die. */ void initialize_objects(dbref first, dbref last) { dbref thing; for(thing = first; thing < last; thing++) { memset(&db[thing], 0, sizeof(db[0])); s_Owner(thing, GOD); s_Flags(thing, (TYPE_GARBAGE | GOING)); s_Flags2(thing, 0); s_Flags3(thing, 0); s_Powers(thing, 0); s_Powers2(thing, 0); s_Location(thing, NOTHING); s_Contents(thing, NOTHING); s_Exits(thing, NOTHING); s_Link(thing, NOTHING); s_Next(thing, NOTHING); s_Zone(thing, NOTHING); s_Parent(thing, NOTHING); s_Stack(thing, NULL); db[thing].ahead = NULL; db[thing].at_count = 0; } } void db_grow(dbref newtop) { int newsize, marksize, delta, i; MARKBUF *newmarkbuf; OBJ *newdb; NAME *newpurenames; char *cp; delta = mudconf.init_size; /* * Determine what to do based on requested size, current top and * * * * * * * * * * * size. Make sure we grow in reasonable-sized * chunks to * * prevent * * * * frequent reallocations of the db * array. */ /* * If requested size is smaller than the current db size, ignore it */ if(newtop <= mudstate.db_top) { return; } /* * If requested size is greater than the current db size but smaller * * * * * * * than the amount of space we have allocated, raise the * db * * * size * * and * initialize the new area. */ if(newtop <= mudstate.db_size) { for(i = mudstate.db_top; i < newtop; i++) { if(mudconf.cache_names) purenames[i] = NULL; } initialize_objects(mudstate.db_top, newtop); mudstate.db_top = newtop; return; } /* * Grow by a minimum of delta objects */ if(newtop <= mudstate.db_size + delta) { newsize = mudstate.db_size + delta; } else { newsize = newtop; } /* * Enforce minimumdatabase size */ if(newsize < mudstate.min_size) newsize = mudstate.min_size + delta;; /* * Grow the name tables */ if(mudconf.cache_names) { newpurenames = (NAME *) XMALLOC((newsize + SIZE_HACK) * sizeof(NAME), "db_grow.purenames"); if(!newpurenames) { LOG_SIMPLE(LOG_ALWAYS, "ALC", "DB", tprintf ("Could not allocate space for %d item name cache.", newsize)); abort(); } bzero((char *) newpurenames, (newsize + SIZE_HACK) * sizeof(NAME)); if(purenames) { /* * An old name cache exists. Copy it. */ purenames -= SIZE_HACK; bcopy((char *) purenames, (char *) newpurenames, (newtop + SIZE_HACK) * sizeof(NAME)); cp = (char *) purenames; XFREE(cp, "db_grow.purename"); } else { /* * Creating a brand new struct database. Fill in the * 'reserved' area in case it gets referenced. */ purenames = newpurenames; for(i = 0; i < SIZE_HACK; i++) { purenames[i] = NULL; } } purenames = newpurenames + SIZE_HACK; newpurenames = NULL; } /* * Grow the db array */ newdb = (OBJ *) XMALLOC((newsize + SIZE_HACK) * sizeof(OBJ), "db_grow.db"); if(!newdb) { LOG_SIMPLE(LOG_ALWAYS, "ALC", "DB", tprintf ("Could not allocate space for %d item struct database.", newsize)); abort(); } if(db) { /* * An old struct database exists. Copy it to the new buffer */ db -= SIZE_HACK; bcopy((char *) db, (char *) newdb, (mudstate.db_top + SIZE_HACK) * sizeof(OBJ)); cp = (char *) db; XFREE(cp, "db_grow.db"); } else { /* * Creating a brand new struct database. Fill in the * * * * * * * * * 'reserved' area in case it gets referenced. */ db = newdb; for(i = 0; i < SIZE_HACK; i++) { s_Owner(i, GOD); s_Flags(i, (TYPE_GARBAGE | GOING)); s_Powers(i, 0); s_Powers2(i, 0); s_Location(i, NOTHING); s_Contents(i, NOTHING); s_Exits(i, NOTHING); s_Link(i, NOTHING); s_Next(i, NOTHING); s_Zone(i, NOTHING); s_Parent(i, NOTHING); s_Stack(i, NULL); db[i].ahead = NULL; db[i].at_count = 0; } } db = newdb + SIZE_HACK; newdb = NULL; for(i = mudstate.db_top; i < newtop; i++) { if(mudconf.cache_names) { purenames[i] = NULL; } } initialize_objects(mudstate.db_top, newtop); mudstate.db_top = newtop; mudstate.db_size = newsize; /* * Grow the db mark buffer */ marksize = (newsize + 7) >> 3; newmarkbuf = (MARKBUF *) XMALLOC(marksize, "db_grow"); bzero((char *) newmarkbuf, marksize); if(mudstate.markbits) { marksize = (newtop + 7) >> 3; bcopy((char *) mudstate.markbits, (char *) newmarkbuf, marksize); cp = (char *) mudstate.markbits; XFREE(cp, "db_grow"); } mudstate.markbits = newmarkbuf; } void db_free(void) { char *cp; if(db != NULL) { db -= SIZE_HACK; cp = (char *) db; XFREE(cp, "db_grow"); db = NULL; } mudstate.db_top = 0; mudstate.db_size = 0; mudstate.freelist = NOTHING; } void db_make_minimal(void) { dbref obj; db_free(); db_grow(1); s_Name(0, "Limbo"); s_Flags(0, TYPE_ROOM); s_Powers(0, 0); s_Powers2(0, 0); s_Location(0, NOTHING); s_Exits(0, NOTHING); s_Link(0, NOTHING); s_Parent(0, NOTHING); s_Zone(0, NOTHING); s_Pennies(0, 1); s_Owner(0, 1); db[0].ahead = NULL; db[0].at_count = 0; /* * should be #1 */ load_player_names(); obj = create_player((char *) "Wizard", (char *) "potrzebie", NOTHING, 0, 0); s_Flags(obj, Flags(obj) | WIZARD); s_Powers(obj, 0); s_Powers2(obj, 0); s_Pennies(obj, 1000); /* * Manually link to Limbo, just in case */ s_Location(obj, 0); s_Next(obj, NOTHING); s_Contents(0, obj); s_Link(obj, 0); } dbref parse_dbref(const char *s) { const char *p; int x; /* * Enforce completely numeric dbrefs */ for(p = s; *p; p++) { if(!isdigit(*p)) return NOTHING; } x = atoi(s); return ((x >= 0) ? x : NOTHING); } void putref(FILE * f, dbref ref) { fprintf(f, "%d\n", ref); } void putstring(FILE * f, const char *s) { putc('"', f); while (s && *s) { switch (*s) { case '\\': case '"': putc('\\', f); default: putc(*s, f); } s++; } putc('"', f); putc('\n', f); } const char *getstring_noalloc(FILE * f, int new_strings) { static char buf[LBUF_SIZE]; char *p; int c, lastc; p = buf; c = fgetc(f); if(!new_strings || (c != '"')) { ungetc(c, f); c = '\0'; for(;;) { lastc = c; c = fgetc(f); /* * If EOF or null, return */ if(!c || (c == EOF)) { *p = '\0'; return buf; } /* * If a newline, return if prior char is not a cr. * * * * Otherwise * keep on truckin' */ if((c == '\n') && (lastc != '\r')) { *p = '\0'; return buf; } safe_chr(c, buf, &p); } } else { for(;;) { c = fgetc(f); if(c == '"') { if((c = fgetc(f)) != '\n') ungetc(c, f); *p = '\0'; return buf; } else if(c == '\\') { c = fgetc(f); } if((c == '\0') || (c == EOF)) { *p = '\0'; return buf; } safe_chr(c, buf, &p); } } } dbref getref(FILE * f) { static char buf[SBUF_SIZE]; fgets(buf, sizeof(buf), f); return (atoi(buf)); } void free_boolexp(BOOLEXP * b) { if(b == TRUE_BOOLEXP) return; switch (b->type) { case BOOLEXP_AND: case BOOLEXP_OR: free_boolexp(b->sub1); free_boolexp(b->sub2); free_bool(b); break; case BOOLEXP_NOT: case BOOLEXP_CARRY: case BOOLEXP_IS: case BOOLEXP_OWNER: case BOOLEXP_INDIR: free_boolexp(b->sub1); free_bool(b); break; case BOOLEXP_CONST: free_bool(b); break; case BOOLEXP_ATR: case BOOLEXP_EVAL: free((char *) b->sub1); free_bool(b); break; } } BOOLEXP *dup_bool(BOOLEXP * b) { BOOLEXP *r; if(b == TRUE_BOOLEXP) return (TRUE_BOOLEXP); r = alloc_bool("dup_bool"); switch (r->type = b->type) { case BOOLEXP_AND: case BOOLEXP_OR: r->sub2 = dup_bool(b->sub2); case BOOLEXP_NOT: case BOOLEXP_CARRY: case BOOLEXP_IS: case BOOLEXP_OWNER: case BOOLEXP_INDIR: r->sub1 = dup_bool(b->sub1); case BOOLEXP_CONST: r->thing = b->thing; break; case BOOLEXP_EVAL: case BOOLEXP_ATR: r->thing = b->thing; r->sub1 = (BOOLEXP *) strsave((char *) b->sub1); break; default: fprintf(stderr, "bad bool type!!\n"); return (TRUE_BOOLEXP); } return (r); } void clone_object(dbref a, dbref b) { bcopy((char *) &db[b], (char *) &db[a], sizeof(struct object)); } /* * check_zone - checks back through a zone tree for control */ int check_zone(dbref player, dbref thing) { mudstate.zone_nest_num++; if(!mudconf.have_zones || (Zone(thing) == NOTHING) || (mudstate.zone_nest_num == mudconf.zone_nest_lim) || (isPlayer(thing))) { mudstate.zone_nest_num = 0; return 0; } /* * If the zone doesn't have an enterlock, DON'T allow control. */ if(atr_get_raw(Zone(thing), A_LENTER) && could_doit(player, Zone(thing), A_LENTER)) { mudstate.zone_nest_num = 0; return 1; } else { return check_zone(player, Zone(thing)); } } int check_zone_for_player(dbref player, dbref thing) { mudstate.zone_nest_num++; if(!mudconf.have_zones || (Zone(thing) == NOTHING) || (mudstate.zone_nest_num == mudconf.zone_nest_lim) || !(isPlayer(thing))) { mudstate.zone_nest_num = 0; return 0; } if(atr_get_raw(Zone(thing), A_LENTER) && could_doit(player, Zone(thing), A_LENTER)) { mudstate.zone_nest_num = 0; return 1; } else { return check_zone(player, Zone(thing)); } } void toast_player(dbref player) { do_clearcom(player, player, 0); do_channelnuke(player); del_commac(player); do_clear_macro(player, NULL); } /* * --------------------------------------------------------------------------- * * dump_restart_db: Writes out socket information. */ void dump_restart_db(void) { FILE *f; DESC *d; OBJQE *obq; int version = 0; /* We maintain a version number for the restart database, so we can restart even if the format of the restart db has been changed in the new executable. */ version |= RS_RECORD_PLAYERS; version |= RS_NEW_STRINGS; version |= RS_HUDKEY; f = fopen("restart.db", "w"); fprintf(f, "+V%d\n", version); putref(f, mudstate.start_time); putstring(f, mudstate.doing_hdr); putref(f, mudstate.record_players); DESC_ITER_ALL(d) { putref(f, d->descriptor); putref(f, d->flags); putref(f, d->connected_at); putref(f, d->command_count); putref(f, d->timeout); putref(f, d->host_info); putref(f, d->player); putref(f, d->last_time); putstring(f, d->output_prefix); putstring(f, d->output_suffix); putstring(f, d->addr); putstring(f, d->doing); putstring(f, d->username); putstring(f, d->hudkey); } putref(f, 0); fclose(f); } #define RESTART_MAGIC 0x0001D1ED void dump_restart_db_xdr(void) { struct mmdb_t *mmdb; DESC *d; int version = 0; /* We maintain a version number for the restart database, so we can restart even if the format of the restart db has been changed in the new executable. */ version |= RS_RECORD_PLAYERS; version |= RS_NEW_STRINGS; version |= RS_HUDKEY; mmdb = mmdb_open_write("restart.xdr"); mmdb_write_uint32(mmdb, RESTART_MAGIC); mmdb_write_uint32(mmdb, 1); mmdb_write_uint32(mmdb, version); mmdb_write_uint32(mmdb, mudstate.start_time); mmdb_write_string(mmdb, mudstate.doing_hdr); mmdb_write_uint32(mmdb, mudstate.record_players); DESC_ITER_ALL(d) { mmdb_write_uint32(mmdb, d->descriptor); mmdb_write_uint32(mmdb, d->flags); mmdb_write_uint32(mmdb, d->connected_at); mmdb_write_uint32(mmdb, d->command_count); mmdb_write_uint32(mmdb, d->timeout); mmdb_write_uint32(mmdb, d->host_info); mmdb_write_uint32(mmdb, d->player); mmdb_write_uint32(mmdb, d->last_time); mmdb_write_string(mmdb, d->output_prefix); mmdb_write_string(mmdb, d->output_suffix); mmdb_write_string(mmdb, d->addr); mmdb_write_string(mmdb, d->doing); mmdb_write_string(mmdb, d->username); mmdb_write_string(mmdb, d->hudkey); } mmdb_write_uint32(mmdb, 0); cque_dump_restart(mmdb); mmdb_close(mmdb); } void accept_client_input(int fd, short event, void *arg); void bsd_write_callback(struct bufferevent *bufev, void *arg); void bsd_read_callback(struct bufferevent *bufev, void *arg); void bsd_error_callback(struct bufferevent *bufev, short whut, void *arg); void load_restart_db() { FILE *f; DESC *d; DESC *p; struct stat statbuffer; int val, version, new_strings = 0; char *temp, buf[8]; f = fopen("restart.db", "r"); if(!f) { mudstate.restarting = 0; return; } mudstate.restarting = 1; fgets(buf, 3, f); if(strncmp(buf, "+V", 2)) { abort(); } version = getref(f); if(version & RS_NEW_STRINGS) new_strings = 1; mudstate.start_time = getref(f); time(&mudstate.restart_time); strcpy(mudstate.doing_hdr, getstring_noalloc(f, new_strings)); if(version & RS_RECORD_PLAYERS) { mudstate.record_players = getref(f); } while ((val = getref(f)) != 0) { d = malloc(sizeof(DESC)); memset(d, 0, sizeof(DESC)); d->descriptor = val; d->flags = getref(f); d->connected_at = getref(f); d->command_count = getref(f); d->timeout = getref(f); d->host_info = getref(f); d->player = getref(f); d->last_time = getref(f); temp = (char *) getstring_noalloc(f, new_strings); if(*temp) { d->output_prefix = alloc_lbuf("set_userstring"); strcpy(d->output_prefix, temp); } else { d->output_prefix = NULL; } temp = (char *) getstring_noalloc(f, new_strings); if(*temp) { d->output_suffix = alloc_lbuf("set_userstring"); strcpy(d->output_suffix, temp); } else { d->output_suffix = NULL; } strcpy(d->addr, getstring_noalloc(f, new_strings)); strcpy(d->doing, getstring_noalloc(f, new_strings)); strcpy(d->username, getstring_noalloc(f, new_strings)); if(version & RS_HUDKEY) strncpy(d->hudkey, getstring_noalloc(f, new_strings), HUDKEYLEN); else d->hudkey[0] = '\0'; d->output_size = 0; d->output_tot = 0; d->output_lost = 0; d->input_size = 0; d->input_tot = 0; d->input_lost = 0; d->raw_input_at = NULL; memset(d->input, 0, sizeof(d->input)); d->quota = mudconf.cmd_quota_max; d->program_data = NULL; d->hashnext = NULL; d->refcount = 1; d->saddr_len = sizeof(d->saddr); getpeername(d->descriptor, (struct sockaddr *) &d->saddr, (socklen_t *) & d->saddr_len); d->outstanding_dnschild_query = dnschild_request(d); if(descriptor_list) { for(p = descriptor_list; p->next; p = p->next); d->prev = &p->next; p->next = d; d->next = NULL; } else { d->next = descriptor_list; d->prev = &descriptor_list; descriptor_list = d; } d->sock_buff = bufferevent_new(d->descriptor, bsd_write_callback, bsd_read_callback, bsd_error_callback, NULL); bufferevent_disable(d->sock_buff, EV_READ); bufferevent_enable(d->sock_buff, EV_WRITE); event_set(&d->sock_ev, d->descriptor, EV_READ | EV_PERSIST, accept_client_input, d); event_add(&d->sock_ev, NULL); desc_addhash(d); if(isPlayer(d->player)) s_Flags2(d->player, Flags2(d->player) | CONNECTED); } DESC_ITER_CONN(d) { if(!isPlayer(d->player) || fstat(d->descriptor, &statbuffer) < 0) { dprintk("dropping descriptor %d.\n", d->descriptor); shutdownsock(d, R_QUIT); } } fclose(f); remove("restart.db"); raw_broadcast(0, "Game: Restart finished."); } int load_restart_db_xdr() { struct mmdb_t *mmdb; DESC *d; DESC *p; struct stat statbuffer; int val, version, new_strings = 0; char *temp, buf[8]; mmdb = mmdb_open_read("restart.xdr"); if(!mmdb) return 0; val = mmdb_read_uint32(mmdb); // RESTART_MAGIC if(val != RESTART_MAGIC) { printk("restart database had invalid magic."); printk("read %08x expected %08x.", val, RESTART_MAGIC); return 0; } mmdb_read_uint32(mmdb); // VERSION mmdb_read_uint32(mmdb); // VERSION mudstate.start_time = mmdb_read_uint32(mmdb); mmdb_read_opaque(mmdb, mudstate.doing_hdr, sizeof(mudstate.doing_hdr)); mudstate.record_players = mmdb_read_uint32(mmdb); mudstate.restarting = 1; while( (val = mmdb_read_uint32(mmdb)) != 0) { dprintk("loading descriptor %d\n", val); d = malloc(sizeof(DESC)); memset(d, 0, sizeof(DESC)); d->descriptor = val; d->flags = mmdb_read_uint32(mmdb); d->connected_at = mmdb_read_uint32(mmdb); d->command_count = mmdb_read_uint32(mmdb); d->timeout = mmdb_read_uint32(mmdb); d->host_info = mmdb_read_uint32(mmdb); d->player = mmdb_read_uint32(mmdb); d->last_time = mmdb_read_uint32(mmdb); d->output_prefix = mmdb_read_string(mmdb); d->output_suffix = mmdb_read_string(mmdb); mmdb_read_opaque(mmdb, d->addr, sizeof(d->addr)); mmdb_read_opaque(mmdb, d->doing, sizeof(d->doing)); mmdb_read_opaque(mmdb, d->username, sizeof(d->username)); mmdb_read_opaque(mmdb, d->hudkey, sizeof(d->hudkey)); d->output_size = 0; d->output_tot = 0; d->output_lost = 0; d->input_size = 0; d->input_tot = 0; d->input_lost = 0; d->raw_input_at = NULL; memset(d->input, 0, sizeof(d->input)); d->quota = mudconf.cmd_quota_max; d->program_data = NULL; d->hashnext = NULL; d->refcount = 1; d->saddr_len = sizeof(d->saddr); getpeername(d->descriptor, (struct sockaddr *) &d->saddr, (socklen_t *) & d->saddr_len); d->outstanding_dnschild_query = dnschild_request(d); if(descriptor_list) { for(p = descriptor_list; p->next; p = p->next); d->prev = &p->next; p->next = d; d->next = NULL; } else { d->next = descriptor_list; d->prev = &descriptor_list; descriptor_list = d; } d->sock_buff = bufferevent_new(d->descriptor, bsd_write_callback, bsd_read_callback, bsd_error_callback, NULL); bufferevent_disable(d->sock_buff, EV_READ); bufferevent_enable(d->sock_buff, EV_WRITE); event_set(&d->sock_ev, d->descriptor, EV_READ | EV_PERSIST, accept_client_input, d); event_add(&d->sock_ev, NULL); desc_addhash(d); if(isPlayer(d->player)) s_Flags2(d->player, Flags2(d->player) | CONNECTED); } DESC_ITER_CONN(d) { if(!isPlayer(d->player) || fstat(d->descriptor, &statbuffer) < 0) { dprintk("dropping descriptor %d.\n", d->descriptor); shutdownsock(d, R_QUIT); } } cque_load_restart(mmdb); mmdb_close(mmdb); remove("restart.xdr"); remove("restart.db"); raw_broadcast(0, "Game: Restart finished."); return 1; }