Mercurial > hg > mlmmj
changeset 565:e3a9ca0e9c33
added support for digest text part and digestissue keyword
author | mortenp |
---|---|
date | Mon, 04 Sep 2006 07:41:02 +1000 |
parents | 8de4095ec6ea |
children | 015056f30f84 |
files | TUNABLES include/send_digest.h src/Makefile.am src/mlmmj-maintd.c src/send_digest.c |
diffstat | 5 files changed, 297 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/TUNABLES Mon Sep 04 07:29:05 2006 +1000 +++ b/TUNABLES Mon Sep 04 07:41:02 2006 +1000 @@ -161,3 +161,8 @@ This specifies what to use as recipient delimiter for the list. Default is "+". + + · nodigesttext (boolean) + + If this file exists, digest mails won't have a text part with a thread + sumary.
--- a/include/send_digest.h Mon Sep 04 07:29:05 2006 +1000 +++ b/include/send_digest.h Mon Sep 04 07:41:02 2006 +1000 @@ -25,6 +25,6 @@ #define SEND_DIGEST_H int send_digest(const char *listdir, int lastindex, int index, - const char *addr, const char *mlmmjsend); + int issue, const char *addr, const char *mlmmjsend); #endif /* SEND_DIGEST_H */
--- a/src/Makefile.am Mon Sep 04 07:29:05 2006 +1000 +++ b/src/Makefile.am Mon Sep 04 07:41:02 2006 +1000 @@ -53,7 +53,8 @@ mlmmj_maintd_SOURCES = mlmmj-maintd.c print-version.c log_error.c mygetline.c \ strgen.c random-int.c chomp.c writen.c memory.c \ ctrlvalue.c send_digest.c getlistaddr.c dumpfd2fd.c \ - mylocking.c log_oper.c readn.c getlistdelim.c + mylocking.c log_oper.c readn.c getlistdelim.c \ + prepstdreply.c statctrl.c gethdrline.c unistr.c mlmmj_list_SOURCES = mlmmj-list.c strgen.c writen.c print-version.c memory.c \ log_error.c random-int.c readn.c
--- a/src/mlmmj-maintd.c Mon Sep 04 07:29:05 2006 +1000 +++ b/src/mlmmj-maintd.c Mon Sep 04 07:41:02 2006 +1000 @@ -749,12 +749,12 @@ int run_digests(const char *listdir, const char *mlmmjsend) { - char *lasttimestr, *lastindexstr; + char *lasttimestr, *lastindexstr, *lastissuestr; char *digestname, *indexname; char *digestintervalstr, *digestmaxmailsstr; char *s1, *s2, *s3; time_t digestinterval, t, lasttime; - long digestmaxmails, lastindex, index; + long digestmaxmails, lastindex, index, lastissue; int fd, indexfd, lock; size_t lenbuf, lenstr; @@ -792,9 +792,15 @@ s1 = mygetline(fd); - /* Syntax is lastindex:lasttime */ + /* Syntax is lastindex:lasttime or lastindex:lasttime:lastissue */ if (s1 && (lasttimestr = strchr(s1, ':'))) { *(lasttimestr++) = '\0'; + if ((lastissuestr = strchr(lasttimestr, ':'))) { + *(lastissuestr++) = '\0'; + lastissue = atol(lastissuestr); + } else { + lastissue = 0; + } lasttime = atol(lasttimestr); lastindexstr = s1; lastindex = atol(lastindexstr); @@ -810,6 +816,7 @@ /* If lastdigest is empty, we start from scratch */ lasttime = 0; lastindex = 0; + lastissue = 0; } indexname = concatstr(2, listdir, "/index"); @@ -843,15 +850,18 @@ if (index > lastindex+digestmaxmails) index = lastindex+digestmaxmails; - send_digest(listdir, lastindex+1, index, NULL, mlmmjsend); + if (index > lastindex) { + lastissue++; + send_digest(listdir, lastindex+1, index, lastissue, NULL, mlmmjsend); + } if (lseek(fd, 0, SEEK_SET) < 0) { log_error(LOG_ARGS, "Could not seek '%s'", digestname); } else { - /* index + ':' + time + '\n' + '\0' */ - lenbuf = 20 + 1 + 20 + 2; + /* index + ':' + time + ':' + issue + '\n' + '\0' */ + lenbuf = 20 + 1 + 20 + 1 + 20 + 2; s3 = mymalloc(lenbuf); - lenstr = snprintf(s3, lenbuf, "%ld:%ld\n", index, (long)t); + lenstr = snprintf(s3, lenbuf, "%ld:%ld:%ld\n", index, (long)t, lastissue); if (lenstr >= lenbuf) lenstr = lenbuf - 1; if (writen(fd, s3, lenstr) == -1) {
--- a/src/send_digest.c Mon Sep 04 07:29:05 2006 +1000 +++ b/src/send_digest.c Mon Sep 04 07:41:02 2006 +1000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 Morten K. Poulsen <morten at afdelingp.dk> +/* Copyright (C) 2004, 2005 Morten K. Poulsen <morten at afdelingp.dk> * * $Id$ * @@ -29,6 +29,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> +#include <ctype.h> #include "mlmmj.h" #include "send_digest.h" @@ -38,15 +39,151 @@ #include "getlistaddr.h" #include "getlistdelim.h" #include "wrappers.h" +#include "prepstdreply.h" +#include "mygetline.h" +#include "gethdrline.h" +#include "statctrl.h" +#include "unistr.h" + + +struct mail { + int idx; + char *from; +}; + +struct thread { + char *subject; + int num_mails; + struct mail *mails; +}; + + +static char *thread_list(const char *listdir, int firstindex, int lastindex) +{ + int i, j, archivefd, thread_idx; + char *ret, *line, *tmp, *subj, *from; + char *archivename; + int num_threads = 0; + struct thread *threads = NULL; + char buf[45]; + + for (i=firstindex; i<=lastindex; i++) { + + snprintf(buf, sizeof(buf), "%d", i); + + archivename = concatstr(3, listdir, "/archive/", buf); + archivefd = open(archivename, O_RDONLY); + myfree(archivename); + + if (archivefd < 0) + continue; + + subj = NULL; + from = NULL; + + while ((line = gethdrline(archivefd))) { + if (strcmp(line, "\n") == 0) { + myfree(line); + break; + } + if (strncasecmp(line, "Subject: ", 9) == 0) { + myfree(subj); + subj = unistr_header_to_utf8(line + 9); + } + if (strncasecmp(line, "From: ", 6) == 0) { + myfree(from); + from = unistr_header_to_utf8(line + 6); + } + myfree(line); + } + + if (!subj) { + subj = mystrdup("no subject"); + } + + if (!from) { + from = mystrdup("anonymous"); + } + + tmp = subj; + for (;;) { + if (isspace(*tmp)) { + tmp++; + continue; + } + if (strncasecmp(tmp, "Re:", 3) == 0) { + tmp += 3; + continue; + } + break; + } + /* tmp is now the clean subject */ + + thread_idx = -1; + for (j=0; j<num_threads; j++) { + if (strcmp(subj, threads[j].subject) == 0) { + thread_idx = j; + break; + } + } + if (thread_idx == -1) { + num_threads++; + threads = myrealloc(threads, + num_threads*sizeof(struct thread)); + threads[num_threads-1].subject = mystrdup(tmp); + threads[num_threads-1].num_mails = 0; + threads[num_threads-1].mails = NULL; + thread_idx = num_threads-1; + } + + threads[thread_idx].num_mails++; + threads[thread_idx].mails = myrealloc(threads[thread_idx].mails, + threads[thread_idx].num_mails*sizeof(struct mail)); + threads[thread_idx].mails[threads[thread_idx].num_mails-1].idx = i; + threads[thread_idx].mails[threads[thread_idx].num_mails-1].from = + concatstr(5, " ", buf, " - ", from, "\n"); + + myfree(subj); + myfree(from); + + close(archivefd); + } + + ret = mystrdup(""); + + for (i=0; i<num_threads; i++) { + + tmp = concatstr(3, ret, threads[i].subject, "\n"); + myfree(ret); + ret = tmp; + myfree(threads[i].subject); + + for (j=0; j<threads[i].num_mails; j++) { + tmp = concatstr(2, ret, threads[i].mails[j].from); + myfree(ret); + ret = tmp; + myfree(threads[i].mails[j].from); + } + myfree(threads[i].mails); + + tmp = concatstr(2, ret, "\n"); + myfree(ret); + ret = tmp; + } + myfree(threads); + + return ret; +} int send_digest(const char *listdir, int firstindex, int lastindex, - const char *addr, const char *mlmmjsend) + int issue, const char *addr, const char *mlmmjsend) { - int i, fd, archivefd, status, hdrfd; + int i, fd, archivefd, status, hdrfd, txtfd; char buf[45]; - char *tmp, *queuename = NULL, *archivename, *fromstr; + char *tmp, *queuename = NULL, *archivename, *subject, *line = NULL; char *boundary, *listaddr, *listdelim, *listname, *listfqdn; + char *subst_data[10]; pid_t childpid, pid; if (addr) { @@ -83,50 +220,161 @@ listaddr = getlistaddr(listdir); listname = genlistname(listaddr); listfqdn = genlistfqdn(listaddr); - myfree(listaddr); + listdelim = getlistdelim(listdir); - if (lastindex == firstindex) { - snprintf(buf, sizeof(buf), " (%d)", firstindex); - } else { - snprintf(buf, sizeof(buf), " (%d-%d)", firstindex, lastindex); + tmp = concatstr(2, listdir, "/text/digest"); + txtfd = open(tmp, O_RDONLY); + myfree(tmp); + if (txtfd < 0) { + log_error(LOG_ARGS, "Notice: Could not open std mail digest"); } - listdelim = getlistdelim(listdir); - fromstr = concatstr(6, "From: ", listname, listdelim, "help@", listfqdn, - "\n"); - myfree(listdelim); + subst_data[0] = "digestfirst"; + snprintf(buf, sizeof(buf), "%d", firstindex); + subst_data[1] = mystrdup(buf); + + subst_data[2] = "digestlast"; + snprintf(buf, sizeof(buf), "%d", lastindex); + subst_data[3] = mystrdup(buf); + + subst_data[4] = "digestinterval"; + if (lastindex == firstindex) { + snprintf(buf, sizeof(buf), "%d", firstindex); + } else { + snprintf(buf, sizeof(buf), "%d-%d", firstindex, lastindex); + } + subst_data[5] = mystrdup(buf); - tmp = concatstr(6, "MIME-Version: 1.0" + subst_data[6] = "digestissue"; + snprintf(buf, sizeof(buf), "%d", issue); + subst_data[7] = mystrdup(buf); + + subst_data[8] = "digestthreads"; + subst_data[9] = thread_list(listdir, firstindex, lastindex); + + if ((txtfd > 0) && (line = mygetline(txtfd)) && + (strncasecmp(line, "Subject: ", 9) == 0)) { + subject = substitute(line + 9, listaddr, listdelim, + 5, subst_data); + } else { + subject = substitute("Digest of $listaddr$ issue $digestissue$" + " ($digestinterval$)\n", listaddr, listdelim, + 5, subst_data); + } + + tmp = concatstr(9, "From: ", listname, listdelim, "help@", listfqdn, + "\nMIME-Version: 1.0" "\nContent-Type: multipart/" DIGESTMIMETYPE "; " "boundary=", boundary, - "\nSubject: Digest of ", listname, buf, "\n\n"); + "\nSubject: ", subject); + /* subject includes a newline */ + myfree(listfqdn); + myfree(subject); - if (writen(fd, fromstr, strlen(fromstr)) < -1) + if (writen(fd, tmp, strlen(tmp)) < 0) { + myfree(tmp); goto errdighdrs; + } + myfree(tmp); if(hdrfd >= 0 && dumpfd2fd(hdrfd, fd) < 0) { - close(hdrfd); goto errdighdrs; } close(hdrfd); + hdrfd = -1; - if (writen(fd, tmp, strlen(tmp)) < -1) { + if (writen(fd, "\n", 1) < 0) { errdighdrs: log_error(LOG_ARGS, "Could not write digest headers to '%s'", queuename); close(fd); unlink(queuename); myfree(boundary); - myfree(fromstr); + myfree(queuename); + myfree(listaddr); + myfree(listname); + myfree(listdelim); + myfree(subst_data[1]); + myfree(subst_data[3]); + myfree(subst_data[5]); + myfree(subst_data[7]); + myfree(subst_data[9]); + if (txtfd > 0) { + close(txtfd); + myfree(line); + } + if (hdrfd > 0) { + close(hdrfd); + } + return -1; + } + + if ((txtfd > 0) && !statctrl(listdir, "nodigesttext")) { + + tmp = concatstr(3, "--", boundary, + "\nContent-Type: text/plain; charset=UTF-8" + "\n\n"); + if (writen(fd, tmp, strlen(tmp)) == -1) { + log_error(LOG_ARGS, "Could not write digest text/plain" + " part headers to '%s'", queuename); + close(fd); + unlink(queuename); + myfree(boundary); myfree(tmp); myfree(queuename); + myfree(listaddr); myfree(listname); + myfree(listdelim); + myfree(subst_data[1]); + myfree(subst_data[3]); + myfree(subst_data[5]); + myfree(subst_data[7]); + myfree(subst_data[9]); + if (txtfd > 0) { + close(txtfd); + myfree(line); + } return -1; } myfree(tmp); - myfree(fromstr); + + if (line && (strncasecmp(line, "Subject: ", 9) == 0)) { + myfree(line); + line = mygetline(txtfd); + if (line && (strcmp(line, "\n") == 0)) { + /* skip empty line after Subject: */ + line[0] = '\0'; + } + } + + if (line) { + do { + tmp = substitute(line, listaddr, listdelim, + 5, subst_data); + myfree(line); + if(writen(fd, tmp, strlen(tmp)) < 0) { + myfree(tmp); + log_error(LOG_ARGS, "Could not write" + " std mail"); + break; + } + myfree(tmp); + } while ((line = mygetline(txtfd))); + } + + close(txtfd); + } + + myfree(line); + myfree(listaddr); + myfree(listdelim); + myfree(subst_data[1]); + myfree(subst_data[3]); + myfree(subst_data[5]); + myfree(subst_data[7]); + myfree(subst_data[9]); for (i=firstindex; i<=lastindex; i++) { snprintf(buf, sizeof(buf), "%d", i);