I have extended the "scan -file" command line so that the "file" can
also be a Maildir directory.

This feature complements the Maildir support added to the inc command
in 1.4.  Just as you may want to inc your mail from Maildir, you might
want to see what awaits you with a scan first.

I've attached the patch.  Let me know how you'd like to work with it.

 < Stephen

diff --git a/Makefile.am b/Makefile.am
index ffc4d65b..0a8f2b48 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -403,6 +403,7 @@ noinst_HEADERS = \
     sbr/m_name.h \
     sbr/m_popen.h \
     sbr/m_rand.h \
+    sbr/maildir_read_and_sort.h \
     sbr/makedir.h \
     sbr/message_id.h \
     sbr/mime_type.h \
@@ -1120,6 +1121,7 @@ sbr_libmh_a_SOURCES = \
     sbr/m_name.c \
     sbr/m_popen.c \
     sbr/m_rand.c \
+    sbr/maildir_read_and_sort.c \
     sbr/makedir.c \
     sbr/message_id.c \
     sbr/mf.c \
diff --git a/docs/pending-release-notes b/docs/pending-release-notes
index 5a932160..a2c415c9 100644
--- a/docs/pending-release-notes
+++ b/docs/pending-release-notes
@@ -23,6 +23,7 @@ NEW FEATURES
      comment indicator.
   3) Add a postproc entry that points to the post that you use.  That can
      be viewed with "mhparam postproc".
+- scan(1) -file argument can be a Maildir directory.
 
 -----------------
 OBSOLETE FEATURES
diff --git a/man/scan.man b/man/scan.man
index 6d41cebb..f823d787 100644
--- a/man/scan.man
+++ b/man/scan.man
@@ -92,13 +92,25 @@ The
 .I filename
 switch allows the user to obtain a
 .B scan
-listing of a mail drop file as produced by
-.BR packf .
+listing of a mail drop.
 This listing
-includes every message in the file (you can't scan individual messages).
+includes every message in the mail drop (you can't scan individual messages).
 The switch
 .B \-reverse
 is ignored with this option.
+If
+.I filename
+is a file, it can be in
+.B mbox
+or
+.B MMDF
+format, as produced by
+.BR packf .
+If
+.I filename
+is a directory, it is considered to be in
+.B Maildir
+format.
 .PP
 The switch
 .B \-width
diff --git a/sbr/maildir_read_and_sort.c b/sbr/maildir_read_and_sort.c
new file mode 100644
index 00000000..bb67f47a
--- /dev/null
+++ b/sbr/maildir_read_and_sort.c
@@ -0,0 +1,75 @@
+/* maildir_read_and_sort.c -- returns a sorted list of msgs in a Maildir.
+ *
+ * This code is Copyright (c) 2020, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ */
+
+#include "h/mh.h"
+
+#include "sbr/maildir_read_and_sort.h"
+
+#include "sbr/concat.h"
+#include "sbr/error.h"
+
+static int maildir_srt(const void *va, const void *vb) PURE;
+
+static int
+maildir_srt(const void *va, const void *vb)
+{
+    const struct Maildir_entry *a = va, *b = vb;
+    if (a->mtime > b->mtime)
+      return 1;
+    if (a->mtime < b->mtime)
+      return -1;
+    return 0;
+}
+
+static void read_one_dir (char *dirpath, char *dirpath_base,
+                          struct Maildir_entry **maildir, int *maildir_size,
+                          int *nmsgs) {
+    DIR *md;
+    struct dirent *de;
+    struct stat ms;
+    char *cp;
+
+    cp = concat (dirpath_base, dirpath, NULL);
+    if ((md = opendir(cp)) == NULL)
+	die("unable to open %s", cp);
+    while ((de = readdir (md)) != NULL) {
+	if (de->d_name[0] == '.')
+	    continue;
+	if (*nmsgs >= *maildir_size) {
+          if ((*maildir = realloc(*maildir, sizeof(**maildir) * (2*(*nmsgs)+16))) == NULL)
+            die("not enough memory for %d messages", 2*(*nmsgs)+16);
+          *maildir_size = 2*(*nmsgs)+16;
+	}
+	(*maildir)[*nmsgs].filename = concat (cp, "/", de->d_name, NULL);
+	if (stat((*maildir)[*nmsgs].filename, &ms) != 0)
+	    adios ((*maildir)[*nmsgs].filename, "couldn't get delivery time");
+	(*maildir)[*nmsgs].mtime = ms.st_mtime;
+	(*nmsgs)++;
+    }
+    free (cp);
+    closedir (md);
+}
+
+/*
+ * On return, maildir_out will be NULL or point to memory the caller may free.
+ */
+void maildir_read_and_sort (char *maildirpath,
+			    struct Maildir_entry **maildir_out,
+			    int *num_maildir_entries_out) {
+    int num_maildir_entries = 0;
+    struct Maildir_entry *Maildir = NULL;
+    int msize = 0;
+
+    read_one_dir("/new", maildirpath, &Maildir, &msize, &num_maildir_entries);
+    read_one_dir("/cur", maildirpath, &Maildir, &msize, &num_maildir_entries);
+    if (num_maildir_entries == 0)
+	die("no mail to incorporate");
+    qsort (Maildir, num_maildir_entries, sizeof(*Maildir), maildir_srt);
+
+    *num_maildir_entries_out = num_maildir_entries;
+    *maildir_out = Maildir;
+}
diff --git a/sbr/maildir_read_and_sort.h b/sbr/maildir_read_and_sort.h
new file mode 100644
index 00000000..a100288f
--- /dev/null
+++ b/sbr/maildir_read_and_sort.h
@@ -0,0 +1,15 @@
+/* maildir_read_and_sort.h -- returns a sorted list of msgs in a Maildir.
+ *
+ * This code is Copyright (c) 2020, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ */
+
+struct Maildir_entry {
+	char *filename;
+	time_t mtime;
+};
+
+void maildir_read_and_sort (char *maildirpath,
+			    struct Maildir_entry **maildir_out,
+			    int *num_msgs_out);
diff --git a/uip/inc.c b/uip/inc.c
index 1d8e94f3..7ebb0581 100644
--- a/uip/inc.c
+++ b/uip/inc.c
@@ -67,6 +67,7 @@
 #include "sbr/lock_file.h"
 #include "sbr/m_maildir.h"
 #include "sbr/m_mktemp.h"
+#include "sbr/maildir_read_and_sort.h"
 
 #ifndef TLS_SUPPORT
 # define TLSminc(a) (a)
@@ -118,11 +119,8 @@ DEFINE_SWITCH_ARRAY(INC, switches);
 #define INC_FILE  0
 #define INC_POP   1
 
-static struct Maildir_entry {
-	char *filename;
-	time_t mtime;
-} *Maildir = NULL;
-static int num_maildir_entries = 0;
+static struct Maildir_entry *Maildir;
+static int num_maildir_entries;
 static bool snoop;
 
 typedef struct {
@@ -181,21 +179,9 @@ static FILE *in;
 /*
  * prototypes
  */
-static int maildir_srt(const void *va, const void *vb) PURE;
 static void inc_done(int) NORETURN;
 static int pop_action(void *closure, char *);
 
-static int
-maildir_srt(const void *va, const void *vb)
-{
-    const struct Maildir_entry *a = va, *b = vb;
-    if (a->mtime > b->mtime)
-      return 1;
-    if (a->mtime < b->mtime)
-      return -1;
-    return 0;
-}
-
 int
 main (int argc, char **argv)
 {
@@ -478,53 +464,7 @@ main (int argc, char **argv)
 	if (stat (newmail, &s1) == NOTOK || s1.st_size == 0)
 	    die("no mail to incorporate");
 	if (s1.st_mode & S_IFDIR) {
-	    DIR *md;
-	    struct dirent *de;
-	    struct stat ms;
-	    int i;
-	    i = 0;
-	    cp = concat (newmail, "/new", NULL);
-	    if ((md = opendir(cp)) == NULL)
-		die("unable to open %s", cp);
-	    while ((de = readdir (md)) != NULL) {
-		if (de->d_name[0] == '.')
-		    continue;
-		if (i >= num_maildir_entries) {
-		    if ((Maildir = realloc(Maildir, sizeof(*Maildir) * (2*i+16))) == NULL)
-			die("not enough memory for %d messages", 2*i+16);
-		    num_maildir_entries = 2*i+16;
-		}
-		Maildir[i].filename = concat (cp, "/", de->d_name, NULL);
-		if (stat(Maildir[i].filename, &ms) != 0)
-	           adios (Maildir[i].filename, "couldn't get delivery time");
-		Maildir[i].mtime = ms.st_mtime;
-		i++;
-	    }
-	    free (cp);
-	    closedir (md);
-	    cp = concat (newmail, "/cur", NULL);
-	    if ((md = opendir(cp)) == NULL)
-		die("unable to open %s", cp);
-	    while ((de = readdir (md)) != NULL) {
-		if (de->d_name[0] == '.')
-		    continue;
-		if (i >= num_maildir_entries) {
-		    if ((Maildir = realloc(Maildir, sizeof(*Maildir) * (2*i+16))) == NULL)
-			die("not enough memory for %d messages", 2*i+16);
-		    num_maildir_entries = 2*i+16;
-		}
-		Maildir[i].filename = concat (cp, "/", de->d_name, NULL);
-		if (stat(Maildir[i].filename, &ms) != 0)
-	           adios (Maildir[i].filename, "couldn't get delivery time");
-		Maildir[i].mtime = ms.st_mtime;
-		i++;
-	    }
-	    free (cp);
-	    closedir (md);
-	    if (i == 0)
-	        die("no mail to incorporate");
-	    num_maildir_entries = i;
-	    qsort (Maildir, num_maildir_entries, sizeof(*Maildir), maildir_srt);
+	    maildir_read_and_sort(newmail, &Maildir, &num_maildir_entries);
 	}
 
 	cp = mh_xstrdup(newmail);
diff --git a/uip/scan.c b/uip/scan.c
index 12879050..4b72e1a3 100644
--- a/uip/scan.c
+++ b/uip/scan.c
@@ -35,6 +35,7 @@
 #include "h/utils.h"
 #include "sbr/m_maildir.h"
 #include "sbr/terminal.h"
+#include "sbr/maildir_read_and_sort.h"
 
 #define SCAN_SWITCHES \
     X("clear", 0, CLRSW) \
@@ -64,7 +65,7 @@ main (int argc, char **argv)
 {
     bool clearflag = false;
     bool hdrflag = false;
-    int ontty;
+    int ontty = 0;
     int width = -1;
     bool revflag = false;
     int i, state, msgnum;
@@ -167,10 +168,10 @@ main (int argc, char **argv)
      */
     nfs = new_fs (form, format, FORMAT);
 
-    /*
-     * We are scanning a maildrop file
-     */
     if (file) {
+        /*
+         * We have a -file argument
+         */
 	if (msgs.size)
 	    die("\"msgs\" not allowed with -file");
 	if (folder)
@@ -181,10 +182,63 @@ main (int argc, char **argv)
 	    in = stdin;
 	    file = "stdin";
 	} else {
-	    if ((in = fopen (file, "r")) == NULL)
-		adios (file, "unable to open");
+	    /* check if "file" is really a Maildir folder */
+	    struct stat st;
+	    if (stat (file, &st) == NOTOK)
+		adios (file, "unable to stat");
+	    if (!(st.st_mode & S_IFDIR)) {
+		if ((in = fopen (file, "r")) == NULL)
+		    adios (file, "unable to open");
+	    } else {
+		/* 
+		 * We are scanning a Maildir folder
+		 */
+		struct Maildir_entry *Maildir;
+		int num_maildir_entries;
+		int msgnum = 0;
+		char *fnp;
+		FILE *in;
+		int i;
+
+		maildir_read_and_sort(file, &Maildir, &num_maildir_entries);
+		for (i = 0; i < num_maildir_entries; i++) {
+		    msgnum++;
+		    fnp = Maildir[i].filename;
+		    
+		    if ((in = fopen (fnp, "r")) == NULL) {
+			admonish (fnp, "unable to open message");
+			continue;
+		    }
+
+		    switch (state = scan (in, msgnum, 0, nfs, width,
+					  0, 0, hdrflag ? file : NULL,
+					  0L, 1, &scanl)) {
+		    case SCNMSG: 
+		    case SCNERR: 
+			break;
+
+		    default: 
+			die("scan() botch (%d)", state);
+
+		    case SCNEOF: 
+			inform("message %d: empty", msgnum);
+			break;
+		    }
+		    if (scanl)
+			charstring_clear(scanl);
+		    scan_finished ();
+		    hdrflag = false;
+		    fclose (in);
+		    if (ontty)
+			fflush (stdout);
+		}
+		done (0);
+	    }
 	}
 
+	/*
+	 * We are scanning a maildrop file
+	 */
 	if (hdrflag) {
 	    printf ("FOLDER %s\t%s\n", file, dtimenow (1));
 	}

Reply via email to