// db.c // // $Id: db.cpp,v 1.26 2000/09/05 20:28:53 sdennis Exp $ // // MUX 2.0 // Portions are derived from MUX 1.6. Portions are original work. // // Copyright (C) 1998 through 2000 Solid Vertical Domains, Ltd. All // rights not explicitly given are reserved. Permission is given to // use this code for building and hosting text-based game servers. // Permission is given to use this code for other non-commercial // purposes. To use this code for commercial purposes other than // building/hosting text-based game servers, contact the author at // Stephen Dennis <sdennis@svdltd.com> for another license. // #include "copyright.h" #include "autoconf.h" #include "config.h" #ifdef STANDALONE #undef MEMORY_BASED #endif #include "externs.h" #define __DB_C #include "mudconf.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 "comsys.h" #ifdef RADIX_COMPRESSION #ifndef COMPRESSOR #define COMPRESSOR #endif #include "radix.h" #endif #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 OBJ *db = NULL; NAME *names = NULL; NAME *purenames = NULL; #ifndef WIN32 extern SOCKET MainGameSockPort; #ifdef CONCENTRATE extern int conc_pid; #endif #endif // WIN32 extern void FDECL(desc_addhash, (DESC *)); #ifdef RADIX_COMPRESSION /* * Buffers for compressing in and out of. NOTE: These assume that compression * will NEVER expand input text by more than 1.5, which is valid for the * radix tree stuff, since it emits at worst a 12 bit code for every input * byte. If this changes, the size of compress_buff needs to be adjusted to the * new worst case. */ char decomp_buff[LBUF_SIZE]; char compress_buff[LBUF_SIZE + (LBUF_SIZE >> 1) + 1]; #endif typedef struct atrcount ATRCOUNT; struct atrcount { dbref thing; int count; }; /* * Check routine forward declaration. */ extern int FDECL(fwdlist_ck, (int, dbref, dbref, int, char *)); extern void FDECL(pcache_reload, (dbref)); extern void FDECL(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}, {"Charges", A_CHARGES, AF_ODARK | AF_NOPROG, NULL}, {"Comment", A_COMMENT, AF_MDARK | AF_WIZARD, NULL}, {"Cost", A_COST, AF_ODARK, NULL}, {"Daily", A_DAILY, AF_ODARK, 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}, {"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}, {"Idesc", A_IDESC, AF_ODARK | AF_NOPROG, NULL}, {"Idle", A_IDLE, AF_ODARK | AF_NOPROG, NULL}, {"IdleTimeout", A_IDLETMOUT, AF_ODARK | AF_NOPROG, NULL}, {"Infilter", A_INFILTER, AF_ODARK | AF_NOPROG, NULL}, {"Inprefix", A_INPREFIX, AF_ODARK | AF_NOPROG, 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}, {"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}, {"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}, {"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}, {"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}, {"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}, {"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}, {"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}, {"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}, {"VRML_URL", A_VRML_URL, AF_ODARK, NULL}, {"HTDesc", A_HTDESC, AF_NOPROG, NULL}, // Added by D.Piper (del@delphinian.com) 2000-APR // {"Reason", A_REASON, AF_PRIVATE | AF_MDARK | AF_NOPROG | AF_NOCMD | AF_GOD, NULL}, #ifdef GAME_DOOFERMUX {"RegInfo", A_REGINFO, AF_PRIVATE | AF_MDARK | AF_NOPROG | AF_NOCMD | AF_WIZARD, NULL}, #endif // GAME_DOOFERMUX {"ConnInfo", A_CONNINFO, AF_PRIVATE | AF_MDARK | AF_NOPROG | AF_NOCMD | AF_GOD, 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}, {NULL, 0, 0, NULL} }; char *aszSpecialDBRefNames[1-NOPERM] = { "", "*NOTHING*", "*AMBIGUOUS*", "*HOME*", "*NOPERMISSION*" }; #ifndef STANDALONE /* * --------------------------------------------------------------------------- * * 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 *)MEMALLOC(sizeof(int) * ((ifp->count) + 1)); ISOUTOFMEMORY(fp); 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) { MEMFREE(xfp); xfp = NULL; hashreplLEN(&thing, sizeof(thing), (int *)fp, &mudstate.fwdlist_htab); } else { hashaddLEN(&thing, sizeof(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) { MEMFREE(xfp); xfp = NULL; hashdeleteLEN(&thing, sizeof(thing), &mudstate.fwdlist_htab); } } #endif /* * --------------------------------------------------------------------------- * * fwdlist_load: Load text into a forwardlist. */ int fwdlist_load(FWDLIST *fp, dbref player, char *atext) { dbref target; char *tp, *bp, *dp; int fail; int count = 0; int errors = 0; bp = tp = alloc_lbuf("fwdlist_load.str"); strcpy(tp, atext); do { // Skip spaces. // for (; Tiny_IsSpace[(unsigned char)*bp]; bp++) ; // Remember string. // for (dp = bp; *bp && !Tiny_IsSpace[(unsigned char)*bp]; bp++) ; // Terminate string. // if (*bp) { *bp++ = '\0'; } if ((*dp++ == '#') && Tiny_IsDigit[(unsigned char)*dp]) { target = Tiny_atol(dp); #ifndef STANDALONE fail = (!Good_obj(target) || (!God(player) && !controls(player, target) && (!Link_ok(target) || !could_doit(player, target, A_LLINK)))); #else fail = !Good_obj(target); #endif if (fail) { #ifndef STANDALONE notify(player, tprintf("Cannot forward to #%d: Permission denied.", target)); #endif errors++; } else { if (count < 1000) { 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) { int count = 0; atext[0] = '\0'; if (fp && fp->count) { char *bp = atext; DTB pContext; DbrefToBuffer_Init(&pContext, atext, &bp); for (int i = 0; i < fp->count; i++) { if ( Good_obj(fp->data[i]) && DbrefToBuffer_Add(&pContext, fp->data[i])) { count++; } } DbrefToBuffer_Final(&pContext); } 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) { #ifndef STANDALONE 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); #else return 1; #endif } FWDLIST *fwdlist_get(dbref thing) { #ifdef STANDALONE static FWDLIST *fp = NULL; if (!fp) { fp = (FWDLIST *) alloc_lbuf("fwdlist_get"); } dbref aowner; int aflags; char *tp = atr_get(thing, A_FORWARDLIST, &aowner, &aflags); int errors = fwdlist_load(fp, GOD, tp); free_lbuf(tp); #else FWDLIST *fp = ((FWDLIST *) hashfindLEN(&thing, sizeof(thing), &mudstate.fwdlist_htab)); #endif return fp; } static char *set_string(char **ptr, char *new0) { // if pointer not null unalloc it. // if (*ptr) { MEMFREE(*ptr); } *ptr = NULL; // If new string is not null allocate space for it and copy it. // if (new0) { *ptr = StringClone(new0); } return *ptr; } /* * --------------------------------------------------------------------------- * * Name, s_Name: Get or set an object's name. */ char *Name(dbref thing) { static char tbuff[LBUF_SIZE]; if (thing < 0) { strcpy(tbuff, aszSpecialDBRefNames[-thing]); return tbuff; } dbref aowner; int aflags; char *buff; if (mudconf.cache_names) { if (!purenames[thing]) { buff = atr_get(thing, A_NAME, &aowner, &aflags); set_string(&purenames[thing], strip_ansi(buff)); free_lbuf(buff); } } #ifndef MEMORY_BASED if (!names[thing]) { buff = atr_get(thing, A_NAME, &aowner, &aflags); set_string(&names[thing], buff); free_lbuf(buff); } return names[thing]; #else atr_get_str(tbuff, thing, A_NAME, &aowner, &aflags); return tbuff; #endif // MEMORY_BASED } char *PureName(dbref thing) { char tbuff[LBUF_SIZE]; if (thing < 0) { char *p = alloc_lbuf("PureName"); strcpy(p, aszSpecialDBRefNames[-thing]); return p; } dbref aowner; int aflags; char *buff; #ifndef MEMORY_BASED if (!names[thing]) { buff = atr_get(thing, A_NAME, &aowner, &aflags); set_string(&names[thing], buff); free_lbuf(buff); } #endif if (mudconf.cache_names) { 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(tbuff, thing, A_NAME, &aowner, &aflags); return strip_ansi(tbuff); } void s_Name(dbref thing, char *s) { atr_add_raw(thing, A_NAME, s); #ifndef MEMORY_BASED set_string(&names[thing], s); #endif if (mudconf.cache_names) { set_string(&purenames[thing], strip_ansi(s)); } } void s_Pass(dbref thing, const char *s) { atr_add_raw(thing, A_PASS, (char *)s); } #ifndef STANDALONE /* * --------------------------------------------------------------------------- * * 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 *sp; VATTR *va; ATTR *va2; // Look up the user-named attribute we want to play with. // int nName; int bValid; char *pName = MakeCanonicalAttributeName(aname, &nName, &bValid); if (!bValid || !(va = (VATTR *)vattr_find_LEN(pName, nName))) { notify(player, "No such user-named attribute."); return; } switch (key) { case ATTRIB_ACCESS: // Modify access to user-named attribute // _strupr(value); TINY_STRTOK_STATE tts; Tiny_StrTokString(&tts, value); Tiny_StrTokControl(&tts, " "); sp = Tiny_StrTokParse(&tts); 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(player, tprintf("Unknown permission: %s.", sp)); } // Get the next token. // sp = Tiny_StrTokParse(&tts); } if (success && !Quiet(player)) notify(player, "Attribute access changed."); break; case ATTRIB_RENAME: { // Save the old name for use later. // char OldName[SBUF_SIZE]; int nOldName = nName; memcpy(OldName, pName, nName+1); // Make sure the new name doesn't already exist. This checks // the built-in and user-defined data structures. // va2 = atr_str(value); if (va2) { notify(player, "An attribute with that name already exists."); return; } pName = MakeCanonicalAttributeName(value, &nName, &bValid); if (!bValid || vattr_rename_LEN(OldName, nOldName, pName, nName) == NULL) notify(player, "Attribute rename failed."); else notify(player, "Attribute renamed."); } break; case ATTRIB_DELETE: // Remove the attribute. // vattr_delete_LEN(pName, nName); notify(player, "Attribute deleted."); break; } } /* * --------------------------------------------------------------------------- * * do_fixdb: Directly edit database fields */ void do_fixdb(dbref player, dbref cause, int key, char *arg1, char *arg2) { init_match(player, arg1, NOTYPE); match_everything(0); dbref thing = noisy_match_result(); if (thing == NOTHING) { return; } dbref 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 = Tiny_atol(arg2); break; } char *pValidName; switch (key) { case FIXDB_OWNER: s_Owner(thing, res); if (!Quiet(player)) notify(player, tprintf("Owner set to #%d", res)); break; case FIXDB_LOC: s_Location(thing, res); if (!Quiet(player)) notify(player, tprintf("Location set to #%d", res)); break; case FIXDB_CON: s_Contents(thing, res); if (!Quiet(player)) notify(player, tprintf("Contents set to #%d", res)); break; case FIXDB_EXITS: s_Exits(thing, res); if (!Quiet(player)) notify(player, tprintf("Exits set to #%d", res)); break; case FIXDB_NEXT: s_Next(thing, res); if (!Quiet(player)) notify(player, tprintf("Next set to #%d", res)); break; case FIXDB_PENNIES: s_Pennies(thing, res); if (!Quiet(player)) notify(player, tprintf("Pennies set to %d", res)); break; case FIXDB_NAME: if (isPlayer(thing)) { if (!ValidatePlayerName(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)) { raw_broadcast(WIZARD, "[Suspect] %s renamed to %s", Name(thing), arg2); } delete_player_name(thing, Name(thing)); s_Name(thing, arg2); add_player_name(thing, arg2); } else { int nTmp; BOOL bValid; pValidName = MakeCanonicalObjectName(arg2, &nTmp, &bValid); if (!bValid) { notify(player, "That is not a reasonable name."); return; } s_Name(thing, pValidName); } if (!Quiet(player)) { notify(player, tprintf("Name set to %s", pValidName)); } break; } } #endif // STANDALONE // MakeCanonicalAttributeName // // First letter must be alphabetic. // Other letters can be alphanumeric or one of "'?!`/-_.@#$^&~=+<>()%". // Letters are converted to uppercase. // // We truncate the attribute name to a length of SBUF_SIZE-1, if // necessary, but we will validate the remaining characters anyway. // // NOTE: Refer to init_attrtab() where is directly manipulates // Tiny_IsAlpha and Tiny_IsAttributeNameCharacter to allow the // attribute name: "*Password". // char *MakeCanonicalAttributeName(const char *pName, int *pnName, BOOL *pbValid) { static char Buffer[SBUF_SIZE]; if ( !pName || !Tiny_IsAlpha[(unsigned char)*pName]) { *pnName = 0; *pbValid = FALSE; return NULL; } int nLeft = SBUF_SIZE-1; char *p = Buffer; while (*pName && nLeft) { if (!Tiny_IsAttributeNameCharacter[(unsigned char)*pName]) { *pnName = 0; *pbValid = FALSE; return Buffer; } *p = Tiny_ToUpper[(unsigned char)*pName]; p++; pName++; nLeft--; } *p = '\0'; // Continue to validate remaining characters even though // we aren't going to use them. This helps to ensure that // softcode will run in the future if we increase the // size of SBUF_SIZE. // while (*pName) { if (!Tiny_IsAttributeNameCharacter[(unsigned char)*pName]) { *pnName = 0; *pbValid = FALSE; return Buffer; } pName++; } // Length of truncated result. // *pnName = p - Buffer; *pbValid = TRUE; return Buffer; } // MakeCanonicalAttributeCommand // char *MakeCanonicalAttributeCommand(const char *pName, int *pnName, BOOL *pbValid) { if (!pName) { *pnName = 0; *pbValid = FALSE; return NULL; } static char Buffer[SBUF_SIZE]; int nLeft = SBUF_SIZE-2; char *p = Buffer; *p++ = '@'; while (*pName && nLeft) { *p = Tiny_ToLower[(unsigned char)*pName]; p++; pName++; nLeft--; } *p = '\0'; // Length of result. // *pnName = p - Buffer; // Is the result valid? // *pbValid = (*pnName > 1) ? TRUE : FALSE; // Pointer to result // return Buffer; } /* * --------------------------------------------------------------------------- * * init_attrtab: Initialize the attribute hash tables. */ void NDECL(init_attrtab) { ATTR *a; // We specifically allow the '*' character at server // initialization because it's part of the A_PASS attribute // name. // Tiny_IsAlpha['*'] = TRUE; Tiny_IsAttributeNameCharacter['*'] = TRUE; for (a = attr; a->number; a++) { int nLen; BOOL bValid; char *buff = MakeCanonicalAttributeName(a->name, &nLen, &bValid); if (!bValid) { continue; } anum_extend(a->number); anum_set(a->number, a); hashaddLEN(buff, nLen, (int *)a, &mudstate.attr_name_htab); } Tiny_IsAlpha['*'] = FALSE; Tiny_IsAttributeNameCharacter['*'] = FALSE; } /* * --------------------------------------------------------------------------- * * atr_str: Look up an attribute by name. */ ATTR *atr_str(char *s) { // Make attribute name canonical. // int nBuffer; BOOL bValid; char *buff = MakeCanonicalAttributeName(s, &nBuffer, &bValid); if (!bValid) { return NULL; } // Look for a predefined attribute. // ATTR *a = (ATTR *)hashfindLEN(buff, nBuffer, &mudstate.attr_name_htab); if (a != NULL) { return a; } // Nope, look for a user attribute. // VATTR *va = (VATTR *)vattr_find_LEN(buff, nBuffer); // If we got one, load tattr and return a pointer to it. // static ATTR tattr; 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; #ifndef STANDALONE delta = mudconf.init_size; #else delta = 1000; #endif if (newtop <= anum_alc_top) { return; } if (newtop < anum_alc_top + delta) { newtop = anum_alc_top + delta; } if (anum_table == NULL) { anum_table = (ATTR **) MEMALLOC((newtop + 1) * sizeof(ATTR *)); ISOUTOFMEMORY(anum_table); for (i = 0; i <= newtop; i++) { anum_table[i] = NULL; } } else { anum_table2 = (ATTR **) MEMALLOC((newtop + 1) * sizeof(ATTR *)); ISOUTOFMEMORY(anum_table2); 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; } MEMFREE((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 = atr_str(buff); if (!ap) { // Unknown attribute name, create a new one. // int nName; BOOL bValid; char *pName = MakeCanonicalAttributeName(buff, &nName, &bValid); VATTR *va; if ( !bValid || !(va = vattr_alloc_LEN(pName, nName, mudconf.vattr_flags)) || !(va->number)) { return -1; } return va->number; } if (!(ap->number)) { return -1; } return ap->number; } /* * --------------------------------------------------------------------------- * * al_decode: Fetch an attribute number from an alist. */ static int al_decode(char **app) { char *ap = *app; int atrnum = 0, atrshft = 0; for (;;) { int ch = *ap++; int bits = ch & 0x7F; if (atrshft > 0) atrnum |= (bits << atrshft); else atrnum = bits; if ((ch & 0x80) == 0) { *app = ap; return atrnum; } atrshft += 7; } } // --------------------------------------------------------------------------- // al_code: Store an attribute number in an alist // // Because A_LIST are attributes, too. We cannot generate a '\0', otherwise // the size of an A_LIST cannot be determined with strlen. Fortunately, the // following routine only genreates a '\0' in the atrnum == 0 case (which is // never used). // static char *al_code(char *ap, int atrnum) { int bits; for (;;) { bits = atrnum & 0x7F; if (atrnum <= 0x7F) break; atrnum >>= 7; bits |= 0x80; *ap++ = bits; } *ap++ = bits; return ap; } /* * --------------------------------------------------------------------------- * * 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; atr_push(); 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)) { atr_pop(); return 1; } } atr_pop(); return 0; } /* * routines to handle object attribute lists */ #ifndef MEMORY_BASED /* * --------------------------------------------------------------------------- * * al_fetch, al_store, al_add, al_delete: Manipulate attribute lists */ /* * al_extend: Get more space for attributes, if needed */ void al_extend(char **buffer, int *bufsiz, int len, int copy) { char *tbuff; if (len > *bufsiz) { int newsize = len + ATR_BUF_CHUNK; tbuff = (char *)MEMALLOC(newsize); ISOUTOFMEMORY(tbuff); if (*buffer) { if (copy) { memcpy(tbuff, *buffer, *bufsiz); } MEMFREE(*buffer); *buffer = NULL; } *buffer = tbuff; *bufsiz = newsize; } } /* * al_store: Write modified attribute list */ void NDECL(al_store) { if (mudstate.mod_al_id != NOTHING) { if (mudstate.mod_alist_len) { atr_add_raw_LEN(mudstate.mod_al_id, A_LIST, mudstate.mod_alist, mudstate.mod_alist_len); } else { atr_clr(mudstate.mod_al_id, A_LIST); } } mudstate.mod_al_id = NOTHING; } /* * al_fetch: Load attribute list */ char *al_fetch(dbref thing) { // We only need fetch if we change things. // if (mudstate.mod_al_id == thing) { return mudstate.mod_alist; } // Save old list, then fetch and set up the attribute list. // al_store(); int len; char *astr = atr_get_raw_LEN(thing, A_LIST, &len); if (astr) { al_extend(&mudstate.mod_alist, &mudstate.mod_size, len+1, 0); memcpy(mudstate.mod_alist, astr, len+1); mudstate.mod_alist_len = len; } else { al_extend(&mudstate.mod_alist, &mudstate.mod_size, 1, 0); *mudstate.mod_alist = '\0'; mudstate.mod_alist_len = 0; } mudstate.mod_al_id = thing; return mudstate.mod_alist; } // al_add: Add an attribute to an attribute list // BOOL al_add(dbref thing, int attrnum) { char *abuf, *cp; int anum; abuf = al_fetch(thing); // See if attr is in the list. If so, exit (need not do anything). // cp = abuf; while (*cp) { anum = al_decode(&cp); if (anum == attrnum) { return TRUE; } } // The attribute isn't there, so we need to try to add it. // int iPosition = cp - abuf; // If we are too large for an attribute // if (iPosition + ATR_BUF_INCR >= LBUF_SIZE) { return FALSE; } // Extend it. // al_extend(&mudstate.mod_alist, &mudstate.mod_size, (iPosition + ATR_BUF_INCR), 1); if (mudstate.mod_alist != abuf) { // extend returned different buffer, re-position the end // cp = mudstate.mod_alist + iPosition; } // Add the new attribute on to the end. // cp = al_code(cp, attrnum); *cp = '\0'; mudstate.mod_alist_len = cp - mudstate.mod_alist; return TRUE; } /* * al_delete: Remove an attribute from an attribute list */ void al_delete(dbref thing, int attrnum) { int anum; char *abuf, *cp, *dp; // If trying to modify List attrib, return. Otherwise, get the attribute list. // if (attrnum == A_LIST) { return; } abuf = al_fetch(thing); if (!abuf) { return; } cp = abuf; while (*cp) { dp = cp; anum = al_decode(&cp); if (anum == attrnum) { while (*cp) { anum = al_decode(&cp); dp = al_code(dp, anum); } *dp = '\0'; mudstate.mod_alist_len = dp - mudstate.mod_alist; return; } } return; } DCL_INLINE static void makekey(dbref thing, int atr, Aname *abuff) { abuff->object = thing; abuff->attrnum = atr; return; } /* * --------------------------------------------------------------------------- * * al_destroy: wipe out an object's attribute list. */ void al_destroy(dbref thing) { if (mudstate.mod_al_id == thing) al_store(); /* * remove from cache */ atr_clr(thing, A_LIST); } #endif /* * * MEMORY_BASED */ /* * --------------------------------------------------------------------------- * * 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_flags_owner: Decode the owner and flags (if present) and // return a pointer to the attribute text. // static const char *atr_decode_flags_owner(const char *iattr, dbref *owner, int *flags) { // See if the first char of the attribute is the special character // *flags = 0; if (*iattr != ATR_INFO_CHAR) { return iattr; } // It has the special character, crack the attr apart. // const char *cp = iattr + 1; // Get the attribute owner // int neg = 0; if (*cp == '-') { neg = 1; cp++; } int tmp_owner = 0; unsigned int ch = *cp; while (Tiny_IsDigit[ch]) { cp++; tmp_owner = 10*tmp_owner + (ch-'0'); ch = *cp; } if (neg) { tmp_owner = -tmp_owner; } // If delimiter is not ':', just return attribute // if (*cp++ != ':') { return iattr; } // Get the attribute flags. // int tmp_flags = 0; ch = *cp; while (Tiny_IsDigit[ch]) { cp++; tmp_flags = 10*tmp_flags + (ch-'0'); ch = *cp; } // If delimiter is not ':', just return attribute. // if (*cp++ != ':') { return iattr; } // Get the attribute text. // if (tmp_owner != NOTHING) { *owner = tmp_owner; } *flags = tmp_flags; return cp; } #ifdef RADIX_COMPRESSION /* --------------------------------------------------------------------------- * atr_get_raw_decode_LEN: Get an attribute string out of the DB, decompress * and decode it in one shot. Since the decompression involves a copy, and we * normally do decode/copy immediately after fetching the attribute, this is * used to roll the two operations together. */ static int atr_get_raw_decode_LEN(dbref thing, char *oattr, dbref *owner, int *flags, int atr, int *pLen) { char *a; int nLen; if (!Good_obj(thing)) return 0; #ifdef MEMORY_BASED a = (char *)atr_get_raw_LEN(thing, atr, &nLen); #else Aname okey; Tiny_Assert(atr != A_LIST); makekey(thing, atr, &okey); a = FETCH(&okey, &nLen); nLen = a ? (nLen-1) : 0; #endif // MEMORY_BASED *owner = Owner(thing); if (!a) { *flags = 0; if (oattr) { *oattr = '\0'; } return 0; } #ifdef MEMORY_BASED // We have already uncompressed it by calling get_atr_raw_LEN above. // const char *a1 = atr_decode_flags_owner(a, owner, flags); if (oattr) { // The caller wants the value of the attribute as well. // // If there was an owner/flag data at the beginning, a != a1. // a1 always points at the beginning of the attribute value. // nLen -= (a1 - a); *pLen = nLen; memcpy(oattr, a1, nLen + 1); } #else // We now have a compressed attribute, decompress it into oattr. // and decode it. // char *cp = oattr; if (cp == NULL) cp = decomp_buff; nLen = string_decompress(a, cp); const char *cp1 = atr_decode_flags_owner(cp, owner, flags); if (oattr) { // The caller wants the value of the attribute as well. // // If there was an owner/flag data at the beginning, cp != cp1. // cp1 always points at the beginning of the attribute value. // if (cp1 != cp) { // There was owner/flag data at the beginning so we // need to move the string down. // *pLen = nLen - (cp1 - oattr); memmove(oattr, cp1, (*pLen)+1); } else { *pLen = nLen; } } #endif // MEMORY_BASED return 1; } #endif // RADIX_COMPRESSION // --------------------------------------------------------------------------- // atr_decode: Decode an attribute string. // static void atr_decode_LEN(char *iattr, int nLen, char *oattr, dbref thing, dbref *owner, int *flags, int *pLen) { // Default the owner // *owner = Owner(thing); // Parse for owner and flags // const char *cp = atr_decode_flags_owner(iattr, owner, flags); // Get the attribute text. // *pLen = nLen - (cp - iattr); if (oattr) { memcpy(oattr, cp, (*pLen) + 1); } } /* * --------------------------------------------------------------------------- * * atr_clr: clear an attribute in the list. */ void atr_clr(dbref thing, int atr) { #ifdef MEMORY_BASED ATRLIST *list; int hi, lo, mid; if (!db[thing].at_count || !db[thing].ahead) { return; } Tiny_Assert(0 <= db[thing].at_count); // 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) { MEMFREE(list[mid].data); db[thing].at_count -= 1; if (mid != db[thing].at_count) { memmove(list+mid, list+mid+1, (db[thing].at_count - mid) * sizeof(ATRLIST)); } break; } else if (list[mid].number > atr) { hi = mid - 1; } else { lo = mid + 1; } } #else Aname okey; makekey(thing, atr, &okey); TM_DELETE(&okey); al_delete(thing, atr); #endif /* * * MEMORY_BASED */ 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_FORWARDLIST: s_Flags2(thing, Flags2(thing) & ~HAS_FWDLIST); break; case A_LISTEN: s_Flags2(thing, Flags2(thing) & ~HAS_LISTEN); break; #ifndef STANDALONE case A_TIMEOUT: desc_reload(thing); break; case A_QUEUEMAX: pcache_reload(thing); break; #endif } } /* * --------------------------------------------------------------------------- * * atr_add_raw, atr_add: add attribute of type atr to list */ void atr_add_raw_LEN(dbref thing, int atr, char *szValue, int nValue) { #ifdef MEMORY_BASED ATRLIST *list; char *text; int found = 0; int hi, lo, mid; if (!szValue || szValue[0] == '\0') { atr_clr(thing, atr); return; } if (nValue > LBUF_SIZE-1) { nValue = LBUF_SIZE-1; szValue[nValue] = '\0'; } #ifdef RADIX_COMPRESSION int nCompressedValue = string_compress(szValue, compress_buff); text = BufferCloneLen(compress_buff, nCompressedValue); #else // RADIX_COMPRESSION text = StringCloneLen(szValue, nValue); #endif // RADIX_COMPRESSION if (!db[thing].ahead) { list = (ATRLIST *)MEMALLOC(sizeof(ATRLIST)); ISOUTOFMEMORY(list); db[thing].ahead = list; db[thing].at_count = 1; list[0].number = atr; list[0].data = text; #ifdef RADIX_COMPRESSION list[0].size = nCompressedValue; #else // RADIX_COMPRESSION list[0].size = nValue+1; #endif // RADIX_COMPRESSION 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) { MEMFREE(list[mid].data); list[mid].data = text; #ifdef RADIX_COMPRESSION list[mid].size = nCompressedValue; #else // RADIX_COMPRESSION list[mid].size = nValue+1; #endif // RADIX_COMPRESSION 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 *)MEMALLOC((db[thing].at_count + 1) * sizeof(ATRLIST)); ISOUTOFMEMORY(list); // Copy bottom part. // if (lo > 0) { memcpy(list, db[thing].ahead, lo * sizeof(ATRLIST)); } // Copy top part. // if (lo < db[thing].at_count) { memcpy(list+lo+1, db[thing].ahead+lo, (db[thing].at_count - lo) * sizeof(ATRLIST)); } MEMFREE(db[thing].ahead); list[lo].data = text; list[lo].number = atr; #ifdef RADIX_COMPRESSION list[lo].size = nCompressedValue; #else // RADIX_COMPRESSION list[lo].size = nValue+1; #endif // RADIX_COMPRESSION db[thing].at_count++; db[thing].ahead = list; } } #else // !MEMORY_BASED Aname okey; makekey(thing, atr, &okey); if (!szValue || szValue[0] == '\0') { TM_DELETE(&okey); al_delete(thing, atr); return; } if (nValue > LBUF_SIZE-1) { nValue = LBUF_SIZE-1; szValue[nValue] = '\0'; } if (atr == A_LIST) { // A_LIST is never compressed and it's never listed within itself. // STORE(&okey, szValue, nValue+1); } else { if (!al_add(thing, atr)) { return; } #ifdef RADIX_COMPRESSION // It's not an A_LIST, so compress it into a buffer and store that. // int nCompressedValue = string_compress(szValue, compress_buff); STORE(&okey, compress_buff, nCompressedValue); #else // RADIX_COMPRESSION STORE(&okey, szValue, nValue+1); #endif // RADIX_COMPRESSION } #endif // MEMORY_BASED 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_FORWARDLIST: s_Flags2(thing, Flags2(thing) | HAS_FWDLIST); break; case A_LISTEN: s_Flags2(thing, Flags2(thing) | HAS_LISTEN); break; #ifndef STANDALONE case A_TIMEOUT: desc_reload(thing); break; case A_QUEUEMAX: pcache_reload(thing); break; #endif } } void atr_add_raw(dbref thing, int atr, char *szValue) { atr_add_raw_LEN(thing, atr, szValue, szValue ? strlen(szValue) : 0); } void atr_add(dbref thing, int atr, char *buff, dbref owner, int flags) { if (!buff || !*buff) { atr_clr(thing, atr); } else { char *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 = atr_str(name); if (!ap) return 0; if (!(ap->number)) return -1; return ap->number; } #ifdef MEMORY_BASED char *atr_get_raw_LEN(dbref thing, int atr, int *pLen) { 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) { #ifdef RADIX_COMPRESSION *pLen = string_decompress(list[mid].data, decomp_buff); return decomp_buff; #else *pLen = list[mid].size - 1; return list[mid].data; #endif // RADIX_COMPRESSION } else if (list[mid].number > atr) { hi = mid - 1; } else { lo = mid + 1; } } *pLen = 0; return NULL; } #else char *atr_get_raw_LEN(dbref thing, int atr, int *pLen) { char *a; Aname okey; makekey(thing, atr, &okey); int nLen; a = FETCH(&okey, &nLen); nLen = a ? (nLen-1) : 0; #ifdef RADIX_COMPRESSION if (!a || atr == A_LIST) { *pLen = nLen; return a; } *pLen = string_decompress(a, decomp_buff) - 1; return decomp_buff; #else *pLen = nLen; return a; #endif // RADIX_COMPRESSION } #endif // MEMORY_BASED char *atr_get_raw(dbref thing, int atr) { int Len; return atr_get_raw_LEN(thing, atr, &Len); } char *atr_get_str_LEN(char *s, dbref thing, int atr, dbref *owner, int *flags, int *pLen) { #ifdef RADIX_COMPRESSION (void)atr_get_raw_decode_LEN(thing, s, owner, flags, atr, pLen); #else char *buff; buff = atr_get_raw_LEN(thing, atr, pLen); if (!buff) { *owner = Owner(thing); *flags = 0; *pLen = 0; *s = '\0'; } else { atr_decode_LEN(buff, *pLen, s, thing, owner, flags, pLen); } #endif // RADIX_COMPRESSION return s; } char *atr_get_str(char *s, dbref thing, int atr, dbref *owner, int *flags) { int nLen; return atr_get_str_LEN(s, thing, atr, owner, flags, &nLen); } char *atr_get_LEN(dbref thing, int atr, dbref *owner, int *flags, int *pLen) { char *buff = alloc_lbuf("atr_get"); return atr_get_str_LEN(buff, thing, atr, owner, flags, pLen); } char *atr_get(dbref thing, int atr, dbref *owner, int *flags) { int nLen; char *buff = alloc_lbuf("atr_get"); return atr_get_str_LEN(buff, thing, atr, owner, flags, &nLen); } int atr_get_info(dbref thing, int atr, dbref *owner, int *flags) { int nLen; #ifdef RADIX_COMPRESSION int retval; retval = atr_get_raw_decode_LEN(thing, NULL, owner, flags, atr, &nLen); return retval; #else char *buff; buff = atr_get_raw_LEN(thing, atr, &nLen); if (!buff) { *owner = Owner(thing); *flags = 0; return 0; } atr_decode_LEN(buff, nLen, NULL, thing, owner, flags, &nLen); return 1; #endif // RADIX_COMPRESSION } #ifndef STANDALONE char *atr_pget_str_LEN(char *s, dbref thing, int atr, dbref *owner, int *flags, int *pLen) { dbref parent; int lev; ATTR *ap; #ifdef RADIX_COMPRESSION int retval; #else char *buff; #endif // RADIX_COMPRESSION ITER_PARENTS(thing, parent, lev) { #ifdef RADIX_COMPRESSION retval = atr_get_raw_decode_LEN(parent, s, owner, flags, atr, pLen); if (retval && ((lev = 0) || !(*flags & AF_PRIVATE))) { return s; } #else buff = atr_get_raw_LEN(parent, atr, pLen); if (buff && *buff) { atr_decode_LEN(buff, *pLen, s, thing, owner, flags, pLen); if ((lev == 0) || !(*flags & AF_PRIVATE)) { return s; } } #endif // RADIX_COMPRESSION 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'; *pLen = 0; return s; } char *atr_pget_str(char *s, dbref thing, int atr, dbref *owner, int *flags) { int nLen; return atr_pget_str_LEN(s, thing, atr, owner, flags, &nLen); } char *atr_pget_LEN(dbref thing, int atr, dbref *owner, int *flags, int *pLen) { char *buff = alloc_lbuf("atr_pget"); return atr_pget_str_LEN(buff, thing, atr, owner, flags, pLen); } char *atr_pget(dbref thing, int atr, dbref *owner, int *flags) { int nLen; char *buff = alloc_lbuf("atr_pget"); return atr_pget_str_LEN(buff, thing, atr, owner, flags, &nLen); } 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) { int nLen; buff = atr_get_raw_LEN(parent, atr, &nLen); if (buff && *buff) { atr_decode_LEN(buff, nLen, NULL, thing, owner, flags, &nLen); 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; } #endif // STANDALONE /* * --------------------------------------------------------------------------- * * atr_free: Return all attributes of an object. */ void atr_free(dbref thing) { #ifdef MEMORY_BASED if (db[thing].ahead) { MEMFREE(db[thing].ahead); } db[thing].ahead = NULL; db[thing].at_count = 0; #else int attr; char *as; atr_push(); for (attr = atr_head(thing, &as); attr; attr = atr_next(&as)) { atr_clr(thing, attr); } atr_pop(); al_destroy(thing); // Just to be on the safe side. #endif // MEMORY_BASED } /* * --------------------------------------------------------------------------- * * 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); atr_push(); for (attr = atr_head(source, &as); attr; attr = atr_next(&as)) { buf = atr_get(source, attr, &aowner, &aflags); if (!(aflags & AF_LOCK)) { // Change owner. // aowner = 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_pop(); } /* * --------------------------------------------------------------------------- * * 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); atr_push(); 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_pop(); } /* * --------------------------------------------------------------------------- * * atr_next: Return next attribute in attribute list. */ int atr_next(char **attrp) { #ifdef MEMORY_BASED ATRCOUNT *atr; if (!attrp || !*attrp) { return 0; } else { atr = (ATRCOUNT *) * attrp; if (atr->count >= db[atr->thing].at_count) { MEMFREE(atr); return 0; } atr->count++; return db[atr->thing].ahead[atr->count - 1].number; } #else if (!*attrp || !**attrp) { return 0; } else { return al_decode(attrp); } #endif // MEMORY_BASED } /* * --------------------------------------------------------------------------- * * atr_push, atr_pop: Push and pop attr lists. */ void NDECL(atr_push) { #ifndef MEMORY_BASED ALIST *new_alist = (ALIST *) alloc_sbuf("atr_push"); new_alist->data = mudstate.iter_alist.data; new_alist->len = mudstate.iter_alist.len; new_alist->next = mudstate.iter_alist.next; mudstate.iter_alist.data = NULL; mudstate.iter_alist.len = 0; mudstate.iter_alist.next = new_alist; #endif // MEMORY_BASED } void NDECL(atr_pop) { #ifndef MEMORY_BASED ALIST *old_alist = mudstate.iter_alist.next; if (mudstate.iter_alist.data) { MEMFREE(mudstate.iter_alist.data); } if (old_alist) { mudstate.iter_alist.data = old_alist->data; mudstate.iter_alist.len = old_alist->len; mudstate.iter_alist.next = old_alist->next; char *cp = (char *)old_alist; free_sbuf(cp); } else { mudstate.iter_alist.data = NULL; mudstate.iter_alist.len = 0; mudstate.iter_alist.next = NULL; } #endif // MEMORY_BASED } /* * --------------------------------------------------------------------------- * * atr_head: Returns the head of the attr list for object 'thing' */ int atr_head(dbref thing, char **attrp) { #ifdef MEMORY_BASED ATRCOUNT *atr; if (db[thing].at_count) { atr = (ATRCOUNT *) MEMALLOC(sizeof(ATRCOUNT)); ISOUTOFMEMORY(atr); atr->thing = thing; atr->count = 1; *attrp = (char *)atr; return db[thing].ahead[0].number; } return 0; #else char *astr; int alen; /* * Get attribute list. Save a read if it is in the modify atr list */ if (thing == mudstate.mod_al_id) { astr = mudstate.mod_alist; alen = mudstate.mod_alist_len; } else { astr = atr_get_raw_LEN(thing, A_LIST, &alen); } // If no list, return nothing. // if (!alen) { return 0; } // Set up the list and return the first entry. // al_extend(&mudstate.iter_alist.data, &mudstate.iter_alist.len, alen+1, 0); memcpy(mudstate.iter_alist.data, astr, alen+1); *attrp = mudstate.iter_alist.data; return atr_next(attrp); #endif // MEMORY_BASED } /* * --------------------------------------------------------------------------- * * 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++) { s_Owner(thing, GOD); s_Flags(thing, (TYPE_GARBAGE | GOING)); 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].cpu_time_used.Set100ns(0); #ifdef MEMORY_BASED db[thing].ahead = NULL; db[thing].at_count = 0; #endif // MEMORY_BASED } } void db_grow(dbref newtop) { int newsize, marksize, delta, i; MARKBUF *newmarkbuf; OBJ *newdb; NAME *newpurenames; char *cp; #ifndef STANDALONE delta = mudconf.init_size; #else delta = 1000; #endif /* * 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++) { #ifndef MEMORY_BASED names[i] = NULL; #endif 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 */ #ifndef MEMORY_BASED // NOTE: There is always one copy of 'names' around that isn't freed even just before the process terminates. // We rely (quite safely) on the OS to reclaim the memory. // NAME *newnames = (NAME *) MEMALLOC((newsize + SIZE_HACK) * sizeof(NAME)); ISOUTOFMEMORY(newnames); memset(newnames, 0, (newsize + SIZE_HACK) * sizeof(NAME)); if (names) { // An old name cache exists. Copy it. // names -= SIZE_HACK; memcpy(newnames, names, (newtop + SIZE_HACK) * sizeof(NAME)); cp = (char *)names; MEMFREE(cp); cp = NULL; } else { // Creating a brand new struct database. Fill in the 'reserved' area in case it gets referenced. // names = newnames; for (i = 0; i < SIZE_HACK; i++) { names[i] = NULL; } } names = newnames + SIZE_HACK; newnames = NULL; #endif if (mudconf.cache_names) { // NOTE: There is always one copy of 'purenames' around that isn't freed even just before the process terminates. // We rely (quite safely) on the OS to reclaim the memory. // newpurenames = (NAME *)MEMALLOC((newsize + SIZE_HACK) * sizeof(NAME)); ISOUTOFMEMORY(newpurenames); memset(newpurenames, 0, (newsize + SIZE_HACK) * sizeof(NAME)); if (purenames) { // An old name cache exists. Copy it. // purenames -= SIZE_HACK; memcpy(newpurenames, purenames, (newtop + SIZE_HACK) * sizeof(NAME)); cp = (char *)purenames; MEMFREE(cp); cp = NULL; } 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 */ // NOTE: There is always one copy of 'db' around that isn't freed even just before the process terminates. // We rely (quite safely) on the OS to reclaim the memory. // newdb = (OBJ *)MEMALLOC((newsize + SIZE_HACK) * sizeof(OBJ)); ISOUTOFMEMORY(newdb); if (db) { // An old struct database exists. Copy it to the new buffer. // db -= SIZE_HACK; memcpy(newdb, db, (mudstate.db_top + SIZE_HACK) * sizeof(OBJ)); cp = (char *)db; MEMFREE(cp); cp = NULL; } 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++) { #ifdef MEMORY_BASED db[i].ahead = NULL; db[i].at_count = 0; #endif // MEMORY_BASED 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 = newdb + SIZE_HACK; newdb = NULL; for (i = mudstate.db_top; i < newtop; i++) { #ifndef MEMORY_BASED names[i] = NULL; #endif 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 *)MEMALLOC(marksize); ISOUTOFMEMORY(newmarkbuf); memset(newmarkbuf, 0, marksize); if (mudstate.markbits) { marksize = (newtop + 7) >> 3; memcpy(newmarkbuf, mudstate.markbits, marksize); cp = (char *)mudstate.markbits; MEMFREE(cp); cp = NULL; } mudstate.markbits = newmarkbuf; } void NDECL(db_free) { char *cp; if (db != NULL) { db -= SIZE_HACK; cp = (char *)db; MEMFREE(cp); cp = NULL; db = NULL; } mudstate.db_top = 0; mudstate.db_size = 0; mudstate.freelist = NOTHING; } #ifndef STANDALONE void NDECL(db_make_minimal) { dbref obj; db_free(); db_grow(1); s_Name(0, "Limbo"); s_Flags(0, TYPE_ROOM); s_Flags2(0, 0); s_Flags3(0, 0); 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); /* * 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); } #endif dbref parse_dbref(const char *s) { const char *p; int x; /* * Enforce completely numeric dbrefs */ for (p = s; *p; p++) { if (!Tiny_IsDigit[(unsigned char)*p]) return NOTHING; } x = Tiny_atol(s); return ((x >= 0) ? x : NOTHING); } void putref(FILE *f, dbref ref) { char buf[SBUF_SIZE]; int n = Tiny_ltoa(ref, buf); buf[n++] = '\n'; fwrite(buf, sizeof(char), n, f); } #define SIZEOF_PUTSTRING_BUFFER (LBUF_SIZE+4) void putstring(FILE *f, const char *pRaw) { char aBuffer[SIZEOF_PUTSTRING_BUFFER]; char *pBuffer = aBuffer; // Always leave room for four characters. One at the beginning and // three on the end. '\\"\n' or '\""\n' // char *pBufferEnd = aBuffer + SIZEOF_PUTSTRING_BUFFER - 4; *pBuffer++ = '"'; if (pRaw) { char ch = *pRaw++; while (ch) { if (pBuffer > pBufferEnd) { fwrite(aBuffer, sizeof(char), pBuffer - aBuffer, f); pBuffer = aBuffer; } if (ch == '\\' || ch == '"') { *pBuffer++ = '\\'; } *pBuffer++ = ch; ch = *pRaw++; } } *pBuffer++ = '"'; *pBuffer++ = '\n'; fwrite(aBuffer, sizeof(char), pBuffer - aBuffer, f); } // Code 0 - Any byte. // Code 1 - CR (0x0D) // Code 2 - '"' (0x22) // Code 3 - '\\' (0x5C) // char xlat_table[256] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #define STATE_START 0 #define STATE_HAVE_ESC 1 // Action 0 - Emit X. // Action 1 - Get a Buffer. // Action 2 - Emit X. Move to START state. // Action 3 - Move to ESC state. // Action 4 - Terminate parse. // int action_table[2][4] = { // Any '\0' " \ { 0, 1, 3, 4 }, // STATE_START { 2, 1, 2, 2 } // STATE_ESC }; char *getstring_noalloc(FILE *f, int new_strings) { static char buf[2*LBUF_SIZE + 20]; int c; c = fgetc(f); if (new_strings && c == '"') { int nBufferLeft = sizeof(buf)-10; int iState = STATE_START; char *pOutput = buf; for (;;) { // Fetch up to and including the next LF. // char *pInput = pOutput + 6; if (fgets(pInput, nBufferLeft, f) == NULL) { // EOF or ERROR. // *pOutput = 0; return buf; } int nOutput = 0; // De-escape this data. removing the '\\' prefixes. // Terminate when you hit a '"'. // for (;;) { int ch = *pInput++; if (iState == STATE_START) { if (xlat_table[ch] == 0) { // As long as xlat_table[*p] is 0, just keep copying the characters. // char *p = pOutput; do { *pOutput++ = ch; ch = *pInput++; } while (xlat_table[ch] == 0); nOutput = pOutput - p; } } int iAction = action_table[iState][xlat_table[ch]]; if (iAction <= 2) { if (iAction == 1) { // Get Buffer and remain in the current state. // break; } else { // iAction == 2 // Emit X and move to START state. // *pOutput++ = ch; nOutput++; iState = STATE_START; } } else if (iAction == 3) { // Terminate parsing. // *pOutput = 0; return buf; } else { // iAction == 4 // Move to ESC state. // iState = STATE_HAVE_ESC; } } nBufferLeft -= nOutput; // Do we have any more room? // if (nBufferLeft <= 0) { *pOutput = 0; return buf; } } } else { ungetc(c, f); char *p = buf; for (;;) { // Fetch up to and including the next LF. // if (fgets(p, LBUF_SIZE, f) == NULL) { // EOF or ERROR. // p[0] = 0; } else { // How much data did we fetch? // int nLine = strlen(p); if (nLine >= 2) { if (p[nLine-2] == '\r') { // Line is continued on the next line. // p += nLine; continue; } // Eat '\n' // p[nLine-1] = '\0'; } } return buf; } } } dbref getref(FILE *f) { static char buf[SBUF_SIZE]; fgets(buf, sizeof(buf), f); return Tiny_atol(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: MEMFREE((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 *)StringClone((char *)b->sub1); break; default: Log.WriteString("bad bool type!!\n"); return TRUE_BOOLEXP; } return (r); } void clone_object(dbref a, dbref b) { memcpy(&db[a], &db[b], sizeof(struct object)); } #ifndef MEMORY_BASED int init_dbfile(char *game_dir_file, char *game_pag_file) { #ifdef STANDALONE Log.printf("Opening (%s,%s)\n", game_dir_file, game_pag_file); #endif int cc = cache_init(game_dir_file, game_pag_file); if (cc != HF_OPEN_STATUS_ERROR) { #ifdef STANDALONE Log.printf("Done opening (%s,%s).\n", game_dir_file, game_pag_file); #else STARTLOG(LOG_ALWAYS, "INI", "LOAD"); Log.printf("Using game db files: (%s,%s).", game_dir_file, game_pag_file); ENDLOG; #endif db_free(); } return cc; } #endif // MEMORY_BASED #ifndef STANDALONE /* * 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)); } } // This function releases: // // 1. comsys resources associated with an object. // 2. @mail resources associated with an object. // void ReleaseAllResources(dbref obj) { if (mudconf.have_comsys) { do_comdisconnect(obj); do_clearcom(obj, obj, 0); do_channelnuke(obj); del_comsys(obj); } if (mudconf.have_mailer) { do_mail_clear(obj, NULL); do_mail_purge(obj); } } #else int check_zone(dbref player, dbref thing) { return 0; } #endif // STANDALONE #if !defined(STANDALONE) && !defined(VMS) && !defined(WIN32) /* * --------------------------------------------------------------------------- * * dump_restart_db: Writes out socket information. */ void dump_restart_db(void) { FILE *f; 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. */ #ifdef CONCENTRATE version |= RS_CONCENTRATE; #endif version |= RS_RECORD_PLAYERS; version |= RS_NEW_STRINGS; f = fopen("restart.db", "wb"); fprintf(f, "+V%d\n", version); putref(f, MainGameSockPort); putref(f, mudstate.start_time.ReturnSeconds()); putstring(f, mudstate.doing_hdr); #ifdef CONCENTRATE putref(f, conc_pid); #endif putref(f, mudstate.record_players); DESC_ITER_ALL(d) { putref(f, d->descriptor); putref(f, d->flags); putref(f, d->connected_at.ReturnSeconds()); putref(f, d->command_count); putref(f, d->timeout); putref(f, d->host_info); putref(f, d->player); putref(f, d->last_time.ReturnSeconds()); putstring(f, d->output_prefix); putstring(f, d->output_suffix); putstring(f, d->addr); putstring(f, d->doing); putstring(f, d->username); #ifdef CONCENTRATE putref(f, d->concid); putref(f, d->cstatus); #endif } putref(f, 0); fclose(f); } void load_restart_db(void) { FILE *f; DESC *d; DESC *p; #ifdef CONCENTRATE DESC *k; #endif 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); Tiny_Assert(strncmp(buf, "+V", 2) == 0); version = getref(f); MainGameSockPort = getref(f); if (version & RS_NEW_STRINGS) new_strings = 1; maxd = MainGameSockPort + 1; mudstate.start_time.SetSeconds(getref(f)); strcpy(mudstate.doing_hdr, getstring_noalloc(f, new_strings)); if (version & RS_CONCENTRATE) { #ifdef CONCENTRATE conc_pid = getref(f); #else (void)getref(f); #endif } if (version & RS_RECORD_PLAYERS) { mudstate.record_players = getref(f); } while ((val = getref(f)) != 0) { ndescriptors++; d = alloc_desc("restart"); d->descriptor = val; d->flags = getref(f); d->connected_at.SetSeconds(getref(f)); d->command_count = getref(f); d->timeout = getref(f); d->host_info = getref(f); d->player = getref(f); d->last_time.SetSeconds(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_CONCENTRATE) { #ifdef CONCENTRATE d->concid = getref(f); d->cstatus = getref(f); #else (void)getref(f); (void)getref(f); #endif } d->output_size = 0; d->output_tot = 0; d->output_lost = 0; d->output_head = NULL; d->output_tail = NULL; d->input_head = NULL; d->input_tail = NULL; d->input_size = 0; d->input_tot = 0; d->input_lost = 0; d->raw_input = NULL; d->raw_input_at = NULL; d->quota = mudconf.cmd_quota_max; d->program_data = NULL; d->hashnext = NULL; 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; } if (d->descriptor >= maxd) { maxd = d->descriptor + 1; } desc_addhash(d); #ifdef CONCENTRATE if (!(d->cstatus & C_CCONTROL)) #endif if (isPlayer(d->player)) { s_Flags2(d->player, Flags2(d->player) | CONNECTED); } } DESC_ITER_CONN(d) { if (!isPlayer(d->player)) { shutdownsock(d, R_QUIT); } #ifdef CONCENTRATE if (d->cstatus & C_REMOTE) { DESC_ITER_ALL(k) { if (k->descriptor = d->descriptor) { d->parent = k; } } } #endif } fclose(f); remove("restart.db"); raw_broadcast(0, "Game: Restart finished."); } #endif // !STANDALONE && !WIN32 #ifdef WIN32 int ReplaceFile(char *old_name, char *new_name) { DeleteFile(new_name); if (MoveFile(old_name, new_name)) { return 0; } else { Log.printf("MoveFile %s to %s fails with GetLastError() of %d\n", old_name, new_name, GetLastError()); } return -1; } void RemoveFile(char *name) { DeleteFile(name); } #else // WIN32 int ReplaceFile(char *old_name, char *new_name) { if (rename(old_name, new_name) == 0) { return 0; } else { Log.printf("rename %s to %s fails with errno of %s(%d)\n", old_name, new_name, strerror(errno), errno); } return -1; } void RemoveFile(char *name) { unlink(name); } #endif // WIN32