]> diplodocus.org Git - nmh/commitdiff
Merge branch 'newlock'
authorKen Hornstein <kenh@pobox.com>
Thu, 21 Mar 2013 21:14:30 +0000 (17:14 -0400)
committerKen Hornstein <kenh@pobox.com>
Thu, 21 Mar 2013 21:14:30 +0000 (17:14 -0400)
1  2 
Makefile.am
configure.ac
docs/pending-release-notes
man/mh-profile.man
uip/mhbuildsbr.c
uip/mhcachesbr.c
uip/mhstoresbr.c
uip/refile.c
uip/rmm.c

diff --combined Makefile.am
index a18a7c6391f92b90d6577b3e79bc18b699250b25,074adb263eec78a2d688dcbb5ea9a090e9955143..1e64f1592c4c06f7f0c68979a41270fb1bf56aac
@@@ -37,6 -37,7 +37,7 @@@ TESTS_ENVIRONMENT = MH_OBJ_DIR="@abs_bu
                    MH_TEST_DIR="@abs_builddir@/test/testdir" \
                    auxexecdir="$(auxexecdir)" bindir="$(bindir)" \
                    mandir="$(mandir)" sysconfdir="$(sysconfdir)" \
+                   supported_locks="$(supported_locks)" \
                    MULTIBYTE_ENABLED=$(MULTIBYTE_ENABLED) \
                    ICONV_ENABLED=$(ICONV_ENABLED) \
                    $(TESTS_SHELL) ## Keep at end of TESTS_ENVIRONMENT.
@@@ -58,9 -59,10 +59,11 @@@ TESTS = test/ali/test-ali test/anno/tes
        test/inc/test-deb359167 test/inc/test-eom-align \
        test/inc/test-inc-scanout test/inc/test-msgchk \
        test/inc/test-pop \
-       test/install-mh/test-install-mh test/manpages/test-manpages \
+       test/install-mh/test-install-mh \
+       test/locking/test-datalocking test/locking/test-spoollocking \
+       test/manpages/test-manpages \
        test/mhbuild/test-forw test/mhbuild/test-utf8-body \
 +      test/mhfixmsg/test-mhfixmsg \
        test/mhlist/test-mhlist test/mhmail/test-mhmail \
        test/mhparam/test-mhparam test/mhpath/test-mhpath \
        test/mhshow/test-cte-binary test/mhshow/test-qp \
@@@ -127,11 -129,11 +130,11 @@@ BUILT_SOURCES = sbr/sigmsg.h sbr/ctype-
  ##
  bin_PROGRAMS = uip/ali uip/anno uip/burst uip/comp uip/dist uip/flist \
               uip/fmttest uip/folder uip/forw uip/inc uip/install-mh \
 -             uip/mark uip/mhbuild uip/mhlist uip/mhn uip/mhparam \
 -             uip/mhpath uip/mhshow uip/mhstore uip/msgchk uip/msh uip/new \
 -             uip/packf uip/pick uip/prompter uip/refile uip/repl uip/rmf \
 -             uip/rmm uip/scan uip/send uip/show uip/sortm uip/whatnow \
 -             uip/whom
 +             uip/mark uip/mhbuild uip/mhfixmsg uip/mhlist uip/mhn \
 +             uip/mhparam uip/mhpath uip/mhshow uip/mhstore uip/msgchk \
 +             uip/msh uip/new uip/packf uip/pick uip/prompter uip/refile \
 +             uip/repl uip/rmf uip/rmm uip/scan uip/send uip/show uip/sortm \
 +             uip/whatnow uip/whom
  
  bin_SCRIPTS = uip/mhmail etc/sendfiles
  
@@@ -213,9 -215,9 +216,9 @@@ man_MANS = man/ali.1 man/anno.1 man/ap.
           man/forw.1 man/fprev.1 man/inc.1 man/install-mh.1 man/mark.1 \
           man/mh-alias.5 man/mh-chart.7 man/mh-draft.5 man/mh-folders.5 \
           man/mh-format.5 man/mh-mail.5 man/mh-profile.5 man/mh_profile.5 \
 -         man/mh-sequence.5 man/mh-tailor.5 man/mhbuild.1 man/mhl.1 \
 -         man/mhlist.1 man/mhmail.1 man/mhn.1 man/mhparam.1 man/mhpath.1 \
 -         man/mhshow.1 man/mhstore.1 man/msgchk.1 man/msh.1 \
 +         man/mh-sequence.5 man/mh-tailor.5 man/mhbuild.1 man/mhfixmsg.1 \
 +         man/mhl.1 man/mhlist.1 man/mhmail.1 man/mhn.1 man/mhparam.1 \
 +         man/mhpath.1 man/mhshow.1 man/mhstore.1 man/msgchk.1 man/msh.1 \
           man/mts.conf.5 man/new.1 man/next.1 man/nmh.7 man/packf.1 \
           man/pick.1 man/post.8 man/prev.1 man/prompter.1 man/rcvdist.1 \
           man/rcvpack.1 man/rcvstore.1 man/rcvtty.1 man/refile.1 \
@@@ -234,10 -236,10 +237,10 @@@ man_SRCS = man/ali.man man/anno.man man
           man/mh-chart-gen.sh man/mh-draft.man man/mh-folders.man \
           man/mh-format.man man/mh-mail.man man/mh-profile.man \
           man/mh_profile.man man/mh-sequence.man man/mh-tailor.man \
 -         man/mhbuild.man man/mhl.man man/mhlist.man man/mhmail.man \
 -         man/mhn.man man/mhparam.man man/mhpath.man man/mhshow.man \
 -         man/mhstore.man man/msgchk.man man/msh.man man/mts.conf.man \
 -         man/new.man man/next.man man/nmh.man \
 +         man/mhbuild.man man/mhfixmsg.man man/mhl.man man/mhlist.man \
 +         man/mhmail.man man/mhn.man man/mhparam.man man/mhpath.man \
 +         man/mhshow.man man/mhstore.man man/msgchk.man man/msh.man \
 +         man/mts.conf.man man/new.man man/next.man man/nmh.man \
           man/packf.man man/pick.man man/post.man man/prev.man \
           man/prompter.man man/rcvdist.man man/rcvpack.man \
           man/rcvstore.man man/rcvtty.man man/refile.man man/repl.man \
@@@ -301,12 -303,6 +304,12 @@@ uip_mhbuild_SOURCES = uip/mhbuild.c uip
                      uip/mhfree.c uip/mhparse.c uip/termsbr.c uip/md5.c
  uip_mhbuild_LDADD = $(LDADD) $(TERMLIB)
  
 +uip_mhfixmsg_SOURCES = uip/mhfixmsg.c uip/mhparse.c uip/mhcachesbr.c \
 +                     uip/mhoutsbr.c uip/mhmisc.c uip/mhfree.c \
 +                     uip/mhshowsbr.c uip/mhlistsbr.c \
 +                     uip/termsbr.c uip/md5.c
 +uip_mhfixmsg_LDADD = $(LDADD) $(ICONVLIB) $(TERMLIB)
 +
  uip_mhlist_SOURCES = uip/mhlist.c uip/mhparse.c uip/mhcachesbr.c \
                     uip/mhlistsbr.c uip/mhmisc.c uip/mhfree.c uip/termsbr.c \
                     uip/md5.c
@@@ -455,6 -451,8 +458,8 @@@ etc/mts.conf: $(srcdir)/etc/mts.conf.i
        $(SED) -e 's,%mts%,$(MTS),' \
               -e 's,%mailspool%,$(mailspool),' \
               -e 's,%smtpservers%,$(smtpservers),' \
+              -e 's,%default_locking%,$(default_locking),' \
+              -e 's,%supported_locks%,$(supported_locks),' \
                                < $(srcdir)/etc/mts.conf.in > $@
  
  etc/mhn.defaults: $(srcdir)/etc/mhn.defaults.sh $(MHNSEARCHPROG)
@@@ -545,13 -543,6 +550,13 @@@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr
                      sbr/m_mktemp.c sbr/getansreadline.c config/config.c \
                      config/version.c
  
 +##
 +## Because these files use the definitions in the libmh rule below,
 +## they need to be rebuilt if the Makefile changes.
 +##
 +
 +config/sbr_libmh_a-config.$(OBJEXT) sbr/sbr_libmh_a-mts.$(OBJEXT): Makefile
 +
  sbr_libmh_a_CPPFLAGS = -I./sbr -DNMHETCDIR='"$(sysconfdir)"' \
                -DMAILSPOOL='"$(mailspool)"' \
                -DSENDMAILPATH='"$(sendmailpath)"' -DNMHBINDIR='"$(bindir)"' \
@@@ -579,6 -570,8 +584,8 @@@ man/man.sed: Makefil
        @echo 's,%mandir%,$(mandir),g' >> $@
        @echo 's,%mailspool%,$(mailspool),g' >> $@
        @echo 's,%sendmailpath%,$(sendmailpath),g' >> $@
+       @echo 's,%default_locking%,$(default_locking),g' >> $@
+       @echo 's,%supported_locks%,$(supported_locks),g' >> $@
        @echo 's,%manext1%,$(manext1),g' >> $@
        @echo 's,%manext5%,$(manext5),g' >> $@
        @echo 's,%manext7%,$(manext7),g' >> $@
diff --combined configure.ac
index 46c831b579643c4b788c4655e814a64d44f5b3dd,bfa3c51828fdb3263fef2052d257576b5105444d..de7f93f147327075a587410075401561e89360ee
@@@ -8,7 -8,7 +8,7 @@@ AC_PREREQ([2.68]
  AC_INIT([nmh], m4_normalize(m4_include([VERSION])), [nmh-workers@nongnu.org])
  AC_CONFIG_SRCDIR([h/nmh.h])
  AC_CONFIG_HEADER([config.h])
 -AM_INIT_AUTOMAKE([-Wall color-tests foreign serial-tests subdir-objects 1.12])
 +AM_INIT_AUTOMAKE([-Wall foreign serial-tests subdir-objects 1.12])
  
  AC_CANONICAL_HOST
  
@@@ -62,43 -62,6 +62,6 @@@ AS_IF([test x"$with_hash_backup" != x -
  AC_DEFINE_UNQUOTED([BACKUP_PREFIX], "$backup_prefix",
      [The prefix that is prepended to the name of message files when they are "removed" by rmm. This should typically be `,' or `#'.])dnl
  
- dnl What method of locking to use?
- AS_CASE(["$host_os"],
-   [aix*|cygwin*|linux*],
-     [default_locktype="fcntl"; default_locking=FCNTL_LOCKING],
-   [freebsd*|openbsd*|darwin*], [default_locktype="flock"; default_locking=FLOCK_LOCKING],
-   [default_locktype="dot"; default_locking=DOT_LOCKING])
- 
- AC_ARG_WITH([locking],
-   AS_HELP_STRING([--with-locking=@<:@dot|fcntl|flock|lockf@:>@],
-   [specify the file locking method]))
- 
- AS_IF([test x"$with_locking" = x"dot"],
-     [LOCKTYPE="dot"
-     AC_DEFINE([DOT_LOCKING], [1], [Define to use dot based file locking.])],
-   [test x"$with_locking" = x"flock"],
-     [LOCKTYPE="flock"
-     AC_DEFINE([FLOCK_LOCKING], [1], [Define to use flock() based locking.])],
-   [test x"$with_locking" = x"lockf"],
-     [LOCKTYPE="lockf"
-     AC_DEFINE([LOCKF_LOCKING], [1], [Define to use lockf() based locking.])],
-   [test x"$with_locking" = x"fcntl"],
-     [LOCKTYPE="fcntl"
-     AC_DEFINE([FCNTL_LOCKING], [1], [Define to use fnctl() based locking.])],
-   [LOCKTYPE="$default_locktype"
-   AC_DEFINE_UNQUOTED([$default_locking], [1])])
- 
- dnl Should we use a locking directory?
- AC_ARG_ENABLE([lockdir],
-   [AS_HELP_STRING([--enable-lockdir=dir], [Store dot-lock files in "dir"])], [
-   AS_IF([test "x$enableval" = xyes],[
-     AC_MSG_ERROR([--enable-lockdir requires an argument])])
-   AS_IF([test "x$LOCKTYPE" != xdot],[
-     AC_MSG_ERROR([Can only use --enable-lockdir with dot locking])])
-   AC_DEFINE_UNQUOTED([LOCKDIR], ["$enableval"],
-                    [Directory to store dot-locking lock files])
- ])
- 
  dnl What method of posting should post use?
  AC_ARG_WITH([mts],
    AS_HELP_STRING([--with-mts=@<:@smtp|sendmail/smtp|sendmail/pipe@:>@],
@@@ -409,6 -372,9 +372,9 @@@ NMH_CHECK_NETLIB
  dnl Check for readline support
  NMH_READLINE
  
+ dnl Check the locking functions supported and what we should use by default
+ NMH_LOCKING
+ 
  dnl Check for iconv
  NMH_CHECK_ICONV
  
@@@ -680,9 -646,8 +646,8 @@@ man page install path      : ${nmhman
  RPM build root             : ${nmhrpm}
  backup prefix              : ${backup_prefix}
  transport system           : ${MTS}
- file locking type          : ${LOCKTYPE}
+ spool default locking type : ${with_locking}
  default smtp servers       : ${smtpservers}
- default editor             : ${editorpath}
  SASL support               : ${sasl_support}
  TLS support                : ${tls_support}
  ])])dnl
index 899318ef4ef11a71e10ff8c45511387b7ef9ef2c,3ff8fbd909886c45538962a23c34b8c1c32147d0..e275dfa6497d2424c350a9859b569722ed3259f0
@@@ -44,12 -44,7 +44,13 @@@ NEW FEATURE
  - A new program, fmttest(1) is included to help debug format files
  - mhshow/mhstore now have support for RFC-2017 (access-type=url) for
    external message bodies.
 +- Added -retainsequences switch to refile(1).
 +- A new program, mhfixmsg(1), is included to rewrite MIME messages with
 +  various transformations.
 +- Added -[no]rmmproc switches to rmm(1).
 +- Added support for Content-Disposition header (RFC 2183) to mhstore(1)
 +  and mhn(1) when used with -auto.
+ - All nmh commands now support transactional locking for sequence files.
  
  ----------------------------
  OBSOLETE/DEPRECATED FEATURES
diff --combined man/mh-profile.man
index 25f5714594196866750e58f4f374f1627e727cd7,75bea09d4d8588fe6bc97369b793ce9319d3bb63..a85522b0009ebb520e4c40ef71c252c435a997ee
@@@ -1,4 -1,4 +1,4 @@@
 -.TH MH-PROFILE %manext5% "November 6, 2012" "%nmhversion%"
 +.TH MH-PROFILE %manext5% "March 18, 2013" "%nmhversion%"
  .\"
  .\" %nmhwarning%
  .\"
@@@ -189,6 -189,28 +189,28 @@@ for an explanation of the octal number
  (profile, default: 700)
  .RE
  .PP
+ .BR datalocking :
+ fcntl
+ .RS 5
+ The locking algorithm used to lock changes to any
+ .B nmh
+ data files, such as sequences or the context.  The locking algorithm is
+ any one of the following entries:
+ .PP
+ .RS 5
+ .nf
+ %supported_locks%
+ .fi
+ .RE
+ .PP
+ Available locking algorithms can vary depending on what is supported by
+ the operating system.  Note: currently transactional locking is only
+ supported on public sequences; see
+ .IR mh\-sequence (5)
+ for more information.
+ (profile, default: fcntl)
+ .RE
+ .PP
  .IR program :
  .I default switches
  .RS 5
@@@ -535,10 -557,9 +557,10 @@@ to do address verification
  none
  .RS 5
  This is the program used by
 -.B rmm
 +.BR rmm ,
 +.BR refile ,
  and
 -.B refile
 +.B mhfixmsg
  to delete a message from a folder.
  .RE
  .PP
diff --combined uip/mhbuildsbr.c
index 121978d71e8fc969f93eb16cfc7e0c9c06af0644,459a25597fdd64a950eddec4cd4aae923dea151b..5d3679f66b7ee5f90eb04f9d0e52c184b3725924
@@@ -347,6 -347,12 +347,6 @@@ finish_field
  static int
  init_decoded_content (CT ct)
  {
 -    CE ce;
 -
 -    if ((ce = (CE) calloc (1, sizeof(*ce))) == NULL)
 -      adios (NULL, "out of memory");
 -
 -    ct->c_cefile     = ce;
      ct->c_ceopenfnx  = open7Bit;      /* since unencoded */
      ct->c_ceclosefnx = close_encoding;
      ct->c_cesizefnx  = NULL;          /* since unencoded */
@@@ -424,7 -430,7 +424,7 @@@ user_content (FILE *in, char *file, cha
  
      /* allocate basic structure for handling decoded content */
      init_decoded_content (ct);
 -    ce = ct->c_cefile;
 +    ce = &ct->c_cefile;
  
      ci = &ct->c_ctinfo;
      set_id (ct, 0);
@@@ -747,7 -753,7 +747,7 @@@ use_forw
        if (!folder)
            folder = add (getfolder (1), NULL);
  
-       if (!(mp = folder_read (folder)))
+       if (!(mp = folder_read (folder, 0)))
            adios (NULL, "unable to read folder %s", folder);
        for (ap = arguments; *ap; ap++) {
            cp = *ap;
                    if ((p = (CT) calloc (1, sizeof(*p))) == NULL)
                        adios (NULL, "out of memory");
                    init_decoded_content (p);
 -                  pe = p->c_cefile;
 +                  pe = &p->c_cefile;
                    if (get_ctinfo ("message/rfc822", p, 0) == NOTOK)
                        done (1);
                    p->c_type = CT_MESSAGE;
@@@ -920,7 -926,7 +920,7 @@@ set_id (CT ct, int top
  static int
  compose_content (CT ct)
  {
 -    CE ce = ct->c_cefile;
 +    CE ce = &ct->c_cefile;
  
      switch (ct->c_type) {
      case CT_MULTIPART:
@@@ -1157,7 -1163,7 +1157,7 @@@ scan_content (CT ct
      char *cp = NULL, buffer[BUFSIZ];
      struct text *t = NULL;
      FILE *in = NULL;
 -    CE ce = ct->c_cefile;
 +    CE ce = &ct->c_cefile;
  
      /*
       * handle multipart by scanning all subparts
@@@ -1626,7 -1632,7 +1626,7 @@@ calculate_digest (CT ct, int asciiP
      unsigned char digest[16];
      unsigned char outbuf[25];
      MD5_CTX mdContext;
 -    CE ce = ct->c_cefile;
 +    CE ce = &ct->c_cefile;
      char *infilename = ce->ce_file ? ce->ce_file : ct->c_file;
      FILE *in;
  
diff --combined uip/mhcachesbr.c
index 7fa27ab39f9f30c5af145227782037e51de567c9,5f7e147919aef84776ec1092d0e994c3ba1bc1be..f0185682d1f1da8d61e458459e1d3bc2380fd4c3
@@@ -96,7 -96,7 +96,7 @@@ cache_content (CT ct
  {
      int       cachetype;
      char *file, cachefile[BUFSIZ];
 -    CE ce = ct->c_cefile;
 +    CE ce = &ct->c_cefile;
  
      if (!ct->c_id) {
        advise (NULL, "no %s: field in %s", ID_FIELD, ct->c_file);
@@@ -344,19 -344,19 +344,19 @@@ use_raw
  
      make_intermediates (mapfile);
      mask = umask (writing == 2 ? 0077 : 0);
-     if (!(fp = lkfopen (mapfile, "a")) && errno == ENOENT) {
+     if (!(fp = lkfopendata (mapfile, "a")) && errno == ENOENT) {
        int fd;
  
        if ((fd = creat (mapfile, 0666)) != NOTOK) {
            close (fd);
-           fp = lkfopen (mapfile, "a");
+           fp = lkfopendata (mapfile, "a");
        }
      }
      umask (mask);
      if (!fp)
        return NOTOK;
      fprintf (fp, "%s: %s\n", mapname, id);
-     lkfclose (fp, mapfile);
+     lkfclosedata (fp, mapfile);
  
  done_map:
      if (*mapname == '/')
@@@ -378,7 -378,7 +378,7 @@@ find_cache_aux2 (char *mapfile, char *i
      FILE *fp;
      m_getfld_state_t gstate = 0;
  
-     if (!(fp = lkfopen (mapfile, "r")))
+     if (!(fp = lkfopendata (mapfile, "r")))
        return NOTOK;
  
      for (;;) {
                result = strcmp (id, dp);
                free (dp);
                if (result == 0) {
-                   lkfclose (fp, mapfile);
+                   lkfclosedata (fp, mapfile);
                    return OK;
                }
                continue;
      }
      m_getfld_state_destroy (&gstate);
  
-     lkfclose (fp, mapfile);
+     lkfclosedata (fp, mapfile);
      return NOTOK;
  }
diff --combined uip/mhstoresbr.c
index 56214167b0de6f677ec2de9f209f0ae4e7e65acb,6badafeb9ffcbf2454dedc71d40a61506919fd3d..57604b5077ef47905eba9cf0a618a41af07b85ea
@@@ -872,7 -872,7 +872,7 @@@ output_content_folder (char *folder, ch
      struct msgs *mp;
  
      /* Read the folder. */
-     if ((mp = folder_read (folder))) {
+     if ((mp = folder_read (folder, 0))) {
        /* Link file into folder */
        msgnum = folder_addmsg (&mp, filename, 0, 0, 0, 0, (char *)0);
      } else {
@@@ -1021,7 -1021,7 +1021,7 @@@ static voi
  get_storeproc (CT ct)
  {
      char **ap, **ep, *cp;
 -    CI ci = &ct->c_ctinfo;
 +    CI ci;
  
      /*
       * If the storeproc has already been defined,
      if (ct->c_storeproc)
        return;
  
 +    /*
 +     * If there's a Content-Disposition header and it has a filename,
 +     * use that (RFC-2183).
 +     */
 +    if (ct->c_dispo) {
 +      char *cp = strchr (ct->c_dispo, ';');
 +      CI ci = calloc (1, sizeof *ci);
 +      int status;
 +      int found_filename = 0;
 +
 +      if (cp  &&  parse_header_attrs (ct->c_file, strlen (invo_name) + 2, &cp,
 +                                        ci, &status) == OK) {
 +          for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
 +              if (! strcasecmp (*ap, "filename")
 +                  && *(cp = *ep) != '/'
 +                  && *cp != '.'
 +                  && *cp != '|'
 +                  && *cp != '!'
 +                  && !strchr (cp, '%')) {
 +                  ct->c_storeproc = add (cp, NULL);
 +                  found_filename = 1;
 +              }
 +              free (*ap);
 +          }
 +      }
 +
 +      free (ci);
 +      if (found_filename) return;
 +    }
 +
      /*
       * Check the attribute/value pairs, for the attribute "name".
       * If found, do a few sanity checks and copy the value into
       * the storeproc.
       */
 +    ci = &ct->c_ctinfo;
      for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
 -      if (!mh_strcasecmp (*ap, "name")
 +      if (! strcasecmp (*ap, "name")
            && *(cp = *ep) != '/'
            && *cp != '.'
            && *cp != '|'
diff --combined uip/refile.c
index 1d44b362d21aa4b4dfec53660318b2b090774c9b,8dd04fb92a46355de6c6ae280f243f9d03eaf31f..725a7ada28b96ad82855d2e1109c4fd9c3c00719
@@@ -12,7 -12,6 +12,7 @@@
  #include <h/utils.h>
  #include <fcntl.h>
  #include <errno.h>
 +#include <assert.h>
  
  #define REFILE_SWITCHES \
      X("draft", 0, DRAFTSW) \
@@@ -20,8 -19,6 +20,8 @@@
      X("nolink", 0, NLINKSW) \
      X("preserve", 0, PRESSW) \
      X("nopreserve", 0, NPRESSW) \
 +    X("retainsequences", 0, RETAINSEQSSW) \
 +    X("noretainsequences", 0, NRETAINSEQSSW) \
      X("unlink", 0, UNLINKSW) \
      X("nounlink", 0, NUNLINKSW) \
      X("src +folder", 0, SRCSW) \
@@@ -52,14 -49,13 +52,14 @@@ struct st_fold 
  static void opnfolds (struct st_fold *, int);
  static void clsfolds (struct st_fold *, int);
  static void remove_files (int, char **);
 -static int m_file (char *, struct st_fold *, int, int, int);
 +static int m_file (struct msgs *, char *, int, struct st_fold *, int, int, int);
 +static void copy_seqs (struct msgs *, int, struct msgs *, int);
  
  
  int
  main (int argc, char **argv)
  {
 -    int       linkf = 0, preserve = 0, filep = 0;
 +    int       linkf = 0, preserve = 0, retainseqs = 0, filep = 0;
      int foldp = 0, isdf = 0, unlink_msgs = 0;
      int i, msgnum;
      char *cp, *folder = NULL, buf[BUFSIZ];
      while ((cp = *argp++)) {
        if (*cp == '-') {
            switch (smatch (++cp, switches)) {
 -          case AMBIGSW: 
 +          case AMBIGSW:
                ambigsw (cp, switches);
                done (1);
 -          case UNKWNSW: 
 +          case UNKWNSW:
                adios (NULL, "-%s unknown\n", cp);
  
 -          case HELPSW: 
 +          case HELPSW:
                snprintf (buf, sizeof(buf), "%s [msgs] [switches] +folder ...",
                          invo_name);
                print_help (buf, switches, 1);
                print_version(invo_name);
                done (0);
  
 -          case LINKSW: 
 +          case LINKSW:
                linkf++;
                continue;
 -          case NLINKSW: 
 +          case NLINKSW:
                linkf = 0;
                continue;
  
 -          case PRESSW: 
 +          case PRESSW:
                preserve++;
                continue;
 -          case NPRESSW: 
 +          case NPRESSW:
                preserve = 0;
                continue;
  
 +          case RETAINSEQSSW:
 +              retainseqs = 1;
 +              continue;
 +          case NRETAINSEQSSW:
 +              retainseqs = 0;
 +              continue;
 +
            case UNLINKSW:
                unlink_msgs++;
                continue;
                unlink_msgs = 0;
                continue;
  
 -          case SRCSW: 
 +          case SRCSW:
                if (folder)
                    adios (NULL, "only one source folder at a time!");
                if (!(cp = *argp++) || *cp == '-')
                isdf = 0;
                files[filep++] = getcpy (m_draft (NULL, NULL, 1, &isdf));
                continue;
 -          case FILESW: 
 +          case FILESW:
                if (filep > NFOLDERS)
                    adios (NULL, "only %d files allowed!", NFOLDERS);
                if (!(cp = *argp++) || *cp == '-')
                files[filep++] = path (cp, TFILE);
                continue;
  
 -          case RPROCSW: 
 +          case RPROCSW:
                if (!(rmmproc = *argp++) || *rmmproc == '-')
                    adios (NULL, "missing argument to %s", argp[-2]);
                continue;
 -          case NRPRCSW: 
 +          case NRPRCSW:
                rmmproc = NULL;
                continue;
            }
            adios (NULL, "use -file or some messages, not both");
        opnfolds (folders, foldp);
        for (i = 0; i < filep; i++)
 -          if (m_file (files[i], folders, foldp, preserve, 0))
 +          if (m_file (0, files[i], 0, folders, foldp, preserve, 0))
                done (1);
        /* If -nolink, then "remove" files */
        if (!linkf)
        adios (maildir, "unable to change directory to");
  
      /* read source folder and create message structure */
-     if (!(mp = folder_read (folder)))
+     if (!(mp = folder_read (folder, 1)))
        adios (NULL, "unable to read folder %s", folder);
  
      /* check for empty folder */
      for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
        if (is_selected (mp, msgnum)) {
            cp = getcpy (m_name (msgnum));
 -          if (m_file (cp, folders, foldp, preserve, !linkf))
 +          if (m_file (mp, cp, retainseqs ? msgnum : 0, folders, foldp,
 +                        preserve, !linkf))
                done (1);
            free (cp);
        }
@@@ -294,7 -282,7 +294,7 @@@ opnfolds (struct st_fold *folders, int 
  
        if (chdir (nmaildir) == NOTOK)
            adios (nmaildir, "unable to change directory to");
-       if (!(mp = folder_read (fp->f_name)))
+       if (!(mp = folder_read (fp->f_name, 1)))
            adios (NULL, "unable to read folder %s", fp->f_name);
        mp->curmsg = 0;
  
@@@ -359,13 -347,12 +359,13 @@@ remove_files (int filep, char **files
  
  
  /*
 - * Link (or copy) the message into each of
 - * the destination folders.
 + * Link (or copy) the message into each of the destination folders.
 + * If oldmsgnum is not 0, call copy_seqs().
   */
  
  static int
 -m_file (char *msgfile, struct st_fold *folders, int nfolders, int preserve, int refile)
 +m_file (struct msgs *mp, char *msgfile, int oldmsgnum,
 +      struct st_fold *folders, int nfolders, int preserve, int refile)
  {
      int msgnum;
      struct st_fold *fp, *ep;
      for (fp = folders, ep = folders + nfolders; fp < ep; fp++) {
        if ((msgnum = folder_addmsg (&fp->f_mp, msgfile, 1, 0, preserve, nfolders == 1 && refile, maildir)) == -1)
            return 1;
 +      if (oldmsgnum) copy_seqs (mp, oldmsgnum, fp->f_mp, msgnum);
      }
      return 0;
  }
 +
 +
 +/*
 + * Copy sequence information for a refiled message to its
 + * new folder.  Skip the cur sequence.
 + */
 +static void
 +copy_seqs (struct msgs *oldmp, int oldmsgnum, struct msgs *newmp, int newmsgnum)
 +{
 +    char **seq;
 +    int seqnum;
 +
 +    for (seq = oldmp->msgattrs, seqnum = 0; *seq; ++seq, ++seqnum) {
 +      if (strcmp (current, *seq)) {
 +          assert (seqnum == seq_getnum (oldmp, *seq));
 +          if (in_sequence (oldmp, seqnum, oldmsgnum)) {
 +              seq_addmsg (newmp, *seq, newmsgnum,
 +                          is_seq_private (oldmp, seqnum) ? 0 : 1, 0);
 +          }
 +      }
 +    }
 +}
diff --combined uip/rmm.c
index 897c50280428066f0af5f913e06b9d06e3b51430,02a55910ba1a95e15034ad80f8b76e7ea3b75554..64d85cea3312b7ab7ffcd225ea1665d441270a24
+++ b/uip/rmm.c
@@@ -13,8 -13,6 +13,8 @@@
  #define RMM_SWITCHES \
      X("unlink", 0, UNLINKSW) \
      X("nounlink", 0, NUNLINKSW) \
 +    X("rmmproc program", 0, RPROCSW) \
 +    X("normmproc", 0, NRPRCSW) \
      X("version", 0, VERSIONSW) \
      X("help", 0, HELPSW) \
  
@@@ -52,13 -50,13 +52,13 @@@ main (int argc, char **argv
      while ((cp = *argp++)) {
        if (*cp == '-') {
            switch (smatch (++cp, switches)) {
 -          case AMBIGSW: 
 +          case AMBIGSW:
                ambigsw (cp, switches);
                done (1);
 -          case UNKWNSW: 
 +          case UNKWNSW:
                adios (NULL, "-%s unknown\n", cp);
  
 -          case HELPSW: 
 +          case HELPSW:
                snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
                          invo_name);
                print_help (buf, switches, 1);
            case NUNLINKSW:
                unlink_msgs = 0;
                continue;
 +
 +            case RPROCSW:
 +                if (!(rmmproc = *argp++) || *rmmproc == '-')
 +                    adios (NULL, "missing argument to %s", argp[-2]);
 +                continue;
 +            case NRPRCSW:
 +                rmmproc = NULL;
 +                continue;
            }
        }
        if (*cp == '+' || *cp == '@') {
        adios (maildir, "unable to change directory to");
  
      /* read folder and create message structure */
-     if (!(mp = folder_read (folder)))
+     if (!(mp = folder_read (folder, 1)))
        adios (NULL, "unable to read folder %s", folder);
  
      /* check for empty folder */