All of lore.kernel.org
 help / color / mirror / Atom feed
From: Steve Beattie <sbeattie@suse.de>
To: mlmmj@mlmmj.org
Subject: [RFC] misc moderation patches
Date: Thu, 05 Jul 2007 19:57:19 +0000	[thread overview]
Message-ID: <20070705195719.GK5523@suse.de> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 2350 bytes --]

Here are some patches mostly related to moderating emails for
discussion. I currently admin some lists with mailman, but would like
to move to mlmmj.

mlmmj-X-List-Administrivia_header.patch

	This patch adds two headers, an "X-List_administrivia: Yes" header
	for a few of the administrative messages that mlmmj sends out, and
	a header "X-mlmmj-mod-msg-id:" with the random string that is used
	as the argument for the 'moderate' command. The former is used
	similarly by mailman, and I filter based on it; I don't strictly
	need it if I have the latter header. The latter is really useful
	for writing scripts to moderate multiple messages at a time,
	rather than requiring them to parse out the Reply-To: header.

	If it's deemed worthwhile to keep the administrivia header,
	there's likely more locations that could use it, or it should
	just be added automatically in prepstdreply(). Another
	alternative would be to add these headers in the listtexts.

mlmmj-multiple_moderation_args.patch

	This patch adds the ability to moderate multiple messages by
	sending mlmmj a single message with multiple cookies addressed
	in the form

	  	listname+moderate-COOKIE[-COOKIE...]@domain.tld

	(This is one of my gripes with mailman, that in order to reject
	multiple spam messages by email, my script has to send a message
	for each message to reject, rather than just one message per
	list.) I left the moderation of subscriptions alone.

mlmmj-reject_command.patch

	This adds a 'reject' command to support rejecting messages for
	moderation, rather than accepting them as the 'moderate' command
	does. It supports rejecting multiple messages by taking messages
	in the form

		listname+reject-COOKIE[-COOKIE...]@domain.tld

	I didn't add support for rejecting subscriptions; that should
	probably be fixed.

mlmmj-add_moderator_command.patch

	This patch converts the From: address (currently
	"listname-moderators") in moderation messages to be a real address
	supported by mlmmj and adds the corresponding 'moderators'
	command. I'm not sure proper envelope filtering is done here,
	though.

As these patches touch similar areas of code, they are expected to be
applied in the order above.

Thanks.
-- 
Steve Beattie
SUSE Labs, Novell Inc. 
<sbeattie@suse.de>
http://NxNW.org/~steve/

[-- Attachment #1.2: mlmmj-X-List-Administrivia_header.patch --]
[-- Type: text/x-patch, Size: 2685 bytes --]

---
 src/mlmmj-process.c |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

Index: b/src/mlmmj-process.c
===================================================================
--- a/src/mlmmj-process.c
+++ b/src/mlmmj-process.c
@@ -79,6 +79,7 @@ void newmoderated(const char *listdir, c
 	int queuefd, moderatorsfd, mailfd;
 	size_t count = 0;
 	char *maildata[4] = { "moderateaddr", NULL, "moderators", NULL };
+	char *adminhdrs = "X-List-Administrivia: Yes";
 #if 0
 	printf("mailfilename = [%s], mailbasename = [%s]\n", mailfilename,
 			                                     mailbasename);
@@ -114,6 +115,7 @@ void newmoderated(const char *listdir, c
 
 	maildata[1] = replyto;
 	maildata[3] = moderators;
+	adminhdrs = concatstr(3, adminhdrs, "\nX-mlmmj-mod-msg-id: ", mailbasename);
 
 	from = concatstr(4, listname, listdelim, "owner@", listfqdn);
 	to = concatstr(3, listname, "-moderators@", listfqdn); /* FIXME JFA: Should this be converted? Why, why not? */
@@ -123,7 +125,7 @@ void newmoderated(const char *listdir, c
 	myfree(listfqdn);
 
 	queuefilename = prepstdreply(listdir, "moderation", "$listowner$",
-				     to, replyto, 2, maildata, NULL);
+				     to, replyto, 2, maildata, adminhdrs);
 
 	if((queuefd = open(queuefilename, O_WRONLY|O_APPEND)) < 0) {
 		log_error(LOG_ARGS, "Could not open '%s'", queuefilename);
@@ -347,6 +349,7 @@ int main(int argc, char **argv)
 	char *queuefilename, *recipextra = NULL, *owner = NULL;
 	char *maxmailsizestr;
 	char *maildata[4] = { "posteraddr", NULL, "maxmailsize", NULL };
+	char *adminhdr = "X-List-Administrivia: Yes";
 	char *envstr, *efrom;
 	struct stat st;
 	uid_t uid;
@@ -657,7 +660,7 @@ int main(int argc, char **argv)
 			queuefilename = prepstdreply(listdir,
 					"maxmailsize", "$listowner$",
 					fromemails.emaillist[0],
-					NULL, 2, maildata, NULL);
+					NULL, 2, maildata, adminhdr);
 			MY_ASSERT(queuefilename)
 			myfree(listdelim);
 			myfree(listname);
@@ -768,7 +771,7 @@ int main(int argc, char **argv)
 				     listfqdn);
 		queuefilename = prepstdreply(listdir, "notintocc",
 					"$listowner$", fromemails.emaillist[0],
-					     NULL, 0, NULL, NULL);
+					     NULL, 0, NULL, adminhdr);
 		MY_ASSERT(queuefilename)
 		myfree(listdelim);
 		myfree(listname);
@@ -829,7 +832,7 @@ int main(int argc, char **argv)
 					"bounces-help@", listfqdn);
 			queuefilename = prepstdreply(listdir, "subonlypost",
 					"$listowner$", fromemails.emaillist[0],
-						     NULL, 1, maildata, NULL);
+						     NULL, 1, maildata, adminhdr);
 			MY_ASSERT(queuefilename)
 			myfree(listaddr);
 			myfree(listdelim);

[-- Attachment #1.3: mlmmj-multiple_moderation_args.patch --]
[-- Type: text/x-patch, Size: 4651 bytes --]


(Note: some mail clients like mutt have hard coded limits on the length
of a To: address; e.g. mutt has a limit of 256 characters which it will
truncate if the address is longer than that.)
---
 src/listcontrol.c |   95 +++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 69 insertions(+), 26 deletions(-)

Index: b/src/listcontrol.c
===================================================================
--- a/src/listcontrol.c
+++ b/src/listcontrol.c
@@ -98,6 +98,34 @@ static struct ctrl_command ctrl_commands
 	{ "list",               0 }
 };
 
+struct strlist *splitparam(const char *param, const char split)
+{
+	char *c;
+	struct strlist *params = mymalloc(sizeof(struct strlist));
+	size_t len;
+
+	params->count = 0;
+	params->strs = NULL;
+
+	if (!param)
+		return params;
+
+	while (*param && (c = strchr(param, split)) != NULL) {
+		len = c - param;
+		params->strs = myrealloc(params->strs, sizeof(c) * (params->count + 1));
+		params->strs[params->count] = mymalloc(len + 1);
+		strncpy(params->strs[params->count], param, len);
+		params->strs[params->count++][len] = '\0';
+		param = c + 1;
+	}
+
+	/* handle last param */
+	if (*param) {
+		params->strs = myrealloc(params->strs, sizeof(c) * (params->count + 1));
+		params->strs[params->count++] = mystrdup(param);
+	}
+	return params;
+}
 
 int listcontrol(struct email_container *fromemails, const char *listdir,
 		const char *controlstr, const char *mlmmjsub,
@@ -114,7 +142,9 @@ int listcontrol(struct email_container *
 	size_t cmdlen;
 	unsigned int ctrl;
 	struct strlist *owners;
-	int owner_idx;
+	struct strlist *params;
+	int owner_idx, rc;
+	pid_t childpid;
 	
 	/* A closed list doesn't allow subscribtion and unsubscription */
 	closedlist = statctrl(listdir, "closedlist");
@@ -588,13 +618,13 @@ int listcontrol(struct email_container *
 		exit(EXIT_FAILURE);
 		break;
 
-	/* listname+moderate-COOKIE@domain.tld */
+	/* listname+moderate-COOKIE[-COOKIE...]@domain.tld */
 	case CTRL_MODERATE:
 		/* TODO Add accept/reject parameter to moderate */
-		moderatefilename = concatstr(3, listdir, "/moderation/", param);
 
 		/* Subscriber moderation */
 		if(strncmp(param, "subscribe", 9) == 0) {
+			moderatefilename = concatstr(3, listdir, "/moderation/", param);
 			log_oper(listdir, OPLOGFNAME, "%s moderated %s",
 				fromemails->emaillist[0], moderatefilename);
 			execlp(mlmmjsub, mlmmjsub,
@@ -603,32 +633,45 @@ int listcontrol(struct email_container *
 					"-c", (char *)NULL);
 		}
 
-		sendfilename = concatstr(2, moderatefilename, ".sending");
+		rc = EXIT_SUCCESS;
+		params = splitparam(param, '-');
+		for (i = 0; i < params->count; i++) {
+			moderatefilename = concatstr(3, listdir, "/moderation/", params->strs[i]);
+
+			sendfilename = concatstr(2, moderatefilename, ".sending");
+
+			if (stat(moderatefilename, &stbuf) < 0) {
+				myfree(moderatefilename);
+				/* no mail to moderate */
+				errno = 0;
+				log_error(LOG_ARGS, "A moderate request was"
+					" sent with a mismatching cookie."
+					" Ignoring mail");
+				continue;
+			}
+			/* Rename it to avoid mail being sent twice */
+			if (rename(moderatefilename, sendfilename) < 0) {
+				log_error(LOG_ARGS, "Could not rename to .sending");
+				rc = EXIT_FAILURE;
+			}
 
-		if(stat(moderatefilename, &stbuf) < 0) {
+			log_oper(listdir, OPLOGFNAME, "%s moderated %s",
+				fromemails->emaillist[0], moderatefilename);
 			myfree(moderatefilename);
-			/* no mail to moderate */
-			errno = 0;
-			log_error(LOG_ARGS, "A moderate request was"
-				" sent with a mismatching cookie."
-				" Ignoring mail");
-			return -1;
-		}
-		/* Rename it to avoid mail being sent twice */
-		if(rename(moderatefilename, sendfilename) < 0) {
-			log_error(LOG_ARGS, "Could not rename to .sending");
-			exit(EXIT_FAILURE);
-		}
+			childpid = fork();
+			if (childpid < 0)
+				log_error(LOG_ARGS, "fork() failed!  Proceeding anyway");
 
-		log_oper(listdir, OPLOGFNAME, "%s moderated %s",
-				fromemails->emaillist[0], moderatefilename);
-		myfree(moderatefilename);
-		execlp(mlmmjsend, mlmmjsend,
-				"-L", listdir,
-				"-m", sendfilename, (char *)NULL);
-		log_error(LOG_ARGS, "execlp() of '%s' failed",
-					mlmmjsend);
-		exit(EXIT_FAILURE);
+			if (!childpid) {
+				execlp(mlmmjsend, mlmmjsend,
+					"-L", listdir,
+					"-m", sendfilename, (char *)NULL);
+				log_error(LOG_ARGS, "execlp() of '%s' failed",
+						mlmmjsend);
+				exit(EXIT_FAILURE);
+			}
+		}
+		exit(rc);
 		break;
 
 	/* listname+help@domain.tld */

[-- Attachment #1.4: mlmmj-reject_command.patch --]
[-- Type: text/x-patch, Size: 1915 bytes --]

---
 src/listcontrol.c |   26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

Index: b/src/listcontrol.c
===================================================================
--- a/src/listcontrol.c
+++ b/src/listcontrol.c
@@ -62,6 +62,7 @@ enum ctrl_e {
 	CTRL_CONFUNSUB,
 	CTRL_BOUNCES,
 	CTRL_MODERATE,
+	CTRL_REJECT,
 	CTRL_HELP,
 	CTRL_FAQ,
 	CTRL_GET,
@@ -92,6 +93,7 @@ static struct ctrl_command ctrl_commands
 	{ "confunsub",          1 },
 	{ "bounces",            1 },
 	{ "moderate",           1 },
+	{ "reject",             1 },
 	{ "help",               0 },
 	{ "faq",                0 },
 	{ "get",                1 },
@@ -620,8 +622,6 @@ int listcontrol(struct email_container *
 
 	/* listname+moderate-COOKIE[-COOKIE...]@domain.tld */
 	case CTRL_MODERATE:
-		/* TODO Add accept/reject parameter to moderate */
-
 		/* Subscriber moderation */
 		if(strncmp(param, "subscribe", 9) == 0) {
 			moderatefilename = concatstr(3, listdir, "/moderation/", param);
@@ -674,6 +674,28 @@ int listcontrol(struct email_container *
 		exit(rc);
 		break;
 
+	/* listname+reject-COOKIE[-COOKIE...]@domain.tld */
+	case CTRL_REJECT:
+		params = splitparam(param, '-');
+		for (i = 0; i < params->count; i++) {
+			moderatefilename = concatstr(3, listdir, "/moderation/", params->strs[i]);
+
+			if (stat(moderatefilename, &stbuf) < 0) {
+				/* no mail to moderate */
+				errno = 0;
+				log_error(LOG_ARGS, "A reject request was"
+					" sent with a mismatching cookie."
+					" Ignoring mail");
+			} else {
+				unlink(moderatefilename);
+				log_oper(listdir, OPLOGFNAME, "%s rejected %s",
+					fromemails->emaillist[0], moderatefilename);
+			}
+			myfree(moderatefilename);
+		}
+		exit(EXIT_SUCCESS);
+		break;
+
 	/* listname+help@domain.tld */
 	case CTRL_HELP:
 		if(!strchr(fromemails->emaillist[0], '@')) {

[-- Attachment #1.5: mlmmj-add_moderator_command.patch --]
[-- Type: text/x-patch, Size: 3779 bytes --]

---
 src/listcontrol.c   |   29 +++++++++++++++++++++++++++--
 src/mlmmj-process.c |    2 +-
 src/mlmmj-sub.c     |    2 +-
 3 files changed, 29 insertions(+), 4 deletions(-)

Index: b/src/mlmmj-sub.c
===================================================================
--- a/src/mlmmj-sub.c
+++ b/src/mlmmj-sub.c
@@ -131,7 +131,7 @@ void moderate_sub(const char *listdir, c
 	modfilebase = mybasename(modfilename);
 
 	from = concatstr(4, listname, listdelim, "owner@", listfqdn);
-	to = concatstr(3, listname, "-moderators@", listfqdn);
+	to = concatstr(4, listname, listdelim, "moderators@", listfqdn);
 	replyto = concatstr(6, listname, listdelim, "moderate-", modfilebase,
 			"@", listfqdn);
 	myfree(modfilebase);
Index: b/src/mlmmj-process.c
===================================================================
--- a/src/mlmmj-process.c
+++ b/src/mlmmj-process.c
@@ -118,7 +118,7 @@ void newmoderated(const char *listdir, c
 	adminhdrs = concatstr(3, adminhdrs, "\nX-mlmmj-mod-msg-id: ", mailbasename);
 
 	from = concatstr(4, listname, listdelim, "owner@", listfqdn);
-	to = concatstr(3, listname, "-moderators@", listfqdn); /* FIXME JFA: Should this be converted? Why, why not? */
+	to = concatstr(4, listname, listdelim, "moderators@", listfqdn); /* FIXME JFA: Should this be converted? Why, why not? */
 
 	myfree(listdelim);
 	myfree(listname);
Index: b/src/listcontrol.c
===================================================================
--- a/src/listcontrol.c
+++ b/src/listcontrol.c
@@ -35,6 +35,7 @@
 #include "listcontrol.h"
 #include "find_email_adr.h"
 #include "getlistdelim.h"
+#include "getlistaddr.h"
 #include "strgen.h"
 #include "send_help.h"
 #include "send_list.h"
@@ -62,6 +63,7 @@ enum ctrl_e {
 	CTRL_CONFUNSUB,
 	CTRL_BOUNCES,
 	CTRL_MODERATE,
+	CTRL_MODERATORS,
 	CTRL_REJECT,
 	CTRL_HELP,
 	CTRL_FAQ,
@@ -93,6 +95,7 @@ static struct ctrl_command ctrl_commands
 	{ "confunsub",          1 },
 	{ "bounces",            1 },
 	{ "moderate",           1 },
+	{ "moderators",         0 },
 	{ "reject",             1 },
 	{ "help",               0 },
 	{ "faq",                0 },
@@ -137,6 +140,7 @@ int listcontrol(struct email_container *
 	char *bouncenr, *tmpstr;
 	char *param = NULL, *conffilename, *moderatefilename;
 	char *c, *archivefilename, *sendfilename;
+	char *listfqdn, *listname, *listaddr = getlistaddr(listdir), *listdelim;
 	const char *subswitch;
 	struct stat stbuf;
 	int closedlist, nosubconfirm, tmpfd, noget, i, closedlistsub,
@@ -216,8 +220,9 @@ int listcontrol(struct email_container *
 		return -1;
 	}
 
-	/* We only need the control mail when bouncing, to save bounced msg */
-	if(ctrl != CTRL_BOUNCES)
+	/* We only need the control mail when bouncing, to save
+	   bounced msg, and when sending to moderators */
+	if(ctrl != CTRL_BOUNCES && ctrl != CTRL_MODERATORS)
 		unlink(mailname);
 
 	switch (ctrl) {
@@ -696,6 +701,26 @@ int listcontrol(struct email_container *
 		exit(EXIT_SUCCESS);
 		break;
 
+	/* listname+moderators@domain.tld */
+	case CTRL_MODERATORS:
+		listfqdn = genlistfqdn(listaddr);
+		listname = genlistname(listaddr);
+		listdelim = getlistdelim(listdir);
+		tmpstr = concatstr(4, listname, listdelim, "owner@", listfqdn);
+		log_oper(listdir, OPLOGFNAME, "mlmmj-recieve: sending"
+				" mail from %s to moderators",
+				fromemails->emaillist[0]);
+		execlp(mlmmjsend, mlmmjsend,
+				"-l", "2",
+				"-L", listdir,
+				"-m", mailname,
+				"-F", tmpstr,
+				"-a", (char *)NULL);
+		log_error(LOG_ARGS, "execlp() of '%s' failed",
+					mlmmjsend);
+		exit(EXIT_FAILURE);
+		break;
+
 	/* listname+help@domain.tld */
 	case CTRL_HELP:
 		if(!strchr(fromemails->emaillist[0], '@')) {

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

             reply	other threads:[~2007-07-05 19:57 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-07-05 19:57 Steve Beattie [this message]
2007-07-05 21:13 ` [RFC] misc moderation patches Morten K. Poulsen
2007-07-09 21:11 ` Steve Beattie
2007-07-11 17:28 ` Morten K. Poulsen
2007-11-11 20:29 ` Morten K. Poulsen
2007-11-12 10:00 ` Alexander Kardailsky
2007-11-12 20:11 ` Morten K. Poulsen
2007-11-12 20:34 ` Alexander Kardailsky
2007-11-12 20:40 ` Steve Beattie
2007-11-12 20:48 ` Morten K. Poulsen
2007-11-12 21:41 ` Morten K. Poulsen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070705195719.GK5523@suse.de \
    --to=sbeattie@suse.de \
    --cc=mlmmj@mlmmj.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.