struct ctrl_command *get_ctrl_command(const char *controlstr, char **param);
int listcontrol(strlist *fromemails, struct ml *ml,
- const char *controlstr, const char *mlmmjsub,
- const char *mlmmjsend, const char *mailname);
+ const char *controlstr, const char *mlmmjsend,
+ const char *mailname);
#endif /* LISTCONTROL_H */
#include <stdbool.h>
+struct subscription {
+ bool send_welcome_email;
+ const char *modstr;
+ enum subreason reasonsub;
+ enum subtype typesub;
+ bool gensubscribed;
+ bool subconfirm;
+ bool force;
+ bool quiet;
+ const char *mlmmjsend;
+};
+
bool find_subscriber(int fd, const char *address);
int is_subbed_in(int fd, const char *subddirname, const char *address);
enum subtype is_subbed(int listfd, const char *address, bool both);
void send_confirmation_mail(struct ml *ml, const char *subaddr, enum subtype typesub, enum subreason reasonsub, bool sub);
bool do_unsubscribe(struct ml *ml, const char *addr, enum subtype typesub, enum subreason reasonsub, bool inform_not_subscribed, bool confirm_unsubscription, bool quiet, bool send_goodbye_mail);
void mod_get_addr_and_type(struct ml *ml, const char *modstr, char **addrptr, enum subtype *subtypeptr);
+bool do_subscribe(struct ml *ml, struct subscription *sub, const char *addr);
struct listcontrol {
const char *fromemail;
- const char *mlmmjsub;
- bool nosubconfirm;
+ const char *mlmmjsend;
+ bool subconfirm;
};
struct sub {
const char *ctrlstr;
const char *type;
const char *typedeny;
- const char *arg;
+ enum subtype typesub;
};
static bool
if (!is_valid_email(lc->fromemail, sub->typereq))
exit(EXIT_FAILURE);
- if (statctrl(ml->ctrlfd, sub->ctrlstr)) {
+ if (sub->ctrlstr != NULL && statctrl(ml->ctrlfd, sub->ctrlstr)) {
char *queuefilename;
text *txt;
errno = 0;
}
log_oper(ml->fd, OPLOGFNAME, "mlmmj-sub: request for %s"
" subscription from %s", sub->type, lc->fromemail);
- exec_or_die(lc->mlmmjsub, "-L", ml->dir, "-a",
- lc->fromemail, sub->arg, "-r", "-c",
- (lc->nosubconfirm ? NULL : "-C"), NULL);
+ struct subscription subc = { 0 };
+ subc.subconfirm = lc->subconfirm;
+ subc.send_welcome_email = true;
+ subc.reasonsub = SUB_REQUEST;
+ subc.typesub = sub->typesub;
+ subc.gensubscribed = true;
+ exit(do_subscribe(ml, &subc, lc->fromemail) ? EXIT_SUCCESS : EXIT_FAILURE);
}
struct ctrl_command *
return (NULL);
}
-int listcontrol(strlist *fromemails, struct ml *ml,
- const char *controlstr, const char *mlmmjsub,
- const char *mlmmjsend, const char *mailname)
+int listcontrol(strlist *fromemails, struct ml *ml, const char *controlstr,
+ const char *mlmmjsend, const char *mailname)
{
char *bouncenr, *tmpstr;
char *param = NULL, *moderatefilename, *gatekeepfilename;
text *txt;
char *queuefilename;
enum subtype ts = SUB_NONE;
- const char *subtype = NULL;
const char *subtypename = NULL;
bounce_t bret;
struct ctrl_command *cc;
struct listcontrol lc = { 0 };
struct sub sub = { 0 };
+ struct subscription subc = { 0 };
- lc.nosubconfirm = statctrl(ml->ctrlfd, "nosubconfirm");
+ lc.subconfirm = !statctrl(ml->ctrlfd, "nosubconfirm");
#if 0
log_error(LOG_ARGS, "controlstr = [%s]\n", controlstr);
if (tll_length(*fromemails) >= 1)
lc.fromemail = tll_front(*fromemails);
- lc.mlmmjsub = mlmmjsub;
+ lc.mlmmjsend = mlmmjsend;
/* We only need the control mail when bouncing, to save bounced msg */
if (cc->type != CTRL_BOUNCES)
sub.typereq = "A subscribe-digest";
sub.ctrlstr = "nodigestsub";
sub.type = "digest";
+ sub.typesub = SUB_DIGEST;
sub.typedeny = "sub-deny-digest";
- sub.arg = "-d";
__attribute__ ((fallthrough));
/* listname+subscribe-nomail@domain.tld */
case CTRL_SUBSCRIBE_NOMAIL:
if (sub.typereq == NULL) {
sub.typereq = "A subscribe-nomail";
sub.ctrlstr = "nomailsub";
+ sub.typesub = SUB_NOMAIL;
sub.type = "nomail";
sub.typedeny = "sub-deny-nomail";
- sub.arg = "-n";
}
__attribute__ ((fallthrough));
/* listname+subscribe-both@domain.tld */
if (sub.typereq == NULL) {
sub.typereq = "A subscribe-both";
sub.ctrlstr = "nodigestsub";
+ sub.typesub = SUB_BOTH;
sub.type = "both";
sub.typedeny = "sub-deny-digest";
- sub.arg = "-b";
}
- lc_sub(&lc, ml, &sub);
- break;
-
+ __attribute__ ((fallthrough));
/* listname+subscribe@domain.tld */
case CTRL_SUBSCRIBE:
- if (!is_valid_email(lc.fromemail, "A subscribe"))
- return -1;
- log_oper(ml->fd, OPLOGFNAME, "mlmmj-sub: request for regular"
- " subscription from %s", lc.fromemail);
- exec_or_die(mlmmjsub, "-L", ml->dir, "-a",
- lc.fromemail, "-r", "-c",
- (lc.nosubconfirm ? NULL : "-C"), NULL);
+ if (sub.typereq == NULL) {
+ sub.typereq = "A subcribe";
+ sub.ctrlstr = NULL;
+ sub.type = "regular";
+ sub.typesub = SUB_NORMAL;
+ }
+ lc_sub(&lc, ml, &sub);
break;
/* listname+subconf-digest-COOKIE@domain.tld */
case CTRL_CONFSUB_DIGEST:
- subtype = "-d";
+ subc.typesub = SUB_DIGEST;
subtypename = "digest";
__attribute__ ((fallthrough));
/* listname+subconf-nomail-COOKIE@domain.tld */
case CTRL_CONFSUB_NOMAIL:
- if (subtype == NULL) {
- subtype = "-n";
+ if (subtypename == NULL) {
+ subc.typesub = SUB_NOMAIL;
subtypename = "nomail";
}
__attribute__ ((fallthrough));
/* listname+subconf-both-COOKIE@domain.tld */
case CTRL_CONFSUB_BOTH:
- if (subtype == NULL) {
- subtype = "-b";
+ if (subtypename == NULL) {
+ subc.typesub = SUB_BOTH;
subtypename = "both";
}
- tmpstr = get_subcookie_content(ml->fd, false, param);
- if (tmpstr == NULL) {
- /* invalid COOKIE */
- errno = 0;
- log_error(LOG_ARGS, "A subconf request was"
- " sent with a mismatching cookie."
- " Ignoring mail");
- return -1;
- }
- log_oper(ml->fd, OPLOGFNAME, "mlmmj-sub: %s confirmed"
- " subscription to %s", tmpstr, subtypename);
- exec_or_die(mlmmjsub, "-L", ml->dir, "-a", tmpstr, subtype,
- "-R", "-c", NULL);
- break;
-
+ __attribute__ ((fallthrough));
/* listname+subconf-COOKIE@domain.tld */
case CTRL_CONFSUB:
+ if (subtypename == NULL) {
+ subc.typesub = SUB_NORMAL;
+ subtypename = "regular list";
+ }
tmpstr = get_subcookie_content(ml->fd, false, param);
if (tmpstr == NULL) {
/* invalid COOKIE */
" Ignoring mail");
return -1;
}
+ subc.send_welcome_email = true;
+ subc.reasonsub = SUB_CONFIRM;
+ subc.gensubscribed = true;
+ subc.mlmmjsend = lc.mlmmjsend;
log_oper(ml->fd, OPLOGFNAME, "mlmmj-sub: %s confirmed"
- " subscription to regular list", tmpstr);
- exec_or_die(mlmmjsub, "-L", ml->dir, "-a", tmpstr,
- "-R", "-c", NULL);
- break;
+ " subscription to %s", tmpstr, subtypename);
+ exit(do_subscribe(ml, &subc, tmpstr) ? EXIT_SUCCESS : EXIT_FAILURE);
/* DEPRECATED: listname+unsubscribe-digest@domain.tld */
case CTRL_UNSUBSCRIBE_DIGEST:
log_oper(ml->fd, OPLOGFNAME, "mlmmj-unsub: %s requests"
" unsubscribe", lc.fromemail);
do_unsubscribe(ml, lc.fromemail, SUB_ALL, SUB_REQUEST,
- false, !lc.nosubconfirm, false, lc.nosubconfirm);
+ false, lc.subconfirm, false, lc.subconfirm);
exit(EXIT_SUCCESS);
break;
}
log_oper(ml->fd, OPLOGFNAME, "%s permitted %s",
lc.fromemail, param);
- exec_or_die(mlmmjsub, "-L", ml->dir, "-m", param, "-c", NULL);
+ subc.modstr = param;
+ subc.send_welcome_email = true;
+ subc.gensubscribed = true;
+ subc.reasonsub = SUB_PERMIT;
+ subc.mlmmjsend = lc.mlmmjsend;
+ exit(do_subscribe(ml, &subc, tmpstr) ? EXIT_SUCCESS : EXIT_FAILURE);
break;
/* listname+obstruct-COOKIE@domain.tld */
bool subonlypost, modonlypost, modnonsubposts, foundaddr = false;
char *mailfile = NULL, *donemailname = NULL;
char *randomstr = NULL, *mqueuename, *omitfilename;
- char *mlmmjsend, *mlmmjsub;
+ char *mlmmjsend;
char *bindir, *subjectprefix, *discardname;
text *txt;
char *queuefilename, *recipextra = NULL, *owner = NULL;
bindir = mydirname(argv[0]);
xasprintf(&mlmmjsend, "%s/mlmmj-send", bindir);
- xasprintf(&mlmmjsub, "%s/mlmmj-sub", bindir);
free(bindir);
while ((opt = getopt(argc, argv, "hVPm:L:")) != -1) {
else
testfrom = &fromemails;
listcontrol(testfrom, &ml, recipextra,
- mlmmjsub, mlmmjsend, donemailname);
+ mlmmjsend, donemailname);
return EXIT_SUCCESS;
}
extern char *subtypes[];
-static void moderate_sub(struct ml *ml, const char *subaddr,
- const char *mlmmjsend, enum subtype typesub,
- enum subreason reasonsub)
-{
- int fd, status;
- text *txt;
- memory_lines_state *mls;
- char *a = NULL, *queuefilename, *from;
- char *modfilename, *mods, *to, *replyto, *moderators = NULL;
- char *cookie, *obstruct;
- strlist *submods;
- const char *type;
- pid_t childpid, pid;
- xstring *str = NULL;
- int modfd = -1;
-
- type = subtypes[typesub];
-
- for (;;) {
- cookie = random_str();
- xasprintf(&modfilename, "moderation/subscribe%s", cookie);
- fd = openat(ml->fd, modfilename, O_RDWR|O_CREAT|O_EXCL,
- S_IRUSR|S_IWUSR);
- if (fd < 0) {
- if (errno == EEXIST) {
- free(cookie);
- free(modfilename);
- continue;
- }
- log_error(LOG_ARGS, "could not create %s"
- "ignoring request for: %s", subaddr);
- exit(EXIT_FAILURE);
- }
- break;
- }
-
- if (dprintf(fd, "%s\n%s\n", subaddr, type) < 0) {
- log_error(LOG_ARGS, "could not write to %s"
- "ignoring request for: %s", subaddr);
- exit(EXIT_FAILURE);
- }
- close(fd);
-
- submods = ctrlvalues(ml->ctrlfd, "submod");
- if (submods == NULL)
- return;
- /* check to see if there's adresses in the submod control file */
- tll_foreach(*submods, it)
- a = strchr(it->item, '@');
-
- /* no addresses in submod control file, use owner */
- if(a == NULL) {
- /* free the submods struct from above */
- tll_free_and_free(*submods, free);
- free(submods);
- submods = ctrlvalues(ml->ctrlfd, "owner");
- modfd = openat(ml->ctrlfd, "owner", O_RDONLY);
- }
- if (modfd == -1)
- modfd = openat(ml->ctrlfd, "submod", O_RDONLY);
-
- gen_addr(from, ml, "owner");
- xasprintf(&to, "%s-moderators@%s", ml->name, ml->fqdn);
- gen_addr_cookie(replyto, ml, "permit-", cookie);
- gen_addr_cookie(obstruct, ml, "obstruct-", cookie);
- free(cookie);
- tll_foreach(*submods, sm) {
- if (str == NULL)
- str = xstring_new();
- fprintf(str->fp, "%s\n", sm->item);
- }
- moderators = xstring_get(str);
- mls = init_memory_lines(moderators);
- free(moderators);
-
- txt = open_text(ml->fd,
- "gatekeep", "sub",
- subreason_strs[reasonsub], subtype_strs[typesub],
- "submod-moderator");
- MY_ASSERT(txt);
- register_default_unformatted(txt, ml);
- register_unformatted(txt, "subaddr", subaddr);
- register_unformatted(txt, "moderateaddr", replyto); /* DEPRECATED */
- register_unformatted(txt, "permitaddr", replyto);
- register_unformatted(txt, "obstructaddr", obstruct);
- register_unformatted(txt, "moderators", "%gatekeepers%"); /* DEPRECATED */
- register_formatted(txt, "gatekeepers",
- rewind_memory_lines, get_memory_line, mls);
- queuefilename = prepstdreply(txt, ml, "$listowner$", to, replyto);
- MY_ASSERT(queuefilename);
- close_text(txt);
-
- /* we might need to exec more than one mlmmj-send */
-
- if (statctrl(ml->ctrlfd, "nosubmodmails"))
- childpid = -1;
- else {
- childpid = fork();
- if(childpid < 0)
- log_error(LOG_ARGS, "Could not fork; requester not notified");
- }
-
- if(childpid != 0) {
- if(childpid > 0) {
- do /* Parent waits for the child */
- pid = waitpid(childpid, &status, 0);
- while(pid == -1 && errno == EINTR);
- }
- finish_memory_lines(mls);
- xasprintf(&mods, "%d", modfd);
- execl(mlmmjsend, mlmmjsend,
- "-a",
- "-l", "4",
- "-L", ml->dir,
- "-s", mods,
- "-F", from,
- "-R", replyto,
- "-m", queuefilename, (char *)NULL);
- log_error(LOG_ARGS, "execl() of '%s' failed", mlmmjsend);
- exit(EXIT_FAILURE);
- }
-
- free(to);
- free(replyto);
-
- /* send mail to requester that the list is submod'ed */
-
- txt = open_text(ml->fd,
- "wait", "sub",
- subreason_strs[reasonsub], subtype_strs[typesub],
- "submod-requester");
- MY_ASSERT(txt);
- register_default_unformatted(txt, ml);
- register_unformatted(txt, "subaddr", subaddr);
- register_unformatted(txt, "moderators", "%gatekeepers"); /* DEPRECATED */
- register_formatted(txt, "gatekeepers",
- rewind_memory_lines, get_memory_line, mls);
- queuefilename = prepstdreply(txt, ml, "$listowner$", subaddr, NULL);
- MY_ASSERT(queuefilename);
- close_text(txt);
-
- finish_memory_lines(mls);
- send_help(ml, queuefilename, subaddr);
-}
-
static void print_help(const char *prg)
{
printf("Usage: %s -L /path/to/list {-a john@doe.org | -m str}\n"
exit(EXIT_SUCCESS);
}
-static void subscribe_type(int listfd, char *address, enum subtype typesub) {
- int dirfd;;
- char chstr[2];
- const char *subdir;
- int groupwritable = 0, subfilefd;
- struct stat st;
-
- dirfd = open_subscriber_directory(listfd, typesub, &subdir);
- if (dirfd == -1)
- err(EXIT_FAILURE, "cannot open(%s)", subdir);
- if (fstat(dirfd, &st) == 0) {
- if(st.st_mode & S_IWGRP) {
- groupwritable = S_IRGRP|S_IWGRP;
- umask(S_IWOTH);
- setgid(st.st_gid);
- }
- }
-
- chstr[0] = address[0];
- chstr[1] = '\0';
-
- subfilefd = openat(dirfd, chstr, O_RDWR|O_CREAT|O_APPEND,
- S_IRUSR|S_IWUSR|groupwritable);
- if(subfilefd == -1 && !lock(subfilefd, true)) {
- log_error(LOG_ARGS, "Could not open '%s/%s'", subdir, chstr);
- exit(EXIT_FAILURE);
- }
-
- dprintf(subfilefd, "%s\n", address);
- close(dirfd);
- close(subfilefd);
-}
int main(int argc, char **argv)
{
char *mlmmjsend, *bindir;
- char *address = NULL, *modstr = NULL;
- bool send_welcome_mail = false;
+ char *address = NULL;
+ struct subscription sub = { 0 };
int opt;
- bool subconfirm = false, notifysub;
bool changeuid = true, digest = false, nomail = false, both = false;
- bool nogensubscribed = false;
- bool force = false, quiet = false;
- enum subtype subbed;
struct stat st;
uid_t uid;
- enum subtype typesub = SUB_NORMAL;
- enum subreason reasonsub = SUB_ADMIN;
struct ml ml;
ml_init(&ml);
bindir = mydirname(argv[0]);
xasprintf(&mlmmjsend, "%s/mlmmj-send", bindir);
free(bindir);
+ sub.reasonsub = SUB_ADMIN;
+ sub.typesub = SUB_NORMAL;
+ sub.gensubscribed = true;
+ sub.mlmmjsend = mlmmjsend;
while ((opt = getopt(argc, argv, "hbcCdfm:nsVUL:a:qrR")) != -1) {
switch(opt) {
both = true;
break;
case 'c':
- send_welcome_mail = true;
+ sub.send_welcome_email = true;
break;
case 'C':
- subconfirm = true;
+ sub.subconfirm = true;
break;
case 'd':
digest = true;
break;
case 'f':
- force = true;
+ sub.force = true;
break;
case 'h':
print_help(argv[0]);
ml.dir = optarg;
break;
case 'm':
- modstr = optarg;
+ sub.modstr = optarg;
break;
case 'n':
nomail = true;
break;
case 'q':
- quiet = true;
+ sub.quiet = true;
break;
case 'r':
- reasonsub = SUB_REQUEST;
+ sub.reasonsub = SUB_REQUEST;
break;
case 'R':
- reasonsub = SUB_CONFIRM;
+ sub.reasonsub = SUB_CONFIRM;
break;
case 's':
- nogensubscribed = true;
+ sub.gensubscribed = false;
break;
case 'U':
changeuid = false;
if (!ml_open(&ml, false))
exit(EXIT_FAILURE);
- if(address == NULL && modstr == NULL) {
+ if(address == NULL && sub.modstr == NULL) {
errx(EXIT_FAILURE, "You have to specify -a or -m\n"
"%s -h for help", argv[0]);
}
}
if(digest)
- typesub = SUB_DIGEST;
+ sub.typesub = SUB_DIGEST;
if(nomail)
- typesub = SUB_NOMAIL;
+ sub.typesub = SUB_NOMAIL;
if(both)
- typesub = SUB_BOTH;
+ sub.typesub = SUB_BOTH;
- if(reasonsub == SUB_CONFIRM && subconfirm) {
+ if(sub.reasonsub == SUB_CONFIRM && sub.subconfirm) {
errx(EXIT_FAILURE, "Cannot specify both -C and -R\n"
"%s -h for help", argv[0]);
}
- if(modstr) {
- mod_get_addr_and_type(&ml, modstr, &address, &typesub);
- reasonsub = SUB_PERMIT;
- }
-
- /* Make the address lowercase */
- address = lowercase(address);
-
- if(strncasecmp(ml.addr, address, strlen(ml.addr)) == 0) {
- free(address);
- errx(EXIT_FAILURE, "Cannot subscribe the list address to the list");
- }
-
if(changeuid) {
uid = getuid();
if(!uid && fstat(ml.fd, &st) == 0 && uid != st.st_uid) {
}
}
- subbed = is_subbed(ml.fd, address, 1);
-
- if(subbed == typesub) {
- if(!nogensubscribed)
- generate_subscription(&ml, address, typesub, true);
- return EXIT_SUCCESS;
- } else if(subbed != SUB_NONE) {
- reasonsub = SUB_SWITCH;
- /* If we want to subscribe to both, we can just subscribe the
- * missing version, so don't unsub. */
- if (!(typesub == SUB_BOTH &&
- subbed != SUB_NOMAIL)) {
- enum subtype ts = SUB_ALL;
- if (subbed == SUB_BOTH) {
- if (typesub == SUB_NORMAL) ts = SUB_DIGEST;
- if (typesub == SUB_DIGEST) ts = SUB_NORMAL;
- }
- if (!unsubscribe(ml.fd, address, ts))
- log_error(LOG_ARGS, "not unsubscribed from "
- "current version");
- }
- }
-
- if(subbed == SUB_NONE && subconfirm)
- generate_subconfirm(&ml, address, typesub, reasonsub, true);
-
- if(modstr == NULL && subbed == SUB_NONE && !force &&
- statctrl(ml.ctrlfd, "submod")) {
- moderate_sub(&ml, address, mlmmjsend, typesub, reasonsub);
- }
-
- if (typesub == SUB_BOTH) {
- if (subbed != SUB_NORMAL) {
- subscribe_type(ml.fd, address, SUB_NORMAL);
- }
- if (subbed != SUB_DIGEST) {
- subscribe_type(ml.fd, address, SUB_DIGEST);
- }
- } else if (!(subbed == SUB_BOTH && typesub != SUB_NOMAIL)) {
- subscribe_type(ml.fd, address, typesub);
- }
-
- if(send_welcome_mail)
- send_confirmation_mail(&ml, address, typesub, reasonsub, true);
-
- notifysub = !quiet && reasonsub != SUB_SWITCH &&
- statctrl(ml.ctrlfd, "notifysub");
-
- /* Notify list owner about subscription */
- if (notifysub)
- notify_sub(&ml, address, typesub, reasonsub, true);
-
- free(address);
- free(mlmmjsend);
-
- return EXIT_SUCCESS;
+ if (do_subscribe(&ml, &sub, address))
+ exit(EXIT_SUCCESS);
+ exit(EXIT_FAILURE);
}
*/
#include <sys/stat.h>
+#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
+#include <err.h>
#include "mlmmj.h"
#include "subscriberfuncs.h"
#include "strgen.h"
#include "send_help.h"
#include "statctrl.h"
+#include "xstring.h"
+#include "ctrlvalues.h"
char *subtype_strs[] = {
"normal",
close(dfd);
free(modfilename);
}
+
+static void moderate_sub(struct ml *ml, const char *subaddr,
+ struct subscription *sub)
+{
+ int fd, status;
+ text *txt;
+ memory_lines_state *mls;
+ char *a = NULL, *queuefilename, *from;
+ char *modfilename, *mods, *to, *replyto, *moderators = NULL;
+ char *cookie, *obstruct;
+ strlist *submods;
+ const char *type;
+ pid_t childpid, pid;
+ xstring *str = NULL;
+ int modfd = -1;
+
+ type = subtypes[sub->typesub];
+
+ for (;;) {
+ cookie = random_str();
+ xasprintf(&modfilename, "moderation/subscribe%s", cookie);
+ fd = openat(ml->fd, modfilename, O_RDWR|O_CREAT|O_EXCL,
+ S_IRUSR|S_IWUSR);
+ if (fd < 0) {
+ if (errno == EEXIST) {
+ free(cookie);
+ free(modfilename);
+ continue;
+ }
+ log_error(LOG_ARGS, "could not create %s"
+ "ignoring request for: %s", subaddr);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+
+ if (dprintf(fd, "%s\n%s\n", subaddr, type) < 0) {
+ log_error(LOG_ARGS, "could not write to %s"
+ "ignoring request for: %s", subaddr);
+ exit(EXIT_FAILURE);
+ }
+ close(fd);
+
+ submods = ctrlvalues(ml->ctrlfd, "submod");
+ if (submods == NULL)
+ return;
+ /* check to see if there's adresses in the submod control file */
+ tll_foreach(*submods, it)
+ a = strchr(it->item, '@');
+
+ /* no addresses in submod control file, use owner */
+ if(a == NULL) {
+ /* free the submods struct from above */
+ tll_free_and_free(*submods, free);
+ free(submods);
+ submods = ctrlvalues(ml->ctrlfd, "owner");
+ modfd = openat(ml->ctrlfd, "owner", O_RDONLY);
+ }
+ if (modfd == -1)
+ modfd = openat(ml->ctrlfd, "submod", O_RDONLY);
+
+ gen_addr(from, ml, "owner");
+ xasprintf(&to, "%s-moderators@%s", ml->name, ml->fqdn);
+ gen_addr_cookie(replyto, ml, "permit-", cookie);
+ gen_addr_cookie(obstruct, ml, "obstruct-", cookie);
+ free(cookie);
+ tll_foreach(*submods, sm) {
+ if (str == NULL)
+ str = xstring_new();
+ fprintf(str->fp, "%s\n", sm->item);
+ }
+ moderators = xstring_get(str);
+ mls = init_memory_lines(moderators);
+ free(moderators);
+
+ txt = open_text(ml->fd,
+ "gatekeep", "sub",
+ subreason_strs[sub->reasonsub], subtype_strs[sub->typesub],
+ "submod-moderator");
+ MY_ASSERT(txt);
+ register_default_unformatted(txt, ml);
+ register_unformatted(txt, "subaddr", subaddr);
+ register_unformatted(txt, "moderateaddr", replyto); /* DEPRECATED */
+ register_unformatted(txt, "permitaddr", replyto);
+ register_unformatted(txt, "obstructaddr", obstruct);
+ register_unformatted(txt, "moderators", "%gatekeepers%"); /* DEPRECATED */
+ register_formatted(txt, "gatekeepers",
+ rewind_memory_lines, get_memory_line, mls);
+ queuefilename = prepstdreply(txt, ml, "$listowner$", to, replyto);
+ MY_ASSERT(queuefilename);
+ close_text(txt);
+
+ /* we might need to exec more than one mlmmj-send */
+
+ if (statctrl(ml->ctrlfd, "nosubmodmails"))
+ childpid = -1;
+ else {
+ childpid = fork();
+ if(childpid < 0)
+ log_error(LOG_ARGS, "Could not fork; requester not notified");
+ }
+
+ if(childpid != 0) {
+ if(childpid > 0) {
+ do /* Parent waits for the child */
+ pid = waitpid(childpid, &status, 0);
+ while(pid == -1 && errno == EINTR);
+ }
+ finish_memory_lines(mls);
+ xasprintf(&mods, "%d", modfd);
+ execl(sub->mlmmjsend, sub->mlmmjsend,
+ "-a",
+ "-l", "4",
+ "-L", ml->dir,
+ "-s", mods,
+ "-F", from,
+ "-R", replyto,
+ "-m", queuefilename, (char *)NULL);
+ log_error(LOG_ARGS, "execl() of '%s' failed", sub->mlmmjsend);
+ exit(EXIT_FAILURE);
+ }
+
+ free(to);
+ free(replyto);
+
+ /* send mail to requester that the list is submod'ed */
+
+ txt = open_text(ml->fd,
+ "wait", "sub",
+ subreason_strs[sub->reasonsub], subtype_strs[sub->typesub],
+ "submod-requester");
+ MY_ASSERT(txt);
+ register_default_unformatted(txt, ml);
+ register_unformatted(txt, "subaddr", subaddr);
+ register_unformatted(txt, "moderators", "%gatekeepers"); /* DEPRECATED */
+ register_formatted(txt, "gatekeepers",
+ rewind_memory_lines, get_memory_line, mls);
+ queuefilename = prepstdreply(txt, ml, "$listowner$", subaddr, NULL);
+ MY_ASSERT(queuefilename);
+ close_text(txt);
+
+ finish_memory_lines(mls);
+ send_help(ml, queuefilename, subaddr);
+}
+
+static void
+subscribe_type(int listfd, char *address, enum subtype typesub)
+{
+ int dirfd;;
+ char chstr[2];
+ const char *subdir;
+ int groupwritable = 0, subfilefd;
+ struct stat st;
+
+ dirfd = open_subscriber_directory(listfd, typesub, &subdir);
+ if (dirfd == -1)
+ err(EXIT_FAILURE, "cannot open(%s)", subdir);
+ if (fstat(dirfd, &st) == 0) {
+ if(st.st_mode & S_IWGRP) {
+ groupwritable = S_IRGRP|S_IWGRP;
+ umask(S_IWOTH);
+ setgid(st.st_gid);
+ }
+ }
+
+ chstr[0] = address[0];
+ chstr[1] = '\0';
+
+ subfilefd = openat(dirfd, chstr, O_RDWR|O_CREAT|O_APPEND,
+ S_IRUSR|S_IWUSR|groupwritable);
+ if(subfilefd == -1 && !lock(subfilefd, true)) {
+ log_error(LOG_ARGS, "Could not open '%s/%s'", subdir, chstr);
+ exit(EXIT_FAILURE);
+ }
+
+ dprintf(subfilefd, "%s\n", address);
+ close(dirfd);
+ close(subfilefd);
+}
+
+bool
+do_subscribe(struct ml *ml, struct subscription *sub, const char *addr)
+{
+ char *address = NULL;
+ enum subtype subbed;
+
+ if (addr != NULL)
+ address = lowercase(addr);
+
+ if (sub->modstr != NULL) {
+ mod_get_addr_and_type(ml, sub->modstr, &address, &sub->typesub);
+ sub->reasonsub = SUB_PERMIT;
+ }
+
+ if(strncasecmp(ml->addr, address, strlen(ml->addr)) == 0)
+ errx(EXIT_FAILURE, "Cannot subscribe the list address to the list");
+
+ subbed = is_subbed(ml->fd, address, 1);
+
+ if (subbed == sub->typesub) {
+ if (sub->gensubscribed)
+ generate_subscription(ml, address, sub->typesub, true);
+ free(address);
+ return (true);
+ }
+ if (subbed != SUB_NONE) {
+ sub->reasonsub = SUB_SWITCH;
+ /* If we want to subscribe to both, we can just subscribe the
+ * missing version, so don't unsub-> */
+ if (!(sub->typesub == SUB_BOTH &&
+ subbed != SUB_NOMAIL)) {
+ enum subtype ts = SUB_ALL;
+ if (subbed == SUB_BOTH) {
+ if (sub->typesub == SUB_NORMAL) ts = SUB_DIGEST;
+ if (sub->typesub == SUB_DIGEST) ts = SUB_NORMAL;
+ }
+ if (!unsubscribe(ml->fd, address, ts))
+ log_error(LOG_ARGS, "not unsubscribed from "
+ "current version");
+ }
+ }
+
+ if (subbed == SUB_NONE && sub->subconfirm)
+ generate_subconfirm(ml, address, sub->typesub, sub->reasonsub,
+ true);
+
+ if(sub->modstr == NULL && subbed == SUB_NONE && !sub->force &&
+ statctrl(ml->ctrlfd, "submod")) {
+ moderate_sub(ml, address, sub);
+ }
+
+ if (sub->typesub == SUB_BOTH) {
+ if (subbed != SUB_NORMAL) {
+ subscribe_type(ml->fd, address, SUB_NORMAL);
+ }
+ if (subbed != SUB_DIGEST) {
+ subscribe_type(ml->fd, address, SUB_DIGEST);
+ }
+ } else if (!(subbed == SUB_BOTH && sub->typesub != SUB_NOMAIL)) {
+ subscribe_type(ml->fd, address, sub->typesub);
+ }
+
+ if (sub->send_welcome_email)
+ send_confirmation_mail(ml, address, sub->typesub,
+ sub->reasonsub, true);
+
+ bool notifysub = !sub->quiet && sub->reasonsub != SUB_SWITCH &&
+ statctrl(ml->ctrlfd, "notifysub");
+
+ /* Notify list owner about subscription */
+ if (notifysub)
+ notify_sub(ml, address, sub->typesub, sub->reasonsub, true);
+
+ free(address);
+ return (true);
+}
strlist fromemails = tll_init();
ATF_REQUIRE(ml_open(&ml, false));
- ATF_REQUIRE_EQ(listcontrol(NULL, &ml, "plop", NULL, NULL, "meh"), -1);
+ ATF_REQUIRE_EQ(listcontrol(NULL, &ml, "plop", NULL, "meh"), -1);
- ATF_REQUIRE_EQ(listcontrol(&fromemails, &ml, "help", NULL, NULL, "meh"), -1);
+ ATF_REQUIRE_EQ(listcontrol(&fromemails, &ml, "help", NULL, "meh"), -1);
atf_utils_create_file("list/control/closedlist", "");
atf_utils_create_file("meh", "mail");
tll_push_back(fromemails, "plop@test");
- ATF_REQUIRE_EQ(listcontrol(&fromemails, &ml, "unsubscribe", NULL, NULL, "meh"), -1);
+ ATF_REQUIRE_EQ(listcontrol(&fromemails, &ml, "unsubscribe", NULL, "meh"), -1);
if (atf_utils_file_exists("me"))
atf_tc_fail("mail should have been removed");
unlink("list/control/closedlist");
atf_utils_create_file("list/control/closedlistsub", "");
- ATF_REQUIRE_EQ(listcontrol(&fromemails, &ml, "subscribe", NULL, NULL, "meh"), -1);
+ ATF_REQUIRE_EQ(listcontrol(&fromemails, &ml, "subscribe", NULL, "meh"), -1);
}
ATF_TC_BODY(send_help, tc)