listname+subscribe-digest@domain.tld
DEPRECATED: use $list+$subscribe-digest@$domain$ instead
+- $digestsubreleaseaddr$
+ (available only in deny-post-subonlypost and wait-post-modnonsubposts)
+ the address to which to send mail to simultaneously subscribe to the digest
+ version of the list and release the post in question
+
- $digestthreads$
(available only in digest)
the formatted list of threads included in the digest
listname+subscribe@domain.tld
DEPRECATED: use $list+$subscribe@$domain$ instead
+- $listsubreleaseaddr$
+ (available only in deny-post-subonlypost and wait-post-modnonsubposts)
+ the address to which to send mail to simultaneously subscribe to the list
+ and release the post in question
+
- $listunsubaddr$
listname+unsubscribe@domain.tld
DEPRECATED: use $list+$unsubscribe@$domain$ instead
listname+subscribe-nomail@domain.tld
DEPRECATED: use $list+$subscribe-nomail@$domain$ instead
+- $nomailsubreleaseaddr$
+ (available only in deny-post-subonlypost and wait-post-modnonsubposts)
+ the address to which to send mail to simultaneously subscribe to the no-mail
+ version of the list and release the post in question
+
- $nomailunsubaddr$
listname+unsubscribe-nomail@domain.tld
DEPRECATED: use $list+$unsubscribe-nomail@$domain$ instead
CTRL_CONFUNSUB_NOMAIL,
CTRL_CONFUNSUB,
CTRL_BOUNCES,
+ CTRL_SUBRELEASE,
+ CTRL_DIGESTSUBRELEASE,
+ CTRL_NOMAILSUBRELEASE,
CTRL_RELEASE,
CTRL_REJECT,
CTRL_PERMIT,
{ "confunsub-nomail", true , false, true , CTRL_CONFUNSUB_NOMAIL },
{ "confunsub", true , false, true , CTRL_CONFUNSUB },
{ "bounces", true , true , true , CTRL_BOUNCES },
+ { "subrelease", true , true , true , CTRL_SUBRELEASE },
+ { "digestsubrelease", true , true , true , CTRL_DIGESTSUBRELEASE },
+ { "nomailsubrelease", true , true , true , CTRL_NOMAILSUBRELEASE },
{ "release", true , true , true , CTRL_RELEASE },
{ "reject", true , true , true , CTRL_REJECT },
{ "permit", true , true , true , CTRL_PERMIT },
exit(EXIT_SUCCESS);
break;
+ /* listname+subrelease-COOKIE@domain.tld */
+ case CTRL_SUBRELEASE:
+ ts = SUB_NORMAL;
+ /* fallthrough */
+ /* listname+digestsubrelease-COOKIE@domain.tld */
+ case CTRL_DIGESTSUBRELEASE:
+ if (ts == SUB_NONE)
+ ts = SUB_DIGEST;
+ /* fallthrough */
+ /* listname+nomailsubrelease-COOKIE@domain.tld */
+ case CTRL_NOMAILSUBRELEASE:
+ if (ts == SUB_NONE)
+ ts = SUB_NOMAIL;
+ /* fallthrough */
/* listname+release-COOKIE@domain.tld */
case CTRL_RELEASE:
/* DEPRECATED: listname+moderate-COOKIE@domain.tld */
unlinkat(ml->fd, omitfilename, 0);
free(omitfilename);
free(moderatefilename);
- bool autosubscribe = statctrl(ml->ctrlfd, "autosubscribe");
- if (autosubscribe) {
+ if (ts != SUB_NONE) {
+ /* subrelease: always subscribe with requested type */
+ int mfd = openat(ml->fd, sendfilename, O_RDONLY);
+ if (mfd == -1) {
+ free(sendfilename);
+ return (-1);
+ }
+ autosubscribe_sender(ml, mfd, ts);
+ } else if (statctrl(ml->ctrlfd, "autosubscribe")) {
int mfd = openat(ml->fd, sendfilename, O_RDONLY);
if (mfd == -1) {
free(sendfilename);
register_formatted(txt, "moderators",
rewind_memory_lines, get_memory_line, mls);
register_originalmail(txt, mailfilename);
- qfname = prepstdreply(txt, ml, "$listowner$", efromsender, NULL);
+
+ char *subreplyto = NULL;
+ if (modreason == MODNONSUBPOSTS &&
+ !statctrl(ml->ctrlfd, "closedlist") &&
+ !statctrl(ml->ctrlfd, "closedlistsub")) {
+ char *listsubreleaseaddr;
+ char *digestsubreleaseaddr;
+ char *nomailsubreleaseaddr;
+ gen_addr_cookie(listsubreleaseaddr, ml,
+ "subrelease-", mailbasename);
+ gen_addr_cookie(digestsubreleaseaddr, ml,
+ "digestsubrelease-", mailbasename);
+ gen_addr_cookie(nomailsubreleaseaddr, ml,
+ "nomailsubrelease-", mailbasename);
+ register_unformatted(txt,
+ "listsubreleaseaddr", listsubreleaseaddr);
+ register_unformatted(txt,
+ "digestsubreleaseaddr", digestsubreleaseaddr);
+ register_unformatted(txt,
+ "nomailsubreleaseaddr", nomailsubreleaseaddr);
+ subreplyto = listsubreleaseaddr;
+ }
+
+ qfname = prepstdreply(txt, ml, "$listowner$", efromsender,
+ subreplyto);
MY_ASSERT(qfname);
close_text(txt);
register_unformatted(txt, "subject", subject);
register_unformatted(txt, "posteraddr", testaddr);
register_originalmail(txt, donemailname);
+
+ bool closedlist = statctrl(ml.ctrlfd, "closedlist");
+ bool closedlistsub = statctrl(ml.ctrlfd, "closedlistsub");
+ char *subreplyto = NULL;
+
+ if (subonlypost && !closedlist && !closedlistsub) {
+ char *modname;
+ char *listsubreleaseaddr;
+ char *digestsubreleaseaddr;
+ char *nomailsubreleaseaddr;
+ xasprintf(&modname, "%s/moderation/%s",
+ ml.dir, randomstr);
+ if (rename(donemailname, modname) != 0) {
+ log_error(LOG_ARGS,
+ "could not rename(%s,%s)",
+ donemailname, modname);
+ free(modname);
+ close_text(txt);
+ free_parsed_hdrs(readhdrs, fromemails,
+ originalfromemails, toemails,
+ ccemails, rpemails, dtemails,
+ allheaders);
+ exit(EXIT_FAILURE);
+ }
+ free(modname);
+ gen_addr_cookie(listsubreleaseaddr, &ml,
+ "subrelease-", randomstr);
+ gen_addr_cookie(digestsubreleaseaddr, &ml,
+ "digestsubrelease-", randomstr);
+ gen_addr_cookie(nomailsubreleaseaddr, &ml,
+ "nomailsubrelease-", randomstr);
+ register_unformatted(txt,
+ "listsubreleaseaddr", listsubreleaseaddr);
+ register_unformatted(txt,
+ "digestsubreleaseaddr", digestsubreleaseaddr);
+ register_unformatted(txt,
+ "nomailsubreleaseaddr", nomailsubreleaseaddr);
+ subreplyto = listsubreleaseaddr;
+ }
+
queuefilename = prepstdreply(txt, &ml,
- "$listowner$", testaddr, NULL);
+ "$listowner$", testaddr, subreplyto);
MY_ASSERT(queuefilename)
close_text(txt);
- unlink(donemailname);
+ if (subreplyto == NULL)
+ unlink(donemailname);
free(donemailname);
send_help(&ml, queuefilename, testaddr);
}
customheaders_with_subst \
verp \
normal_email_with_dot \
- multi_line_headers
+ multi_line_headers \
+ subrelease
mlmmjreceive=$(command -v mlmmj-receive)
EOF
atf_check -o file:expected-2.txt sed -e "/^Message-ID:/d; /^Date:/d;" mail-2.txt
}
+
+subrelease_body()
+{
+ init_ml list
+ rmdir list/text
+ ln -s ${top_srcdir}/listtexts/en list/text
+ echo test@mlmmjtest > list/control/listaddress
+ start_fakesmtp list
+ echo "heloname" > list/control/smtphelo
+
+ touch list/control/subonlypost
+ printf "user@test\nuser2@test" > list/subscribers.d/u
+
+cat > first <<EOF
+From: bob@test
+To: test@mlmmjtest
+Return-path: bob@test
+Subject: yeah
+
+Let's go, first email
+EOF
+ atf_check -s exit:0 $mlmmjreceive -L list -F <first
+
+ # Verify the mail was held in moderation
+ var=$(ls list/moderation/)
+ if [ -z "$var" ]; then
+ atf_fail "No file in moderation directory"
+ fi
+
+ # Verify the deny-post mail contains subrelease addresses
+ atf_check -o match:"test\+subrelease-${var}@mlmmjtest" cat mail-1.txt
+ atf_check -o match:"test\+digestsubrelease-${var}@mlmmjtest" cat mail-1.txt
+ atf_check -o match:"test\+nomailsubrelease-${var}@mlmmjtest" cat mail-1.txt
+ # Verify Reply-To is set to subrelease address
+ atf_check -o match:"Reply-To: test\+subrelease-${var}@mlmmjtest" cat mail-1.txt
+
+ # Now send to the subrelease address to subscribe and release
+cat > subrel <<EOF
+From: bob@test
+To: test+subrelease-${var}@mlmmjtest
+Return-path: bob@test
+EOF
+ atf_check -s exit:0 $mlmmjreceive -L list -F <subrel
+
+ # Verify the sender is subscribed
+ atf_check -o match:"bob@test" cat list/subscribers.d/b
+
+ # Verify the post was released (archived)
+ atf_check -s exit:0 test -f list/archive/1
+
+ # Verify the released mail was sent to subscribers (including bob who just subscribed)
+ cat > expected-release.txt <<EOF
+EHLO heloname\r
+MAIL FROM:<test+bounces-1-user=test@mlmmjtest>\r
+RCPT TO:<user@test>\r
+DATA\r
+From: bob@test\r
+To: test@mlmmjtest\r
+Subject: yeah\r
+\r
+Let's go, first email\r
+\r
+.\r
+MAIL FROM:<test+bounces-1-user2=test@mlmmjtest>\r
+RCPT TO:<user2@test>\r
+DATA\r
+From: bob@test\r
+To: test@mlmmjtest\r
+Subject: yeah\r
+\r
+Let's go, first email\r
+\r
+.\r
+MAIL FROM:<test+bounces-1-bob=test@mlmmjtest>\r
+RCPT TO:<bob@test>\r
+DATA\r
+From: bob@test\r
+To: test@mlmmjtest\r
+Subject: yeah\r
+\r
+Let's go, first email\r
+\r
+.\r
+QUIT\r
+EOF
+ atf_check -o file:expected-release.txt sed -e "/^Message-ID:/d; /^Date:/d;" mail-2.txt
+}