changeset 907:16df1cc898d0

Implement modonlypost.
author Ben Schmidt
date Sun, 22 May 2016 23:16:12 +1000
parents a5b51bf2aed9
children 72c345b0aa91
files .hgsubstate ChangeLog README.listtexts TUNABLES contrib/web/perl-admin/conf/tunables.pl contrib/web/php-admin/conf/tunables.pl src/mlmmj-process.c
diffstat 7 files changed, 173 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsubstate	Tue May 26 08:23:11 2015 +1000
+++ b/.hgsubstate	Sun May 22 23:16:12 2016 +1000
@@ -1,1 +1,1 @@
-904ef617130887762690c5d42d48cd9bee80115b listtexts
+c2e607ef2791003f1da201d2d1b33bb159a36069 listtexts
--- a/ChangeLog	Tue May 26 08:23:11 2015 +1000
+++ b/ChangeLog	Sun May 22 23:16:12 2016 +1000
@@ -1,3 +1,4 @@
+ o Implement modonlypost
 1.2.19.0
  o Add README.footers and footer-related resources
  o Support ESMTP so OpenSMTPD uses 8 bits (Paul Fariello)
--- a/README.listtexts	Tue May 26 08:23:11 2015 +1000
+++ b/README.listtexts	Sun May 22 23:16:12 2016 +1000
@@ -90,6 +90,7 @@
 - deny-sub-obstruct *
 - deny-unsub-unsubbed-{normal|digest|nomail|all} (unsub-notsubscribed)
 - deny-post-subonlypost (subonlypost)
+- deny-post-modonlypost
 - deny-post-access (access)
 - deny-post-maxmailsize (maxmailsize)
 - deny-post-tocc (notintocc)
@@ -352,7 +353,7 @@
 - %originalmail%
 - %originalmail N%
   (available only in moderate-post-*, wait-post-* and
-  deny-post-{access|maxmailsize|tocc|subonlypost})
+  deny-post-{access|maxmailsize|tocc|subonlypost|modonlypost})
   the email message being processed (usually a mail being moderated); N
   represents a number, which is how many lines of the message (including
   headers) to include: if omitted, the whole message will be included
@@ -537,8 +538,8 @@
   the address to which to send mail to permit the subscription in question
 
 - $posteraddr$
-  (available only in deny-post-{access|tocc|subonlypost|maxmailsize},
-  moderate-post-* and wait-post-*)
+  (available only in deny-post-{access|tocc|subonlypost|modonlypost|
+  maxmailsize}, moderate-post-* and wait-post-*)
   the from address of the message that was received as determined by Mlmmj
 
 - $random0$
@@ -561,8 +562,8 @@
   the address requested to be (un-)subscribed
 
 - $subject$
-  (available only in deny-post-{access|tocc|subonlypost|maxmailsize},
-  moderate-post-* and wait-post-*)
+  (available only in deny-post-{access|tocc|subonlypost|modonlypost|
+  maxmailsize}, moderate-post-* and wait-post-*)
   the subject line of the message in question
 
 - $text T$
--- a/TUNABLES	Tue May 26 08:23:11 2015 +1000
+++ b/TUNABLES	Sun May 22 23:16:12 2016 +1000
@@ -45,10 +45,15 @@
    When this file is present, only people who are subscribed to the list,
    are allowed to post to it. The check is made against the "From:" header.
 
+ · modonlypost			(boolean)
+
+   When this file is present, only people listed in listdir/control/moderators
+   are allowed to post to it. The check is made against the "From:" header.
+
  · modnonsubposts		(boolean)
 
-   When this file is present, all postings from people who are not subscribed
-   to the list will be moderated.
+   When this file is present, all postings from people who are not allowed
+   to post to the list will be moderated instead of denied.
 
  · modreqlife			(normal)
 
@@ -171,11 +176,12 @@
  · notoccdenymails		(boolean)
  · noaccessdenymails		(boolean)
  · nosubonlydenymails		(boolean)
+ · nomodonlydenymails		(boolean)
 
    These switches turns off whether mlmmj sends out notification about postings
    being denied due to the listaddress not being in To: or Cc: (see 'tocc'),
    when it was rejected due to an access rule (see 'access') or whether it's a
-   subscribers only posting list (see 'subonlypost').
+   subscribers/moderators only posting list (see 'subonlypost/modonlypost').
 
  · nosubmodmails		(boolean)
 
--- a/contrib/web/perl-admin/conf/tunables.pl	Tue May 26 08:23:11 2015 +1000
+++ b/contrib/web/perl-admin/conf/tunables.pl	Sun May 22 23:16:12 2016 +1000
@@ -43,10 +43,20 @@
 			  "If this option is set, only people who are subscribed to the list, are allowed to post to it. ".
 			  "The check is made against the \"From:\" header.");
 
+mlmmj_boolean("modonlypost",
+			  "Moderators only post",
+			  "When this file is present, only people listed in listdir/control/moderators ".
+			  "are allowed to post to it. The check is made against the "From:" header.");
+
 mlmmj_boolean("modnonsubposts",
-			  "Moderate non-subscriber posts",
-			  "If this option is set and subonlypost is enabled, all postings from ".
-			  "people who are not subscribed to the list will be moderated.");
+			  "Moderate non-allowed posts",
+			  "If this option is set, postings from people who are not allowed to post ".
+			  "to the list will be moderated instead of denied.");
+
+mlmmj_string("modreqlife",
+			 "Moderation request lifetime",
+			 "This specifies how long in seconds a mail awaits moderation before it's ".
+			 "discarded. Defaults to 604800 seconds, which is 7 days.");
 
 mlmmj_string("prefix",
 			 "Prefix",
@@ -120,8 +130,8 @@
 
 mlmmj_string("bouncelife",
 			 "Bouncing lifetime",
-			 "Here is specified for how long time in seconds an address can bounce before it's unsubscribed. Defaults ".
-			 "to 432000 seconds, which is 5 days.");
+			 "This specifies how long in seconds an address can bounce before it's ".
+			 "unsubscribed. Defaults to 432000 seconds, which is 5 days.");
 
 mlmmj_boolean("noarchive",
 			  "No archive",
@@ -161,6 +171,11 @@
 			  "This switch turns off whether mlmmj sends out notification about postings ".
 			  "being rejected due to a subscribers only posting list (see 'subonlypost').");
 
+mlmmj_boolean("nomodonlydenymails",
+			  "No moderators only deny mails",
+			  "This switch turns off whether mlmmj sends out notification about postings ".
+			  "being rejected due to a moderators only posting list (see 'modonlypost').");
+
 mlmmj_boolean("nosubmodmails",
 			  "No subscription moderated mails",
 			  "This switch turns off whether mlmmj sends out notification about ".
--- a/contrib/web/php-admin/conf/tunables.pl	Tue May 26 08:23:11 2015 +1000
+++ b/contrib/web/php-admin/conf/tunables.pl	Sun May 22 23:16:12 2016 +1000
@@ -43,10 +43,20 @@
 			  "If this option is set, only people who are subscribed to the list, are allowed to post to it. ".
 			  "The check is made against the \"From:\" header.");
 
+mlmmj_boolean("modonlypost",
+			  "Moderators only post",
+			  "When this file is present, only people listed in listdir/control/moderators ".
+			  "are allowed to post to it. The check is made against the "From:" header.");
+
 mlmmj_boolean("modnonsubposts",
-			  "Moderate non-subscriber posts",
-			  "If this option is set and subonlypost is enabled, all postings from ".
-			  "people who are not subscribed to the list will be moderated.");
+			  "Moderate non-allowed posts",
+			  "If this option is set, postings from people who are not allowed to post ".
+			  "to the list will be moderated instead of denied.");
+
+mlmmj_string("modreqlife",
+			 "Moderation request lifetime",
+			 "This specifies how long in seconds a mail awaits moderation before it's ".
+			 "discarded. Defaults to 604800 seconds, which is 7 days.");
 
 mlmmj_string("prefix",
 			 "Prefix",
@@ -120,8 +130,8 @@
 
 mlmmj_string("bouncelife",
 			 "Bouncing lifetime",
-			 "Here is specified for how long time in seconds an address can bounce before it's unsubscribed. Defaults ".
-			 "to 432000 seconds, which is 5 days.");
+			 "This specifies how long in seconds an address can bounce before it's ".
+			 "unsubscribed. Defaults to 432000 seconds, which is 5 days.");
 
 mlmmj_boolean("noarchive",
 			  "No archive",
@@ -161,6 +171,11 @@
 			  "This switch turns off whether mlmmj sends out notification about postings ".
 			  "being rejected due to a subscribers only posting list (see 'subonlypost').");
 
+mlmmj_boolean("nomodonlydenymails",
+			  "No moderators only deny mails",
+			  "This switch turns off whether mlmmj sends out notification about postings ".
+			  "being rejected due to a moderators only posting list (see 'modonlypost').");
+
 mlmmj_boolean("nosubmodmails",
 			  "No subscription moderated mails",
 			  "This switch turns off whether mlmmj sends out notification about ".
--- a/src/mlmmj-process.c	Tue May 26 08:23:11 2015 +1000
+++ b/src/mlmmj-process.c	Sun May 22 23:16:12 2016 +1000
@@ -53,6 +53,7 @@
 #include "memory.h"
 #include "log_oper.h"
 #include "unistr.h"
+#include "chomp.h"
 
 enum action {
 	ALLOW,
@@ -74,6 +75,7 @@
 
 enum modreason {
 	MODNONSUBPOSTS,
+	MODNONMODPOSTS,
 	ACCESS,
 	MODERATED
 };
@@ -81,30 +83,16 @@
 
 static char *modreason_strs[] = {
 	"modnonsubposts",
+	"modnonmodposts",
 	"access",
 	"moderated"
 };
 
 
-static void newmoderated(const char *listdir, const char *mailfilename,
-		  const char *mlmmjsend, const char *efromsender,
-		  const char *subject, const char *posteraddr,
-		  enum modreason modreason)
-{
-	char *from, *listfqdn, *listname, *moderators = NULL;
-	char *buf, *replyto, *listaddr = getlistaddr(listdir), *listdelim;
-	text *txt;
-	memory_lines_state *mls;
-	char *queuefilename = NULL, *moderatorsfilename, *efromismod = NULL;
-	char *mailbasename = mybasename(mailfilename), *tmp, *to, *reject;
-	int moderatorsfd, foundaddr = 0, notifymod = 0, status;
-	pid_t childpid, pid;
-#if 0
-	printf("mailfilename = [%s], mailbasename = [%s]\n", mailfilename,
-			                                     mailbasename);
-#endif
-	listfqdn = genlistfqdn(listaddr);
-	listname = genlistname(listaddr);
+static int is_moderator(const char *listdir, const char *address,
+		char **moderators) {
+	char *buf, *tmp, *moderatorsfilename;
+	int moderatorsfd, foundaddr = 0;
 
 	moderatorsfilename = concatstr(2, listdir, "/control/moderators");
 	if((moderatorsfd = open(moderatorsfilename, O_RDONLY)) < 0) {
@@ -114,27 +102,59 @@
 	}
 	myfree(moderatorsfilename);
 
-	if(statctrl(listdir, "ifmodsendonlymodmoderate"))
-		efromismod = concatstr(2, efromsender, "\n");
-
 	while((buf = mygetline(moderatorsfd))) {
-		if(efromismod && strcmp(buf, efromismod) == 0)
+		chomp(buf);
+		if(address && strcasecmp(buf, address) == 0) {
 			foundaddr = 1;
-		tmp = moderators;
-		moderators = concatstr(2, moderators, buf);
+			if (!moderators) {
+				close(moderatorsfd);
 		myfree(buf);
+				return foundaddr;
+			}
+		}
+		if (moderators) {
+			tmp = *moderators;
+			*moderators = concatstr(3, *moderators, buf, "\n");
 		myfree(tmp);
 	}
+		myfree(buf);
+	}
 
-	if(!foundaddr) {
-		myfree(efromismod);
+	close(moderatorsfd);
+	return foundaddr;
+}
+
+
+static void newmoderated(const char *listdir, const char *mailfilename,
+		  const char *mlmmjsend, const char *efromsender,
+		  const char *subject, const char *posteraddr,
+		  enum modreason modreason)
+{
+	char *from, *listfqdn, *listname, *moderators = NULL;
+	char *replyto, *listaddr = getlistaddr(listdir), *listdelim;
+	text *txt;
+	memory_lines_state *mls;
+	char *queuefilename = NULL;
+	const char *efromismod = NULL;
+	char *mailbasename = mybasename(mailfilename), *to, *reject;
+	int notifymod = 0, status;
+	pid_t childpid, pid;
+#if 0
+	printf("mailfilename = [%s], mailbasename = [%s]\n", mailfilename,
+			                                     mailbasename);
+#endif
+	listfqdn = genlistfqdn(listaddr);
+	listname = genlistname(listaddr);
+
+	if(statctrl(listdir, "ifmodsendonlymodmoderate"))
+		efromismod = efromsender;
+
+	if(!is_moderator(listdir, efromismod, &moderators))
 		efromismod = NULL;
-	}
 
 	if(efromismod) mls = init_memory_lines(efromismod);
 	else mls = init_memory_lines(moderators);
 
-	close(moderatorsfd);
 	myfree(moderators);
 
 	listdelim = getlistdelim(listdir);
@@ -421,6 +441,7 @@
 	int addrtocc = 1, intocc = 0;
 	int maxmailsize = 0;
 	int notmetoo = 0;
+	int subonlypost = 0, modonlypost = 0, modnonsubposts = 0, foundaddr = 0;
 	char *listdir = NULL, *mailfile = NULL, *headerfilename = NULL;
 	char *footerfilename = NULL, *donemailname = NULL;
 	char *randomstr = NULL, *mqueuename, *omitfilename;
@@ -972,29 +993,45 @@
 		}
 	}
 
-	if(!send && (statctrl(listdir, "subonlypost") ||
-			statctrl(listdir, "modnonsubposts"))) {
+	subonlypost = statctrl(listdir, "subonlypost");
+	modonlypost = statctrl(listdir, "modonlypost");
+	modnonsubposts = statctrl(listdir, "modnonsubposts");
+	/* modnonsubposts implies subonlypost if modonlypost is not set */
+	if (modnonsubposts && !modonlypost) subonlypost = 1;
+
+	if(!send && (subonlypost || modonlypost || modnonsubposts)) {
 		/* Don't send a mail about denial to the list, but silently
 		 * discard and exit. */
 		if (strcasecmp(listaddr, posteraddr) == 0) {
 			log_error(LOG_ARGS, "Discarding %s because"
-					" subonlypost was set and From: was"
-					" the list address",
+					" there are sender restrictions but"
+					" From: was the list address",
 					mailfile);
 			myfree(listaddr);
 			unlink(donemailname);
 			myfree(donemailname);
 			exit(EXIT_SUCCESS);
 		}
-		if(is_subbed(listdir, posteraddr, 0) == SUB_NONE) {
-			if(statctrl(listdir, "modnonsubposts")) {
+		if(subonlypost) {
+			foundaddr = (is_subbed(listdir, posteraddr, 0) !=
+					SUB_NONE);
+		} else if (modonlypost) {
+			foundaddr = is_moderator(listdir, posteraddr, NULL);
+		}
+		if(!foundaddr) {
+			if(modnonsubposts) {
 				moderated = 1;
+			    if (subonlypost)
 				modreason = MODNONSUBPOSTS;
+			    else if (modonlypost)
+				modreason = MODNONMODPOSTS;
 			} else {
-				if(statctrl(listdir, "nosubonlydenymails")) {
+			    if((subonlypost &&
+				    statctrl(listdir, "nosubonlydenymails")) ||
+				    (modonlypost &&
+				    statctrl(listdir, "nomodonlydenymails"))) {
 				    log_error(LOG_ARGS, "Discarding %s because"
-					    " subonlypost and"
-					    " nosubonlydenymails was set",
+					" no{sub|mod}onlydenymails was set",
 					    mailfile);
 				    myfree(listaddr);
 				    unlink(donemailname);
@@ -1006,8 +1043,13 @@
 				listfqdn = genlistfqdn(listaddr);
 				fromaddr = concatstr(4, listname, listdelim,
 					"bounces-help@", listfqdn);
+			    if (subonlypost) {
 				txt = open_text(listdir, "deny", "post",
 					"subonlypost", NULL, "subonlypost");
+			    } else if (modonlypost) {
+				txt = open_text(listdir, "deny", "post",
+					"modonlypost", NULL, NULL);
+			    }
 				MY_ASSERT(txt);
 				register_unformatted(txt, "subject", subject);
 				register_unformatted(txt, "posteraddr", posteraddr);