# HG changeset patch # User Ben Schmidt # Date 1463922972 -36000 # Node ID 16df1cc898d020499922ea580a94760193d9b1b1 # Parent a5b51bf2aed919d5669ce3f7f80c80af7a69c134 Implement modonlypost. diff -r a5b51bf2aed9 -r 16df1cc898d0 .hgsubstate --- 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 diff -r a5b51bf2aed9 -r 16df1cc898d0 ChangeLog --- 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) diff -r a5b51bf2aed9 -r 16df1cc898d0 README.listtexts --- 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$ diff -r a5b51bf2aed9 -r 16df1cc898d0 TUNABLES --- 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) diff -r a5b51bf2aed9 -r 16df1cc898d0 contrib/web/perl-admin/conf/tunables.pl --- 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 ". diff -r a5b51bf2aed9 -r 16df1cc898d0 contrib/web/php-admin/conf/tunables.pl --- 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 ". diff -r a5b51bf2aed9 -r 16df1cc898d0 src/mlmmj-process.c --- 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);