From: mmj Date: Thu, 23 Sep 2004 14:29:31 +0000 (+1000) Subject: This is post crash commit of working copy mmj. Will test compile etc. X-Git-Tag: RELEASE_1_1_0~54 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cd702d63af176640b37567b69c274255e6dd373a;p=thirdparty%2Fmlmmj.git This is post crash commit of working copy mmj. Will test compile etc. 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 --- diff --git a/ChangeLog b/ChangeLog index 59af1722..00ad7bbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/TUNABLES b/TUNABLES index 00659882..bfc4a523 100644 --- a/TUNABLES +++ b/TUNABLES @@ -93,3 +93,8 @@ to specify several entries (one pr. line), it's marked "list". 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. diff --git a/VERSION b/VERSION index 7dea76ed..3b9f2caa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.1 +1.1-pre-09182004 diff --git a/include/mlmmj-sub.h b/include/mlmmj-sub.h index e0d0a614..c17c2da7 100644 --- a/include/mlmmj-sub.h +++ b/include/mlmmj-sub.h @@ -24,10 +24,13 @@ #ifndef MLMMJ_SUBSCRIBE_H #define MLMMJ_SUBSCRIBE_H +#include + 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 */ diff --git a/include/mlmmj-unsub.h b/include/mlmmj-unsub.h index 974f926b..36bc5e5a 100644 --- a/include/mlmmj-unsub.h +++ b/include/mlmmj-unsub.h @@ -27,10 +27,11 @@ #include 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 */ diff --git a/include/mlmmj.h b/include/mlmmj.h index eb8dd912..52a58d3f 100644 --- a/include/mlmmj.h +++ b/include/mlmmj.h @@ -65,6 +65,13 @@ struct mailhdr { 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)) { \ diff --git a/include/subscriberfuncs.h b/include/subscriberfuncs.h index c70abf18..e36f2746 100644 --- a/include/subscriberfuncs.h +++ b/include/subscriberfuncs.h @@ -25,6 +25,7 @@ #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 */ diff --git a/listtexts/notifysub-nomail b/listtexts/notifysub-nomail new file mode 100644 index 00000000..f263a983 --- /dev/null +++ b/listtexts/notifysub-nomail @@ -0,0 +1,10 @@ +Hi, this is the mlmmj program managing the mailinglist + +*LSTADDR* + + +The following address has just subscribed to the nomail version of the +mailinglist: + +*SUBADDR* + diff --git a/listtexts/notifyunsub-nomail b/listtexts/notifyunsub-nomail new file mode 100644 index 00000000..1c01b966 --- /dev/null +++ b/listtexts/notifyunsub-nomail @@ -0,0 +1,10 @@ +Hi, this is the mlmmj program managing the mailinglist + +*LSTADDR* + + +The following address has just unsubscribed from the nomail version of +mailinglist: + +*SUBADDR* + diff --git a/listtexts/sub-confirm-nomail b/listtexts/sub-confirm-nomail new file mode 100644 index 00000000..b4759feb --- /dev/null +++ b/listtexts/sub-confirm-nomail @@ -0,0 +1,31 @@ +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. diff --git a/listtexts/sub-ok-nomail b/listtexts/sub-ok-nomail new file mode 100644 index 00000000..89a23453 --- /dev/null +++ b/listtexts/sub-ok-nomail @@ -0,0 +1,6 @@ +WELCOME! You have been subscribed to the nomail version of the + +*LSTADDR* + + +mailinglist. diff --git a/listtexts/unsub-confirm-nomail b/listtexts/unsub-confirm-nomail new file mode 100644 index 00000000..33260dea --- /dev/null +++ b/listtexts/unsub-confirm-nomail @@ -0,0 +1,21 @@ +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. diff --git a/listtexts/unsub-ok-nomail b/listtexts/unsub-ok-nomail new file mode 100644 index 00000000..c2c44c25 --- /dev/null +++ b/listtexts/unsub-ok-nomail @@ -0,0 +1,6 @@ +GOODBYE! You have been removed from the nomail version of the + +*LSTADDR* + + +mailinglist. diff --git a/man/mlmmj-sub.1 b/man/mlmmj-sub.1 index 63aac5cd..c92fec3f 100644 --- a/man/mlmmj-sub.1 +++ b/man/mlmmj-sub.1 @@ -3,19 +3,23 @@ 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 @@ -28,6 +32,11 @@ Unless the \fB\-U\fR switch is used it will switch its user id to the user id 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" diff --git a/man/mlmmj-unsub.1 b/man/mlmmj-unsub.1 index b2767eb7..5bf709a8 100644 --- a/man/mlmmj-unsub.1 +++ b/man/mlmmj-unsub.1 @@ -4,7 +4,7 @@ mlmmj-unsub \- manual page for mlmmj-unsub .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 @@ -12,10 +12,14 @@ mlmmj-unsub \- manual page for mlmmj-unsub .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 diff --git a/src/listcontrol.c b/src/listcontrol.c index 62b9e16b..8682fa92 100644 --- a/src/listcontrol.c +++ b/src/listcontrol.c @@ -44,12 +44,16 @@ 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, @@ -70,12 +74,16 @@ struct ctrl_command { * 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 }, @@ -167,6 +175,24 @@ int listcontrol(struct email_container *fromemails, const char *listdir, 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); @@ -209,6 +235,31 @@ int listcontrol(struct email_container *fromemails, const char *listdir, 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); @@ -251,6 +302,24 @@ int listcontrol(struct email_container *fromemails, const char *listdir, 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); @@ -293,6 +362,31 @@ int listcontrol(struct email_container *fromemails, const char *listdir, 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); diff --git a/src/mlmmj-make-ml.sh b/src/mlmmj-make-ml.sh index 55d8a2e2..04b5d7c0 100755 --- a/src/mlmmj-make-ml.sh +++ b/src/mlmmj-make-ml.sh @@ -67,7 +67,8 @@ LISTDIR="$SPOOLDIR/$LISTNAME" 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 diff --git a/src/mlmmj-send.c b/src/mlmmj-send.c index 80e72204..9e12fac0 100644 --- a/src/mlmmj-send.c +++ b/src/mlmmj-send.c @@ -472,6 +472,7 @@ int main(int argc, char **argv) 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; @@ -611,6 +612,7 @@ int main(int argc, char **argv) addtohdr = statctrl(listdir, "addtohdr"); memmailsizestr = ctrlvalue(listdir, "memorymailsize"); + ctrlarchive = statctrl(listdir, "noarchive"); if(memmailsizestr) { memmailsize = strtol(memmailsizestr, NULL, 10); myfree(memmailsizestr); @@ -865,7 +867,10 @@ int main(int argc, char **argv) close(mailfd); if(archive) { - rename(mailfilename, archivefilename); + if(!ctrlarchive) + rename(mailfilename, archivefilename); + else + unlink(mailfilename); myfree(archivefilename); } else if(deletewhensent) unlink(mailfilename); diff --git a/src/mlmmj-sub.c b/src/mlmmj-sub.c index aef205f9..4f01c65c 100644 --- a/src/mlmmj-sub.c +++ b/src/mlmmj-sub.c @@ -48,16 +48,25 @@ 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) { @@ -89,16 +98,23 @@ void confirm_sub(const char *listdir, const char *listaddr, 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); @@ -138,11 +154,11 @@ void confirm_sub(const char *listdir, const char *listaddr, 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); @@ -150,19 +166,31 @@ void notify_sub(const char *listdir, const char *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); @@ -182,12 +210,12 @@ void notify_sub(const char *listdir, const char *listaddr, 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); @@ -224,18 +252,29 @@ void generate_subconfirm(const char *listdir, const char *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); @@ -262,16 +301,23 @@ void generate_subconfirm(const char *listdir, const char *listaddr, 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); @@ -326,13 +372,14 @@ void generate_subconfirm(const char *listdir, const char *listaddr, 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 " @@ -343,14 +390,15 @@ static void print_help(const char *prg) 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]); @@ -360,7 +408,7 @@ int main(int argc, char **argv) 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; @@ -380,6 +428,9 @@ int main(int argc, char **argv) case 'L': listdir = optarg; break; + case 'n': + nomail = 1; + break; case 'U': changeuid = 0; break; @@ -388,12 +439,24 @@ int main(int argc, char **argv) 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]); @@ -422,11 +485,21 @@ int main(int argc, char **argv) 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) { @@ -444,7 +517,7 @@ int main(int argc, char **argv) if(suboff == -1) { if(subconfirm) generate_subconfirm(listdir, listaddr, address, - mlmmjsend, digest); + mlmmjsend, typesub); else { lseek(subfilefd, 0L, SEEK_END); len = strlen(address); @@ -466,7 +539,7 @@ int main(int argc, char **argv) if(childpid < 0) { log_error(LOG_ARGS, "Could not fork"); confirm_sub(listdir, listaddr, address, mlmmjsend, - digest); + typesub); } if(childpid > 0) { @@ -478,14 +551,14 @@ int main(int argc, char **argv) /* 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); diff --git a/src/mlmmj-unsub.c b/src/mlmmj-unsub.c index 9721fd86..0b336b0d 100644 --- a/src/mlmmj-unsub.c +++ b/src/mlmmj-unsub.c @@ -47,17 +47,26 @@ #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) { @@ -89,16 +98,23 @@ void confirm_unsub(const char *listdir, const char *listaddr, 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); @@ -137,11 +153,12 @@ void confirm_unsub(const char *listdir, const char *listaddr, } 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); @@ -149,30 +166,44 @@ void notify_unsub(const char *listdir, const char *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); @@ -181,11 +212,11 @@ void notify_unsub(const char *listdir, const char *listaddr, 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); @@ -224,18 +255,28 @@ void generate_unsubconfirm(const char *listdir, const char *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); @@ -261,17 +302,22 @@ void generate_unsubconfirm(const char *listdir, const char *listaddr, 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); @@ -362,13 +408,14 @@ ssize_t unsubscribe(int subreadfd, int subwritefd, const char *address) 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); @@ -377,15 +424,16 @@ static void print_help(const char *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]); @@ -395,11 +443,14 @@ int main(int argc, char **argv) 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; @@ -426,6 +477,17 @@ int main(int argc, char **argv) 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]); @@ -435,34 +497,50 @@ int main(int argc, char **argv) /* 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) { @@ -574,12 +652,13 @@ int main(int argc, char **argv) } } + 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); diff --git a/src/subscriberfuncs.c b/src/subscriberfuncs.c index 1000c2b4..401105a1 100644 --- a/src/subscriberfuncs.c +++ b/src/subscriberfuncs.c @@ -87,7 +87,7 @@ off_t find_subscriber(int fd, const char *address) 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; @@ -148,5 +148,11 @@ int is_subbed(const char *listdir, const char *address) 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; }