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;
+	
+}

Reply via email to