Subject: pkg/19262: segmentation fault during ezmlm-send resulting in core dump on 64-bit platforms
To: None <gnats-bugs@gnats.netbsd.org>
From: None <tom@minnesota.com>
List: netbsd-bugs
Date: 12/04/2002 10:43:47
>Number:         19262
>Category:       pkg
>Synopsis:       segmentation fault during ezmlm-send resulting in core dump on 64-bit platforms
>Confidential:   yes
>Severity:       critical
>Priority:       high
>Responsible:    pkg-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Dec 04 02:44:00 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     Thomas T. Thai
>Release:        NetBSD 1.6
>Organization:

--
Thomas T. Thai
Minnesota.com, Inc.
>Environment:
System: NetBSD ns01 1.6 NetBSD 1.6 (ns01-1.6) #1: Mon Nov 25 17:03:01 CST 2002 root@ns01:/usr/src/1.6/sys/arch/alpha/compile/ns01-1.6 alpha
Architecture: alpha
Machine: alpha
>Description:
/usr/pkgsrc/mail/ezmlm-idx  ezmlm-idx-0.40 (latest pkgsrc) once installed and 
running will core dump when ezmlm-send is executed on 64-bit platforms
(tested on Alpha and Solaris). 
>How-To-Repeat:
send a message via ezmlm-send on 64-bit platform system.
>Fix:
diff -u ezmlm-0.53.orig/Makefile ezmlm-0.53/Makefile
--- ezmlm-0.53.orig/Makefile	Fri Jul  5 13:19:04 2002
+++ ezmlm-0.53/Makefile	Fri Jul  5 13:09:31 2002
@@ -663,10 +663,10 @@
 load ezmlm-send.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \
 slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a conf-sqlld \
 substdio.a cookie.o stralloc.a alloc.a error.a str.a fd.a case.a fs.a surf.a \
-getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o
+getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o seek.a
 	./load ezmlm-send subdb.a cookie.o surf.a auto_qmail.o getconf.o \
 	getopt.a qmail.o quote.o constmap.o slurp.o slurpclose.o \
-	wait.a getln.a strerr.a \
+	wait.a getln.a strerr.a seek.a \
 	sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a error.a \
 	fd.a case.a fs.a getopt.a copy.o mime.a makehash.o str.a ${SQLLD}
 
@@ -679,17 +679,17 @@
 subfd.h substdio.h strerr.h error.h qmail.h env.h makehash.h sgetopt.h \
 lock.h sig.h open.h getln.h case.h scan.h str.h fmt.h readwrite.h quote.h \
 exit.h getconf.h constmap.h byte.h errtxt.h idx.h mime.h subscribe.h \
-uint32.h
+uint32.h seek.h
 	./compile ezmlm-send.c
 
 ezmlm-master: \
 load ezmlm-master.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \
 slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a conf-sqlld \
 substdio.a cookie.o stralloc.a alloc.a error.a str.a fd.a case.a fs.a surf.a\
-getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o
+getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o seek.a
 	./load ezmlm-master subdb.a cookie.o surf.a auto_qmail.o getconf.o \
 	getopt.a qmail.o quote.o constmap.o slurp.o slurpclose.o \
-	wait.a getln.a strerr.a \
+	wait.a getln.a strerr.a seek.a \
 	sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a error.a \
 	fd.a case.a fs.a getopt.a copy.o mime.a makehash.o str.a ${SQLLD}
 
@@ -702,7 +702,7 @@
 subfd.h substdio.h strerr.h error.h qmail.h env.h makehash.h sgetopt.h \
 lock.h sig.h open.h getln.h case.h scan.h str.h fmt.h readwrite.h quote.h \
 exit.h getconf.h constmap.h byte.h errtxt.h idx.h mime.h subscribe.h \
-uint32.h
+uint32.h seek.h
 	./compile ezmlm-master.c
 
 ezmlm-slave: \
diff -u ezmlm-0.53.orig/ezmlm-cgi.1 ezmlm-0.53/ezmlm-cgi.1
--- ezmlm-0.53.orig/ezmlm-cgi.1	Fri Dec 24 14:15:01 1999
+++ ezmlm-0.53/ezmlm-cgi.1	Fri Jul  5 13:09:31 2002
@@ -234,16 +234,21 @@
 to avoid trapping robots in the archive.
 .SH EXECUTION
 .B ezmlm-cgi
-can operate in three modes,
-.IR SUID\ root ,
-.IR SUID\ user ,
+can operate in two modes,
+.I SUID\ root
 and
 .IR normal .
+.B ezmlm-cgi
+should not be installed SUID
+.I user
+other than root.
+Please see the
+.B SECURITY
+section before installing SUID
+.IR root .
 
 In
 .I normal
-and
-.I SUID user
 mode,
 .B ezmlm-cgi
 will read the configuration file
@@ -255,9 +260,7 @@
 .B ezmlm-cgi
 is in), then
 change directory to the list directory. ``uid'' is ignored.
-.I SUID user
-may be required to read the particular archive if it is not owned by the
-httpd user. For user installations or systems where
+For user installations or systems where
 the httpd user has access to all the lists,
 .I normal
 mode usually gives sufficient access.
@@ -277,22 +280,10 @@
 directory is not, it is safest to leave ``uid'' blank. The httpd user will still
 be able to read the files.
 .SH "EXECUTION OF BANNER PROGRAMS"
-A banner program can be specified in the config file. It is executed
-immediately before the end of the text. The formatting for
-``<BODY>'' is active and the banner program output is encapsulated in
-a ``<DIV class=banner>'' segment to allow additional formatting.
-The banner program is called for all summary views, but not for the message
-view itself.
-
-The banner program is give the list local name as argument 1, and the host
-name as argument 2. It is expected to exit 0 on success. The return code is
-checked, but the archive page (and whatever the banner program has already
-produced) is output even if the banner program fails.
-
-.B chroot(3)
-may make it difficult to run banner programs that depend on e.g. ``sh''
-or ``perl''. For this reason, the chroot call can be suppressed by prefixing
-the ``uid'' with a ``-''.
+.B ezmlm-cgi
+supports display of banners, but not execution of banner programs. To
+obtain dynamic banners, use a URL that points to a banner program elsewhere.
+
 .SH SECURITY
 .B ezmlm-cgi
 will refuse to run as root.
@@ -308,14 +299,8 @@
 list directories and archives).
 
 .B ezmlm-cgi
-will allow execution of banner programs that are located outside of the list
-directory. These are executed with the privileges of the userid set in the
-config file. If the program is installed SUID root, banner programs outside
-of the list directory are not normally accessible. Even when this is overridden,
-.B ezmlm-cgi
-will never execute the program with root permissions.
+will not allow execution of banner programs.
 
-Input to the CGI script is not propagated to the banner program.
 .SH BUGS
 .B ezmlm-send(1)
 updates the list message counter once a message is safely archived, but
diff -u ezmlm-0.53.orig/ezmlm-cgi.c ezmlm-0.53/ezmlm-cgi.c
--- ezmlm-0.53.orig/ezmlm-cgi.c	Fri Dec 24 14:15:01 1999
+++ ezmlm-0.53/ezmlm-cgi.c	Fri Jul  5 13:09:52 2002
@@ -88,7 +88,7 @@
 #define ITEM_DATE 4
 #define ITEM_INDEX 5
 
-#define DIRECT "psnpn"
+#define DIRECT "psnpnz"
 #define DIRECT_SAME 0
 #define DIRECT_NEXT 1
 #define DIRECT_PREV -1
@@ -136,7 +136,7 @@
 int child,wstat;
 int flagtoplevel;
 unsigned int flagmime;
-unsigned int cs,csbase;
+unsigned int cs,csbase,pos;
 int flagrobot;
 int flagpre;
 int precharcount;
@@ -146,6 +146,20 @@
 char *bannerargs[4];
 
 
+struct msginfo {	/* clean info on the target message */
+  char item;		/* What we want */
+  char direction;	/* Relation to current msg */
+  char axis;		/* Axis of desired movement [may be calculated] */
+  unsigned long source;	/* reference message number */
+  unsigned long target;
+  unsigned long date;
+  unsigned long *authnav;	/* msgnav structure */
+  unsigned long *subjnav;	/* msgnav structure */
+  char *author;
+  char *subject;
+  char *cgiarg;			/* sub/auth as expected from axis */
+} msginfo;
+
 mime_info *mime_current = 0;
 mime_info *mime_tmp = 0;
 
@@ -197,20 +211,6 @@
 
 unsigned long msgnav[5]; /* 0 prev prev 1 prev 2 this 3 next 4 next-next */
 
-struct msginfo {	/* clean info on the target message */
-  char item;		/* What we want */
-  char direction;	/* Relation to current msg */
-  char axis;		/* Axis of desired movement [may be calculated] */
-  unsigned long source;	/* reference message number */
-  unsigned long target;
-  unsigned long date;
-  unsigned long *authnav;	/* msgnav structure */
-  unsigned long *subjnav;	/* msgnav structure */
-  char *author;
-  char *subject;
-  char *cgiarg;			/* sub/auth as expected from axis */
-} msginfo;
-
 void toggle_flagpre(int flag)
 {
   flagpre = flag;
@@ -254,7 +254,7 @@
   return CS_BAD;
 }
 
-void htmlencode_put (register char *s,register unsigned int l)
+void html_put (register char *s,register unsigned int l)
 /* At this time, us-ascii, iso-8859-? create no problems. We just encode  */
 /* some html chars. iso-2022 may have these chars as character components.*/
 /* cs is set for these, 3 for CN, 2 for others. Bit 0 set means 2 byte    */
@@ -382,7 +382,7 @@
 	    case 5:  state = 0; break;		/* 4th char of ESC $ *|+|) X */
 	    case 11: state = 0; break;		/* 3nd char of ESC . */
 	    case 21: state = 0; break;		/* ESC ( X for JP */
-	    default: die_prog("bad state in htmlencode_put"); break;
+	    default: die_prog("bad state in html_put"); break;
 	  }
       } else if (so && flagpre && precharcount >= 84) {
 		/* 84 is nicer than 78/80 since most use GUI browser */
@@ -431,6 +431,58 @@
   urlencode_put(s,str_len(s));
 }
 
+void anchor_put(unsigned char *s, unsigned int l)
+/* http://, ftp:// only */
+{
+  unsigned char *cpl,*cpafter,*cpstart,*cpend;
+  unsigned int pos,i;
+
+  pos = byte_chr(s,l,':');
+  if (pos + 3 >= l || !pos) {			/* no ':' no URL (most lines) */
+    html_put(s,l);
+    return;
+  }
+
+  cpl = s;
+  cpafter = s + l;
+  for (;;) {
+    cpstart = (char *) 0;
+    if (s[pos + 1] == '/' && s[pos + 2] == '/') {
+      cpend = s + pos + 2;
+      for (i = pos - 1; i + 6 >= pos; i--) {		/* pos always >=1 */
+        if ((s[i] < 'a' || s[i] > 'z') && (s[i] < 'A' || s[i] > 'Z')) {
+          cpstart = s + i + 1;	/* "[:alpha:]{1,5}://" accepted */
+	  break;
+        }
+	if (!i && i + 6 < pos) {
+	  cpstart = s;
+	  break;
+	}
+      }
+    }
+    if (cpstart) {					/* found URL */
+      while (cpend < cpafter && str_chr(" \t\n",*cpend) == 3) cpend++;
+      cpend--;						/* locate end */
+      while (cpend > cpstart && str_chr(".,;])>\"\'",*cpend) != 8) cpend--;
+      html_put(cpl,cpstart - cpl);			/* std txt */
+      oputs("<a href=\"");				/* link start */
+      oput(cpstart,cpend - cpstart + 1);		/* link */
+      oputs("\">");
+      html_put(cpstart,cpend - cpstart + 1);		/* visible */
+      oputs("</a>");					/* end */
+      cpl = cpend + 1;
+      pos = cpend - s;
+      if (pos >= l) return;
+    } else
+      pos++;
+    pos += byte_chr(s + pos,l - pos,':');
+    if (pos + 3 >= l) {
+      html_put(cpl,cpafter - cpl);	/* std txt */
+      return;
+    }
+  }
+}
+
 int checkhash(register char *s)
 {
   register int l = HASHLEN;
@@ -514,7 +566,7 @@
     default: oputs("#b\">"); break;
   }
   if (HASHLEN + 1 < l)
-    htmlencode_put(data + HASHLEN + 1,l - HASHLEN - 1);
+    html_put(data + HASHLEN + 1,l - HASHLEN - 1);
   else
     oputs("(none)");
   oputs("</A>");
@@ -722,7 +774,7 @@
     oputs(": ");
   }
   if (t) oputs(t);
-  if (s) htmlencode_put(s,l);
+  if (s) html_put(s,l);
   oputs("</TITLE>\n");
   if (class && *class && stylesheet && *stylesheet) {
     oputs("<LINK href=\"");
@@ -753,31 +805,8 @@
   if ((flagspecial & SPC_BANNER) && banner && *banner) {
     oputs("<DIV class=banner>\n");
     if (*banner == '<') oputs(banner);
-    else {
-      substdio_flush(&ssout);
-      sig_pipeignore();
-      bannerargs[0] = banner;
-      bannerargs[1] = host;
-      bannerargs[2] = local;
-      bannerargs[3] = 0;
-	/* We log errors but just complete the page anyway, since we're */
-	/* already committed to output something. */
-      switch(child = fork()) {
-        case -1:
-          strerr_warn3(FATAL,ERR_FORK,"banner program: ",&strerr_sys);
-          break;
-        case 0:
-          execv(*bannerargs,bannerargs);
-          strerr_die3x(100,FATAL,ERR_EXECUTE,"banner program: ");
-	  break;
-      }
-         /* parent */
-      wait_pid(&wstat,child);
-      if (wait_crashed(wstat))
-        strerr_warn2(FATAL,ERR_CHILD_CRASHED,(struct strerr *) 0);
-      if (wait_exitcode(wstat))
-        strerr_warn2(FATAL,ERR_CHILD_UNKNOWN,(struct strerr *) 0);
-    }
+    else
+      strerr_die2x(100,FATAL,"Sorry - banner programs not supported");
     oputs("</DIV>\n");
   }
   oputs("</BODY>\n</HTML>\n");
@@ -875,14 +904,14 @@
   }
 }
 
-void firstdate(struct msginfo *infop,int flagfail)
+void firstdate(struct msginfo *infop)
 {
     infop->date = 0;
     infop->direction = DIRECT_NEXT;
     finddate(infop);
 }
 
-void getdate(struct msginfo *infop,int flagfail)
+void gtdate(struct msginfo *infop,int flagfail)
 /* infop->date has to be 0 or valid on entry. Month outside of [1-12] on */
 /* entry causes GIGO */
 {
@@ -1272,6 +1301,7 @@
 			/* base64/QP ignored for multipart */
   r = CTENC_NONE;
   while (l && (*s == ' ' || *s == '\t')) { s++; l--; }	/* skip LWSP */
+s[l-1] = 0;
   if (case_startb(s,l,"quoted-printable")) {
     r = CTENC_QP;
   } else if (case_startb(s,l,"base64")) {
@@ -1339,6 +1369,7 @@
 	hdr[HDR_VERSION - 1].len);
   html_header(decline.s,line.s,line.len - 1,
 		"msgbody",SPC_BASE);
+  decline.len = 0;		/* reset */
   msglinks(infop);
   oputs("<DIV class=message>\n");
 }
@@ -1370,7 +1401,14 @@
       strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
     if (!match) return;
     if ((btype = check_boundary())) {
-      if (flagpre) {
+      if (decline.len) {		/* flush last line that doesn't */
+	if (flaghtml)			/* end in \n for QP/base64 */
+	  oput(decline.s,decline.len);
+	else
+          anchor_put(decline.s,decline.len);
+        decline.len = 0;
+      }
+      if (flagpre) {			/* ending part was <PRE> */
 	oputs("</PRE>");
 	toggle_flagpre(0);
       }
@@ -1410,12 +1448,14 @@
 	      oputs("\">");
 	    }
 	    if (flagobscure && i == HDR_FROM - 1) {
+	      int k;
 	      oputs(" ");
-	      decodeHDR(cp,author_name(&cp,line.s,line.len),&decline,"",FATAL);
-	      htmlencode_put(decline.s,decline.len);
+	      k = author_name(&cp,line.s,line.len);
+	      decodeHDR(cp,k,&decline,"",FATAL);
+	      html_put(decline.s,decline.len);
 	    } else {
 	      decodeHDR(hdr[i].s,hdr[i].len,&decline,"",FATAL);
-              htmlencode_put(decline.s,decline.len - 1);
+              html_put(decline.s,decline.len - 1);
 	    }
 	    if (i == HDR_SUBJECT - 1 && flagtoplevel)
 	      oputs("</A></SPAN>");
@@ -1491,17 +1531,20 @@
     } else {
       if (flaggoodfield) {
 	if (mime_current->ctenc) {
-	  if (!stralloc_copy(&decline,&line)) die_nomem();
-	  line.len = 0;
 	  if (mime_current->ctenc == CTENC_QP)
-	    decodeQ(decline.s,decline.len,&line);
+	    decodeQ(line.s,line.len,&decline);
 	  else
-	    decodeB(decline.s,decline.len,&line);
+	    decodeB(line.s,line.len,&decline);
+	  if (decline.s[decline.len - 1] == '\n') {	/* complete line */
+	    if (!stralloc_copy(&line,&decline)) die_nomem();
+	    decline.len = 0;
+	  } else				/* incomplete - wait for next */
+	    line.len = 0;			/* in case URL is split */
 	}
 	if (flaghtml)
 	  oput(line.s,line.len);
 	else {
-          htmlencode_put(line.s,line.len);		/* body */
+          anchor_put(line.s,line.len);		/* body */
 	}
       }
     }
@@ -1698,7 +1741,7 @@
       strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
   }
   substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
-  if (infop->source != ITEM_DATE) {
+  if (infop->axis != ITEM_DATE) {
     if (getln(&ssin,&line,&match,'\n') == -1)	/* first line */
       strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
     if (!match)
@@ -1713,8 +1756,13 @@
     if (!match) break;
     msgnav[0] = msgnav[1];
     msgnav[1] = msgnav[2];
-    (void) scan_ulong(line.s,&(msgnav[2]));
-    if (infop->direction == DIRECT_FIRST) break;
+    pos = scan_ulong(line.s,&(msgnav[2]));
+    if (infop->direction == DIRECT_FIRST && infop->axis == ITEM_DATE) {
+      if (pos + HASHLEN + 1 < line.len)
+        if (!stralloc_copyb(&subject,line.s+pos+1,HASHLEN)) die_nomem();
+	if (!stralloc_0(&subject)) die_nomem();
+      break;
+    }
     if (msgnav[2] == infop->source) {
       if (getln(&ssin,&line,&match,'\n') == -1)
         strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
@@ -1736,8 +1784,12 @@
       infop->date = 0;
       break;
     case ITEM_SUBJECT:
-      infop->subjnav = msgnav + 2 + infop->direction;
-      infop->target = *(infop->subjnav);
+      if (infop->direction == DIRECT_FIRST)
+        infop->target = msgnav[2];
+      else {
+        infop->subjnav = msgnav + 2 + infop->direction;
+        infop->target = *(infop->subjnav);
+      }
       infop->author = (char *)0;	/* what we know is not for this msg */
       infop->date = 0;
       break;
@@ -1745,6 +1797,7 @@
       infop->target = msgnav[2];
       infop->subject = (char *)0;	/* what we know is not for this msg */
       infop->author = (char *)0;	/* what we know is not for this msg */
+      break;
     default:
       die_prog("Bad item in setmsg");
   }
@@ -1766,9 +1819,15 @@
 }
 
 void date2msg(struct msginfo *infop)
+/* this is all a terrible hack */
 {
   (void) makefn(&fn,ITEM_DATE,infop->date,"");
-  setmsg(infop);
+  infop->direction = DIRECT_FIRST;
+  infop->axis = ITEM_DATE;
+  setmsg(infop);		/* got first thread */
+  infop->subject = subject.s;
+  infop->axis = ITEM_SUBJECT;
+  subj2msg(infop);		/* get 1st message no in that thread */
 }
 
 void findlastmsg(struct msginfo *infop)
@@ -1866,15 +1925,13 @@
 	      case ITEM_DATE:
 		if (!infop->date && infop->source)
 		  if (!msg2hash(infop)) return 0;
-		  getdate(infop,0);
+		  gtdate(infop,0);
 		break;
 	    }
 	    break;
 	  case ITEM_INDEX:	/* ignore direction etc - only for index */
 	    if (!infop->target)
 	      infop->target = infop->source;
-	    if (!infop->target)
-	      findlastmsg(infop);
 	    break;
   }
   return 1;
@@ -2019,6 +2076,9 @@
   cmd = env_get("QUERY_STRING");			/* get command */
   cppath = env_get("PATH_INFO");			/* get path_info */
 
+  if (!cmd && !cppath)
+    cmd = argv[1];
+
   if (!cppath || !*cppath) {
     if (cmd && *cmd) {
       cmd += scan_ulong(cmd,&thislistno);
@@ -2026,7 +2086,7 @@
     } else
       thislistno = 0L;
   } else {
-    cppath++;
+    if (*cppath == '/') cppath++;
       cppath += scan_ulong(cppath,&thislistno);		/* this listno */
       if (!thislistno || *cppath++ == '/') {
 	if (str_start(cppath,"index")) {
@@ -2143,6 +2203,7 @@
 
 /********************* Get info from server on BASE etc ****************/
 
+  if (!stralloc_copys(&url,"<A HREF=\"")) die_nomem();
   if (!stralloc_copys(&base,"<BASE href=\"http://")) die_nomem();
   cp = env_get("SERVER_PORT");
   if (cp) {			/* port */
@@ -2155,18 +2216,15 @@
       if (!stralloc_cats(&base,":")) die_nomem();
       if (!stralloc_catb(&base,strnum,fmt_ulong(strnum,port))) die_nomem();
   }
-  if (!(cp = env_get("HTTP_HOST")))
-    if (!(cp = env_get("SERVER_NAME")))
-      strerr_die2x(100,FATAL,"both HTTP_HOST and SERVER_NAME are empty");
-  if (!stralloc_cats(&base,cp)) die_nomem();
-  if (!(cp = env_get("SCRIPT_NAME")))
-    strerr_die2x(100,FATAL,"empty SCRIPT_NAME");
-  if (!stralloc_cats(&base,cp)) die_nomem();
+  if ((cp = env_get("HTTP_HOST")) || (cp = env_get("SERVER_NAME")))
+    if (!stralloc_cats(&base,cp)) die_nomem();
+  if (cp = env_get("SCRIPT_NAME")) {
+    if (!stralloc_cats(&base,cp)) die_nomem();
+    pos = str_rchr(cp,'/');
+    if (cp[pos])
+      if (!stralloc_cats(&url,cp + pos + 1)) die_nomem();
+  }
   if (!stralloc_cats(&base,"\">\n")) die_nomem();
-  if (!stralloc_copys(&url,"<A HREF=\"")) die_nomem();
-  pos = str_rchr(cp,'/');
-  if (cp[pos])
-    if (!stralloc_cats(&url,cp + pos + 1)) die_nomem();
   if (!stralloc_cats(&url,"?")) die_nomem();
   if (thislistno) {
     if (!stralloc_catb(&url,strnum,fmt_ulong(strnum,thislistno))) die_nomem();
@@ -2189,7 +2247,7 @@
 
   switch (msginfo.item) {
     case ITEM_MESSAGE:
-	if (!show_message(&msginfo)) {		/* assume next exists ... */
+	if (!(ret = show_message(&msginfo))) {	/* assume next exists ... */
 	  cache = 0;				/* border cond. - no cache */
 	  msginfo.target = msginfo.source;	/* show same */
 	  msginfo.subjnav = 0;
@@ -2198,32 +2256,35 @@
 	}
 	break;
     case ITEM_AUTHOR:
-	if (!show_object(&msginfo,ITEM_AUTHOR))
+	if (!(ret = show_object(&msginfo,ITEM_AUTHOR)))
 	  cgierr ("I couldn't find the author for that message","","");
 	break;
     case ITEM_SUBJECT:
-	if (!show_object(&msginfo,ITEM_SUBJECT))
+	if (!(ret = show_object(&msginfo,ITEM_SUBJECT)))
 	  cgierr ("I couldn't find the subject for that message","","");
 	break;
     case ITEM_DATE:
-	if (!show_object(&msginfo,ITEM_DATE)) {
+	if (!(ret = show_object(&msginfo,ITEM_DATE))) {
 	  finddate(&msginfo);
 	  ret = show_object(&msginfo,ITEM_DATE);
 	}
 	break;
     case ITEM_INDEX:
-	if (!show_index(&msginfo)) {
-	  tmptarget = msginfo.target;
-	  findlastmsg(&msginfo);
-	  cache = 0;			/* latest one - no cache */
-	  if (!msginfo.target || msginfo.target > tmptarget) {
-	    cache = 2;			/* won't change */
-            firstdate(&msginfo,1);	/* first thread index */
-	    msginfo.direction = DIRECT_FIRST;
-	    date2msg(&msginfo);		/* (may not be 1 if parts removed) */
-	  }
+	ret = 1;
+	if (show_index(&msginfo)) break;/* msgnumber valid */
+	tmptarget = msginfo.target;
+	findlastmsg(&msginfo);
+	cache = 0;			/* latest one - no cache */
+	if (msginfo.target > tmptarget) {
+	  cache = 2;			/* first one won't change */
+	  msginfo.target = 1;		/* try */
+	  if (show_index(&msginfo)) break;
+	  msginfo.date = 0;		/* first indexes missing */
+          firstdate(&msginfo);		/* instead get first msg of first */
+	  date2msg(&msginfo);		/* thread. */
+	  if (show_index(&msginfo)) break;
+	} else
 	  ret = show_index(&msginfo);
-	}
 	break;
     default:
 	strerr_die2x(100,FATAL,"bad item in main");
Only in ezmlm-0.53: ezmlm-cgi.c.orig
diff -u ezmlm-0.53.orig/ezmlm-idx.c ezmlm-0.53/ezmlm-idx.c
--- ezmlm-0.53.orig/ezmlm-idx.c	Fri Dec 24 14:15:01 1999
+++ ezmlm-0.53/ezmlm-idx.c	Fri Jul  5 13:09:52 2002
@@ -282,6 +282,8 @@
     } else if (fstat(fd,&st) == -1 || (!(st.st_mode & 0100)))
         close(fd);
     else {
+      int k;
+
       subject.len = 0;		/* clear in case they're missing in msg */
       author.len = 0;
       received.len = 0;
@@ -303,7 +305,9 @@
       mkauthhash(lines.s,lines.len,hash);
       if (!stralloc_catb(&line,hash,HASHLEN)) die_nomem();
 
-      decodeHDR(cp,author_name(&cp,lines.s,lines.len),&author,charset.s,FATAL);
+      k = author_name(&cp,lines.s,lines.len);
+      decodeHDR(cp,k,&author,charset.s,FATAL);
+
       (void) unfoldHDR(author.s,author.len,&lines,charset.s,&prefix,0,FATAL);
 
       if (!stralloc_cats(&line," ")) die_nomem();
diff -u ezmlm-0.53.orig/ezmlm-manage.c ezmlm-0.53/ezmlm-manage.c
--- ezmlm-0.53.orig/ezmlm-manage.c	Fri Dec 24 14:15:01 1999
+++ ezmlm-0.53/ezmlm-manage.c	Fri Jul  5 13:11:19 2002
@@ -915,6 +915,12 @@
       copy(&qq,"text/sub-confirm",flagcd,FATAL);
       copybottom();
       qmail_to(&qq,target.s);
+    } else if (flagmod) {
+      store_from(&fromline,target.s);
+      doconfirm(ACTION_TC);
+      copy(&qq,"text/mod-sub-confirm",flagcd,FATAL);
+      copybottom();
+      sendtomods();	
     } else {				/* normal subscribe, no confirm */
       r = geton(action);		/* should be rarely used. */
       copybottom();
diff -u ezmlm-0.53.orig/ezmlm-send.1 ezmlm-0.53/ezmlm-send.1
--- ezmlm-0.53.orig/ezmlm-send.1	Fri Jul  5 13:19:04 2002
+++ ezmlm-0.53/ezmlm-send.1	Fri Jul  5 13:09:31 2002
@@ -4,7 +4,7 @@
 .SH SYNOPSIS
 .B ezmlm-send
 [
-.B \-cCrRvV
+.B \-aAcCrRvV
 ] [
 .B \-h\fI header
 ]
@@ -149,6 +149,43 @@
 rejects the message.
 .SH OPTIONS
 .TP
+.B \-a
+.B ezmlm-send
+assumes that there are two trailer files:
+.I dir\fB/text/trailer
+and
+.IR dir\fB/text/alttrailer .
+.B ezmlm-send
+will scan the message for the occurence of ``##''. If found, the trailer
+used (if the message is otherwise suitable for trailer addition) will be
+.IR dir\fB/text/trailer .
+If not found,
+.I dir\fB/text/alttrailer
+will be used, and a header will be prefixed with ``#''. In conjunction with
+the qmail-verh patch to
+.B qmail-remote
+this allows inclusing of per-subscriber customized unsubscribe
+instructions in
+.I dir\fB/text/alttrailer
+in a manner that does not risk message corruption.
+.B \-aa
+Same as
+.B \-a
+(see that switch),
+but the message is assumed to be free of ``##'' without checking.
+This is especially useful if piping the message directly to
+.B ezmlm-send
+since it avoids the need to rewind stdin.
+.TP
+.B \-A
+(Default.)
+The message is not checked for ``##''. If
+.I dir\fB/text/trailer
+exists and the message is otherwise suitable for header addition,
+that trailer will be added. No signals for
+.B qmail-remote
+are added.
+.TP
 .B \-c
 No longer supported. Ignored for backwards compatibility.
 .TP
diff -u ezmlm-0.53.orig/ezmlm-send.c ezmlm-0.53/ezmlm-send.c
--- ezmlm-0.53.orig/ezmlm-send.c	Fri Dec 24 14:15:00 1999
+++ ezmlm-0.53/ezmlm-send.c	Fri Jul  5 13:11:26 2002
@@ -29,6 +29,7 @@
 #include "cookie.h"
 #include "idx.h"
 #include "copy.h"
+#include "seek.h"
 
 int flagnoreceived = 1;		/* suppress received headers by default. They*/
 				/* are still archived. =0 => archived and */
@@ -39,7 +40,7 @@
 
 void die_usage()
 {
-  strerr_die1x(100,"ezmlm-send: usage: ezmlm-send [-cClLqQrR] [-h header] dir");
+  strerr_die1x(100,"ezmlm-send: usage: ezmlm-send [-aAcClLqQrR] [-h header] dir");
 }
 void die_nomem()
 {
@@ -191,6 +192,7 @@
 
 char buf0[256];
 substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
+substdio ss1 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
 
 void numwrite()
 {		/* this one deals with msgnum, not outnum! */
@@ -229,6 +231,7 @@
   int match;
   int r;
   unsigned int pos;
+  int k;
 
   if (!stralloc_copys(&fnadir,"archive/")) die_nomem();
   if (!stralloc_catb(&fnadir,strnum,fmt_ulong(strnum,outnum / 100)))
@@ -306,7 +309,9 @@
   if (!stralloc_catb(&qline,hash,HASHLEN)) die_nomem();
   if (!stralloc_cats(&qline," ")) die_nomem();
 
-  decodeHDR(cp,author_name(&cp,lines.s,lines.len),&from,charset.s,FATAL);
+  k = author_name(&cp,lines.s,lines.len);
+  decodeHDR(cp,k,&from,charset.s,FATAL);
+
   (void) unfoldHDR(from.s,from.len,&lines,charset.s,&dcprefix,0,FATAL);
   if (!stralloc_cat(&qline,&lines)) die_nomem();
 
@@ -360,8 +365,8 @@
   char *ret;
   char *err;
   int flagmlwasthere;
-  int flagqmqp = 0;	/* don't use qmqp by default */
-  int flaglistid = 0;	/* no listid header added */
+  int flagqmqp = 0;		/* don't use qmqp by default */
+  int flaglistid = 0;		/* no listid header added */
   int match;
   unsigned int i;
   int r,fd;
@@ -373,7 +378,8 @@
   int flagfromline;
   int flagcontline;
   int flagarchiveonly;
-  int flagtrailer;
+  int flagtrailer = 1;
+  int flagalttrailer = 0;	/* std trailer if at all except if -a */
   unsigned int pos;
   int opt;
   char *cp, *cpstart, *cpafter;
@@ -381,8 +387,10 @@
   umask(022);
   sig_pipeignore();
 
-  while ((opt = getopt(argc,argv,"cCh:H:lLrRqQs:S:vV")) != opteof)
+  while ((opt = getopt(argc,argv,"aAcCh:H:lLrRqQs:S:vV")) != opteof)
     switch(opt) {
+      case 'a': flagalttrailer++; break;
+      case 'A': flagalttrailer = 0; break;
       case 'c': case 'C': break;	/* ignore for backwards compat */
       case 'h':
       case 'H': mlheader = optarg;	/* Alternative sublist check header */
@@ -398,8 +406,7 @@
 		(void) scan_ulong(optarg+pos,&hash_hi);
 		if (hash_hi > 52L) hash_hi = 52L;
 		if (hash_lo > hash_hi) hash_lo = hash_hi;
-
- break;
+		break;
       case 'q': flagqmqp = 0; break;
       case 'Q': flagqmqp = 1; break;
       case 'v':
@@ -409,7 +416,6 @@
 	die_usage();
     }
 
-
   dir = argv[optind++];
   if (!dir) die_usage();
 
@@ -437,12 +443,13 @@
     if (!stralloc_copy(&dcprefix,&line)) die_nomem();
     serial = byte_rchr(prefix.s,prefix.len,'#');
   }
-  if ((fd = open_read("text/trailer")) == -1) {	/* see if there is a trailer */
-    if (errno == error_noent) flagtrailer = 0;
-    else strerr_die2sys(111,ERR_OPEN,"text/trailer: ");
-  } else {
-    close(fd);
-    flagtrailer = 1;
+  if (!flagalttrailer) {				/* skip test if -a */
+    if ((fd = open_read("text/trailer")) == -1) {	/* see if trailer */
+      if (errno == error_noent) flagtrailer = 0;
+      else strerr_die2sys(111,ERR_OPEN,"text/trailer: ");
+    } else {
+      close(fd);
+    }
   }
 
   getconf(&mimeremove,"mimeremove",0,FATAL,dir);
@@ -501,6 +508,27 @@
   szmsgnum[fmt_ulong(szmsgnum,outnum)] = '\0';
   set_cpnum(szmsgnum);				/* for copy */
 
+  if (flagalttrailer == 1) {
+    while (flagalttrailer) {			/* verify no '##L/##H */
+      if (getln(&ss1,&line,&match,'\n') == -1)
+        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+      if (!match) break;
+      pos = 0;
+      while ((pos += byte_chr(line.s + pos,line.len - pos,'#')) < line.len) {
+        if (++pos + 1 < line.len) {
+          if (line.s[pos] == '#') {
+	    if (line.s[pos + 1] == 'H' || line.s[pos + 1] == 'L') {
+	      flagalttrailer = 0;
+	      break;
+	    }
+	  }
+        }
+      }
+    }
+    if (seek_begin(0) == -1)		/* rewind */
+      strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
+  }
+
   if (flagarchived) {
     if (!stralloc_copys(&fnadir,"archive/")) die_nomem();
     if (!stralloc_catb(&fnadir,strnum,
@@ -548,6 +576,8 @@
     }
     qa_puts("\n");
   }
+  if (flagalttrailer)
+    qmail_put(&qq,"#",1);		/* VERH body signal */
   copy(&qq,"headeradd",'H',FATAL);
   qa_put(mydtline.s,mydtline.len);
 
@@ -704,7 +734,10 @@
             qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
             qmail_puts(&qq,charset.s);
             transferenc();		/* trailer for multipart message */
-	    copy(&qq,"text/trailer",flagcd,FATAL);
+	    if (flagalttrailer)
+	      copy(&qq,"text/alttrailer",flagcd,FATAL);
+	    else
+	      copy(&qq,"text/trailer",flagcd,FATAL);
             if (flagcd == 'B')	{	/* need to do our own flushing */
               encodeB("",0,&qline,2,FATAL);
               qmail_put(&qq,qline.s,qline.len);
@@ -731,7 +764,9 @@
           }
         } else if (line.len == 1) {	/* end of content desc */
           flagbadpart = 0;		/* default type, so ok */
+          flagfoundokpart = 1;		/* this is part of a multipart msg */
           flagseenext = 0;		/* done thinking about it */
+          qa_put(lines.s,lines.len);	/* saved lines */
         } else				/* save line in cont desc */
           if (!stralloc_cat(&lines,&line)) die_nomem();
       }
@@ -746,7 +781,10 @@
   if (!boundary.len && flagtrailer) {
     qmail_puts(&qq,"\n");		/* trailer for non-multipart message */
     if (!encin || encin == 'Q') {	/* can add for QP, but not for base64 */
-      copy(&qq,"text/trailer",encin,FATAL);
+      if (flagalttrailer)
+	copy(&qq,"text/alttrailer",encin,FATAL);
+      else
+	copy(&qq,"text/trailer",encin,FATAL);
       qmail_puts(&qq,"\n");		/* no need to flush for plain/QP */
     }
   }
Only in ezmlm-0.53: ezmlm-send.c.orig
diff -u ezmlm-0.53.orig/ezmlm-sub.1 ezmlm-0.53/ezmlm-sub.1
--- ezmlm-0.53.orig/ezmlm-sub.1	Fri Jul  5 13:19:04 2002
+++ ezmlm-0.53/ezmlm-sub.1	Fri Jul  5 13:09:31 2002
@@ -4,7 +4,7 @@
 .SH SYNOPSIS
 .B ezmlm-sub
 [
-.B \-HmMnNsSvV
+.B \-HmMnNvV
 ][
 .B \-h
 .I hash
diff -u ezmlm-0.53.orig/ezmlm-test.sh ezmlm-0.53/ezmlm-test.sh
--- ezmlm-0.53.orig/ezmlm-test.sh	Fri Dec 24 14:15:01 1999
+++ ezmlm-0.53/ezmlm-test.sh	Fri Jul  5 13:09:31 2002
@@ -73,19 +73,53 @@
 HEAD='head'
 MKDIR='mkdir'
 MV='mv'
-# a ps command that would list qmail if running. This works for RedHat Linux
-PS='ps auxw'
 RM='rm'
 SED='sed'
 STRINGS='strings'
 TAIL='tail'
 UNSET='unset'
 WC='wc'
-# if you don't have this, you can put 'echo "user"' where user is the current
-# login user name.
-WHOAMI='whoami'
 
-###################### END CONFIRGRABLE ITEMS #########################
+
+###################### END CONFIGURABLE ITEMS #########################
+if echo -n | grep n > /dev/null 2>&1; then
+    prompt()
+    {
+	echo "$*\c"
+    }
+else
+    prompt()
+    {
+	echo -n "$*"
+    }    
+fi
+
+if ps auxw > /dev/null 2>&1; then
+    PS='ps auxw'
+else
+    PS='ps -ef'
+fi
+
+if (whoami) > /dev/null 2>&1; then
+    myself() {
+        whoami
+    }
+elif (id) > /dev/null 2>&1; then
+    myself() {
+        id | cut -d'(' -f2 | cut -d')' -f1
+    }
+# the remaining two tests work only if `su -' was used
+# perhaps delete them
+elif (logname) > /dev/null 2>&1; then
+        myself() {
+        logname
+    }
+elif (who am i)  > /dev/null 2>&1; then
+    myself() {
+        who am i | cut -d' ' -f1 | cut -d'!' -f2
+    }
+fi
+
 SQLUSER=''	# must be empty
 ARR='-------------------->'
 ALLOW='allow'
@@ -152,13 +186,25 @@
 	SQLUSER="$SQLUSR"
 fi
 
-USER=`${WHOAMI}` >/dev/null 2>&1 || \
+USER=`myself` >/dev/null 2>&1 || \
 	{ ${ECHO} "whoami doesn't work. If you're not \"${EZTEST}\" the";
-	  ${ECHO} "will fail."; USER="${EZTEST}"; }
+	  ${ECHO} "test will fail."; USER="${EZTEST}"; }
 
 if [ "$USER" != "${EZTEST}" ]; then 
   ${ECHO} "Must be user ${EZTEST} to execute"; exit 99
 fi
+
+# test for the common uid=0 error; not foolproof 
+# any system w/o id or UID ?
+if (id) > /dev/null 2>&1 \
+    && test "x`id|cut -d'(' -f1 |cut -d'=' -f2`" = "x0"; then
+    ${ECHO} 'uid is 0 but superuser does not receive mail under qmail'
+    exit 1  
+elif test "x$UID" = "x0" ; then
+    ${ECHO} '$UID = 0 but superuser does not receive mail under qmail'
+    exit 1
+fi
+
 LOC="$EZTEST-$LIST"
 # calculate position in LOCAL where [normally] default starts
 LOCLEN=`${ECHO} "$LOC-" | ${WC} -c | ${SED} 's/ //g'`
@@ -293,9 +339,9 @@
 ############################
 sleep_5()
 {
-  sleep 1; ${ECHO} -n "."; sleep 1; ${ECHO} -n "."
-  sleep 1; ${ECHO} -n "."; sleep 1; ${ECHO} -n "."
-  sleep 1; ${ECHO} -n "${1}"
+  sleep 1; prompt "."; sleep 1; prompt "."
+  sleep 1; prompt "."; sleep 1; prompt "."
+  sleep 1; prompt "${1}"
   return 0
 }
 
@@ -304,7 +350,7 @@
 ################################
 wait_test()
 {
-${ECHO} -n "max 35s for delivery: "
+prompt "max 35s for delivery: "
 sleep_5 5s
 TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null`
 if [ -z "$TSTMSG" ]; then
@@ -410,7 +456,7 @@
 ##############
 # ezmlm-make #
 ##############
-  ${ECHO} -n "ezmlm-make (1/2):     "
+  prompt "ezmlm-make (1/2):     "
 
 # edit non-existant list
   ${EZBIN}/ezmlm-make -e -C${EZBIN}/ezmlmrc "${DIR}" "${DOT}" \
@@ -437,7 +483,7 @@
   ${EZBIN}/ezmlm-make -ed -C${EZBIN}/ezmlmrc "${DIR}" "$DOT" "$LOC" "$HOST" \
 	>/dev/null 2>&1 || \
 	{ ${ECHO} "failed without DIR/config: 0.313 bug, fixed in 0.314."
-	  ${ECHO} -n "ezmlm-make ......     "
+	  prompt "ezmlm-make ......     "
 	  BUG="${BUG} config"
 	}
   ${MV} "${DIR}/config~" "${DIR}/config"
@@ -446,19 +492,19 @@
 	{ ${ECHO} "no ezmlm-weed in bouncer"; exit 100; }
   ${GREP} "ezmlm-return" "${DIR}/bouncer" >/dev/null 2>&1 || \
 	{ ${ECHO} "no ezmlm-return in bouncer: 0.32 bug, fixed in 0.321."
-	  ${ECHO} -n "ezmlm-make ......     "
+	  prompt "ezmlm-make ......     "
 	  BUG="${BUG} return"
 	}
 # digest/bouncer only for >=0.32
   if [  "$EZVER" != '31' ]; then
     if [ ! -f "${DIR}/digest/bouncer" ]; then
-	echo "failed to create digest/bouncer"; exit 100;
+	${ECHO} "failed to create digest/bouncer"; exit 100;
     fi
     ${GREP} "ezmlm-weed" "${DIR}/digest/bouncer" >/dev/null 2>&1 || \
 	{ ${ECHO} "no ezmlm-weed in bouncer"; exit 100; }
     ${GREP} "ezmlm-return" "${DIR}/digest/bouncer" >/dev/null 2>&1 || \
 	{ ${ECHO} "no ezmlm-return in digest/bouncer: 0.32 bug, OK in 0.321."
-	  ${ECHO} -n "ezmlm-make ......     "
+	  prompt "ezmlm-make ......     "
 	  BUG="${BUG} return"
 	}
   fi
@@ -466,7 +512,7 @@
 
 # Add sql files for sql testing
 RDBMS='STD'
-${ECHO} -n "Using RDBMS support:  "
+prompt "Using RDBMS support:  "
 if [ $USESQL ]; then
   ${EZBIN}/ezmlm-make -+6 "$SQLHOST::$SQLUSER:$PW:$DB:$TABLE" \
 	-C${EZBIN}/ezmlmrc "${DIR}"|| \
@@ -538,7 +584,7 @@
 	fi
 fi
 
-${ECHO} -n "testing for qmail:    "
+prompt "testing for qmail:    "
 if [ "$QMVER" = "n" ]; then
 	${ECHO} ">=1.02"
 else
@@ -600,7 +646,7 @@
 #####################
 # test ezmlm-reject #
 #####################
-  ${ECHO} -n "ezmlm-reject:         "
+  prompt "ezmlm-reject:         "
   FROM="$EZTEST"
   TO="$EZTEST-__tstlist@$HOST"
   SUBJECT="test"
@@ -632,31 +678,30 @@
 
 #too large
   ${ECHO} "20:10" > "${DIR}/msgsize"
-  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
-	{ ${ECHO} "ezmlm-reject failed to reject too large message"; \
-		exit 100; }
+  { make_message  | ${EZBIN}/ezmlm-reject "${DIR}"; } > /dev/null 2>&1 && \
+        { ${ECHO} "ezmlm-reject failed to reject too large message"; \
+                exit 100; }
 
 # restore
   ${RM} -f "${DIR}/msgsize"
 
 # without subject
   SUBJECT=''
-  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
-	{ ${ECHO} "ezmlm-reject failed to reject message without subject"; \
-		exit 100; }
-  OUT=`make_message | ${EZBIN}/ezmlm-reject 2>&1` && \
-	{ ${ECHO} "ezmlm-reject failed to reject message without subject"; \
-		exit 100; }
+   { make_message  | ${EZBIN}/ezmlm-reject "${DIR}"; } > /dev/null 2>&1 && \
+        { ${ECHO} "ezmlm-reject failed to reject null subject"; \
+                exit 100; }
+   { make_message  | ${EZBIN}/ezmlm-reject ; } > /dev/null 2>&1 && \
+        { ${ECHO} "ezmlm-reject failed to reject null subject"; \
+                exit 100; }		
 
 # with empty subject
   SUBJECT='(NUll)'
-  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
-	{ ${ECHO} "ezmlm-reject failed to reject null subject"; \
-		exit 100; }
-  OUT=`make_message | ${EZBIN}/ezmlm-reject 2>&1` && \
-	{ ${ECHO} "ezmlm-reject failed to reject null subject"; \
-		exit 100; }
-
+   { make_message  | ${EZBIN}/ezmlm-reject "${DIR}"; } > /dev/null 2>&1 && \
+        { ${ECHO} "ezmlm-reject failed to reject null subject with dir"; \
+                exit 100; }
+   { make_message  | ${EZBIN}/ezmlm-reject ; } > /dev/null 2>&1 && \
+        { ${ECHO} "ezmlm-reject failed to reject null subject without dir"; \
+                exit 100; }
 # testing -S
   OUT=`make_message | ${EZBIN}/ezmlm-reject -S "${DIR}"` || \
 	{ ${ECHO} "-S switch failed with dir"; exit 100; }
@@ -665,20 +710,19 @@
 
 # with command subject
   SUBJECT='REmOVE'
-  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+  { make_message | ${EZBIN}/ezmlm-reject "${DIR}"; } > /dev/null 2>&1 && \
 	{ ${ECHO} "failed to reject command subject with dir"; \
 		exit 100; }
-  OUT=`make_message | ${EZBIN}/ezmlm-reject 2>&1` && \
+  { make_message | ${EZBIN}/ezmlm-reject "${DIR}"; } > /dev/null 2>&1 && \
 	{ ${ECHO} "failed to reject command subject without dir"; \
 		exit 100; }
-
 # testing -C
   OUT=`make_message | ${EZBIN}/ezmlm-reject -C "${DIR}"` || \
 	{ ${ECHO} "-C switch failed with dir"; exit 100; }
   OUT=`make_message | ${EZBIN}/ezmlm-reject -C ` || \
-	{ ${ECHO} "-C switch failed without dir"; exit 100; }
-
-  SUBJECT='test'
+        { ${ECHO} "-C switch failed without dir"; exit 100; }
+  
+SUBJECT='test'
 
 # Test with list name in Cc:
   CC="$TO"
@@ -692,13 +736,13 @@
 
 # Bad To/Cc
   CC="$TO"
-  OUT=`make_message "$MESSAGE" | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+  { make_message | ${EZBIN}/ezmlm-reject "${DIR}"; } > /dev/null 2>&1 && \
 		{ ${ECHO} "failed to reject bad To/Cc with dir"; \
 		exit 100; }
   if [ "$?" != "100" ]; then
 	${ECHO} "failed to exit 100 on error"; exit 100
   fi
-  OUT=`make_message "$MESSAGE" | ${EZBIN}/ezmlm-reject -q "${DIR}" 2>&1` && \
+  { make_message | ${EZBIN}/ezmlm-reject -q "${DIR}"; } > /dev/null 2>&1 && \
 		{ ${ECHO} "failed to reject bad To/Cc with dir"; \
 		exit 100; }
   if [ "$?" -ne "99" ]; then
@@ -707,14 +751,14 @@
 
 # for backwards-compatibility and since we don't know inlocal@inhost without
 # dir, ezmlm-reject doesn't check To/Cc when there is no dir
-  OUT=`make_message "$MESSAGE" | ${EZBIN}/ezmlm-reject` || \
+  OUT=`make_message | ${EZBIN}/ezmlm-reject` || \
 		{ ${ECHO} "failed to accept bad To/Cc without dir"; \
 		exit 100; }
 
 # testing -T
   OUT=`make_message | ${EZBIN}/ezmlm-reject -T "${DIR}"` || \
 	{ ${ECHO} "-T switch failed with dir"; exit 100; }
-OUT=`make_message | ${EZBIN}/ezmlm-reject -T ` || \
+  OUT=`make_message | ${EZBIN}/ezmlm-reject -T ` || \
 	{ ${ECHO} "-T switch failed without dir"; exit 100; }
 
 # restore good TO
@@ -723,7 +767,7 @@
 # if part is mimereject message should be rejected
   touch "${DIR}"/mimeremove
   ${ECHO} "text/html" > "${DIR}"/mimereject
-  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+  { make_message | ${EZBIN}/ezmlm-reject "${DIR}"; }  > /dev/null 2>&1 && \
 	{ ${ECHO} "mimereject failed with dir"; exit 100; }
   OUT=`make_message | ${EZBIN}/ezmlm-reject` || \
 	{ ${ECHO} "mimereject without dir"; exit 100; }
@@ -739,9 +783,9 @@
 # test content-type with something after boundary=xxx
   AFTERBOUND=';micalg=pgp-md5'
   ${ECHO} "text/html" > "${DIR}"/mimereject
-  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+  { make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1; } > /dev/null 2>&1 && \
 	{ ${ECHO} "err with text after boundary: 0.30 bug fixed in 0.322"
-	  ${ECHO} -n "ezmlm-reject.......   "
+	  prompt "ezmlm-reject.......   "
 	  BUG="${BUG} reject_bound"
 	}
 
@@ -751,7 +795,7 @@
 
 # if entire message is mimeremove type is should be rejected
   ${ECHO} "multipart/mixed" > "${DIR}"/mimeremove
-  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+  { make_message | ${EZBIN}/ezmlm-reject "${DIR}"; } > /dev/null 2>&1  && \
 	{ ${ECHO} "mimereject failed with dir"; exit 100; }
   OUT=`make_message | ${EZBIN}/ezmlm-reject` || \
 	{ ${ECHO} "mimereject without dir"; exit 100; }
@@ -763,11 +807,11 @@
   ${ECHO} "Content-TYPE" > "${DIR}"/headerreject
   OUT=`make_message | ${EZBIN}/ezmlm-reject -H "${DIR}"` || \
 	{ ${ECHO} "headerreject -H failed with dir"; exit 100; }
-  OUT=`make_message | ${EZBIN}/ezmlm-reject -h "${DIR}" 2>&1` && \
+  { make_message | ${EZBIN}/ezmlm-reject -h "${DIR}"; } > /dev/null 2>&1 && \
 	{ ${ECHO} "headerreject failed with dir"; exit 100; }
   OUT=`make_message | ${EZBIN}/ezmlm-reject` || \
 	{ ${ECHO} "headerreject failed without dir"; exit 100; }
-  OUT=`make_message | ${EZBIN}/ezmlm-reject -h 2>&1` && \
+  { make_message | ${EZBIN}/ezmlm-reject -h; }  > /dev/null 2>&1  && \
 	{ ${ECHO} "-h was accepted without dir"; exit 100; }
 
 # Suppress content-type header
@@ -783,7 +827,7 @@
 # ezmlm-sub/unsub/list/issubn #
 ###############################
 
-  ${ECHO} -n "ezmlm-[un|is]sub[n]:  "
+  prompt "ezmlm-[un|is]sub[n]:  "
 
   SENDER="XYZZY@HOst"; export SENDER
 
@@ -861,7 +905,7 @@
 ##############
 # ezmlm-send #
 ##############
-  ${ECHO} -n "ezmlm-send (1/2):     "
+  prompt "ezmlm-send (1/2):     "
 
   SENDER="${SND}@$HOST"; export SENDER
   ${EZBIN}/ezmlm-sub "${DIR}" "$SENDER"
@@ -887,13 +931,13 @@
 
 # test to see that trailer is added to nom-mime messages
   CONTENT=''
-  { echo "X-num: msg5"; make_message; } | \
+  { ${ECHO} "X-num: msg5"; make_message; } | \
 	${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1  || \
 	{ ${ECHO} "failed to accept non-mime message"; exit 100; }
 
 # test to see that trailer is suppressed for multipart/signed
   CONTENT='multipart/signed'
-  { echo "X-num: msg6"; make_message; } | \
+  { ${ECHO} "X-num: msg6"; make_message; } | \
 	${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1  || \
 	{ ${ECHO} "failed to accept multipart/signed message"; exit 100; }
 
@@ -905,7 +949,7 @@
   ${ECHO} "text/html" > "${DIR}"/mimeremove
   make_message | ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1  || \
 	{ ${ECHO} "err with text after boundary: 0.30 bug fixed in 0.322"
-	  ${ECHO} -n "ezmlm-send.........   "
+	  prompt "ezmlm-send.........   "
 	  BUG="${BUG} send_bound"
 	}
 # restore
@@ -945,7 +989,7 @@
 ################
 # ezmlm-tstdig #
 ################
-  ${ECHO} -n "ezmlm-tstdig:         "
+  prompt "ezmlm-tstdig:         "
 
   ${EZBIN}/ezmlm-tstdig -k2 -m5 -t1 "${DIR}" || \
 	{ ${ECHO} "-t1 failed"; exit 100; }
@@ -970,7 +1014,7 @@
   fi
   ${EZBIN}/ezmlm-tstdig -k2 -m5 -t0 "${DIR}" || \
 	{ ${ECHO} "err with -digest- in mgr pos: 0.31 bug fixed in 0.321"
-	  ${ECHO} -n "ezmlm-tstdig.......   "
+	  prompt "ezmlm-tstdig.......   "
 	  BUG="${BUG} digest"
 	}
   LOCAL=''; export LOCAL
@@ -985,7 +1029,7 @@
   ${EZBIN}/ezmlm-tstdig -k1 -m5 -t0 "${DIR}" > "${ERR}" 2>&1 || \
 	{
 	 ${ECHO} "problem with DEFAULT unset: 0.32 bug, OK in 0.321."
-	 ${ECHO} -n "ezmlm-tstdig.......   "
+	 prompt "ezmlm-tstdig.......   "
 	  BUG="${BUG} tstdig"
 	}
   ${ECHO} "OK"
@@ -994,7 +1038,7 @@
 # ezmlm-weed #
 ##############
 
-  ${ECHO} -n "ezmlm-weed:           "
+  prompt "ezmlm-weed:           "
 
   ${ECHO} "Subject: test" | ${EZBIN}/ezmlm-weed || \
 	{ ${ECHO} "failed to accept good message"; exit 100; }
@@ -1006,7 +1050,7 @@
 ##############
 # ezmlm-make #
 ##############
-  ${ECHO} -n "ezmlm-make (2/2):     "
+  prompt "ezmlm-make (2/2):     "
 
 # make sure a few ezmlm-make switches work
   ${EZBIN}/ezmlm-make -+qkgu -C${EZBIN}/ezmlmrc "${DIR}" || \
@@ -1067,7 +1111,7 @@
 # ezmlm-clean #
 ###############
 
-  ${ECHO} -n "ezmlm-clean (1/2):    "
+  prompt "ezmlm-clean (1/2):    "
 
 # clean1 should be silently removed (no -x).
 # clean2 should result in a message
@@ -1115,7 +1159,7 @@
 # ezmlm-store #
 ###############
 
-  ${ECHO} -n "ezmlm-store (1/2):    "
+  prompt "ezmlm-store (1/2):    "
 
   SENDER="${SND}@$HOST"; export SENDER
   ${EZBIN}/ezmlm-sub "${DIR}/mod" "$SENDER"
@@ -1172,7 +1216,7 @@
 ################
 # ezmlm-return #
 ################
-  ${ECHO} -n "ezmlm-return:         "
+  prompt "ezmlm-return:         "
 
   SENDER="${BNC}@$HOST"; export SENDER
   HOST="$HOST"; export HOST
@@ -1229,7 +1273,7 @@
 ##############
 # ezmlm-warn #
 ##############
-  ${ECHO} -n "ezmlm-warn (1/3):     "
+  prompt "ezmlm-warn (1/3):     "
 
 # should send a warning
   ${EZBIN}/ezmlm-warn -t0 "${DIR}" >"${ERR}" 2>&1 || \
@@ -1247,7 +1291,7 @@
 ################
 # ezmlm-manage #
 ################
-  ${ECHO} -n "ezmlm-manage (1/4):   "
+  prompt "ezmlm-manage (1/4):   "
 
   LOCAL="$LOC-unsubscribe"; export LOCAL
   if [ "$QMVER" = "n" ]; then
@@ -1275,7 +1319,7 @@
   ${EZBIN}/ezmlm-manage "${DIR}" </dev/null >/dev/null 2>&1 && \
 	{
 	 ${ECHO} "Deny open to regular subscribers: 0.31 bug, OK in 0.321."
-	 ${ECHO} -n "ezmlm-manage ...      "
+	 prompt "ezmlm-manage ...      "
 	 BUG="${BUG} deny"
 	}
   SENDER="${MOD}@$HOST"; export SENDER
@@ -1293,7 +1337,7 @@
   ${EZBIN}/ezmlm-manage "${DIR}" </dev/null > "${ERR}" 2>&1 && \
 	{
 	 ${ECHO} "Deny even without remote/modsub: 0.31 bug, OK in 0.321."
-	 ${ECHO} -n "ezmlm-manage ...      "
+	 prompt "ezmlm-manage ...      "
 	 BUG="${BUG} deny"
 	}
 
@@ -1350,7 +1394,7 @@
 #################
 # ezmlm-request #
 #################
-  ${ECHO} -n "ezmlm-request (1/2):  "
+  prompt "ezmlm-request (1/2):  "
 
   SENDER="${SND}@$HOST"; export SENDER
   LOCAL="$LOC-request"; export LOCAL
@@ -1384,7 +1428,7 @@
 # ezmlm-split #
 ###############
 if [ "$QMVER" = "n" ]; then
-  ${ECHO} -n "ezmlm-split (1/2):    "
+  prompt "ezmlm-split (1/2):    "
 # set up split file
   ${ECHO} "edu:1:26:l1@h1" > "${DIR}/split"
   ${ECHO} "edu:27:52:l2@h2" >> "${DIR}/split"
@@ -1441,7 +1485,7 @@
 #############
 # ezmlm-idx #
 #############
-  ${ECHO} -n "ezmlm-idx:            "
+  prompt "ezmlm-idx:            "
   ${RM} -f "${DIR}/archive/0/index" "${DIR}/indexed"
   ${EZBIN}/ezmlm-idx "${DIR}" >"${ERR}" 2>&1 || \
 	{ ${ECHO} "failed to run"; exit 100; }
@@ -1456,7 +1500,7 @@
 #############
 # ezmlm-get #
 #############
-${ECHO} -n "ezmlm-get (1/2):      "
+prompt "ezmlm-get (1/2):      "
 
 # blast digest recipient account with all these excerpts.
 ${EZBIN}/ezmlm-sub "${DIR}/digest" "${DIG}@$HOST"
@@ -1708,7 +1752,7 @@
 ##############
 # ezmlm-send #
 ##############
-${ECHO} -n "ezmlm-send (2/2):     "
+prompt "ezmlm-send (2/2):     "
 MSG1=`${GREP} -l "msg1" $SINKDIR/new/*` || \
 	{ ${ECHO} "failed to deliver message 1 to subscriber"; \
 	exit 100; }
@@ -1738,7 +1782,7 @@
 ${GREP} "msg3" $SINKDIR/new/* >/dev/null 2>&1 && \
 	{ ${ECHO} "-C failed to exclude sender (no longer supported)"; \
 	  BUG="${BUG}_noself"; \
-	  echo -n "ezmlm-send:           "; }
+	  prompt "ezmlm-send:           "; }
 
 MSG5=`${GREP} -l "msg5" $SINKDIR/new/*` || \
 	{ ${ECHO} "failed to deliver message 5 to subscriber"; \
@@ -1753,9 +1797,9 @@
 
 ${GREP} 'TRAILER' "$MSG6" >/dev/null 2>&1 && \
 	{ ${ECHO} "failed to suppress trailer for multipart/signed message"; \
-	  echo "                      0.31 bug fixed in 0.316/0.323";
+	  ${ECHO} "                      0.31 bug fixed in 0.316/0.323";
 	  BUG="${BUG}_signed"; \
-	  echo -n "ezmlm-send ......:    "; }
+	  prompt "ezmlm-send ......:    "; }
 
 ${GREP} "msg3" $SINKDIR/new/* >/dev/null 2>&1 && \
 	{ 
@@ -1763,7 +1807,7 @@
 	  {
 	    ${ECHO} "-C failed to exclude sender (no longer supported)"
 	    BUG="${BUG}_noself"
-	    echo -n "ezmlm-send ......:   ${BUG} "
+	    prompt "ezmlm-send ......:   ${BUG} "
 	  }
 	}
 
@@ -1772,7 +1816,7 @@
 # ezmlm-clean #
 ###############
 
-${ECHO} -n "ezmlm-clean (2/2):    "
+prompt "ezmlm-clean (2/2):    "
 
 ${GREP} "clean1" ${DIGDIR}/new/* >/dev/null 2>&1 && \
 	{ ${ECHO} "removal of non-x mod queue entry 1 wasn't silent"; exit 100; }
@@ -1798,7 +1842,7 @@
 ###############
 # ezmlm-store #
 ###############
-${ECHO} -n "ezmlm-store (2/2):    "
+prompt "ezmlm-store (2/2):    "
 
 MOD1=`${GREP} -l "mod1" $SINKDIR/new/* 2>/dev/null`
 if [ -z "$MOD1" ]; then
@@ -1822,7 +1866,7 @@
 ################
 # ezmlm-manage #
 ################
-${ECHO} -n "ezmlm-manage (2/4):   "
+prompt "ezmlm-manage (2/4):   "
 
 # check digest-subscribe and list-unsubscribe replies
 SUB1=`${GREP} -l 'sub1' $MANDIR/new/*` || \
@@ -1937,7 +1981,7 @@
 # ezmlm-moderate #
 ##################
 
-${ECHO} -n "ezmlm-moderate (1/2): "
+prompt "ezmlm-moderate (1/2): "
 
 # MOD1 and MOD3 are defined from ezmlm-store testing
 
@@ -2030,7 +2074,7 @@
 ##############
 # ezmlm-warn #
 ##############
-${ECHO} -n "ezmlm-warn (2/3):     "
+prompt "ezmlm-warn (2/3):     "
 
 ${EZBIN}/ezmlm-warn -t0 "${DIR}" >"${ERR}" 2>&1 || \
 	{ ${ECHO} "failed with normal bounce for warning"; exit 100; }
@@ -2044,7 +2088,7 @@
 # ezmlm-request #
 #################
 
-  ${ECHO} -n "ezmlm-request (2/2):  "
+  prompt "ezmlm-request (2/2):  "
 
   ${GREP} "$LOC-qqqq-$SND=$HOST" "${REQ}" >/dev/null || \
 	{ ${ECHO} "'qqqq' subject query rewriting failed"; exit 100; }
@@ -2068,7 +2112,7 @@
 # ezmlm-split #
 ###############
 if [ "$QMVER" = "n" ]; then
-  ${ECHO} -n "ezmlm-split (2/2):    "
+  prompt "ezmlm-split (2/2):    "
 
 # we know that ezmlm-manage works. A bounce would go to MODDIR, so a
 # message in SINKDIR means that the request was forwarded to ezmlm-manage,
@@ -2092,7 +2136,7 @@
 # ezmlm-moderate #
 ##################
 
-  ${ECHO} -n "ezmlm-moderate (2/2): "
+  prompt "ezmlm-moderate (2/2): "
 
   MOD1=`${GREP} -l "mod1" $SINKDIR/new/* | head -1` || \
 	{ ${ECHO} "failed to send rejection notice for message mod1"; exit 100; }
@@ -2116,7 +2160,7 @@
 ################
 # ezmlm-manage #
 ################
-  ${ECHO} -n "ezmlm-manage (3/4):   "
+  prompt "ezmlm-manage (3/4):   "
 
   SENDER="${MOD}@$HOST"; export SENDER
   ${EZBIN}/ezmlm-issubn "${DIR}" && \
@@ -2179,7 +2223,7 @@
 #############
 # ezmlm-get #
 #############
-  ${ECHO} -n "ezmlm-get (2/2):      "
+  prompt "ezmlm-get (2/2):      "
 
 # index1/get1/thread1 should bounce and will not be looked for
 # index2 ... should be in DIG@HOST's inbox
@@ -2238,7 +2282,7 @@
 ##############
 # ezmlm-warn #
 ##############
-  ${ECHO} -n "ezmlm-warn (3/3):     "
+  prompt "ezmlm-warn (3/3):     "
 
   SENDER="${BNC}@${HOST}"
   export SENDER
@@ -2252,7 +2296,7 @@
 ################
 # ezmlm-manage #
 ################
-  ${ECHO} -n "ezmlm-manage (4/4):   "
+  prompt "ezmlm-manage (4/4):   "
 
   ${GREP} "#NEW_TEXT#" "${DIR}/text/test" >/dev/null 2>&1 || \
 	{ ${ECHO} "edit4 failed to update text file"; exit 100; }
diff -u ezmlm-0.53.orig/ezmlm-unsub.c ezmlm-0.53/ezmlm-unsub.c
--- ezmlm-0.53.orig/ezmlm-unsub.c	Fri Dec 24 14:15:00 1999
+++ ezmlm-0.53/ezmlm-unsub.c	Fri Jul  5 13:09:31 2002
@@ -20,7 +20,7 @@
 void die_usage()
 {
   strerr_die1x(100,
-   "ezmlm-unsub: usage: ezmlm-unsub [-h hash] [-HmMnNvV] dir box@domain ...");
+   "ezmlm-unsub: usage: ezmlm-unsub [-h hash] [-HmMvV] dir box@domain ...");
 }
 
 void main(argc,argv)
@@ -88,7 +88,7 @@
 	if (ch)
 	  *cp = '\0';
       }
-      (void) subscribe(dir,line.s,0,"","+manual",flagmysql,
+      (void) subscribe(dir,line.s,0,"","-manual",flagmysql,
 		forcehash,(char *) 0,FATAL);
     }
   }
Common subdirectories: ezmlm-0.53.orig/sub_mysql and ezmlm-0.53/sub_mysql
Common subdirectories: ezmlm-0.53.orig/sub_pgsql and ezmlm-0.53/sub_pgsql
Common subdirectories: ezmlm-0.53.orig/sub_std and ezmlm-0.53/sub_std
diff -u ezmlm-0.53.orig/tagmsg.c ezmlm-0.53/tagmsg.c
--- ezmlm-0.53.orig/tagmsg.c	Fri Dec 24 14:15:01 1999
+++ ezmlm-0.53/tagmsg.c	Fri Jul  5 13:09:31 2002
@@ -47,6 +47,7 @@
       case 0:
 	strerr_die3x(100,fatal,"key",ERR_NOEXIST);
     }
+    if (!seed) seed = "";
     cookie(hash,key.s,key.len,strnum,seed,action);
     for (i = 0; i < COOKIE; i++)
       hashout[i] = hash[i];


>Release-Note:
>Audit-Trail:
>Unformatted: