Renamed -version switch to -Version to remove the conflict with -verbose.
[mmh] / uip / burst.c
index 15756d3..8d6e69b 100644 (file)
-
 /*
- * burst.c -- explode digests into individual messages
- *
- * $Id$
- *
- * This code is Copyright (c) 2002, by the authors of nmh.  See the
- * COPYRIGHT file in the root directory of the nmh distribution for
- * complete copyright information.
- */
+** burst.c -- explode digests into individual messages
+**
+** This code is Copyright (c) 2002, 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>
 
 static struct swit switches[] = {
-#define        INPLSW  0
-    { "inplace", 0 },
-#define        NINPLSW 1
-    { "noinplace", 0 },
-#define        QIETSW  2
-    { "quiet", 0 },
-#define        NQIETSW 3
-    { "noquiet", 0 },
-#define        VERBSW  4
-    { "verbose", 0 },
-#define        NVERBSW 5
-    { "noverbose", 0 },
-#define VERSIONSW 6
-    { "version", 0 },
-#define        HELPSW  7
-    { "help", 0 },
-    { NULL, 0 }
+#define VERBSW 0
+       { "verbose", 0 },
+#define NVERBSW 1
+       { "noverbose", 0 },
+#define VERSIONSW 2
+       { "Version", 0 },
+#define HELPSW 3
+       { "help", 0 },
+       { NULL, 0 }
 };
 
 static char delim3[] = "-------";
 
 struct smsg {
-    long s_start;
-    long s_stop;
+       long s_start;
+       long s_stop;
 };
 
 /*
- * static prototypes
- */
-static int find_delim (int, struct smsg *);
-static void burst (struct msgs **, int, struct smsg *, int, int, int, char *);
-static void cpybrst (FILE *, FILE *, char *, char *, int);
+** static prototypes
+*/
+static int find_delim(int, struct smsg *);
+static void burst(struct msgs **, int, struct smsg *, int, int, char *);
+static void cpybrst(FILE *, FILE *, char *, char *, int);
 
 
 int
-main (int argc, char **argv)
+main(int argc, char **argv)
 {
-    int inplace = 0, quietsw = 0, verbosw = 0;
-    int msgp = 0, hi, msgnum, numburst;
-    char *cp, *maildir, *folder = NULL, buf[BUFSIZ];
-    char **argp, **arguments, *msgs[MAXARGS];
-    struct smsg *smsgs;
-    struct msgs *mp;
+       int verbosw = 0;
+       int msgp = 0, hi, msgnum, numburst;
+       char *cp, *maildir, *folder = NULL, buf[BUFSIZ];
+       char **argp, **arguments, *msgs[MAXARGS];
+       struct smsg *smsgs;
+       struct msgs *mp;
 
 #ifdef LOCALE
-    setlocale(LC_ALL, "");
+       setlocale(LC_ALL, "");
 #endif
-    invo_name = r1bindex (argv[0], '/');
-
-    /* read user profile/context */
-    context_read();
-
-    arguments = getarguments (invo_name, argc, argv, 1);
-    argp = arguments;
-
-    while ((cp = *argp++)) {
-       if (*cp == '-') {
-           switch (smatch (++cp, switches)) {
-           case AMBIGSW: 
-               ambigsw (cp, switches);
-               done (1);
-           case UNKWNSW: 
-               adios (NULL, "-%s unknown\n", cp);
-
-           case HELPSW: 
-               snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
-                       invo_name);
-               print_help (buf, switches, 1);
-               done (1);
-           case VERSIONSW:
-               print_version(invo_name);
-               done (1);
-
-           case INPLSW: 
-               inplace++;
-               continue;
-           case NINPLSW: 
-               inplace = 0;
-               continue;
-
-           case QIETSW: 
-               quietsw++;
-               continue;
-           case NQIETSW: 
-               quietsw = 0;
-               continue;
-
-           case VERBSW: 
-               verbosw++;
-               continue;
-           case NVERBSW: 
-               verbosw = 0;
-               continue;
-           }
+       invo_name = mhbasename(argv[0]);
+
+       /* read user profile/context */
+       context_read();
+
+       arguments = getarguments(invo_name, argc, argv, 1);
+       argp = arguments;
+
+       while ((cp = *argp++)) {
+               if (*cp == '-') {
+                       switch (smatch(++cp, switches)) {
+                       case AMBIGSW:
+                               ambigsw(cp, switches);
+                               done(1);
+                       case UNKWNSW:
+                               adios(NULL, "-%s unknown\n", cp);
+
+                       case HELPSW:
+                               snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name);
+                               print_help(buf, switches, 1);
+                               done(1);
+                       case VERSIONSW:
+                               print_version(invo_name);
+                               done(1);
+
+                       case VERBSW:
+                               verbosw++;
+                               continue;
+                       case NVERBSW:
+                               verbosw = 0;
+                               continue;
+                       }
+               }
+               if (*cp == '+' || *cp == '@') {
+                       if (folder)
+                               adios(NULL, "only one folder at a time!");
+                       else
+                               folder = getcpy(expandfol(cp));
+               } else {
+                       msgs[msgp++] = cp;
+               }
        }
-       if (*cp == '+' || *cp == '@') {
-           if (folder)
-               adios (NULL, "only one folder at a time!");
-           else
-               folder = pluspath (cp);
-       } else {
-           msgs[msgp++] = cp;
+
+       if (!msgp)
+               msgs[msgp++] = seq_cur;
+       if (!folder)
+               folder = getcurfol();
+       maildir = toabsdir(folder);
+
+       if (chdir(maildir) == NOTOK)
+               adios(maildir, "unable to change directory to");
+
+       /* read folder and create message structure */
+       if (!(mp = folder_read(folder)))
+               adios(NULL, "unable to read folder %s", folder);
+
+       /* check for empty folder */
+       if (mp->nummsg == 0)
+               adios(NULL, "no messages in %s", folder);
+
+       /* parse all the message ranges/sequences and set SELECTED */
+       for (msgnum = 0; msgnum < msgp; msgnum++)
+               if (!m_convert(mp, msgs[msgnum]))
+                       done(1);
+       seq_setprev(mp);  /* set the previous-sequence */
+
+       smsgs = (struct smsg *)
+               calloc((size_t) (MAXFOLDER + 2), sizeof(*smsgs));
+       if (smsgs == NULL)
+               adios(NULL, "unable to allocate burst storage");
+
+       hi = mp->hghmsg + 1;
+
+       /* burst all the SELECTED messages */
+       for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
+               if (is_selected(mp, msgnum)) {
+                       if ((numburst = find_delim(msgnum, smsgs)) > 0) {
+                               if (verbosw)
+                                       printf("%d message%s exploded from digest %d\n", numburst, numburst > 1 ? "s" : "", msgnum);
+                               burst(&mp, msgnum, smsgs, numburst, verbosw, maildir);
+                       } else if (numburst == 0) {
+                               admonish(NULL, "message %d not in digest format", msgnum);
+                       } else {
+                               adios(NULL, "burst() botch -- you lose big");
+                       }
+               }
        }
-    }
-
-    if (!context_find ("path"))
-       free (path ("./", TFOLDER));
-    if (!msgp)
-       msgs[msgp++] = "cur";
-    if (!folder)
-       folder = getfolder (1);
-    maildir = m_maildir (folder);
-
-    if (chdir (maildir) == NOTOK)
-       adios (maildir, "unable to change directory to");
-
-    /* read folder and create message structure */
-    if (!(mp = folder_read (folder)))
-       adios (NULL, "unable to read folder %s", folder);
-
-    /* check for empty folder */
-    if (mp->nummsg == 0)
-       adios (NULL, "no messages in %s", folder);
-
-    /* parse all the message ranges/sequences and set SELECTED */
-    for (msgnum = 0; msgnum < msgp; msgnum++)
-       if (!m_convert (mp, msgs[msgnum]))
-           done (1);
-    seq_setprev (mp);  /* set the previous-sequence */
-
-    smsgs = (struct smsg *)
-       calloc ((size_t) (MAXFOLDER + 2), sizeof(*smsgs));
-    if (smsgs == NULL)
-       adios (NULL, "unable to allocate burst storage");
-
-    hi = mp->hghmsg + 1;
-
-    /* burst all the SELECTED messages */
-    for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
-       if (is_selected (mp, msgnum)) {
-           if ((numburst = find_delim (msgnum, smsgs)) >= 1) {
-               if (verbosw)
-                   printf ("%d message%s exploded from digest %d\n",
-                           numburst, numburst > 1 ? "s" : "", msgnum);
-               burst (&mp, msgnum, smsgs, numburst, inplace, verbosw, maildir);
-           } else {
-               if (numburst == 0) {
-                   if (!quietsw)
-                       admonish (NULL, "message %d not in digest format",
-                                 msgnum);
-               }  /* this pair of braces was missing before 1999-07-15 */
-               else
-                   adios (NULL, "burst() botch -- you lose big");
-           }
+
+       free(smsgs);
+       context_replace(curfolder, folder);
+
+       /*
+       ** The first message extracted from the first digest
+       ** becomes the current message.
+       */
+       if (hi <= mp->hghmsg) {
+               seq_setcur(mp, hi);
        }
-    }
-
-    free ((char *) smsgs);
-    context_replace (pfolder, folder); /* update current folder */
-
-    /*
-     * If -inplace is given, then the first message burst becomes
-     * the current message (which will now show a table of contents).
-     * Otherwise, the first message extracted from the first digest
-     * becomes the current message.
-     */
-    if (inplace) {
-       if (mp->lowsel != mp->curmsg)
-           seq_setcur (mp, mp->lowsel);
-    } else {
-       if (hi <= mp->hghmsg)
-           seq_setcur (mp, hi);
-    }
-
-    seq_save (mp);     /* synchronize message sequences */
-    context_save ();   /* save the context file         */
-    folder_free (mp);  /* free folder/message structure */
-    done (0);
-    return 1;
+
+       seq_save(mp);
+       context_save();
+       folder_free(mp);
+       done(0);
+       return 1;
 }
 
 
 /*
- * Scan the message and find the beginning and
- * end of all the messages in the digest.
- */
-
+** Scan the message and find the beginning and
+** end of all the messages in the digest.
+*/
 static int
-find_delim (int msgnum, struct smsg *smsgs)
+find_delim(int msgnum, struct smsg *smsgs)
 {
-    int ld3, wasdlm, msgp;
-    long pos;
-    char c, *msgnam;
-    int cc;
-    char buffer[BUFSIZ];
-    FILE *in;
-
-    ld3 = strlen (delim3);
-
-    if ((in = fopen (msgnam = m_name (msgnum), "r")) == NULL)
-       adios (msgnam, "unable to read message");
-
-    for (msgp = 0, pos = 0L; msgp <= MAXFOLDER;) {
-       while (fgets (buffer, sizeof(buffer), in) && buffer[0] == '\n')
-           pos += (long) strlen (buffer);
-       if (feof (in))
-           break;
-       fseek (in, pos, SEEK_SET);
-       smsgs[msgp].s_start = pos;
-
-       for (c = 0; fgets (buffer, sizeof(buffer), in); c = buffer[0]) {
-           if (strncmp (buffer, delim3, ld3) == 0
-                   && (msgp == 1 || c == '\n')
-                   && ((cc = peekc (in)) == '\n' || cc == EOF))
-               break;
-           else
-               pos += (long) strlen (buffer);
-       }
+       int ld3, wasdlm, msgp;
+       long pos;
+       char c, *msgnam;
+       int cc;
+       char buffer[BUFSIZ];
+       FILE *in;
+
+       ld3 = strlen(delim3);
+
+       if ((in = fopen(msgnam = m_name(msgnum), "r")) == NULL)
+               adios(msgnam, "unable to read message");
+
+       for (msgp = 0, pos = 0L; msgp <= MAXFOLDER; msgp++) {
+               while (fgets(buffer, sizeof(buffer), in) && buffer[0] == '\n')
+                       pos += (long) strlen(buffer);
+               if (feof(in)) {
+                       break;
+               }
+               fseek(in, pos, SEEK_SET);
+               smsgs[msgp].s_start = pos;
+
+               for (c = 0; fgets(buffer, sizeof(buffer), in); c = buffer[0]) {
+                       if (strncmp(buffer, delim3, ld3) == 0
+                                       && (msgp == 1 || c == '\n')) {
+                               cc = getc(in);
+                               ungetc(cc, in);
+                               if (cc == '\n' || cc == EOF) {
+                                       break;
+                               }
+                       } else
+                               pos += (long) strlen(buffer);
+               }
 
-       wasdlm = strncmp (buffer, delim3, ld3) == 0;
-       if (smsgs[msgp].s_start != pos)
-           smsgs[msgp++].s_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
-       if (feof (in)) {
-#if 0
-           if (wasdlm) {
-               smsgs[msgp - 1].s_stop -= ((long) strlen (buffer) + 1);
-               msgp++;         /* fake "End of XXX Digest" */
-           }
-#endif
-           break;
+               wasdlm = strncmp(buffer, delim3, ld3) == 0;
+               if (smsgs[msgp].s_start != pos)
+                       smsgs[msgp].s_stop = (c == '\n' && wasdlm) ?
+                                       pos - 1 : pos;
+               if (feof(in)) {
+                       break;
+               }
+               pos += (long) strlen(buffer);
        }
-       pos += (long) strlen (buffer);
-    }
 
-    fclose (in);
-    return (msgp - 1);         /* toss "End of XXX Digest" */
+       fclose(in);
+       return (msgp > 0) ? msgp-1 : 0;  /* toss "End of XXX Digest" */
 }
 
 
 /*
- * Burst out the messages in the digest into the folder
- */
-
+** Burst out the messages in the digest into the folder
+*/
 static void
-burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
-       int inplace, int verbosw, char *maildir)
+burst(struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
+       int verbosw, char *maildir)
 {
-    int i, j, mode;
-    char *msgnam;
-    char f1[BUFSIZ], f2[BUFSIZ], f3[BUFSIZ];
-    FILE *in, *out;
-    struct stat st;
-    struct msgs *mp;
-
-    if ((in = fopen (msgnam = m_name (msgnum), "r")) == NULL)
-       adios (msgnam, "unable to read message");
-
-    mode = fstat (fileno(in), &st) != NOTOK ? (st.st_mode & 0777) : m_gmprot();
-    mp = *mpp;
-
-    /*
-     * See if we have enough space in the folder
-     * structure for all the new messages.
-     */
-    if ((mp->hghmsg + numburst > mp->hghoff) &&
-       !(mp = folder_realloc (mp, mp->lowoff, mp->hghmsg + numburst)))
-       adios (NULL, "unable to allocate folder storage");
-    *mpp = mp;
-
-    j = mp->hghmsg;            /* old value */
-    mp->hghmsg += numburst;
-    mp->nummsg += numburst;
-
-    /*
-     * If this is not the highest SELECTED message, then
-     * increment mp->hghsel by numburst, since the highest
-     * SELECTED is about to be slid down by that amount.
-     */
-    if (msgnum < mp->hghsel)
-       mp->hghsel += 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--) {
-           strncpy (f1, m_name (i), sizeof(f1));
-           strncpy (f2, m_name (j), sizeof(f2));
-           if (does_exist (mp, j)) {
-               if (verbosw)
-                   printf ("message %d becomes message %d\n", j, i);
-
-               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);
+       int i, j, mode;
+       char *msgnam;
+       char destfil[BUFSIZ];
+       FILE *in, *out;
+       struct stat st;
+       struct msgs *mp;
+
+       if ((in = fopen(msgnam = m_name(msgnum), "r")) == NULL)
+               adios(msgnam, "unable to read message");
+
+       mode = fstat(fileno(in), &st) != NOTOK ?
+                       (int)(st.st_mode & 0777) : m_gmprot();
+       mp = *mpp;
+
+       /*
+       ** Ensure we have enough space in the folder
+       ** structure for all the new messages.
+       */
+       if ((mp->hghmsg + numburst > mp->hghoff) && !(mp = folder_realloc(mp,
+                       mp->lowoff, mp->hghmsg + numburst)))
+               adios(NULL, "unable to allocate folder storage");
+       *mpp = mp;
+
+       /*
+       ** 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. Go through the message
+       ** numbers. Ignore smsgs[0], which is the table of contents.
+       */
+       for (j=1, i=mp->hghmsg+1; j<=numburst; j++, i++) {
+               snprintf(destfil, sizeof destfil, "%s/%d", maildir, i);
+               if (!(out = fopen(destfil, "w"))) {
+                       adios(destfil, "unable to open");
+               }
+               if (verbosw) {
+                       printf("message %d of digest %d becomes message %d\n",
+                                       j, msgnum, i);
+               }
+               chmod(destfil, mode);
+               fseek(in, smsgs[j].s_start, SEEK_SET);
+               cpybrst(in, out, msgnam, destfil,
+                               (int) (smsgs[j].s_stop - smsgs[j].s_start));
+               fclose(out);
+               mp->hghmsg++;
+               mp->nummsg++;
+               /*
+               ** Bursting each message is equivalent to adding a
+               ** new message from the point of view of the external hooks.
+               */
+               ext_hook("add-hook", destfil, NULL);
+               copy_msg_flags(mp, i, msgnum);
                mp->msgflags |= SEQMOD;
-           }
        }
-    }
-    
-    unset_selected (mp, msgnum);
-
-    /* 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));
-       strncpy (f2, m_scratch ("", invo_name), sizeof(f2));
-       if (verbosw && i != msgnum)
-           printf ("message %d of digest %d becomes message %d\n", j, msgnum, i);
-
-       if ((out = fopen (f2, "w")) == NULL)
-           adios (f2, "unable to write message");
-       chmod (f2, mode);
-       fseek (in, smsgs[j].s_start, SEEK_SET);
-       cpybrst (in, out, msgnam, f2,
-               (int) (smsgs[j].s_stop - smsgs[j].s_start));
-       fclose (out);
-
-       if (i == msgnum) {
-           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;
-    }
-
-    fclose (in);
+       fclose(in);
 }
 
 
-#define        S1  0
-#define        S2  1
-#define        S3  2
-
 /*
- * Copy a mesage which is being burst out of a digest.
- * It will remove any "dashstuffing" in the message.
- */
-
+** Copy a message which is being burst out of a digest.
+** It will remove any "dashstuffing" in the message.
+*/
 static void
-cpybrst (FILE *in, FILE *out, char *ifile, char *ofile, int len)
+cpybrst(FILE *in, FILE *out, char *ifile, char *ofile, int len)
 {
-    register int c, state;
-
-    for (state = S1; (c = fgetc (in)) != EOF && len > 0; len--) {
-       if (c == 0)
-           continue;
-       switch (state) {
-           case S1: 
-               switch (c) {
-                   case '-': 
-                       state = S3;
-                       break;
-
-                   default: 
-                       state = S2;
-                   case '\n': 
-                       fputc (c, out);
+       int c;
+       enum { S1, S2, S3 } state;
+
+       for (state = S1; (c = fgetc(in)) != EOF && len > 0; len--) {
+               if (c == 0)
+                       continue;
+               switch (state) {
+               case S1:
+                       switch (c) {
+                       case '-':
+                               state = S3;
+                               break;
+
+                       default:
+                               state = S2;
+                       case '\n':
+                               fputc(c, out);
+                               break;
+                       }
                        break;
-               }
-               break;
-
-           case S2: 
-               switch (c) {
-                   case '\n': 
-                       state = S1;
-                   default: 
-                       fputc (c, out);
-                       break;
-               }
-               break;
 
-           case S3: 
-               switch (c) {
-                   case ' ': 
-                       state = S2;
+               case S2:
+                       switch (c) {
+                       case '\n':
+                               state = S1;
+                       default:
+                               fputc(c, out);
+                               break;
+                       }
                        break;
 
-                   default: 
-                       state = (c == '\n') ? S1 : S2;
-                       fputc ('-', out);
-                       fputc (c, out);
+               case S3:
+                       switch (c) {
+                       case ' ':
+                               state = S2;
+                               break;
+
+                       default:
+                               state = (c == '\n') ? S1 : S2;
+                               fputc('-', out);
+                               fputc(c, out);
+                               break;
+                       }
                        break;
                }
-               break;
        }
-    }
 
-    if (ferror (in) && !feof (in))
-       adios (ifile, "error reading");
-    if (ferror (out))
-       adios (ofile, "error writing");
+       if (ferror(in) && !feof(in))
+               adios(ifile, "error reading");
+       if (ferror(out))
+               adios(ofile, "error writing");
 }