in a minute.
--- ChangeLog 14 Sep 2004 11:06:43 -0000 1.82
+++ ChangeLog 23 Sep 2004 14:25:13 -0000
@@ -1,6 +1,9 @@
- o Avoid message about changing uid in mlmmj-sub by only saying so when doing
- so
+ o Add support for not archiving the list by touching listdir/control/noarchive
+ o Add 'nomail' version of lists. Subscribers to the nomail version are
+ subscribed, but does not get any mail
+ o Don't talk about changing uid in mlmmj-sub when we're not really doing it
o Add sanity checks to disallow denial mails going to the list
+ o Add digest functionality
o Implement -d option for mlmmj-maintd to be able to supply it with a directory
containing several listdirs, where mlmmj-maintd then will run maintenance
o Chown option and a fix for mlmmj-make-ml.sh. Thanks Ingo Lameter
- o Avoid message about changing uid in mlmmj-sub by only saying so when doing
- so
+ o Add support for not archiving the list by touching listdir/control/noarchive
+ o Add 'nomail' version of lists. Subscribers to the nomail version are
+ subscribed, but does not get any mail
+ o Don't talk about changing uid in mlmmj-sub when we're not really doing it
o Add sanity checks to disallow denial mails going to the list
+ o Add digest functionality
o Implement -d option for mlmmj-maintd to be able to supply it with a directory
containing several listdirs, where mlmmj-maintd then will run maintenance
o Chown option and a fix for mlmmj-make-ml.sh. Thanks Ingo Lameter
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.
+
+ ยท noarchive (boolean)
+
+ If this file exists, the mail won't be saved in the archive but simply
+ deleted.
#ifndef MLMMJ_SUBSCRIBE_H
#define MLMMJ_SUBSCRIBE_H
+#include <mlmmj.h>
+
void confirm_sub(const char *listdir, const char *listaddr,
- const char *subaddr, const char *mlmmjsend, int digest);
+ const char *subaddr, const char *mlmmjsend,
+ enum subtype typesub);
void generate_subconfirm(const char *listdir, const char *listadr,
const char *subaddr, const char *mlmmjsend,
- int digest);
+ enum subtype typesub);
#endif /* MLMMJ_SUBSCRIBE_H */
#include <sys/types.h>
void confirm_unsub(const char *listdir, const char *listaddr,
- const char *subaddr, const char *mlmmj, int digest);
+ const char *subaddr, const char *mlmmj,
+ enum subtype typesub);
ssize_t unsubscribe(int subreadfd, int subwritefd, const char *address);
void generate_unsubconfirm(const char *listdir, const char *listaddr,
const char *subaddr, const char *mlmmjsend,
- int digest);
+ enum subtype typesub);
#endif /* MLMMJ_UNSUBSCRIBE_H */
char **values;
};
+/* Has to go here, since it's used in many places */
+enum subtype {
+ SUB_NORMAL,
+ SUB_DIGEST,
+ SUB_NOMAIL
+};
+
void print_version(const char *prg);
#define MY_ASSERT(expression) if (!(expression)) { \
#define SUBSCRIBERFUNC_H
off_t find_subscriber(int fd, const char *address);
+int is_subbed_in(const char *subddirname, const char *address);
int is_subbed(const char *listdir, const char *address);
#endif /* SUBSCRIBERFUNC_H */
--- /dev/null
+Hi, this is the mlmmj program managing the mailinglist
+
+*LSTADDR*
+
+
+The following address has just subscribed to the nomail version of the
+mailinglist:
+
+*SUBADDR*
+
--- /dev/null
+Hi, this is the mlmmj program managing the mailinglist
+
+*LSTADDR*
+
+
+The following address has just unsubscribed from the nomail version of
+mailinglist:
+
+*SUBADDR*
+
--- /dev/null
+Hi, this is the mlmmj program managing the mailinglist
+
+*LSTADDR*
+
+
+To confirm you want the address
+
+*SUBADDR*
+
+
+added to the nomail version of this list, please send a reply to
+
+*CNFADDR*
+
+
+You are getting this mail because of two possible scenarios:
+
+1) You want to be subscribed to the list without getting any mail from it,
+ because you have other means of reading it, and have sent an email
+ specifically to subscribe
+
+2) You have tried to post to a list that only allows posting from sub-
+ scribers. In this case simply reply to this mail, and you will be
+ able to post to the list with this emailaddress in the future
+
+Your mailer probably automatically replies to this address, when you hit
+the reply button.
+
+This confirmation serves two purposes. It tests that mail can be sent to your
+address. Second, it makes sure someone else did not try and subscribe your
+emailaddress.
--- /dev/null
+WELCOME! You have been subscribed to the nomail version of the
+
+*LSTADDR*
+
+
+mailinglist.
--- /dev/null
+Hi, this is the mlmmj program managing the mailinglist
+
+*LSTADDR*
+
+
+To confirm you want the address
+
+*SUBADDR*
+
+
+removed from the nomail version of this list, please send a reply to
+
+*CNFADDR*
+
+
+Your mailer probably automatically replies to this address, when you hit
+the reply button.
+
+If you're not subscribed with this list, you will recieve no reply. You can
+see in the From header of a mail to the mailinglist which mail you're sub-
+scribed with.
--- /dev/null
+GOODBYE! You have been removed from the nomail version of the
+
+*LSTADDR*
+
+
+mailinglist.
mlmmj-sub \- subscribe address to a mailinglist run by mlmmj
.SH SYNOPSIS
.B mlmmj-sub
-\fI-L /path/to/list -a john@doe.org \fR[\fI-c\fR | \fI-C\fR] [\fI-h\fR]
-[\fI-U\fR] [\fI-V\fR]
+\fI-L /path/to/list -a john@doe.org \fR[\fI-c\fR | \fI-C\fR] \fR[\fI-d\fR | \fI-n\fR]
+[\fI-h\fR] [\fI-U\fR] [\fI-V\fR]
.HP
\fB\-a\fR: Email address to subscribe
.HP
\fB\-c\fR: Send welcome mail
.HP
+\fB\-d\fR: Subscribe to digest version of the list
+.HP
\fB\-C\fR: Request mail confirmation
.HP
\fB\-h\fR: This help
.HP
\fB\-L\fR: Full path to list directory
.HP
+\fB\-n\fR: Subscribe to nomail version of the list
+.HP
\fB\-U\fR: Don't switch to the user id of the listdir owner
.HP
\fB\-V\fR: Print version
owning the list directory. This is done to make sure that new files created are
having correct permissions.
+The nomail version of the list is a list version where people are subscribed
+like usual, but they won't recieve any postings to the list. This is useful for
+people who read the mailinglist through a news gateway, but want to be able to
+post to the list.
+
When neither \fB\-c\fR nor \fB\-C\fR are specified, subscription silently
happens.
.SH "SEE ALSO"
.SH SYNOPSIS
.B mlmmj-sub
\fI-L /path/to/list -a john@doe.org \fR[\fI-c\fR | \fI-C\fR] [\fI-h\fR]
-[\fI-V\fR]
+\fR[\fI-d\fR | \fI-n\fR] [\fI-V\fR]
.HP
\fB\-a\fR: Email address to unsubscribe
.HP
.HP
\fB\-C\fR: Request mail confirmation
.HP
+\fB\-d\fR: Unsubscribe from the digest version of the list
+.HP
\fB\-h\fR: This help
.HP
\fB\-L\fR: Full path to list directory
.HP
+\fB\-n\fR: Unsubscribe from the nomail version of the list
+.HP
\fB\-V\fR: Print version
.SH DESCRIPTION
This utility is used to unsubscribe people from the specified mailinglist. It
enum ctrl_e {
CTRL_SUBSCRIBE_DIGEST,
+ CTRL_SUBSCRIBE_NOMAIL,
CTRL_SUBSCRIBE,
CTRL_CONFSUB_DIGEST,
+ CTRL_CONFSUB_NOMAIL,
CTRL_CONFSUB,
CTRL_UNSUBSCRIBE_DIGEST,
+ CTRL_UNSUBSCRIBE_NOMAIL,
CTRL_UNSUBSCRIBE,
CTRL_CONFUNSUB_DIGEST,
+ CTRL_CONFUNSUB_NOMAIL,
CTRL_CONFUNSUB,
CTRL_BOUNCES,
CTRL_MODERATE,
* first to match correctly. */
static struct ctrl_command ctrl_commands[] = {
{ "subscribe-digest", 0 },
+ { "subscribe-nomail", 0 },
{ "subscribe", 0 },
{ "confsub-digest", 1 },
+ { "confsub-nomail", 1 },
{ "confsub", 1 },
{ "unsubscribe-digest", 0 },
+ { "unsubscribe-nomail", 0 },
{ "unsubscribe", 0 },
{ "confunsub-digest", 1 },
+ { "confunsub-nomail", 1 },
{ "confunsub", 1 },
{ "bounces", 1 },
{ "moderate", 1 },
exit(EXIT_FAILURE);
break;
+ /* listname+subscribe-nomail@domain.tld */
+ case CTRL_SUBSCRIBE_NOMAIL:
+ unlink(mailname);
+ if (closedlist)
+ exit(EXIT_SUCCESS);
+ if (!strchr(fromemails->emaillist[0], '@'))
+ /* Not a valid From: address, silently ignore */
+ exit(EXIT_SUCCESS);
+ execlp(mlmmjsub, mlmmjsub,
+ "-L", listdir,
+ "-a", fromemails->emaillist[0],
+ "-n",
+ "-C", NULL);
+ log_error(LOG_ARGS, "execlp() of '%s' failed",
+ mlmmjsub);
+ exit(EXIT_FAILURE);
+ break;
+
/* listname+subscribe@domain.tld */
case CTRL_SUBSCRIBE:
unlink(mailname);
exit(EXIT_FAILURE);
break;
+ /* listname+subconf-nomail-COOKIE@domain.tld */
+ case CTRL_CONFSUB_NOMAIL:
+ unlink(mailname);
+ if (closedlist)
+ exit(EXIT_SUCCESS);
+ conffilename = concatstr(3, listdir, "/subconf/", param);
+ myfree(param);
+ if((tmpfd = open(conffilename, O_RDONLY)) < 0) {
+ /* invalid COOKIE, silently ignore */
+ exit(EXIT_SUCCESS);
+ }
+ tmpstr = mygetline(tmpfd);
+ chomp(tmpstr);
+ close(tmpfd);
+ unlink(conffilename);
+ execlp(mlmmjsub, mlmmjsub,
+ "-L", listdir,
+ "-a", tmpstr,
+ "-n",
+ "-c", NULL);
+ log_error(LOG_ARGS, "execlp() of '%s' failed",
+ mlmmjsub);
+ exit(EXIT_FAILURE);
+ break;
+
/* listname+subconf-COOKIE@domain.tld */
case CTRL_CONFSUB:
unlink(mailname);
exit(EXIT_FAILURE);
break;
+ /* listname+unsubscribe-nomail@domain.tld */
+ case CTRL_UNSUBSCRIBE_NOMAIL:
+ unlink(mailname);
+ if (closedlist)
+ exit(EXIT_SUCCESS);
+ if (!strchr(fromemails->emaillist[0], '@'))
+ /* Not a valid From: address, silently ignore */
+ exit(EXIT_SUCCESS);
+ execlp(mlmmjunsub, mlmmjunsub,
+ "-L", listdir,
+ "-a", fromemails->emaillist[0],
+ "-n",
+ "-C", NULL);
+ log_error(LOG_ARGS, "execlp() of '%s' failed",
+ mlmmjunsub);
+ exit(EXIT_FAILURE);
+ break;
+
/* listname+unsubscribe@domain.tld */
case CTRL_UNSUBSCRIBE:
unlink(mailname);
exit(EXIT_FAILURE);
break;
+ /* listname+unsubconf-nomail-COOKIE@domain.tld */
+ case CTRL_CONFUNSUB_NOMAIL:
+ unlink(mailname);
+ if (closedlist)
+ exit(EXIT_SUCCESS);
+ conffilename = concatstr(3, listdir, "/unsubconf/", param);
+ myfree(param);
+ if((tmpfd = open(conffilename, O_RDONLY)) < 0) {
+ /* invalid COOKIE, silently ignore */
+ exit(EXIT_SUCCESS);
+ }
+ tmpstr = mygetline(tmpfd);
+ close(tmpfd);
+ chomp(tmpstr);
+ unlink(conffilename);
+ execlp(mlmmjunsub, mlmmjunsub,
+ "-L", listdir,
+ "-a", tmpstr,
+ "-n",
+ "-c", NULL);
+ log_error(LOG_ARGS, "execlp() of '%s' failed",
+ mlmmjunsub);
+ exit(EXIT_FAILURE);
+ break;
+
/* listname+unsubconf-COOKIE@domain.tld */
case CTRL_CONFUNSUB:
unlink(mailname);
mkdir -p $LISTDIR
for DIR in incoming queue queue/discarded archive text subconf unsubconf \
- bounce control moderation subscribers.d digesters.d requeue
+ bounce control moderation subscribers.d digesters.d requeue \
+ nomailsubs.d
do
mkdir "$LISTDIR"/"$DIR"
done
size_t len = 0, hdrslen, bodylen;
int sockfd = 0, mailfd = 0, opt, mindex, subfd, tmpfd;
int deletewhensent = 1, sendres, archive = 1, digest = 0;
+ int ctrlarchive;
char *listaddr, *mailfilename = NULL, *subfilename = NULL;
char *replyto = NULL, *bounceaddr = NULL, *to_addr = NULL;
char *relayhost = NULL, *archivefilename = NULL, *tmpstr;
addtohdr = statctrl(listdir, "addtohdr");
memmailsizestr = ctrlvalue(listdir, "memorymailsize");
+ ctrlarchive = statctrl(listdir, "noarchive");
if(memmailsizestr) {
memmailsize = strtol(memmailsizestr, NULL, 10);
myfree(memmailsizestr);
close(mailfd);
if(archive) {
- rename(mailfilename, archivefilename);
+ if(!ctrlarchive)
+ rename(mailfilename, archivefilename);
+ else
+ unlink(mailfilename);
myfree(archivefilename);
} else if(deletewhensent)
unlink(mailfilename);
void confirm_sub(const char *listdir, const char *listaddr,
const char *subaddr, const char *mlmmjsend,
- int digest)
+ enum subtype typesub)
{
int subtextfd, queuefd;
char *buf, *subtextfilename, *randomstr, *queuefilename = NULL;
- char *fromaddr, *listname, *listfqdn, *s1;
+ char *fromaddr, *listname, *listfqdn, *s1, *subject;
- if (!digest) {
- subtextfilename = concatstr(2, listdir, "/text/sub-ok");
- } else {
- subtextfilename = concatstr(2, listdir, "/text/sub-ok-digest");
+ switch(typesub) {
+ case SUB_NORMAL:
+ subtextfilename = concatstr(2, listdir,
+ "/text/sub-ok");
+ break;
+ case SUB_DIGEST:
+ subtextfilename = concatstr(2, listdir,
+ "/text/sub-ok-digest");
+ break;
+ case SUB_NOMAIL:
+ subtextfilename = concatstr(2, listdir,
+ "/text/sub-ok-nomail");
+ break;
}
if((subtextfd = open(subtextfilename, O_RDONLY)) < 0) {
fromaddr = concatstr(3, listname, "+bounces-help@", listfqdn);
- if (!digest) {
- s1 = concatstr(9, "From: ", listname, "+help@", listfqdn,
- "\nTo: ", subaddr, "\nSubject: Welcome to ",
- listaddr, "\n\n");
- } else {
- s1 = concatstr(9, "From: ", listname, "+help@", listfqdn,
- "\nTo: ", subaddr, "\nSubject: Welcome to "
- "digest of ", listaddr, "\n\n");
+ switch(typesub) {
+ case SUB_NORMAL:
+ subject = mystrdup("to ");
+ break;
+ case SUB_DIGEST:
+ subject = mystrdup("to digest of ");
+ break;
+ case SUB_NOMAIL:
+ subject = mystrdup("to nomail version of ");
+ break;
}
+ s1 = concatstr(10, "From: ", listname, "+help@", listfqdn, "\nTo: ",
+ subaddr, "\nSubject: Welcome ", subject, listaddr,
+ "\n\n");
+ myfree(subject);
+
if(writen(queuefd, s1, strlen(s1)) < 0) {
log_error(LOG_ARGS, "Could not write welcome mail");
exit(EXIT_FAILURE);
void notify_sub(const char *listdir, const char *listaddr,
const char *subaddr, const char *mlmmjsend,
- int digest)
+ enum subtype typesub)
{
char *maildata[4] = { "*LSTADDR*", NULL, "*SUBADDR*", NULL };
char *listfqdn, *listname, *fromaddr, *fromstr, *subject;
- char *queuefilename = NULL;
+ char *queuefilename = NULL, *listtext;
listname = genlistname(listaddr);
listfqdn = genlistfqdn(listaddr);
maildata[3] = mystrdup(subaddr);
fromaddr = concatstr(3, listname, "+bounces-help@", listfqdn);
fromstr = concatstr(3, listname, "+owner@", listfqdn);
- if (!digest) {
- subject = concatstr(2, "New subscription to ", listaddr);
- queuefilename = prepstdreply(listdir, "notifysub", fromstr,
- fromstr, NULL, subject, 2,
- maildata);
- } else {
- subject = concatstr(2, "New subscription to digest of ",
+
+ switch(typesub) {
+ case SUB_NORMAL:
+ subject = concatstr(2,
+ "New subscription to ", listaddr);
+ listtext = mystrdup("notifysub");
+ break;
+ case SUB_DIGEST:
+ subject = concatstr(2,
+ "New subscription to digest of ",
+ listaddr);
+ listtext = mystrdup("notifysub-digest");
+ break;
+ case SUB_NOMAIL:
+ subject = concatstr(2,
+ "New subscription to nomail of ",
listaddr);
- queuefilename = prepstdreply(listdir, "notifysub-digest",
- fromstr, fromstr, NULL,
- subject, 2, maildata);
+ listtext = mystrdup("notifysub-nomail");
+ break;
}
+
+ queuefilename = prepstdreply(listdir, listtext, fromstr, fromstr,
+ NULL, subject, 2, maildata);
MY_ASSERT(queuefilename)
+ myfree(listtext);
myfree(listname);
myfree(listfqdn);
myfree(subject);
void generate_subconfirm(const char *listdir, const char *listaddr,
const char *subaddr, const char *mlmmjsend,
- int digest)
+ enum subtype typesub)
{
int subconffd, subtextfd, queuefd;
char *confirmaddr, *listname, *listfqdn, *confirmfilename = NULL;
char *subtextfilename, *queuefilename = NULL, *fromaddr;
- char *buf, *s1, *randomstr = NULL;
+ char *buf, *s1, *randomstr = NULL, *tmpstr, *subject;
listname = genlistname(listaddr);
listfqdn = genlistfqdn(listaddr);
fromaddr = concatstr(5, listname, "+bounces-confsub-", randomstr,
"@", listfqdn);
-
- if (!digest) {
- subtextfilename = concatstr(2, listdir, "/text/sub-confirm");
- confirmaddr = concatstr(5, listname, "+confsub-",
- randomstr, "@", listfqdn);
- } else {
- subtextfilename = concatstr(2, listdir, "/text/sub-confirm-digest");
- confirmaddr = concatstr(5, listname, "+confsub-digest-",
- randomstr, "@", listfqdn);
+
+ switch(typesub) {
+ case SUB_NORMAL:
+ subtextfilename = concatstr(2, listdir,
+ "/text/sub-confirm");
+ tmpstr = mystrdup("+confsub-");
+ break;
+ case SUB_DIGEST:
+ subtextfilename = concatstr(2, listdir,
+ "/text/sub-confirm-digest");
+ tmpstr = mystrdup("+confsub-digest-");
+ break;
+ case SUB_NOMAIL:
+ subtextfilename = concatstr(2, listdir,
+ "/text/sub-confirm-nomail");
+ tmpstr = mystrdup("+confsub-nomail-");
+ break;
}
+ confirmaddr = concatstr(5, listname, tmpstr, randomstr, "@", listfqdn);
+
myfree(randomstr);
+ myfree(tmpstr);
if((subtextfd = open(subtextfilename, O_RDONLY)) < 0) {
log_error(LOG_ARGS, "Could not open '%s'", subtextfilename);
exit(EXIT_FAILURE);
}
- if (!digest) {
- s1 = concatstr(9, "From: ", listname, "+help@", listfqdn,
- "\nTo: ", subaddr, "\nSubject: Confirm subscribe to ",
- listaddr, "\n\n");
- } else {
- s1 = concatstr(9, "From: ", listname, "+help@", listfqdn,
- "\nTo: ", subaddr, "\nSubject: Confirm subscribe to "
- "digest of ", listaddr, "\n\n");
+ switch(typesub) {
+ case SUB_NORMAL:
+ subject = mystrdup("to ");
+ break;
+ case SUB_DIGEST:
+ subject = mystrdup("to digest of ");
+ break;
+ case SUB_NOMAIL:
+ subject = mystrdup("to nomail version of ");
+ break;
}
+ s1 = concatstr(10, "From: ", listname, "+help@", listfqdn, "\nTo: ",
+ subaddr, "\nSubject: Confirm subscribe ", subject,
+ listaddr, "\n\n");
+ myfree(subject);
+
if(writen(queuefd, s1, strlen(s1)) < 0) {
log_error(LOG_ARGS, "Could not write subconffile");
exit(EXIT_FAILURE);
static void print_help(const char *prg)
{
printf("Usage: %s -L /path/to/list -a john@doe.org "
- "[-c] [-C] [-h]\n [-L] [-U] [-V]\n"
+ "[-c] [-C] [-h]\n [-L] [-d | -n] [-U] [-V]\n"
" -a: Email address to subscribe \n"
" -c: Send welcome mail\n"
" -C: Request mail confirmation\n"
" -d: Subscribe to digest of list\n"
" -h: This help\n"
" -L: Full path to list directory\n"
+ " -n: Subscribe to no mail version of list\n"
" -U: Don't switch to the user id of the listdir owner\n"
" -V: Print version\n"
"When no options are specified, subscription silently "
int main(int argc, char **argv)
{
char *listaddr, *listdir = NULL, *address = NULL, *subfilename = NULL;
- char *mlmmjsend, *bindir, chstr[2];
+ char *mlmmjsend, *bindir, chstr[2], *subdir;
int subconfirm = 0, confirmsub = 0, opt, subfilefd, lock, notifysub;
- int changeuid = 1, status, digest = 0;
+ int changeuid = 1, status, digest = 0, nomail = 0;
size_t len;
off_t suboff;
struct stat st;
pid_t pid, childpid;
uid_t uid;
+ enum subtype typesub = SUB_NORMAL;
CHECKFULLPATH(argv[0]);
mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
myfree(bindir);
- while ((opt = getopt(argc, argv, "hcCdVL:a:")) != -1) {
+ while ((opt = getopt(argc, argv, "hcCdnVL:a:")) != -1) {
switch(opt) {
case 'a':
address = optarg;
case 'L':
listdir = optarg;
break;
+ case 'n':
+ nomail = 1;
+ break;
case 'U':
changeuid = 0;
break;
exit(0);
}
}
+
if(listdir == 0 || address == 0) {
fprintf(stderr, "You have to specify -L and -a\n");
fprintf(stderr, "%s -h for help\n", argv[0]);
exit(EXIT_FAILURE);
}
+ if(digest && nomail) {
+ fprintf(stderr, "Specify either -d or -n, not both\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if(digest)
+ typesub = SUB_DIGEST;
+ if(nomail)
+ typesub = SUB_NOMAIL;
+
if(confirmsub && subconfirm) {
fprintf(stderr, "Cannot specify both -C and -c\n");
fprintf(stderr, "%s -h for help\n", argv[0]);
chstr[0] = address[0];
chstr[1] = '\0';
- if (!digest) {
- subfilename = concatstr(3, listdir, "/subscribers.d/", chstr);
- } else {
- subfilename = concatstr(3, listdir, "/digesters.d/", chstr);
+
+ switch(typesub) {
+ case SUB_NORMAL:
+ subdir = mystrdup("/subscribers.d/");
+ break;
+ case SUB_DIGEST:
+ subdir = mystrdup("/digesters.d/");
+ break;
+ case SUB_NOMAIL:
+ subdir = mystrdup("/nomailsubs.d/");
+ break;
}
+
+ subfilename = concatstr(3, listdir, subdir, chstr);
+ myfree(subdir);
subfilefd = open(subfilename, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
if(subfilefd == -1) {
if(suboff == -1) {
if(subconfirm)
generate_subconfirm(listdir, listaddr, address,
- mlmmjsend, digest);
+ mlmmjsend, typesub);
else {
lseek(subfilefd, 0L, SEEK_END);
len = strlen(address);
if(childpid < 0) {
log_error(LOG_ARGS, "Could not fork");
confirm_sub(listdir, listaddr, address, mlmmjsend,
- digest);
+ typesub);
}
if(childpid > 0) {
/* child confirms subscription */
if(childpid == 0)
confirm_sub(listdir, listaddr, address, mlmmjsend,
- digest);
+ typesub);
}
notifysub = statctrl(listdir, "notifysub");
/* Notify list owner about subscription */
if (notifysub)
- notify_sub(listdir, listaddr, address, mlmmjsend, digest);
+ notify_sub(listdir, listaddr, address, mlmmjsend, typesub);
myfree(listaddr);
#include "prepstdreply.h"
void confirm_unsub(const char *listdir, const char *listaddr,
- const char *subaddr, const char *mlmmjsend, int digest)
+ const char *subaddr, const char *mlmmjsend,
+ enum subtype typesub)
{
int subtextfd, queuefd;
char *buf, *subtextfilename, *randomstr, *queuefilename = NULL;
- char *fromaddr, *listname, *listfqdn, *s1;
+ char *fromaddr, *listname, *listfqdn, *s1, *subject;
- if (!digest) {
- subtextfilename = concatstr(2, listdir, "/text/unsub-ok");
- } else {
- subtextfilename = concatstr(2, listdir,
- "/text/unsub-ok-digest");
+ switch(typesub) {
+ case SUB_NORMAL:
+ subtextfilename = concatstr(2, listdir,
+ "/text/sub-ok");
+ break;
+ case SUB_DIGEST:
+ subtextfilename = concatstr(2, listdir,
+ "/text/sub-ok-digest");
+ break;
+ case SUB_NOMAIL:
+ subtextfilename = concatstr(2, listdir,
+ "/text/sub-ok-nomail");
+ break;
}
if((subtextfd = open(subtextfilename, O_RDONLY)) < 0) {
fromaddr = concatstr(3, listname, "+bounces-help@", listfqdn);
- if (!digest) {
- s1 = concatstr(9, "From: ", listname, "+help@", listfqdn,
- "\nTo: ", subaddr, "\nSubject: Goodbye from ",
- listaddr, "\n\n");
- } else {
- s1 = concatstr(9, "From: ", listname, "+help@", listfqdn,
- "\nTo: ", subaddr, "\nSubject: Goodbye from "
- "digest of ", listaddr, "\n\n");
+ switch(typesub) {
+ case SUB_NORMAL:
+ subject = mystrdup("from ");
+ break;
+ case SUB_DIGEST:
+ subject = mystrdup("from digest of ");
+ break;
+ case SUB_NOMAIL:
+ subject = mystrdup("from nomail version of ");
+ break;
}
+ s1 = concatstr(10, "From: ", listname, "+help@", listfqdn, "\nTo: ",
+ subaddr, "\nSubject: Goodbye ", subject, listaddr,
+ "\n\n");
+ myfree(subject);
+
if(writen(queuefd, s1, strlen(s1)) < 0) {
log_error(LOG_ARGS, "Could not write subconffile");
exit(EXIT_FAILURE);
}
void notify_unsub(const char *listdir, const char *listaddr,
- const char *subaddr, const char *mlmmjsend, int digest)
+ const char *subaddr, const char *mlmmjsend,
+ enum subtype typesub)
{
char *maildata[4] = { "*LSTADDR*", NULL, "*SUBADDR*", NULL };
char *listfqdn, *listname, *fromaddr, *fromstr, *subject;
- char *queuefilename = NULL;
+ char *queuefilename = NULL, *listtext;
listname = genlistname(listaddr);
listfqdn = genlistfqdn(listaddr);
maildata[3] = mystrdup(subaddr);
fromaddr = concatstr(3, listname, "+bounces-help@", listfqdn);
fromstr = concatstr(3, listname, "+owner@", listfqdn);
- if (!digest) {
- subject = concatstr(2, "Unsubscription from ", listaddr);
- queuefilename = prepstdreply(listdir, "notifyunsub", fromstr,
- fromstr, NULL, subject, 2, maildata);
- } else {
- subject = concatstr(2, "Unsubscription from digest of ",
+
+ switch(typesub) {
+ case SUB_NORMAL:
+ subject = concatstr(2,
+ "Unsubscription from ", listaddr);
+ listtext = mystrdup("notifyunsub");
+ break;
+ case SUB_DIGEST:
+ subject = concatstr(2,
+ "Unsubscription from digest of ",
listaddr);
- queuefilename = prepstdreply(listdir, "notifyunsub-digest",
- fromstr, fromstr, NULL, subject, 2,
- maildata);
+ listtext = mystrdup("notifyunsub-digest");
+ break;
+ case SUB_NOMAIL:
+ subject = concatstr(2,
+ "Unsubscription from nomail of ",
+ listaddr);
+ listtext = mystrdup("notifyunsub-nomail");
+ break;
}
- MY_ASSERT(queuefilename)
- myfree(listname);
- myfree(listfqdn);
- myfree(subject);
- myfree(maildata[1]);
- myfree(maildata[3]);
- execlp(mlmmjsend, mlmmjsend,
- "-l", "1",
- "-T", fromstr,
- "-F", fromaddr,
- "-m", queuefilename, NULL);
-
- myfree(fromstr);
+
+
+ queuefilename = prepstdreply(listdir, listtext, fromstr, fromstr,
+ NULL, subject, 2, maildata);
+ MY_ASSERT(queuefilename);
+ myfree(listtext);
+ myfree(listname);
+ myfree(listfqdn);
+ myfree(subject);
+ myfree(maildata[1]);
+ myfree(maildata[3]);
+ execlp(mlmmjsend, mlmmjsend,
+ "-l", "1",
+ "-T", fromstr,
+ "-F", fromaddr,
+ "-m", queuefilename, NULL);
+
+ myfree(fromstr);
log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
exit(EXIT_FAILURE);
void generate_unsubconfirm(const char *listdir, const char *listaddr,
const char *subaddr, const char *mlmmjsend,
- int digest)
+ enum subtype typesub)
{
- char *confirmaddr, *buf, *listname, *listfqdn;
+ char *confirmaddr, *buf, *listname, *listfqdn, *tmpstr;
char *subtextfilename, *queuefilename = NULL, *fromaddr, *s1;
- char *randomstr = NULL, *confirmfilename = NULL;
+ char *randomstr = NULL, *confirmfilename = NULL, *subject;
int subconffd, subtextfd, queuefd;
listname = genlistname(listaddr);
fromaddr = concatstr(5, listname, "+bounces-confunsub-", randomstr,
"@", listfqdn);
- if (!digest) {
- subtextfilename = concatstr(2, listdir, "/text/unsub-confirm");
- confirmaddr = concatstr(5, listname, "+confunsub-", randomstr,
- "@", listfqdn);
- } else {
- subtextfilename = concatstr(2, listdir,
- "/text/unsub-confirm-digest");
- confirmaddr = concatstr(5, listname, "+confunsub-digest-",
- randomstr, "@", listfqdn);
+ switch(typesub) {
+ case SUB_NORMAL:
+ subtextfilename = concatstr(2, listdir,
+ "/text/unsub-confirm");
+ tmpstr = mystrdup("+confunsub-");
+ break;
+ case SUB_DIGEST:
+ subtextfilename = concatstr(2, listdir,
+ "/text/unsub-confirm-digest");
+ tmpstr = mystrdup("+confunsub-digest-");
+ break;
+ case SUB_NOMAIL:
+ subtextfilename = concatstr(2, listdir,
+ "/text/unsub-confirm-nomail");
+ tmpstr = mystrdup("+confunsub-nomail-");
+ break;
}
+ confirmaddr = concatstr(5, listname, tmpstr, randomstr, "@", listfqdn);
+
myfree(randomstr);
+ myfree(tmpstr);
if((subtextfd = open(subtextfilename, O_RDONLY)) < 0) {
log_error(LOG_ARGS, "Could not open '%s'", subtextfilename);
exit(EXIT_FAILURE);
}
- if (!digest) {
- s1 = concatstr(9, "From: ", listname, "+help@", listfqdn,
- "\nTo: ", subaddr, "\nSubject: Confirm "
- "unsubscribe from ", listaddr, "\n\n");
- } else {
- s1 = concatstr(9, "From: ", listname, "+help@", listfqdn,
- "\nTo: ", subaddr, "\nSubject: Confirm "
- "unsubscribe from digest of ", listaddr,
- "\n\n");
+ switch(typesub) {
+ case SUB_NORMAL:
+ subject = mystrdup("from ");
+ break;
+ case SUB_DIGEST:
+ subject = mystrdup("from digest of ");
+ break;
+ case SUB_NOMAIL:
+ subject = mystrdup("from nomail version of ");
+ break;
}
+ s1 = concatstr(10, "From: ", listname, "+help@", listfqdn, "\nTo: ",
+ subaddr, "\nSubject: Confirm unsubscribe ", subject,
+ listaddr, "\n\n");
+
if(writen(queuefd, s1, strlen(s1)) < 0) {
log_error(LOG_ARGS, "Could not write subconffile");
exit(EXIT_FAILURE);
static void print_help(const char *prg)
{
printf("Usage: %s -L /path/to/list -a john@doe.org "
- "[-c] [-C] [-h] [-L] [-V]\n"
+ "[-c] [-C] [-h] [-L] [-d | -n] [-V]\n"
" -a: Email address to unsubscribe \n"
" -c: Send goodbye mail\n"
" -C: Request mail confirmation\n"
" -d: Subscribe to digest of list\n"
" -h: This help\n"
" -L: Full path to list directory\n"
+ " -n: Subscribe to no mail version of list\n"
" -V: Print version\n"
"When no options are specified, unsubscription silently "
"happens\n", prg);
int main(int argc, char **argv)
{
- int subread, subwrite, rlock, wlock, opt, unsubres, status;
+ int subread, subwrite, rlock, wlock, opt, unsubres, status, nomail = 0;
int confirmunsub = 0, unsubconfirm = 0, notifysub = 0, digest = 0;
char *listaddr, *listdir = NULL, *address = NULL, *subreadname = NULL;
- char *subwritename, *mlmmjsend, *bindir;
+ char *subwritename, *mlmmjsend, *bindir, *subdir;
char *subddirname;
off_t suboff;
DIR *subddir;
struct dirent *dp;
pid_t pid, childpid;
+ enum subtype typesub = SUB_NORMAL;
CHECKFULLPATH(argv[0]);
mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
myfree(bindir);
- while ((opt = getopt(argc, argv, "hcCdVL:a:")) != -1) {
+ while ((opt = getopt(argc, argv, "hcCdnVL:a:")) != -1) {
switch(opt) {
case 'L':
listdir = optarg;
break;
+ case 'n':
+ nomail = 1;
+ break;
case 'a':
address = optarg;
break;
exit(EXIT_FAILURE);
}
+ if(digest && nomail) {
+ fprintf(stderr, "Specify either -d or -n, not both\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if(digest)
+ typesub = SUB_DIGEST;
+ if(nomail)
+ typesub = SUB_NOMAIL;
+
if(confirmunsub && unsubconfirm) {
fprintf(stderr, "Cannot specify both -C and -c\n");
fprintf(stderr, "%s -h for help\n", argv[0]);
/* get the list address */
listaddr = getlistaddr(listdir);
+ switch(typesub) {
+ case SUB_NORMAL:
+ subdir = mystrdup("/subscribers.d/");
+ break;
+ case SUB_DIGEST:
+ subdir = mystrdup("/digesters.d/");
+ break;
+ case SUB_NOMAIL:
+ subdir = mystrdup("/nomailsubs.d/");
+ break;
+ }
+
+ subddirname = concatstr(2, listdir, subdir);
+
+ if(is_subbed_in(subddirname, address)) {
+ /* Address is not subscribed, so exit silently */
+ myfree(subddirname);
+ myfree(subdir);
+ myfree(listaddr);
+ exit(EXIT_SUCCESS);
+ }
+
if(unsubconfirm)
generate_unsubconfirm(listdir, listaddr, address, mlmmjsend,
- digest);
+ typesub);
- if (!digest) {
- subddirname = concatstr(2, listdir, "/subscribers.d/");
- } else {
- subddirname = concatstr(2, listdir, "/digesters.d/");
- }
if((subddir = opendir(subddirname)) == NULL) {
log_error(LOG_ARGS, "Could not opendir(%s)",
subddirname);
myfree(subddirname);
+ myfree(subdir);
+ myfree(listaddr);
exit(EXIT_FAILURE);
}
+
myfree(subddirname);
+
while((dp = readdir(subddir)) != NULL) {
if(!strcmp(dp->d_name, "."))
continue;
if(!strcmp(dp->d_name, ".."))
continue;
- if (!digest) {
- subreadname = concatstr(3, listdir, "/subscribers.d/",
- dp->d_name);
- } else {
- subreadname = concatstr(3, listdir, "/digesters.d/",
- dp->d_name);
- }
+
+ subreadname = concatstr(3, listdir, subdir, dp->d_name);
subread = open(subreadname, O_RDWR);
if(subread == -1) {
}
}
+ myfree(subdir);
notifysub = statctrl(listdir, "notifysub");
/* Notify list owner about subscription */
if (notifysub)
- notify_unsub(listdir, listaddr, address, mlmmjsend, digest);
+ notify_unsub(listdir, listaddr, address, mlmmjsend, typesub);
myfree(listaddr);
return (off_t)-1;
}
-static int is_subbed_in(const char *subddirname, const char *address)
+int is_subbed_in(const char *subddirname, const char *address)
{
int retval = 1, subread;
char *subreadname;
if (retval == 0)
return 0;
+ subddirname = concatstr(2, listdir, "/nomailsubs.d/");
+ retval = is_subbed_in(subddirname, address);
+ myfree(subddirname);
+ if (retval == 0)
+ return 0;
+
return 1;
}