Hi I have now finished the -thread option for pick. My current patch is attached. The option takes a single string with folders messages and files. So it's possible to reference a mail from a diffrent folder for the thread-id.
I have to write some test and documentation befor I commit, but the implementation should work. What do you think about this option and the implementation? Philipp
diff --git a/h/prototypes.h b/h/prototypes.h index 69556f94..50d8a8b7 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/sbr/Makefile.in b/sbr/Makefile.in index 58cf5c7d..07877590 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 00000000..ef7a3331 --- /dev/null +++ b/sbr/getthreadid.c @@ -0,0 +1,71 @@ +#include <h/mh.h> +#include <h/utils.h> +#include <h/addrsbr.h> + +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("in-reply-to", f.name, f.namelen)==0) { + inreplto = 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; + + if (referens) { + threadfrom = referens; + } else { + threadfrom = 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 4cb33fb1..5d58b0e1 100644 --- a/uip/pick.c +++ b/uip/pick.c @@ -63,9 +63,11 @@ static struct swit switches[] = { { "list", 0 }, #define NLISTSW 21 { "nolist", 2 }, -#define VERSIONSW 22 +#define THREADSW 22 + { "thread", 0 }, +#define VERSIONSW 23 { "Version", 0 }, -#define HELPSW 23 +#define HELPSW 24 { "help", 0 }, { NULL, 0 } }; @@ -77,6 +79,8 @@ char *version=VERSION; */ static int pcompile(char **, char *); static int pmatches(FILE *, int, long, long); +static struct nexus * createOneThread(char *); +static struct nexus * createPickthread(char *); static int listsw = -1; @@ -142,6 +146,7 @@ main(int argc, char **argv) case AFTRSW: case BEFRSW: case SRCHSW: + case THREADSW: vec[vecp++] = --cp; pattern: if (!(cp = *argp++)) /* allow -xyz arguments */ @@ -352,6 +357,8 @@ static struct swit parswit[] = { { "before date", 0 }, #define PRDATF 14 { "datefield field", 5 }, +#define PRTHREAD 15 + { "thread msg", 0 }, { NULL, 0 } }; @@ -701,6 +708,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: @@ -1296,3 +1308,95 @@ plist mh_free0(&bp); return state; } +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; + 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(ORaction); + or->n_L_child = ret; + ret = or; + ret->n_R_child = c; + } + + mh_free0(&(files.msgs)); + mh_free0(&(msgarray.msgs)); + + return ret; +} + +static struct nexus * +createOneThread(char *c) +{ + struct nexus *ret = newnexus(ORaction); + struct nexus *left = newnexus(GREPaction); + struct nexus *right = newnexus(GREPaction); + char buf[BUFSIZ]; + + ret->n_L_child = left; + ret->n_R_child = right; + right->n_header = 1; + left->n_header = 1; + + snprintf(buf, sizeof(buf), "^message-id[ \t]*:[ \t]*<%s>", c); + if(!gcompile(left, buf)) { + padvise(NULL, "pattern error %s", c); + goto error; + } + left->n_patbuf = mh_xstrdup(buf); + + snprintf(buf, sizeof(buf), "^references[ \t]*:[ \t]*<%s>", c); + if(!gcompile(right, buf)) { + padvise(NULL, "pattern error in %s", c); + goto error; + } + right->n_patbuf = mh_xstrdup(buf); + + return ret; + +error: + mh_free0(&left->n_patbuf); + mh_free0(&left); + mh_free0(&right); + mh_free0(&ret); + return NULL; + +}