changeset 813:74d5ebb67b34

Rework the internals of list text substitution and add some substitutions. This includes making some substitutions more widely available, too, and marking some old ones as deprecated, too.
author Ben Schmidt
date Tue, 17 Jan 2012 01:26:45 +1100
parents 58a2cba0be3e
children 757225257ef3
files ChangeLog README.listtexts include/prepstdreply.h include/send_help.h src/listcontrol.c src/mlmmj-bounce.c src/mlmmj-process.c src/mlmmj-sub.c src/mlmmj-unsub.c src/prepstdreply.c src/send_digest.c src/send_help.c src/send_list.c
diffstat 13 files changed, 378 insertions(+), 293 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Jan 16 21:30:29 2012 +1100
+++ b/ChangeLog	Tue Jan 17 01:26:45 2012 +1100
@@ -1,3 +1,7 @@
+ o Deprecate various list text substitutions such as $newsub$, $oldsub$,
+   $moderateaddr$
+ o Add $permitaddr$ and $releaseaddr$ substitutions
+ o Make $subject$, $posteraddr$ and $subaddr$ more widely available
  o Fix potential crash when mail to the owner arrives with no From: header
  o Add %originalmail% directive and restore backward compatibility of
    $originalmail$
--- a/README.listtexts	Mon Jan 16 21:30:29 2012 +1100
+++ b/README.listtexts	Tue Jan 17 01:26:45 2012 +1100
@@ -324,9 +324,11 @@
   DEPRECATED: use %bouncenumbers%
 
 - $confaddr$
+- $confirmaddr$
   (available only in confirm-[un]sub-*)
   the address to which to send mail to confirm the (un-)subscription in
   question
+  NOTE: the short version of this substitution is DEPRECATED
 
 - $control C$
   the contents of the control file named C in listdir/control, with its final
@@ -410,15 +412,17 @@
   (available only in moderate-post-* and gatekeep-sub)
   the address to which to send mail to approve the post or subscription in
   question
+  DEPRECATED: use $releaseaddr$ or $permitaddr$ instead
 
 - $moderators$
   (available only in moderate-post-*, wait-post-*, gatekeep-sub and wait-sub)
   the formatted list of moderators to whom the moderation request has been sent
-  DEPRECATED: use %moderators% or %gatekeepers%
+  DEPRECATED: use %moderators% or %gatekeepers% instead
 
 - $newsub$
   (available only in notify-sub-*-*)
   the address that has been subscribed
+  DEPRECATED: use $subaddr$ instead
 
 - $nomailsubaddr$
   listname+subscribe-nomail@domain.tld
@@ -429,16 +433,21 @@
   DEPRECATED: use $list+$unsubscribe-nomail@$domain$ instead
 
 - $oldsub$
-  (available only in notify-nsub-*-*)
+  (available only in notify-sub-*-*)
   the address that has been unsubscribed
+  DEPRECATED: use $subaddr$ instead
 
 - $originalmail$
   the same as %originalmail 100% preceded by a space
   DEPRECATED: use %originalmail%
 
+- $permitaddr$
+  (available only in gatekeep-sub)
+  the address to which to send mail to permit the subscription in question
+
 - $posteraddr$
-  (available only in deny-post-{access|tocc|subonlypost}, moderate-post-* and
-  wait-post-*)
+  (available only in deny-post-{access|tocc|subonlypost|maxmailsize},
+  moderate-post-* and wait-post-*)
   the from address of the message that was received as determined by Mlmmj
 
 - $random0$
@@ -451,13 +460,18 @@
   that are MIME messages with attachments by creating boundaries that are
   unlikely to appear in the attached messages
 
+- $releaseaddr$
+  (available only in moderate-post-*)
+  the address to which to send mail to release the post in question
+
 - $subaddr$
-  (available only in gatekeep-sub and confirm-[un]sub-*)
+  (available only in gatekeep-sub, confirm-[un]sub-*, finish-[un]sub-*,
+  notify-[un]sub-* and deny-[un]sub-*)
   the address requested to be (un-)subscribed
 
 - $subject$
-  (available only in deny-post-{access|tocc|subonlypost}, moderate-post-* and
-  wait-post-*)
+  (available only in deny-post-{access|tocc|subonlypost|maxmailsize},
+  moderate-post-* and wait-post-*)
   the subject line of the message in question
 
 - $text T$
--- a/include/prepstdreply.h	Mon Jan 16 21:30:29 2012 +1100
+++ b/include/prepstdreply.h	Tue Jan 17 01:26:45 2012 +1100
@@ -29,18 +29,16 @@
 typedef struct text text;
 
 char *substitute(const char *line, const char *listaddr, const char *listdelim,
-		size_t datacount, char **data, const char *listdir);
+		const char *listdir, text *txt);
 text *open_text_file(const char *listdir, const char *filename);
 text *open_text(const char *listdir, const char *purpose, const char *action,
 		   const char *reason, const char *type, const char *compat);
+void register_unformatted(text *txt, const char *token, const char *subst);
+void register_originalmail(text *txt, const char *mailname);
 char *get_processed_text_line(text *txt,
-		const char *listaddr, const char *listdelim,
-		size_t datacount, char **data, const char *listdir,
-		const char *mailname);
+		const char *listaddr, const char *listdelim, const char *listdir);
 void close_text(text *txt);
-char *prepstdreply(const char *listdir, const char *purpose, const char *action,
-		const char *reason, const char *type, const char *compat,
-		const char *from, const char *to, const char *replyto,
-		size_t tokencount, char **data, const char *mailname);
+char *prepstdreply(text *txt, const char *listdir,
+		const char *from, const char *to, const char *replyto);
 
 #endif /* PREPSTDREPLY_H */
--- a/include/send_help.h	Mon Jan 16 21:30:29 2012 +1100
+++ b/include/send_help.h	Tue Jan 17 01:26:45 2012 +1100
@@ -24,8 +24,7 @@
 #ifndef SEND_HELP_H
 #define SEND_HELP_H
 
-void send_help(const char *listdir, const char *emailaddr,
-	       const char *mlmmjsend, const char *purpose, const char *action,
-	       const char *reason, const char *type, const char *compat);
+void send_help(const char *listdir, const char *queuefilename,
+		const char *emailaddr, const char *mlmmjsend);
 
 #endif
--- a/src/listcontrol.c	Mon Jan 16 21:30:29 2012 +1100
+++ b/src/listcontrol.c	Tue Jan 17 01:26:45 2012 +1100
@@ -36,6 +36,7 @@
 #include "find_email_adr.h"
 #include "getlistdelim.h"
 #include "strgen.h"
+#include "prepstdreply.h"
 #include "send_help.h"
 #include "send_list.h"
 #include "log_error.h"
@@ -116,6 +117,8 @@
 	unsigned int ctrl;
 	struct strlist *owners;
 	int owner_idx;
+	text *txt;
+	char *queuefilename;
 	
 	/* A closed list doesn't allow subscribtion and unsubscription */
 	closedlist = statctrl(listdir, "closedlist");
@@ -209,10 +212,20 @@
 		}
 		if (statctrl(listdir, "nodigestsub")) {
 			errno = 0;
-			log_error(LOG_ARGS, "A subcribe-digest request was"
+			log_error(LOG_ARGS, "A subscribe-digest request was"
 				" denied");
-			send_help(listdir, fromemails->emaillist[0],
-				mlmmjsend, "deny", "sub", "disabled", "digest", "sub-deny-digest");
+			txt = open_text(listdir, "deny", "sub", "disabled",
+					"digest", "sub-deny-digest");
+			MY_ASSERT(txt);
+			register_unformatted(txt, "subaddr",
+					fromemails->emaillist[0]);
+			queuefilename = prepstdreply(txt, listdir,
+					"$listowner$",
+					fromemails->emaillist[0], NULL);
+			MY_ASSERT(queuefilename);
+			close_text(txt);
+			send_help(listdir, queuefilename,
+					fromemails->emaillist[0], mlmmjsend);
 			return -1;
 		}
 		log_oper(listdir, OPLOGFNAME, "mlmmj-sub: request for digest"
@@ -246,10 +259,20 @@
 		}
 		if (statctrl(listdir, "nonomailsub")) {
 			errno = 0;
-			log_error(LOG_ARGS, "A subcribe-nomail request was"
+			log_error(LOG_ARGS, "A subscribe-nomail request was"
 				" denied");
-			send_help(listdir, fromemails->emaillist[0],
-				mlmmjsend, "deny", "sub", "disabled", "nomail", "sub-deny-nomail");
+			txt = open_text(listdir, "deny", "sub", "disabled",
+					"nomail", "sub-deny-nomail");
+			MY_ASSERT(txt);
+			register_unformatted(txt, "subaddr",
+					fromemails->emaillist[0]);
+			queuefilename = prepstdreply(txt, listdir,
+					"$listowner$",
+					fromemails->emaillist[0], NULL);
+			MY_ASSERT(queuefilename);
+			close_text(txt);
+			send_help(listdir, queuefilename,
+					fromemails->emaillist[0], mlmmjsend);
 			return -1;
 		}
 		log_oper(listdir, OPLOGFNAME, "mlmmj-sub: request for nomail"
@@ -664,8 +687,14 @@
 		}
 		log_oper(listdir, OPLOGFNAME, "%s requested help",
 				fromemails->emaillist[0]);
-		send_help(listdir, fromemails->emaillist[0], mlmmjsend,
-				"help", NULL, NULL, NULL, "listhelp");
+		txt = open_text(listdir, "help", NULL, NULL, NULL, "listhelp");
+		MY_ASSERT(txt);
+		queuefilename = prepstdreply(txt, listdir,
+				"$listowner$", fromemails->emaillist[0], NULL);
+		MY_ASSERT(queuefilename);
+		close_text(txt);
+		send_help(listdir, queuefilename,
+				fromemails->emaillist[0], mlmmjsend);
 		break;
 
        /* listname+faq@domain.tld */
@@ -680,8 +709,14 @@
                }
                log_oper(listdir, OPLOGFNAME, "%s requested faq",
                                fromemails->emaillist[0]);
-               send_help(listdir, fromemails->emaillist[0], mlmmjsend,
-               		"faq", NULL, NULL, NULL, "listfaq");
+		txt = open_text(listdir, "faq", NULL, NULL, NULL, "listfaq");
+		MY_ASSERT(txt);
+		queuefilename = prepstdreply(txt, listdir,
+				"$listowner$", fromemails->emaillist[0], NULL);
+		MY_ASSERT(queuefilename);
+		close_text(txt);
+		send_help(listdir, queuefilename,
+				fromemails->emaillist[0], mlmmjsend);
                break;
 
 	/* listname+get-INDEX@domain.tld */
--- a/src/mlmmj-bounce.c	Mon Jan 16 21:30:29 2012 +1100
+++ b/src/mlmmj-bounce.c	Tue Jan 17 01:26:45 2012 +1100
@@ -108,9 +108,9 @@
 
 void do_probe(const char *listdir, const char *mlmmjsend, const char *addr)
 {
+	text *txt;
 	char *myaddr, *from, *a, *indexstr, *queuefilename, *listaddr;
 	char *listfqdn, *listname, *probefile, *listdelim=getlistdelim(listdir);
-	char *maildata[] = { "bouncenumbers", NULL };
 	int fd;
 	time_t t;
 
@@ -144,12 +144,13 @@
 		exit(EXIT_FAILURE);
 	}
 
-	maildata[1] = indexstr;
-	queuefilename = prepstdreply(listdir,
-			"probe", NULL, NULL, NULL, "bounce-probe",
-			"$listowner$", myaddr, NULL, 1, maildata, NULL);
+	txt = open_text(listdir, "probe", NULL, NULL, NULL, "bounce-probe");
+	MY_ASSERT(txt);
+	register_unformatted(txt, "bouncenumbers", indexstr);
+	myfree(indexstr);
+	queuefilename = prepstdreply(txt, listdir, "$listowner$", myaddr, NULL);
 	MY_ASSERT(queuefilename);
-	myfree(indexstr);
+	close_text(txt);
 
 	probefile = concatstr(4, listdir, "/bounce/", addr, "-probe");
 	MY_ASSERT(probefile);
--- a/src/mlmmj-process.c	Mon Jan 16 21:30:29 2012 +1100
+++ b/src/mlmmj-process.c	Tue Jan 17 01:26:45 2012 +1100
@@ -86,17 +86,17 @@
 };
 
 
-void newmoderated(const char *listdir, const char *mailfilename,
+static void newmoderated(const char *listdir, const char *mailfilename,
 		  const char *mlmmjsend, const char *efromsender,
-		  size_t tokencount, char **data, enum modreason modreason)
+		  const char *subject, const char *posteraddr,
+		  enum modreason modreason)
 {
-	size_t i;
 	char *from, *listfqdn, *listname, *moderators = NULL;
 	char *buf, *replyto, *listaddr = getlistaddr(listdir), *listdelim;
+	text *txt;
 	char *queuefilename = NULL, *moderatorsfilename, *efromismod = NULL;
 	char *mailbasename = mybasename(mailfilename), *tmp, *to;
 	int moderatorsfd, foundaddr = 0, notifymod = 0, status;
-	char *maildata[10] = { "moderateaddr", NULL, "moderators", NULL };
 	pid_t childpid, pid;
 #if 0
 	printf("mailfilename = [%s], mailbasename = [%s]\n", mailfilename,
@@ -105,13 +105,6 @@
 	listfqdn = genlistfqdn(listaddr);
 	listname = genlistname(listaddr);
 
-	MY_ASSERT(tokencount<=3)
-	for (i=0; i<tokencount; i++) {
-		maildata[4+2*i] = data[2*i];
-		maildata[5+2*i] = data[1+2*i];
-	}
-	tokencount += 2;
-
 	moderatorsfilename = concatstr(2, listdir, "/control/moderators");
 	if((moderatorsfd = open(moderatorsfilename, O_RDONLY)) < 0) {
 		log_error(LOG_ARGS, "Could not open '%s'", moderatorsfilename);
@@ -143,13 +136,6 @@
 	replyto = concatstr(6, listname, listdelim, "moderate-", mailbasename,
 			    "@", listfqdn);
 
-	maildata[1] = replyto;
-	if(efromismod) {
-		myfree(moderators);
-		maildata[3] = efromismod;
-	} else
-		maildata[3] = moderators;
-
 	from = concatstr(4, listname, listdelim, "owner@", listfqdn);
 	to = concatstr(3, listname, "-moderators@", listfqdn); /* FIXME JFA: Should this be converted? Why, why not? */
 
@@ -157,10 +143,19 @@
 	myfree(listname);
 	myfree(listfqdn);
 
-	queuefilename = prepstdreply(listdir,
-			"moderate", "post", modreason_strs[modreason], NULL,
-			"moderation", "$listowner$", to, replyto,
-			tokencount, maildata, mailfilename);
+	txt = open_text(listdir, "moderate", "post",
+			modreason_strs[modreason], NULL, "moderation");
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subject", subject);
+	register_unformatted(txt, "posteraddr", posteraddr);
+	register_unformatted(txt, "moderateaddr", replyto); /* DEPRECATED */
+	register_unformatted(txt, "releaseaddr", replyto);
+	if(efromismod) register_unformatted(txt, "moderators", efromismod);
+	else register_unformatted(txt, "moderators", moderators);
+	register_originalmail(txt, mailfilename);
+	queuefilename = prepstdreply(txt, listdir, "$listowner$", to, replyto);
+	MY_ASSERT(queuefilename);
+	close_text(txt);
 
 	/* we might need to exec more than one mlmmj-send */
 	
@@ -200,10 +195,18 @@
 
 	/* send mail to poster that the list is moderated */
 
-	queuefilename = prepstdreply(listdir,
-			"wait", "post", modreason_strs[modreason], NULL,
-			"moderation-poster", "$listowner$", efromsender,
-			NULL, tokencount-1, maildata+2, mailfilename);
+	txt = open_text(listdir, "wait", "post",
+			modreason_strs[modreason], NULL, "moderation-poster");
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subject", subject);
+	register_unformatted(txt, "posteraddr", posteraddr);
+	if(efromismod) register_unformatted(txt, "moderators", efromismod);
+	else register_unformatted(txt, "moderators", moderators);
+	register_originalmail(txt, mailfilename);
+	queuefilename = prepstdreply(txt, listdir,
+			"$listowner$", efromsender, NULL);
+	MY_ASSERT(queuefilename);
+	close_text(txt);
 
 	execlp(mlmmjsend, mlmmjsend,
 			"-l", "1",
@@ -412,10 +415,10 @@
 	char *mlmmjsend, *mlmmjsub, *mlmmjunsub, *mlmmjbounce;
 	char *bindir, *subjectprefix, *discardname, *listaddr, *listdelim;
 	char *listfqdn, *listname, *fromaddr;
+	text *txt;
 	char *queuefilename, *recipextra = NULL, *owner = NULL;
 	char *maxmailsizestr;
-	char *maildata[6] = { "subject", NULL,
-		"posteraddr", NULL, "maxmailsize", NULL };
+	char *subject = NULL, *posteraddr = NULL;
 	char *envstr, *efrom;
 	struct stat st;
 	uid_t uid;
@@ -591,10 +594,7 @@
 		/* TODO: free emailstructs */
 		exit(EXIT_SUCCESS);
 	}
-	maildata[3] = fromemails.emaillist[0];
-
-	if (fromemails.emailcount)
-		maildata[3] = fromemails.emaillist[0];
+	posteraddr = fromemails.emaillist[0];
 
 	/* To: addresses */
 	for(i = 0; i < readhdrs[1].valuecount; i++) {
@@ -618,9 +618,8 @@
 
 	/* Subject: */
 	if (readhdrs[5].valuecount)
-		maildata[1] = unistr_header_to_utf8(readhdrs[5].values[0]);
-	if (!maildata[1])
-		maildata[1] = mystrdup("");
+			subject = unistr_header_to_utf8(readhdrs[5].values[0]);
+	if (!subject) subject = mystrdup("");
 
 	/* envelope from */
 	if((envstr = getenv("SENDER")) != NULL) {
@@ -755,13 +754,17 @@
 			listfqdn = genlistfqdn(listaddr);
 			fromaddr = concatstr(4, listname, listdelim,
 					"bounces-help@", listfqdn);
-			maildata[5] = maxmailsizestr;
-			queuefilename = prepstdreply(listdir,
-					"deny", "post", "maxmailsize", NULL,
-					"maxmailsize", "$listowner$",
-					fromemails.emaillist[0],
-					NULL, 1, maildata+4, donemailname);
-			MY_ASSERT(queuefilename)
+			txt = open_text(listdir, "deny", "post",
+					"maxmailsize", NULL, "maxmailsize");
+			MY_ASSERT(txt);
+			register_unformatted(txt, "subject", subject);
+			register_unformatted(txt, "posteraddr", posteraddr);
+			register_unformatted(txt, "maxmailsize", maxmailsizestr);
+			register_originalmail(txt, donemailname);
+			queuefilename = prepstdreply(txt, listdir,
+					"$listowner$", posteraddr, NULL);
+			MY_ASSERT(queuefilename);
+			close_text(txt);
 			myfree(listdelim);
 			myfree(listname);
 			myfree(listfqdn);
@@ -772,7 +775,7 @@
 			execlp(mlmmjsend, mlmmjsend,
 					"-l", "1",
 					"-L", listdir,
-					"-T", fromemails.emaillist[0],
+					"-T", posteraddr,
 					"-F", fromaddr,
 					"-m", queuefilename, (char *)NULL);
 
@@ -835,7 +838,7 @@
 		/* Don't send a mail about denial to the list, but silently
 		 * discard and exit. Also don't in case of it being turned off
 		 */
-		if ((strcasecmp(listaddr, fromemails.emaillist[0]) == 0) ||
+		if ((strcasecmp(listaddr, posteraddr) == 0) ||
 				notoccdenymails) {
 			log_error(LOG_ARGS, "Discarding %s because list"
 					" address was not in To: or Cc:,"
@@ -852,11 +855,16 @@
 		listfqdn = genlistfqdn(listaddr);
 		fromaddr = concatstr(4, listname, listdelim, "bounces-help@",
 				     listfqdn);
-		queuefilename = prepstdreply(listdir,
-				"deny", "post", "notintocc", NULL, "notintocc",
-				"$listowner$", fromemails.emaillist[0], NULL,
-				2, maildata, donemailname);
+		txt = open_text(listdir, "deny", "post",
+				"notintocc", NULL, "notintocc");
+		MY_ASSERT(txt);
+		register_unformatted(txt, "subject", subject);
+		register_unformatted(txt, "posteraddr", posteraddr);
+		register_originalmail(txt, donemailname);
+		queuefilename = prepstdreply(txt, listdir,
+				"$listowner$", posteraddr, NULL);
 		MY_ASSERT(queuefilename)
+		close_text(txt);
 		myfree(listdelim);
 		myfree(listname);
 		myfree(listfqdn);
@@ -865,7 +873,7 @@
 		execlp(mlmmjsend, mlmmjsend,
 				"-l", "1",
 				"-L", listdir,
-				"-T", fromemails.emaillist[0],
+				"-T", posteraddr,
 				"-F", fromaddr,
 				"-m", queuefilename, (char *)NULL);
 
@@ -877,7 +885,7 @@
 	if(subonlypost) {
 		/* Don't send a mail about denial to the list, but silently
 		 * discard and exit. */
-		if (strcasecmp(listaddr, fromemails.emaillist[0]) == 0) {
+		if (strcasecmp(listaddr, posteraddr) == 0) {
 			log_error(LOG_ARGS, "Discarding %s because"
 					" subonlypost was set and From: was"
 					" the list address",
@@ -887,7 +895,7 @@
 			myfree(donemailname);
 			exit(EXIT_SUCCESS);
 		}
-		if(is_subbed(listdir, fromemails.emaillist[0]) != 0) {
+		if(is_subbed(listdir, posteraddr) != 0) {
 			modnonsubposts = statctrl(listdir,
 					"modnonsubposts");
 			if(modnonsubposts) {
@@ -914,12 +922,16 @@
 			listfqdn = genlistfqdn(listaddr);
 			fromaddr = concatstr(4, listname, listdelim,
 					"bounces-help@", listfqdn);
-			queuefilename = prepstdreply(listdir,
-					"deny", "post", "subonlypost", NULL,
-					"subonlypost", "$listowner$",
-					fromemails.emaillist[0], NULL,
-					2, maildata, donemailname);
+			txt = open_text(listdir, "deny", "post",
+					"subonlypost", NULL, "subonlypost");
+			MY_ASSERT(txt);
+			register_unformatted(txt, "subject", subject);
+			register_unformatted(txt, "posteraddr", posteraddr);
+			register_originalmail(txt, donemailname);
+			queuefilename = prepstdreply(txt, listdir,
+					"$listowner$", posteraddr, NULL);
 			MY_ASSERT(queuefilename)
+			close_text(txt);
 			myfree(listaddr);
 			myfree(listdelim);
 			myfree(listname);
@@ -928,7 +940,7 @@
 			myfree(donemailname);
 			execlp(mlmmjsend, mlmmjsend,
 					"-l", "1",
-					"-T", fromemails.emaillist[0],
+					"-T", posteraddr,
 					"-F", fromaddr,
 					"-m", queuefilename, (char *)NULL);
 
@@ -954,10 +966,10 @@
 		/* Don't send a mail about denial to the list, but silently
 		 * discard and exit. Also do this in case it's turned off */
 		accret = do_access(access_rules, &allheaders,
-					fromemails.emaillist[0], listdir);
+					posteraddr, listdir);
 		if (accret == DENY) {
-			if ((strcasecmp(listaddr, fromemails.emaillist[0]) ==
-						0) || noaccessdenymails) {
+			if ((strcasecmp(listaddr, posteraddr) == 0) ||
+					noaccessdenymails) {
 				log_error(LOG_ARGS, "Discarding %s because"
 						" it was denied by an access"
 						" rule, and From: was the list"
@@ -974,12 +986,16 @@
 			listfqdn = genlistfqdn(listaddr);
 			fromaddr = concatstr(4, listname, listdelim,
 					"bounces-help@", listfqdn);
-			queuefilename = prepstdreply(listdir,
-					"deny", "post", "access", NULL,
-					"access", "$listowner$",
-					fromemails.emaillist[0], NULL,
-					2, maildata, donemailname);
+			txt = open_text(listdir, "deny", "post",
+					"access", NULL, "access");
+			MY_ASSERT(txt);
+			register_unformatted(txt, "subject", subject);
+			register_unformatted(txt, "posteraddr", posteraddr);
+			register_originalmail(txt, donemailname);
+			queuefilename = prepstdreply(txt, listdir,
+					"$listowner$", posteraddr, NULL);
 			MY_ASSERT(queuefilename)
+			close_text(txt);
 			myfree(listaddr);
 			myfree(listdelim);
 			myfree(listname);
@@ -990,7 +1006,7 @@
 			execlp(mlmmjsend, mlmmjsend,
 					"-l", "1",
 					"-L", listdir,
-					"-T", fromemails.emaillist[0],
+					"-T", posteraddr,
 					"-F", fromaddr,
 					"-m", queuefilename, (char *)NULL);
 
@@ -1046,8 +1062,7 @@
 				exit(EXIT_FAILURE);
 			}
 			myfree(omitfilename);
-			if(writen(omitfd, fromemails.emaillist[0],
-					strlen(fromemails.emaillist[0])) < 0) {
+			if(writen(omitfd, posteraddr, strlen(posteraddr)) < 0) {
 				log_error(LOG_ARGS,
 						"could not write omit file");
 				myfree(mqueuename);
@@ -1057,7 +1072,8 @@
 			close(omitfd);
 		}
 		newmoderated(listdir, mqueuename,
-				mlmmjsend, efrom, 2, maildata, modreason);
+				mlmmjsend, efrom, subject, posteraddr,
+				modreason);
 		return EXIT_SUCCESS;
 	}
 
@@ -1072,7 +1088,7 @@
 	if (notmetoo)
 		execlp(mlmmjsend, mlmmjsend,
 				"-L", listdir,
-				"-o", fromemails.emaillist[0],
+				"-o", posteraddr,
 				"-m", donemailname, (char *)NULL);
 	else
 		execlp(mlmmjsend, mlmmjsend,
--- a/src/mlmmj-sub.c	Mon Jan 16 21:30:29 2012 +1100
+++ b/src/mlmmj-sub.c	Tue Jan 17 01:26:45 2012 +1100
@@ -71,13 +71,12 @@
 		const char *mlmmjsend, enum subtype typesub)
 {
 	int i, fd, status, nosubmodmails = 0;
+	text *txt;
 	char *a = NULL, *queuefilename, *from, *listname, *listfqdn, *str;
 	char *modfilename, *randomstr, *mods, *to, *replyto, *moderators = NULL;
 	char *modfilebase;
 	struct strlist *submods;
 	pid_t childpid, pid;
-	char *maildata[6] = { "subaddr", NULL, "moderateaddr", NULL,
-				"moderators", NULL };
 
 	/* generate the file in moderation/ */
 	switch(typesub) {
@@ -158,15 +157,16 @@
 		myfree(str);
 	}
 
-	maildata[1] = mystrdup(subaddr);
-	maildata[3] = replyto;
-	maildata[5] = moderators;
-
-	queuefilename = prepstdreply(listdir,
-			"gatekeep", "sub", NULL, NULL, "submod-moderator",
-			"$listowner$", to, replyto, 3, maildata, NULL);
-
-	myfree(maildata[1]);
+	txt = open_text(listdir,
+			"gatekeep", "sub", NULL, NULL, "submod-moderator");
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	register_unformatted(txt, "moderateaddr", replyto); /* DEPRECATED */
+	register_unformatted(txt, "permitaddr", replyto);
+	register_unformatted(txt, "moderators", moderators);
+	queuefilename = prepstdreply(txt, listdir, "$listowner$", to, replyto);
+	MY_ASSERT(queuefilename);
+	close_text(txt);
 	
 	/* we might need to exec more than one mlmmj-send */
 	
@@ -200,17 +200,24 @@
 
 	myfree(to);
 	myfree(replyto);
-	myfree(moderators);
 	
 	/* send mail to requester that the list is submod'ed */
 
 	from = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
-	queuefilename = prepstdreply(listdir,
-			"wait", "sub", NULL, NULL, "submod-requester",
-			"$listowner$", subaddr, NULL, 0, NULL, NULL);
+
+	txt = open_text(listdir,
+			"wait", "sub", NULL, NULL, "submod-requester");
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	register_unformatted(txt, "moderators", moderators);
+	queuefilename = prepstdreply(txt, listdir,
+			"$listowner$", subaddr, NULL);
+	MY_ASSERT(queuefilename);
+	close_text(txt);
 
 	myfree(listname);
 	myfree(listfqdn);
+	myfree(moderators);
 	execl(mlmmjsend, mlmmjsend,
 				"-l", "1",
 				"-L", listdir,
@@ -276,6 +283,7 @@
 		const char *listdelim, const char *subaddr,
 		const char *mlmmjsend, enum subtype typesub, enum subreason reasonsub)
 {
+	text *txt;
 	char *queuefilename, *fromaddr, *listname, *listfqdn, *listtext;
 
 	listname = genlistname(listaddr);
@@ -299,13 +307,16 @@
 			break;
 	}
 
-	queuefilename = prepstdreply(listdir,
-			"finish", "sub",
+	txt = open_text(listdir, "finish", "sub",
 			subreason_strs[reasonsub], subtype_strs[typesub],
-			listtext, "$helpaddr$", subaddr, NULL,
-			0, NULL, NULL);
+			listtext);
+	myfree(listtext);
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	queuefilename = prepstdreply(txt, listdir,
+			"$helpaddr$", subaddr, NULL);
 	MY_ASSERT(queuefilename);
-	myfree(listtext);
+	close_text(txt);
 
 	execlp(mlmmjsend, mlmmjsend,
 				"-l", "1",
@@ -321,15 +332,13 @@
 		const char *listdelim, const char *subaddr,
 		const char *mlmmjsend, enum subtype typesub, enum subreason reasonsub)
 {
-	char *maildata[2] = { "newsub", NULL };
 	char *listfqdn, *listname, *fromaddr, *tostr;
+	text *txt;
 	char *queuefilename = NULL, *listtext = NULL;
 
 	listname = genlistname(listaddr);
 	listfqdn = genlistfqdn(listaddr);
 
-	maildata[1] = mystrdup(subaddr);
-	
 	fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
 	tostr = concatstr(4, listname, listdelim, "owner@", listfqdn);
 	
@@ -349,14 +358,18 @@
 			break;
 	}
 
-	queuefilename = prepstdreply(listdir,
-			"notify", "sub",
+	txt = open_text(listdir, "notify", "sub",
 			subreason_strs[reasonsub], subtype_strs[typesub],
-			listtext, "$listowner$", "$listowner$", NULL,
-			1, maildata, NULL);
-	MY_ASSERT(queuefilename)
+			listtext);
 	myfree(listtext);
-	myfree(maildata[1]);
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	register_unformatted(txt, "newsub", subaddr); /* DEPRECATED */
+	queuefilename = prepstdreply(txt, listdir,
+			"$listowner$", "$listowner$", NULL);
+	MY_ASSERT(queuefilename);
+	close_text(txt);
+
 	execlp(mlmmjsend, mlmmjsend,
 			"-l", "1",
 			"-L", listdir,
@@ -374,9 +387,9 @@
 {
 	int subconffd;
 	char *confirmaddr, *listname, *listfqdn, *confirmfilename = NULL;
+	text *txt;
 	char *listtext, *queuefilename = NULL, *fromaddr;
 	char *randomstr = NULL, *tmpstr;
-	char *maildata[4] = { "subaddr", NULL, "confaddr", NULL };
 
 	listname = genlistname(listaddr);
 	listfqdn = genlistfqdn(listaddr);
@@ -436,17 +449,18 @@
 	myfree(randomstr);
 	myfree(tmpstr);
 
-	maildata[1] = mystrdup(subaddr);
-	maildata[3] = mystrdup(confirmaddr);
-
-	queuefilename = prepstdreply(listdir,
-			"confirm", "sub",
+	txt = open_text(listdir, "confirm", "sub",
 			subreason_strs[reasonsub], subtype_strs[typesub],
-			listtext, "$helpaddr$", subaddr, confirmaddr,
-			2, maildata, NULL);
-
-	myfree(maildata[1]);
-	myfree(maildata[3]);
+			listtext);
+	myfree(listtext);
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	register_unformatted(txt, "confaddr", confirmaddr); /* DEPRECATED */
+	register_unformatted(txt, "confirmaddr", confirmaddr);
+	queuefilename = prepstdreply(txt, listdir,
+			"$helpaddr$", subaddr, confirmaddr);
+	MY_ASSERT(queuefilename);
+	close_text(txt);
 
 	myfree(listname);
 	myfree(listfqdn);
@@ -487,6 +501,7 @@
 void generate_subscribed(const char *listdir, const char *subaddr,
 		const char *mlmmjsend)
 {
+	text *txt;
 	char *queuefilename, *fromaddr, *listname, *listfqdn, *listaddr;
 	char *listdelim = getlistdelim(listdir);
 
@@ -497,10 +512,14 @@
 	fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
 	myfree(listdelim);
 
-	queuefilename = prepstdreply(listdir,
-			"deny", "sub", "subbed", NULL, "sub-subscribed",
-			"$helpaddr$", subaddr, NULL, 0, NULL, NULL);
+	txt = open_text(listdir,
+			"deny", "sub", "subbed", NULL, "sub-subscribed");
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	queuefilename = prepstdreply(txt, listdir,
+			"$helpaddr$", subaddr, NULL);
 	MY_ASSERT(queuefilename);
+	close_text(txt);
 
 	myfree(listaddr);
 	myfree(listname);
--- a/src/mlmmj-unsub.c	Mon Jan 16 21:30:29 2012 +1100
+++ b/src/mlmmj-unsub.c	Tue Jan 17 01:26:45 2012 +1100
@@ -53,6 +53,7 @@
 		   const char *mlmmjsend,
 		   enum subtype typesub, enum subreason reasonsub)
 {
+	text *txt;
 	char *queuefilename, *fromaddr, *listname, *listfqdn, *listtext;
 
 	listname = genlistname(listaddr);
@@ -76,12 +77,16 @@
 			break;
 	}
 
-	queuefilename = prepstdreply(listdir,
-			"finish", "unsub",
+	txt = open_text(listdir, "finish", "unsub",
 			subreason_strs[reasonsub], subtype_strs[typesub],
-			listtext, "$helpaddr$", subaddr, NULL, 0, NULL, NULL);
+			listtext);
+	myfree(listtext);
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	queuefilename = prepstdreply(txt, listdir,
+			"$helpaddr$", subaddr, NULL);
 	MY_ASSERT(queuefilename);
-	myfree(listtext);
+	close_text(txt);
 
 	execlp(mlmmjsend, mlmmjsend,
 				"-l", "1",
@@ -99,15 +104,13 @@
 		  const char *mlmmjsend,
 		  enum subtype typesub, enum subreason reasonsub)
 {
-        char *maildata[4] = { "oldsub", NULL };
         char *listfqdn, *listname, *fromaddr, *tostr;
+	text *txt;
         char *queuefilename = NULL, *listtext;
 
         listname = genlistname(listaddr);
         listfqdn = genlistfqdn(listaddr);
 
-        maildata[1] = mystrdup(subaddr);
-
         fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
 	tostr = concatstr(4, listname, listdelim, "owner@", listfqdn);
 
@@ -127,14 +130,17 @@
 			break;
 	}
 	
-	queuefilename = prepstdreply(listdir,
-			"notify", "unsub",
+	txt = open_text(listdir, "notify", "unsub",
 			subreason_strs[reasonsub], subtype_strs[typesub],
-			listtext, "$listowner$", "$listowner$", NULL,
-			1, maildata, NULL);
+			listtext);
+	myfree(listtext);
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	register_unformatted(txt, "oldsub", subaddr); /* DEPRECATED */
+	queuefilename = prepstdreply(txt, listdir,
+			"$listowner$", "$listowner$", NULL);
 	MY_ASSERT(queuefilename);
-	myfree(listtext);
-	myfree(maildata[1]);
+	close_text(txt);
 
 	execlp(mlmmjsend, mlmmjsend,
 			"-l", "1",
@@ -154,9 +160,9 @@
 			   enum subtype typesub, enum subreason reasonsub)
 {
 	char *confirmaddr, *listname, *listfqdn, *tmpstr;
+	text *txt;
 	char *queuefilename, *fromaddr;
 	char *randomstr = NULL, *confirmfilename = NULL, *listtext;
-	char *maildata[4] = { "subaddr", NULL, "confaddr", NULL };
 	int subconffd;
 
 	listname = genlistname(listaddr);
@@ -217,17 +223,18 @@
 	myfree(randomstr);
 	myfree(tmpstr);
 
-	maildata[1] = mystrdup(subaddr);
-	maildata[3] = mystrdup(confirmaddr);
-
-	queuefilename = prepstdreply(listdir,
-			"confirm", "unsub",
+	txt = open_text(listdir, "confirm", "unsub",
 			subreason_strs[reasonsub], subtype_strs[typesub],
-			listtext, "$helpaddr$", subaddr, confirmaddr,
-			2, maildata, NULL);
-
-	myfree(maildata[1]);
-	myfree(maildata[3]);
+			listtext);
+	myfree(listtext);
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	register_unformatted(txt, "confaddr", confirmaddr); /* DEPRECATED */
+	register_unformatted(txt, "confirmaddr", confirmaddr);
+	queuefilename = prepstdreply(txt, listdir,
+			"$helpaddr$", subaddr, confirmaddr);
+	MY_ASSERT(queuefilename);
+	close_text(txt);
 
 	myfree(listname);
 	myfree(listfqdn);
@@ -308,6 +315,7 @@
 void generate_notsubscribed(const char *listdir, const char *subaddr,
 		const char *mlmmjsend)
 {
+	text *txt;
 	char *queuefilename, *fromaddr, *listname, *listfqdn, *listaddr;
 	char *listdelim = getlistdelim(listdir);
 
@@ -318,11 +326,15 @@
 	fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
 	myfree(listdelim);
 
-	queuefilename = prepstdreply(listdir,
+	txt = open_text(listdir,
 			"deny", "unsub", "unsubbed", NULL,
-			"unsub-notsubscribed", "$helpaddr$", subaddr, NULL,
-			0, NULL, NULL);
+			"unsub-notsubscribed");
+	MY_ASSERT(txt);
+	register_unformatted(txt, "subaddr", subaddr);
+	queuefilename = prepstdreply(txt, listdir,
+			"$helpaddr$", subaddr, NULL);
 	MY_ASSERT(queuefilename);
+	close_text(txt);
 
 	myfree(listaddr);
 	myfree(listname);
--- a/src/prepstdreply.c	Mon Jan 16 21:30:29 2012 +1100
+++ b/src/prepstdreply.c	Tue Jan 17 01:26:45 2012 +1100
@@ -59,8 +59,19 @@
 };
 
 
+struct substitution;
+typedef struct substitution substitution;
+struct substitution {
+	char *token;
+	char *subst;
+	substitution *next;
+};
+
+
 struct text {
 	source *src;
+	substitution *substs;
+	char *mailname;
 };
 
 
@@ -94,8 +105,7 @@
 
 
 static void substitute_one(char **line_p, char **pos_p, const char *listaddr,
-			const char *listdelim, size_t datacount, char **data,
-			const char *listdir)
+			const char *listdelim, const char *listdir, text *txt)
 {
 	char *line = *line_p;
 	char *pos = *pos_p;
@@ -103,7 +113,7 @@
 	char *endpos;
 	char *fqdn, *listname;
 	char *value = NULL;
-	size_t i;
+	substitution *subst;
 
 	endpos = strchr(token, '$');
 	if (endpos == NULL) {
@@ -171,12 +181,14 @@
 	} else if(strcmp(token, "originalmail") == 0) {
 		/* DEPRECATED: use %originalmail% instead */
 		value = mystrdup(" %originalmail 100%");
-	} else if(data) {
-		for(i = 0; i < datacount; i++) {
-			if(strcmp(token, data[i*2]) == 0) {
-				value = mystrdup(data[(i*2)+1]);
+	} else {
+		subst = txt->substs;
+		while (subst != NULL) {
+			if(strcmp(token, subst->token) == 0) {
+				value = mystrdup(subst->subst);
 				break;
 			}
+			subst = subst->next;
 		}
 	}
 
@@ -198,7 +210,7 @@
 
 
 char *substitute(const char *line, const char *listaddr, const char *listdelim,
-		 size_t datacount, char **data, const char *listdir)
+		const char *listdir, text *txt)
 {
 	char *new;
 	char *pos;
@@ -209,8 +221,7 @@
 	while (*pos != '\0') {
 		if (*pos == '$') {
 			substitute_one(&new, &pos,
-					listaddr, listdelim,
-					datacount, data, listdir);
+					listaddr, listdelim, listdir, txt);
 			/* The function sets up for the next character
 			 * to process, so continue straight away. */
 			continue;
@@ -235,6 +246,8 @@
 	txt->src->suffix = NULL;
 	txt->src->transparent = 0;
 	txt->src->limit = -1;
+	txt->substs = NULL;
+	txt->mailname = NULL;
 
 	tmp = concatstr(3, listdir, "/text/", filename);
 	txt->src->fd = open(tmp, O_RDONLY);
@@ -295,6 +308,22 @@
 }
 
 
+void register_unformatted(text *txt, const char *token, const char *replacement)
+{
+	substitution * subst = mymalloc(sizeof(substitution));
+	subst->token = mystrdup(token);
+	subst->subst = mystrdup(replacement);
+	subst->next = txt->substs;
+	txt->substs = subst;
+}
+
+
+void register_originalmail(text *txt, const char *mailname)
+{
+	txt->mailname = mystrdup(mailname);
+}
+
+
 static void begin_new_source_file(text *txt, char **line_p, char **pos_p,
 		const char *filename) {
 	char *line = *line_p;
@@ -339,7 +368,7 @@
 
 
 static void handle_directive(text *txt, char **line_p, char **pos_p,
-		const char *listdir, const char *mailname) {
+		const char *listdir) {
 	char *line = *line_p;
 	char *pos = *pos_p;
 	char *token = pos + 1;
@@ -397,7 +426,8 @@
 			myfree(filename);
 			return;
 		}
-	} else if(strncmp(token, "originalmail", 12) == 0 && mailname != NULL) {
+	} else if(strncmp(token, "originalmail", 12) == 0 &&
+			txt->mailname != NULL) {
 		token += 12;
 		limit = 0;
 		if (*token == '\0') {
@@ -410,7 +440,8 @@
 			if (token != NULL) limit = atol(token);
 		}
 		if (limit != 0) {
-			begin_new_source_file(txt, line_p, pos_p, mailname);
+			begin_new_source_file(txt, line_p, pos_p,
+					txt->mailname);
 			txt->src->transparent = 1;
 			if (limit == -1) txt->src->limit = -1;
 			else txt->src->limit = limit - 1;
@@ -436,8 +467,7 @@
 
 char *get_processed_text_line(text *txt,
 		const char *listaddr, const char *listdelim,
-		size_t datacount, char **data, const char *listdir,
-		const char *mailname)
+		const char *listdir)
 {
 	char *line = NULL;
 	char *pos;
@@ -493,13 +523,12 @@
 			 * transparently */
 		} else if (*pos == '$') {
 			substitute_one(&line, &pos,
-					listaddr, listdelim,
-					datacount, data, listdir);
+					listaddr, listdelim, listdir, txt);
 			/* The function sets up for the next character
 			 * to process, so continue straight away. */
 			continue;
 		} else if (*pos == '%') {
-			handle_directive(txt, &line, &pos, listdir, mailname);
+			handle_directive(txt, &line, &pos, listdir);
 			/* The function sets up for the next character
 			 * to process, so continue straight away. */
 			continue;
@@ -519,32 +548,35 @@
 
 void close_text(text *txt) {
 	source *tmp;
+	substitution *subst;
 	while (txt->src != NULL) {
 		close(txt->src->fd);
 		tmp = txt->src;
 		txt->src = txt->src->prev;
 		myfree(tmp);
 	}
+	while (txt->substs != NULL) {
+		subst = txt->substs;
+		myfree(subst->token);
+		myfree(subst->subst);
+		txt->substs = txt->substs->next;
+		myfree(subst);
+	}
+	if (txt->mailname != NULL) myfree(txt->mailname);
+	myfree(txt);
 }
 
 
-char *prepstdreply(const char *listdir, const char *purpose, const char *action,
-		   const char *reason, const char *type, const char *compat,
-		   const char *from, const char *to, const char *replyto,
-		   size_t tokencount, char **data, const char *mailname)
+char *prepstdreply(text *txt, const char *listdir,
+		   const char *from, const char *to, const char *replyto)
 {
 	size_t len, i;
 	int outfd;
-	text *txt;
 	char *listaddr, *listdelim, *tmp, *retstr = NULL;
 	char *listfqdn, *line;
 	char *str;
-	char **moredata;
 	char *headers[10] = { NULL }; /* relies on NULL to flag end */
 
-	txt = open_text(listdir, purpose, action, reason, type, compat);
-	if (txt == NULL) return NULL;
-
 	listaddr = getlistaddr(listdir);
 	listdelim = getlistdelim(listdir);
 	listfqdn = genlistfqdn(listaddr);
@@ -570,23 +602,19 @@
 		return NULL;
 	}
 
-	moredata = mymalloc(2*(tokencount+6) * sizeof(char *));
-	for (i=0; i<2*tokencount; i++) {
-		moredata[i] = data[i];
+	for (i=0; i<6; i++) { 
+		tmp = mystrdup("randomN");
+		tmp[6] = '0' + i;
+		str = random_str();
+		register_unformatted(txt, tmp, str);
+		myfree(tmp);
+		myfree(str);
 	}
-	for (i=0; i<6; i++) { 
-		moredata[2*(tokencount+i)] = mystrdup("randomN");
-		moredata[2*(tokencount+i)][6] = '0' + i;
-		moredata[2*(tokencount+i)+1] = random_str();
-	}
-	tokencount += 6;
 
-	tmp = substitute(from, listaddr, listdelim,
-	                 tokencount, moredata, listdir);
+	tmp = substitute(from, listaddr, listdelim, listdir, txt);
 	headers[0] = concatstr(2, "From: ", tmp);
 	myfree(tmp);
-	tmp = substitute(to, listaddr, listdelim,
-	                 tokencount, moredata, listdir);
+	tmp = substitute(to, listaddr, listdelim, listdir, txt);
 	headers[1] = concatstr(2, "To: ", tmp);
 	myfree(tmp);
 	headers[2] = genmsgid(listfqdn);
@@ -599,15 +627,14 @@
 	headers[7] = mystrdup("Content-Transfer-Encoding: 8bit");
 
 	if(replyto) {
-		tmp = substitute(replyto, listaddr, listdelim,
-		                 tokencount, moredata, listdir);
+		tmp = substitute(replyto, listaddr, listdelim, listdir, txt);
 		headers[8] = concatstr(2, "Reply-To: ", tmp);
 		myfree(tmp);
 	}
 
 	for(;;) {
 		line = get_processed_text_line(txt, listaddr, listdelim,
-				tokencount, moredata, listdir, NULL);
+				listdir);
 		if (!line) {
 			log_error(LOG_ARGS, "No body in listtext");
 			break;
@@ -700,7 +727,7 @@
 
 	if (line == NULL) {
 		line = get_processed_text_line(txt, listaddr, listdelim,
-				tokencount, moredata, listdir, mailname);
+				listdir);
 	}
 	while(line) {
 			len = strlen(line);
@@ -714,7 +741,7 @@
 			}
 		myfree(line);
 		line = get_processed_text_line(txt, listaddr, listdelim,
-				tokencount, moredata, listdir, mailname);
+				listdir);
 	}
 
 	fsync(outfd);
@@ -725,14 +752,5 @@
 	myfree(listdelim);
 	myfree(listfqdn);
 
-	for (i=tokencount-6; i<tokencount; i++) {
-		myfree(moredata[2*i]);
-		myfree(moredata[2*i+1]);
-	}
-	myfree(moredata);
-
-	close_text(txt);
-	myfree(txt);
-
 	return retstr;
 }
--- a/src/send_digest.c	Mon Jan 16 21:30:29 2012 +1100
+++ b/src/send_digest.c	Tue Jan 17 01:26:45 2012 +1100
@@ -183,10 +183,9 @@
 	int i, fd, archivefd, status, hdrfd;
 	size_t len;
 	text * txt;
-	char buf[45];
+	char buf[100];
 	char *tmp, *queuename = NULL, *archivename, *subject = NULL, *line = NULL;
 	char *boundary, *listaddr, *listdelim, *listname, *listfqdn;
-	char *subst_data[10];
 	pid_t childpid, pid;
 
 	if (addr) {
@@ -228,35 +227,29 @@
 	txt = open_text_file(listdir, "digest");
 	if (txt == NULL) {
 		log_error(LOG_ARGS, "Could not open listtext 'digest'");
+		goto fallback_subject;
 	}
 
-	subst_data[0] = "digestfirst";
 	snprintf(buf, sizeof(buf), "%d", firstindex);
-	subst_data[1] = mystrdup(buf);
+	register_unformatted(txt, "digestfirst", buf);
 
-	subst_data[2] = "digestlast";
 	snprintf(buf, sizeof(buf), "%d", lastindex);
-	subst_data[3] = mystrdup(buf);
+	register_unformatted(txt, "digestlast", buf);
 
-	subst_data[4] = "digestinterval";
 	if (lastindex == firstindex) {
 		snprintf(buf, sizeof(buf), "%d", firstindex);
 	} else {
 		snprintf(buf, sizeof(buf), "%d-%d", firstindex, lastindex);
 	}
-	subst_data[5] = mystrdup(buf);
+	register_unformatted(txt, "digestinterval", buf);
 
-	subst_data[6] = "digestissue";
 	snprintf(buf, sizeof(buf), "%d", issue);
-	subst_data[7] = mystrdup(buf);
+	register_unformatted(txt, "digestissue", buf);
 
-	subst_data[8] = "digestthreads";
-	subst_data[9] = thread_list(listdir, firstindex, lastindex);
+	tmp = thread_list(listdir, firstindex, lastindex);
+	register_unformatted(txt, "digestthreads", tmp);
 
-	if (txt == NULL) goto fallback_subject;
-
-	line = get_processed_text_line(txt, listaddr, listdelim,
-			5, subst_data, listdir, NULL);
+	line = get_processed_text_line(txt, listaddr, listdelim, listdir);
 
 	if (line == NULL) {
 		log_error(LOG_ARGS, "No content in digest listtext");
@@ -284,7 +277,7 @@
 
 		/* Skip the empty line after the subject */
 		line = get_processed_text_line(txt, listaddr, listdelim,
-				5, subst_data, listdir, NULL);
+				listdir);
 		if (line == NULL || *line != '\0') {
 			log_error(LOG_ARGS, "Too many headers "
 					"in digest listtext");
@@ -301,10 +294,15 @@
 
 fallback_subject:
 	if (subject == NULL) {
-		tmp = substitute("Digest of $listaddr$ issue $digestissue$"
-				" ($digestinterval$)", listaddr, listdelim,
-				5, subst_data, listdir);
-		subject = unistr_utf8_to_header(tmp);
+		if (lastindex == firstindex) {
+			snprintf(buf, sizeof(buf), "%d", firstindex);
+		} else {
+			snprintf(buf, sizeof(buf), "%d-%d", firstindex, lastindex);
+		}
+		tmp = mystrdup(buf);
+		snprintf(buf, sizeof(buf), "Digest of %s issue %d (%s)",
+				listaddr, issue, tmp);
+		subject = unistr_utf8_to_header(buf);
 		myfree(tmp);
 	}
 
@@ -342,11 +340,6 @@
 		myfree(listaddr);
 		myfree(listname);
 		myfree(listdelim);
-		myfree(subst_data[1]);
-		myfree(subst_data[3]);
-		myfree(subst_data[5]);
-		myfree(subst_data[7]);
-		myfree(subst_data[9]);
 		if (txt != NULL) {
 			close_text(txt);
 			myfree(line);
@@ -374,11 +367,6 @@
 			myfree(listaddr);
 			myfree(listname);
 			myfree(listdelim);
-			myfree(subst_data[1]);
-			myfree(subst_data[3]);
-			myfree(subst_data[5]);
-			myfree(subst_data[7]);
-			myfree(subst_data[9]);
 			if (txt != NULL) {
 				close_text(txt);
 				myfree(line);
@@ -389,7 +377,7 @@
 
 		for (;;) {
 			line = get_processed_text_line(txt, listaddr, listdelim,
-					5, subst_data, listdir, NULL);
+					listdir);
 			if (line == NULL) break;
 			len = strlen(line);
 			line[len] = '\n';
@@ -410,11 +398,6 @@
 	if (line != NULL) myfree(line);
 	myfree(listaddr);
 	myfree(listdelim);
-	myfree(subst_data[1]);
-	myfree(subst_data[3]);
-	myfree(subst_data[5]);
-	myfree(subst_data[7]);
-	myfree(subst_data[9]);
 
 	for (i=firstindex; i<=lastindex; i++) {
 		snprintf(buf, sizeof(buf), "%d", i);
--- a/src/send_help.c	Mon Jan 16 21:30:29 2012 +1100
+++ b/src/send_help.c	Tue Jan 17 01:26:45 2012 +1100
@@ -42,11 +42,10 @@
 #include "prepstdreply.h"
 #include "memory.h"
 
-void send_help(const char *listdir, const char *emailaddr,
-	       const char *mlmmjsend, const char *purpose, const char *action,
-	       const char *reason, const char *type, const char *compat)
+void send_help(const char *listdir, const char *queuefilename,
+		const char *emailaddr, const char *mlmmjsend)
 {
-	char *queuefilename, *listaddr, *listdelim, *listname, *listfqdn;
+	char *listaddr, *listdelim, *listname, *listfqdn;
 	char *fromaddr;
 
 	listaddr = getlistaddr(listdir);
@@ -55,23 +54,11 @@
 	listfqdn = genlistfqdn(listaddr);
 
 	fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
+
+	myfree(listname);
 	myfree(listdelim);
-
-	queuefilename = prepstdreply(listdir,
-			purpose, action, reason, type, compat,
-			"$listowner$", emailaddr, NULL, 0, NULL, NULL);
-	if(queuefilename == NULL) {
-		if (action == NULL) action = "";
-		if (reason == NULL) reason = "";
-		if (type == NULL) type = "";
-		log_error(LOG_ARGS, "Could not prepare %s-%s-%s-%s mail",
-				purpose, action, reason, type);
-		exit(EXIT_FAILURE);
-	}
-	
+	myfree(listfqdn);
 	myfree(listaddr);
-	myfree(listname);
-	myfree(listfqdn);
 
 	execlp(mlmmjsend, mlmmjsend,
 				"-l", "1",
--- a/src/send_list.c	Mon Jan 16 21:30:29 2012 +1100
+++ b/src/send_list.c	Tue Jan 17 01:26:45 2012 +1100
@@ -86,6 +86,7 @@
 void send_list(const char *listdir, const char *emailaddr,
 	       const char *mlmmjsend)
 {
+	text *txt;
 	char *queuefilename, *listaddr, *listdelim, *listname, *listfqdn;
 	char *fromaddr, *subdir, *nomaildir, *digestdir;
 	int fd;
@@ -98,14 +99,12 @@
 	fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
 	myfree(listdelim);
 
-	queuefilename = prepstdreply(listdir,
-			"list", NULL, NULL, subtype_strs[SUB_ALL],
-			"listsubs", "$listowner$", emailaddr, NULL,
-			0, NULL, NULL);
-	if(queuefilename == NULL) {
-		log_error(LOG_ARGS, "Could not prepare sub list mail");
-		exit(EXIT_FAILURE);
-	}
+	txt = open_text(listdir, "list", NULL, NULL, subtype_strs[SUB_ALL],
+			"listsubs");
+	MY_ASSERT(txt);
+	queuefilename = prepstdreply(txt, listdir, "$listowner$", emailaddr, NULL);
+	MY_ASSERT(queuefilename);
+	close_text(txt);
 
 	fd = open(queuefilename, O_WRONLY);
 	if(fd < 0) {
@@ -114,7 +113,7 @@
 	}
 
 	if(lseek(fd, 0, SEEK_END) < 0) {
-		log_error(LOG_ARGS, "Could not seek to send of file");
+		log_error(LOG_ARGS, "Could not seek to end of file");
 		exit(EXIT_FAILURE);
 	}