acme Mail: add Search command

Introduces the Search command for mailboxes.
Arguments passed are treated as one space-
separated string, passed on to mailfs' IMAP
search interface.

R=rsc, david.ducolombier
CC=plan9port.codebot
https://codereview.appspot.com/13238044
diff --git a/src/cmd/acme/mail/dat.h b/src/cmd/acme/mail/dat.h
index 9a6be95..a7ac6a0 100644
--- a/src/cmd/acme/mail/dat.h
+++ b/src/cmd/acme/mail/dat.h
@@ -142,6 +142,7 @@
 extern	void		mesgfreeparts(Message*);
 extern	int		mesgcommand(Message*, char*);
 
+extern	char*	info(Message*, int, int);
 extern	char*	readfile(char*, char*, int*);
 extern	char*	readbody(char*, char*, int*);
 extern	void		ctlprint(CFid*, char*, ...);
diff --git a/src/cmd/acme/mail/mail.c b/src/cmd/acme/mail/mail.c
index 474d849..d79721f 100644
--- a/src/cmd/acme/mail/mail.c
+++ b/src/cmd/acme/mail/mail.c
@@ -395,9 +395,11 @@
 mboxcommand(Window *w, char *s)
 {
 	char *args[10], **targs, *save;
+	Window *sbox;
 	Message *m, *next;
 	int ok, nargs, i, j;
-	char buf[128];
+	CFid *searchfd;
+	char buf[128], *res;
 
 	nargs = tokenize(s, args, nelem(args));
 	if(nargs == 0)
@@ -415,6 +417,10 @@
 			fprint(2, "mail: mailbox not written\n");
 			return 1;
 		}
+		if(w != mbox.w){
+			windel(w, 1);
+			return 1;
+		}
 		ok = 1;
 		for(m=mbox.head; m!=nil; m=next){
 			next = m->next;
@@ -475,6 +481,61 @@
 		free(targs);
 		return 1;
 	}
+	if(strcmp(s, "Search") == 0){
+		if(nargs <= 1)
+			return 1;
+		s = estrstrdup(mboxname, "/search");
+		searchfd = fsopen(mailfs, s, ORDWR);
+		if(searchfd == nil)
+			return 1;
+		save = estrdup(args[1]);
+		for(i=2; i<nargs; i++)
+			save = eappend(save, " ", args[i]);
+		fswrite(searchfd, save, strlen(save));
+		fsseek(searchfd, 0, 0);
+		j = fsread(searchfd, buf, sizeof buf - 1);
+ 		if(j == 0){
+			fprint(2, "[%s] search %s: no results found\n", mboxname, save);
+			fsclose(searchfd);
+			free(save);
+			return 1;
+		}
+		free(save);
+		buf[j] = '\0';
+		res = estrdup(buf);
+		j = fsread(searchfd, buf, sizeof buf - 1);
+		for(; j != 0; j = fsread(searchfd, buf, sizeof buf - 1), buf[j] = '\0')
+			res = eappend(res, "", buf);
+		fsclose(searchfd);
+
+		sbox = newwindow();
+		winname(sbox, s);
+		free(s);
+		threadcreate(mainctl, sbox, STACK);
+		winopenbody(sbox, OWRITE);
+
+		/* show results in reverse order */
+		m = mbox.tail;
+		save = nil;
+		for(s=strrchr(res, ' '); s!=nil || save!=res; s=strrchr(res, ' ')){
+			if(s != nil){
+				save = s+1;
+				*s = '\0';
+			}
+			else save = res;
+			save = estrstrdup(save, "/");
+			for(; m && strcmp(save, m->name) != 0; m=m->prev);
+			free(save);
+			if(m == nil)
+				break;
+			fsprint(sbox->body, "%s%s\n", m->name, info(m, 0, 0));
+			m = m->prev;
+		}
+		free(res);
+		winclean(sbox);
+		winclosebody(sbox);
+		return 1;
+	}
 	return 0;
 }