}
static bool
-resend_queue(int dfd, int ctrlfd, const char *mlmmjsend, const char *listdir, int logfd)
+resend_queue(struct ml *ml, const char *mlmmjsend, int logfd)
{
DIR *queuedir;
struct dirent *dp;
time_t t, bouncelife;
bool ret = true;
- opendirat(dfd, qfd, queuedir, "queue");
+ opendirat(ml->fd, qfd, queuedir, "queue");
while((dp = readdir(queuedir)) != NULL) {
if(fstatat(qfd, dp->d_name, &st, 0) < 0) {
free(reptoname);
/* before we try again, check and see if it's old */
- bouncelife = ctrltimet(ctrlfd, "bouncelife", BOUNCELIFE);
+ bouncelife = ctrltimet(ml->ctrlfd, "bouncelife", BOUNCELIFE);
t = time(NULL);
if(t - st.st_mtime > bouncelife) {
if (unlinkat(qfd, dp->d_name, 0) == -1) {
}
if(repto)
- exec_and_wait(mlmmjsend, "-l", "1", "-L", listdir, "-m",
+ exec_and_wait(mlmmjsend, "-l", "1", "-L", ml->dir, "-m",
mailname, "-F", from, "-T", to, "-R", repto, "-a",
NULL);
else
- exec_and_wait(mlmmjsend, "-l", "1", "-L", listdir, "-m",
+ exec_and_wait(mlmmjsend, "-l", "1", "-L", ml->dir, "-m",
mailname, "-F", from, "-T", to, "-a", NULL);
}
}
static bool
-resend_requeue(int dfd, const char *mlmmjsend, const char *listdir, int logfd)
+resend_requeue(struct ml *ml, const char *mlmmjsend, int logfd)
{
DIR *queuedir;
struct dirent *dp;
int fd;
bool ret = true;
- opendirat(dfd, fd, queuedir, "requeue");
+ opendirat(ml->fd, fd, queuedir, "requeue");
while((dp = readdir(queuedir)) != NULL) {
if((strcmp(dp->d_name, "..") == 0) ||
(strcmp(dp->d_name, ".") == 0))
/* Explicitly initialize for each mail we examine */
fromrequeuedir = false;
- if(faccessat(dfd, archivefilename, F_OK, 0) < 0) {
+ if(faccessat(ml->fd, archivefilename, F_OK, 0) < 0) {
/* Might be it's just not moved to the archive
* yet because it's still getting sent, so just
* continue
*/
xasprintf(&archivefilename, "requeue/%s/mailfile",
dp->d_name);
- if(faccessat(dfd, archivefilename, F_OK, 0) < 0) {
+ if(faccessat(ml->fd, archivefilename, F_OK, 0) < 0) {
free(archivefilename);
continue;
}
xasprintf(&subfilename, "%s/subscribers", dp->d_name);
if(faccessat(fd, subfilename, F_OK, 0) < 0) {
if (fromrequeuedir) {
- if (unlinkat(dfd, archivefilename, 0) == -1) {
+ if (unlinkat(ml->fd, archivefilename, 0) == -1) {
log(" - Cound not remove %s: %s\n",
archivefilename, strerror(errno));
ret = false;
}
free(subfilename);
- exec_and_wait(mlmmjsend, "-l", "3", "-L", listdir, "-m",
+ exec_and_wait(mlmmjsend, "-l", "3", "-L", ml->dir, "-m",
archivefilename, "-s", subnewname, "-a", "-D", NULL);
}
}
static bool
-probe_bouncers(int dfd, const char *mlmmjbounce, const char *listdir, int logfd)
+probe_bouncers(struct ml *ml, const char *mlmmjbounce, int logfd)
{
DIR *bouncedir;
char *probefile, *s;
int fd;
bool ret = true;
- opendirat(dfd, fd, bouncedir, "bounce");
+ opendirat(ml->fd, fd, bouncedir, "bounce");
while((dp = readdir(bouncedir)) != NULL) {
if((strcmp(dp->d_name, "..") == 0) ||
(strcmp(dp->d_name, ".") == 0))
}
free(probefile);
- exec_and_wait(mlmmjbounce, "-L", listdir, "-a", dp->d_name,
+ exec_and_wait(mlmmjbounce, "-L", ml->dir, "-a", dp->d_name,
"-p", NULL);
}
closedir(bouncedir);
}
static bool
-run_digests(int dfd, int ctrlfd, const char *mlmmjsend, const char *listdir, int logfd)
+run_digests(struct ml *ml, const char *mlmmjsend, int logfd)
{
char *s1, *s2;
time_t digestinterval, t, lasttime;
const char *errstr = NULL;
bool ret = false;
- if (statctrl(ctrlfd, "noarchive")) {
+ if (statctrl(ml->ctrlfd, "noarchive")) {
log(" - noarchive tunable: skipping digest\n");
return (true);
}
- if (faccessat(dfd, "index", R_OK, 0) == -1) {
+ if (faccessat(ml->fd, "index", R_OK, 0) == -1) {
log(" - No readable index file: no digest\n");
return (true);
}
- digestinterval = ctrltimet(ctrlfd, "digestinterval", DIGESTINTERVAL);
- digestmaxmails = ctrllong(ctrlfd, "digestmaxmail", DIGESTMAXMAILS);
+ digestinterval = ctrltimet(ml->ctrlfd, "digestinterval", DIGESTINTERVAL);
+ digestmaxmails = ctrllong(ml->ctrlfd, "digestmaxmail", DIGESTMAXMAILS);
- fd = openat(dfd, "lastdigest", O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
+ fd = openat(ml->fd, "lastdigest", O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0 && !lock(fd, true)) {
log(" - Could not open or create 'lastdigest': %s\n",
strerror(errno));
return (false);
}
- indexfd = openat(dfd, "index", O_RDONLY);
+ indexfd = openat(ml->fd, "index", O_RDONLY);
if (indexfd < 0) {
log("Could not open'index': %s", strerror(errno));
free(s1);
if (index > lastindex) {
lastissue++;
- send_digest(listdir, lastindex+1, index, lastissue, NULL, mlmmjsend, dfd, ctrlfd);
+ send_digest(ml, lastindex+1, index, lastissue, NULL, mlmmjsend);
}
if (lseek(fd, 0, SEEK_SET) < 0) {
return (ret);
}
-void do_maintenance(int listfd, const char *listdir, const char *mlmmjsend,
- const char *mlmmjbounce)
+void do_maintenance(struct ml *ml, const char *mlmmjsend, const char *mlmmjbounce)
{
char *random, *logname;
char timenow[64];
- struct stat st;
int logfd;
- uid_t uid = getuid();
time_t t;
- int ctrlfd;
-
- if (listfd == -1)
- return;
-
- ctrlfd = openat(listfd, "control", O_DIRECTORY|O_CLOEXEC);
-
- if (fstat(listfd, &st) < 0) {
- log_error(LOG_ARGS, "Could not stat "
- "No maintenance run performed.");
- return;
- }
-
- if(uid == 0) { /* We're root. Do something about it.*/
- if(setuid(st.st_uid) < 0) {
- log_error(LOG_ARGS, "Could not setuid listdir owner.");
- return;
- }
- } else if(uid != st.st_uid) {
- log_error(LOG_ARGS,
- "User ID not equal to the ID of %s. No "
- "maintenance run performed.", listdir);
- return;
- }
random = random_str();
xasprintf(&logname, "maintdlog-%s", random);
free(random);
- logfd = openat(listfd, logname, O_WRONLY|O_EXCL|O_CREAT, S_IRUSR|S_IWUSR);
+ logfd = openat(ml->fd, logname, O_WRONLY|O_EXCL|O_CREAT, S_IRUSR|S_IWUSR);
if(logfd == -1) {
log_err("Could not open %s: %s", logname, strerror(errno));
free(logname);
timenow);
log("clean_moderation\n");
- if (!clean_moderation(listfd, ctrlfd, logfd))
+ if (!clean_moderation(ml->fd, ml->ctrlfd, logfd))
log_err("An error occured while cleaning moderation, see %s",
MAINTD_LOGFILE);
log("clean_discarded\n");
- if (!clean_discarded(listfd, logfd))
+ if (!clean_discarded(ml->fd, logfd))
log_err("An error occured while cleaning discarded mails, see "
"%s", MAINTD_LOGFILE);
log("clean_subconf\n");
- if (!clean_subconf(listfd, logfd))
+ if (!clean_subconf(ml->fd, logfd))
log_err("An error occured while cleaning subscribtion "
"confirmations, mails, see %s", MAINTD_LOGFILE);
log("clean_unsubconf\n");
- if (!clean_unsubconf(listfd, logfd))
+ if (!clean_unsubconf(ml->fd, logfd))
log_err("An error occured while cleaning unsubscribtion "
"confirmations, mails, see %s", MAINTD_LOGFILE);
log("resend_queue\n");
- if (!resend_queue(listfd, ctrlfd, mlmmjsend, listdir, logfd))
+ if (!resend_queue(ml, mlmmjsend, logfd))
log_err("An error occured while resending queued mails, see %s",
MAINTD_LOGFILE);
log("resend_requeue\n");
- if (!resend_requeue(listfd, mlmmjsend, listdir, logfd))
+ if (!resend_requeue(ml, mlmmjsend, logfd))
log_err("An error occured while resending requeued mails, see "
"%s", MAINTD_LOGFILE);
log("clean_nolongerbouncing\n");
- if (!clean_nolongerbouncing(listfd, logfd))
+ if (!clean_nolongerbouncing(ml->fd, logfd))
log_err("An error occured while cleaning no longer bouncing "
"traces, see %s", MAINTD_LOGFILE);
log("unsub_bouncers\n");
- if (!unsub_bouncers(listfd, ctrlfd, logfd))
+ if (!unsub_bouncers(ml->fd, ml->ctrlfd, logfd))
log_err("An error occured while unsubscribing bouncing emails, "
"see %s", MAINTD_LOGFILE);
log("probe_bouncers\n");
- if (!probe_bouncers(listfd, mlmmjbounce, listdir, logfd))
+ if (!probe_bouncers(ml, mlmmjbounce, logfd))
log_err("An error occured while sending probes for bouncers, "
"see %s", MAINTD_LOGFILE);
log("run_digests\n");
- if (!run_digests(listfd, ctrlfd, mlmmjsend, listdir, logfd))
+ if (!run_digests(ml, mlmmjsend, logfd))
log_err("An error occured while running digests, see %s",
MAINTD_LOGFILE);
close(logfd);
- if (renameat(listfd, logname, listfd, MAINTD_LOGFILE) < 0)
+ if (renameat(ml->fd, logname, ml->fd, MAINTD_LOGFILE) < 0)
log_error(LOG_ARGS, "Could not rename(%s,%s)",
logname, MAINTD_LOGFILE);
while(1) {
if(listdir) {
+ struct ml ml;
+ ml_init(&ml);
+ ml.dir = listdir;
log_set_namef("%s(%s)", argv[0], listdir);
- int fd = open(listdir, O_DIRECTORY|O_CLOEXEC);
- do_maintenance(fd, listdir, mlmmjsend, mlmmjbounce);
+ if (!ml_open(&ml, true))
+ goto mainsleep;
+ do_maintenance(&ml, mlmmjsend, mlmmjbounce);
+ ml_close(&ml);
goto mainsleep;
}
}
while((dp = readdir(dirp)) != NULL) {
+ char *l;
if((strcmp(dp->d_name, "..") == 0) ||
(strcmp(dp->d_name, ".") == 0))
continue;
- int fd = openat(dfd, dp->d_name, O_DIRECTORY);
- if (fd == -1)
- continue;
-
- if (faccessat(fd, "control/listaddress", F_OK, 0) <0)
- continue;
-
- char *l;
xasprintf(&l, "%s/%s", dirlists, dp->d_name);
log_set_namef("%s(%s)", argv[0], l);
- do_maintenance(fd, l, mlmmjsend, mlmmjbounce);
+ struct ml ml;
+ ml_init(&ml);
+ ml.dir = l;
+ if (!ml_open(&ml, true))
+ continue;
+ do_maintenance(&ml, mlmmjsend, mlmmjbounce);
+ ml_close(&ml);
free(l);
- close(fd);
}
closedir(dirp);
}
-int send_digest(const char *listdir, int firstindex, int lastindex,
- int issue, const char *addr, const char *mlmmjsend, int listfd, int ctrlfd)
+int send_digest(struct ml *ml, int firstindex, int lastindex,
+ int issue, const char *addr, const char *mlmmjsend)
{
int i, fd, archivefd, hdrfd;
size_t len;
text * txt;
char buf[100];
char *tmp, *queuename = NULL, *archivename, *subject = NULL, *line = NULL;
- char *boundary, *listaddr, *listdelim, *listname, *listfqdn;
+ char *boundary;
thread_list_state * tls;
if (addr) {
do {
tmp = random_str();
free(queuename);
- queuename = concatstr(3, listdir, "/queue/", tmp);
+ xasprintf(&queuename, "%s/queue/%s", ml->dir, tmp);
free(tmp);
fd = open(queuename, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
} while ((fd < 0) && (errno == EEXIST));
return -1;
}
- tmp = concatstr(2, listdir, "/control/customheaders");
- hdrfd = open(tmp, O_RDONLY);
- free(tmp);
+ hdrfd = openat(ml->ctrlfd, "customheaders", O_RDONLY);
boundary = random_str();
- listaddr = getlistaddr(ctrlfd);
- listname = genlistname(listaddr);
- listfqdn = genlistfqdn(listaddr);
- listdelim = getlistdelim(ctrlfd);
-
- txt = open_text_file(listfd, "digest");
+ txt = open_text_file(ml->fd, "digest");
if (txt == NULL) {
log_error(LOG_ARGS, "Could not open listtext 'digest'");
goto fallback_subject;
}
- register_default_unformatted(txt, listdelim, listaddr);
+ register_default_unformatted(txt, ml->delim, ml->addr);
snprintf(buf, sizeof(buf), "%d", firstindex);
register_unformatted(txt, "digestfirst", buf);
register_unformatted(txt, "digestthreads", "%digestthreads%"); /* DEPRECATED */
- tls = init_thread_list(listdir, firstindex, lastindex);
+ tls = init_thread_list(ml->dir, firstindex, lastindex);
register_formatted(txt, "digestthreads", rewind_thread_list,
get_thread_list_line, tls);
- line = get_processed_text_line(txt, 1, listdir, listfd, ctrlfd);
+ line = get_processed_text_line(txt, 1, ml->dir, ml->fd, ml->ctrlfd);
if (line == NULL) {
log_error(LOG_ARGS, "No content in digest listtext");
free(line);
/* Skip the empty line after the subject */
- line = get_processed_text_line(txt, 1, listdir, listfd, ctrlfd);
+ line = get_processed_text_line(txt, 1, ml->dir, ml->fd, ml->ctrlfd);
if (line == NULL || *line != '\0') {
log_error(LOG_ARGS, "Too many headers "
"in digest listtext");
}
tmp = xstrdup(buf);
snprintf(buf, sizeof(buf), "Digest of %s issue %d (%s)",
- listaddr, issue, tmp);
+ ml->addr, issue, tmp);
subject = unistr_utf8_to_header(buf);
free(tmp);
}
"\nContent-Type: multipart/" DIGESTMIMETYPE "; "
"boundary=%s"
"\nSubject: %s\n",
- listname, listdelim, listfqdn, boundary, subject) < 0) {
- free(listfqdn);
+ ml->name, ml->delim, ml->fqdn, boundary, subject) < 0) {
free(subject);
goto errdighdrs;
}
- free(listfqdn);
free(subject);
if(hdrfd >= 0 && dumpfd2fd(hdrfd, fd) < 0) {
unlink(queuename);
free(boundary);
free(queuename);
- free(listaddr);
- free(listname);
- free(listdelim);
if (txt != NULL) {
close_text(txt);
free(line);
return -1;
}
- if ((txt != NULL) && !statctrl(ctrlfd, "nodigesttext")) {
+ if ((txt != NULL) && !statctrl(ml->ctrlfd, "nodigesttext")) {
if (dprintf(fd, "\n--%s"
"\nContent-Type: text/plain; charset=UTF-8"
unlink(queuename);
free(boundary);
free(queuename);
- free(listaddr);
- free(listname);
- free(listdelim);
if (txt != NULL) {
close_text(txt);
free(line);
}
for (;;) {
- line = get_processed_text_line(txt, 0, listdir, listfd, ctrlfd);
+ line = get_processed_text_line(txt, 0, ml->dir, ml->fd, ml->ctrlfd);
if (line == NULL) break;
if(dprintf(fd, "%s\n", line) < 0) {
free(line);
}
if (line != NULL) free(line);
- free(listaddr);
- free(listdelim);
for (i=firstindex; i<=lastindex; i++) {
- snprintf(buf, sizeof(buf), "%d", i);
-
- archivename = concatstr(3, listdir, "/archive/", buf);
- archivefd = open(archivename, O_RDONLY);
+ xasprintf(&archivename, "archive/%d", i);
+ archivefd = openat(ml->fd, archivename, O_RDONLY);
free(archivename);
-
+
if (archivefd < 0)
continue;
-
+
if (dprintf(fd, "\n--%s"
"\nContent-Type: message/rfc822"
"\nContent-Disposition: inline; filename=\"%s_%s.eml\"\n\n",
- boundary, listname, buf) < 0) {
+ boundary, ml->name, buf) < 0) {
log_error(LOG_ARGS, "Could not write digest part "
"headers for archive index %d to "
"'%s'", i, queuename);
free(boundary);
free(tmp);
free(queuename);
- free(listname);
return -1;
}
unlink(queuename);
free(boundary);
free(queuename);
- free(listname);
return -1;
}
-
close(archivefd);
}
unlink(queuename);
free(boundary);
free(queuename);
- free(listname);
return -1;
}
close(fd);
free(boundary);
- free(listname);
- exec_and_wait(mlmmjsend, "-l", "7", "-L", listdir, "-m", queuename,
+ exec_and_wait(mlmmjsend, "-l", "7", "-L", ml->dir, "-m", queuename,
NULL);
free(queuename);