+ o Fix bug where the normal listtext would be sent when unsubscribing from the
+ nomail version of the list
+ o New listtext naming scheme
o Avoid trailing whitespace in MAIL FROM line (Lukas Fleischer)
o Better end-of-line handling and error reporting in php-admin (Franky Van
Liedekerke)
#ifndef MLMMJ_SUBSCRIBE_H
#define MLMMJ_SUBSCRIBE_H
-#include <mlmmj.h>
-
-void moderate_sub(const char *listdir, const char *listaddr,
- const char *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub);
-void getaddrandtype(const char *listdir, const char *modstr,
- char **addrptr, enum subtype *subtypeptr);
-void confirm_sub(const char *listdir, const char *listaddr,
- const char *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub);
-void generate_subconfirm(const char *listdir, const char *listadr,
- const char *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub);
#endif /* MLMMJ_SUBSCRIBE_H */
#ifndef MLMMJ_UNSUBSCRIBE_H
#define MLMMJ_UNSUBSCRIBE_H
-#include <sys/types.h>
-
-void confirm_unsub(const char *listdir, const char *listaddr,
- const char *listdelim, 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 *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub);
#endif /* MLMMJ_UNSUBSCRIBE_H */
};
/* Has to go here, since it's used in many places */
+
enum subtype {
SUB_NORMAL,
SUB_DIGEST,
SUB_NOMAIL,
- SUB_FILE /* For single files (moderator, owner etc.) */
+ SUB_FILE, /* For single files (moderator, owner etc.) */
+ SUB_ALL /* For listing all kinds of subscribers */
};
+char *subtype_strs[5]; /* count matches enum above; defined in mlmmj-sub.c */
+
+enum subreason {
+ SUB_REQUEST,
+ SUB_CONFIRM,
+ SUB_PERMIT,
+ SUB_ADMIN,
+ SUB_BOUNCING
+};
+
+char * subreason_strs[5]; /* count matches enum above; defined in mlmmj-sub.c */
+
void print_version(const char *prg);
#define MY_ASSERT(expression) if (!(expression)) { \
char *substitute_one(const char *line, const char *listaddr,
const char *listdelim, size_t datacount, char **data, const char *listdir);
int open_listtext(const char *listdir, const char *filename);
-char *prepstdreply(const char *listdir, const char *filename, const char *from,
- const char *to, const char *replyto, size_t tokencount,
- char **data, const char *mailname);
+char *prepstdreply(const char *listdir, const char *purpose, const char *action,
+ const char *reason, const char *type, const char *compat,
+ const char *from, const char *to, const char *replyto,
+ size_t tokencount, char **data, const char *mailname);
#endif /* PREPSTDREPLY_H */
#define SEND_HELP_H
void send_help(const char *listdir, const char *emailaddr,
- const char *mlmmjsend, const char *name, const char *textfile);
+ const char *mlmmjsend, const char *purpose, const char *action,
+ const char *reason, const char *type, const char *compat);
#endif
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] \fR[\fI-d\fR | \fI-n\fR]
-[\fI-f\fR] [\fI-h\fR] [\fI-U\fR] [\fI-V\fR]
+\fI-L /path/to/list\fR [\fI-a john@doe.org\fR | \fI-m str\fR]
+[\fI-c\fR | \fI-C\fR] [\fI-d\fR | \fI-n\fR] [\fI-f\fR] [\fI-h\fR] \fR[\fI-r\fR | \fI-R\fR] [\fI-s\fR] [\fI-U\fR] [\fI-V\fR]
.HP
\fB\-a\fR: Email address to subscribe
.HP
.HP
\fB\-n\fR: Subscribe to nomail version of the list
.HP
+\fB\-r\fR: Behave as if request arrived via email (internal use)
+.HP
+\fB\-R\fR: Behave as if confirmation arrived via email (internal use)
+.HP
\fB\-s\fR: Don't send a mail to the subscriber if already subscribed
.HP
\fB\-U\fR: Don't switch to the user id of the listdir owner
mlmmj-unsub \- manual page for mlmmj-unsub
.SH SYNOPSIS
.B mlmmj-unsub
-\fI-L /path/to/list -a john@doe.org \fR[\fI-c\fR | \fI-C\fR] [\fI-h\fR]
-\fR[\fI-d\fR | \fI-n\fR] [\fI-V\fR]
+\fI-L /path/to/list -a john@doe.org\fR [\fI-b\fR] [\fI-c\fR | \fI-C\fR]
+[\fI-d\fR | \fI-n\fR] [\fI-h\fR] [\fI-r\fR | \fI-R\fR] [\fI-s\fR] [\fI-U\fR] [\fI-V\fR]
.HP
\fB\-a\fR: Email address to unsubscribe
.HP
+\fB\-b\fR: Behave as if unsubscription is due to bouncing (internal use)
+.HP
\fB\-c\fR: Send goodbye mail
.HP
\fB\-C\fR: Request mail confirmation
.HP
\fB\-n\fR: Unsubscribe from the nomail version of the list
.HP
+\fB\-r\fR: Behave as if request arrived via email (internal use)
+.HP
+\fB\-R\fR: Behave as if confirmation arrived via email (internal use)
+.HP
\fB\-s\fR: Don't send a mail to the address if not subscribed
.HP
\fB\-U\fR: Don't switch to the user id of the listdir owner
log_error(LOG_ARGS, "A subcribe-digest request was"
" denied");
send_help(listdir, fromemails->emaillist[0],
- mlmmjsend, "nodigest", "sub-deny-digest");
+ mlmmjsend, "deny", "sub", "disabled", "digest", "sub-deny-digest");
return -1;
}
log_oper(listdir, OPLOGFNAME, "mlmmj-sub: request for digest"
"-L", listdir,
"-a", fromemails->emaillist[0],
"-d",
- subswitch, (char *)NULL);
+ "-r", subswitch, (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjsub);
exit(EXIT_FAILURE);
log_error(LOG_ARGS, "A subcribe-nomail request was"
" denied");
send_help(listdir, fromemails->emaillist[0],
- mlmmjsend, "nonomail", "sub-deny-nomail");
+ mlmmjsend, "deny", "sub", "disabled", "nomail", "sub-deny-nomail");
return -1;
}
log_oper(listdir, OPLOGFNAME, "mlmmj-sub: request for nomail"
"-L", listdir,
"-a", fromemails->emaillist[0],
"-n",
- subswitch, (char *)NULL);
+ "-r", subswitch, (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjsub);
exit(EXIT_FAILURE);
execlp(mlmmjsub, mlmmjsub,
"-L", listdir,
"-a", fromemails->emaillist[0],
- subswitch, (char *)NULL);
+ "-r", subswitch, (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjsub);
exit(EXIT_FAILURE);
"-L", listdir,
"-a", tmpstr,
"-d",
- "-c", (char *)NULL);
+ "-R", "-c", (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjsub);
exit(EXIT_FAILURE);
"-L", listdir,
"-a", tmpstr,
"-n",
- "-c", (char *)NULL);
+ "-R", "-c", (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjsub);
exit(EXIT_FAILURE);
execlp(mlmmjsub, mlmmjsub,
"-L", listdir,
"-a", tmpstr,
- "-c", (char *)NULL);
+ "-R", "-c", (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjsub);
exit(EXIT_FAILURE);
"-L", listdir,
"-a", fromemails->emaillist[0],
"-d",
- subswitch, (char *)NULL);
+ "-r", subswitch, (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjunsub);
exit(EXIT_FAILURE);
"-L", listdir,
"-a", fromemails->emaillist[0],
"-n",
- subswitch, (char *)NULL);
+ "-r", subswitch, (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjunsub);
exit(EXIT_FAILURE);
execlp(mlmmjunsub, mlmmjunsub,
"-L", listdir,
"-a", fromemails->emaillist[0],
- subswitch, (char *)NULL);
+ "-r", subswitch, (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjunsub);
exit(EXIT_FAILURE);
"-L", listdir,
"-a", tmpstr,
"-d",
- "-c", (char *)NULL);
+ "-R", "-c", (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjunsub);
exit(EXIT_FAILURE);
"-L", listdir,
"-a", tmpstr,
"-n",
- "-c", (char *)NULL);
+ "-R", "-c", (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjunsub);
exit(EXIT_FAILURE);
execlp(mlmmjunsub, mlmmjunsub,
"-L", listdir,
"-a", tmpstr,
- "-c", (char *)NULL);
+ "-R", "-c", (char *)NULL);
log_error(LOG_ARGS, "execlp() of '%s' failed",
mlmmjunsub);
exit(EXIT_FAILURE);
}
log_oper(listdir, OPLOGFNAME, "%s requested help",
fromemails->emaillist[0]);
- send_help(listdir, fromemails->emaillist[0], mlmmjsend, "help", "listhelp");
+ send_help(listdir, fromemails->emaillist[0], mlmmjsend,
+ "help", NULL, NULL, NULL, "listhelp");
break;
/* listname+faq@domain.tld */
}
log_oper(listdir, OPLOGFNAME, "%s requested faq",
fromemails->emaillist[0]);
- send_help(listdir, fromemails->emaillist[0], mlmmjsend, "faq", "listfaq");
+ send_help(listdir, fromemails->emaillist[0], mlmmjsend,
+ "faq", NULL, NULL, NULL, "listfaq");
break;
/* listname+get-INDEX@domain.tld */
}
maildata[1] = indexstr;
- queuefilename = prepstdreply(listdir, "bounce-probe", "$listowner$",
- myaddr, NULL, 1, maildata, NULL);
+ queuefilename = prepstdreply(listdir,
+ "probe", NULL, NULL, NULL, "bounce-probe",
+ "$listowner$", myaddr, NULL, 1, maildata, NULL);
MY_ASSERT(queuefilename);
myfree(indexstr);
} else {
execlp(mlmmjunsub, mlmmjunsub,
"-L", listdir,
- "-a", address, (char *)NULL);
+ "-b", "-a", address, (char *)NULL);
log_error(LOG_ARGS, "Could not execlp %s",
mlmmjunsub);
return 1;
};
+enum modreason {
+ MODNONSUBPOSTS,
+ ACCESS,
+ MODERATED
+};
+
+
+static char *modreason_strs[] = {
+ "modnonsubposts",
+ "access",
+ "moderated"
+};
+
+
void newmoderated(const char *listdir, const char *mailfilename,
const char *mlmmjsend, const char *efromsender,
- size_t tokencount, char **data)
+ size_t tokencount, char **data, enum modreason modreason)
{
size_t i;
char *from, *listfqdn, *listname, *moderators = NULL;
myfree(listname);
myfree(listfqdn);
- queuefilename = prepstdreply(listdir, "moderation", "$listowner$",
- to, replyto, tokencount, maildata,
- mailfilename);
+ queuefilename = prepstdreply(listdir,
+ "moderate", "post", modreason_strs[modreason], NULL,
+ "moderation", "$listowner$", to, replyto,
+ tokencount, maildata, mailfilename);
/* we might need to exec more than one mlmmj-send */
/* send mail to poster that the list is moderated */
- queuefilename = prepstdreply(listdir, "moderation-poster",
- "$listowner$", efromsender,
- NULL, tokencount-1, maildata+2, mailfilename);
+ queuefilename = prepstdreply(listdir,
+ "wait", "post", modreason_strs[modreason], NULL,
+ "moderation-poster", "$listowner$", efromsender,
+ NULL, tokencount-1, maildata+2, mailfilename);
execlp(mlmmjsend, mlmmjsend,
"-l", "1",
int main(int argc, char **argv)
{
int i, j, opt, noprocess = 0, moderated = 0;
+ enum modreason modreason;
int hdrfd, footfd, rawmailfd, donemailfd, omitfd;
int subonlypost = 0, addrtocc = 1, intocc = 0, modnonsubposts = 0;
int maxmailsize = 0;
"bounces-help@", listfqdn);
maildata[5] = maxmailsizestr;
queuefilename = prepstdreply(listdir,
+ "deny", "post", "maxmailsize", NULL,
"maxmailsize", "$listowner$",
fromemails.emaillist[0],
NULL, 1, maildata+4, donemailname);
listfqdn = genlistfqdn(listaddr);
fromaddr = concatstr(4, listname, listdelim, "bounces-help@",
listfqdn);
- queuefilename = prepstdreply(listdir, "notintocc",
- "$listowner$", fromemails.emaillist[0],
- NULL, 2, maildata, donemailname);
+ queuefilename = prepstdreply(listdir,
+ "deny", "post", "notintocc", NULL, "notintocc",
+ "$listowner$", fromemails.emaillist[0], NULL,
+ 2, maildata, donemailname);
MY_ASSERT(queuefilename)
myfree(listdelim);
myfree(listname);
"modnonsubposts");
if(modnonsubposts) {
moderated = 1;
+ modreason = MODNONSUBPOSTS;
goto startaccess;
}
listfqdn = genlistfqdn(listaddr);
fromaddr = concatstr(4, listname, listdelim,
"bounces-help@", listfqdn);
- queuefilename = prepstdreply(listdir, "subonlypost",
- "$listowner$", fromemails.emaillist[0],
- NULL, 2, maildata, donemailname);
+ queuefilename = prepstdreply(listdir,
+ "deny", "post", "subonlypost", NULL,
+ "subonlypost", "$listowner$",
+ fromemails.emaillist[0], NULL,
+ 2, maildata, donemailname);
MY_ASSERT(queuefilename)
myfree(listaddr);
myfree(listdelim);
startaccess:
- if(!moderated)
- moderated = statctrl(listdir, "moderated");
+ if(!moderated) {
+ if(statctrl(listdir, "moderated")) {
+ moderated = 1;
+ modreason = MODERATED;
+ }
+ }
noaccessdenymails = statctrl(listdir, "noaccessdenymails");
listfqdn = genlistfqdn(listaddr);
fromaddr = concatstr(4, listname, listdelim,
"bounces-help@", listfqdn);
- queuefilename = prepstdreply(listdir, "access",
- "$listowner$",
- fromemails.emaillist[0],
- NULL, 2, maildata, donemailname);
+ queuefilename = prepstdreply(listdir,
+ "deny", "post", "access", NULL,
+ "access", "$listowner$",
+ fromemails.emaillist[0], NULL,
+ 2, maildata, donemailname);
MY_ASSERT(queuefilename)
myfree(listaddr);
myfree(listdelim);
exit(EXIT_FAILURE);
} else if (accret == MODERATE) {
moderated = 1;
+ modreason = ACCESS;
} else if (accret == DISCARD) {
discardname = concatstr(3, listdir,
"/queue/discarded/", randomstr);
fsync(omitfd);
close(omitfd);
}
- newmoderated(listdir, mqueuename, mlmmjsend, efrom, 2, maildata);
+ newmoderated(listdir, mqueuename,
+ mlmmjsend, efrom, 2, maildata, modreason);
return EXIT_SUCCESS;
}
#include "ctrlvalues.h"
#include "chomp.h"
+char *subtype_strs[] = {
+ "normal",
+ "digest",
+ "nomail",
+ "file",
+ "all"
+};
+
+char * subreason_strs[] = {
+ "request",
+ "confirm",
+ "permit",
+ "admin",
+ "bouncing"
+};
+
void moderate_sub(const char *listdir, const char *listaddr,
const char *listdelim, const char *subaddr,
const char *mlmmjsend, enum subtype typesub)
maildata[3] = replyto;
maildata[5] = moderators;
- queuefilename = prepstdreply(listdir, "submod-moderator",
- "$listowner$", to, replyto, 3, maildata, NULL);
-
+ queuefilename = prepstdreply(listdir,
+ "gatekeep", "sub", NULL, NULL, "submod-moderator",
+ "$listowner$", to, replyto, 3, maildata, NULL);
+
myfree(maildata[1]);
/* we might need to exec more than one mlmmj-send */
/* send mail to requester that the list is submod'ed */
from = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
- queuefilename = prepstdreply(listdir, "submod-requester", "$listowner$",
- subaddr, NULL, 0, NULL, NULL);
-
+ queuefilename = prepstdreply(listdir,
+ "wait", "sub", NULL, NULL, "submod-requester",
+ "$listowner$", subaddr, NULL, 0, NULL, NULL);
+
myfree(listname);
myfree(listfqdn);
execl(mlmmjsend, mlmmjsend,
void confirm_sub(const char *listdir, const char *listaddr,
const char *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub)
+ const char *mlmmjsend, enum subtype typesub, enum subreason reasonsub)
{
char *queuefilename, *fromaddr, *listname, *listfqdn, *listtext;
break;
}
- queuefilename = prepstdreply(listdir, listtext, "$helpaddr$",
- subaddr, NULL, 0, NULL, NULL);
+ queuefilename = prepstdreply(listdir,
+ "finish", "sub",
+ subreason_strs[reasonsub], subtype_strs[typesub],
+ listtext, "$helpaddr$", subaddr, NULL,
+ 0, NULL, NULL);
MY_ASSERT(queuefilename);
myfree(listtext);
void notify_sub(const char *listdir, const char *listaddr,
const char *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub)
+ const char *mlmmjsend, enum subtype typesub, enum subreason reasonsub)
{
char *maildata[2] = { "newsub", NULL };
char *listfqdn, *listname, *fromaddr, *tostr;
break;
}
- queuefilename = prepstdreply(listdir, listtext, "$listowner$",
- "$listowner$", NULL, 1, maildata, NULL);
+ queuefilename = prepstdreply(listdir,
+ "notify", "sub",
+ subreason_strs[reasonsub], subtype_strs[typesub],
+ listtext, "$listowner$", "$listowner$", NULL,
+ 1, maildata, NULL);
MY_ASSERT(queuefilename)
myfree(listtext);
myfree(maildata[1]);
void generate_subconfirm(const char *listdir, const char *listaddr,
const char *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub)
+ const char *mlmmjsend, enum subtype typesub, enum subreason reasonsub)
{
int subconffd;
char *confirmaddr, *listname, *listfqdn, *confirmfilename = NULL;
maildata[1] = mystrdup(subaddr);
maildata[3] = mystrdup(confirmaddr);
- queuefilename = prepstdreply(listdir, listtext, "$helpaddr$", subaddr,
- confirmaddr, 2, maildata, NULL);
+ queuefilename = prepstdreply(listdir,
+ "confirm", "sub",
+ subreason_strs[reasonsub], subtype_strs[typesub],
+ listtext, "$helpaddr$", subaddr, confirmaddr,
+ 2, maildata, NULL);
myfree(maildata[1]);
myfree(maildata[3]);
static void print_help(const char *prg)
{
- printf("Usage: %s -L /path/to/list [-a john@doe.org | -m str]\n"
- " [-c] [-C] [-f] [-h] [-L] [-d | -n] [-s] [-U] [-V]\n"
+ printf("Usage: %s -L /path/to/list {-a john@doe.org | -m str}\n"
+ " [-c | -C] [-f] [-h] [-L] [-d | -n] [-r | -R] [-s] [-U] [-V]\n"
" -a: Email address to subscribe \n"
" -c: Send welcome mail\n"
" -C: Request mail confirmation\n"
" -L: Full path to list directory\n"
" -m: moderation string\n"
" -n: Subscribe to no mail version of list\n", prg);
- printf(" -s: Don't send a mail to subscriber if already subscribed\n"
+ printf(" -r: Behave as if request arrived via email (internal use)\n"
+ " -R: Behave as if confirmation arrived via email (internal use)\n"
+ " -s: Don't send a mail to subscriber if already subscribed\n"
" -U: Don't switch to the user id of the listdir owner\n"
" -V: Print version\n"
"When no options are specified, subscription may be "
fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
myfree(listdelim);
- queuefilename = prepstdreply(listdir, "sub-subscribed", "$helpaddr$",
- subaddr, NULL, 0, NULL, NULL);
+ queuefilename = prepstdreply(listdir,
+ "deny", "sub", "subbed", NULL, "sub-subscribed",
+ "$helpaddr$", subaddr, NULL, 0, NULL, NULL);
MY_ASSERT(queuefilename);
myfree(listaddr);
pid_t pid, childpid;
uid_t uid;
enum subtype typesub = SUB_NORMAL;
+ enum subreason reasonsub = SUB_ADMIN;
CHECKFULLPATH(argv[0]);
mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
myfree(bindir);
- while ((opt = getopt(argc, argv, "hcCdfm:nsVUL:a:")) != -1) {
+ while ((opt = getopt(argc, argv, "hcCdfm:nsVUL:a:rR")) != -1) {
switch(opt) {
case 'a':
address = optarg;
case 'n':
nomail = 1;
break;
+ case 'r':
+ reasonsub = SUB_REQUEST;
+ break;
+ case 'R':
+ reasonsub = SUB_CONFIRM;
+ break;
case 's':
nogensubscribed = 1;
break;
exit(EXIT_FAILURE);
}
- if(modstr)
+ if(modstr) {
getaddrandtype(listdir, modstr, &address, &typesub);
+ reasonsub = SUB_PERMIT;
+ }
if(strchr(address, '@') == NULL) {
log_error(LOG_ARGS, "No '@' sign in '%s', not subscribing",
exit(EXIT_FAILURE);
}
+ if(reasonsub == SUB_CONFIRM && subconfirm) {
+ fprintf(stderr, "Cannot specify both -C and -R\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
/* Make the address lowercase */
lowcaseaddr = mystrdup(address);
i = 0;
unlink(sublockname);
myfree(sublockname);
generate_subconfirm(listdir, listaddr, listdelim,
- address, mlmmjsend, typesub);
+ address, mlmmjsend, typesub, reasonsub);
} else {
if(modstr == NULL)
submod = !force && statctrl(listdir, "submod");
if(childpid < 0) {
log_error(LOG_ARGS, "Could not fork; owner not notified");
confirm_sub(listdir, listaddr, listdelim, address,
- mlmmjsend, typesub);
+ mlmmjsend, typesub, reasonsub);
}
if(childpid > 0) {
/* child confirms subscription */
if(childpid == 0)
confirm_sub(listdir, listaddr, listdelim, address,
- mlmmjsend, typesub);
+ mlmmjsend, typesub, reasonsub);
}
notifysub = statctrl(listdir, "notifysub");
/* Notify list owner about subscription */
if (notifysub)
notify_sub(listdir, listaddr, listdelim, address, mlmmjsend,
- typesub);
+ typesub, reasonsub);
myfree(address);
myfree(listaddr);
void confirm_unsub(const char *listdir, const char *listaddr,
const char *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub)
+ const char *mlmmjsend,
+ enum subtype typesub, enum subreason reasonsub)
{
char *queuefilename, *fromaddr, *listname, *listfqdn, *listtext;
break;
}
- queuefilename = prepstdreply(listdir, listtext, "$helpaddr$",
- subaddr, NULL, 0, NULL, NULL);
+ queuefilename = prepstdreply(listdir,
+ "finish", "unsub",
+ subreason_strs[reasonsub], subtype_strs[typesub],
+ listtext, "$helpaddr$", subaddr, NULL, 0, NULL, NULL);
MY_ASSERT(queuefilename);
myfree(listtext);
void notify_unsub(const char *listdir, const char *listaddr,
const char *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub)
+ const char *mlmmjsend,
+ enum subtype typesub, enum subreason reasonsub)
{
char *maildata[4] = { "oldsub", NULL };
char *listfqdn, *listname, *fromaddr, *tostr;
break;
}
- queuefilename = prepstdreply(listdir, listtext, "$listowner$",
- "$listowner$", NULL, 1, maildata, NULL);
+ queuefilename = prepstdreply(listdir,
+ "notify", "unsub",
+ subreason_strs[reasonsub], subtype_strs[typesub],
+ listtext, "$listowner$", "$listowner$", NULL,
+ 1, maildata, NULL);
MY_ASSERT(queuefilename);
myfree(listtext);
myfree(maildata[1]);
void generate_unsubconfirm(const char *listdir, const char *listaddr,
const char *listdelim, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub)
+ const char *mlmmjsend,
+ enum subtype typesub, enum subreason reasonsub)
{
char *confirmaddr, *listname, *listfqdn, *tmpstr;
char *queuefilename, *fromaddr;
maildata[1] = mystrdup(subaddr);
maildata[3] = mystrdup(confirmaddr);
- queuefilename = prepstdreply(listdir, listtext, "$helpaddr$", subaddr,
- confirmaddr, 2, maildata, NULL);
+ queuefilename = prepstdreply(listdir,
+ "confirm", "unsub",
+ subreason_strs[reasonsub], subtype_strs[typesub],
+ listtext, "$helpaddr$", subaddr, confirmaddr,
+ 2, maildata, NULL);
myfree(maildata[1]);
myfree(maildata[3]);
static void print_help(const char *prg)
{
printf("Usage: %s -L /path/to/list -a john@doe.org\n"
- " [-c] [-C] [-h] [-L] [-d | -n] [-s] [-V]\n"
+ " [-b] [-c | -C] [-h] [-L] [-d | -n] [-r | -R] [-s] [-V]\n"
" -a: Email address to unsubscribe \n"
+ " -b: Behave as if unsubscription is due to bouncing (internal use)\n"
" -c: Send goodbye mail\n"
" -C: Request mail confirmation\n"
" -d: Unsubscribe from digest of list\n"
" -h: This help\n"
" -L: Full path to list directory\n"
- " -n: Unsubscribe from no mail version of list\n"
+ " -n: Unsubscribe from no mail version of list\n", prg);
+ printf(" -r: Behave as if request arrived via email (internal use)\n"
+ " -R: Behave as if confirmation arrived via email (internal use)\n"
" -s: Don't send a mail to the address if not subscribed\n"
" -U: Don't switch to the user id of the listdir owner\n"
" -V: Print version\n"
"When no options are specified, unsubscription silently "
- "happens\n", prg);
+ "happens\n");
exit(EXIT_SUCCESS);
}
fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
myfree(listdelim);
- queuefilename = prepstdreply(listdir, "unsub-notsubscribed",
- "$helpaddr$", subaddr, NULL, 0, NULL, NULL);
+ queuefilename = prepstdreply(listdir,
+ "deny", "unsub", "unsubbed", NULL,
+ "unsub-notsubscribed", "$helpaddr$", subaddr, NULL,
+ 0, NULL, NULL);
MY_ASSERT(queuefilename);
myfree(listaddr);
struct dirent *dp;
pid_t pid, childpid;
enum subtype typesub = SUB_NORMAL;
+ enum subreason reasonsub = SUB_ADMIN;
uid_t uid;
struct stat st;
mlmmjsend = concatstr(2, bindir, "/mlmmj-send");
myfree(bindir);
- while ((opt = getopt(argc, argv, "hcCdnVUL:a:s")) != -1) {
+ while ((opt = getopt(argc, argv, "hcCdnVUL:a:sbrR")) != -1) {
switch(opt) {
case 'L':
listdir = optarg;
case 'a':
address = optarg;
break;
+ case 'b':
+ reasonsub = SUB_BOUNCING;
+ break;
case 'c':
confirmunsub = 1;
break;
case 'h':
print_help(argv[0]);
break;
+ case 'r':
+ reasonsub = SUB_REQUEST;
+ break;
+ case 'R':
+ reasonsub = SUB_CONFIRM;
+ break;
case 's':
nogennotsubscribed = 1;
break;
exit(EXIT_FAILURE);
}
+ if(reasonsub == SUB_CONFIRM && unsubconfirm) {
+ fprintf(stderr, "Cannot specify both -C and -R\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if(reasonsub == SUB_BOUNCING && unsubconfirm) {
+ fprintf(stderr, "Cannot specify both -C and -b\n");
+ fprintf(stderr, "%s -h for help\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
/* Make the address lowercase */
lowcaseaddr = mystrdup(address);
i = 0;
listdelim = getlistdelim(listdir);
if(unsubconfirm)
generate_unsubconfirm(listdir, listaddr, listdelim, address,
- mlmmjsend, typesub);
+ mlmmjsend, typesub, reasonsub);
if((subddir = opendir(subddirname)) == NULL) {
log_error(LOG_ARGS, "Could not opendir(%s)",
if(childpid < 0) {
log_error(LOG_ARGS, "Could not fork");
confirm_unsub(listdir, listaddr, listdelim,
- address, mlmmjsend, digest);
+ address, mlmmjsend,
+ typesub, reasonsub);
}
if(childpid > 0) {
/* child confirms subscription */
if(childpid == 0)
confirm_unsub(listdir, listaddr, listdelim,
- address, mlmmjsend, digest);
+ address, mlmmjsend,
+ typesub, reasonsub);
}
}
/* Notify list owner about subscription */
if (notifysub)
notify_unsub(listdir, listaddr, listdelim, address, mlmmjsend,
- typesub);
+ typesub, reasonsub);
myfree(listaddr);
myfree(listdelim);
if (fd >= 0)
return fd;
- log_error(LOG_ARGS, "Could not open listtext '%s'", filename);
return -1;
}
-char *prepstdreply(const char *listdir, const char *filename, const char *from,
- const char *to, const char *replyto, size_t tokencount,
- char **data, const char *mailname)
+char *prepstdreply(const char *listdir, const char *purpose, const char *action,
+ const char *reason, const char *type, const char *compat,
+ const char *from, const char *to, const char *replyto,
+ size_t tokencount, char **data, const char *mailname)
{
- size_t i, len;
+ size_t filenamelen, i, len;
int infd, outfd, mailfd;
- char *listaddr, *listdelim, *tmp, *retstr = NULL;
+ char *filename, *listaddr, *listdelim, *tmp, *retstr = NULL;
char *listfqdn, *line, *utfline, *utfsub, *utfsub2;
char *str = NULL;
char **moredata;
char *headers[10] = { NULL }; /* relies on NULL to flag end */
- if ((infd = open_listtext(listdir, filename)) < 0) {
+ filename = concatstr(7,purpose,"-",action,"-",reason,"-",type);
+ filenamelen = strlen(filename);
+ do {
+ if ((infd = open_listtext(listdir, filename)) >= 0) break;
+ len = type ? strlen(type) : 0;
+ filename[filenamelen-len-1] = '\0';
+ if ((infd = open_listtext(listdir, filename)) >= 0) break;
+ filename[filenamelen-len-1] = '-';
+ filenamelen -= len + 1;
+ len = reason ? strlen(reason) : 0;
+ filename[filenamelen-len-1] = '\0';
+ if ((infd = open_listtext(listdir, filename)) >= 0) break;
+ filename[filenamelen-len-1] = '-';
+ filenamelen -= len + 1;
+ len = action ? strlen(action) : 0;
+ filename[filenamelen-len-1] = '\0';
+ if ((infd = open_listtext(listdir, filename)) >= 0) break;
+ filename[filenamelen-len-1] = '-';
+ filenamelen -= len + 1;
+ if ((infd = open_listtext(listdir, compat)) >= 0) {
+ myfree(filename);
+ filename = mystrdup(compat);
+ break;
+ }
+ log_error(LOG_ARGS, "Could not open listtext '%s'", filename);
+ myfree(filename);
return NULL;
- }
+ } while (0);
listaddr = getlistaddr(listdir);
listdelim = getlistdelim(listdir);
myfree(listdelim);
myfree(listfqdn);
myfree(retstr);
+ myfree(filename);
return NULL;
}
}
myfree(moredata);
+ myfree(filename);
+
return retstr;
}
txtfd = open_listtext(listdir, "digest");
if (txtfd < 0) {
- log_error(LOG_ARGS, "Notice: Could not open std mail digest");
+ log_error(LOG_ARGS, "Could not open listtext 'digest'");
}
subst_data[0] = "digestfirst";
#include "memory.h"
void send_help(const char *listdir, const char *emailaddr,
- const char *mlmmjsend, const char *name, const char *textfile)
+ const char *mlmmjsend, const char *purpose, const char *action,
+ const char *reason, const char *type, const char *compat)
{
char *queuefilename, *listaddr, *listdelim, *listname, *listfqdn;
char *fromaddr;
fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
myfree(listdelim);
- queuefilename = prepstdreply(listdir, textfile, "$listowner$",
- emailaddr, NULL, 0, NULL, NULL);
+ queuefilename = prepstdreply(listdir,
+ purpose, action, reason, type, compat,
+ "$listowner$", emailaddr, NULL, 0, NULL, NULL);
if(queuefilename == NULL) {
- log_error(LOG_ARGS, "Could not prepare %s mail", name);
+ if (action == NULL) action = "";
+ if (reason == NULL) reason = "";
+ if (type == NULL) type = "";
+ log_error(LOG_ARGS, "Could not prepare %s-%s-%s-%s mail",
+ purpose, action, reason, type);
exit(EXIT_FAILURE);
}
fromaddr = concatstr(4, listname, listdelim, "bounces-help@", listfqdn);
myfree(listdelim);
- queuefilename = prepstdreply(listdir, "listsubs", "$listowner$",
- emailaddr, NULL, 0, NULL, NULL);
+ queuefilename = prepstdreply(listdir,
+ "list", NULL, NULL, subtype_strs[SUB_ALL],
+ "listsubs", "$listowner$", emailaddr, NULL,
+ 0, NULL, NULL);
if(queuefilename == NULL) {
log_error(LOG_ARGS, "Could not prepare sub list mail");
exit(EXIT_FAILURE);