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 --]
next 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.