From: Philipp Takacs Date: Sun, 26 Feb 2017 19:28:06 +0000 (+0100) Subject: pick option -thread X-Git-Tag: mmh-0.4~10^2~7 X-Git-Url: http://git.marmaro.de/?p=mmh;a=commitdiff_plain;h=3ec7019fb0a1c08f1c866f0a84fa75fe5b498596 pick option -thread The -thread option allows to pick mails of a specific thread. The thread is choosen by a mail in the option argument. --- diff --git a/h/prototypes.h b/h/prototypes.h index 69556f9..50d8a8b 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -162,4 +162,4 @@ int is_readonly(struct msgs *); void set_readonly(struct msgs *); int other_files(struct msgs *); void set_other_files(struct msgs *); - +char *getthreadid(const char *); diff --git a/man/pick.man1 b/man/pick.man1 index 4f223df..8188ff4 100644 --- a/man/pick.man1 +++ b/man/pick.man1 @@ -43,6 +43,8 @@ pick \- select messages by content .IR formatfile ] .RB [ \-width .IR columns ] +.RB [ \-thread +.RI [ +folder ] messages "|" files ] .RB [ \-sequence .I name \&...] diff --git a/sbr/Makefile.in b/sbr/Makefile.in index 58cf5c7..0787759 100644 --- a/sbr/Makefile.in +++ b/sbr/Makefile.in @@ -72,7 +72,8 @@ SRCS = addrsbr.c ambigsw.c brkstring.c \ smatch.c snprintb.c strcasecmp.c \ strindex.c trim.c trimcpy.c uprf.c vfgets.c fmt_def.c \ mf.c utils.c m_mktemp.c seq_msgstats.c \ - unquote.c encode_rfc2047.c parse_msgs.c + unquote.c encode_rfc2047.c parse_msgs.c \ + getthreadid.c OBJS = $(SRCS:.c=.o) diff --git a/sbr/getthreadid.c b/sbr/getthreadid.c new file mode 100644 index 0000000..99a7d67 --- /dev/null +++ b/sbr/getthreadid.c @@ -0,0 +1,61 @@ +#include +#include +#include + +static char *threadid(char *, char *); + +char * +getthreadid(const char *path) +{ + char *msgid = NULL; + char *referens = NULL; + char *ret; + struct field f = {{0}}; + enum state state = FLD2; + FILE *file = fopen(path, "r"); + + while (state == FLD2 && !msgid && !referens) { + switch (state = m_getfld2(state, &f, file)) { + case FLD2: + if (strncasecmp("message-id", f.name, f.namelen)==0) { + msgid = f.value; + f.value = NULL; + } else if (strncasecmp("references", f.name, f.namelen)==0) { + referens = f.value; + f.value = NULL; + } + break; + default: + fclose(file); + break; + } + } + + ret = threadid(msgid, referens); + + mh_free0(&msgid); + mh_free0(&referens); + + return ret; +} + +static char * +threadid(char *msgid, char *referens) +{ + char *threadfrom; + char *start, *end; + char *cp; + + threadfrom = referens ? referens : msgid; + + start = strchr(threadfrom, '<'); + end = strchr(start, '>'); + if (!(*start) || !(*end)) { + return NULL; + } + *end = '\0'; + cp = mh_xstrdup(start + 1); + *end = '>'; + + return cp; +} diff --git a/uip/pick.c b/uip/pick.c index 1c195be..464a734 100644 --- a/uip/pick.c +++ b/uip/pick.c @@ -71,9 +71,11 @@ static struct swit switches[] = { { "format format", 0 }, #define WIDTHSW 23 { "width columns", 0 }, -#define VERSIONSW 24 +#define THREADSW 24 + { "thread", 0 }, +#define VERSIONSW 25 { "Version", 0 }, -#define HELPSW 25 +#define HELPSW 26 { "help", 0 }, { NULL, 0 } }; @@ -96,6 +98,8 @@ static boolean body = FALSE; */ static int pcompile(char **, char *); static int pmatches(FILE *, int); +static struct nexus * createonethread(char *); +static struct nexus * createpickthread(char *); static int listsw = -1; @@ -169,6 +173,7 @@ main(int argc, char **argv) case AFTRSW: case BEFRSW: case SRCHSW: + case THREADSW: vec[vecp++] = --cp; pattern: if (!(cp = *argp++)) /* allow -xyz arguments */ @@ -324,7 +329,9 @@ main(int argc, char **argv) } } - head->free(&head); + if (head) { + head->free(&head); + } mp->lowsel = lo; mp->hghsel = hi; @@ -421,6 +428,8 @@ static struct swit parswit[] = { { "before date", 0 }, #define PRDATF 14 { "datefield field", 5 }, +#define PRTHREAD 15 + { "thread msg", 0 }, { NULL, 0 } }; @@ -731,6 +740,11 @@ nexp3(void) prvarg(); return NULL; + case PRTHREAD: + if (!(cp = nxtarg())) { /* allow -xyz arguments */ + padvise(NULL, "missing argument to %s", argp[-2]); + } + return createpickthread(cp); case PRCC: case PRDATE: case PRFROM: @@ -975,8 +989,13 @@ BINaction(struct field *f, int msgnum, void *data) static void BINfree(struct nexus **n) { - struct nexus *bin = *n; - struct bin_data *bd = bin->data; + struct bin_data *bd; + + if (!(*n)) { + return; + } + + bd = (*n)->data; if (bd->left && bd->left->free) { bd->left->free(&bd->left); @@ -1020,12 +1039,12 @@ GREPaction(struct field *f, int msgnum, void *data) int ret; char *buf; - /* check for the write field */ - if (g->header && *g->header && mh_strcasecmp(g->header, f->name)) { + if (!g->header && *f->name) { return FALSE; } - if (!g->header && *f->name) { + /* check for the right field */ + if (g->header && *g->header && mh_strcasecmp(g->header, f->name)==0) { return FALSE; } @@ -1047,7 +1066,11 @@ GREPaction(struct field *f, int msgnum, void *data) static void GREPfree(struct nexus **n) { - struct grep_data *gd = (*n)->data; + struct grep_data *gd; + if (!(*n)) { + return; + } + gd = (*n)->data; mh_free0(&gd->header); regfree(gd->preg); mh_free0(n); @@ -1202,7 +1225,11 @@ DATEaction(struct field *f, int msgnum, void *data) static void DATEfree(struct nexus **n) { - struct date_data *dd = (*n)->data; + struct date_data *dd; + if (!(*n)) { + return; + } + dd = (*n)->data; mh_free0(&dd->datef); mh_free0(n); @@ -1215,3 +1242,100 @@ DATEdebug(void *data, size_t level) print_debug_level(level); fprintf(stderr, "TEMPORAL(%s) %s: %s\n",dd->after ? "after" : "before", dd->datef, dasctime(&dd->tws)); } + +static struct nexus * +createpickthread(char *msgs) +{ + char *folder = NULL; + struct msgs_array msgarray = {0}; + struct msgs_array files = {0}; + struct nexus *ret = NULL; + struct nexus *c; + struct nexus *or; + struct bin_data *bd; + char *buf; + char **cp = brkstring(msgs, " \t", NULL); + int i; + + for (; cp && *cp; cp++) { + switch (**cp) { + case '@': + case '+': + if (folder) { + advise("",""); + break; + } + folder = mh_xstrdup(*cp); + break; + default: + app_msgarg(&msgarray, mh_xstrdup(*cp)); + } + } + + parse_msgs(&msgarray, folder, &files); + + for (i = 0; i < files.size; i++) { + buf = getthreadid(files.msgs[i]); + if (!buf) { + continue; + } + + c = createonethread(buf); + + if (!ret) { + ret = c; + continue; + } + + + or = newnexus(TYPE_OR); + bd = or->data; + bd->right = ret; + bd->left = c; + ret = or; + } + + mh_free0(&(files.msgs)); + mh_free0(&(msgarray.msgs)); + + return ret; +} + +static struct nexus * +createonethread(char *c) +{ + struct nexus *ret = newnexus(TYPE_OR); + struct nexus *left = newnexus(TYPE_GREP); + struct nexus *right = newnexus(TYPE_GREP); + struct bin_data *bd = ret->data; + struct grep_data *gd = left->data; + char buf[BUFSIZ]; + + bd->left = left; + bd->right = right; + gd->header = "message-id"; + + snprintf(buf, sizeof(buf), "^[ \t]*<%s>", c); + if(!gcompile(gd, buf)) { + padvise(NULL, "pattern error %s", c); + goto error; + } + + gd = right->data; + gd->header = "references"; + + snprintf(buf, sizeof(buf), "^[ \t]*<%s>", c); + if(!gcompile(gd, buf)) { + padvise(NULL, "pattern error in %s", c); + goto error; + } + + return ret; + +error: + GREPfree(&left); + GREPfree(&right); + BINfree(&ret); + return NULL; + +}