This is patch03 to PennMUSH 1.8.2. After applying this patch, you will have version 1.8.2p3 To apply this patch, save it to a file in your top-level MUSH directory, and do the following: patch -p1 < 1.8.2-patch03 make clean make install If you use GNU patch 2.2, you probably want the above to be 'patch -b -p1', not just 'patch -p1'. Unix (or cygwin) users need not worry about failed hunks in src/switchinc.c, hdrs/switches.h, hdrs/cmds.h, or hdrs/funs.h. These files are automatically rebuilt on compile. On the off chance they appear not to be, simply rm them and re-run make. Then @shutdown and restart your MUSH. - Ervin/Noltar In this patch: Fixes: * Unterminated buffer in sortkey() fixed. Reported by Balerion. Patch by Javelin. * Memory leaks in setunion() and revwords() fixed by Javelin. * Crash bug in speak() fixed. Reported by Trinsec. Patch by Javelin. * Crash bug in buy fixed. Reported by Amy. Patch by Javelin. * If we should fail to clear a semaphore attribute for some reason (e.g., it's the branch of an attribute tree), reset the semaphore count on the attribute to 0. Patch by Javelin. * iter() dealt badly with freeing buffers when CPU_LIMIT or function_invocation_limit was hit. Found by Ashen-Shugar. [GM] * @ps/all displayed the wrong queue entry count for mortals. Reported by Cheetah. [SW] * @hook/override of say would get an extra leading " if that was used instead of the literal say command. Reported by Tuxedo Ian. [SW] * Fixed a bug where speech seemed to come from the wrong object for nospoof information. Reported by Jules. [SW] * The help entry for @poll failed to mention @poll/clear. Reported by Cooee. [SW] Prereq: 1.8.2p2 *** 1_8_2p2/Patchlevel Sat Jan 27 02:20:54 2007 --- 1_8_2p3/Patchlevel Sun Mar 11 20:21:16 2007 *************** *** 1,2 **** Do not edit this file. It is maintained by the official PennMUSH patches. ! This is PennMUSH 1.8.2p2 --- 1,2 ---- Do not edit this file. It is maintained by the official PennMUSH patches. ! This is PennMUSH 1.8.2p3 *** 1_8_2p2/CHANGES.182 Sat Jan 27 02:20:54 2007 --- 1_8_2p3/CHANGES.182 Sun Mar 11 20:21:16 2007 *************** *** 14,19 **** --- 14,42 ---- ========================================================================== + Version 1.8.2 patchlevel 3 March 11, 2007 + + Fixes: + * Unterminated buffer in sortkey() fixed. Reported by Balerion. + Patch by Javelin. + * Memory leaks in setunion() and revwords() fixed by Javelin. + * Crash bug in speak() fixed. Reported by Trinsec. Patch by Javelin. + * Crash bug in buy fixed. Reported by Amy. Patch by Javelin. + * If we should fail to clear a semaphore attribute for some + reason (e.g., it's the branch of an attribute tree), reset + the semaphore count on the attribute to 0. Patch by Javelin. + * iter() dealt badly with freeing buffers when CPU_LIMIT or + function_invocation_limit was hit. Found by Ashen-Shugar. [GM] + * @ps/all displayed the wrong queue entry count for mortals. + Reported by Cheetah. [SW] + * @hook/override of say would get an extra leading " if that was + used instead of the literal say command. Reported by Tuxedo Ian. + [SW] + * Fixed a bug where speech seemed to come from the wrong + object for nospoof information. Reported by Jules. [SW] + * The help entry for @poll failed to mention @poll/clear. + Reported by Cooee. [SW] + Version 1.8.2 patchlevel 2 January 27, 2007 Fixes: *** 1_8_2p2/game/txt/hlp/penncmd.hlp Sat Jan 27 02:20:53 2007 --- 1_8_2p3/game/txt/hlp/penncmd.hlp Sun Mar 11 20:21:15 2007 *************** *** 2692,2701 **** See also @emit, @oemit, @remit, NOSPOOF, and SPOOFING. & @poll @poll ! This wizard-only command sets the "poll" - the Doing question. If ! "@poll" is used by itself, the question is reset to the default ! string "Doing". It can also be used by those with the poll @power. See also: @doing, WHO, DOING & @poor --- 2692,2704 ---- See also @emit, @oemit, @remit, NOSPOOF, and SPOOFING. & @poll + @poll @poll ! @poll/clear ! ! This command manipulate the message at the top of WHO/DOING. By itself, ! it displays the current poll. Wizards and those with the poll @power can ! set or clear the message. See also: @doing, WHO, DOING & @poor *** 1_8_2p2/game/txt/hlp/pennv182.hlp Sat Jan 27 02:20:53 2007 --- 1_8_2p3/game/txt/hlp/pennv182.hlp Sun Mar 11 20:21:15 2007 *************** *** 1,4 **** ! & 1.8.2p2 & changes This is a list of changes in this patchlevel which are probably of interest to players. More information about new commands and functions --- 1,4 ---- ! & 1.8.2p3 & changes This is a list of changes in this patchlevel which are probably of interest to players. More information about new commands and functions *************** *** 11,16 **** --- 11,40 ---- A list of the patchlevels associated with each release can be read in 'help patchlevels'. + Version 1.8.2 patchlevel 3 March 11, 2007 + + Fixes: + * Unterminated buffer in sortkey() fixed. Reported by Balerion. + Patch by Javelin. + * Memory leaks in setunion() and revwords() fixed by Javelin. + * Crash bug in speak() fixed. Reported by Trinsec. Patch by Javelin. + * Crash bug in buy fixed. Reported by Amy. Patch by Javelin. + * If we should fail to clear a semaphore attribute for some + reason (e.g., it's the branch of an attribute tree), reset + the semaphore count on the attribute to 0. Patch by Javelin. + * iter() dealt badly with freeing buffers when CPU_LIMIT or + function_invocation_limit was hit. Found by Ashen-Shugar. [GM] + * @ps/all displayed the wrong queue entry count for mortals. + Reported by Cheetah. [SW] + * @hook/override of say would get an extra leading " if that was + used instead of the literal say command. Reported by Tuxedo Ian. + [SW] + * Fixed a bug where speech seemed to come from the wrong + object for nospoof information. Reported by Jules. [SW] + * The help entry for @poll failed to mention @poll/clear. + Reported by Cooee. [SW] + + & 1.8.2p2 Version 1.8.2 patchlevel 2 January 27, 2007 Fixes: *************** *** 30,35 **** --- 54,60 ---- of the name for @ahear/@aahear/@amhear. [SW] * Fixed the distribution of random numbers with a huge range. Reported by Luke. + & 1.8.2p1 Version 1.8.2 patchlevel 1 November 26, 2006 *** 1_8_2p2/hdrs/version.h Sat Jan 27 02:20:54 2007 --- 1_8_2p3/hdrs/version.h Sun Mar 11 20:21:16 2007 *************** *** 1,4 **** #define VERSION "1.8.2" ! #define PATCHLEVEL "2" ! #define PATCHDATE "[01/27/2007]" ! #define NUMVERSION 1008002002 --- 1,4 ---- #define VERSION "1.8.2" ! #define PATCHLEVEL "3" ! #define PATCHDATE "[03/11/2007]" ! #define NUMVERSION 1008002003 *** 1_8_2p2/src/attrib.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/attrib.c Sun Mar 11 20:21:14 2007 *************** *** 461,466 **** --- 461,473 ---- set_default_flags(atr, flags); num_new++; } + /* Only GOD can create an AF_NODUMP attribute (used for semaphores) + * or add a leaf to a tree with such an attribute + */ + if ((AL_FLAGS(atr) & AF_NODUMP) && (player != GOD)) { + missing_name[0] = '\0'; + return AE_ERROR; + } if (Cannot_Write_This_Attr(player, atr, 1)) { missing_name[0] = '\0'; return AE_ERROR; *** 1_8_2p2/src/bsd.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/bsd.c Sun Mar 11 20:21:14 2007 *************** *** 3786,3792 **** int first; int start, count; int powered = (*(called_as + 1) != 'M'); ! int objid = (index(called_as, 'D') != NULL); if (!is_strict_integer(args[0]) || !is_strict_integer(args[1])) { safe_str(T(e_int), buff, bp); --- 3786,3792 ---- int first; int start, count; int powered = (*(called_as + 1) != 'M'); ! int objid = (strchr(called_as, 'D') != NULL); if (!is_strict_integer(args[0]) || !is_strict_integer(args[1])) { safe_str(T(e_int), buff, bp); *************** *** 3844,3850 **** int first; dbref victim; int powered = ((*called_as == 'L') && Priv_Who(executor)); ! int objid = (index(called_as, 'D') != NULL); first = 1; --- 3844,3850 ---- int first; dbref victim; int powered = ((*called_as == 'L') && Priv_Who(executor)); ! int objid = (strchr(called_as, 'D') != NULL); first = 1; *** 1_8_2p2/src/command.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/command.c Sun Mar 11 20:21:15 2007 *************** *** 912,919 **** --- 912,922 ---- return NULL; case SAY_TOKEN: replacer = "SAY"; + #if 0 + /* Messes up hooks when chat_strip_quote is yes. See bug #6677 */ if (CHAT_STRIP_QUOTE) p--; /* Since 'say' strips out the '"' */ + #endif break; case POSE_TOKEN: replacer = "POSE"; *** 1_8_2p2/src/cque.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/cque.c Sun Mar 11 20:21:15 2007 *************** *** 123,132 **** if (a) num = parse_integer(atr_value(a)); num += am; ! if (num) { ! sprintf(buff, "%d", num); ! (void) atr_add(player, name, buff, GOD, flags); ! } else { (void) atr_clr(player, name, GOD); } return (num); --- 123,135 ---- if (a) num = parse_integer(atr_value(a)); num += am; ! /* We set the attribute's value to 0 even if we're going to clear ! * it later, because clearing it may fail (perhaps someone's also ! * foolishly using it as a branch in an attribute tree) ! */ ! sprintf(buff, "%d", num); ! (void) atr_add(player, name, buff, GOD, flags); ! if (!num) { (void) atr_clr(player, name, GOD); } return (num); *************** *** 903,930 **** if (!GoodObject(tmp->player)) (*del)++; else if (q_all || (Owner(tmp->player) == victim)) { ! (*self)++; ! if (!q_quiet && (LookQueue(player) ! || Owns(tmp->player, player))) { switch (q_type) { case 1: /* wait queue */ ! notify_format(player, "[%ld]%s:%s", tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); break; case 2: /* semaphore queue */ if (tmp->left != 0) { ! notify_format(player, "[#%d/%s/%ld]%s:%s", tmp->sem, tmp->semattr, tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); } else { ! notify_format(player, "[#%d/%s]%s:%s", tmp->sem, tmp->semattr, unparse_object(player, tmp->player), tmp->comm); } break; default: /* player or object queue */ ! notify_format(player, "%s:%s", unparse_object(player, ! tmp->player), tmp->comm); } } --- 906,935 ---- if (!GoodObject(tmp->player)) (*del)++; else if (q_all || (Owner(tmp->player) == victim)) { ! if ((LookQueue(player) ! || Owns(tmp->player, player))) { ! (*self)++; ! if (q_quiet) ! continue; switch (q_type) { case 1: /* wait queue */ ! notify_format(player, "[%ld]%s: %s", tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); break; case 2: /* semaphore queue */ if (tmp->left != 0) { ! notify_format(player, "[#%d/%s/%ld]%s: %s", tmp->sem, tmp->semattr, tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); } else { ! notify_format(player, "[#%d/%s]%s: %s", tmp->sem, tmp->semattr, unparse_object(player, tmp->player), tmp->comm); } break; default: /* player or object queue */ ! notify_format(player, "%s: %s", unparse_object(player, ! tmp->player), tmp->comm); } } *** 1_8_2p2/src/filecopy.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/filecopy.c Sun Mar 11 20:21:15 2007 *************** *** 206,212 **** #ifndef _DEBUG char FileName[256]; if (GetModuleFileName(NULL, FileName, 256) != 0) { ! if (!strcasecmp(rindex(FileName, '\\') + 1, "pennmush.exe")) { if (CopyFile("pennmush.exe", "pennmush_run.exe", FALSE)) { do_rawlog(LT_ERR, "Successfully copied executable, starting copy."); #ifdef WIN32SERVICES --- 206,212 ---- #ifndef _DEBUG char FileName[256]; if (GetModuleFileName(NULL, FileName, 256) != 0) { ! if (!strcasecmp(strrchr(FileName, '\\') + 1, "pennmush.exe")) { if (CopyFile("pennmush.exe", "pennmush_run.exe", FALSE)) { do_rawlog(LT_ERR, "Successfully copied executable, starting copy."); #ifdef WIN32SERVICES *** 1_8_2p2/src/funlist.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/funlist.c Sun Mar 11 20:21:15 2007 *************** *** 1211,1223 **** char sep; char outsep[BUFFER_LEN]; int i; - char tbuff[BUFFER_LEN]; - char *tp; - char const *cp; char result[BUFFER_LEN]; ! char *rp; ! ATTR *attrib; ! dbref thing; /* sortkey(attr,list,sort_type,delim,osep) */ --- 1211,1219 ---- char sep; char outsep[BUFFER_LEN]; int i; char result[BUFFER_LEN]; ! ufun_attrib ufun; ! char *wenv[1]; /* sortkey(attr,list,sort_type,delim,osep) */ *************** *** 1233,1264 **** } else strcpy(outsep, args[4]); ! /* Find object and attribute to get sortby function from. */ ! parse_anon_attrib(executor, args[0], &thing, &attrib); ! if (!GoodObject(thing) || !attrib || !Can_Read_Attr(executor, thing, attrib)) { ! free_anon_attrib(attrib); ! return; ! } ! if (!CanEvalAttr(executor, thing, attrib)) { ! free_anon_attrib(attrib); return; - } - tp = tbuff; - safe_str(atr_value(attrib), tbuff, &tp); - *tp = '\0'; - nptrs = list2arr_ansi(ptrs, MAX_SORTSIZE, args[1], sep); /* Now we make a list of keys */ for (i = 0; i < nptrs; i++) { ! global_eval_context.wenv[0] = (char *) ptrs[i]; ! rp = result; ! cp = tbuff; ! process_expression(result, &rp, &cp, ! thing, executor, enactor, ! PE_DEFAULT, PT_DEFAULT, pe_info); ! *rp = '\0'; keys[i] = mush_strdup(result, "sortkey"); } --- 1229,1245 ---- } else strcpy(outsep, args[4]); ! /* find our object and attribute */ ! if (!fetch_ufun_attrib(args[0], executor, &ufun, 1)) return; nptrs = list2arr_ansi(ptrs, MAX_SORTSIZE, args[1], sep); /* Now we make a list of keys */ for (i = 0; i < nptrs; i++) { ! /* Build our %0 args */ ! wenv[0] = (char *)ptrs[i]; ! call_ufun(&ufun, wenv, 2, result, executor, enactor, pe_info); keys[i] = mush_strdup(result, "sortkey"); } *************** *** 1461,1467 **** { char sep; char **a1, **a2; ! int n1, n2, x1, x2, val; int lastx1, lastx2, found; char *sort_type = ALPHANUM_LIST; int osepl = 0; --- 1442,1448 ---- { char sep; char **a1, **a2; ! int n1, n2, x1, x2, val, orign1, orign2; int lastx1, lastx2, found; char *sort_type = ALPHANUM_LIST; int osepl = 0; *************** *** 1480,1487 **** mush_panic("Unable to allocate memory in fun_setunion"); /* make arrays out of the lists */ ! n1 = list2arr_ansi(a1, MAX_SORTSIZE, args[0], sep); ! n2 = list2arr_ansi(a2, MAX_SORTSIZE, args[1], sep); if (nargs < 4) { osepd[0] = sep; --- 1461,1468 ---- mush_panic("Unable to allocate memory in fun_setunion"); /* make arrays out of the lists */ ! orign1 = n1 = list2arr_ansi(a1, MAX_SORTSIZE, args[0], sep); ! orign2 = n2 = list2arr_ansi(a2, MAX_SORTSIZE, args[1], sep); if (nargs < 4) { osepd[0] = sep; *************** *** 1589,1596 **** } } } ! freearr(a1, n1); ! freearr(a2, n2); mush_free((Malloc_t) a1, "ptrarray"); mush_free((Malloc_t) a2, "ptrarray"); } --- 1570,1577 ---- } } } ! freearr(a1, orign1); ! freearr(a2, orign2); mush_free((Malloc_t) a1, "ptrarray"); mush_free((Malloc_t) a2, "ptrarray"); } *************** *** 2585,2591 **** FUNCTION(fun_revwords) { char **words; ! int count; char sep; char *osep, osepd[2] = { '\0', '\0' }; --- 2566,2572 ---- FUNCTION(fun_revwords) { char **words; ! int count, origcount; char sep; char *osep, osepd[2] = { '\0', '\0' }; *************** *** 2601,2607 **** words = (char **) mush_malloc(sizeof(char *) * BUFFER_LEN, "wordlist"); ! count = list2arr_ansi(words, BUFFER_LEN, args[0], sep); if (count == 0) { mush_free((Malloc_t) words, "wordlist"); return; --- 2582,2588 ---- words = (char **) mush_malloc(sizeof(char *) * BUFFER_LEN, "wordlist"); ! origcount = count = list2arr_ansi(words, BUFFER_LEN, args[0], sep); if (count == 0) { mush_free((Malloc_t) words, "wordlist"); return; *************** *** 2612,2618 **** safe_str(osep, buff, bp); safe_str(words[--count], buff, bp); } ! freearr(words, count); mush_free((Malloc_t) words, "wordlist"); } --- 2593,2599 ---- safe_str(osep, buff, bp); safe_str(words[--count], buff, bp); } ! freearr(words, origcount); mush_free((Malloc_t) words, "wordlist"); } *************** *** 2746,2755 **** tbuf2 = replace_string2(standard_tokens, replace, args[1]); sp = tbuf2; if (process_expression(buff, bp, &sp, executor, caller, enactor, ! PE_DEFAULT, PT_DEFAULT, pe_info)) break; ! if (*bp == (buff + BUFFER_LEN - 1) && pe_info->fun_invocations == funccount) break; funccount = pe_info->fun_invocations; oldbp = *bp; mush_free((Malloc_t) tbuf2, "replace_string.buff"); --- 2727,2740 ---- tbuf2 = replace_string2(standard_tokens, replace, args[1]); sp = tbuf2; if (process_expression(buff, bp, &sp, executor, caller, enactor, ! PE_DEFAULT, PT_DEFAULT, pe_info)) { ! mush_free((Malloc_t) tbuf2, "replace_string.buff"); break; ! } ! if (*bp == (buff + BUFFER_LEN - 1) && pe_info->fun_invocations == funccount) { ! mush_free((Malloc_t) tbuf2, "replace_string.buff"); break; + } funccount = pe_info->fun_invocations; oldbp = *bp; mush_free((Malloc_t) tbuf2, "replace_string.buff"); *** 1_8_2p2/src/funmisc.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/funmisc.c Sun Mar 11 20:21:14 2007 *************** *** 68,73 **** --- 68,74 ---- { int ns = string_prefix(called_as, "NS"); int flags = PEMIT_LIST; + dbref saved_orator = orator; if (!command_check_byname(executor, ns ? "@nspemit" : "@pemit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); *************** *** 77,82 **** --- 78,84 ---- if (ns) flags |= PEMIT_SPOOF; do_pemit_list(executor, args[0], args[1], flags); + orator = saved_orator; } *** 1_8_2p2/src/funstr.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/funstr.c Sun Mar 11 20:21:14 2007 *************** *** 2247,2253 **** if (strlen(rbuff) > 0) { safe_format(buff, bp, "%s %s %s", Name(speaker), say_string, rbuff); return; ! } else { wenv[0] = speaker_str; wenv[1] = unparse_integer(fragment); if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) --- 2247,2253 ---- if (strlen(rbuff) > 0) { safe_format(buff, bp, "%s %s %s", Name(speaker), say_string, rbuff); return; ! } else if (null == 1) { wenv[0] = speaker_str; wenv[1] = unparse_integer(fragment); if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) *************** *** 2297,2303 **** pe_info->fun_invocations == funccount) break; funccount = pe_info->fun_invocations; ! if (strlen(rbuff) == 0) { wenv[0] = speaker_str; wenv[1] = unparse_integer(fragment); if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) --- 2297,2303 ---- pe_info->fun_invocations == funccount) break; funccount = pe_info->fun_invocations; ! if ((null == 1) && (strlen(rbuff) == 0)) { wenv[0] = speaker_str; wenv[1] = unparse_integer(fragment); if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) *** 1_8_2p2/src/rob.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/rob.c Sun Mar 11 20:21:14 2007 *************** *** 158,164 **** do_buy(dbref player, char *item, char *from, int price) { dbref vendor; ! char *prices; char *plus; char *cost; char finditem[BUFFER_LEN]; --- 158,164 ---- do_buy(dbref player, char *item, char *from, int price) { dbref vendor; ! char prices[BUFFER_LEN]; char *plus; char *cost; char finditem[BUFFER_LEN]; *************** *** 226,235 **** a = atr_get(vendor, "PRICELIST"); if (!a) continue; ! /* atr_value uses a static buffer, so we'll take advantage of that */ ! prices = atr_value(a); upcasestr(prices); ! count = list2arr(r, BUFFER_LEN / 2, atr_value(a), ' '); if (!count) continue; for (i = 0; i < count; i++) { --- 226,235 ---- a = atr_get(vendor, "PRICELIST"); if (!a) continue; ! strncpy(prices,atr_value(a),BUFFER_LEN); ! prices[BUFFER_LEN-1] = '\0'; upcasestr(prices); ! count = list2arr(r, BUFFER_LEN / 2, prices, ' '); if (!count) continue; for (i = 0; i < count; i++) { *** 1_8_2p2/src/utils.c Sat Jan 27 02:20:53 2007 --- 1_8_2p3/src/utils.c Sun Mar 11 20:21:14 2007 *************** *** 146,153 **** AL_FLAGS(*attrib) = AF_ANON; AL_NEXT(*attrib) = NULL; *thing = player; - return; } } parse_attrib(player, str, thing, attrib); } --- 146,153 ---- AL_FLAGS(*attrib) = AF_ANON; AL_NEXT(*attrib) = NULL; *thing = player; } + return; } parse_attrib(player, str, thing, attrib); } *** 1_8_2p2/win32/cmds.h Sat Jan 27 02:20:54 2007 --- 1_8_2p3/win32/cmds.h Sun Mar 11 21:02:16 2007 *************** *** 134,141 **** COMMAND_PROTO(cmd_version); COMMAND_PROTO(cmd_wait); COMMAND_PROTO(cmd_wall); - COMMAND_PROTO(cmd_warnings); COMMAND_PROTO(cmd_warn_on_missing); COMMAND_PROTO(cmd_wcheck); COMMAND_PROTO(cmd_whereis); COMMAND_PROTO(cmd_whisper); --- 134,141 ---- COMMAND_PROTO(cmd_version); COMMAND_PROTO(cmd_wait); COMMAND_PROTO(cmd_wall); COMMAND_PROTO(cmd_warn_on_missing); + COMMAND_PROTO(cmd_warnings); COMMAND_PROTO(cmd_wcheck); COMMAND_PROTO(cmd_whereis); COMMAND_PROTO(cmd_whisper);