pick option -thread
authorPhilipp Takacs <philipp@bureaucracy.de>
Sun, 26 Feb 2017 19:28:06 +0000 (20:28 +0100)
committerPhilipp Takacs <philipp@bureaucracy.de>
Sun, 28 May 2017 12:06:53 +0000 (14:06 +0200)
The -thread option allows to pick mails of a specific thread. The
thread is choosen by a mail in the option argument.

h/prototypes.h
man/pick.man1
sbr/Makefile.in
sbr/getthreadid.c [new file with mode: 0644]
uip/pick.c

index 69556f9..50d8a8b 100644 (file)
@@ -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 *);
index 4f223df..8188ff4 100644 (file)
@@ -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
 \&...]
index 58cf5c7..0787759 100644 (file)
@@ -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 (file)
index 0000000..99a7d67
--- /dev/null
@@ -0,0 +1,61 @@
+#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("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;
+}
index 1c195be..464a734 100644 (file)
@@ -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;
+       
+}