pick option -thread
[mmh] / uip / pick.c
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;
+       
+}