source: trunk/third/nmh/uip/burst.c @ 12455

Revision 12455, 9.2 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * burst.c -- explode digests into individual messages
4 *
5 * $Id: burst.c,v 1.1.1.1 1999-02-07 18:14:13 danw Exp $
6 */
7
8#include <h/mh.h>
9
10static struct swit switches[] = {
11#define INPLSW  0
12    { "inplace", 0 },
13#define NINPLSW 1
14    { "noinplace", 0 },
15#define QIETSW  2
16    { "quiet", 0 },
17#define NQIETSW 3
18    { "noquiet", 0 },
19#define VERBSW  4
20    { "verbose", 0 },
21#define NVERBSW 5
22    { "noverbose", 0 },
23#define VERSIONSW 6
24    { "version", 0 },
25#define HELPSW  7
26    { "help", 4 },
27    { NULL, 0 }
28};
29
30static char delim3[] = "-------";
31
32struct smsg {
33    long s_start;
34    long s_stop;
35};
36
37/*
38 * static prototypes
39 */
40static int find_delim (int, struct smsg *);
41static void burst (struct msgs **, int, struct smsg *, int, int, int);
42static void cpybrst (FILE *, FILE *, char *, char *, int);
43
44
45int
46main (int argc, char **argv)
47{
48    int inplace = 0, quietsw = 0, verbosw = 0;
49    int msgp = 0, hi, msgnum, numburst;
50    char *cp, *maildir, *folder = NULL, buf[BUFSIZ];
51    char **argp, **arguments, *msgs[MAXARGS];
52    struct smsg *smsgs;
53    struct msgs *mp;
54
55#ifdef LOCALE
56    setlocale(LC_ALL, "");
57#endif
58    invo_name = r1bindex (argv[0], '/');
59
60    /* read user profile/context */
61    context_read();
62
63    arguments = getarguments (invo_name, argc, argv, 1);
64    argp = arguments;
65
66    while ((cp = *argp++)) {
67        if (*cp == '-') {
68            switch (smatch (++cp, switches)) {
69            case AMBIGSW:
70                ambigsw (cp, switches);
71                done (1);
72            case UNKWNSW:
73                adios (NULL, "-%s unknown\n", cp);
74
75            case HELPSW:
76                snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
77                        invo_name);
78                print_help (buf, switches, 1);
79                done (1);
80            case VERSIONSW:
81                print_version(invo_name);
82                done (1);
83
84            case INPLSW:
85                inplace++;
86                continue;
87            case NINPLSW:
88                inplace = 0;
89                continue;
90
91            case QIETSW:
92                quietsw++;
93                continue;
94            case NQIETSW:
95                quietsw = 0;
96                continue;
97
98            case VERBSW:
99                verbosw++;
100                continue;
101            case NVERBSW:
102                verbosw = 0;
103                continue;
104            }
105        }
106        if (*cp == '+' || *cp == '@') {
107            if (folder)
108                adios (NULL, "only one folder at a time!");
109            else
110                folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
111        } else {
112            msgs[msgp++] = cp;
113        }
114    }
115
116    if (!context_find ("path"))
117        free (path ("./", TFOLDER));
118    if (!msgp)
119        msgs[msgp++] = "cur";
120    if (!folder)
121        folder = getfolder (1);
122    maildir = m_maildir (folder);
123
124    if (chdir (maildir) == NOTOK)
125        adios (maildir, "unable to change directory to");
126
127    /* read folder and create message structure */
128    if (!(mp = folder_read (folder)))
129        adios (NULL, "unable to read folder %s", folder);
130
131    /* check for empty folder */
132    if (mp->nummsg == 0)
133        adios (NULL, "no messages in %s", folder);
134
135    /* parse all the message ranges/sequences and set SELECTED */
136    for (msgnum = 0; msgnum < msgp; msgnum++)
137        if (!m_convert (mp, msgs[msgnum]))
138            done (1);
139    seq_setprev (mp);   /* set the previous-sequence */
140
141    smsgs = (struct smsg *)
142        calloc ((size_t) (MAXFOLDER + 2), sizeof(*smsgs));
143    if (smsgs == NULL)
144        adios (NULL, "unable to allocate burst storage");
145
146    hi = mp->hghmsg + 1;
147
148    /* burst all the SELECTED messages */
149    for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
150        if (is_selected (mp, msgnum)) {
151            if ((numburst = find_delim (msgnum, smsgs)) >= 1) {
152                if (verbosw)
153                    printf ("%d message%s exploded from digest %d\n",
154                            numburst, numburst > 1 ? "s" : "", msgnum);
155                burst (&mp, msgnum, smsgs, numburst, inplace, verbosw);
156            } else {
157                if (numburst == 0)
158                    if (!quietsw)
159                        admonish (NULL, "message %d not in digest format", msgnum);
160                else
161                    adios (NULL, "burst() botch -- you lose big");
162            }
163        }
164    }
165
166    free ((char *) smsgs);
167    context_replace (pfolder, folder);  /* update current folder */
168
169    /*
170     * If -inplace is given, then the first message burst becomes
171     * the current message (which will now show a table of contents).
172     * Otherwise, the first message extracted from the first digest
173     * becomes the current message.
174     */
175    if (inplace) {
176        if (mp->lowsel != mp->curmsg)
177            seq_setcur (mp, mp->lowsel);
178    } else {
179        if (hi <= mp->hghmsg)
180            seq_setcur (mp, hi);
181    }
182
183    seq_save (mp);      /* synchronize message sequences */
184    context_save ();    /* save the context file         */
185    folder_free (mp);   /* free folder/message structure */
186    done (0);
187}
188
189
190/*
191 * Scan the message and find the beginning and
192 * end of all the messages in the digest.
193 */
194
195static int
196find_delim (int msgnum, struct smsg *smsgs)
197{
198    int ld3, wasdlm, msgp;
199    long pos;
200    char c, *msgnam;
201    int cc;
202    char buffer[BUFSIZ];
203    FILE *in;
204
205    ld3 = strlen (delim3);
206
207    if ((in = fopen (msgnam = m_name (msgnum), "r")) == NULL)
208        adios (msgnam, "unable to read message");
209
210    for (msgp = 0, pos = 0L; msgp <= MAXFOLDER;) {
211        while (fgets (buffer, sizeof(buffer), in) && buffer[0] == '\n')
212            pos += (long) strlen (buffer);
213        if (feof (in))
214            break;
215        fseek (in, pos, SEEK_SET);
216        smsgs[msgp].s_start = pos;
217
218        for (c = 0; fgets (buffer, sizeof(buffer), in); c = buffer[0]) {
219            if (strncmp (buffer, delim3, ld3) == 0
220                    && (msgp == 1 || c == '\n')
221                    && ((cc = peekc (in)) == '\n' || cc == EOF))
222                break;
223            else
224                pos += (long) strlen (buffer);
225        }
226
227        wasdlm = strncmp (buffer, delim3, ld3) == 0;
228        if (smsgs[msgp].s_start != pos)
229            smsgs[msgp++].s_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
230        if (feof (in)) {
231#if 0
232            if (wasdlm) {
233                smsgs[msgp - 1].s_stop -= ((long) strlen (buffer) + 1);
234                msgp++;         /* fake "End of XXX Digest" */
235            }
236#endif
237            break;
238        }
239        pos += (long) strlen (buffer);
240    }
241
242    fclose (in);
243    return (msgp - 1);          /* toss "End of XXX Digest" */
244}
245
246
247/*
248 * Burst out the messages in the digest into the folder
249 */
250
251static void
252burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
253        int inplace, int verbosw)
254{
255    int i, j, mode;
256    char *msgnam;
257    char f1[BUFSIZ], f2[BUFSIZ], f3[BUFSIZ];
258    FILE *in, *out;
259    struct stat st;
260    struct msgs *mp;
261
262    if ((in = fopen (msgnam = m_name (msgnum), "r")) == NULL)
263        adios (msgnam, "unable to read message");
264
265    mode = fstat (fileno(in), &st) != NOTOK ? (st.st_mode & 0777) : m_gmprot();
266    mp = *mpp;
267
268    /*
269     * See if we have enough space in the folder
270     * structure for all the new messages.
271     */
272    if ((mp->hghmsg + numburst > mp->hghoff) &&
273        !(mp = folder_realloc (mp, mp->lowoff, mp->hghmsg + numburst)))
274        adios (NULL, "unable to allocate folder storage");
275    *mpp = mp;
276
277    j = mp->hghmsg;             /* old value */
278    mp->hghmsg += numburst;
279    mp->nummsg += numburst;
280
281    /*
282     * If this is not the highest SELECTED message, then
283     * increment mp->hghsel by numburst, since the highest
284     * SELECTED is about to be slid down by that amount.
285     */
286    if (msgnum < mp->hghsel)
287        mp->hghsel += numburst;
288
289    /*
290     * If -inplace is given, renumber the messages after the
291     * source message, to make room for each of the messages
292     * contained within the digest.
293     */
294    if (inplace) {
295        for (i = mp->hghmsg; j > msgnum; i--, j--) {
296            strncpy (f1, m_name (i), sizeof(f1));
297            strncpy (f2, m_name (j), sizeof(f2));
298            if (does_exist (mp, j)) {
299                if (verbosw)
300                    printf ("message %d becomes message %d\n", j, i);
301
302                if (rename (f2, f1) == NOTOK)
303                    admonish (f1, "unable to rename %s to", f2);
304                copy_msg_flags (mp, i, j);
305                clear_msg_flags (mp, j);
306                mp->msgflags |= SEQMOD;
307            }
308        }
309    }
310   
311    unset_selected (mp, msgnum);
312
313    /* new hghmsg is hghmsg + numburst */
314    i = inplace ? msgnum + numburst : mp->hghmsg;
315    for (j = numburst; j >= (inplace ? 0 : 1); i--, j--) {
316        strncpy (f1, m_name (i), sizeof(f1));
317        strncpy (f2, m_scratch ("", invo_name), sizeof(f2));
318        if (verbosw && i != msgnum)
319            printf ("message %d of digest %d becomes message %d\n", j, msgnum, i);
320
321        if ((out = fopen (f2, "w")) == NULL)
322            adios (f2, "unable to write message");
323        chmod (f2, mode);
324        fseek (in, smsgs[j].s_start, SEEK_SET);
325        cpybrst (in, out, msgnam, f2,
326                (int) (smsgs[j].s_stop - smsgs[j].s_start));
327        fclose (out);
328
329        if (i == msgnum) {
330            strncpy (f3, m_backup (f1), sizeof(f3));
331            if (rename (f1, f3) == NOTOK)
332                admonish (f3, "unable to rename %s to", f1);
333        }
334        if (rename (f2, f1) == NOTOK)
335            admonish (f1, "unable to rename %s to", f2);
336        copy_msg_flags (mp, i, msgnum);
337        mp->msgflags |= SEQMOD;
338    }
339
340    fclose (in);
341}
342
343
344#define S1  0
345#define S2  1
346#define S3  2
347
348/*
349 * Copy a mesage which is being burst out of a digest.
350 * It will remove any "dashstuffing" in the message.
351 */
352
353static void
354cpybrst (FILE *in, FILE *out, char *ifile, char *ofile, int len)
355{
356    register int c, state;
357
358    for (state = S1; (c = fgetc (in)) != EOF && len > 0; len--) {
359        if (c == 0)
360            continue;
361        switch (state) {
362            case S1:
363                switch (c) {
364                    case '-':
365                        state = S3;
366                        break;
367
368                    default:
369                        state = S2;
370                    case '\n':
371                        fputc (c, out);
372                        break;
373                }
374                break;
375
376            case S2:
377                switch (c) {
378                    case '\n':
379                        state = S1;
380                    default:
381                        fputc (c, out);
382                        break;
383                }
384                break;
385
386            case S3:
387                switch (c) {
388                    case ' ':
389                        state = S2;
390                        break;
391
392                    default:
393                        state = (c == '\n') ? S1 : S2;
394                        fputc ('-', out);
395                        fputc (c, out);
396                        break;
397                }
398                break;
399        }
400    }
401
402    if (ferror (in) && !feof (in))
403        adios (ifile, "error reading");
404    if (ferror (out))
405        adios (ofile, "error writing");
406}
Note: See TracBrowser for help on using the repository browser.