From: Ben Schmidt Date: Sun, 22 May 2016 13:16:12 +0000 (+1000) Subject: Implement modonlypost. X-Git-Tag: RELEASE_1_3_0a1~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb0b47028289da7ddf1aae71cf049d95eb15dbd5;p=thirdparty%2Fmlmmj.git Implement modonlypost. --- diff --git a/ChangeLog b/ChangeLog index cd7e91f3..390fdab3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 --git a/README.listtexts b/README.listtexts index 9e8a78d1..b2e75c54 100644 --- a/README.listtexts +++ b/README.listtexts @@ -90,6 +90,7 @@ is given in brackets. Those with asterisks (*) are not yet used. - 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 @@ appropriate for use in headers. They are: - %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 @@ Unformatted substitutions that are available are: 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 @@ Unformatted substitutions that are available are: 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 --git a/TUNABLES b/TUNABLES index 749ff702..a9b05cf8 100644 --- a/TUNABLES +++ b/TUNABLES @@ -45,10 +45,15 @@ entire content is used as value, it's marked "text". 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 @@ entire content is used as value, it's marked "text". · 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 --git a/contrib/web/perl-admin/conf/tunables.pl b/contrib/web/perl-admin/conf/tunables.pl index d72a055e..77cf2fe1 100644 --- a/contrib/web/perl-admin/conf/tunables.pl +++ b/contrib/web/perl-admin/conf/tunables.pl @@ -43,10 +43,20 @@ mlmmj_boolean("subonlypost", "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("digestmaxmails", 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 @@ mlmmj_boolean("nosubonlydenymails", "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 --git a/contrib/web/php-admin/conf/tunables.pl b/contrib/web/php-admin/conf/tunables.pl index f4592d25..dcb0ba38 100644 --- a/contrib/web/php-admin/conf/tunables.pl +++ b/contrib/web/php-admin/conf/tunables.pl @@ -43,10 +43,20 @@ mlmmj_boolean("subonlypost", "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("digestmaxmails", 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 @@ mlmmj_boolean("nosubonlydenymails", "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 --git a/src/mlmmj-process.c b/src/mlmmj-process.c index 4c8e9595..26423673 100644 --- a/src/mlmmj-process.c +++ b/src/mlmmj-process.c @@ -53,6 +53,7 @@ #include "memory.h" #include "log_oper.h" #include "unistr.h" +#include "chomp.h" enum action { ALLOW, @@ -74,6 +75,7 @@ static char *action_strs[] = { enum modreason { MODNONSUBPOSTS, + MODNONMODPOSTS, ACCESS, MODERATED }; @@ -81,23 +83,61 @@ enum modreason { static char *modreason_strs[] = { "modnonsubposts", + "modnonmodposts", "access", "moderated" }; +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) { + log_error(LOG_ARGS, "Could not open '%s'", moderatorsfilename); + myfree(moderatorsfilename); + exit(EXIT_FAILURE); + } + myfree(moderatorsfilename); + + while((buf = mygetline(moderatorsfd))) { + chomp(buf); + if(address && strcasecmp(buf, address) == 0) { + foundaddr = 1; + if (!moderators) { + close(moderatorsfd); + myfree(buf); + return foundaddr; + } + } + if (moderators) { + tmp = *moderators; + *moderators = concatstr(3, *moderators, buf, "\n"); + myfree(tmp); + } + myfree(buf); + } + + 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 *buf, *replyto, *listaddr = getlistaddr(listdir), *listdelim; + char *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; + 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, @@ -106,35 +146,15 @@ static void newmoderated(const char *listdir, const char *mailfilename, listfqdn = genlistfqdn(listaddr); listname = genlistname(listaddr); - moderatorsfilename = concatstr(2, listdir, "/control/moderators"); - if((moderatorsfd = open(moderatorsfilename, O_RDONLY)) < 0) { - log_error(LOG_ARGS, "Could not open '%s'", moderatorsfilename); - myfree(moderatorsfilename); - exit(EXIT_FAILURE); - } - myfree(moderatorsfilename); - if(statctrl(listdir, "ifmodsendonlymodmoderate")) - efromismod = concatstr(2, efromsender, "\n"); + efromismod = efromsender; - while((buf = mygetline(moderatorsfd))) { - if(efromismod && strcmp(buf, efromismod) == 0) - foundaddr = 1; - tmp = moderators; - moderators = concatstr(2, moderators, buf); - myfree(buf); - myfree(tmp); - } - - if(!foundaddr) { - myfree(efromismod); + 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 main(int argc, char **argv) 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,65 +993,86 @@ int main(int argc, char **argv) } } - 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")) { - moderated = 1; + 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")) { - log_error(LOG_ARGS, "Discarding %s because" - " subonlypost and" - " nosubonlydenymails was set", - mailfile); - myfree(listaddr); - unlink(donemailname); - myfree(donemailname); - exit(EXIT_SUCCESS); - } - listdelim = getlistdelim(listdir); - listname = genlistname(listaddr); - listfqdn = genlistfqdn(listaddr); - fromaddr = concatstr(4, listname, listdelim, - "bounces-help@", listfqdn); - 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); + if((subonlypost && + statctrl(listdir, "nosubonlydenymails")) || + (modonlypost && + statctrl(listdir, "nomodonlydenymails"))) { + log_error(LOG_ARGS, "Discarding %s because" + " no{sub|mod}onlydenymails was set", + mailfile); myfree(listaddr); - myfree(listdelim); - myfree(listname); - myfree(listfqdn); unlink(donemailname); myfree(donemailname); - execlp(mlmmjsend, mlmmjsend, - "-L", listdir, - "-l", "1", - "-T", posteraddr, - "-F", fromaddr, - "-m", queuefilename, (char *)NULL); - - log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend); - exit(EXIT_FAILURE); + exit(EXIT_SUCCESS); + } + listdelim = getlistdelim(listdir); + listname = genlistname(listaddr); + 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); + register_originalmail(txt, donemailname); + queuefilename = prepstdreply(txt, listdir, + "$listowner$", posteraddr, NULL); + MY_ASSERT(queuefilename) + close_text(txt); + myfree(listaddr); + myfree(listdelim); + myfree(listname); + myfree(listfqdn); + unlink(donemailname); + myfree(donemailname); + execlp(mlmmjsend, mlmmjsend, + "-L", listdir, + "-l", "1", + "-T", posteraddr, + "-F", fromaddr, + "-m", queuefilename, (char *)NULL); + + log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend); + exit(EXIT_FAILURE); } } }