nmh-workers
[Top] [All Lists]

Re: [Nmh-workers] New new/fn/fp/unseen program

2009-01-16 13:28:35
Peter Maydell <pmaydell(_at_)chiark(_dot_)greenend(_dot_)org(_dot_)uk> writes:

I finally got round to looking at this, as promised.
I guess I'm happy for it to be checked in, modulo the
comments below.

- changing the command names (what should they be called?)

I'm fine with this, but unsure of new names.  Are fnext/fprev
really better?  'new' may be a worse offender than 'fn' or 'fp'
anyway.  I threw out prefixing them all with 'mh' (mhnew), but
saw no comment on that.

Don't think anybody came up with anything much better. I would
go with "new", "fnext" and "fprev", because the space of two
letter command names is very small and I don't think we should
be adding things to it.

Done.

- not using system(3) in unseen, or dropping unseen altogether

I have a stack of other things I want to do first, but afterwards
I may take a look at this.  I never use the unseen command, so
just don't care about this one much.  I'd be fine with dropping
it until someone refactors scan.

You might as well leave the code with system() in there;
there's a TODO comment to remind us about it.

DOne.

- man page (I'll write it if this goes in, and it will document
  folders -fast -recur > `mhpath +`/.folders)

I'm willing to do this if the new commands are accepted.

I do definitely want the documentation, yes.

Done.

Sorry this took so long.  Life with a baby leaves even less spare
time for hacking than I originally figured!

=== modified file 'ChangeLog'
--- ChangeLog   2008-12-27 05:54:19 +0000
+++ ChangeLog   2009-01-16 15:51:59 +0000
@@ -1,3 +1,24 @@
+2009-01-16  Eric Gillespie  <epg(_at_)pretzelnet(_dot_)org>
+
+       * test/runtest, test/tests/inc/test-deb359167,
+       test/tests/inc/test-eom-align, test/tests/manpages/test-manpages:
+       Load common.sh via absolute path, otherwise some /bin/sh
+       (e.g. dash) can't load it.
+
+       * uip/Makefile.in, uip/new.c, test/tests/new/test-basic: Add new
+       program, and fn/fp/unseen symlinks.
+
+       * test/{runtest,setup-test}: Move MH profile under Mail directory
+       so each test script will have its own to muck with, if needed.
+
+       * h/Makefile.in, h/crawl_folders.h, sbr/Makefile.in,
+       sbr/crawl_folders.c, uip/folder.c: Extract the folder crawling
+       code from folder.c into new crawl_folders function, using a
+       callback to assemble the folder info in folder.c.  Drop compare
+       function and use strcmp instead.  Rename addfold and addir to
+       add_folder and add_children (add dir vs. add folder?
+       confusing names).
+
 2008-12-26  Peter Maydell  
<pmaydell(_at_)chiark(_dot_)greenend(_dot_)org(_dot_)uk>
 
        * sbr/m_getfld.c: fix two bugs which could cause us to walk off

=== modified file 'h/Makefile.in'
--- h/Makefile.in       2007-01-16 02:08:10 +0000
+++ h/Makefile.in       2008-08-06 23:29:50 +0000
@@ -10,7 +10,7 @@ srcdir = @srcdir@
 VPATH  = @srcdir@
 
 # header files included in distribution
-HDRS =         addrsbr.h aliasbr.h dropsbr.h fmt_compile.h fmt_scan.h          
\
+HDRS =         addrsbr.h aliasbr.h crawl_folders.h dropsbr.h fmt_compile.h 
fmt_scan.h \
        md5.h mf.h mh.h mhcachesbr.h mhparse.h mime.h msh.h mts.h       \
        netdb.h nmh.h nntp.h picksbr.h popsbr.h prototypes.h rcvmail.h  \
        scansbr.h signals.h tws.h vmhsbr.h utils.h

=== added file 'h/crawl_folders.h'
--- h/crawl_folders.h   1970-01-01 00:00:00 +0000
+++ h/crawl_folders.h   2008-08-08 06:08:10 +0000
@@ -0,0 +1,18 @@
+
+/*
+ * crawl_folders.h -- crawl folder hierarchy
+ *
+ * $Id$
+ */
+
+#define CRAWL_NUMFOLDERS 100
+
+/* Callbacks return TRUE crawl_folders should crawl the children of `folder'.
+ * Callbacks need not duplicate folder, as crawl_folders does not free it. */
+typedef boolean (crawl_callback_t)(char *folder, void *baton);
+
+/* Crawl the folder hierarchy rooted at the relative path `dir'.  For each
+ * folder, pass `callback' the folder name (as a path relative to the current
+ * directory) and `baton'; the callback may direct crawl_folders not to crawl
+ * its children; see above. */
+void crawl_folders (char *dir, crawl_callback_t *callback, void *baton);

=== modified file 'man/.cvsignore'
--- man/.cvsignore      2006-04-11 05:48:43 +0000
+++ man/.cvsignore      2008-10-28 18:40:29 +0000
@@ -10,9 +10,11 @@ dp.8
 flist.1
 flists.1
 fmtdump.8
+fnext.1
 folder.1
 folders.1
 forw.1
+fprev.1
 inc.1
 install-mh.1
 man.sed
@@ -37,6 +39,7 @@ mhstore.1
 msgchk.1
 msh.1
 mts.conf.5
+new.1
 next.1
 nmh.1
 packf.1
@@ -58,5 +61,6 @@ sendfiles.1
 show.1
 slocal.1
 sortm.1
+unseen.1
 whatnow.1
 whom.1

=== modified file 'man/Makefile.in'
--- man/Makefile.in     2006-01-16 10:00:46 +0000
+++ man/Makefile.in     2008-10-28 18:38:59 +0000
@@ -57,6 +57,7 @@ MAN1SRC = ali. anno. burst. comp.             \
        nmh. mhbuild. mhl. mhlist. mhmail.      \
        mhn. mhparam. mhpath. mhshow.           \
        mhstore. msgchk. msh.                   \
+       new. fnext. fprev. unseen.              \
        next. packf. pick. prev.                        \
        prompter. rcvdist. rcvpack.             \
        rcvstore. rcvtty. refile.               \

=== added file 'man/fnext.man'
--- man/fnext.man       1970-01-01 00:00:00 +0000
+++ man/fnext.man       2008-10-28 18:36:08 +0000
@@ -0,0 +1 @@
+.so man1/new.1

=== added file 'man/fprev.man'
--- man/fprev.man       1970-01-01 00:00:00 +0000
+++ man/fprev.man       2008-10-28 18:35:57 +0000
@@ -0,0 +1 @@
+.so man1/new.1

=== added file 'man/new.man'
--- man/new.man 1970-01-01 00:00:00 +0000
+++ man/new.man 2008-10-28 19:44:00 +0000
@@ -0,0 +1,110 @@
+.\"
+.\" %nmhwarning%
+.\" $Id$
+.\"
+.TH NEW %manext1% "%nmhdate%" MH.6.8 [%nmhversion%]
+
+.SH NAME
+new \- report on folders with new messages
+.PP
+fnext \- set current folder to next folder with new messages
+.PP
+fprev \- set current folder to previous folder with new messages
+.PP
+unseen \- scan new messages in all folders with new messages
+
+.SH SYNOPSIS
+.HP 5
+.na
+.B new
+.RI [ sequences ]
+.RB [ \-mode
+.IR mode ]
+.RB [ \-folders
+.IR foldersfile ]
+.RB [ \-version ]
+.RB [ \-help ]
+.PP
+.HP 5
+.B fnext
+is equivalent to
+.B new \-mode fnext
+.PP
+.HP 5
+.B fprev
+is equivalent to
+.B new \-mode fprev
+.PP
+.HP 5
+.B unseen
+is equivalent to
+.B new \-mode unseen
+.ad
+
+.SH DESCRIPTION
+.B New
+in its default mode produces a one\-line\-per\-folder listing of all
+folders containing messages in the listed
+.IR sequences
+or in the sequences listed in the profile entry
+.RI \*(lq Unseen-Sequence \*(rq.
+Each line contains the folder, the number of messages in the desired
+sequences, and the message lists from the .mh_sequences file.  For example:
+.PP
+.RS 5
+.nf
+foo     11.* 40\-50
+bar    380.  760\-772 824\-828
+ total    391.
+.fi
+.RE
+.PP
+The `*' on foo indicates that it is the current folder.  The last line shows
+the total number of messages in the desired sequences.
+.PP
+.B New
+crawls the folder hierarchy recursively to find all folders, and prints them
+in lexicographic order.  Override this behavior by providing
+.IR foldersfile
+containing the pre-sorted list of folders
+.B new
+should check, one per line.
+.PP
+In
+.B fnext
+and
+.B fprev
+modes,
+.B new
+instead changes to the next or previous matching folder, respectively.
+.PP
+In
+.B unseen
+mode,
+.B new
+executes
+.B scan sequences
+for each matching folder.
+
+.SH FILES
+.fc ^ ~
+.nf
+.ta \w'%etcdir%/ExtraBigFileName  'u
+^$HOME/\&.mh\(ruprofile~^The user profile
+.fi
+
+.SH "PROFILE COMPONENTS"
+.fc ^ ~
+.nf
+.ta 2.4i
+.ta \w'ExtraBigProfileName  'u
+^Path:~^To determine the user's nmh directory
+^Current\-Folder:~^To find the default current folder
+^Unseen-Sequence:~^The name of the unseen message sequence
+.fi
+
+.SH "SEE ALSO"
+scan(1), mh\-format(5)
+
+.SH HISTORY
+Based on Luke Mewburn's new (http://www.mewburn.net/luke/src/new).

=== added file 'man/unseen.man'
--- man/unseen.man      1970-01-01 00:00:00 +0000
+++ man/unseen.man      2008-10-28 18:36:12 +0000
@@ -0,0 +1 @@
+.so man1/new.1

=== modified file 'sbr/Makefile.in'
--- sbr/Makefile.in     2008-05-20 19:04:57 +0000
+++ sbr/Makefile.in     2008-08-06 23:30:15 +0000
@@ -58,7 +58,8 @@ SRCS = addrsbr.c ambigsw.c atooi.c brkst
        check_charset.c client.c closefds.c concat.c context_del.c      \
        context_find.c context_foil.c context_read.c                    \
        context_replace.c context_save.c copy.c                         \
-       copyip.c cpydata.c cpydgst.c discard.c done.c dtime.c dtimep.c  \
+       copyip.c cpydata.c cpydgst.c crawl_folders.c                    \
+       discard.c done.c dtime.c dtimep.c                               \
        error.c ext_hook.c fdcompare.c folder_addmsg.c folder_delmsgs.c \
        folder_free.c folder_pack.c folder_read.c                       \
        folder_realloc.c gans.c getans.c getanswer.c                    \

=== added file 'sbr/crawl_folders.c'
--- sbr/crawl_folders.c 1970-01-01 00:00:00 +0000
+++ sbr/crawl_folders.c 2008-08-06 23:41:08 +0000
@@ -0,0 +1,151 @@
+
+/*
+ * crawl_folders.c -- crawl folder hierarchy
+ *
+ * $Id$
+ *
+ * This code is Copyright (c) 2008, 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 <h/crawl_folders.h>
+#include <h/utils.h>
+
+struct crawl_context {
+    int max;                   /* how many folders we currently can hold in
+                                * the array `folders', increased by
+                                * CRAWL_NUMFOLDERS at a time */
+    int total;                 /* how many `folders' actually has */
+    char **folders;            /* the array of folders */
+    int start;
+    int foldp;
+};
+
+/*
+ * Add the folder name into the
+ * list in a sorted fashion.
+ */
+
+static void
+add_folder (char *fold, struct crawl_context *crawl)
+{
+    register int i, j;
+
+    /* if necessary, reallocate the space for folder names */
+    if (crawl->foldp >= crawl->max) {
+       crawl->max += CRAWL_NUMFOLDERS;
+       crawl->folders = mh_xrealloc (crawl->folders,
+                                     crawl->max * sizeof(char *));
+    }
+
+    for (i = crawl->start; i < crawl->foldp; i++)
+       if (strcmp (fold, crawl->folders[i]) < 0) {
+           for (j = crawl->foldp - 1; j >= i; j--)
+               crawl->folders[j + 1] = crawl->folders[j];
+           crawl->foldp++;
+           crawl->folders[i] = fold;
+           return;
+       }
+
+    crawl->total++;
+    crawl->folders[crawl->foldp++] = fold;
+}
+
+static void
+add_children (char *name, struct crawl_context *crawl)
+{
+    char *prefix, *child;
+    struct stat st;
+    struct dirent *dp;
+    DIR * dd;
+    int child_is_folder;
+
+    if (!(dd = opendir (name))) {
+       admonish (name, "unable to read directory ");
+       return;
+    }
+
+    if (strcmp (name, ".") == 0) {
+       prefix = getcpy ("");
+    } else {
+       prefix = concat (name, "/", (void *)NULL);
+    }
+
+    while ((dp = readdir (dd))) {
+       /* If the system supports it, try to skip processing of children we
+        * know are not directories or symlinks. */
+       child_is_folder = -1;
+#if defined(HAVE_STRUCT_DIRENT_D_TYPE)
+       if (dp->d_type == DT_DIR) {
+           child_is_folder = 1;
+       } else if (dp->d_type != DT_LNK && dp->d_type != DT_UNKNOWN) {
+           continue;
+       }
+#endif
+       if (!strcmp (dp->d_name, ".") || !strcmp (dp->d_name, "..")) {
+           continue;
+       }
+       child = concat (prefix, dp->d_name, (void *)NULL);
+       /* If we have no d_type or d_type is DT_LNK or DT_UNKNOWN, stat the
+        * child to see what it is. */
+       if (child_is_folder == -1) {
+           child_is_folder = (stat (child, &st) != -1 && S_ISDIR(st.st_mode));
+       }
+       if (child_is_folder) {
+           /* add_folder saves child in the list, don't free it */
+           add_folder (child, crawl);
+       } else {
+           free (child);
+       }
+    }
+
+    closedir (dd);
+    free(prefix);
+}
+
+static void
+crawl_folders_body (struct crawl_context *crawl,
+                   char *dir, crawl_callback_t *callback, void *baton)
+{
+    int i;
+    int os = crawl->start;
+    int of = crawl->foldp;
+
+    crawl->start = crawl->foldp;
+
+    add_children (dir, crawl);
+
+    for (i = crawl->start; i < crawl->foldp; i++) {
+       char *fold = crawl->folders[i];
+       int crawl_children = 1;
+
+       if (callback != NULL) {
+           crawl_children = callback (fold, baton);
+       }
+
+       if (crawl_children) {
+           crawl_folders_body (crawl, fold, callback, baton);
+       }
+    }
+
+    crawl->start = os;
+    crawl->foldp = of;
+}
+
+void
+crawl_folders (char *dir, crawl_callback_t *callback, void *baton)
+{
+    struct crawl_context *crawl = mh_xmalloc (sizeof(*crawl));
+    crawl->max = CRAWL_NUMFOLDERS;
+    crawl->total = crawl->start = crawl->foldp = 0;
+    crawl->folders = mh_xmalloc (crawl->max * sizeof(*crawl->folders));
+
+    crawl_folders_body (crawl, dir, callback, baton);
+
+    /* Note that we "leak" the folder names, on the assumption that the caller
+     * is using them. */
+    free (crawl->folders);
+    free (crawl);
+}

=== modified file 'test/runtest'
--- test/runtest        2008-12-26 07:30:33 +0000
+++ test/runtest        2009-01-16 15:47:22 +0000
@@ -13,15 +13,18 @@ if [ ! -e "$MH_TEST_DIR/bld/Makefile" ];
    echo "temporary directory missing or broken: running setup-test"
    ./setup-test
    export MH_TEST_DIR=`cat test-temp-dir`
-fi   
+fi
 
-export MH=$MH_TEST_DIR/mh_profile
+export MH=$MH_TEST_DIR/Mail/.mh_profile
 export PATH=$MH_TEST_DIR/bin:$PATH
 
+export MH_TEST_COMMON=$PWD/common.sh
+
 # clean old test data
 rm -rf $MH_TEST_DIR/Mail
 # setup test data
 mkdir $MH_TEST_DIR/Mail
+echo "Path: $MH_TEST_DIR/Mail" > $MH
 folder -create +inbox > /dev/null
 # create 10 basic messages
 for i in `seq 1 10`;

=== modified file 'test/setup-test'
--- test/setup-test     2008-08-15 02:47:29 +0000
+++ test/setup-test     2008-08-16 00:33:57 +0000
@@ -20,5 +20,3 @@ mkdir $TEMPDIR/bld
 cd $TEMPDIR/bld
 $srcdir/configure --prefix=$TEMPDIR --with-locking=fcntl --enable-debug
 make install
-
-echo "Path: $TEMPDIR/Mail" > $TEMPDIR/mh_profile

=== modified file 'test/tests/inc/test-deb359167'
--- test/tests/inc/test-deb359167       2008-12-27 05:54:19 +0000
+++ test/tests/inc/test-deb359167       2009-01-16 15:47:46 +0000
@@ -2,7 +2,7 @@
 # Test a variant of a mailbox which caused debian bug 359167.
 set -e
 
-. common.sh
+. $MH_TEST_COMMON
 
 THISDIR="tests/inc"
 

=== modified file 'test/tests/inc/test-eom-align'
--- test/tests/inc/test-eom-align       2008-12-27 05:54:19 +0000
+++ test/tests/inc/test-eom-align       2009-01-16 15:47:43 +0000
@@ -4,7 +4,7 @@
 
 set -e
 
-. common.sh
+. $MH_TEST_COMMON
 
 THISDIR="tests/inc"
 

=== modified file 'test/tests/manpages/test-manpages'
--- test/tests/manpages/test-manpages   2008-12-27 00:32:07 +0000
+++ test/tests/manpages/test-manpages   2009-01-16 15:47:37 +0000
@@ -6,7 +6,7 @@
 #
 ######################################################
 
-. common.sh
+. $MH_TEST_COMMON
 
 require_prog groff
 

=== added directory 'test/tests/new'
=== added file 'test/tests/new/test-basic'
--- test/tests/new/test-basic   1970-01-01 00:00:00 +0000
+++ test/tests/new/test-basic   2008-10-29 22:24:31 +0000
@@ -0,0 +1,164 @@
+#!/bin/sh
+
+# TODO: Move to a common file tests can source; need more framework...
+failed=0
+check() {
+    diff -u $expected $actual
+    if [ $? -ne 0 ]; then
+        failed=$((failed + 1))
+    fi
+}
+
+folders=$MH_TEST_DIR/Mail/.folders
+
+expected=$MH_TEST_DIR/$$.expected
+actual=$MH_TEST_DIR/$$.actual
+
+# make second folder
+cp -r $MH_TEST_DIR/Mail/inbox $MH_TEST_DIR/Mail/foo1
+cp -r $MH_TEST_DIR/Mail/inbox $MH_TEST_DIR/Mail/foo2
+# but only list inbox and foo2 in .folders, and sorted differently
+cat > $folders <<EOF
+inbox
+foo2
+EOF
+
+# test with no sequence
+cat > $expected <<EOF
+new: must specify sequences or set Unseen-Sequence
+EOF
+new > $actual 2>&1
+check
+
+# test with no desired messages
+cat > $expected <<EOF
+ total      0.
+EOF
+new aseq > $actual 2>&1
+check
+new -folders $folders aseq > $actual 2>&1
+check
+
+# test fnext/fprev with no desired messages
+cat /dev/null > $expected
+fnext aseq > $actual 2>&1
+check
+fprev aseq > $actual 2>&1
+check
+
+# add 1 desired message in each folder
+echo 'aseq: 1' > $MH_TEST_DIR/Mail/inbox/.mh_sequences
+echo 'aseq: 1' > $MH_TEST_DIR/Mail/foo1/.mh_sequences
+echo 'aseq: 1' > $MH_TEST_DIR/Mail/foo2/.mh_sequences
+
+# test with all folders
+cat > $expected <<EOF
+foo1       1.  1
+foo2       1.  1
+inbox      1.* 1
+ total      3.
+EOF
+new aseq > $actual 2>&1
+check
+
+# test with .folders
+cat > $expected <<EOF
+inbox      1.* 1
+foo2       1.  1
+ total      2.
+EOF
+new -folders $folders aseq > $actual 2>&1
+check
+
+# add 2 desired messages to another sequence in each folder
+echo 'bseq: 3-4' >> $MH_TEST_DIR/Mail/inbox/.mh_sequences
+echo 'bseq: 3-4' >> $MH_TEST_DIR/Mail/foo1/.mh_sequences
+echo 'bseq: 3-4' >> $MH_TEST_DIR/Mail/foo2/.mh_sequences
+
+# test listing aseq and bseq
+cat > $expected <<EOF
+foo1       3.  1 3-4
+foo2       3.  1 3-4
+inbox      3.* 1 3-4
+ total      9.
+EOF
+new aseq bseq > $actual 2>&1
+check
+
+# set aseq bseq as unseen
+echo 'Unseen-Sequence: aseq bseq' >> $MH
+new > $actual 2>&1
+check
+
+# test unseen
+cat > $expected <<EOF
+
+3 aseq bseq messages in foo1
+   1  09/29 Test1              Testing message 1<<This is message number 1 >>
+   3  09/29 Test3              Testing message 3<<This is message number 3 >>
+   4  09/29 Test4              Testing message 4<<This is message number 4 >>
+
+3 aseq bseq messages in foo2
+   1  09/29 Test1              Testing message 1<<This is message number 1 >>
+   3  09/29 Test3              Testing message 3<<This is message number 3 >>
+   4  09/29 Test4              Testing message 4<<This is message number 4 >>
+
+3 aseq bseq messages in inbox (*: current folder)
+   1  09/29 Test1              Testing message 1<<This is message number 1 >>
+   3  09/29 Test3              Testing message 3<<This is message number 3 >>
+   4  09/29 Test4              Testing message 4<<This is message number 4 >>
+EOF
+unseen > $actual 2>&1
+check
+
+# test fnext with the current folder not in the list
+echo 'Current-Folder: foo1' > $MH_TEST_DIR/Mail/context
+echo 'inbox  1 3-4' > $expected
+fnext -folders $folders > $actual 2>&1
+check
+
+# test fprev with the current folder not in the list
+echo 'Current-Folder: foo1' > $MH_TEST_DIR/Mail/context
+echo 'inbox  1 3-4' > $expected
+fprev -folders $folders > $actual 2>&1
+check
+
+# test fnext with current folder in the middle of the list
+echo 'Current-Folder: foo2' > $MH_TEST_DIR/Mail/context
+echo 'inbox  1 3-4' > $expected
+fnext > $actual 2>&1
+check
+
+# test fprev with current folder in the middle of the list
+echo 'Current-Folder: foo2' > $MH_TEST_DIR/Mail/context
+echo 'foo1  1 3-4' > $expected
+fprev > $actual 2>&1
+check
+
+# test fprev with current folder at the beginning of the list
+echo 'Current-Folder: foo1' > $MH_TEST_DIR/Mail/context
+echo 'inbox  1 3-4' > $expected
+fprev > $actual 2>&1
+check
+
+# test fnext with current folder at the end of the list
+echo 'Current-Folder: inbox' > $MH_TEST_DIR/Mail/context
+echo 'foo1  1 3-4' > $expected
+fnext > $actual 2>&1
+check
+
+# test fnext with no current folder
+rm $MH_TEST_DIR/Mail/context
+echo 'foo1  1 3-4' > $expected
+fnext > $actual 2>&1
+check
+
+# test fnext with only one folder in the list
+cat > $folders <<EOF
+inbox
+EOF
+echo 'inbox  1 3-4' > $expected
+fnext -folders $folders > $actual 2>&1
+check
+
+exit $failed

=== modified file 'uip/Makefile.in'
--- uip/Makefile.in     2008-08-14 08:11:12 +0000
+++ uip/Makefile.in     2008-10-28 19:41:11 +0000
@@ -60,7 +60,7 @@ SETGID_MAIL    = @SETGID_MAIL@
 # commands to build
 CMDS = ali anno burst comp dist flist folder forw install-mh mark mhbuild \
        mhlist mhmail mhn mhparam mhpath mhshow mhstore msgchk \
-       msh packf pick prompter refile repl rmf rmm scan send show \
+       msh new packf pick prompter refile repl rmf rmm scan send show \
        sortm whatnow whom
 
 ## removed this from CMDS until I can fix it
@@ -83,7 +83,7 @@ SRCS = ali.c aliasbr.c anno.c annosbr.c 
        mhbuildsbr.c mhcachesbr.c mhfree.c mhl.c mhlist.c mhlistsbr.c     \
        mhlsbr.c mhmail.c mhmisc.c mhn.c mhoutsbr.c mhparam.c mhparse.c   \
        mhpath.c mhshow.c mhshowsbr.c mhstore.c mhstoresbr.c mhtest.c     \
-       msgchk.c msh.c mshcmds.c packf.c pick.c picksbr.c popsbr.c \
+       msgchk.c msh.c mshcmds.c new.c packf.c pick.c picksbr.c popsbr.c \
        post.c prompter.c rcvdist.c rcvpack.c rcvstore.c rcvtty.c         \
        refile.c repl.c replsbr.c rmf.c rmm.c scan.c scansbr.c send.c     \
        sendsbr.c show.c slocal.c sortm.c spost.c termsbr.c viamail.c     \
@@ -183,6 +183,9 @@ msgchk: msgchk.o $(POPLIB) $(LOCALLIBS)
 msh: msh.o mshcmds.o vmhsbr.o picksbr.o scansbr.o dropsbr.o mhlsbr.o termsbr.o 
$(LOCALLIBS)
        $(LINK) msh.o mshcmds.o vmhsbr.o picksbr.o scansbr.o dropsbr.o mhlsbr.o 
termsbr.o $(LINKLIBS) $(TERMLIB)
 
+new: new.o $(LOCALLIBS)
+       $(LINK) new.o $(LINKLIBS)
+
 packf: packf.o dropsbr.o $(LOCALLIBS)
        $(LINK) packf.o dropsbr.o $(LINKLIBS)
 
@@ -265,11 +268,17 @@ install-cmds:
 install-lcmds:
        rm -f $(DESTDIR)$(bindir)/flists
        rm -f $(DESTDIR)$(bindir)/folders
+       rm -f $(DESTDIR)$(bindir)/fnext
+       rm -f $(DESTDIR)$(bindir)/fprev
+       rm -f $(DESTDIR)$(bindir)/unseen
        rm -f $(DESTDIR)$(bindir)/prev
        rm -f $(DESTDIR)$(bindir)/next
        rm -f $(DESTDIR)$(libdir)/install-mh
        $(LN) $(DESTDIR)$(bindir)/flist  $(DESTDIR)$(bindir)/flists
        $(LN) $(DESTDIR)$(bindir)/folder $(DESTDIR)$(bindir)/folders
+       $(LN) $(DESTDIR)$(bindir)/new    $(DESTDIR)$(bindir)/fnext
+       $(LN) $(DESTDIR)$(bindir)/new    $(DESTDIR)$(bindir)/fprev
+       $(LN) $(DESTDIR)$(bindir)/new    $(DESTDIR)$(bindir)/unseen
        $(LN) $(DESTDIR)$(bindir)/show   $(DESTDIR)$(bindir)/prev
        $(LN) $(DESTDIR)$(bindir)/show   $(DESTDIR)$(bindir)/next
 

=== modified file 'uip/folder.c'
--- uip/folder.c        2008-08-06 04:06:00 +0000
+++ uip/folder.c        2008-08-12 21:58:28 +0000
@@ -6,12 +6,13 @@
  *
  * $Id: folder.c,v 1.16 2008/08/05 21:06:00 pm215 Exp $
  *
- * This code is Copyright (c) 2002, by the authors of nmh.  See the
+ * This code is Copyright (c) 2002, 2008, 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 <h/crawl_folders.h>
 #include <h/utils.h>
 #include <errno.h>
 
@@ -78,22 +79,10 @@ static int all      = 0;    /* should we ou
 
 static int total_folders = 0;  /* total number of folders                  */
 
-static int start = 0;
-static int foldp = 0;
-
 static char *nmhdir;
 static char *stack = "Folder-Stack";
 static char folder[BUFSIZ];
 
-#define NUMFOLDERS 100
-
-/*
- * This is how many folders we currently can hold in the array
- * `folds'.  We increase this amount by NUMFOLDERS at a time.
- */
-static int maxfolders;
-static char **folds;
-
 /*
  * Structure to hold information about
  * folders as we scan them.
@@ -118,13 +107,10 @@ static int maxFolderInfo;
 /*
  * static prototypes
  */
-static void dodir (char *);
 static int get_folder_info (char *, char *);
+static crawl_callback_t get_folder_info_callback;
 static void print_folders (void);
 static int sfold (struct msgs *, char *);
-static void addir (char *);
-static void addfold (char *);
-static int compare (char *, char *);
 static void readonly_folders (void);
 
 
@@ -350,12 +336,8 @@ main (int argc, char **argv)
            done (0);
     }
 
-    /* Allocate initial space to record folder names */
-    maxfolders = NUMFOLDERS;
-    folds = mh_xmalloc (maxfolders * sizeof(char *));
-
     /* Allocate initial space to record folder information */
-    maxFolderInfo = NUMFOLDERS;
+    maxFolderInfo = CRAWL_NUMFOLDERS;
     fi = mh_xmalloc (maxFolderInfo * sizeof(*fi));
 
     /*
@@ -365,7 +347,7 @@ main (int argc, char **argv)
        /*
         * If no folder is given, do them all
         */
-       /* change directory to base of nmh directory for dodir */
+       /* change directory to base of nmh directory for crawl_folders */
        if (chdir (nmhdir) == NOTOK)
            adios (nmhdir, "unable to change directory to");
        if (!argfolder) {
@@ -373,7 +355,7 @@ main (int argc, char **argv)
                admonish (NULL, "no folder given for message %s", msg);
            readonly_folders (); /* do any readonly folders */
            strncpy (folder, (cp = context_find (pfolder)) ? cp : "", 
sizeof(folder));
-           dodir (".");
+           crawl_folders (".", get_folder_info_callback, NULL);
        } else {
            strncpy (folder, argfolder, sizeof(folder));
            if (get_folder_info (argfolder, msg)) {
@@ -385,7 +367,7 @@ main (int argc, char **argv)
             * we still need to list all level-1 sub-folders.
             */
            if (!frecurse)
-               dodir (folder);
+               crawl_folders (folder, get_folder_info_callback, NULL);
        }
     } else {
        strncpy (folder, argfolder ? argfolder : getfolder (1), sizeof(folder));
@@ -412,32 +394,8 @@ main (int argc, char **argv)
     return 1;
 }
 
-/*
- * Base routine for scanning a folder
- */
-
-static void
-dodir (char *dir)
-{
-    int i;
-    int os = start;
-    int of = foldp;
-
-    start = foldp;
-
-    addir (dir);
-
-    for (i = start; i < foldp; i++) {
-       get_folder_info (folds[i], NULL);
-       fflush (stdout);
-    }
-
-    start = os;
-    foldp = of;
-}
-
 static int
-get_folder_info (char *fold, char *msg)
+get_folder_info_body (char *fold, char *msg, boolean *crawl_children)
 {
     int        i, retval = 1;
     struct msgs *mp = NULL;
@@ -449,7 +407,7 @@ get_folder_info (char *fold, char *msg)
      * for folder information
      */
     if (total_folders >= maxFolderInfo) {
-       maxFolderInfo += NUMFOLDERS;
+       maxFolderInfo += CRAWL_NUMFOLDERS;
        fi = mh_xrealloc (fi, maxFolderInfo * sizeof(*fi));
     }
 
@@ -493,8 +451,32 @@ get_folder_info (char *fold, char *msg)
        folder_free (mp); /* free folder/message structure */
     }
 
-    if (frecurse && (fshort || fi[i].others) && (fi[i].error == 0))
-       dodir (fold);
+    *crawl_children = (frecurse && (fshort || fi[i].others)
+                      && (fi[i].error == 0));
+    return retval;
+}
+
+static boolean
+get_folder_info_callback (char *fold, void *baton)
+{
+    boolean crawl_children;
+    get_folder_info_body (fold, NULL, &crawl_children);
+    fflush (stdout);
+    return crawl_children;
+}
+
+static int
+get_folder_info (char *fold, char *msg)
+{
+    boolean crawl_children;
+    int retval;
+
+    retval = get_folder_info_body (fold, msg, &crawl_children);
+
+    if (crawl_children) {
+       crawl_folders (fold, get_folder_info_callback, NULL);
+    }
+
     return retval;
 }
 
@@ -654,99 +636,6 @@ sfold (struct msgs *mp, char *msg)
 }
 
 
-static void
-addir (char *name)
-{
-    char *prefix, *child;
-    struct stat st;
-    struct dirent *dp;
-    DIR * dd;
-    int child_is_folder;
-
-    if (!(dd = opendir (name))) {
-       admonish (name, "unable to read directory ");
-       return;
-    }
-
-    if (strcmp (name, ".") == 0) {
-       prefix = getcpy ("");
-    } else {
-       prefix = concat (name, "/", (void *)NULL);
-    }
-
-    while ((dp = readdir (dd))) {
-       /* If the system supports it, try to skip processing of children we
-        * know are not directories or symlinks. */
-       child_is_folder = -1;
-#if defined(HAVE_STRUCT_DIRENT_D_TYPE)
-       if (dp->d_type == DT_DIR) {
-           child_is_folder = 1;
-       } else if (dp->d_type != DT_LNK && dp->d_type != DT_UNKNOWN) {
-           continue;
-       }
-#endif
-       if (!strcmp (dp->d_name, ".") || !strcmp (dp->d_name, "..")) {
-           continue;
-       }
-       child = concat (prefix, dp->d_name, (void *)NULL);
-       /* If we have no d_type or d_type is DT_LNK or DT_UNKNOWN, stat the
-        * child to see what it is. */
-       if (child_is_folder == -1) {
-           child_is_folder = (stat (child, &st) != -1 && S_ISDIR(st.st_mode));
-       }
-       if (child_is_folder) {
-           /* addfold saves child in the list, don't free it */
-           addfold (child);
-       } else {
-           free (child);
-       }
-    }
-
-    closedir (dd);
-    free(prefix);
-}
-
-/*
- * Add the folder name into the
- * list in a sorted fashion.
- */
-
-static void
-addfold (char *fold)
-{
-    register int i, j;
-
-    /* if necessary, reallocate the space for folder names */
-    if (foldp >= maxfolders) {
-       maxfolders += NUMFOLDERS;
-       folds = mh_xrealloc (folds, maxfolders * sizeof(char *));
-    }
-
-    for (i = start; i < foldp; i++)
-       if (compare (fold, folds[i]) < 0) {
-           for (j = foldp - 1; j >= i; j--)
-               folds[j + 1] = folds[j];
-           foldp++;
-           folds[i] = fold;
-           return;
-       }
-
-    folds[foldp++] = fold;
-}
-
-
-static int
-compare (char *s1, char *s2)
-{
-    register int i;
-
-    while (*s1 || *s2)
-       if ((i = *s1++ - *s2++))
-           return i;
-
-    return 0;
-}
-
 /*
  * Do the read only folders
  */

=== added file 'uip/new.c'
--- uip/new.c   1970-01-01 00:00:00 +0000
+++ uip/new.c   2008-10-29 22:23:24 +0000
@@ -0,0 +1,511 @@
+
+/*
+ * new.c -- as new,    list all folders with unseen messages
+ *       -- as fnext,  move to next folder with unseen messages
+ *       -- as fprev,  move to previous folder with unseen messages
+ *       -- as unseen, scan all unseen messages
+ * $Id$
+ *
+ * This code is Copyright (c) 2008, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ *
+ * Inspired by Luke Mewburn's new: http://www.mewburn.net/luke/src/new
+ */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <h/mh.h>
+#include <h/crawl_folders.h>
+#include <h/utils.h>
+
+static struct swit switches[] = {
+#define MODESW 0
+    { "mode", 1 },
+#define FOLDERSSW 1
+    { "folders", 1 },
+#define VERSIONSW 2
+    { "version", 1 },
+#define HELPSW 3
+    { "help", 1 },
+    { NULL, 0 }
+};
+
+static enum { NEW, FNEXT, FPREV, UNSEEN } run_mode = NEW;
+
+/* check_folders uses this to maintain state with both .folders list of
+ * folders and with crawl_folders. */
+struct list_state {
+    struct node **first, **cur_node;
+    size_t *maxlen;
+    char *cur;
+    char **sequences;
+    struct node *node;
+};
+
+/* Return the number of messages in a string list of message numbers. */
+static int
+count_messages(char *field)
+{
+    int total = 0;
+    int j, k;
+    char *cp, **ap;
+
+    field = getcpy(field);
+
+    /* copied from seq_read.c:seq_init */
+    for (ap = brkstring (field, " ", "\n"); *ap; ap++) {
+        if ((cp = strchr(*ap, '-')))
+            *cp++ = '\0';
+        if ((j = m_atoi (*ap)) > 0) {
+            k = cp ? m_atoi (cp) : j;
+
+            total += k - j + 1;
+        }
+    }
+
+    free(field);
+
+    return total;
+}
+
+/* Return TRUE if the sequence 'name' is in 'sequences'. */
+static boolean
+seq_in_list(char *name, char *sequences[])
+{
+    int i;
+
+    for (i = 0; sequences[i] != NULL; i++) {
+       if (strcmp(name, sequences[i]) == 0) {
+           return TRUE;
+       }
+    }
+
+    return FALSE;
+}
+
+/* Return the string list of message numbers from the sequences file, or NULL
+ * if none. */
+static char *
+get_msgnums(char *folder, char *sequences[])
+{
+    char *seqfile = concat(m_maildir(folder), "/", mh_seq, (void *)NULL);
+    FILE *fp = fopen(seqfile, "r");
+    int state;
+    char name[NAMESZ], field[BUFSIZ];
+    char *cp;
+    char *msgnums = NULL, *this_msgnums, *old_msgnums;
+
+    /* no sequences file -> no messages */
+    if (fp == NULL) {
+        return NULL;
+    }
+
+    /* copied from seq_read.c:seq_public */
+    for (state = FLD;;) {
+        switch (state = m_getfld (state, name, field, sizeof(field), fp)) {
+            case FLD:
+            case FLDPLUS:
+            case FLDEOF:
+                if (state == FLDPLUS) {
+                    cp = getcpy (field);
+                    while (state == FLDPLUS) {
+                        state = m_getfld (state, name, field,
+                                          sizeof(field), fp);
+                        cp = add (field, cp);
+                    }
+
+                    /* Here's where we differ from seq_public: if it's in a
+                    * sequence we want, save the list of messages. */
+                    if (seq_in_list(name, sequences)) {
+                       this_msgnums = trimcpy(cp);
+                       if (msgnums == NULL) {
+                           msgnums = this_msgnums;
+                       } else {
+                           old_msgnums = msgnums;
+                           msgnums = concat(old_msgnums, " ",
+                                            this_msgnums, (void *)NULL);
+                           free(old_msgnums);
+                           free(this_msgnums);
+                       }
+                    }
+                    free (cp);
+                } else {
+                   /* and here */
+                    if (seq_in_list(name, sequences)) {
+                       this_msgnums = trimcpy(field);
+                       if (msgnums == NULL) {
+                           msgnums = this_msgnums;
+                       } else {
+                           old_msgnums = msgnums;
+                           msgnums = concat(old_msgnums, " ",
+                                            this_msgnums, (void *)NULL);
+                           free(old_msgnums);
+                           free(this_msgnums);
+                       }
+                    }
+                }
+
+                if (state == FLDEOF)
+                    break;
+                continue;
+
+            case BODY:
+            case BODYEOF:
+                adios (NULL, "no blank lines are permitted in %s", seqfile);
+                /* fall */
+
+            case FILEEOF:
+                break;
+
+            default:
+                adios (NULL, "%s is poorly formatted", seqfile);
+        }
+        break;  /* break from for loop */
+    }
+
+    fclose(fp);
+
+    return msgnums;
+}
+
+/* Check `folder' (of length `len') for interesting messages, filling in the
+ * list in `b'. */
+static void
+check_folder(char *folder, size_t len, struct list_state *b)
+{
+    char *msgnums = get_msgnums(folder, b->sequences);
+    int is_cur = strcmp(folder, b->cur) == 0;
+
+    if (is_cur || msgnums != NULL) {
+       if (*b->first == NULL) {
+           *b->first = b->node = mh_xmalloc(sizeof(*b->node));
+       } else {
+           b->node->n_next = mh_xmalloc(sizeof(*b->node));
+           b->node = b->node->n_next;
+       }
+       b->node->n_name = folder;
+       b->node->n_field = msgnums;
+
+       if (*b->maxlen < len) {
+           *b->maxlen = len;
+       }
+    }
+
+    /* Save the node for the current folder, so we can fall back to it. */
+    if (is_cur) {
+       *b->cur_node = b->node;
+    }
+}
+
+static boolean
+crawl_callback(char *folder, void *baton)
+{
+    check_folder(folder, strlen(folder), baton);
+    return TRUE;
+}
+
+/* Scan folders, returning:
+ * first        -- list of nodes for all folders which have desired messages;
+ *                 if the current folder is listed in .folders, it is also in
+ *                 the list regardless of whether it has any desired messages
+ * last         -- last node in list
+ * cur_node     -- node of current folder, if listed in .folders
+ * maxlen       -- length of longest folder name
+ *
+ * `cur' points to the name of the current folder, `folders' points to the
+ * name of a .folder (if NULL, crawl all folders), and `sequences' points to
+ * the array of sequences for which to look.
+ */
+static void
+check_folders(struct node **first, struct node **last,
+             struct node **cur_node, size_t *maxlen,
+             char *cur, char *folders, char *sequences[])
+{
+    struct list_state b;
+    FILE *fp;
+    char *line;
+    size_t len;
+
+    *first = *cur_node = NULL;
+    *maxlen = 0;
+
+    b.first = first;
+    b.cur_node = cur_node;
+    b.maxlen = maxlen;
+    b.cur = cur;
+    b.sequences = sequences;
+
+    if (folders == NULL) {
+       chdir(m_maildir(""));
+       crawl_folders(".", crawl_callback, &b);
+    } else {
+       fp = fopen(folders, "r");
+       if (fp  == NULL) {
+           adios(NULL, "failed to read %s", folders);
+       }
+       while (vfgets(fp, &line) == OK) {
+           len = strlen(line) - 1;
+           line[len] = '\0';
+           check_folder(getcpy(line), len, &b);
+       }
+       fclose(fp);
+    }
+
+    if (*first != NULL) {
+       b.node->n_next = NULL;
+       *last = b.node;
+    }
+}
+
+/* Return a single string of the `sequences' joined by a space (' '). */
+static char *
+join_sequences(char *sequences[])
+{
+    int i;
+    size_t len = 0;
+    char *result, *cp;
+
+    for (i = 0; sequences[i] != NULL; i++) {
+       len += strlen(sequences[i]) + 1;
+    }
+    result = mh_xmalloc(len + 1);
+
+    for (i = 0, cp = result; sequences[i] != NULL; i++, cp += len + 1) {
+       len = strlen(sequences[i]);
+       memcpy(cp, sequences[i], len);
+       cp[len] = ' ';
+    }
+    /* -1 to overwrite the last delimiter */
+    *--cp = '\0';
+
+    return result;
+}
+
+/* Return a struct node for the folder to change to.  This is the next
+ * (previous, if FPREV mode) folder with desired messages, or the current
+ * folder if no folders have desired.  If NEW or UNSEEN mode, print the
+ * output but don't change folders.
+ *
+ * n_name is the folder to change to, and n_field is the string list of
+ * desired message numbers.
+ */
+static struct node *
+doit(char *cur, char *folders, char *sequences[])
+{
+    struct node *first, *cur_node, *node, *last, *prev;
+    size_t folder_len;
+    int count, total = 0;
+    char *command, *sequences_s;
+
+    if (cur == NULL || cur[0] == '\0') {
+        cur = "inbox";
+    }
+
+    check_folders(&first, &last, &cur_node, &folder_len, cur,
+                 folders, sequences);
+
+    if (run_mode == FNEXT || run_mode == FPREV) {
+       if (first->n_next == NULL) {
+           /* We have only one node; any desired messages in it? */
+           if (first->n_field == NULL) {
+               return NULL;
+           } else {
+               return first;
+           }
+       } else if (cur_node == NULL) {
+           /* Current folder is not listed in .folders, return first. */
+           return first;
+       }
+    } else if (run_mode == UNSEEN) {
+       sequences_s = join_sequences(sequences);
+    }
+
+    for (node = first, prev = NULL;
+        node != NULL;
+        prev = node, node = node->n_next) {
+        if (run_mode == FNEXT) {
+            /* If we have a previous node and it is the current
+             * folder, return this node. */
+            if (prev != NULL && strcmp(prev->n_name, cur) == 0) {
+                return node;
+            }
+        } else if (run_mode == FPREV) {
+            if (strcmp(node->n_name, cur) == 0) {
+                /* Found current folder in fprev mode; if we have a
+                 * previous node in the list, return it; else return
+                 * the last node. */
+                if (prev == NULL) {
+                    return last;
+                }
+                return prev;
+            }
+        } else if (run_mode == UNSEEN) {
+            if (node->n_field == NULL) {
+                continue;
+            }
+
+            printf("\n%d %s messages in %s",
+                   count_messages(node->n_field),
+                  sequences_s,
+                   node->n_name);
+            if (strcmp(node->n_name, cur) == 0) {
+                puts(" (*: current folder)");
+            } else {
+                puts("");
+            }
+            fflush(stdout);
+
+           /* TODO: Split enough of scan.c out so that we can call it here. */
+           command = concat("scan +", node->n_name, " ", sequences_s,
+                            (void *)NULL);
+           system(command);
+           free(command);
+        } else {
+            if (node->n_field == NULL) {
+                continue;
+            }
+
+            count = count_messages(node->n_field);
+            total += count;
+
+            printf("%-*s %6d.%c %s\n",
+                   folder_len, node->n_name,
+                   count,
+                   (strcmp(node->n_name, cur) == 0 ? '*' : ' '),
+                   node->n_field);
+        }
+    }
+
+    /* If we're fnext, we haven't checked the last node yet.  If it's the
+     * current folder, return the first node. */
+    if (run_mode == FNEXT && strcmp(last->n_name, cur) == 0) {
+        return first;
+    }
+
+    if (run_mode == NEW) {
+        printf("%-*s %6d.\n", folder_len, " total", total);
+    }
+
+    return cur_node;
+}
+
+int
+main(int argc, char **argv)
+{
+    char **ap, *cp, **argp, **arguments;
+    char help[BUFSIZ];
+    char *folders = NULL;
+    char *sequences[NUMATTRS + 1];
+    int i = 0;
+    char *unseen;
+    struct node *folder;
+
+#ifdef LOCALE
+    setlocale(LC_ALL, "");
+#endif
+    invo_name = r1bindex(argv[0], '/');
+
+    /* read user profile/context */
+    context_read();
+
+    arguments = getarguments (invo_name, argc, argv, 1);
+    argp = arguments;
+
+    /*
+     * Parse arguments
+     */
+    while ((cp = *argp++)) {
+       if (*cp == '-') {
+           switch (smatch (++cp, switches)) {
+           case AMBIGSW:
+               ambigsw (cp, switches);
+               done (1);
+           case UNKWNSW:
+               adios (NULL, "-%s unknown", cp);
+
+           case HELPSW:
+               snprintf (help, sizeof(help), "%s [switches] [sequences]",
+                         invo_name);
+               print_help (help, switches, 1);
+               done (1);
+           case VERSIONSW:
+               print_version(invo_name);
+               done (1);
+
+           case FOLDERSSW:
+               if (!(folders = *argp++) || *folders == '-')
+                   adios(NULL, "missing argument to %s", argp[-2]);
+               continue;
+           case MODESW:
+               if (!(invo_name = *argp++) || *invo_name == '-')
+                   adios(NULL, "missing argument to %s", argp[-2]);
+               invo_name = r1bindex(invo_name, '/');
+               continue;
+           }
+       }
+       /* have a sequence argument */
+       if (!seq_in_list(cp, sequences)) {
+           sequences[i++] = cp;
+       }
+    }
+
+    if (strcmp(invo_name, "fnext") == 0) {
+        run_mode = FNEXT;
+    } else if (strcmp(invo_name, "fprev") == 0) {
+        run_mode = FPREV;
+    } else if (strcmp(invo_name, "unseen") == 0) {
+        run_mode = UNSEEN;
+    }
+
+    if (folders == NULL) {
+       /* will flists */
+    } else {
+       if (folders[0] != '/') {
+           folders = m_maildir(folders);
+       }
+    }
+
+    if (i == 0) {
+       /* no sequence arguments; use unseen */
+       unseen = context_find(usequence);
+       if (unseen == NULL || unseen[0] == '\0') {
+           adios(NULL, "must specify sequences or set %s", usequence);
+       }
+       for (ap = brkstring(unseen, " ", "\n"); *ap; ap++) {
+           sequences[i++] = *ap;
+       }
+    }
+    sequences[i] = NULL;
+
+    folder = doit(context_find(pfolder), folders, sequences);
+    if (folder == NULL) {
+        done(0);
+        return 1;
+    }
+
+    if (run_mode == UNSEEN) {
+        /* All the scan(1)s it runs change the current folder, so we
+         * need to put it back.  Unfortunately, context_replace lamely
+         * ignores the new value you give it if it is the same one it
+         * has in memory.  So, we'll be lame, too.  I'm not sure if i
+         * should just change context_replace... */
+        context_replace(pfolder, "defeat_context_replace_optimization");
+    }
+
+    /* update current folder */
+    context_replace(pfolder, folder->n_name);
+
+    if (run_mode == FNEXT || run_mode == FPREV) {
+        printf("%s  %s\n", folder->n_name, folder->n_field);
+    }
+
+    context_save();
+
+    done (0);
+    return 1;
+}



_______________________________________________
Nmh-workers mailing list
Nmh-workers(_at_)nongnu(_dot_)org
http://lists.nongnu.org/mailman/listinfo/nmh-workers

<Prev in Thread] Current Thread [Next in Thread>