Added external program hooks.
authorJon Steinhart <jon@fourwinds.com>
Fri, 23 Aug 2002 20:37:01 +0000 (20:37 +0000)
committerJon Steinhart <jon@fourwinds.com>
Fri, 23 Aug 2002 20:37:01 +0000 (20:37 +0000)
16 files changed:
docs/README-ATTACHMENTS
docs/README-HOOKS [new file with mode: 0644]
h/prototypes.h
sbr/Makefile.in
sbr/folder_addmsg.c
sbr/folder_delmsgs.c
sbr/folder_pack.c
sbr/m_convert.c
uip/burst.c
uip/inc.c
uip/mhstoresbr.c
uip/rcvstore.c
uip/refile.c
uip/rmf.c
uip/rmm.c
uip/sortm.c

index ff9db2a..a996364 100644 (file)
@@ -1,3 +1,5 @@
+$Id$
+
 Jon Steinhart's (jon@fourwinds.com) Attachment Handling Mods
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/docs/README-HOOKS b/docs/README-HOOKS
new file mode 100644 (file)
index 0000000..bb5d6ee
--- /dev/null
@@ -0,0 +1,111 @@
+$Id$
+
+Jon Steinhart's (jon@fourwinds.com) External Program Hooks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This blurb describes a changes to nmh that implement an interface
+to external programs.  This interface is different than the limited
+interface provided by things like the rmmproc context entry.
+
+
+Why Did I Do This?
+~~~~~~~~~~~~~~~~~~
+
+I'm working on a project (grokmail) that will get released via GPL sometime
+soon.  This project keeps a database synchronized with the messages in the
+mail system.  New functionality is built on top of this database.  This
+functionality allows fast searching, and searching based on interest
+criteria.  The latter can be used for spam filtering.
+
+The changes to nmh allow external programs to be run whenever a message is
+added to a folder, removed from a folder, or refiled.  The changes are
+implemented in a general way so that it can be used for other purposes than
+mine.
+
+What Are The Changes?
+~~~~~~~~~~~~~~~~~~~~~
+
+The changes add four new profile components:
+
+add-hook:      This is the full pathname of a program that is invoked
+               whenever a message is added to a folder.  The program
+               is passed one argument which is the full pathname of the
+               message file.  The program is executed after the message
+               is written so that it can act upon that message.
+
+del-hook:      This is the full pathname of a program that is invoked
+               whenever a message is deleted from a folder.  The program
+               is passed one argument which is the full pathname of the
+               message file.  The program is executed before the message
+               is written so that it can act upon that message.
+
+ref-hook:      This is the full pathname of a program that is invoked
+               whenever a message is refiled.  The program is passed two
+               arguments:  the first is the full pathname of the original
+               message file, the second is the full pathname of the final
+               message file.  The program is executed after the message
+               is written.
+       
+msg-hook:      This is a text message that is output if the execution of
+               one of the external hook programs fails.  There is a built-in
+               default message if none is specified.
+
+The definition of refiling is a bit tricky.  The refile hook is executed if a
+message is moved from one place to another.  So, for example, the command
+
+       refile -link
+
+causes the add hook to be executed, not the refile hook, because a new message
+is created, the old one isn't moved.
+
+These changes affect the following commands:
+
+burst:         The add hook is executed for messages burst from a digest, and
+               for the table of contents if -inplace is specified.  The delete
+               hook is executed for the original message if -inplace is
+               specified.  The refile hook is executed for messages that are
+               moved.
+
+folder:                The refile hook is executed for -pack.
+
+inc:           The add hook is executed when messages are incorporated.
+
+refile:                Either the add or refile hooks are executed.
+
+rmf:           The delete hook is executed when messages are deleted.
+
+rmm:           The delete hook is executed when messages are deleted.
+
+sortm:         The refile hook is executed for each message moved.  Note that
+               a magic temporary message number of 2147483647 is used to hold
+               messages as they are being shuffled.
+
+
+
+Did I Do This Correctly?
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Well, sort of.  This all works, but I'm not really happy with it.  The issue
+is that an examination of the nmh code shows that message handling is scattered
+all over the place.  Although there are library routines such as folder_addmsg
+and folder_delmsgs, they are not used consistently.  Long term, I think that it
+would be better to make all message handling go through the same choke points.
+
+Also, I added a function to run the external programs.  This sort of stuff is
+also scattered around the nmh code, for example in the code to run the rmmproc.
+Again, I'd like to make this more consistent in the long term.
+
+What Files Did I Change?
+~~~~~~~~~~~~~~~~~~~~~~~~
+uip/
+       burst.c
+       inc.c
+       refile.c
+       rmf.c
+       sortm.c
+
+sbr/
+       folder_addmsg.c
+       folder_delmsgs.c
+       folder_pack.c
+       ext_hook.c      (new file)
index 63ea87e..1b815bc 100644 (file)
@@ -49,9 +49,10 @@ void cpydgst (int, int, char *, char *);
 int decode_rfc2047 (char *, char *);
 void discard (FILE *);
 int done (int);
+int ext_hook(char *, char *, char *);
 int fdcompare (int, int);
-int folder_addmsg (struct msgs **, char *, int, int, int);
-int folder_delmsgs (struct msgs *, int);
+int folder_addmsg (struct msgs **, char *, int, int, int, int);
+int folder_delmsgs (struct msgs *, int, int);
 void folder_free (struct msgs *);
 int folder_pack (struct msgs **, int);
 struct msgs *folder_read (char *);
index 882094e..b27b126 100644 (file)
@@ -57,7 +57,7 @@ SRCS = add.c addrsbr.c ambigsw.c atooi.c brkstring.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  \
-       error.c fdcompare.c folder_addmsg.c folder_delmsgs.c            \
+       error.c ext_hook.o 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                    \
        getarguments.c getcpy.c getfolder.c getpass.c                   \
index 16f4cc5..b3bc891 100644 (file)
 
 int
 folder_addmsg (struct msgs **mpp, char *msgfile, int selected,
-               int unseen, int preserve)
+               int unseen, int preserve, int deleting)
 {
     int infd, outfd, linkerr, first_time, msgnum;
     char *nmsg, newmsg[BUFSIZ];
+    char oldmsg[BUFSIZ];
+    struct msgs *op;
     struct msgs *mp;
     struct stat st1, st2;
 
@@ -132,9 +134,23 @@ folder_addmsg (struct msgs **mpp, char *msgfile, int selected,
        snprintf (newmsg, sizeof(newmsg), "%s/%s", mp->foldpath, nmsg);
 
        /*
-        * Now try to link message into folder
+        * Now try to link message into folder.
+        * Then run the external hook on the message if one was specified in the context.
+        * Run the refile hook if we're moving the message from one place to another.
+        * We have to construct the from path name for this because it's not there.
+        * Run the add hook if the message is getting copied or lined somewhere else.
         */
        if (link (msgfile, newmsg) != -1) {
+
+           if (deleting) {
+               op = folder_read(getfolder(1));
+               (void)snprintf(oldmsg, sizeof (oldmsg), "%s/%s", op->foldpath, msgfile);
+               folder_free(op);
+               (void)ext_hook("ref-hook", oldmsg, newmsg);
+           }
+           else
+               (void)ext_hook("add-hook", newmsg, (char *)0);
+
            return msgnum;
        } else {
            linkerr = errno;
@@ -183,6 +199,12 @@ folder_addmsg (struct msgs **mpp, char *msgfile, int selected,
                    cpydata (infd, outfd, msgfile, newmsg);
                    close (infd);
                    close (outfd);
+
+                   if (deleting)
+                       (void)ext_hook("ref-hook", newmsg, msgfile);
+                   else
+                       (void)ext_hook("add-hook", newmsg, (char *)0);
+
                    return msgnum;
                }
            }
index 3d2e549..4567f6d 100644 (file)
  */
 
 int
-folder_delmsgs (struct msgs *mp, int unlink_msgs)
+folder_delmsgs (struct msgs *mp, int unlink_msgs, int nohook)
 {
     pid_t pid;
     int msgnum, vecp, retval = 0;
     char buf[100], *dp, **vec;
+    char       msgpath[BUFSIZ];
 
     /*
      * If "rmmproc" is defined, exec it to remove messages.
@@ -83,6 +84,19 @@ folder_delmsgs (struct msgs *mp, int unlink_msgs)
            unset_selected (mp, msgnum);
            mp->numsel--;
 
+           /*
+            *  Run the external hook on the message if one was specified in the context.
+            *  All we have is the message number; we have changed to the directory
+            *  containing the message.  So, we need to extract that directory to form
+            *  the complete path.  Note that the caller knows the directory, but has
+            *  no way of passing that to us.
+            */
+
+           if (!nohook) {
+                   (void)snprintf(msgpath, sizeof (msgpath), "%s/%d", getcwd(msgpath, sizeof (msgpath)), msgnum);
+                   (void)ext_hook("del-hook", msgpath, (char *)0);
+               }
+
            dp = m_name (msgnum);
 
            if (unlink_msgs) {
index 7a661a5..bebc145 100644 (file)
@@ -59,6 +59,14 @@ folder_pack (struct msgs **mpp, int verbose)
                    return -1;
                }
 
+               /*
+                * Invoke the external refile hook for each message being renamed.
+                */
+
+               (void)snprintf(oldmsg, sizeof (oldmsg), "%s/%d", mp->foldpath, msgnum);
+               (void)snprintf(newmsg, sizeof (newmsg), "%s/%d", mp->foldpath, hole);
+               ext_hook("ref-hook", oldmsg, newmsg);
+
                /* check if this is the current message */
                if (msgnum == mp->curmsg)
                    newcurrent = hole;
index 8acfb1a..bbefc99 100644 (file)
@@ -225,7 +225,7 @@ single:
 
 /*
  * Convert the various message names to
- * there numeric value.
+ * their numeric values.
  *
  * n     (integer)
  * prev
index 6b9be83..908de0d 100644 (file)
@@ -42,7 +42,7 @@ struct smsg {
  * static prototypes
  */
 static int find_delim (int, struct smsg *);
-static void burst (struct msgs **, int, struct smsg *, int, int, int);
+static void burst (struct msgs **, int, struct smsg *, int, int, int, char *);
 static void cpybrst (FILE *, FILE *, char *, char *, int);
 
 
@@ -156,7 +156,7 @@ main (int argc, char **argv)
                if (verbosw)
                    printf ("%d message%s exploded from digest %d\n",
                            numburst, numburst > 1 ? "s" : "", msgnum);
-               burst (&mp, msgnum, smsgs, numburst, inplace, verbosw);
+               burst (&mp, msgnum, smsgs, numburst, inplace, verbosw, maildir);
            } else {
                if (numburst == 0) {
                    if (!quietsw)
@@ -256,7 +256,7 @@ find_delim (int msgnum, struct smsg *smsgs)
 
 static void
 burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
-       int inplace, int verbosw)
+       int inplace, int verbosw, char *maildir)
 {
     int i, j, mode;
     char *msgnam;
@@ -296,6 +296,9 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
      * If -inplace is given, renumber the messages after the
      * source message, to make room for each of the messages
      * contained within the digest.
+     *
+     * This is equivalent to refiling a message from the point
+     * of view of the external hooks.
      */
     if (inplace) {
        for (i = mp->hghmsg; j > msgnum; i--, j--) {
@@ -307,6 +310,11 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
 
                if (rename (f2, f1) == NOTOK)
                    admonish (f1, "unable to rename %s to", f2);
+
+               (void)snprintf(f1, sizeof (f1), "%s/%d", maildir, i);
+               (void)snprintf(f2, sizeof (f2), "%s/%d", maildir, j);
+               ext_hook("ref-hook", f1, f2);
+
                copy_msg_flags (mp, i, j);
                clear_msg_flags (mp, j);
                mp->msgflags |= SEQMOD;
@@ -316,7 +324,25 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
     
     unset_selected (mp, msgnum);
 
-    /* new hghmsg is hghmsg + numburst */
+    /* new hghmsg is hghmsg + numburst
+     *
+     * At this point, there is an array of numburst smsgs, each element of
+     * which contains the starting and stopping offsets (seeks) of the message
+     * in the digest.  The inplace flag is set if the original digest is replaced
+     * by a message containing the table of contents.  smsgs[0] is that table of
+     * contents.  Go through the message numbers in reverse order (high to low).
+     *
+     * Set f1 to the name of the destination message, f2 to the name of a scratch
+     * file.  Extract a message from the digest to the scratch file.  Move the
+     * original message to a backup file if the destination message number is the
+     * same as the number of the original message, which only happens if the
+     * inplace flag is set.  Then move the scratch file to the destination message.
+     *
+     * Moving the original message to the backup file is equivalent to deleting the
+     * message from the point of view of the external hooks.  And bursting each
+     * message is equivalent to adding a new message.
+     */
+
     i = inplace ? msgnum + numburst : mp->hghmsg;
     for (j = numburst; j >= (inplace ? 0 : 1); i--, j--) {
        strncpy (f1, m_name (i), sizeof(f1));
@@ -336,9 +362,16 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
            strncpy (f3, m_backup (f1), sizeof(f3));
            if (rename (f1, f3) == NOTOK)
                admonish (f3, "unable to rename %s to", f1);
+
+           (void)snprintf(f3, sizeof (f3), "%s/%d", maildir, i);
+           ext_hook("del-hook", f3, (char *)0);
        }
        if (rename (f2, f1) == NOTOK)
            admonish (f1, "unable to rename %s to", f2);
+
+       (void)snprintf(f3, sizeof (f3), "%s/%d", maildir, i);
+       ext_hook("add-hook", f3, (char *)0);
+
        copy_msg_flags (mp, i, msgnum);
        mp->msgflags |= SEQMOD;
     }
index 7886411..ec4f520 100644 (file)
--- a/uip/inc.c
+++ b/uip/inc.c
@@ -245,6 +245,7 @@ main (int argc, char **argv)
     struct msgs *mp;
     struct stat st, s1;
     FILE *aud = NULL;
+    char       b[MAXPATHLEN + 1];
 
 #ifdef POP
     int nmsgs, nbytes, p = 0;
@@ -802,7 +803,6 @@ go_to_it:
            /* link message into folder */
            newmsg = folder_addmsg(mp, tmpfilenam);
 #endif
-
            /* create scanline for new message */
            switch (i = scan (in, msgnum + 1, msgnum + 1, nfs, width,
                              msgnum == hghnum && chgflag, 1, NULL, 0L, noisy)) {
@@ -826,6 +826,13 @@ go_to_it:
 
            case SCNMSG:
            case SCNENC:
+               /*
+                *  Run the external program hook on the message.
+                */
+
+               (void)snprintf(b, sizeof (b), "%s/%d", maildir, msgnum + 1);
+               (void)ext_hook("add-hook", b, (char *)0);
+
                if (aud)
                    fputs (scanl, aud);
 #ifdef MHE
index d91b7b4..2e88df2 100644 (file)
@@ -921,7 +921,7 @@ output_content_folder (char *folder, char *filename)
     /* Read the folder. */
     if ((mp = folder_read (folder))) {
        /* Link file into folder */
-       msgnum = folder_addmsg (&mp, filename, 0, 0, 0);
+       msgnum = folder_addmsg (&mp, filename, 0, 0, 0, 0);
     } else {
        advise (NULL, "unable to read folder %s", folder);
        return NOTOK;
index ca8789f..8f6a6f8 100644 (file)
@@ -203,7 +203,7 @@ main (int argc, char **argv)
      * Link message into folder, and possibly add
      * to the Unseen-Sequence's.
      */
-    if ((msgnum = folder_addmsg (&mp, tmpfilenam, 0, unseensw, 0)) == -1)
+    if ((msgnum = folder_addmsg (&mp, tmpfilenam, 0, unseensw, 0, 0)) == -1)
        done (1);
 
     /*
index 9e1ed20..663092b 100644 (file)
@@ -66,7 +66,7 @@ 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);
+static int m_file (char *, struct st_fold *, int, int, int);
 
 
 int
@@ -213,7 +213,7 @@ main (int argc, char **argv)
            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))
+           if (m_file (files[i], folders, foldp, preserve, 0))
                done (1);
        /* If -nolink, then "remove" files */
        if (!linkf)
@@ -247,11 +247,16 @@ main (int argc, char **argv)
     /* create folder structures for each destination folder */
     opnfolds (folders, foldp);
 
-    /* Link all the selected messages into destination folders */
+    /* Link all the selected messages into destination folders.
+     *
+     * This causes the add hook to be run for messages that are
+     * linked into another folder.  The refile hook is run for
+     * messages that are moved to another 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))
+           if (m_file (cp, folders, foldp, preserve, !linkf))
                done (1);
            free (cp);
        }
@@ -269,9 +274,13 @@ main (int argc, char **argv)
        fflush (stdout);
     }
 
-    /* If -nolink, then "remove" messages from source folder */
+    /* If -nolink, then "remove" messages from source folder.
+     *
+     * Note that folder_delmsgs does not call the delete hook
+     * because the message has already been handled above.
+     */
     if (!linkf) {
-       folder_delmsgs (mp, unlink_msgs);
+       folder_delmsgs (mp, unlink_msgs, 1);
     }
 
     clsfolds (folders, foldp);
@@ -387,13 +396,13 @@ remove_files (int filep, char **files)
  */
 
 static int
-m_file (char *msgfile, struct st_fold *folders, int nfolders, int preserve)
+m_file (char *msgfile, 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)) == -1)
+       if ((msgnum = folder_addmsg (&fp->f_mp, msgfile, 1, 0, preserve, nfolders == 1 && refile)) == -1)
            return 1;
     }
     return 0;
index fccbb09..2909196 100644 (file)
--- a/uip/rmf.c
+++ b/uip/rmf.c
@@ -152,6 +152,12 @@ rmf (char *folder)
        adios (NULL, "unable to read folder +%s", folder);
     others = 0;
 
+    /*
+     * Run the external delete hook program.
+     */
+
+    (void)ext_hook("del-hook", maildir, (char *)0);
+
     j = strlen(BACKUP_PREFIX);
     while ((dp = readdir (dd))) {
        switch (dp->d_name[0]) {
index a18c278..072097a 100644 (file)
--- a/uip/rmm.c
+++ b/uip/rmm.c
@@ -145,7 +145,7 @@ main (int argc, char **argv)
     }
 
     /* "remove" the SELECTED messages */
-    folder_delmsgs (mp, unlink_msgs);
+    folder_delmsgs (mp, unlink_msgs, 0);
 
     seq_save (mp);             /* synchronize message sequences  */
     context_replace (pfolder, folder); /* update current folder   */
index 4b348cf..5cff943 100644 (file)
@@ -232,7 +232,7 @@ main (int argc, char **argv)
 
     if (verbose) {     /* announce what we're doing */
        if (subjsort)
-           printf ("sorting by %s-major %s-minor\n", 
+           printf ("sorting by %s-major %s-minor\n",
                submajor ? subjsort : datesw,
                submajor ? datesw : subjsort);
        else
@@ -240,7 +240,7 @@ main (int argc, char **argv)
     }
 
     /* first sort by date, or by subject-major, date-minor */
-    qsort ((char *) dlist, nmsgs, sizeof(*dlist), 
+    qsort ((char *) dlist, nmsgs, sizeof(*dlist),
            (qsort_comp) (submajor && subjsort ? txtsort : dsort));
 
     /*
@@ -292,7 +292,7 @@ main (int argc, char **argv)
             */
            while (*s && (*s)->s_subj[0] &&
                   strcmp((*s)->s_subj, s[-1]->s_subj) == 0 &&
-                  (datelimit == 0 || 
+                  (datelimit == 0 ||
                   (*s)->s_clock - s[-1]->s_clock <= datelimit)) {
                il[(*s)->s_msg] = 0;
                *fp++ = *s++;
@@ -303,6 +303,12 @@ main (int argc, char **argv)
        free (dlist);
        dlist = flist;
     }
+
+    /*
+     * At this point, dlist is a sorted array of pointers to smsg structures,
+     * each of which contains a message number.
+     */
+
     rename_msgs (mp, dlist);
 
     context_replace (pfolder, folder); /* update current folder         */
@@ -312,7 +318,7 @@ main (int argc, char **argv)
     return done (0);
 }
 
-static int 
+static int
 read_hdrs (struct msgs *mp, char *datesw)
 {
     int msgnum;
@@ -431,7 +437,7 @@ get_fields (char *datesw, int msg, struct smsg *smsg)
            /*
             * try to make the subject "canonical": delete
             * leading "re:", everything but letters & smash
-            * letters to lower case. 
+            * letters to lower case.
             */
            register char  *cp, *cp2, c;
 
@@ -472,7 +478,7 @@ get_fields (char *datesw, int msg, struct smsg *smsg)
 /*
  * sort on dates.
  */
-static int 
+static int
 dsort (struct smsg **a, struct smsg **b)
 {
     if ((*a)->s_clock < (*b)->s_clock)
@@ -488,7 +494,7 @@ dsort (struct smsg **a, struct smsg **b)
 /*
  * sort on subjects.
  */
-static int 
+static int
 subsort (struct smsg **a, struct smsg **b)
 {
     register int i;
@@ -499,7 +505,7 @@ subsort (struct smsg **a, struct smsg **b)
     return (dsort (a, b));
 }
 
-static int 
+static int
 txtsort (struct smsg **a, struct smsg **b)
 {
     register int i;
@@ -517,6 +523,7 @@ rename_chain (struct msgs *mp, struct smsg **mlist, int msg, int endmsg)
 {
     int nxt, old, new;
     char *newname, oldname[BUFSIZ];
+    char newbuf[MAXPATHLEN + 1];
 
     for (;;) {
        nxt = mlist[msg] - smsgs;       /* mlist[msg] is a ptr into smsgs */
@@ -531,11 +538,15 @@ rename_chain (struct msgs *mp, struct smsg **mlist, int msg, int endmsg)
        if (rename (oldname, newname) == NOTOK)
            adios (newname, "unable to rename %s to", oldname);
 
+       (void)snprintf(oldname, sizeof (oldname), "%s/%d", mp->foldpath, old);
+       (void)snprintf(newbuf, sizeof (newbuf), "%s/%d", mp->foldpath, new);
+       ext_hook("ref-hook", oldname, newbuf);
+
        copy_msg_flags (mp, new, old);
        if (mp->curmsg == old)
            seq_setcur (mp, new);
 
-       if (nxt == endmsg) 
+       if (nxt == endmsg)
            break;
 
        msg = nxt;
@@ -550,12 +561,13 @@ rename_msgs (struct msgs *mp, struct smsg **mlist)
     int i, j, old, new;
     seqset_t tmpset;
     char f1[BUFSIZ], tmpfil[BUFSIZ];
+    char newbuf[MAXPATHLEN + 1];
     struct smsg *sp;
 
     strncpy (tmpfil, m_name (mp->hghmsg + 1), sizeof(tmpfil));
 
     for (i = 0; i < nmsgs; i++) {
-       if (! (sp = mlist[i])) 
+       if (! (sp = mlist[i]))
            continue;   /* did this one */
 
        j = sp - smsgs;
@@ -576,12 +588,31 @@ rename_msgs (struct msgs *mp, struct smsg **mlist)
 
        if (rename (f1, tmpfil) == NOTOK)
            adios (tmpfil, "unable to rename %s to ", f1);
+
+       /*
+        *      Run the external hook to refile the old message as message
+        *      number 2147483647.  This is our way of making a temporary
+        *      message number.  I don't really like this.
+        */
+
+       (void)snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, old);
+       (void)snprintf(newbuf, sizeof (newbuf), "%s/2147483647", mp->foldpath);
+       ext_hook("ref-hook", f1, newbuf);
+
        get_msg_flags (mp, &tmpset, old);
 
        rename_chain (mp, mlist, j, i);
        if (rename (tmpfil, m_name(new)) == NOTOK)
            adios (m_name(new), "unable to rename %s to", tmpfil);
 
+       /*
+        *      Run the external hook to refile the temorary message number
+        *      to the real place.
+        */
+
+       (void)snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, new);
+       ext_hook("ref-hook", newbuf, f1);
+
        set_msg_flags (mp, &tmpset, new);
        mp->msgflags |= SEQMOD;
     }